Prompt: 海边的灯塔 (5 characters). Same prompt + same 2D code, lifted twice — once with the v1 lift prompt (no semantic types taught) and once with the v2 prompt (18 named atom + component types). v1 emit: 0 atoms (the original 3D had no moon and no stars). v2 emit: moon × 1, star × 15, plus the tower shown here. The library expansion → prompt rewrite → atom emission is a fully quantified loop — scripts/regression reproduces the result for $0.07 per demo.
→ Try the live gallery · no API key needed, click any of 8 pre-lifted scenes and fly through with WASD.
Prompt: 一座哥特式大教堂 (6 characters). 2D code: emitted but failed to render (closing-vertex bug in one polygon call). 3D scene: read by the lift LLM as semantic structure (twin towers + rose window + lancet portals + flying buttresses + crossing tower), compiled into editable SceneData, rendered via BOB GPU.
Two parallel pipelines from prompt to viewer — only one needs to succeed. Diffusion has one.
Atlas — the LLM-native illustration platform. An atlas in differential geometry is a collection of charts covering a manifold. Here it's a collection of forms × renderers × patterns × scenes — composed via four orthogonal input sources (LLM prompt, generator, 2D editor, 3D editor) into a single renderer pool. Built on sdf-js — the underlying open-source SDF library. Signed distance functions are a paradigm where diffusion models structurally cannot compete.
This is a structural separation of domains, not a "diffusion is worse" claim. Diffusion owns photo-realistic / impressionistic / "vibe" generation. We own everything that needs geometric exactness:
| Domain | Why diffusion fails | Why SDF wins |
|---|---|---|
| Clocks showing specific times | Hallucinates plausible-looking clock faces with wrong/distorted numerals | Code defines 12 tick marks at exact angles, hour/minute hands at exact rotations |
| Emoji / icon design | Same emoji rendered slightly different each time → unrecognizable as the same symbol | Same SDF code produces pixel-identical output, every time |
| Editorial illustration with text labels | Garbles letters | Vector text composes geometrically |
| Architectural / engineering diagrams | Mangles right angles, parallel lines | Exact primitive composition |
| Pattern / textile / motif libraries | Cannot reproduce the same motif consistently | Motif data is loaded, not generated |
| Anything plotter-output (vector) | Outputs raster, must be vectorized lossy | Native vector polyline output |
The diffusion boundary above is about input modality (pixel-sampling vs symbolic structure). This second boundary is about system architecture — what kind of 3D substrate the AI is generating into. Same active-concession pattern: each system below is excellent within its own architecture; the question is which architecture is reachable by an LLM writing code.
Two families, not two products. SDF is one point in a larger symbolic-representation family that LLMs can natively write: OpenSCAD, CadQuery / build123d, JSCAD, L-systems, CSG trees, bpy procedural scripts, parametric CAD. The opposing family is sampled-asset: meshes, NeRF, Gaussian Splat, voxel grids, point clouds. The load-bearing claim is family-to-family. SDF's specific advantages within the symbolic family — dimension-agnostic (d(p): ℝⁿ → ℝ works at any n), single-expression representation (a tree, not an API call sequence), GPU-native compile path, continuous infinite resolution — make it the optimal point for web-native simulator work; but the architectural contrast below runs at the family level, not as a product-vs-product fight.
A rung map across existing 3D systems — by state shape × loop contract × LLM writability:
| Representative system | State shape | Loop contract | LLM writes natively? | |
|---|---|---|---|---|
| rung-0 | three.js (static, one renderer.render() call) | Sampled mesh tree | Optional | No — RPC into renderer only |
| rung-1 | p5 sketch | Globals + frameCount | Required, no purity contract | Partially (short sketches only) |
| rung-1.5 | three.js + user-written animate() | Mesh tree + keyframe tween | User code, no enforced contract | Tween yes, mesh no |
| rung-2 | Unity / Unreal / Bevy | ECS components on GameObjects | Enforced Update() per system | Possible but engineering-heavy |
| rung-2 LLM-native | Atlas / M7 | SDF symbolic tree + Rule[] | Pure step() | Yes — native fit |
three.js sits at rung 1.5 — it has mesh state (great for rendering) but no enforced loop contract (dynamics are user code). The same three.js app can be entirely static, keyframe-animated, or coupled to a physics engine — three.js doesn't pick. That's why the clean shorthand below is "graph without a loop contract."
Why sampled-asset AI (VAST Eden, Tripo, Trellis, Hunyuan3D, CSM, Sloyd, Meshy) is structurally outside the rung-2 world-model market:
Identity-preserving edit at object granularity is impossible. Object-level regeneration is real — these systems can swap one door without disturbing the rest of the scene. But say "make this door iron and keep the dents and the handle." What you get is a different door, roughly door-shaped and iron, not the door you had with iron and the dents preserved. Iteration is resampling at object grain, not editing. Atlas's circle(0.3) edited to circle(0.35) is the same primitive, larger — a different category of operation altogether.
Engines give you parameter knobs over a family of laws, not authorship of laws. setGravity(0, -12.7, 0) is one line — Bullet, PhysX, Rapier all handle 1.3× Earth's gravity trivially. Custom forces inside the Newtonian family (n-body gravity, magnetism) are doable by bypassing the built-in pipeline — Outer Wilds famously did this in Unity, reinventing a small rule runtime inside the engine to escape Unity's default gravity assumption. (That game's existence is the strongest field evidence we have: brilliant teams have to fight the engine's defaults to get behavior the engine didn't anticipate.) What no engine gives you is law-family authorship — non-Coulomb friction, modified inertia, position-varying time flow — because the shape of "what must be true" (Signorini conditions, Coulomb cones, shared global dt) is compile-time fixed in the solver's C++. Determinism on this path is an engineering achievement (Rapier supports cross-platform-determinism mode; RTS lockstep physics is a 20-year discipline). On Atlas, both law authorship and determinism are structural defaults — you have to break them (Math.random outside the rng helper, variable dt, mutable cross-tick state) to lose them.
State lives in three disjoint stores: mesh arrays (GPU), scene-graph transforms (CPU), physics-engine internal buffers (solver-private). Fork, time-travel, multiplayer-sync, audit are each engineering projects on this path. On Atlas they are properties of the substrate. (Determinism CI verifies bit-equal replay across 600 ticks; full-mode log is human-readable JSON.)
Atlas inverts the family on all three:
step(world, actions, dt) → newWorld, a pure function. The LLM is writing functions, not configuring a solver.World object. Savegame is serializing it.Where we don't try to compete. Atlas's simulator covers authorable-laws dynamics — fields, swarms, orbits, resources, rule systems, particle flow, rocket-style integration. It does NOT cover solver-grade contact physics — a 500-box pile, ragdoll, constraint-rich rigid-body chains. Bullet / PhysX / Rapier do those well; we don't try to. The trade is explicit: give up solver-grade contact, gain savegame-native composable worlds whose laws the LLM authors.
The real adjacency to flag. Sampled-asset AI is one competing path. A more sophisticated one is Claude Code emitting Bevy / Godot / Unity ECS systems — there the LLM does write code that runs, ECS gives a loop contract close in shape to our step() rule fold, and Rust / C# / GDScript are well within LLM's writing skill. Atlas's differentiation against this path is narrower but durable: web-native zero-install (browser URL = experience, no runtime to ship), determinism by default rather than by engineering discipline, savegame as a single human-readable JSON document rather than engine-specific binary serialization, and dimension-agnostic by SDF math (works in ℝⁿ; ECS components are 3D-shaped). A sophisticated reader will think of this competitor within 60 seconds — better to surface it than be asked.
The killer compression of all this — ask each path how it would let you visit a tidally-locked ocean world where surface gravity is 1.3× Earth's, kilometer-tall waves are driven by tidal forces from an orbiting black hole, and gravitational time dilation means an hour on the surface is seven years outside. (The physics is Kip Thorne's published science; the example is canonical in hard SF.)
dt as a function of position — requires rewriting the integrator architecture, because every solver line and every cache assumes a shared global dt.gravity: 9.8 → 12.7, plus a tidal-force rule in the forces phase, plus a timeScale(p) rule that multiplies dt per region. The patch lives in the savegame — anyone can diff and read exactly how this world differs from Earth in three laws.This is the entire rung-2 argument compressed into one axis:
Physics engines bind laws at compile time. Learning models bind laws at training time. Rule runtimes bind laws at runtime.
A world is a set of rules; another world is a diff.
The clean summary:
Or shorter still:
three.js lets the LLM call the renderer; Atlas lets the LLM write the world.
Across four themes, ten architectural advantages distinguish a code-based SDF generator from a statistical pixel sampler. The conclusion is at the bottom.
A. Structural correctness
Exact structural detail. Every primitive is a function. Clocks show the right time. Bicycles have two wheels of the right size at the right angle. Letters spell words. Diffusion hallucinates plausible-looking but structurally broken output in any precision-content domain (charts, maps, fonts, mechanical drawings).
Infinite semantic composition. Boolean algebra (union / difference / intersection) plus numerical coordinates plus domain operators (rep / mirror / twist / bend) lets any scene be expressed as a finite, auditable, editable tree of named operations. Diffusion has no compositional algebra; composition is emergent from the training distribution, not first-class.
Native infinite resolution. SDF is a continuous function — sharp at any zoom. Vector / plotter / print pipelines plug in directly. Diffusion is locked to a pixel grid; super-resolution requires lossy upscalers.
B. Auditability
Auditable bias, bias-free visual layer. The LLM still carries cultural bias in its language understanding, but the visual output layer is bias-free — the renderer is user-curated, inspectable code. Same SDF can render in 50 visual styles because the renderer is decoupled. Diffusion's bias is encoded in latent weights, opaque, and inherited by every output.
Determinism / reproducibility. Same SceneData → same output, pixel-identical. Essential for emoji sets, icon families, brand assets, character consistency. Diffusion samples stochastically; getting the same emoji style across an entire pack is the fundamental problem diffusion-based sticker tools can't solve.
C. UX
Prompt is specification, not incantation. Domain-language prompts ("a wine bottle on a table") still matter — but the diffusion-era visual incantation prompts ("trending on artstation, 8k uhd, masterpiece, hyperrealistic, ...") become obsolete. The LLM understands shape; we don't need keyword-magic to produce quality.
Editability / iterative loop. The output is code / data, not raster. Change one subject's radius, re-render — everything else stays bit-identical. Diffusion outputs raster; partial edits require inpainting, which breaks lighting consistency and style coherence. The client-revision workflow that takes 5 rounds in diffusion takes 5 field-edits in Atlas.
D. Economics
LLM cost-down beneficiary. Diffusion: quality ↑ → diffusion steps ↑ / model size ↑ → cost per image ↑. Atlas: LLM capability ↑ → better SDF → same flat cost per image (one LLM call + cheap SDF eval). LLM token prices are on a long-term cost-down curve; we ride that trajectory directly.
Multi-axis combinatorial supply. Form × Renderer × Pattern × Motif × Scene = O(N⁵) outputs from O(N) primitive inputs. One SDF rendered through 5 renderers = 5 emotional registers. One renderer × 4 patterns = 4 backgrounds. The supply economy compounds across orthogonal axes. Diffusion: 1 prompt = 1 output; each new variant requires another full inference pass.
Zero-marginal-cost variants. Once an SDF is generated, render-time randomization (palette shuffle, autoscope knobs of mirror/twist/grid-rotation, scene-hash PRNG) yields infinite further visual variants with no additional LLM tokens consumed. Autoscope-clone is the proof: one SceneData × thousands of PRNG hashes × 21 palettes = thousands of distinct images, total marginal cost ≈ GPU shader eval. This is orthogonal to #9: #9 is cross-product across axes, #10 is seed-randomization within an axis.
Diffusion is, at its core, a statistical sampler. Atlas is a world simulator with an LLM as its physicist.
World models have three rungs:
| Rung | Mechanism | Future is… | Example |
|---|---|---|---|
| 1. Scripted | f(t) → state — a timeline plays back a predetermined trajectory | authored | animation, cutscenes |
| 2. Simulated | f(state_t, action) → state_t+1 — a transition function computes the next state | computed | game engines, physics sims |
| 3. Learned | the transition function itself is a trained model | predicted | Genie-class research |
Video-generation approaches attempt rung 3 directly and lose the explicit state along the way: the world is compressed into pixels, objects vanish when the camera looks away, and no two players can share one world. Atlas takes the opposite route — a fully explicit, auditable world state (SceneData), with transition rules written as code by an LLM.
To be precise about what we claim: Atlas is not a world model. It is a world-spec language today, and a rung-2 world simulator on the current roadmap (M7) — with the LLM, rather than a human engineer, writing the physics and the game rules. Every tick is a JSON diff: replayable, forkable, diffable, multiplayer-shareable. Worlds are savegame-native — persistence costs nothing because the state is a document. That is the part of the world-model stack that pixel-based approaches structurally cannot offer, no matter how much compute they burn.
For readers from the generative-art tradition (Processing / p5.js / Pasma / Tyler Hobbs / BOB lineage): Atlas's runtime is a p5-style draw loop with one consequential rewrite — the tick body is a pure function. That single discipline turns a rendering loop into a simulator — savegame-native, forkable, multiplayer-ready — without changing the loop's shape at all. p5's draw() reads globals, calls random(), mutates canvas mid-frame; Atlas's step(world, actions, dt) → newWorld does none of those things. The shape you already know — minus the impurities. (See docs/M7-SPEC.md; determinism CI at sdf-js/scripts/world/test-determinism.mjs proves bit-equal replay across 600 ticks.)
This aligns with cognitive-science models of perception (objects-with-properties-and-relations) and with Marr's 2.5D / 3D representation hierarchy: diffusion stops at the 2D pixel layer, Atlas operates at the 3D representation layer with rendering as the projection step. Diffusion learns a distribution of pixel surfaces — its "understanding" of a red train is the probability cloud of pixels that historically depicted red trains. Atlas constructs a latent geometric world specification — its "understanding" of a train is an executable composition of cylinders, boxes, wheels, with explicit spatial relations.
The LLM is the reasoning engine; SDF is the world-spec geometry language. Together: an LLM-driven world simulator, where the user authors the laws of the world, not samples from a fixed viewing distribution.
SDF is dimension-agnostic: a signed distance field is a function d(p): ℝⁿ → ℝ, defined for any n, not just n = 3. Atlas's dn.js primitives already operate in arbitrary dimensions — this is not a future feature, it is a property of the math.
A 4D world in Atlas is a SceneData with one extra coordinate, rendered by slicing: the camera becomes a moving hyperplane w = c, and a hypersphere appears as a sphere that grows and shrinks as you scrub through w. The same WASD fly camera plus one scroll axis is a complete 4D explorer.
This is the deepest consequence of the spec-first route. Video-based world models can only learn worlds that have been filmed; a world-spec language can define worlds that have never appeared. Diffusion models a distribution over our world's appearances. An SDF + transition-rule stack can simulate non-Euclidean spaces, 4D mechanics, and counterfactual physics — anywhere a distance function and an update rule can be written, a world can run.
What can be written is not just the shape of the world but the laws of the world. SDF gives us symbolic geometry; the M7 rule-runtime gives us symbolic dynamics. The world-spec language extends to wherever both halves can be written — and "both halves can be written" is the boundary of what Atlas claims, no more, no less.
A minimal 4D slice-explorer demo is queued on the bench (see roadmap) so this section's claim ships with a reproducible artifact, not just an argument.
Atlas's first application: pure-text input → spatial-narrative output. Built as two independent products — a 2D end (text → presentation-style pseudo-3D slides) and a 3D end (reads those slides as PDF → lifts them visually to real 3D, each slide a station in one continuous world the camera flies through). The 3D end recognises visual structure, not semantics — and because the 2D slides are already pseudo-3D, the lift is "un-flatten back to 3D," not "invent 3D from flat pixels." (Status + product-form lock: docs/STATUS.md.)
apps/present/ — the product host (a thin Layer-2 app standing on the studio engine).apps/present/landing/ — a cinematic three.js front door (dark room + a glowing screen + click-to-enter → hands off to the SDF deck). three.js is quarantined to this marketing shell; the product runtime stays studio/SDF.src/present/atoms-2d/ (~68 registered pseudo-3D infographic atoms) ↔ src/scene/components/ (42 -3d atoms). ≈71% of 2D atoms have a 3D twin; all core shapes/charts/diagrams aligned. These are the lift's vocabulary.Split into two implementation families. All renderers are polymorphic over SDF2 / SDF3 (12-cell matrix); the GPU family adds real-time interactivity.
Canvas2D family — offline / vector-ready / SVG-exportable:
| Renderer | What it does | Art-history lineage |
|---|---|---|
| Silhouette | Flat-color filled regions, sharp edges | Lotta Nieminen / editorial illustration |
| Stipple (BOB) | Multi-layer painterly brush stipple, SDF3 mode probes Lambert intensity → density modulation | Bonnard / post-impressionism / Aboriginal dot |
| Lines (Pasma) | Contour-following streamlines (2D) / 3D surface-wrap rayhatching (3D) | Piter Pasma / Universal Rayhatcher |
| Lambert (canvas) | Canvas-rendered raymarched diffuse shading | Standard 3D shading |
GPU shader family — real-time, pointer-lock WASD, 60fps:
| Renderer | What it does | Art-history lineage |
|---|---|---|
| Fly 3D | GPU Lambert + free-fly camera; preview & scene-composition mode | Standard 3D shading |
| BOB GPU | GPU quantized-palette spaceCol + 2-pass FBO sand painting + scene-wide palette parity lock | Erik Swahn Autoscope / Aboriginal dot meets Bonnard / generative grid |
| Studio | Cinematic HDR raymarch — premium PBR (roughness / softbox reflections / clearcoat), warm/cool key-fill + kicker lighting, volumetric beams/fog, cameraSequence with ease modes + rack focus, bloom/DoF post; render-on-demand idle-stop. The Atlas Present deck renderer. | Film lighting / product photography |
Compile path: any SDF3 expression → GLSL via sdf3.compile.js (with optional emitObjectIndex for multi-object color separation). Same SDF tree feeds both canvas and GPU renderers.
Pattern is a third independent axis on top of subject SDF × renderer. Patterns auto-mask with subject silhouette (Pasma surreal-staging idiom) so they live behind/around the subject without overpainting it.
| Pattern | Algorithm | Output type |
|---|---|---|
| None | — | Plain bg / canvas-color |
| Truchet | Smith arcs on uniform grid | Plotter-vector |
| Gosper | L-system flowsnake (hexagonal triskele) | Plotter-vector |
| Motifs | Reinder Nijhoff-style hand-drawn motif library × 3-band uniform grid sweep | Plotter-vector |
(Hilbert recursive space-filling curve is still exported from src/render/spaceCurve.js for library users but retired from the MVP pill rail in favor of Gosper's stronger visual contrast.)
.extrude(h), .revolve(offset) — turns 2D primitives into 3D shapes.twist(k), .bend(k), elongateunion / intersection / difference with smooth-k blending.rep([px, py], opts) for tiled instancesexamples/mvp/ — text prompt → Anthropic Claude → SDF JS code → render. Live editable in-browser, history persisted, all 4 renderers × 5 patterns selectable.
sdf-js/src/
├── sdf/ shape algebra
│ ├── d2.js / d3.js / dn.js 2D + 3D primitives, dim-agnostic ops
│ ├── core.js SDF2 / SDF3 classes, defineOp* registrar
│ ├── probe.js 4-value contract {intensity, region, hit, normal}
│ ├── raymarch.js CPU raymarching for canvas2D renderers
│ ├── sdf2.glsl.js 2D SDF → GLSL compilation
│ ├── sdf3.glsl.js 3D SDF → GLSL compilation
│ ├── sdf3.compile.js scene tree → fragment shader (with emitObjectIndex)
│ ├── time.js time-aware primitive wrappers
│ └── vec.js / vec2.js math primitives
├── scene/ SceneData v1 — 4-input lingua franca (M0, locked 2026-05-17)
│ ├── SPEC.md single source of truth for the format
│ ├── spec.js (M0 d2-3) validator + JSDoc types
│ ├── compile.js (M0 d2-3) SceneData → SDF tree + camera + light + regionFn
│ └── serialize.js (M0 d2-3) parse / stringify / version migration
├── render/ output consumers (6 renderers + pattern family)
│ ├── silhouette / bobStipple / hatch / raymarched canvas2D family
│ ├── flyLambert / bobShader GPU shader family
│ ├── truchet / spaceCurve (Hilbert/Gosper) / motifGrid pattern family
│ └── bands / sand / painted / flowLines / lineTile / tileGrid legacy / supporting
├── field/ scalar fields (procedural) — noise / proto
├── streamline/ Pasma rayhatching core (2D contour-following, 3D surface-wrap)
├── motifs/ hand-crafted SVG path library (Reinder Nijhoff default set + path parser)
├── palette/ BOB / Fidenza / Tyler Hobbs / Autoscope color schemes
├── ca/ cellular automata over SDFs (kjetil-golid-derived)
├── input/ pointer-lock WASD fly camera (shared between Fly 3D and BOB GPU)
└── math/ easing curves
scene/ is the new lingua franca: all four Compositor input sources (LLM, generator, 2D editor, 3D editor) emit the same SceneData shape; the renderer pool consumes it.sdf3.compile.js.{intensity, region, hit, normal} — single source of truth for camera + lighting + raymarching. Same probe contract is honored by the GPU compile path.cd sdf-js
python3 dev-server.py 8001 # dev server with no-store cache header
open http://localhost:8001/examples/
| Demo | Path |
|---|---|
| MVP — text → SDF (Anthropic API) | examples/mvp/ |
| Streamline scenes — Pasma 2D + 3D rayhatching gallery | examples/sdf/streamline-scenes.html |
| Painted scenes — BOB stipple gallery (incl. 3D scenes 15+16) | examples/sdf/painted-scenes.html |
| 3D fly camera tuning — pointer-lock WASD scene composition | examples/sdf/test-pasma-capsules.html |
| Render showcase — 4 renderers × same SDF set | examples/sdf/render-showcase.html |
| Editor — interactive SDF construction | examples/sdf/editor.html |
import { circle, sphere, capsule, union, render } from './sdf-js/src/index.js';
// 2D: a flower
const petal = circle(0.3).translate([0.5, 0]);
const flower = union(...Array.from({length: 6}, (_, i) =>
petal.rotate(i * Math.PI / 3)
));
// Render as silhouette
render.silhouette(ctx, [{ sdf: flower, color: [200, 80, 100] }], { view: 1 });
// Or as Pasma streamlines (vector, axidraw-ready)
render.hatch(ctx, [{ sdf: flower, color: '#222' }], { view: 1 });
// 3D: a wine bottle
const bottle = polygon([...profile]).revolve(0);
render.raymarched(ctx, [{ sdf: bottle, color: [0.2, 0.6, 0.9] }], { view: 1.2 });
Where we are right now: see docs/STATUS.md for the current milestone tracker, locked decisions, and ship status.
Input is the new axis. The current MVP ships one input path (LLM text prompt → SDF). The next phase splits the input layer into four orthogonal sources, all emitting the same SceneData format, all consumed by the same renderer pool:
┌─ text-mode (LLM prompt → SceneData) ─┐
├─ generator-mode (autoscope-style PRNG → Data) ─┤
│ ├→ SceneData → renderer pool (silhouette / stipple / lines / Lambert / BOB-GPU × 5 patterns)
├─ 2d-edit-mode (node-graph editor → Data) ─┤
└─ 3d-edit-mode (viewport editor → Data) ─┘
Three architectural decisions (locked 2026-05-17):
subjects + ground + defaults.camera + defaults.light + regions). Without this, the four inputs become silos and the Compositor can't unify them.text-mode tab. Four pages, not five. One shared renderer pool, one palette control surface, one camera widget. The existing examples/mvp/ URL stays alive via redirect.| M | Goal | Time | Depends on | Output |
|---|---|---|---|---|
| M0 | Scene data spec | 3–5 days | — | src/scene/spec.js + compile.js + serialize.js; autoscope-scenes refactor validates spec |
| M1 | Compositor v0 | 5–7 days | M0 | 4-tab UI + renderer pool; text + generator tabs functional |
| M2 | Generator framework | 5–7 days | M0 | src/generator/; autoscope re-expressed as a Generator instance; +1–2 new templates |
| M3 | 2D node-graph editor | 2–3 weeks | M0 | viewport + primitive palette + boolean nodes + outliner + undo |
| M4 | 3D viewport editor | 3–4 weeks | M0 | three.js viewport + transform gizmo + 3D primitive panel + SceneData output |
| M5 | LLM emits SceneData | 1–2 weeks | M0, M1 | SKILL.md rewrite → LLM outputs SceneData JSON → editable in 2D/3D editors |
| M6 | LLM emits Generator function | 1–2 weeks | M2, M5 | LLM writes (hash) → SceneData → autoscope-style generative output from prompt |
| M7 | LLM emits Transition rules | 2–3 weeks | M5, M6 | LLM writes step(SceneData_t, actions, dt) → SceneData_t+1 as auditable JS; runtime executes per tick. Unlocks counterfactual intervention (grab the rocket mid-flight), emergent failure (insufficient thrust → it falls), and savegame-native persistent worlds |
Critical path: M0 → M1 → M2 → M3/M4 → M5 → M6 → M7. M3 and M4 can run in parallel after M0 lands.
This is Point 4 (multi-axis decoupling) extended from the output side (renderer × pattern × motif library) to the input side (LLM × generator × 2D-edit × 3D-edit). Every input source becomes a tradable asset class in the marketplace economy:
M5 and M6 are the commercial-thesis demonstrations: LLM produces editable output (M5) and generators (M6) — neither of which diffusion can structurally reach. M7 is the world-simulator demonstration: the same explicit-state architecture that makes output editable also makes worlds runnable — the M6 signature (hash) → SceneData becomes the M7 signature (SceneData, action) → SceneData, and Atlas crosses from generating worlds to simulating them.
text(font, str) → SDF — capability blocker for PPT titles + emoji text + logo work; queued after M2w-axis slicing camera (existing WASD fly camera + one scroll axis); the reproducible artifact backing the "Beyond ℝ³" section; queued after M7The first three segments share one supply-side property: the visual is reused at multiplied scale (one motif used 30× across a deck; one icon set used by millions; one preset applied to 100 editorial pieces). Diffusion's per-generation cost is a tax on this supply economy. SDF's deterministic preset model is the inverse — supply compounds.
Started as a JavaScript port of fogleman/sdf (Python, marching-cubes mesh export). Has since diverged into an interactive vector + plotter + LLM-native creative engine, with its own renderers, pattern layer, motif library, scene engine, and MVP. The Python original is unmaintained — see git history pre-2026-05-15 for the legacy archive.
PolyForm Noncommercial 1.0.0 for the Atlas Project original work (renderer family, motif library, scene engine, Compositor, BOB GPU pipeline, autoscope scene generators, brand surface, and all documentation/examples). Personal / academic / research use is free; commercial use requires a separate license — see COMMERCIAL.md.
Third-party components retain their original licenses:
fogleman/sdf Python derivative primitives: MIT666 commits
13 commits
JavaScript
93.2%
HTML
6.5%
Prompt: 海边的灯塔 (5 characters). Same prompt + same 2D code, lifted twice — once with the v1 lift prompt (no semantic types taught) and once with the v2 prompt (18 named atom + component types). v1 emit: 0 atoms (the original 3D had no moon and no stars). v2 emit: moon × 1, star × 15, plus the tower shown here. The library expansion → prompt rewrite → atom emission is a fully quantified loop — scripts/regression reproduces the result for $0.07 per demo.
→ Try the live gallery · no API key needed, click any of 8 pre-lifted scenes and fly through with WASD.
Prompt: 一座哥特式大教堂 (6 characters). 2D code: emitted but failed to render (closing-vertex bug in one polygon call). 3D scene: read by the lift LLM as semantic structure (twin towers + rose window + lancet portals + flying buttresses + crossing tower), compiled into editable SceneData, rendered via BOB GPU.
Two parallel pipelines from prompt to viewer — only one needs to succeed. Diffusion has one.
Atlas — the LLM-native illustration platform. An atlas in differential geometry is a collection of charts covering a manifold. Here it's a collection of forms × renderers × patterns × scenes — composed via four orthogonal input sources (LLM prompt, generator, 2D editor, 3D editor) into a single renderer pool. Built on sdf-js — the underlying open-source SDF library. Signed distance functions are a paradigm where diffusion models structurally cannot compete.
This is a structural separation of domains, not a "diffusion is worse" claim. Diffusion owns photo-realistic / impressionistic / "vibe" generation. We own everything that needs geometric exactness:
| Domain | Why diffusion fails | Why SDF wins |
|---|---|---|
| Clocks showing specific times | Hallucinates plausible-looking clock faces with wrong/distorted numerals | Code defines 12 tick marks at exact angles, hour/minute hands at exact rotations |
| Emoji / icon design | Same emoji rendered slightly different each time → unrecognizable as the same symbol | Same SDF code produces pixel-identical output, every time |
| Editorial illustration with text labels | Garbles letters | Vector text composes geometrically |
| Architectural / engineering diagrams | Mangles right angles, parallel lines | Exact primitive composition |
| Pattern / textile / motif libraries | Cannot reproduce the same motif consistently | Motif data is loaded, not generated |
| Anything plotter-output (vector) | Outputs raster, must be vectorized lossy | Native vector polyline output |
The diffusion boundary above is about input modality (pixel-sampling vs symbolic structure). This second boundary is about system architecture — what kind of 3D substrate the AI is generating into. Same active-concession pattern: each system below is excellent within its own architecture; the question is which architecture is reachable by an LLM writing code.
Two families, not two products. SDF is one point in a larger symbolic-representation family that LLMs can natively write: OpenSCAD, CadQuery / build123d, JSCAD, L-systems, CSG trees, bpy procedural scripts, parametric CAD. The opposing family is sampled-asset: meshes, NeRF, Gaussian Splat, voxel grids, point clouds. The load-bearing claim is family-to-family. SDF's specific advantages within the symbolic family — dimension-agnostic (d(p): ℝⁿ → ℝ works at any n), single-expression representation (a tree, not an API call sequence), GPU-native compile path, continuous infinite resolution — make it the optimal point for web-native simulator work; but the architectural contrast below runs at the family level, not as a product-vs-product fight.
A rung map across existing 3D systems — by state shape × loop contract × LLM writability:
| Representative system | State shape | Loop contract | LLM writes natively? | |
|---|---|---|---|---|
| rung-0 | three.js (static, one renderer.render() call) | Sampled mesh tree | Optional | No — RPC into renderer only |
| rung-1 | p5 sketch | Globals + frameCount | Required, no purity contract | Partially (short sketches only) |
| rung-1.5 | three.js + user-written animate() | Mesh tree + keyframe tween | User code, no enforced contract | Tween yes, mesh no |
| rung-2 | Unity / Unreal / Bevy | ECS components on GameObjects | Enforced Update() per system | Possible but engineering-heavy |
| rung-2 LLM-native | Atlas / M7 | SDF symbolic tree + Rule[] | Pure step() | Yes — native fit |
three.js sits at rung 1.5 — it has mesh state (great for rendering) but no enforced loop contract (dynamics are user code). The same three.js app can be entirely static, keyframe-animated, or coupled to a physics engine — three.js doesn't pick. That's why the clean shorthand below is "graph without a loop contract."
Why sampled-asset AI (VAST Eden, Tripo, Trellis, Hunyuan3D, CSM, Sloyd, Meshy) is structurally outside the rung-2 world-model market:
Identity-preserving edit at object granularity is impossible. Object-level regeneration is real — these systems can swap one door without disturbing the rest of the scene. But say "make this door iron and keep the dents and the handle." What you get is a different door, roughly door-shaped and iron, not the door you had with iron and the dents preserved. Iteration is resampling at object grain, not editing. Atlas's circle(0.3) edited to circle(0.35) is the same primitive, larger — a different category of operation altogether.
Engines give you parameter knobs over a family of laws, not authorship of laws. setGravity(0, -12.7, 0) is one line — Bullet, PhysX, Rapier all handle 1.3× Earth's gravity trivially. Custom forces inside the Newtonian family (n-body gravity, magnetism) are doable by bypassing the built-in pipeline — Outer Wilds famously did this in Unity, reinventing a small rule runtime inside the engine to escape Unity's default gravity assumption. (That game's existence is the strongest field evidence we have: brilliant teams have to fight the engine's defaults to get behavior the engine didn't anticipate.) What no engine gives you is law-family authorship — non-Coulomb friction, modified inertia, position-varying time flow — because the shape of "what must be true" (Signorini conditions, Coulomb cones, shared global dt) is compile-time fixed in the solver's C++. Determinism on this path is an engineering achievement (Rapier supports cross-platform-determinism mode; RTS lockstep physics is a 20-year discipline). On Atlas, both law authorship and determinism are structural defaults — you have to break them (Math.random outside the rng helper, variable dt, mutable cross-tick state) to lose them.
State lives in three disjoint stores: mesh arrays (GPU), scene-graph transforms (CPU), physics-engine internal buffers (solver-private). Fork, time-travel, multiplayer-sync, audit are each engineering projects on this path. On Atlas they are properties of the substrate. (Determinism CI verifies bit-equal replay across 600 ticks; full-mode log is human-readable JSON.)
Atlas inverts the family on all three:
step(world, actions, dt) → newWorld, a pure function. The LLM is writing functions, not configuring a solver.World object. Savegame is serializing it.Where we don't try to compete. Atlas's simulator covers authorable-laws dynamics — fields, swarms, orbits, resources, rule systems, particle flow, rocket-style integration. It does NOT cover solver-grade contact physics — a 500-box pile, ragdoll, constraint-rich rigid-body chains. Bullet / PhysX / Rapier do those well; we don't try to. The trade is explicit: give up solver-grade contact, gain savegame-native composable worlds whose laws the LLM authors.
The real adjacency to flag. Sampled-asset AI is one competing path. A more sophisticated one is Claude Code emitting Bevy / Godot / Unity ECS systems — there the LLM does write code that runs, ECS gives a loop contract close in shape to our step() rule fold, and Rust / C# / GDScript are well within LLM's writing skill. Atlas's differentiation against this path is narrower but durable: web-native zero-install (browser URL = experience, no runtime to ship), determinism by default rather than by engineering discipline, savegame as a single human-readable JSON document rather than engine-specific binary serialization, and dimension-agnostic by SDF math (works in ℝⁿ; ECS components are 3D-shaped). A sophisticated reader will think of this competitor within 60 seconds — better to surface it than be asked.
The killer compression of all this — ask each path how it would let you visit a tidally-locked ocean world where surface gravity is 1.3× Earth's, kilometer-tall waves are driven by tidal forces from an orbiting black hole, and gravitational time dilation means an hour on the surface is seven years outside. (The physics is Kip Thorne's published science; the example is canonical in hard SF.)
dt as a function of position — requires rewriting the integrator architecture, because every solver line and every cache assumes a shared global dt.gravity: 9.8 → 12.7, plus a tidal-force rule in the forces phase, plus a timeScale(p) rule that multiplies dt per region. The patch lives in the savegame — anyone can diff and read exactly how this world differs from Earth in three laws.This is the entire rung-2 argument compressed into one axis:
Physics engines bind laws at compile time. Learning models bind laws at training time. Rule runtimes bind laws at runtime.
A world is a set of rules; another world is a diff.
The clean summary:
Or shorter still:
three.js lets the LLM call the renderer; Atlas lets the LLM write the world.
Across four themes, ten architectural advantages distinguish a code-based SDF generator from a statistical pixel sampler. The conclusion is at the bottom.
A. Structural correctness
Exact structural detail. Every primitive is a function. Clocks show the right time. Bicycles have two wheels of the right size at the right angle. Letters spell words. Diffusion hallucinates plausible-looking but structurally broken output in any precision-content domain (charts, maps, fonts, mechanical drawings).
Infinite semantic composition. Boolean algebra (union / difference / intersection) plus numerical coordinates plus domain operators (rep / mirror / twist / bend) lets any scene be expressed as a finite, auditable, editable tree of named operations. Diffusion has no compositional algebra; composition is emergent from the training distribution, not first-class.
Native infinite resolution. SDF is a continuous function — sharp at any zoom. Vector / plotter / print pipelines plug in directly. Diffusion is locked to a pixel grid; super-resolution requires lossy upscalers.
B. Auditability
Auditable bias, bias-free visual layer. The LLM still carries cultural bias in its language understanding, but the visual output layer is bias-free — the renderer is user-curated, inspectable code. Same SDF can render in 50 visual styles because the renderer is decoupled. Diffusion's bias is encoded in latent weights, opaque, and inherited by every output.
Determinism / reproducibility. Same SceneData → same output, pixel-identical. Essential for emoji sets, icon families, brand assets, character consistency. Diffusion samples stochastically; getting the same emoji style across an entire pack is the fundamental problem diffusion-based sticker tools can't solve.
C. UX
Prompt is specification, not incantation. Domain-language prompts ("a wine bottle on a table") still matter — but the diffusion-era visual incantation prompts ("trending on artstation, 8k uhd, masterpiece, hyperrealistic, ...") become obsolete. The LLM understands shape; we don't need keyword-magic to produce quality.
Editability / iterative loop. The output is code / data, not raster. Change one subject's radius, re-render — everything else stays bit-identical. Diffusion outputs raster; partial edits require inpainting, which breaks lighting consistency and style coherence. The client-revision workflow that takes 5 rounds in diffusion takes 5 field-edits in Atlas.
D. Economics
LLM cost-down beneficiary. Diffusion: quality ↑ → diffusion steps ↑ / model size ↑ → cost per image ↑. Atlas: LLM capability ↑ → better SDF → same flat cost per image (one LLM call + cheap SDF eval). LLM token prices are on a long-term cost-down curve; we ride that trajectory directly.
Multi-axis combinatorial supply. Form × Renderer × Pattern × Motif × Scene = O(N⁵) outputs from O(N) primitive inputs. One SDF rendered through 5 renderers = 5 emotional registers. One renderer × 4 patterns = 4 backgrounds. The supply economy compounds across orthogonal axes. Diffusion: 1 prompt = 1 output; each new variant requires another full inference pass.
Zero-marginal-cost variants. Once an SDF is generated, render-time randomization (palette shuffle, autoscope knobs of mirror/twist/grid-rotation, scene-hash PRNG) yields infinite further visual variants with no additional LLM tokens consumed. Autoscope-clone is the proof: one SceneData × thousands of PRNG hashes × 21 palettes = thousands of distinct images, total marginal cost ≈ GPU shader eval. This is orthogonal to #9: #9 is cross-product across axes, #10 is seed-randomization within an axis.
Diffusion is, at its core, a statistical sampler. Atlas is a world simulator with an LLM as its physicist.
World models have three rungs:
| Rung | Mechanism | Future is… | Example |
|---|---|---|---|
| 1. Scripted | f(t) → state — a timeline plays back a predetermined trajectory | authored | animation, cutscenes |
| 2. Simulated | f(state_t, action) → state_t+1 — a transition function computes the next state | computed | game engines, physics sims |
| 3. Learned | the transition function itself is a trained model | predicted | Genie-class research |
Video-generation approaches attempt rung 3 directly and lose the explicit state along the way: the world is compressed into pixels, objects vanish when the camera looks away, and no two players can share one world. Atlas takes the opposite route — a fully explicit, auditable world state (SceneData), with transition rules written as code by an LLM.
To be precise about what we claim: Atlas is not a world model. It is a world-spec language today, and a rung-2 world simulator on the current roadmap (M7) — with the LLM, rather than a human engineer, writing the physics and the game rules. Every tick is a JSON diff: replayable, forkable, diffable, multiplayer-shareable. Worlds are savegame-native — persistence costs nothing because the state is a document. That is the part of the world-model stack that pixel-based approaches structurally cannot offer, no matter how much compute they burn.
For readers from the generative-art tradition (Processing / p5.js / Pasma / Tyler Hobbs / BOB lineage): Atlas's runtime is a p5-style draw loop with one consequential rewrite — the tick body is a pure function. That single discipline turns a rendering loop into a simulator — savegame-native, forkable, multiplayer-ready — without changing the loop's shape at all. p5's draw() reads globals, calls random(), mutates canvas mid-frame; Atlas's step(world, actions, dt) → newWorld does none of those things. The shape you already know — minus the impurities. (See docs/M7-SPEC.md; determinism CI at sdf-js/scripts/world/test-determinism.mjs proves bit-equal replay across 600 ticks.)
This aligns with cognitive-science models of perception (objects-with-properties-and-relations) and with Marr's 2.5D / 3D representation hierarchy: diffusion stops at the 2D pixel layer, Atlas operates at the 3D representation layer with rendering as the projection step. Diffusion learns a distribution of pixel surfaces — its "understanding" of a red train is the probability cloud of pixels that historically depicted red trains. Atlas constructs a latent geometric world specification — its "understanding" of a train is an executable composition of cylinders, boxes, wheels, with explicit spatial relations.
The LLM is the reasoning engine; SDF is the world-spec geometry language. Together: an LLM-driven world simulator, where the user authors the laws of the world, not samples from a fixed viewing distribution.
SDF is dimension-agnostic: a signed distance field is a function d(p): ℝⁿ → ℝ, defined for any n, not just n = 3. Atlas's dn.js primitives already operate in arbitrary dimensions — this is not a future feature, it is a property of the math.
A 4D world in Atlas is a SceneData with one extra coordinate, rendered by slicing: the camera becomes a moving hyperplane w = c, and a hypersphere appears as a sphere that grows and shrinks as you scrub through w. The same WASD fly camera plus one scroll axis is a complete 4D explorer.
This is the deepest consequence of the spec-first route. Video-based world models can only learn worlds that have been filmed; a world-spec language can define worlds that have never appeared. Diffusion models a distribution over our world's appearances. An SDF + transition-rule stack can simulate non-Euclidean spaces, 4D mechanics, and counterfactual physics — anywhere a distance function and an update rule can be written, a world can run.
What can be written is not just the shape of the world but the laws of the world. SDF gives us symbolic geometry; the M7 rule-runtime gives us symbolic dynamics. The world-spec language extends to wherever both halves can be written — and "both halves can be written" is the boundary of what Atlas claims, no more, no less.
A minimal 4D slice-explorer demo is queued on the bench (see roadmap) so this section's claim ships with a reproducible artifact, not just an argument.
Atlas's first application: pure-text input → spatial-narrative output. Built as two independent products — a 2D end (text → presentation-style pseudo-3D slides) and a 3D end (reads those slides as PDF → lifts them visually to real 3D, each slide a station in one continuous world the camera flies through). The 3D end recognises visual structure, not semantics — and because the 2D slides are already pseudo-3D, the lift is "un-flatten back to 3D," not "invent 3D from flat pixels." (Status + product-form lock: docs/STATUS.md.)
apps/present/ — the product host (a thin Layer-2 app standing on the studio engine).apps/present/landing/ — a cinematic three.js front door (dark room + a glowing screen + click-to-enter → hands off to the SDF deck). three.js is quarantined to this marketing shell; the product runtime stays studio/SDF.src/present/atoms-2d/ (~68 registered pseudo-3D infographic atoms) ↔ src/scene/components/ (42 -3d atoms). ≈71% of 2D atoms have a 3D twin; all core shapes/charts/diagrams aligned. These are the lift's vocabulary.Split into two implementation families. All renderers are polymorphic over SDF2 / SDF3 (12-cell matrix); the GPU family adds real-time interactivity.
Canvas2D family — offline / vector-ready / SVG-exportable:
| Renderer | What it does | Art-history lineage |
|---|---|---|
| Silhouette | Flat-color filled regions, sharp edges | Lotta Nieminen / editorial illustration |
| Stipple (BOB) | Multi-layer painterly brush stipple, SDF3 mode probes Lambert intensity → density modulation | Bonnard / post-impressionism / Aboriginal dot |
| Lines (Pasma) | Contour-following streamlines (2D) / 3D surface-wrap rayhatching (3D) | Piter Pasma / Universal Rayhatcher |
| Lambert (canvas) | Canvas-rendered raymarched diffuse shading | Standard 3D shading |
GPU shader family — real-time, pointer-lock WASD, 60fps:
| Renderer | What it does | Art-history lineage |
|---|---|---|
| Fly 3D | GPU Lambert + free-fly camera; preview & scene-composition mode | Standard 3D shading |
| BOB GPU | GPU quantized-palette spaceCol + 2-pass FBO sand painting + scene-wide palette parity lock | Erik Swahn Autoscope / Aboriginal dot meets Bonnard / generative grid |
| Studio | Cinematic HDR raymarch — premium PBR (roughness / softbox reflections / clearcoat), warm/cool key-fill + kicker lighting, volumetric beams/fog, cameraSequence with ease modes + rack focus, bloom/DoF post; render-on-demand idle-stop. The Atlas Present deck renderer. | Film lighting / product photography |
Compile path: any SDF3 expression → GLSL via sdf3.compile.js (with optional emitObjectIndex for multi-object color separation). Same SDF tree feeds both canvas and GPU renderers.
Pattern is a third independent axis on top of subject SDF × renderer. Patterns auto-mask with subject silhouette (Pasma surreal-staging idiom) so they live behind/around the subject without overpainting it.
| Pattern | Algorithm | Output type |
|---|---|---|
| None | — | Plain bg / canvas-color |
| Truchet | Smith arcs on uniform grid | Plotter-vector |
| Gosper | L-system flowsnake (hexagonal triskele) | Plotter-vector |
| Motifs | Reinder Nijhoff-style hand-drawn motif library × 3-band uniform grid sweep | Plotter-vector |
(Hilbert recursive space-filling curve is still exported from src/render/spaceCurve.js for library users but retired from the MVP pill rail in favor of Gosper's stronger visual contrast.)
.extrude(h), .revolve(offset) — turns 2D primitives into 3D shapes.twist(k), .bend(k), elongateunion / intersection / difference with smooth-k blending.rep([px, py], opts) for tiled instancesexamples/mvp/ — text prompt → Anthropic Claude → SDF JS code → render. Live editable in-browser, history persisted, all 4 renderers × 5 patterns selectable.
sdf-js/src/
├── sdf/ shape algebra
│ ├── d2.js / d3.js / dn.js 2D + 3D primitives, dim-agnostic ops
│ ├── core.js SDF2 / SDF3 classes, defineOp* registrar
│ ├── probe.js 4-value contract {intensity, region, hit, normal}
│ ├── raymarch.js CPU raymarching for canvas2D renderers
│ ├── sdf2.glsl.js 2D SDF → GLSL compilation
│ ├── sdf3.glsl.js 3D SDF → GLSL compilation
│ ├── sdf3.compile.js scene tree → fragment shader (with emitObjectIndex)
│ ├── time.js time-aware primitive wrappers
│ └── vec.js / vec2.js math primitives
├── scene/ SceneData v1 — 4-input lingua franca (M0, locked 2026-05-17)
│ ├── SPEC.md single source of truth for the format
│ ├── spec.js (M0 d2-3) validator + JSDoc types
│ ├── compile.js (M0 d2-3) SceneData → SDF tree + camera + light + regionFn
│ └── serialize.js (M0 d2-3) parse / stringify / version migration
├── render/ output consumers (6 renderers + pattern family)
│ ├── silhouette / bobStipple / hatch / raymarched canvas2D family
│ ├── flyLambert / bobShader GPU shader family
│ ├── truchet / spaceCurve (Hilbert/Gosper) / motifGrid pattern family
│ └── bands / sand / painted / flowLines / lineTile / tileGrid legacy / supporting
├── field/ scalar fields (procedural) — noise / proto
├── streamline/ Pasma rayhatching core (2D contour-following, 3D surface-wrap)
├── motifs/ hand-crafted SVG path library (Reinder Nijhoff default set + path parser)
├── palette/ BOB / Fidenza / Tyler Hobbs / Autoscope color schemes
├── ca/ cellular automata over SDFs (kjetil-golid-derived)
├── input/ pointer-lock WASD fly camera (shared between Fly 3D and BOB GPU)
└── math/ easing curves
scene/ is the new lingua franca: all four Compositor input sources (LLM, generator, 2D editor, 3D editor) emit the same SceneData shape; the renderer pool consumes it.sdf3.compile.js.{intensity, region, hit, normal} — single source of truth for camera + lighting + raymarching. Same probe contract is honored by the GPU compile path.cd sdf-js
python3 dev-server.py 8001 # dev server with no-store cache header
open http://localhost:8001/examples/
| Demo | Path |
|---|---|
| MVP — text → SDF (Anthropic API) | examples/mvp/ |
| Streamline scenes — Pasma 2D + 3D rayhatching gallery | examples/sdf/streamline-scenes.html |
| Painted scenes — BOB stipple gallery (incl. 3D scenes 15+16) | examples/sdf/painted-scenes.html |
| 3D fly camera tuning — pointer-lock WASD scene composition | examples/sdf/test-pasma-capsules.html |
| Render showcase — 4 renderers × same SDF set | examples/sdf/render-showcase.html |
| Editor — interactive SDF construction | examples/sdf/editor.html |
import { circle, sphere, capsule, union, render } from './sdf-js/src/index.js';
// 2D: a flower
const petal = circle(0.3).translate([0.5, 0]);
const flower = union(...Array.from({length: 6}, (_, i) =>
petal.rotate(i * Math.PI / 3)
));
// Render as silhouette
render.silhouette(ctx, [{ sdf: flower, color: [200, 80, 100] }], { view: 1 });
// Or as Pasma streamlines (vector, axidraw-ready)
render.hatch(ctx, [{ sdf: flower, color: '#222' }], { view: 1 });
// 3D: a wine bottle
const bottle = polygon([...profile]).revolve(0);
render.raymarched(ctx, [{ sdf: bottle, color: [0.2, 0.6, 0.9] }], { view: 1.2 });
Where we are right now: see docs/STATUS.md for the current milestone tracker, locked decisions, and ship status.
Input is the new axis. The current MVP ships one input path (LLM text prompt → SDF). The next phase splits the input layer into four orthogonal sources, all emitting the same SceneData format, all consumed by the same renderer pool:
┌─ text-mode (LLM prompt → SceneData) ─┐
├─ generator-mode (autoscope-style PRNG → Data) ─┤
│ ├→ SceneData → renderer pool (silhouette / stipple / lines / Lambert / BOB-GPU × 5 patterns)
├─ 2d-edit-mode (node-graph editor → Data) ─┤
└─ 3d-edit-mode (viewport editor → Data) ─┘
Three architectural decisions (locked 2026-05-17):
subjects + ground + defaults.camera + defaults.light + regions). Without this, the four inputs become silos and the Compositor can't unify them.text-mode tab. Four pages, not five. One shared renderer pool, one palette control surface, one camera widget. The existing examples/mvp/ URL stays alive via redirect.| M | Goal | Time | Depends on | Output |
|---|---|---|---|---|
| M0 | Scene data spec | 3–5 days | — | src/scene/spec.js + compile.js + serialize.js; autoscope-scenes refactor validates spec |
| M1 | Compositor v0 | 5–7 days | M0 | 4-tab UI + renderer pool; text + generator tabs functional |
| M2 | Generator framework | 5–7 days | M0 | src/generator/; autoscope re-expressed as a Generator instance; +1–2 new templates |
| M3 | 2D node-graph editor | 2–3 weeks | M0 | viewport + primitive palette + boolean nodes + outliner + undo |
| M4 | 3D viewport editor | 3–4 weeks | M0 | three.js viewport + transform gizmo + 3D primitive panel + SceneData output |
| M5 | LLM emits SceneData | 1–2 weeks | M0, M1 | SKILL.md rewrite → LLM outputs SceneData JSON → editable in 2D/3D editors |
| M6 | LLM emits Generator function | 1–2 weeks | M2, M5 | LLM writes (hash) → SceneData → autoscope-style generative output from prompt |
| M7 | LLM emits Transition rules | 2–3 weeks | M5, M6 | LLM writes step(SceneData_t, actions, dt) → SceneData_t+1 as auditable JS; runtime executes per tick. Unlocks counterfactual intervention (grab the rocket mid-flight), emergent failure (insufficient thrust → it falls), and savegame-native persistent worlds |
Critical path: M0 → M1 → M2 → M3/M4 → M5 → M6 → M7. M3 and M4 can run in parallel after M0 lands.
This is Point 4 (multi-axis decoupling) extended from the output side (renderer × pattern × motif library) to the input side (LLM × generator × 2D-edit × 3D-edit). Every input source becomes a tradable asset class in the marketplace economy:
M5 and M6 are the commercial-thesis demonstrations: LLM produces editable output (M5) and generators (M6) — neither of which diffusion can structurally reach. M7 is the world-simulator demonstration: the same explicit-state architecture that makes output editable also makes worlds runnable — the M6 signature (hash) → SceneData becomes the M7 signature (SceneData, action) → SceneData, and Atlas crosses from generating worlds to simulating them.
text(font, str) → SDF — capability blocker for PPT titles + emoji text + logo work; queued after M2w-axis slicing camera (existing WASD fly camera + one scroll axis); the reproducible artifact backing the "Beyond ℝ³" section; queued after M7The first three segments share one supply-side property: the visual is reused at multiplied scale (one motif used 30× across a deck; one icon set used by millions; one preset applied to 100 editorial pieces). Diffusion's per-generation cost is a tax on this supply economy. SDF's deterministic preset model is the inverse — supply compounds.
Started as a JavaScript port of fogleman/sdf (Python, marching-cubes mesh export). Has since diverged into an interactive vector + plotter + LLM-native creative engine, with its own renderers, pattern layer, motif library, scene engine, and MVP. The Python original is unmaintained — see git history pre-2026-05-15 for the legacy archive.
PolyForm Noncommercial 1.0.0 for the Atlas Project original work (renderer family, motif library, scene engine, Compositor, BOB GPU pipeline, autoscope scene generators, brand surface, and all documentation/examples). Personal / academic / research use is free; commercial use requires a separate license — see COMMERCIAL.md.
Third-party components retain their original licenses:
fogleman/sdf Python derivative primitives: MIT666 commits
13 commits
JavaScript
93.2%
HTML
6.5%