The complete design manual for 3JSE — every system, every decision, every bet. Written to be read by humans and by the AI agents that will help build it.
VisionVISION.md
What 3JSE is
3JSE is an open-source game engine and editor built around Three.js and WebGPU, not on top of a fork of them. It exists to answer one question honestly: if Unreal Engine were invented today, for WebGPU, TypeScript, and AI-assisted development, what would it look like?
The answer is not "Unreal's UI redrawn in a browser tab." Unreal's strengths — a real editor, a visual scripting system expressive enough for shipped games, a deep library of reusable gameplay systems, and (increasingly) AI-assisted iteration — are not tied to C++ or a desktop process model. They are tied to having all of those layers exist and agree on the same underlying representation of a game. Three.js has never had that. It has a renderer. 3JSE is everything a renderer needs around it to become a platform: an editor, an object model, a scripting system, an asset pipeline, an AI-native command surface, and a deployment story that a desktop engine cannot match.
Tandem with the Harness
This design package is one half of a tandem project. The other half — 3JSE Harness v0.1 — already exists and works today: an agent-native development system that turns a general coding agent into a reference-first Three.js/WebGPU game-development agent (HARNESS.md, source in 3JSE_Harness_v0.2/). The harness is where the AI-native bet on this page is tested against reality first; the engine this document describes is where those practices become first-class machinery. The harness's governing idea — the coding agent is the editor; visual tools are added only when repeated work proves them necessary — is the through-line for every "AI-native" claim made here.
The core bet
Three.js already won the "does the web have a real renderer" argument. Nobody chooses Unity or Unreal over Three.js because Three.js renders badly — they choose it because Three.js stops being productive the moment you need a scene hierarchy you can see, gameplay logic you don't have to hand-wire, an asset pipeline that isn't a shell script, or a way for a non-programmer (or an AI agent) to safely change how the game plays. That gap — not rendering quality — is what 3JSE closes.
The second bet is about when this is being built. 3JSE is designed in the era where a meaningful fraction of a game's code will be written by an AI agent operating the engine, not typed by a human into a text editor. That is not a feature bolted onto a traditional engine design — it changes the engine's architecture at the root. Every layer of 3JSE is built to be machine-readable and machine-editable first, human-friendly second — which, done correctly, produces an engine that is also unusually friendly to humans, because "structured, inspectable, and consistent" is what both audiences actually want.
Guiding philosophy
3JSE is designed so that four different ways of working edit the same underlying game, never four parallel ones:
- Humans edit visually — dragging assets, placing entities, adjusting values in an inspector, wiring nodes in a graph.
- Programmers write TypeScript — the same components, the same systems, the same APIs the editor and the graph compiler use, with no separate "scripting language."
- Designers navigate meaning and tune feel — 3JSE Atlas (
3JSE_ATLAS_FULL_PLAN.md), the semantic navigation and FeelSpec tuning layer over the same intermediate representation: eleven lenses over the project, direct tuning knobs, and agent-scoped structural changes. The human edits intent and feel; the agent edits implementation; the viewport is a witness. Graphs remain one lens among many, not the primary authoring surface. - AI agents manipulate structured primitives — entities, components, graphs, and assets through the same programmatic command surface the editor calls internally, never through opaque code generation or simulated mouse clicks.
This only works if there is one canonical, typed, serializable representation of "what the game does" underneath all four — the 3JSE Gameplay IR (see GAMEPLAY_IR.md). That single decision is the architectural spine the rest of this design hangs from.
Assemble first
3JSE does not reinvent wheels. The Three.js ecosystem is full of brilliant wheel engineers — dreaming, building, and maintaining wheels for generations — and every wheel we bolt on instead of re-forging is one less thing we update forever. The operating rule: adopt → wrap → build, in that order, and build only when nothing good exists. Three.js itself is the renderer wheel. The Owen pantheon is the water/foliage/flora/terrain wheels, vendored at pinned commits and wrapped as @3jse/* packages. The license notebook (packages/vendor/licenses.json) records every adopted part, and the update tracker (tools/vendor-update.mjs) tells us which wheels have rolled forward — bumping a pin is a deliberate adoption decision, never an accident. What 3JSE builds itself is the part nobody else is building: the editor, the Gameplay IR, the AI command surface, and the glue that makes all those wheels one machine. This is the strategy, not a phase — see VENDOR_INTEGRATIONS.md.
Non-goals
- 3JSE is not a Three.js fork. Three.js stays a normal, upgradable dependency. 3JSE does not vendor it, patch it, or assume private internals. If a project outgrows 3JSE's abstractions, it can drop to raw Three.js at any layer without losing the ability to update Three.js itself.
- 3JSE is not an Unreal clone. Where Unreal's design is excellent (Blueprints' expressiveness, a real content browser, a construction/runtime script duality), 3JSE preserves the capability, not the implementation. Where Unreal is carrying twenty years of C++ legacy (a hard visual/code boundary, an opaque binary project format, an editor that assumes a beefy local workstation), 3JSE deliberately does better.
- 3JSE is not chasing Unreal's rendering ceiling. Nanite-class virtualized geometry and Lumen-class global illumination are not the fight this engine picks in its first several years. WebGPU compute and Three.js's rendering roadmap set the ceiling; 3JSE's job is everything Unreal has besides the renderer.
- 3JSE does not assume every game is a giant open world, and does not assume every game is a tiny arcade demo either. The world/level system (
WORLD_SYSTEM.md) is built to be equally unopinionated about both.
Who this is for
- A Three.js developer today who is manually building a scene hierarchy UI, an undo stack, and a component system for the third time across three projects.
- A designer or artist who can think in Blueprint/node-graph terms and wants that expressiveness without needing Unreal installed, a C++ toolchain, or a five-minute editor boot time.
- A studio that wants instant web distribution — a shareable URL instead of a multi-gigabyte installer — without giving up a professional editor workflow.
- An AI agent (and the human directing it) that needs a game engine whose state can be inspected, queried, and safely mutated through a stable API, not one that has to be operated by simulating a mouse.
What success looks like
A developer with Blueprint, Verse, Unity-component, or Godot-node experience can open 3JSE and be productive within a day, because the underlying concepts — entities, components, typed graphs, prefabs — map cleanly onto what they already know. A game built in 3JSE is, at every layer, a normal, readable, Git-diffable software project — never a proprietary binary blob that only the editor can open. And an AI agent, given a one-sentence request, can operate 3JSE through the exact same primitives a human uses, produce a working change, verify it by actually running the game, and hand back something the human can keep editing normally — because "AI-native" in 3JSE means legible to both the AI and the human, not opaque to one of them.
ArchitectureARCHITECTURE.md
Design principles
- Three.js is a dependency, never a fork. 3JSE imports
threelike any other npm package, pins a compatible range, and upgrades it like any other dependency. No subsystem reaches into Three.js internals that aren't part of its public API. Where 3JSE needs something Three.js doesn't expose, it composes around Three.js (a parallel data structure, a wrapper), not inside it. - One IR, many frontends. Gameplay logic authored via TypeScript, 3JSE Graph, or an AI agent all compile to the same 3JSE Gameplay IR (
GAMEPLAY_IR.md). No subsystem is allowed to become a parallel, opaque execution engine. - Everything the editor can do, code can do. Every editor mutation — moving an entity, adding a component, wiring a graph node — has a corresponding call in the runtime's command API. The editor is a GUI for that API, not a separate authority. This is what makes the Agent API (
AI_AGENT_API.md) possible without inventing a second interface. The community Babylon.js Editor is the cautionary example this principle exists to rule out: a capable GUI built on top of a code-first engine that was never designed to expose an equivalent command API, so the editor and hand-written code inevitably drift into two only-partially-overlapping authorities over the same scene. 3JSE's editor panels don't get a privileged path — Physics, 3JSE Graph, the Debugger, and the Agent Panel all read and write the sameWorld/Level/IRGraphobjects a hand-written script would, through the identical calls, which is what keeps this from becoming that failure mode by construction rather than by discipline. - Plugins are first-class, not an afterthought. The engine you get by default is a curated set of official plugins on top of a small core. A third-party physics engine, terrain system, or gameplay package installs the same way an official one does. See
PLUGIN_ARCHITECTURE.md. - Projects are software projects. Scenes, prefabs, graphs, and settings are readable, deterministically-serialized files under version control — never a proprietary binary the editor is the only thing that can open. See
PROJECT_FORMAT.md. - Adding a feature should touch a small, predictable set of places — a command, a data schema, a runtime system, an editor panel, inspector fields, optional graph nodes — not a scavenger hunt across the codebase. This is a load-bearing constraint, not a nicety: 3JSE expects a large share of its own future development to be done by coding agents, and an architecture that can't be safely extended by an agent won't stay coherent as it grows.
The ten layers
┌─────────────────────────────────────────────────────────────────┐
│ 9 Project / Templates starter kits, genre scaffolding │
│ 8 Build + Deployment play → publish, web/desktop/XR │
│ 7 Plugin / Package System @3jse/* registry & sandboxing │
│ 6 AI Development Layer Agent API, agentic loop │
│ 5 Visual Authoring (Atlas) node authoring → 3IR │
│ 4 Gameplay Framework CharacterController, Inventory… │
│ 3 Asset Pipeline import, analyze, optimize │
│ 2 Editor viewport, panels, PIE │
│ 1 Runtime world/level tick, ECS, systems │
│ 0 Three.js (dependency) scene graph, WebGPU renderer │
└─────────────────────────────────────────────────────────────────┘Layers 0–1 are the only ones a shipped game strictly needs at runtime. Layers 2, 3, 6, 7, 9 are development-time (editor, tooling, AI, packaging, scaffolding) and do not ship in the game bundle. Layer 5 (3JSE Graph) is development-time as authoring, but its compiled output (plain functions, layer 1) does ship — the graph editor itself never does.
0 — Three.js (dependency)
Object3D hierarchy, cameras, the WebGPU/WebGL2 renderer, TSL, loaders, AnimationMixer. 3JSE treats Object3D as the transform component — see ENTITY_COMPONENT_MODEL.md — rather than inventing a competing scene graph. Any existing Three.js example or library that operates on Object3D keeps working inside a 3JSE project.
1 — 3JSE Runtime (@3jse/runtime)
Owns the World → Level → Entity/Component model, the archetype/system scheduler, the resource/service registry, and the render/physics/audio tick order. Ships as a standalone package usable with zero editor dependency — a 3JSE game is a normal TypeScript/JS app that imports @3jse/runtime and three. Detailed in RUNTIME.md, ENTITY_COMPONENT_MODEL.md, GAMEPLAY_FRAMEWORK.md.
2 — 3JSE Editor
A desktop-class, dockable GUI (viewport, hierarchy, inspector, content browser, graph editor, profiler, etc.) that edits a live Runtime instance in-process — Edit/Play/Pause/Inspect/Modify/Resume without a rebuild. Ships as a Tauri (or browser) application; games it produces are ordinary web builds with zero editor dependency. Detailed in EDITOR.md.
3 — Asset Pipeline
Import, analysis, and optimization for meshes, textures, audio, animation. Runs both inside the editor (drag-and-drop) and headless (CI, CLI, agent-driven). Detailed in ASSET_PIPELINE.md.
4 — Gameplay Framework
The standard library of composable gameplay systems (CharacterController, Inventory, SaveGame, BehaviorTree, …) that every non-trivial game rebuilds from scratch otherwise. Ships as independent @3jse/* plugin packages on top of the Entity/Component model. Detailed in GAMEPLAY_FRAMEWORK.md.
5 — Visual Authoring (3JSE Atlas)
The authoring surface is 3JSE Atlas (3JSE_ATLAS_FULL_PLAN.md): semantic navigation, FeelSpec tuning, and agent-scoped editing over the same 3JSE Gameplay IR — the Blueprint/Verse alternative in which the human edits intent and feel, the agent edits implementation, and the viewport is a witness. The node-graph machinery of VISUAL_SCRIPTING.md remains underneath as the execution architecture (and one of Atlas's lenses), not the primary authoring surface.
6 — AI Development Layer
The Agent API and the observe → plan → act → verify loop that lets an AI agent operate the editor's own command surface. Detailed in AI_AGENT_API.md.
7 — Plugin / Package System
The @3jse/* package contract: how a subsystem (physics, terrain, water, networking, an editor panel, an importer) registers itself, what stability guarantees it gets, and how third-party packages become first-class. Detailed in PLUGIN_ARCHITECTURE.md.
8 — Build + Deployment
Play-button local run, Publish pipeline, and the target matrix (static web, PWA, desktop shell, mobile wrapper, XR). Detailed in BUILD_DEPLOYMENT.md.
9 — Project / Templates
Genre starter kits and the project scaffolding CLI/UI. Detailed in TEMPLATES.md, PROJECT_FORMAT.md.
Three more documents cut across these layers rather than owning one: GAMEPLAY_IR.md (the compiler architecture connecting layers 1, 5, and 6), 3JSE_ATLAS_FULL_PLAN.md (the semantic visual layer over the harness and layer 5's authoring surface), and VERSE_COMPATIBILITY.md (an evaluation of how far to lean on Verse-shaped concepts in layer 5).
Data flow: how the layers actually talk
Editor (2) ───┐
│ same command API
Agent (6) ────┼──▶ Runtime command surface (1) ──▶ World/Level state
│ ▲
3JSE Graph(5) ─┘ │ compiles to
3JSE Gameplay IR ◀── TypeScript source (hand-written)The editor, the AI layer, and the compiled output of 3JSE Graph are three callers of the same runtime command surface — createEntity, addComponent, setProperty, and so on (full list in AI_AGENT_API.md). None of them has a privileged, undocumented path into the World that the others lack. This is what keeps "the editor did it," "the AI did it," and "a script did it" indistinguishable in the resulting project state and undo history.
Package map
@3jse/runtime world/level/ECS scheduler, resource registry
@3jse/ir 3JSE Gameplay IR types, validator, JS/TS emitter
@3jse/graph 3JSE Graph node model, graph→IR compiler, debugger protocol
@3jse/editor editor shell, panel framework, docking
@3jse/agent Agent API, tool schemas, observe/verify harness
@3jse/assets importers, analyzers, optimizers
@3jse/cli project scaffolding, headless build, headless run
@3jse/physics-rapier plugin: physics (default)
@3jse/physics-jolt plugin: physics (alternative)
@3jse/terrain plugin: heightfield/terrain
@3jse/water plugin: water rendering + buoyancy
@3jse/foliage plugin: instanced vegetation + painting
@3jse/networking plugin: replication
@3jse/nav plugin: navmesh + pathfinding
@3jse/ai-behavior plugin: perception + behavior trees
@3jse/ui plugin: retained-mode HUD/UI system
@3jse/character plugin: CharacterController + camera rig
@3jse/vehicle plugin: VehicleControllerEvery package above 1–7 is optional. A minimal 3JSE game can depend on nothing but @3jse/runtime and three.
Why this layering, specifically
Most of the risk in an engine like this is coupling risk, not rendering risk — the danger that the visual scripting system, the AI layer, and hand-written code quietly drift into three different ways of expressing "what the game does," at which point the editor stops being trustworthy for any of them. Putting the IR at the center (rather than treating the graph compiler as a private implementation detail of the graph editor, which is what most engines do) is the one structural decision that prevents that drift. Everything else in this document follows from protecting that decision.
3JSE RuntimeRUNTIME.md
@3jse/runtime is the only package a shipped game strictly depends on besides three. It owns the tick loop, the World/Level/Entity/Component model (fully specified in ENTITY_COMPONENT_MODEL.md), and the boundary where 3JSE's abstractions hand off to raw Three.js.
Relationship to Three.js
3JSE does not replace any Three.js concept that already works:
| Stays exactly Three.js | 3JSE adds around it |
|---|---|
Object3D hierarchy, transforms | Entity/Component data attached via a side-table keyed by Object3D |
WebGPURenderer / WebGLRenderer fallback | A render-graph/pass ordering layer, quality tiers |
Camera, Light, Material, Mesh | Component wrappers that make these inspectable/serializable |
| TSL node materials | 3JSE's material graph compiles into TSL, not around it |
AnimationMixer, AnimationClip | Blend trees and state machines layered on top (ANIMATION.md) |
Loaders (GLTFLoader, KTX2Loader, …) | The asset pipeline wraps them with analysis and caching |
A project can always drop one level down: get the raw Object3D for any entity and hand-write Three.js against it. Nothing in 3JSE requires going through its own API exclusively — this is the release valve that keeps 3JSE from becoming a second thing to fight when Three.js already does something well.
The tick loop
requestAnimationFrame / fixed-step accumulator
│
▼
1. Input sampling (@3jse/runtime input resource)
2. Fixed-step systems (physics, gameplay logic — deterministic order)
3. Variable-step systems (camera, animation blending, particles)
4. 3JSE Graph tick (compiled Behavior functions, event dispatch)
5. Render systems (culling, LOD select, render-graph submit)
6. Late/post systems (UI layout, audio listener update)Systems declare which stage(s) they run in and which component archetypes they read/write; the scheduler topologically sorts by declared data dependencies and parallelizes across Web Workers where dependencies allow (see PERFORMANCE.md). Fixed-step logic runs on an accumulator decoupled from display refresh rate so gameplay and physics stay deterministic-per-machine regardless of frame rate.
World and Level
A World is the runtime container for one or more loaded Levels (see WORLD_SYSTEM.md for streaming/sectors/persistence). At the runtime layer, World is deliberately thin: a registry of loaded Levels, the global resource table, and the system scheduler. All gameplay state lives in Levels and their Entities.
Resource and Service registry
Not everything is an Entity. Global, non-spatial state — the input manager, the audio mixer, the save-game service, a game-mode singleton — is a Resource, registered once on the World and injected into any system that declares a dependency on it. A Service is a Resource that exposes an imperative method surface in addition to data (e.g. SaveService.save()), for the cases where "just data + systems" is more indirection than the problem needs. Both are plain, inspectable objects — the editor lists registered Resources/Services in a Project Settings panel the same way it lists components on an entity.
Hot reload
Because compiled Behaviors (from TypeScript or 3JSE Graph) are registered in the scheduler as named function references rather than baked into entity construction, hot-reload is a function swap, not an entity teardown/rebuild. Editing a system's TypeScript source, or recompiling a 3JSE Graph, replaces the registered function and the next tick picks it up — no scene reload, no lost state. This is the mechanism behind Edit → Play → Pause → Inspect → Modify → Resume (EDITOR.md): a paused game's entities and their live values are untouched by a code or graph edit; only the logic driving them changes underneath them.
Determinism posture
Fixed-step gameplay/physics is deterministic per machine (same build, same OS/GPU, same inputs → same result), which is sufficient for save/replay and single-machine time-travel debugging (AI_AGENT_API.md, EDITOR.md). It is explicitly not claimed to be cross-platform bit-exact — floating point and physics engine behavior vary across hardware/drivers. Lockstep multiplayer that requires cross-machine determinism is out of scope for the runtime's default execution model; NETWORKING.md uses state replication instead, precisely to avoid depending on a guarantee the web platform can't reliably give.
Proven in the reference games (REFERENCE_GAMES.md): MANDELHOP builds its whole difficulty model on this posture — constant-velocity lanes, seeded per-run generation, render-only visuals, and collision on grid math on the same numbers the player sees, so every death is fair and replays reproduce; its time powers all route through one clock (worldDt = dt · scale), and its 12 Hz ghost replay is recorded state, nothing more. DAMN BEAVERS extends the same posture to counterfactual replay — fork/alter/diff over snapshots. The runtime's fixed-step accumulator with a time-scale is exactly the mechanism those games hand-build.
@3jse/replay (ROADMAP.md Phase 5) is this claim exercised for real, not just asserted: it records the exact InputManager press/release edges and the tick they happened on, then replays them against a freshly-built, identical starting World. Its own test suite proved this holds precisely down to a real, load-bearing subtlety — replaying without calling InputManager.endFrame() on every tick (this doc's tick loop stage 1) leaves edge-triggered reads like wasActionPressed("jump") true for extra ticks, producing a fully reproducible wrong result that looks exactly like non-determinism until traced back to the missing call. With that contract actually followed, per-machine determinism holds precisely through @3jse/physics-rapier's Rapier/WASM simulation too, not just plain gameplay Systems — confirmed by test, not assumed from this paragraph's own claim.
Headless mode
The runtime has no hard dependency on a DOM or a visible canvas. It can boot against an offscreen canvas / software fallback for CI, automated tests, and the AI Agent API's runGame / inspectScene verification loop (AI_AGENT_API.md), producing console output, a frame capture, and a performance report without a visible window. This is a first-class supported mode, not a hack — the CLI (@3jse/cli) exposes it directly as 3jse run --headless.
This mode is already proven in production, not speculative (REFERENCE_GAMES.md): 3JSURF's mechcheck.mjs runs wave + surfer with no renderer/canvas/DOM and asserts its numbers match the rendered build; ZENDRIVE's npm test runs full races headless; DAMN BEAVERS' simulation tests run the entire systemic sim headless — its constitution states it outright: "the renderer, animation system, UI, audio, particles, and Chronicle observe simulation state; they do not own simulation truth." The discipline those projects impose by convention (gameplay logic must be renderer-independent; a stub scene must suffice) is exactly what the runtime enforces by construction here.
3JSE Object ModelENTITY_COMPONENT_MODEL.md
The decision
3JSE uses a hybrid Actor/Component authoring model backed by ECS-style storage — not pure ECS, not classic OOP inheritance, and not a thin wrapper that just renames Object3D.
The reasoning, worked through against the optimization targets the model has to satisfy simultaneously:
- Pure ECS (à la bitECS/Bevy) wins on performance and query composability, but a bare ECS has no natural unit that corresponds to "a thing in the level" for an inspector, a prefab, or a sentence like "the shark has a perception component." Entities are anonymous integers; meaning lives in which systems happen to query them. That is hostile to an editor UI and to AI legibility — the explicit design target from
VISION.md. - Classic OOP actor hierarchies (deep inheritance,
Player extends Character extends Actor) are exactly what an inspector and a beginner expect, but they serialize badly, fight hot reload (redefining a class invalidates live instances), and degrade badly at scale (virtual dispatch, poor cache locality, fragile diamond-inheritance workarounds). - Unity's GameObject + MonoBehaviour and Godot's Node models split the difference and are what most working game developers already think in. That mental model — a named, spatial "thing" with an attached bag of typed components — is what 3JSE keeps at the authoring surface, while storing the data underneath in ECS-style archetype tables for the systems that actually iterate over thousands of instances per frame.
Concretely: an Entity behaves like an Actor/GameObject/Node to a human or an AI reading the project, and like an ECS row to the scheduler at runtime. Nothing about this is a compromise between the two models — it's a deliberate separation of authoring ergonomics from storage layout, which is exactly the kind of separation that lets one change (say, a future storage optimization) happen without ever being visible to the other.
Vocabulary
| Term | What it is |
|---|---|
| World | The runtime container for all loaded Levels, the Resource/Service registry, and the scheduler. One per running game. |
| Level (aka Scene) | A serializable unit of content — a set of Entities plus level-local settings (environment, lighting). A World can have several Levels loaded at once (WORLD_SYSTEM.md). |
| Entity | An addressable, named "thing" in a Level. Has a stable ID, optionally a Transform (backed by an Object3D), and a set of Components. Directly analogous to an Unreal Actor, a Unity GameObject, or a Godot Node. |
| Component | Typed data attached to an Entity — Health, CharacterController, Inventory. Pure data by convention; behavior lives in Systems or Behaviors, not component methods, so components stay serializable and diffable. |
| System | Logic that runs each tick over every Entity matching a component query — the ECS half of the model. Hand-written (TypeScript) or generated (compiled 3JSE Graph). |
| Behavior | A convenience wrapper: a Component that also names a Graph or a small TS function to run for that entity specifically, registered into the scheduler as a per-entity-scoped System under the hood. This is the "attach a script to this one object" workflow every engine needs, expressed without inventing a second execution model. |
| Prefab | A serialized Entity (with children) usable as a template. Instances track their source Prefab and can override specific fields (a Prefab variant), matching Unreal's Blueprint-instance and Unity's Prefab-override model. |
| Resource | Global, non-spatial data not owned by any single Entity (input state, audio mixer settings). |
| Service | A Resource that also exposes an imperative API (SaveService.save()) alongside its data. |
Storage
Components of the same type are stored contiguously (archetype/SoA storage), so a System querying (Transform, Velocity) iterates a tight, cache-friendly array rather than chasing pointers through heterogeneous objects — this is the specific mechanism that makes "editor-friendly" and "fast at 10,000 instances" compatible rather than contradictory. Adding or removing a component moves an Entity between archetypes; this is a well-understood, bounded-cost operation in every ECS implementation 3JSE draws from, not a novel risk.
Object3D is treated as the storage for the Transform component specifically — position, rotation, scale, parenting all continue to live on the Three.js scene graph exactly where every existing Three.js library expects to find them. An Entity without a Transform (a game-mode manager, a spawn director) simply has no associated Object3D and is not part of the render scene graph at all.
Why this is legible to an AI (and a human skimming a diff)
The whole point of choosing this shape is that a serialized Entity reads as a sentence, not a call stack:
{
"name": "Player",
"components": {
"Transform": { "position": [0, 1, 0] },
"CharacterController": { "maxSpeed": 6, "jumpHeight": 1.4 },
"Health": { "current": 100, "max": 100 },
"Inventory": { "slots": 8, "items": [] },
"AnimationController": { "graph": "player_locomotion.3jgraph" },
"GrapplingHook": { "range": 25, "reelSpeed": 12 }
}
}An AI agent (or a teammate) inspecting the project via scene.query (AI_AGENT_API.md) sees exactly the sentence from VISION.md: "Player contains CharacterController, Health, Inventory, AnimationController, and GrapplingHook." There is no arbitrary imperative code to trace through to reconstruct that fact — it's the literal shape of the data. Adding a feature to the Player is, structurally, adding or editing a component entry, not hunting through the codebase for where "player stuff" happens to live this month.
Serialization, hot reload, and networking fall out of the same choice
- Serialization: a Component is required to be representable as plain JSON-compatible data (primitives, arrays, typed-array-backed vectors, references to other Entities/Assets by stable ID). This is enforced by the component schema system, not left to convention — a Component type declares its fields' types once, and the editor's inspector, the serializer, and the network replicator all derive their behavior from that single schema.
- Hot reload: because Systems are registered by name/reference and Components are plain data, redefining a System's logic (via TS edit or Graph recompile) never invalidates existing Entity data — see
RUNTIME.md. - Networking: replication (
NETWORKING.md) is just "which Components, on which Entities, does this client need diffs for" — a direct consequence of Components being the atomic unit of state, not an afterthought bolted onto an OOP object graph. - Editor inspection: the Inspector panel (
EDITOR.md) is generated directly from each Component's schema — there is no per-component custom UI to hand-write unless a component wants a bespoke editor experience (a curve, a gradient), in which case it opts in explicitly.
What this model deliberately does not do
It does not claim to be the fastest possible ECS — a hand-tuned Bevy/bitECS-style engine with no authoring-ergonomics constraints will out-iterate it in a synthetic benchmark. It optimizes for the actual bottleneck in practice, which is how long it takes a human or an AI agent to understand and safely change what an entity does, while keeping the storage layer fast enough that this doesn't become a real-world performance ceiling (target budgets in PERFORMANCE.md).
World SystemWORLD_SYSTEM.md
The deliberate non-assumption
3JSE does not assume every game is a giant seamless open world, and does not assume every game is a single tiny scene either. The World system is built so a tiny arcade game, a linear level-select game (Crash Bandicoot-style), a sector-based game (KOTOR-style discrete zones with loading transitions), a large streamed environment, and an interconnected multi-space project (Roblox/UEFN-style hub-and-experiences) are all the same underlying mechanism configured differently — not five separate features.
Vocabulary recap and extension
ENTITY_COMPONENT_MODEL.md defines World (the runtime container) and Level (a serializable unit of Entities). This document specifies how multiple Levels compose:
- Sublevel: a Level that streams in/out as a unit alongside a persistent base Level — the standard technique for both "large environment split into loadable chunks" and "hub level with an optional decoration layer."
- Sector: a named group of sublevels that stream together, with defined transition triggers (volume-based, portal-based, or explicit loading-screen). This is what a KOTOR-style discrete-zone game configures: each planet/area is a sector, transitions are explicit loads rather than seamless streaming.
- Portal: a paired trigger volume between two Levels/sectors — either a hard transition (loading screen) or, where budgets allow, a seamless streamed handoff (both sides loaded briefly, camera crosses, far side unloads).
- World Partition (large open worlds): automatic grid-based sublevel generation from a single authored large Level, streamed by camera-distance, analogous to Unreal's World Partition but implemented as an authoring-time cell splitter over ordinary sublevels rather than a distinct runtime concept — a large-world project is still "a base Level plus streamed sublevels," just with the sublevel boundaries computed instead of hand-drawn.
- Persistent World State: state that survives a Level unloading — inventory, quest flags, defeated-enemy markers — lives on
@3jse/save's tagged-Component persistence (GAMEPLAY_FRAMEWORK.md) keyed by a stable id, not on the Level itself, specifically so it survives the Level being unloaded and reloaded (or never having been loaded again at all, for a "defeated enemies don't respawn" pattern).
How each use case configures the same mechanism
| Game shape | Configuration |
|---|---|
| Tiny arcade game | One World, one Level, no streaming, no sectors |
| Linear level-select (Crash Bandicoot-style) | One World, N Levels, hard transitions between them via a level-select Resource, no sublevel streaming needed |
| Sector-based (KOTOR-style) | One World, sectors = discrete zones, portal-triggered hard transitions with a loading Level shown during the swap |
| Large streamed environment | One World, one authored Level auto-split into a World Partition grid of sublevels, camera-distance streaming |
| Interconnected multi-space (Roblox/UEFN-style) | One persistent "hub" World/Level plus independently-loadable "experience" Levels, each with its own Entities but sharing player-identity/inventory state via @3jse/save's cross-Level persistence |
Multiple open Levels in the editor
The Editor (EDITOR.md) supports multiple Levels open simultaneously — the same runtime capability that enables sublevel streaming lets a level designer edit a sublevel in isolation or in the context of its neighbors loaded read-only around it, without a separate "isolation mode" needing to be built as a distinct feature.
Input contexts
Per-Level (or per-sector) input context stacking is part of the World system rather than a separate system: entering a vehicle, a dialogue, or a menu pushes an input context that remaps or blocks actions without the underlying InputManager (GAMEPLAY_FRAMEWORK.md) needing per-game special-casing — a natural fit for World-level transitions (entering a sector-specific minigame area, for instance) as well as gameplay-state transitions within one Level.
3JSE Gameplay IR (3IR)GAMEPLAY_IR.md
This is the most important document in the design package. Every other claim in VISION.md — that visual scripting, hand-written TypeScript, and AI generation are "the same program" — is only true because of the architecture described here. Get this wrong and 3JSE Graph becomes exactly the "isolated universe" VISUAL_SCRIPTING.md is explicitly told not to become.
The compiler-architecture framing
Treat gameplay authoring the way a real compiler treats source languages: multiple frontends, one intermediate representation, multiple backends.
FRONTENDS IR BACKENDS
────────── ────── ────────
TypeScript adapter ──┐ ┌──► JS/TS emitter (ships in game)
3JSE Graph frontend ──┼──► 3JSE Gameplay IR ──┼──► Interpreter (editor live-debug)
AI structured-gen ──┤ (3IR) ├──► WASM emitter (hot-path opt-in)
frontend │ │
(future) Verse frontend ─┘ └──► Static analyzer (lint/AI context)- TypeScript adapter: hand-written code that calls 3JSE's runtime APIs is parsed into 3IR for tooling purposes (cross-referencing, the Agent API's project understanding, and optional bidirectional graph view —
VISUAL_SCRIPTING.md§Bidirectional editing below). It is not forced to round-trip through 3IR to execute — see "What actually executes," below. - 3JSE Graph frontend: the node graph compiles to 3IR directly; this is its only execution path (
VISUAL_SCRIPTING.md). - AI structured-generation frontend: an AI agent emits 3IR nodes directly through the Agent API's
circuits.write-equivalent tool, constrained by the IR's own type system rather than free-form code generation (AI_AGENT_API.md). - Verse frontend (future, optional): evaluated in
VERSE_COMPATIBILITY.md; not required for 3IR to be useful today.
What 3IR actually is
3IR is a small, typed, JSON-serializable node-graph format — not the same thing as "abstract JavaScript," and not the same thing as "abstract Blueprint." It's deliberately narrower than a general-purpose AST because gameplay logic is a narrower problem than general-purpose programming: it needs events, typed data flow, ordered side effects, branching, loops, async waits, and calls into the engine's Component/Resource API — and does not need, say, arbitrary closures over the JS module graph or dynamic eval.
// simplified 3IR node shape
type IRNode =
| { kind: "event"; id: string; name: string; params: IRType[] }
| { kind: "pure"; id: string; op: string; inputs: IRRef[]; outputType: IRType }
| { kind: "call"; id: string; target: EngineAPIRef; args: IRRef[]; next: IRRef }
| { kind: "branch"; id: string; cond: IRRef; then: IRRef; else: IRRef }
| { kind: "loop"; id: string; over: IRRef; body: IRRef; next: IRRef }
| { kind: "await"; id: string; signal: IRRef; next: IRRef }
| { kind: "variable"; id: string; scope: "local" | "component" | "resource"; type: IRType };
type IRRef = { node: string; pin?: string }; // wire = an edge between two node pinsEvery IRRef is typed (number, vector3, EntityRef, ComponentRef<Health>, string, boolean, domain enums, and struct types generated from Component schemas — ENTITY_COMPONENT_MODEL.md). Type errors are caught at the IR level, before any backend ever sees the graph — which is what lets both the Graph editor and an AI agent get fast, structural feedback ("this pin wants a number, you connected a string") instead of a runtime TypeError three layers downstream.
Pure nodes (no side effects, no next) are evaluated on demand and can fan out to multiple consumers safely — this maps directly to 3JSE Graph's pure/impure pin distinction (VISUAL_SCRIPTING.md). Nodes with a next pin form the explicit execution order — this is 3IR's "exec wire," and it is what keeps ordering unambiguous, unlike a plain expression tree.
What actually executes
Two backends consume the same 3IR, deliberately:
- Interpreter (editor / live-debug mode). A tree-walking evaluator over the IR graph, instrumented to report every intermediate value back to the editor — this is what powers active-wire visualization, breakpoints, and watches in
VISUAL_SCRIPTING.md. Slower, but every frame is fully inspectable, which is the correct tradeoff while iterating. - JS/TS emitter (shipping mode). The same IR compiles ahead-of-time to a plain function — readable, formatted TypeScript, not minified/opaque output — registered into the Runtime scheduler exactly like a hand-written System (
RUNTIME.md). This is what ships in the built game: no interpreter, no IR walking, no visual-scripting runtime tax at all. A WASM emitter is a defined extension point for the rare hot path (large-scale particle/crowd logic) that profiles as needing it — deliberately not the default backend, because most gameplay logic is not the bottleneck a WASM compile target is worth the complexity for.
Hand-written TypeScript never has to round-trip through 3IR to run — it already is valid input to the JS/TS pipeline. It participates in 3IR voluntarily, when a developer wants graph-view/AI-legibility for code they wrote by hand (next section).
Bidirectional graph ↔ code editing
This is the mechanism, not just the feature:
- The TypeScript adapter frontend parses a constrained, recognizable subset of TS — calls into the Runtime/Component API,
if/for/awaitin patterns the IR can represent, no arbitrary metaprogramming — into 3IR. Code outside that subset is not a bug to fix; it's the intended boundary (next section). - The JS/TS backend emits from 3IR back into that same recognizable subset, with a source map: every emitted line carries a reference back to the originating IR node ID, and every IR node carries a reference back to the graph node that produced it (or
nullif it came from hand-written code). - A graph edit recompiles to new text in the mapped region only; a text edit inside the mapped region re-parses to a new IR subgraph and the Graph editor's view updates live. This is the same category of problem as source maps between TypeScript and emitted JS in every modern web toolchain — 3JSE applies the identical idea one level up, between a graph and its emitted code, instead of inventing a new synchronization mechanism.
The honest limit: the moment hand-written code leaves the recognized subset — a closure that captures unrelated module state, a control-flow shape the IR can't represent, a call into something outside the Runtime API — that region stops round-tripping and the corresponding graph view shows it as an opaque "code" node: a black box with typed inputs/outputs (inferred from the function's signature) that the graph can still wire into, but not decompose visually. This mirrors Unreal's Blueprint/C++ boundary and Verse's own native-function escape hatch, made visible in the graph instead of silently breaking sync. VISUAL_SCRIPTING.md covers the editor-facing behavior of this boundary; this document is why it's structurally the only honest option.
Why one IR instead of "the graph just emits JavaScript"
The tempting shortcut — have the graph editor emit JS text directly, the way most visual-scripting-on-the-web tools do — is rejected deliberately. It would satisfy "compiles to clean JS" (user requirement) but fail everything else 3IR is required to do:
- AI structured generation needs a typed target it can validate against before anything executes — emitting text directly means an AI's mistakes surface as runtime or syntax errors instead of IR-validation errors, exactly the failure mode
AI_AGENT_API.md's verify loop exists to avoid upstream of. - Live debugging (active-wire values, step, breakpoints) needs a structured graph to instrument at runtime — you cannot cleanly breakpoint "a line of generated JS" and highlight the originating node without the IR-to-source map this section describes.
- Bidirectional editing needs a common structural form both graph and code can losslessly (within the recognized subset) convert to and from — text-to-text diffing between two independently-generated JS files does not give you that.
- A future Verse frontend (
VERSE_COMPATIBILITY.md) needs a target that isn't JavaScript's syntax specifically — an IR is frontend-agnostic by construction; "compile to JS text" is not.
3IR is more upfront design work than "graph emits JS," and it is the reason 3JSE Graph does not become the isolated universe the brief explicitly warns against.
3JSE GraphVISUAL_SCRIPTING.md
Superseded as the authoring UI by 3JSE Atlas (
3JSE_ATLAS_FULL_PLAN.md). Atlas replaces the Blueprint-style node-wiring canvas with semantic navigation, FeelSpec tuning, and agent-scoped editing — the graph becomes one of Atlas's lenses rather than the primary authoring surface. Everything in this document about the machinery — the 3IR compiler, the JS/TS backend, bidirectional graph↔code, the debugger — remains the execution architecture underneath Atlas. A human rarely wires nodes by hand anymore: they navigate meaning, tune feel, and let the agent (or a direct edit) produce the graph.
3JSE Graph is 3JSE's visual scripting system — a node-graph authoring frontend for 3JSE Gameplay IR (GAMEPLAY_IR.md), not a separate execution engine. Every capability below exists because it's expressible in 3IR; there is no 3JSE Graph feature that hand-written TypeScript can't also express, and no TypeScript-callable engine API that a graph node can't also call. That symmetry is deliberate — it's what keeps this from becoming "its own isolated universe," which the design brief calls out as the one thing to avoid above all else.
Node families
| Family | Examples |
|---|---|
| Events | BeginPlay, Tick(dt), OnCollision, OnInput, custom Events (fan-out, multiple listeners) |
| Flow control | Branch, Sequence, ForLoop, WhileLoop, Gate, Delay, Switch |
| Pure functions | math/vector/quaternion ops, string/array ops, curve sampling — no exec pins, evaluate on demand |
| Impure functions | SpawnEntity, DestroyEntity, AddComponent, PlaySound — ordered, exec-pin driven |
| Data | Get/Set Variable, GetComponent, typed Entity/Asset references |
| Async | Timer, Tween, Await Signal, coroutine-style yield |
| State machines | Nested sub-graph per state, guarded transitions, entry/exit events |
| Interfaces | Typed contracts a graph can implement/require (see below) |
| Composition | Graph Functions (reusable, callable subgraphs) and Graph Macros (inline-expanded reusable fragments) — the direct equivalent of Blueprint Functions/Macros |
| Behavior Tree | Sequence/Selector/Decorator/Leaf nodes, sharing the blackboard model with @3jse/ai-behavior |
| Animation | Blend, state-transition, and event-sync nodes feeding ANIMATION.md's runtime |
| UI logic | Bind, event-listen, and dispatch nodes against @3jse/ui widgets |
| Networking | IsServer/IsClient guards, RPC-call and RPC-receive nodes (NETWORKING.md) |
| Debug | Print, Breakpoint, Watch |
Typed pins throughout: a pin's type comes directly from 3IR's type system (GAMEPLAY_IR.md), so an incompatible connection is rejected at wire-creation time in the editor, not discovered at runtime.
Graph scopes
- Event Graph — per-entity or per-Behavior, the primary gameplay-logic surface (the equivalent of a Blueprint's Event Graph).
- Construction/editor-time script — runs in the editor as values change (placing/tuning an entity), not during Play — for procedural setup that should be visible while authoring, not just at runtime.
- Graph Function / Macro — reusable, versioned, shareable as a package (
PLUGIN_ARCHITECTURE.md), callable from any Event Graph. - Level (global) Graph — attached to a non-spatial "level logic" Entity for game-mode-scoped logic, the equivalent of Unreal's Level Blueprint.
- Animation Graph and Behavior Tree — specialized node families operating over the same 3IR core, so debugging, breakpoints, and the compiler pipeline are shared rather than reimplemented per graph type.
Debugging
All of the following are properties of the interpreter backend described in GAMEPLAY_IR.md, not bespoke visual-scripting-only tooling:
- Active-wire visualization — every wire renders its last-evaluated value live during Play, because the interpreter reports every intermediate value by construction.
- Breakpoints / step — pause the scheduler at a specific IR node; step node-by-node or resume; works identically whether the node came from a graph or from the TypeScript adapter frontend.
- Watches — pin a variable or component field to a persistent panel, independent of which node graph currently references it.
- Execution history — a scrollable log of the last N ticks' fired events and branch outcomes, for "why did this happen three frames ago" debugging without needing to have had a breakpoint set in advance.
- Performance timing — per-node cost shown inline on hover, and per-graph cost in the Profiler (
PERFORMANCE.md), so a slow Behavior shows up by name instead of folding into an undifferentiated "script time" bucket.
Bidirectional editing, from the graph editor's side
GAMEPLAY_IR.md specifies the mechanism (a source-mapped 3IR round-trip through a recognized TypeScript subset); this is what it looks like in the editor:
- Any graph can be viewed as generated TypeScript in the Code Editor panel (
EDITOR.md), live-updated as the graph changes. - Edits made in the Code Editor, within the recognized subset, re-parse and update the graph view live in the other direction.
- The moment code leaves that subset, the corresponding region of the graph renders as an opaque Code node — typed inputs/outputs inferred from the function signature, wireable like any other node, but not decomposable back into primitive graph nodes. This is a visible, honest boundary rather than a silent desync, and it's the same tradeoff Unreal has lived with between Blueprint and C++ for over a decade — 3JSE's contribution is making the boundary a first-class, inspectable editor object instead of a wall between two separate tools.
Worked example
Player enters Trigger → Check HasKey → Play Door Animation → Play Sound → Disable Collision → Save Door State
[OnTriggerEnter(other)] ──► [Branch: other.HasComponent<Key>()]
│ true
▼
[PlayAnimation(door, "open")] ──► [PlaySound(doorOpenSfx)]
│
▼
[SetComponent(door, Collision.enabled = false)]
│
▼
[SaveService.setFlag("door_1_open", true)]Every node here is a thin wrapper over a Runtime/Component API call (ENTITY_COMPONENT_MODEL.md, GAMEPLAY_FRAMEWORK.md) — the compiled TypeScript output reads exactly like the hand-written version a programmer would write for the same behavior, because it's produced by the same JS/TS backend described in GAMEPLAY_IR.md, not a graph-specific code generator with its own conventions.
What this is not
3JSE Graph is not scoped to materials or shaders (that's RENDERING.md's Material Graph, a related but separate node system compiling to TSL, not 3IR) and it is not a simplified subset of "real" scripting held back from doing anything TypeScript can do — any Runtime API callable from TS is callable from a graph node, by construction, because both compile through the same IR and the same backend.
3JSE EditorEDITOR.md
What it is, physically
The Editor is a single-page application built on the exact same @3jse/runtime a shipped game uses, running the actual WebGPU viewport in-process rather than talking to a separate game process over IPC. It distributes three ways from one codebase:
- Browser — for quick edits, sharing a project link, and CI-driven visual review. No install.
- Tauri desktop app — the primary target for serious work: native file-system access, multiple windows, better GPU/driver access than a sandboxed browser tab, still just a webview around the same SPA.
- (Electron is a viable fallback for the desktop shell if a Tauri limitation forces it; the SPA itself doesn't care which shell hosts it.)
Games built with 3JSE never depend on the editor at runtime — the editor is strictly a development-time tool that reads and writes the same project files a hand-editing developer or a CI pipeline would (PROJECT_FORMAT.md).
UI implementation
The editor's own chrome (panels, docking, forms) is React, built on @galacean/editor-ui and @galacean/gui (MIT, engine-agnostic — peer-deps only on React/React-DOM, no dependency on Galacean's own renderer). This is an adopt decision, not a build decision, and it resolves a question this document previously left open: the panel/docking layer needed a real UI framework choice, and this library is purpose-built for exactly this problem rather than a generic component kit pressed into service. Concretely, it supplies the Inspector's hardest recurring pieces out of the box — ColorPicker, BezierCurveEditor (Animation Graph curve editing, ANIMATION.md), GradientSlider (fog/sky authoring, RENDERING.md; later the particle/VFX graph, ROADMAP.md Phase 5), ParticleSlider, AssetPicker (Content Browser drag-targets), and Vector/property form items for every Transform and Component field in ENTITY_COMPONENT_MODEL.md — accessible (Radix UI primitives underneath), themeable (built-in light/dark, restyled to 3JSE's own visual identity via its Stitches-based token system rather than forked), and independent of Galacean's engine entirely, so adopting it carries no coupling to another engine's rendering or scene-graph assumptions. Registered as a direct dependency of @3jse/editor rather than through the @3jse/vendor registry (VENDOR_INTEGRATIONS.md) — see that document's note on why editor-tooling adoptions and project-facing content plugins are handled differently.
Panel inventory
All panels are dockable/rearrangeable (a standard docking layout engine — tabs, splits, floating windows, saved layouts per project or per user). Panels are declared through the same panel-registration API third-party plugins use (PLUGIN_ARCHITECTURE.md) — there is no separate "built-in panel" privilege tier.
| Panel | Role |
|---|---|
| Viewport | Live WebGPU render of the active Level(s); gizmos, camera navigation, stats overlay |
| Hierarchy / Outliner | Entity tree for loaded Levels; Prefab instances visually distinguished; multi-select |
| Inspector | Component editors generated from schema (ENTITY_COMPONENT_MODEL.md); multi-edit diffing |
| Content Browser | Project assets — meshes, textures, audio, prefabs, graphs, materials — tagged/searchable/thumbnailed |
| Open Source | Browse the @3jse/vendor registry, preview license/stack/screenshot, install a Tier A plugin or stage a Tier B import; see VENDOR_INTEGRATIONS.md |
| 3JSE Graph Editor | Full-tab node canvas; see VISUAL_SCRIPTING.md |
| Material/Shader Graph | Node editor compiling to TSL; see RENDERING.md |
| Code Editor | Embedded TypeScript editing (Monaco-class: LSP, go-to-definition) for hand-written systems |
| Animation Tools | Timeline, state-machine/blend-tree editor, skeleton view; see ANIMATION.md |
| Terrain / Water / Vegetation | Heightfield sculpting, water volume placement, foliage painting; each owned by its plugin |
| Particle Editor | VFX graph (roadmap Phase 5, PLUGIN_ARCHITECTURE.md) |
| Physics / Collision Editor | Collider gizmos, constraint authoring; see PHYSICS.md |
| Navigation | Navmesh bake + visualization; see PLUGIN_ARCHITECTURE.md (@3jse/nav) |
| UI/HUD Editor | Retained-mode layout canvas for @3jse/ui |
| Environment Settings | Sky, fog, post-processing stack, lighting presets |
| Profiler | Frame timing by system/draw-call/GPU pass; see PERFORMANCE.md |
| Console | Runtime logs, warnings, errors — clickable to source (TS line or graph node) |
| Debugger | Breakpoints/step/watch across both TypeScript and 3JSE Graph (VISUAL_SCRIPTING.md) |
| Asset Dependency Viewer | Graph of what references what — "what breaks if I delete this" |
| Project Settings | Registered Resources/Services, quality tiers, input mappings, build targets |
| Input Mapping | Action/axis binding editor for InputManager |
| Packaging / Deployment | Build target selection, Publish flow; see BUILD_DEPLOYMENT.md |
| Source Control | Git status, diff, stage/commit, branch — operating directly on the readable project format |
Multiple Scenes/Levels can be open at once (WORLD_SYSTEM.md); the Hierarchy panel scopes to the active Level while allowing cross-level entity references where the World architecture permits.
Edit → Play → Pause → Inspect → Modify → Resume
This loop is the editor's central promise, and it is possible specifically because of two Runtime properties (RUNTIME.md):
- No process boundary. Play mode runs the same World in the same WebGPU context the edit view uses — entering Play does not serialize the scene out to a separate game process and back. Exiting Play can optionally keep the resulting state ("apply Play state to Level") instead of always discarding it.
- Hot-swappable logic. Pausing freezes the scheduler's tick advancement, not the World's data. Editing a Component value, a TypeScript system, or a 3JSE Graph while paused mutates live state or swaps a registered function (
RUNTIME.md's hot reload) — Resume continues the same simulation with the new logic or data in effect, not a fresh boot.
Concretely: pause mid-jump, open the Inspector, change jumpHeight from 1.4 to 2.2, resume — the character's current velocity and position are untouched, only the constant driving future jumps has changed. Pause during a bug, open the 3JSE Graph debugger, see exactly which branch fired last frame with real captured values on the wires, patch the graph, resume without restarting the level.
The Agent Panel
Not a floating chat widget — a permanent dock, because in the AI-native posture (VISION.md, AI_AGENT_API.md) most sessions use it. It shows the agent's current plan, the tool calls it's making against the same command API the rest of the editor uses, and a running diff of what's changed — reviewable and revertible through the same undo stack as a manual edit (ARCHITECTURE.md — "everything the editor can do, code can do" cuts both ways: everything the agent does is visible the same way a human's edit is).
Multi-scene, multi-user posture
3JSE does not build a live multi-user CRDT collaboration layer into the editor's first several years (see ROADMAP.md for where that's revisited). Instead, collaboration is Git-based, matching the "projects are software projects" principle in ARCHITECTURE.md: the project format is deterministically serialized and diff/merge-friendly (PROJECT_FORMAT.md), the editor's Source Control panel operates on it directly, and two people can work on the same project the way two people work on the same codebase — branches, PRs, merge conflicts a human resolves in a real diff, not a proprietary "who wins" resolution dialog. This is a deliberate, simpler bet than live co-editing: it costs nothing to build relative to a CRDT sync layer, and it's the collaboration model most of 3JSE's target developers already trust.
3JSE Gameplay FrameworkGAMEPLAY_FRAMEWORK.md
The Gameplay Framework is the standard library every non-trivial game otherwise rebuilds from scratch: character and vehicle movement, cameras, inventory, damage, save games, AI perception, and so on. It exists so that a new project — or an AI agent building one from a one-sentence prompt (AI_AGENT_API.md) — starts from working, composable systems instead of an empty World.
Design rule: composable plugins, not a monolith
Every system in this document ships as an independent @3jse/* package built entirely on the public Entity/Component/System API (ENTITY_COMPONENT_MODEL.md) — none of them get privileged runtime access the Gameplay Framework author has that a third-party package author doesn't. This is enforced, not just a style preference: it's the same constraint that makes third-party packages first-class in PLUGIN_ARCHITECTURE.md, and it's what stops the Gameplay Framework from calcifying into "the parts of the engine nobody can safely touch."
A game depends only on the systems it uses. Removing @3jse/inventory from a racing game's package.json removes the Inventory component schema, its systems, and its inspector/graph-node registrations — cleanly, because registration is explicit (PLUGIN_ARCHITECTURE.md), not a side effect of importing the framework as a whole.
Catalog
| System | Package | Provides |
|---|---|---|
| CharacterController | @3jse/character | Capsule movement, slopes, stairs, jumping, coyote time, ground/air state machine |
| VehicleController | @3jse/vehicle | Wheel raycasts or physics-wheel constraints, suspension, drivetrain, arcade/sim tuning modes |
| CameraRig | @3jse/character | Third-person spring-arm, first-person head, top-down, cinematic-follow presets |
| InputManager | @3jse/runtime (core) | Device-agnostic action/axis mapping (WORLD_SYSTEM.md covers per-level input contexts) |
| Inventory / Items | @3jse/inventory | Slot-based inventory Component, item Asset schema, stacking/equip events |
| Weapons | @3jse/combat | Hitscan/projectile firing Behaviors, ammo, cooldowns |
| Health / Damage | @3jse/combat | Health Component, damage-event pipeline, death/respawn hooks |
| Interaction | @3jse/interaction | "Interactable" component + prompt UI, range/line-of-sight checks |
| Quests / Objectives | @3jse/quests | Objective graph state, completion events, HUD binding |
| Dialogue | @3jse/dialogue | Branching dialogue asset format, speaker/UI binding |
| SaveGame / Checkpoints | @3jse/save | Snapshot of tagged Components to a save slot; checkpoint = named save trigger |
| Spawning / Pooling | @3jse/spawning | Spawn-point Components, ObjectPool resource for high-churn entities (projectiles, VFX) |
| AI Perception / Behavior Trees | @3jse/ai-behavior | Sight/hearing sensors, blackboard, behavior-tree nodes exposed to 3JSE Graph |
| Navigation | @3jse/nav | Navmesh bake, pathfinding queries, NavAgent component |
| Teams / Objectives / Scoring | @3jse/match | Team assignment, score resource, round/match state machine |
| Achievements | @3jse/achievements | Event-driven unlock tracking, platform-agnostic (maps to Steam/web later) |
| Localization | @3jse/localization | String table asset, LocalizedText component, runtime locale switch |
| Accessibility | @3jse/accessibility | Remappable input, subtitle/caption pipeline, colorblind-safe palette hooks in @3jse/ui |
| Multiplayer Replication | @3jse/networking | See NETWORKING.md |
| Cinematics | @3jse/cinematics | Timeline/sequencer runtime (editor tooling in EDITOR.md, PERFORMANCE.md/roadmap phase 5) |
Physics, animation, and audio are foundational enough to have their own documents (PHYSICS.md, ANIMATION.md, AUDIO.md) rather than a catalog row each.
How a system is "composable," concretely
Take Health as the minimal example. It is:
- A Component schema (
current,max,invulnerable) — inspectable, serializable, replicable, exactly as described inENTITY_COMPONENT_MODEL.md. - A System (
HealthRegenSystem, if regen is enabled) — plain logic over theHealtharchetype. - A set of events (
onDamaged,onHealed,onDied) — the seam other systems and 3JSE Graph hook into, rather than reaching intoHealth's internals. - A set of 3JSE Graph nodes (
Get Health,Apply Damage,On Died) — auto-registered from the Component/event schema (VISUAL_SCRIPTING.md), not hand-authored twice. - Optional inspector affordances — a health-bar preview widget in the Inspector, opted into via a decorator, not required.
Every other catalog entry follows the same five-part shape. This uniformity is what lets a new Gameplay Framework package — official or third-party — plug into the editor, the graph, and the Agent API automatically instead of needing bespoke integration work each time.
Reference implementations
Three catalog entries already have shipping reference implementations (REFERENCE_GAMES.md), which the official packages should mine before designing:
- VehicleController / arcade mode ← ZENDRIVE's track-space physics:
(distance, lateral)coordinates on a self-closing spline, pure-pursuit homing, and a demand-vs-capacity corner model (curv · v²vs. steer authority) that produces slide and drift as emergent behavior — the same axes Atlas's driving FeelSpec names. - InputManager / intent-relative input ← PULSEHOP's hop grammar: screen-relative directions on diagonal boards, momentum-maintained zigzag, ledge-guard double-press, floating key hints over exact target tiles — and MANDELHOP's unfairness-free rule (every kill must be reactable; complications unlock progressively with banners).
- Water / breaking waves ← BREAKING WAVES' parametric compositor: shader-painted breaking waves on an FFT ocean (storage-buffer slots, winner-take-all, lip rotation, barrel cavity) with live tuning — the upstream for
@3jse/water's breaking-wave authoring. - Time control & replay ← MANDELHOP's one-clock time powers (
worldDt = dt · scale— slow/freeze/phase/reverse/accelerate through a single timescale) and 12 Hz ghost replay: recorded state is enough for speedrun ghosts and time-travel debugging. - Systemic simulation (hydrology/economy) ← DAMN BEAVERS'
sim/tree: simulation-authoritative with a projection seam, seeded determinism, counterfactual replay, and per-phase gate-sentence tests — the closest working instance of this framework's own five-part composable-system shape.
The reference games also donate the headless mechanics harness pattern (headless mech checks, feel-as-numbers tables, per-frame invariant soaks, single-term debug isolation) now standard in the harness's mechanics-harness skill — every Gameplay Framework package should ship one.
Configuration over code, but never opaque
Most of these systems are usable by tuning exposed Component fields and wiring a few graph events — a designer building a third-person game should rarely need to open a TypeScript file for CharacterController. But every default is a real, readable value on a real Component, not a hidden constant inside a compiled black box: maxSpeed, jumpHeight, and coyoteTimeMs are inspector fields today, not "someday." Templates (TEMPLATES.md) pre-wire these systems together into a working starting point; the Gameplay Framework is what they're built from.
PhysicsPHYSICS.md
Engine choice: wrap, don't build
Physics simulation is exactly the kind of subsystem ARCHITECTURE.md's "build ourselves / wrap / adopt / plugin interface" framework (PLUGIN_ARCHITECTURE.md) says not to build from scratch — it's a solved, hard problem with mature WASM-compiled options available to the web platform today. 3JSE ships Rapier (Rust, compiled to WASM) as the default physics backend via @3jse/physics-rapier, with Jolt (also WASM-compiled) supported as a swappable alternative via @3jse/physics-jolt for projects that need its specific character-controller or large-scene performance characteristics. Both implement the same @3jse/physics interface, so swapping backends is a package swap, not a rewrite of gameplay code.
Babylon.js runs four physics backends (Ammo, Cannon, Havok, Oimo) behind one plugin interface in production, which is useful here as validation, not as a reason to widen scope: it confirms a real, shipping engine has proven that "one interface, swappable WASM backend" holds up under actual gameplay-code load rather than just looking clean on paper, and its plugin interface is the concrete reference for what @3jse/physics's own surface should cover (body/collider CRUD, raycasts, joints, character-controller primitives) so @3jse/physics-jolt isn't designed in a vacuum when it's actually built. It is not, on its own, a reason to ship more than the two backends above list — a third WASM physics engine is only worth adding when a real project need shows up, the same bar VENDOR_INTEGRATIONS.md applies everywhere else.
Integration with the Entity/Component model
Physics bodies are Components (RigidBody, Collider, Joint) exactly like anything else in ENTITY_COMPONENT_MODEL.md — inspectable, serializable, replicable. The physics step runs as a fixed-step System (RUNTIME.md's tick loop, stage 2); after stepping, a sync System writes resulting transforms back to each Entity's Object3D, so downstream render/animation/camera systems always see current-frame physics results without needing physics-engine-specific knowledge.
Collision editing
The Physics/Collision Editor panel (EDITOR.md) provides gizmos for box/sphere/capsule/convex-hull colliders, snapping to mesh bounds, and the asset pipeline's collider suggestions (ASSET_PIPELINE.md) as a starting point rather than a mandatory default. Compound colliders (multiple shapes on one Entity) and physics constraints/joints (hinge, slider, fixed, spring) are authored the same way — gizmo-first, with exact numeric entry in the Inspector.
Threading
Rapier and Jolt both support running their simulation step off the main thread via a Web Worker, communicating body-transform deltas back through a SharedArrayBuffer where cross-origin isolation allows it (falling back to structured-clone message passing otherwise). 3JSE's default configuration runs physics on a worker whenever the deployment target permits, keeping the main thread free for rendering and input — see PERFORMANCE.md for the isolation-header requirements this depends on and the graceful degradation path when they're unavailable.
What 3JSE adds beyond the wrapped engine
- Query API (
raycast,overlap,sweep) exposed uniformly to both TypeScript and 3JSE Graph nodes, backend-agnostic. - Collision/trigger events surfaced as 3IR events (
GAMEPLAY_IR.md) —OnCollisionEnter,OnTriggerEnter— so gameplay logic never touches the underlying WASM API directly. - Networking-friendly state:
RigidBodytransform/velocity are Component fields, which is what makes them replicable by the same mechanism as any other Component state (NETWORKING.md), rather than needing a physics-specific network sync layer. - Determinism posture: per-machine deterministic given identical build/inputs (
RUNTIME.md), which is what save/replay and single-machine time-travel debugging rely on — explicitly not claimed as cross-platform bit-exact, since neither Rapier nor Jolt guarantee that across differing hardware.
AnimationANIMATION.md
Foundation
3JSE builds directly on Three.js's AnimationMixer and AnimationClip for clip playback and blending primitives — the same posture as the rest of the engine toward Three.js (ARCHITECTURE.md). What 3JSE adds is the authoring and orchestration layer Three.js deliberately leaves to the application: state machines, blend trees/spaces, retargeting, and IK.
Animation Graph
A specialized 3JSE Graph scope (VISUAL_SCRIPTING.md) built from animation-specific node families sharing the same underlying IR and debugger:
- State machine nodes: states hold a clip or blend tree; guarded transitions (typed conditions against Component fields — e.g.
Speed > 0.1); entry/exit events fire as ordinary 3IR events other graphs can listen to. - Blend trees / blend spaces: 1D (e.g. walk↔run by speed) and 2D (e.g. move-direction blend space) nodes, sampling multiple clips and producing a weighted pose.
- Sync/event nodes: notify-style markers on a clip (footstep, hit-frame) surfaced as 3IR events so gameplay graphs can react (spawn a footstep VFX, apply damage on a hit-frame) without polling animation state.
- IK nodes: two-bone IK (limbs), look-at (head/torso aim), and foot-placement/ground-adaption solvers, layered on top of the base pose produced by the state machine.
Skeletal retargeting
A named humanoid bone-mapping standard (root/hips/spine/head/limb chain naming convention, aligned with the character-detection heuristics in ASSET_PIPELINE.md) lets a clip authored on one skeleton play on another compatible skeleton via a retarget map — generated automatically when both skeletons match the standard, editable manually when they don't. This is what makes template character controllers (TEMPLATES.md) usable with a project's own custom character mesh without hand-rebuilding every clip.
Editor tooling
The Animation Tools panel (EDITOR.md) provides a timeline for clip scrubbing/trimming, the state-machine/blend-tree graph canvas, a skeleton viewer for bone-weight and IK-chain inspection, and live preview against the currently-selected Entity in the Viewport — changes to a blend tree are visible on the actual character immediately, using the same "edit while Play is paused" model described in EDITOR.md.
Performance
Skinning is GPU-driven (bone matrices uploaded to a texture/buffer per Three.js's existing skinning path); the mixer/blend-tree evaluation for many simultaneously-animated Entities (crowds) is a documented target for the WASM emitter path noted in GAMEPLAY_IR.md and the instancing strategy in PERFORMANCE.md, not a default requirement for typical character counts.
AudioAUDIO.md
Foundation
Built on the Web Audio API via Three.js's existing Audio/PositionalAudio and AudioListener — spatialization, distance attenuation, and doppler are Three.js/Web-Audio-native, not reimplemented. @3jse/audio adds the mixing, event, and authoring layer around them.
Mixer
A bus-graph model (Master → categories: Music, SFX, Voice, UI, Ambience, each independently volume/effect-controllable), authored in Project Settings (EDITOR.md) and addressable from both TypeScript and 3JSE Graph. Buses map to Web Audio GainNode/effect-node chains under the hood; ducking (lower Music when Voice plays) is a bus-level rule, not something each sound designer wires by hand per clip.
AudioSource as a Component
Sound playback is a Component (AudioSource: clip reference, bus, loop, spatial-blend, min/max distance) exactly like everything else in ENTITY_COMPONENT_MODEL.md — inspectable, and controllable from 3JSE Graph nodes (PlaySound, StopSound, SetVolume) that are thin wrappers over the same API a TypeScript system would call, per the pattern established in GAMEPLAY_FRAMEWORK.md.
Event-driven triggering
Sounds are triggered from 3IR events, not hardcoded into gameplay systems — a footstep sync node from ANIMATION.md, a Health.onDamaged event from GAMEPLAY_FRAMEWORK.md, a OnTriggerEnter from VISUAL_SCRIPTING.md's worked example all connect to a PlaySound node the same way. This keeps sound design editable by wiring, not by finding and modifying the gameplay code that happens to also play a sound.
Generative audio — gameplay is the score
The event-driven model above has a proven far end, demonstrated by three reference games (REFERENCE_GAMES.md): PULSEHOP rebuilds Qbert as a musical instrument — every hop quantized to a 16th-note grid, tiles mapped to scale degrees, combos fading in groove layers (kick/hats/snare/bass/echo arps), board clear as a cadence — with Web MIDI out (lead/chords/bass/drums + MIDI clock) and an OSC-over-WebSocket bridge so the game literally sequences a DAW. ZENDRIVE runs a generative vaporwave engine that listens to driving state: speed opens the filter and thickens the arp, drifting bends the tape, checkpoints ring FM bells. MANDELHOP uses its generative score as progression: hops climb a pentatonic ladder, biome crossings swell, enemy telegraphs glissando, checkpoints resolve the phrase, and rhythm-chained landings enter a flow state with generative percussion and score ×2 — all synthesized, no recordings. 3JSE's audio layer should therefore treat the mixer/event model as the plumbing* and ship two additional first-class surfaces: (1) a sequencer/quantizer — gameplay events quantized to a musical grid with scale/root/BPM per level, so audio directors can be authored in 3JSE Graph and FeelSpec; and (2) a MIDI/OSC out bridge as a standard audio device, because "the game composes a DAW" is a shipping feature, not a debug tool.
Practical scope
Occlusion/reverb-zone modeling (a room-aware reverb graph keyed to level geometry) is a defined extension point (@3jse/audio exposes a ReverbZone component and a pluggable occlusion query) rather than a built-in physically-modeled solution in early phases — see ROADMAP.md for when deeper acoustic modeling is revisited. Audio asset import (compression, format normalization) is handled by the Asset Pipeline (ASSET_PIPELINE.md), not duplicated here.
RenderingRENDERING.md
Posture toward Three.js
3JSE does not build a renderer. It builds an authoring and orchestration layer on top of Three.js's WebGPURenderer (with WebGL2 as its existing automatic fallback), consistent with ARCHITECTURE.md principle 1. Nothing in this document proposes reimplementing what Three.js already does well; it proposes exposing it through the editor and a graph-based material authoring tool, and adding the render-graph/quality-tier orchestration Three.js intentionally leaves to the application.
Material Graph
A visual node editor, analogous in day-to-day usability to Unreal's Material Editor, that compiles into Three.js's own TSL (Three Shading Language) node system rather than emitting WGSL/GLSL text from a competing shader-graph implementation. This is the same architectural principle as GAMEPLAY_IR.md applied to shading: one canonical representation (here, TSL's own node graph, which Three.js already backs with both a WebGPU/WGSL and a WebGL/GLSL code path) instead of a second parallel compiler 3JSE would have to maintain.
Supported node categories:
- PBR building blocks: albedo, metalness/roughness, normal, AO, emissive — the standard TSL
MeshStandardNodeMaterial/MeshPhysicalNodeMaterialinputs, exposed as graph pins. - Textures: sampling, UV transforms, triplanar projection.
- Procedural: noise (Perlin/Simplex/Worley), gradients, patterns.
- Math: the standard node-graph arithmetic/vector/trig library.
- Normals/displacement: normal blending, parallax, vertex displacement (including for terrain —
PLUGIN_ARCHITECTURE.md's@3jse/terrain). - Vertex animation: wind sway, wave displacement — driven by TSL's vertex-stage node graph, usable by
@3jse/waterand@3jse/foliagedirectly. - Transparency/blending: alpha modes, refraction approximations.
- Post-processing: the same node graph authors screen-space effects against Three.js's WebGPU-native pass system, exposed in the editor as an ordered, reorderable effect stack (Environment Settings panel,
EDITOR.md). - Compute: TSL's compute-shader nodes are exposed for advanced users/plugins (GPU particle simulation, GPU-driven foliage placement) — a deliberately advanced, opt-in node category rather than part of the default palette.
ROADMAP.mdPhase 5's particle/VFX graph is the primary consumer of this category, and its architecture reference is Babylon.js's GPU particle system specifically: per-particle simulation state (position, velocity, age, custom attributes) packed into a data texture and advanced entirely on the GPU via a compute pass, with the CPU only ever touching emission parameters — not the per-particle read-modify-write loop a CPU-simulated system needs. Adopted as the architectural pattern for@3jse/particleswhen Phase 5 builds it, compiled through TSL's own compute nodes rather than a ported implementation. - Custom nodes: a plugin can register a new Material Graph node the same way it registers a 3JSE Graph node (
PLUGIN_ARCHITECTURE.md) — both are instances of the same "register a typed node into a graph editor" extension point.
UX reference
Babylon.js's Node Material Editor is the direct UX reference for this panel — not for its compiler (TSL is 3JSE's compilation target, as above), but for the parts of a node-based material editor that are genuinely hard to get right and don't need reinventing: frame/group nodes for organizing a large graph, live preview thumbnails on individual nodes (not just the final material ball) so a mid-graph value is visible without wiring a temporary output, collapsible subgraphs for reusable node clusters, and — most directly relevant given the WebGPU/WebGL2 dual-backend posture above — a visible fallback-node pattern for marking which parts of a graph don't have a WebGL2-compatible path, the same category of problem VENDOR_INTEGRATIONS.md already flags for WebGPU-only vendor plugins like poseidon/demiurge.
Why TSL specifically, and what the WebGL2 fallback means
TSL's node graph already compiles to both WGSL (WebGPU) and GLSL (WebGL2) from one authored graph — Three.js did the hard cross-backend compiler work already. 3JSE's Material Graph editor is therefore a visual authoring surface over an existing, maintained compiler, not a rendering-backend project of its own. A material authored once in the Material Graph works on both backends automatically, and the WebGL2 fallback (RUNTIME.md, PERFORMANCE.md) never requires a parallel authoring path.
Render graph and quality tiers
Three.js's renderer gives an application control over what to draw and how; 3JSE's runtime adds the orchestration layer an application-level project needs and shouldn't have to hand-roll each time: an ordered render-pass graph (opaque → transparent → post-process, with plugin-registerable custom passes — @3jse/water's refraction pass, for instance), and a small set of quality tiers (see PERFORMANCE.md for the full budget table) that scale shadow resolution, post-processing complexity, particle density, and LOD bias together as one selectable unit rather than dozens of independent settings a developer has to reason about combinatorially.
Environment and lighting
The Environment Settings panel (EDITOR.md) exposes sky/HDRI, fog, and a lighting-preset system on top of Three.js's existing light types and image-based lighting support — again orchestration and presets, not new lighting math. Global illumination beyond what Three.js's roadmap provides (baked or real-time) is explicitly out of scope for 3JSE's early phases (VISION.md's non-goals, ROADMAP.md) — 3JSE tracks and adopts Three.js's own GI capabilities as they mature rather than building a competing solution.
NetworkingNETWORKING.md
Scope and honesty up front
This document covers gameplay networking — client/server multiplayer for a shipped game — which is a separate concern from editor collaboration (EDITOR.md uses Git, not a live sync layer). It also deliberately does not promise deterministic lockstep networking: RUNTIME.md is explicit that 3JSE's fixed-step simulation is per-machine deterministic, not cross-platform bit-exact, so 3JSE's default networking model is state replication with server authority, the same category of approach Unity, Unreal, and most shipped web multiplayer games actually use — not rollback-netcode-by-default, which is a specialized, higher-cost model better left to a dedicated plugin for the genres that truly need it (fast-paced competitive action).
Why replication fits the object model without extra machinery
Because gameplay state already lives in typed, schema-declared Components (ENTITY_COMPONENT_MODEL.md), replication is "which Components, on which Entities, does this connection need diffs for" — not a parallel serialization system bolted on afterward. A Component opts into replication by a schema flag; @3jse/networking then:
- Tracks per-field dirty state each tick (cheap, since Component storage is already columnar —
ENTITY_COMPONENT_MODEL.md). - Serializes only changed fields, per-connection, at a configurable send rate.
- Interpolates/extrapolates on receiving clients for smooth motion between updates (standard snapshot interpolation), with per-Component override for fields that should snap instead of interpolate (e.g. discrete state like
AnimationState).
Authority model
- Server-authoritative by default: gameplay-affecting Systems (damage, inventory changes, physics resolution for contested objects) run only where a Component/Entity's
authorityfield says they should — typically the server, or the current owning client for locally-predicted objects (the player's own CharacterController). - Client-side prediction + reconciliation for the locally-controlled player: input is applied immediately client-side for responsiveness, corrected against the authoritative server snapshot when it arrives, using standard input-buffering/replay-on-correction — implemented once in
@3jse/networking'sPredictedControllerbehavior, not something every game reimplements. - RPCs: 3JSE Graph exposes
IsServer/IsClientguard nodes and RPC call/receive nodes (VISUAL_SCRIPTING.md) for one-off events (a fired weapon, a chat message) that don't fit the continuous-Component-diff model.
Transport
WebSocket by default (broad compatibility, simplest server deployment); WebRTC data channels as a plugin-swappable transport for lower-latency peer-to-peer or client-server setups where an SFU/relay is available. The transport is an interface @3jse/networking depends on, not a hardcoded assumption — this is the same "wrap, adopt, don't build a novel protocol" posture the physics engine choice takes (PHYSICS.md, PLUGIN_ARCHITECTURE.md).
What ships as core vs. plugin
@3jse/networking provides the replication core, the authority model, and RPC nodes — enough for the Multiplayer template (TEMPLATES.md) to work out of the box for a small-session co-op or arena game. Matchmaking, dedicated-server orchestration/scaling, and rollback netcode for competitive-action genres are explicitly not core — they're documented extension points for community or official plugins once real usage patterns from Phase 3–4 projects (ROADMAP.md) show which of them are worth standardizing.
PerformancePERFORMANCE.md
Posture
Performance work in 3JSE is not a late optimization pass — it's a set of architectural decisions made early enough that most projects never have to fight the engine to hit a reasonable budget, plus honest, visible instrumentation (the Profiler panel, EDITOR.md) for the projects that need to go further. This document lists the specific mechanisms, not just the aspiration.
WebGPU and the WebGL2 fallback
Three.js's WebGPURenderer is the primary target; WebGL2 is the automatic fallback for browsers/devices without WebGPU support, using the same TSL-authored materials on both backends (RENDERING.md). This is a permanent second render path to keep correct, not a temporary bridge — device/driver WebGPU support (particularly mobile Safari at the time of this writing) is uneven enough that treating WebGL2 as disposable would cut off a real share of the target audience.
Workers and threading
- Physics runs on a dedicated worker where cross-origin isolation headers permit
SharedArrayBuffer(PHYSICS.md); falls back to structured-clone message passing (higher latency, still off the main thread) where they don't. - Asset decoding/transcoding (KTX2/Basis, mesh decompression) runs on workers via the loaders' existing worker-pool support.
- 3IR's WASM emitter (
GAMEPLAY_IR.md) is the defined escape hatch for gameplay logic that profiles as genuinely hot (large-scale crowd/particle simulation) — deliberately not the default backend, because most gameplay logic's bottleneck is elsewhere (draw calls, physics, GC pressure), and defaulting to WASM compilation would trade iteration speed for a performance win most projects don't need.
Rendering-side techniques
| Technique | Mechanism |
|---|---|
| Spatial partitioning | BVH-backed frustum/occlusion culling over the Level's Entities, rebuilt incrementally as Transforms change |
| Instancing | Automatic InstancedMesh promotion for repeated Prefab instances above a configurable count threshold (foliage, crowd, projectile-heavy scenes) |
| Batching | Static-geometry merging for non-moving Entities sharing a Material, applied at build time (BUILD_DEPLOYMENT.md), not at runtime cost |
| LOD | Asset-pipeline-generated tiers (ASSET_PIPELINE.md) selected by screen-space size, blended/cross-faded to avoid popping |
| Occlusion culling | Software occlusion (hierarchical depth buffer from the previous frame) as a portable baseline, with a defined extension point for platform-specific hardware occlusion queries where available |
| Texture compression | KTX2/Basis universal, transcoded per-target format at build time (ASSET_PIPELINE.md, BUILD_DEPLOYMENT.md) |
| Streaming | Distance/sector-based sublevel and asset streaming (WORLD_SYSTEM.md), with a priority queue keyed to camera frustum and movement direction |
| GPU compute | TSL compute nodes (RENDERING.md) for particle simulation and GPU-driven foliage placement, opt-in per project |
| Particle rendering | Two @3jse/render paths behind one sync(pools) call site: ParticleRenderer (THREE.PointsMaterial) and GpuParticleRenderer (PointsNodeMaterial — per-particle size + soft sprite in a TSL graph, streams into storage buffers). @3jse/vfx stays the headless simulation authority for both; a full GPU-compute re-sim is the "GPU compute" row above, still opt-in future work |
Quality tiers
A small number of named tiers (e.g. Low / Medium / High / Ultra), each a coordinated bundle of settings rather than independent sliders a developer has to reason about in combination: shadow map resolution and cascade count, post-processing effect set, particle density multiplier, LOD bias, instancing threshold, and physics substep count all move together per tier. Projects can override individual settings per tier, but the default experience is "pick a tier," not "tune forty knobs" — and the Mobile/Low-power template default (TEMPLATES.md) starts at a conservative tier rather than requiring a developer to discover the need for one after shipping.
Memory budgets
The Profiler surfaces GPU memory (texture/mesh VRAM estimate), JS heap, and asset-cache size as first-class panels, with per-quality-tier target budgets documented per platform class (a Low-tier mobile target and an Ultra-tier desktop target have deliberately different budget ceilings, set and revisited as real project data comes in during ROADMAP.md's later phases rather than fixed speculatively here).
GPU frame capture
The Profiler's draw-call view is backed by a Spector.js-style capture: a single frame's full GPU command sequence (draw calls, state changes, bound textures/buffers, shader source per pass) captured on demand from the live Viewport, not a separate standalone tool a developer has to leave the editor to use. This is adopted as an integration pattern, not a code dependency — whether it's Spector.js itself or a WebGPU-native capture mechanism built against Three.js's own render-graph instrumentation is an implementation choice at build time, not a design commitment made here. What matters architecturally is that "what did the GPU actually do this frame" is one click from the Viewport a developer (or an agent, via runtime.captureFrame/runtime.getPerf in AI_AGENT_API.md) is already looking at, the same "debug tooling lives where the problem is, not in a separate app" posture Babylon's Inspector debug layer models for the editor as a whole (picking, live property readout, and draw-call stats overlaid directly on the running scene rather than in a disconnected panel).
Shader compilation
TSL's node-graph materials compile to WGSL/GLSL ahead-of-time at build (RENDERING.md, BUILD_DEPLOYMENT.md) wherever the material's inputs are static; runtime shader variant compilation (from dynamic material parameter combinations) is minimized by the Material Graph editor warning when a graph structure implies runtime branching that will produce shader-compile stalls — surfaced as a build-time lint, not discovered as a hitch during play.
Proven precedents
The budget-shaped choices above are not hypothetical — five reference games (REFERENCE_GAMES.md) already exercise them: PULSEHOP pools every particle/ring/text sprite for zero per-frame allocation in the hot loop with half-resolution bloom and a DPR cap of 2; ZENDRIVE renders thousands of grass tufts and hundreds of instanced trees in single draw calls with a self-intersection-tested terrain ribbon; 3JSURF holds a 300 m wave at frame with GPU particles rendered as instanced billboards (including the discovered 26-pixel fine-mist cap, reproduced in world units) and a face-space UV parameterisation that keeps a near-vertical surface detail from smearing; MANDELHOP streams an infinite track at ~120 fps by pooling rows 45-ahead/25-behind, chunking vegetation by biome genome, and masking one world-anchored water plane with a sliding 128-row DataTexture; BREAKING WAVES documents the WebGPU adapter-limit requirement its compositor needs explicitly (requiredLimits: { maxStorageTexturesPerShaderStage: 8 } — 4 cascades × 2 layers), so adapters that default lower don't fail to compile the assemble pass.
Large worlds
World Partition-style streaming (WORLD_SYSTEM.md) plus asset streaming together are what let a large open-world project stay within a bounded per-frame and per-memory budget regardless of total world size — the budget is a function of streaming radius and quality tier, not total authored content, which is the property that makes "large worlds" and "runs on a mid-range laptop" compatible goals rather than a tradeoff a developer has to negotiate manually per project.
Asset PipelineASSET_PIPELINE.md
Goal
Dragging a file into the Content Browser should produce something closer to "imported and understood" than "copied and referenced." The pipeline runs identically in the editor (drag-and-drop), headless (CLI/CI), and under Agent control (assets.import in AI_AGENT_API.md) — one implementation, three callers, per ARCHITECTURE.md principle 3.
Supported formats
| Category | Formats |
|---|---|
| Meshes/scenes | glTF, GLB (primary/recommended), FBX, OBJ, USD/USDZ (import-only, best-effort — USD's full spec is not a near-term target; a practical geometry+material subset is) |
| Textures | PNG, JPG, KTX2/Basis, HDR/EXR |
| Environment | HDRI (equirectangular) |
| Audio | WAV, MP3, OGG/Opus |
| Video | MP4/WebM (for in-world screens, cutscene playback) |
| Fonts | TTF/OTF, plus MSDF atlas generation for crisp in-world/UI text |
| Animation | Embedded in glTF/FBX; standalone retargetable clips |
GLB/glTF is the pipeline's native, best-supported path — it's already Three.js's best-supported format and already carries PBR materials, skeletons, and animation in one container. FBX/OBJ/USD support exists for import convenience from other DCC tools, converting into 3JSE's own internal representations rather than being treated as first-class native formats the rest of the engine needs to understand.
What "analyze" means, concretely
On import, the pipeline runs a fixed analysis pass and stages results as suggestions, not silent automatic mutation — a human (or an agent) approves what actually lands in the project:
- Character detection: a rigged mesh with a recognizable humanoid/creature bone hierarchy is flagged as "likely a character" and offered a starter Entity —
Transform,AnimationController, an emptyCharacterControllerslot — instead of landing as an inert mesh. This is the literal "drag a rigged GLB in and 3JSE understands it's probably a character" behavior fromVISION.md, implemented as bone-naming/hierarchy heuristics (root/hip/spine/limb pattern matching), not a black-box ML classifier. - Skeleton/animation detection: separates static meshes from skinned meshes, groups animation clips by armature, and offers clip renaming/retargeting (
ANIMATION.md). - LOD generation: mesh simplification at 2–3 automatic tiers (configurable), using a standard edge-collapse simplifier; a human can always author custom LODs instead.
- Texture compression: transcodes to KTX2/Basis for GPU-native formats, with per-platform target format selection (BCn desktop, ASTC/ETC2 mobile) baked in at build time (
BUILD_DEPLOYMENT.md), not import time — so the source texture is preserved and re-transcoded whenever the target matrix changes. - Mesh compression: Draco or meshopt encoding for delivery size, chosen per the streaming needs in
PERFORMANCE.md. - Collider generation: convex-hull or simplified-mesh collider suggestion for
@3jse/physics-rapier, offered alongside the visual mesh rather than assumed identical to it. - Thumbnails: rendered automatically for the Content Browser at import time and cached.
- Metadata: bounding box, triangle/material/bone counts, source file hash — surfaced in the Inspector and to
scene.queryso an agent can reason about asset cost without loading it. - Dependency tracking: every asset records what it references (a Material referencing a Texture, a Prefab referencing a Mesh) and what references it — this is the data the Asset Dependency Viewer panel (
EDITOR.md) renders directly.
glTF/PBR validation checklist (informed by Babylon.js)
Not a novel invention — Babylon.js's glTF validator and 15+ years of production import-pipeline experience already worked out what actually breaks in practice on real, DCC-exported files. 3JSE adopts the checklist, not the code (its validator isn't a dependency; the categories of thing worth checking are what's reused):
- Structural validation: required/used extensions are actually supported (
KHR_materials_*,KHR_texture_transform,KHR_draco_mesh_compression,EXT_meshopt_compression), accessor bounds/component-type consistency, node-hierarchy cycles, and orphaned buffer views — surfaced as import warnings, not hard failures, matching the "suggestions, not silent mutation" posture above. - PBR material sanity: metallic-roughness channel packing verified against the glTF convention (metalness = B, roughness = G — a common DCC-export mix-up), normal-map Y-convention (OpenGL vs. DirectX) detected and corrected rather than silently rendering wrong, missing occlusion/emissive filled with spec defaults instead of rendering black.
- Environment/IBL staging: an imported HDRI gets the same "environment studio" treatment — a prefiltered specular mip chain plus an irradiance SH are generated and cached at import time, so a level's lighting previews correctly before any material authoring happens, not after a separate manual bake step.
Compression matrix — decided per platform target at build time (BUILD_DEPLOYMENT.md), not import time, per "What analyze means" above; this table is the derivation rule the build step reads, not a per-asset hand pick:
| Asset | Desktop | Mobile | Always retained |
|---|---|---|---|
| Textures | BCn via KTX2/Basis | ASTC/ETC2 via KTX2/Basis | Uncompressed source (PNG/JPG/HDR) |
| Meshes | Draco or meshopt | meshopt (lower CPU decode cost on mobile) | Uncompressed accessor data |
Storage model
Imported assets are content-addressed internally (a hash of the source file) so re-importing an identical file is a no-op and two projects sharing an asset (via a Grid-style package, future work) don't duplicate storage needlessly. The human-facing project tree (PROJECT_FORMAT.md) still shows assets under conventional, readable paths — content-addressing is an implementation detail of the cache, not something that leaks into how a developer browses the project.
Headless and CI use
3jse assets import <path> --headless runs the identical analysis pipeline outside the editor, emitting the same suggestion JSON the editor's import dialog would show, for scripted bulk-import pipelines and for the Agent API's assets.import tool. There is exactly one asset-analysis implementation; the editor UI and the CLI are both thin callers of it.
Project FormatPROJECT_FORMAT.md
Requirements, restated as constraints
A 3JSE project must be readable, inspectable, Git-friendly, diffable, portable, and recoverable without the editor. Every choice below is in service of those six words specifically — none of them are negotiable trade-offs against "but a binary format would be faster," because none of the operations that matter (load time, editor responsiveness) actually require a binary project format to hit their targets; the runtime's in-memory representation, not the on-disk format, is what performance-sensitive code touches.
Directory layout
/project
/assets imported source assets (meshes, textures, audio, fonts)
/scenes Level files
/prefabs Prefab files
/graphs 3JSE Graph files (.3jgraph)
/materials Material Graph files
/scripts hand-written TypeScript systems/components
/systems compiled output when a Graph is "ejected" to code (GAMEPLAY_IR.md)
/ui UI/HUD layout files
/audio audio-specific config (mixer buses, not raw clips — those live in /assets)
/plugins project-local plugin packages (not published to a registry)
project.json engine version, dependencies, build targets, quality tiersThis is the literal structure the brief specifies, because it already matches how a working software project is organized — there's no reason to deviate from it for novelty's sake.
Serialization rules
- Deterministic key ordering. Every serializer writes object keys in a fixed, schema-defined order (never object-insertion order, never alphabetical-by-accident) — this is what keeps a trivial value change producing a one-line diff instead of a reshuffled file.
- Stable IDs, not array position. Entities, Components, and graph nodes are referenced by a stable ID (ULID-style: sortable, collision-resistant, generated once at creation), never by array index — reordering a list in the editor must never look like every element changed in the diff.
- Human-readable JSON, pretty-printed with a fixed indent, not minified and not a binary pack format — this is the direct implementation of "readable, diffable, recoverable without the editor": any text editor, and any AI agent's plain file-read tool, can open a scene file and understand it.
- Large binary payloads stay binary, referenced by path/hash — a texture or a mesh's binary data doesn't belong inlined into a JSON scene file; the scene file stores a reference (
asset://<hash>), and the asset itself sits under/assetsas its native binary format, which is both the correct diff granularity (a texture re-export shows as one changed binary file, not a giant base64 diff) and how Git's own binary-diffing (or Git LFS, for large asset sets) is meant to be used.
Versioning and migration
Every serialized file (Level, Prefab, a 3JSE Graph) carries an explicit schema-version field, checked on load, never inferred from content shape. This is a lesson worth taking directly from Babylon.js's own scene-serialization history rather than re-learning it: a scene format that has been in production for over a decade accumulates real, specific breakage patterns — a field silently renamed between versions, a default value that changed meaning, an enum that gained a case old files don't have — and the fix that actually holds up is a versioned, ordered chain of small migration functions (v3 → v4 → v5 …) run automatically on load, each one narrow enough to unit-test against a real fixture file from that version, rather than a single "best guess" up-converter that tries to handle every historical shape in one pass. A file's version field is what tells the loader which migrations to run and lets it refuse — loudly, not silently — a version newer than the running engine understands.
Example: a Level file (abbreviated)
{
"kind": "Level",
"id": "01J8Z…",
"name": "MainMenu",
"entities": [
{
"id": "01J8ZA…",
"name": "Player",
"components": {
"Transform": { "position": [0, 1, 0], "rotation": [0, 0, 0, 1] },
"CharacterController": { "maxSpeed": 6, "jumpHeight": 1.4 },
"Health": { "current": 100, "max": 100 }
}
}
]
}This is exactly the shape shown in ENTITY_COMPONENT_MODEL.md for a single Entity — a Level file is simply a list of these plus level-scoped settings (environment, sublevel references from WORLD_SYSTEM.md). There is deliberately no separate "runtime scene format" a build step converts this into beyond the ordinary bundling described in BUILD_DEPLOYMENT.md — the same JSON structure that's diffable in a PR is what the runtime loads (parsed once at Level-load, not re-parsed per frame).
Recoverability without the editor
Because every file is plain JSON (or a native binary asset format loaders elsewhere already understand) under a conventional directory tree, a developer who has lost access to 3JSE entirely can still: read exactly what a scene contained, hand-edit a Component value with a text editor, and — because @3jse/runtime is a normal npm package with no editor dependency (RUNTIME.md) — write a small script that loads the project's project.json and boots the game with no editor installed at all. The project file format's only real dependency is the schema definitions published by whichever @3jse/* packages the project uses, which are themselves versioned, published packages, not editor-internal state.
Git workflow implications
This format is what makes EDITOR.md's Git-based collaboration model (rather than live CRDT co-editing) actually viable day-to-day: two developers' changes to different Entities in the same Level file produce a clean line-level merge in the overwhelming common case, and a genuine conflict (both editing the same Component's same field) shows up as an ordinary, human-resolvable Git conflict marker in readable JSON — not a binary merge failure requiring the editor to arbitrate.
Build + DeploymentBUILD_DEPLOYMENT.md
The claim
This is the area 3JSE can beat Unreal outright, not just match it, because the web platform's distribution model is structurally better than a desktop engine's — no multi-gigabyte installer, no platform-store review cycle standing between a build and a player for the default target. 3JSE's job is not inventing this advantage; it's not squandering it by making deployment feel like a traditional engine's export pipeline bolted onto a web target as an afterthought.
Play
Pressing Play in the editor never triggers a build. RUNTIME.md's in-process execution model means Play boots the current World directly in the same WebGPU context the editor uses — this is instant by construction, not something a build pipeline is optimized to make fast.
Publish
Publish does produce a real, optimized build — separate from Play specifically because Play's priority (instant iteration) and Publish's priority (smallest, fastest, most compatible output) are different problems:
- Tree-shaking: only the
@3jse/*packages and Gameplay Framework systems a project actually uses are bundled (PLUGIN_ARCHITECTURE.md's "a game depends only on the systems it uses" is enforced here, not just aspirational). - Asset finalization: textures transcode to the target's optimal compressed format (
ASSET_PIPELINE.md), meshes get Draco/meshopt compression, unused LOD tiers for the selected quality-tier range are dropped. - Graph compilation: every 3JSE Graph compiles to its JS/TS backend output (
GAMEPLAY_IR.md) — the shipped build contains zero interpreter, zero visual-scripting runtime tax. - Code bundling: standard modern bundler (esbuild/rollup-class) output — minified, code-split by Level/sublevel where
WORLD_SYSTEM.md's streaming applies, so a large project's initial download isn't the whole game. - Manifest generation: a build manifest records exact asset hashes/versions for CDN cache-busting and for the Agent API's build-verification tooling (
AI_AGENT_API.md'sbuild.typecheck/build.runTestsoperate against this same pipeline headless). - Third-party notices: a
THIRD_PARTY_NOTICESfile is generated from every installed@3jse/vendorTier A package's registry entry (VENDOR_INTEGRATIONS.md) — source, license, author. Publish fails, not just warns, if anything shipping in the bundle traces back to an unresolved Tier B staged import (/plugins/_vendor/) that was never promoted to a proper attributed plugin — a project can prototype with staged open-source code, but can't accidentally ship it unattributed.
Target matrix
| Target | Mechanism | Status posture |
|---|---|---|
| Static web | Plain bundled output, deployable to any static host/CDN | Primary target, day one |
| PWA | Static web output + generated manifest/service-worker for offline play and install-to-homescreen | Near-term, low incremental cost over static web |
| Desktop (macOS/Windows/Linux) | Tauri shell wrapping the static web build, native file-system/save access | Near-term — reuses the same shell technology as the editor itself |
| Steam wrapper | Desktop build + Steamworks SDK integration (achievements/cloud-save bridged to @3jse/achievements/@3jse/save) | Mid-term, once desktop packaging is proven |
| Mobile wrappers (iOS/Android) | Tauri-mobile or Capacitor-class WebView wrapper around the static build, with the Mobile template's aggressive default quality tier (PERFORMANCE.md) | Mid-term — gated on WebGPU/WebGL2 mobile support maturity, honestly tracked rather than promised early |
| XR | WebXR directly from the static web build — no wrapper needed for browser-based XR; store-distributed XR follows the same wrapper path as mobile | Near-term for browser WebXR, mid-term for store distribution |
A 3JSE game remains distributable as normal web technology at every tier above "static web" — the desktop/mobile/Steam targets are wrappers around the same build, not divergent platform-specific codepaths a developer has to maintain separately. This is the concrete meaning of "the browser is not a limitation to apologize for" from VISION.md: every non-web target is additive packaging on top of a build that already works, not a prerequisite the web target was a stepping stone toward.
Babylon Native — a C++/JSI shell that runs the same Babylon.js scene code inside a native host instead of a WebView, used for their iOS/Android/Windows/UWP native targets — is worth naming here as the alternative this table's Tauri/Capacitor-class wrapper approach deliberately isn't taking. It's a real, proven path for squeezing out WebView overhead, and it's evidence for the mobile row's "gated on WebGPU/WebGL2 mobile support maturity" caveat being a genuine tradeoff rather than an oversight: a JSI-style native shell is the mechanism to reach for specifically if WebView-hosted WebGPU/WebGL2 mobile performance turns out not to be good enough once real projects hit that ceiling — sharpening the Tauri bet's failure mode rather than replacing it preemptively with more native-shell complexity before there's project evidence it's needed.
Quality tiers as a build concern
The quality-tier system (PERFORMANCE.md) is resolved partly at build time — target-specific texture formats, LOD ranges, and default tier selection per deployment target are baked into that target's build variant, so a mobile build isn't shipping desktop-resolution textures it will never use, and a desktop build isn't capped at mobile settings by default.
TemplatesTEMPLATES.md
Design rule
A 3JSE template is a working starting point built from real Gameplay Framework systems (GAMEPLAY_FRAMEWORK.md), not a demo scene wired together with one-off hacks that fall apart the moment a developer tries to extend them. The test for whether a template is done: an AI agent, given a one-sentence request (AI_AGENT_API.md), should be able to transform it into a materially different game by editing Components, Graphs, and assets — not by rewriting the template's foundations first.
Third Person — the reference template
Specified in full because every other template follows the same shape:
| Piece | Package / mechanism |
|---|---|
| Character controller (capsule movement, slopes, stairs, jump) | @3jse/character |
| Camera (spring-arm third-person rig, collision-avoidance) | @3jse/character |
| Gamepad + keyboard/mouse input, remappable | InputManager (GAMEPLAY_FRAMEWORK.md) |
| Animation controller (locomotion blend tree, jump/land states) | @3jse/character + ANIMATION.md Animation Graph |
| Interaction system (world prompts, pick-up/use) | @3jse/interaction |
| Checkpoints | @3jse/save |
| Basic UI (health, interaction prompt) | @3jse/ui |
| Save system | @3jse/save |
All of it is ordinary Entities/Components/Graphs sitting in a normal project (PROJECT_FORMAT.md) — opening the template in the editor shows exactly the same Hierarchy/Inspector/Graph views a hand-built project would, because it is one.
Catalog
Shipped (@3jse/templates, TEMPLATE_CATALOG): Third Person (buildThirdPersonTemplate), Top-Down (buildTopDownTemplate), First Person (buildFirstPersonTemplate). All three are the same wiring — input → CharacterController → physics → CameraRig → Animation → Save — differing only by the @3jse/character CameraRig preset (thirdPerson / topDown / firstPerson / orbit), so a new genre camera is a preset, not a new System.
| Template | Distinguishing systems on top of the shared base |
|---|---|
| First Person (shipped) | CameraRig firstPerson preset (eye-height, look-along-facing). Head-bob / weapon-viewmodel mount / @3jse/combat are follow-ups. |
| Top-Down (shipped) | CameraRig topDown preset (overhead, pitchDegrees tilt). Click-to-move / twin-stick input variant is a follow-up. |
| Platformer | Precision-jump tuning (coyote time, jump buffering), side-view or 3D-platformer camera preset |
| Racing | @3jse/vehicle, checkpoint/lap-timer objectives (@3jse/match) |
| Surfing | Buoyancy/water-interaction (@3jse/water), momentum-based movement variant of @3jse/character |
| Flight | Six-degrees-of-freedom controller variant, altitude/speed HUD |
| RTS | Top-down camera rig, unit-selection/command Graph patterns, @3jse/nav group pathing |
| RPG | @3jse/inventory, @3jse/dialogue, @3jse/quests, stat/leveling Components |
| FPS | @3jse/combat (hitscan/projectile), @3jse/ai-behavior enemy patrol/engage patterns |
| Multiplayer | @3jse/networking wired into whichever base movement template is layered underneath (default: Third Person) |
| Top Down | Fixed/rotating top-down camera preset, click-to-move or twin-stick input variant |
| Side Scroller | 2.5D constrained-axis movement variant, parallax background setup |
| VR/XR | WebXR camera rig, hand/controller input mapping, teleport + smooth-locomotion presets |
| Mobile | Touch input mapping, aggressive default quality tier (PERFORMANCE.md), UI scaled for small screens |
| Walking Simulator | Interaction + Dialogue systems foregrounded, no combat, environmental-storytelling trigger patterns |
| Open World | World Partition-configured base Level (WORLD_SYSTEM.md), streaming-aware spawn/objective systems |
| Physics Sandbox | @3jse/physics-rapier exposed directly — grab/throw interaction, constraint-building tools, minimal scripted logic by design |
| Musical Hopper | Hop-grammar input (@3jse/character variant) + the audio sequencer/quantizer and MIDI/OSC bridge (AUDIO.md) — reference: PULSEHOP (REFERENCE_GAMES.md) |
| Endless Hopper | Unfairness-free deterministic core (constant-velocity lanes, seeded generation, grid-math collision), one-clock time powers, 12 Hz ghost replay, player-agent QA — reference: MANDELHOP (REFERENCE_GAMES.md) |
| Colony Sim | Simulation-authoritative architecture: pure sim + projection seam, seeded determinism, counterfactual replay, gate-sentence test discipline — reference: DAMN BEAVERS (REFERENCE_GAMES.md) |
Reference implementations
Several templates already have shipping reference games (REFERENCE_GAMES.md) whose systems are donation candidates: Surfing ← 3JSURF (headless mechanics harness, feel anchors, rigged riders + baked clip library; first-person variant ← BREAKING WAVES' parametric compositor with live Tweakpane knobs), Racing ← ZENDRIVE (track-space demand-capacity vehicle model, procedural road/terrain, generative music), Musical Hopper ← PULSEHOP, Endless Hopper ← MANDELHOP (unfairness-free core, time powers, ghost replay, player-agent QA), Colony Sim ← DAMN BEAVERS. The test for a template remains the same — an agent can transform it from a one-sentence request — but for these six the starting point no longer has to be invented.
What ships in a template package
/template-third-person
/assets placeholder character, environment kit
/scenes a small playable demo Level using the template's systems
/prefabs Player prefab, checkpoint prefab, interactable prefab
/graphs locomotion animation graph, interaction event graph
project.json declares which @3jse/* gameplay packages the template depends onInstantiating a template via the Project/Templates system is a project-scaffold operation (PROJECT_FORMAT.md, @3jse/cli), not a special editor mode — the resulting project is indistinguishable in structure from a project built up manually package-by-package, which is what keeps templates from becoming a maintenance-diverging special case.
Genre skill packs for the Agent API
Each template ships a matching skill pack for @3jse/agent (AI_AGENT_API.md) — vocabulary and worked patterns specific to that genre ("groove meter," "combo chain," and "boost" resolve against the Racing/Surfing template's conventions; "aggro range" and "patrol" resolve against the FPS/RPG templates' @3jse/ai-behavior conventions) so natural-language requests land on the right existing systems instead of generic first-principles scaffolding every time.
AI Agent APIAI_AGENT_API.md
The constraint that shapes everything here
3JSE is built in the era where a meaningful share of its own use — and a meaningful share of its own future development — will be done by an AI agent, not a human moving a mouse. That means the Agent API cannot be a bolted-on chat feature with its own bespoke access path into the engine. It has to be the same command surface the editor itself is built on (ARCHITECTURE.md principle 3: "everything the editor can do, code can do"). An agent that can only act by simulating mouse coordinates is fragile, unauditable, and slow. An agent that calls scene.mutate is doing exactly what a human dragging a slider in the Inspector caused to happen, through the identical code path, landing in the identical undo history.
Tandem note: the 3JSE Harness (
HARNESS.md) is the first working slice of this layer — the observe → plan → act → verify loop, evidence gates, and structured routing already run today as agent instructions, registries, and deterministic scripts. The Agent API generalizes what the harness does by convention into what the engine does by construction: the same loop, backed by a typed command surface instead of disciplined prompting.
Tool surface
Exposed as an MCP-shaped local tool server (@3jse/agent), so any MCP-capable agent — not just a bespoke in-editor chatbot — can drive a 3JSE project.
| Tool | Does |
|---|---|
scene.query | Read entities/components matching a filter; returns the same JSON shape ENTITY_COMPONENT_MODEL.md describes |
scene.createEntity / scene.destroyEntity | Add/remove an Entity, optionally from a Prefab |
scene.addComponent / scene.removeComponent / scene.setProperty | Mutate Component data — schema-validated, same path as the Inspector |
assets.import | Run the Asset Pipeline (ASSET_PIPELINE.md) against a file, headless |
materials.create | Build a Material Graph node tree (RENDERING.md) |
graph.read / graph.write | Read or patch a 3JSE Graph's IR directly (GAMEPLAY_IR.md) — the agent edits the same JSON the Graph editor renders, never "draws" nodes via simulated interaction |
graph.connect | Wire two node pins, type-checked against 3IR's type system at call time |
codegen.writeFile | Create/modify a TypeScript file under the project's systems/ tree |
project.settings.get / .set | Read/write Project Settings (EDITOR.md) |
runtime.run | Boot the game headless or windowed (RUNTIME.md's headless mode) |
runtime.pause / .step | Control execution for inspection |
runtime.getConsole | Pull captured logs/errors/warnings since a given point |
runtime.getPerf | Pull a frame-timing/draw-call report (PERFORMANCE.md) |
runtime.captureFrame | Screenshot the viewport for visual verification |
build.typecheck | Run the TS/IR type checker without a full build |
build.runTests | Run the project's automated test suite (BUILD_DEPLOYMENT.md) |
Every tool call is schema-validated against the same Component/IR type system the editor UI enforces (GAMEPLAY_IR.md) — a malformed call fails fast with a structured error, not a silent bad state.
Implemented today (@3jse/agent, headless, Node-testable): scene., graph., runtime.run/pause/step, runtime.getConsole, build.typecheck/runTests, and — as of the harness-integration work — runtime.getPerf (real measured CPU/simulation frame timing plus a scene census; not draw calls or GPU time, which need the Profiler panel) and runtime.captureState (the headless-honest stand-in for runtime.captureFrame: authoritative simulation state — transforms + components — serialized deterministically for diffing/invariant checks, rather than a faked pixel grab). buildEvidenceReport() composes these into the EVIDENCE_REPORT shape. A true pixel captureFrame, assets.import, materials.create, codegen.writeFile, and project.settings.* still wait on the renderer / Asset Pipeline / Material Graph.
The model behind PLAN. @3jse/llm is a provider-agnostic chat client (OpenAI, Anthropic, DeepSeek, Gemini, OpenRouter, Groq, Mistral, xAI, Ollama, or any OpenAI-compatible endpoint — two wire protocols, openai-chat and anthropic-messages, cover all of them). The editor's AI Providers panel is where a user picks one and pastes an API key; the key lives in that browser's localStorage only and is sent straight to the chosen provider, nothing in between. Once a provider is active, Atlas's "Ask agent" button and the Agent panel's "Plan with AI" send the scoped-context package (@3jse/atlas's exportAgentContext + previewChange) to the model and surface its plan for a human to act on. The model proposes; it does not auto-execute tool calls — ACT stays human-driven until trust tiers (below) are built.
The loop: plan → modify → run → inspect → diagnose → repair → test
OBSERVE scene.query + runtime.getConsole + runtime.getPerf + last screenshot
│
PLAN step list, surfaced to the human for non-trivial changes
│
ACT graph.write / scene.mutate / codegen.writeFile / assets.import …
│
VERIFY build.typecheck → runtime.run(headless) → runtime.getConsole
→ runtime.captureFrame → compare against expectation
│
├── passes ──► report diff + screenshot to human, land in history
└── fails ──► DIAGNOSE (read the specific console error / perf
regression / screenshot mismatch) ──► repeat ACTThe verify step is the difference between "code that compiles" and "a change that actually works," and it's why the loop always includes an actual headless run, not just a type check — a change can typecheck cleanly and still throw at runtime, render a blank viewport, or silently do nothing, and all three are things runtime.getConsole, runtime.getPerf, and runtime.captureFrame respectively are positioned to catch before a human ever sees the failure.
Worked example: the shark
"Make this shark patrol this area until it sees the player, then chase them. If it gets harpooned, allow it to tow the player."
scene.query— inspect theSharkentity's current components.scene.addComponent(shark, Perception)andscene.addComponent(shark, NavAgent)from@3jse/ai-behavior/@3jse/nav(GAMEPLAY_FRAMEWORK.md).graph.write— construct a Behavior Tree:Patrol(area)→Selectorgated byPerception.canSee(player)→Chase(player).graph.connect— wire aHarpoon.onHit(shark)event into a newTowstate that reparents the player's tow-point to the shark and reduces the shark's max speed.graph.write— wire the Animation Graph transitions (ANIMATION.md) for patrol/chase/towed states.scene.addComponent(shark, RigidBody)with tow-appropriate physics constraints (PHYSICS.md).runtime.run(headless)— boot the level.runtime.getConsole— catch, e.g., a missing animation-state reference.graph.write— repair the missing transition.runtime.runagain,runtime.captureFrameat a moment the shark should be visibly chasing, report the plan, the diff, and the screenshot to the human.
At every step the agent used tools a human could have triggered from the Inspector, the Graph editor, or the Console — nothing here required a capability the GUI doesn't also expose.
Natural-language project creation
The same loop, run once at project-creation scope instead of feature scope: parse intent → select the closest genre Template (TEMPLATES.md) as a starting point rather than an empty World → decompose into the same ACT/VERIFY steps as the shark example, applied across scene setup, asset import/generation, Component wiring, graph construction, physics/input configuration, and UI — then hand the result to the human exactly as authored: real Entities, real Components, real Graphs, browsable and editable in the ordinary editor, never a black box the editor can display but not decompose. This is a hard constraint, not an aspiration: any AI output that can't be inspected and edited through the same panels a human uses is treated as an Agent API bug, because it violates the founding premise in VISION.md that all four ways of working edit the same underlying game.
Trust tiers and safety
| Tier | Behavior |
|---|---|
| Suggest | Every change is proposed as a diff/graph patch; nothing lands without explicit approval |
| Co-pilot | Free to make local, additive, reversible edits (new entities, new components, new graph nodes, new files); deletions, breaking API changes, and new package dependencies still require approval |
| Autonomous | For CI-style batch jobs on a sandboxed branch; output lands as a change-proposal merged through the normal Git workflow (EDITOR.md's Source Control panel), never a silent direct commit |
Structural guarantees, independent of tier:
- Every Agent-initiated mutation goes through
scene.mutate/graph.write/etc. and therefore lands in the same undo/version history as a manual edit (EDITOR.md) — nothing an agent does is a special, unrevertable category of change. - Generated TypeScript executes in a capability-scoped sandbox: no network access, no filesystem access outside the project tree, enforced by the tool server rather than assumed from good behavior.
- Secrets and environment values are excluded from the context an agent can read, by construction of what
scene.query/project.settings.getare allowed to return. - Scope limits (files touched, entities mutated per turn) are configurable per trust tier, so a Suggest-tier session reviewing "fix this one bug" can't accidentally touch two hundred files without that being a visible, flagged deviation from plan.
Why this doesn't need a second engine
Because the tool surface is the editor's own command API, there was no temptation — and no need — to build a parallel "AI scripting language" or a simulated-input automation layer. The Agent API's entire job is exposing ARCHITECTURE.md principle 3 over a stable, typed, MCP-shaped interface. Everything hard about making that reliable (typed validation, headless verification, undo-integrated history) was already required by the rest of the engine; the Agent API mostly assembles those pieces into a loop rather than inventing new ones.
Plugin ArchitecturePLUGIN_ARCHITECTURE.md
Why this document matters more than usual
3JSE expects a significant share of its own future feature development to be done by coding agents (VISION.md, AI_AGENT_API.md), and expects third-party packages to be genuinely first-class rather than a tolerated extension mechanism bolted onto a closed core. Both of those goals fail unless adding a subsystem is a small, predictable, well-bounded operation — the opposite of "understand the whole engine first." This document specifies what that boundary looks like.
What a plugin registers
A @3jse/* package (official or third-party) declares itself against a small set of typed extension points — the same ones an official package uses, with no private API tier:
| Extension point | Registers |
|---|---|
| Component schemas | New Component types (with field types, defaults, validation) — instantly inspectable, serializable, and replicable per ENTITY_COMPONENT_MODEL.md |
| Systems | Tick-stage-scoped logic operating over a component query (RUNTIME.md) |
| Resources/Services | Global singletons (RUNTIME.md) |
| 3JSE Graph nodes | New node types wrapping the package's API, auto-derived from Component/event schemas where possible (GAMEPLAY_FRAMEWORK.md's Health example) |
| Material Graph nodes | New shading node types compiling into TSL (RENDERING.md) |
| Editor panels | New dockable panels (EDITOR.md), built on the same panel-registration API every built-in panel uses |
| Inspector field renderers | Custom widgets for specific field types (a curve editor, a gradient picker) |
| Importers/Exporters | New Asset Pipeline format handlers (ASSET_PIPELINE.md) |
| Agent tools | New MCP-shaped tools extending the Agent API's surface (AI_AGENT_API.md) for package-specific operations |
| Build targets | New deployment targets (BUILD_DEPLOYMENT.md) |
A minimal plugin package might register just a Component schema and a couple of Systems (a pure-gameplay package like @3jse/quests); a subsystem-scale plugin like @3jse/terrain registers Component schemas, Systems, editor panels, Material Graph nodes, and an importer, but through the exact same manifest shape — scale changes how many extension points a package uses, not the mechanism.
Stability contract
Extension-point APIs are versioned independently of the engine's overall version, with semver guarantees per point (a breaking change to the Component-schema API is a major bump on that API specifically). A plugin declares which extension-point API versions it targets in its manifest; the editor and CLI warn — rather than silently fail — when a plugin targets an API range the running 3JSE version doesn't satisfy. This is what makes third-party packages survivable across engine upgrades without every plugin author needing to track engine internals.
The cadence this contract runs on is modeled on Babylon.js's governance, not invented from scratch: a predictable yearly major (so a breaking change has a known landing window, not a surprise), long deprecation warnings before an extension-point API actually breaks (a plugin sees "this will stop working in the next major" for a full release cycle before it does), and an LTS designation on select majors for teams that need a version to sit still for a shipped game's lifetime. Copying a governance cadence is cheap and low-risk compared to copying code, and it's specifically what makes the stability guarantees above something a third-party author can actually plan around instead of a promise with no operational teeth.
Sandboxing and trust
Plugin code runs with the same capability-scoping the Agent API's generated code runs under (AI_AGENT_API.md) — no ambient filesystem/network access beyond what the extension-point contract requires (an importer needs file read access to the asset being imported; a gameplay package needs none). This matters specifically because 3JSE expects both AI agents and third-party authors to be writing plugins, and neither should be implicitly trusted with more access than the extension point they're using actually needs.
Build vs. wrap vs. adopt vs. plugin-interface
Applying ARCHITECTURE.md's "avoid reinventing excellent libraries" principle concretely, subsystem by subsystem:
| Subsystem | Strategy | Rationale |
|---|---|---|
| Rendering | Adopt (Three.js WebGPURenderer/TSL) | Already excellent, already the reason developers choose the web for 3D |
| Physics | Wrap (Rapier default, Jolt alternative, both WASM) | Mature, fast, no reason to reimplement (PHYSICS.md) |
| ECS storage | Build (thin, purpose-fit) | Needs tight integration with Object3D and the schema/inspector/replication system no off-the-shelf ECS assumes (ENTITY_COMPONENT_MODEL.md) |
| Navigation/pathfinding | Wrap existing navmesh-generation libraries where license/output quality fit; build the query/agent integration layer | Navmesh baking is a solved problem; the Entity/Component integration is 3JSE-specific |
| Audio | Adopt (Web Audio via Three.js) + build mixer/event layer | Web Audio already does spatialization well; the bus/event model is the actual gap |
| Networking transport | Wrap (WebSocket/WebRTC) + build replication layer | Transports are commodity; Component-diff replication is the integration work worth owning |
| Node graph editor (canvas/rendering) | Build | Needs to render thousands of nodes/wires at interactive frame rates with custom debug overlays (VISUAL_SCRIPTING.md) — general-purpose DOM node-graph libraries don't hold up at this scale or integrate with 3IR's live-value overlays |
| Code editor | Adopt (Monaco-class embeddable editor) | Solved problem; not a differentiator worth owning |
| Editor UI toolkit (panels, forms, inspector controls) | Adopt (@galacean/editor-ui + @galacean/gui) | MIT, engine-agnostic (peer-deps on React only), purpose-built for exactly this problem — ships the ColorPicker/BezierCurveEditor/GradientSlider/AssetPicker/Vector-field controls a 3D editor's Inspector otherwise hand-rolls one at a time; see EDITOR.md |
| Terrain/water/foliage | Wrap named open-source projects where a permissively-licensed, technically-compatible one already exists; build the adapter layer | Revised from an earlier "build from scratch" call — see VENDOR_INTEGRATIONS.md. The render/physics/asset-pipeline coupling that made wrapping look awkward is exactly what the Tier A adapter shape (Component + System + Graph nodes, not a raw dependency) is designed to absorb |
| Asset compression (Draco/meshopt/KTX2/Basis) | Adopt | Established, widely used, no reason to reimplement (ASSET_PIPELINE.md) |
| Multiplayer editor collaboration | Not built (Git instead) | Deliberately deferred — see EDITOR.md |
| Community/solo-developer graphics work generally (water, vegetation, terrain, VFX techniques) | Wrap when licensable, fetch-and-stage otherwise | The Three.js/WebGPU ecosystem includes individual developers producing best-in-class effects work; a curated registry plus an in-editor fetcher (VENDOR_INTEGRATIONS.md) turns that into either an official plugin or an attributed, sandboxed starting point — never a silent, unverified dependency |
Package examples, expanded
@3jse/core runtime primitives (World/Level/Entity/Component/System)
@3jse/editor editor shell, panel framework, docking
@3jse/runtime game-side runtime (superset of core, includes scheduler)
@3jse/graph 3JSE Graph node model, compiler, debugger protocol
@3jse/ir 3JSE Gameplay IR types, validator, backends
@3jse/agent Agent API tool server
@3jse/assets import/analysis pipeline
@3jse/vendor open-source registry + fetch-on-demand importer (VENDOR_INTEGRATIONS.md)
@3jse/physics-rapier official plugin
@3jse/physics-jolt official plugin (alternative backend)
@3jse/water-poseidon official plugin — wraps github.com/owenyuwono/poseidon (FFT ocean)
@3jse/terrain official plugin (procedural mode: @3jse/terrain-demiurge, wraps demiurge)
@3jse/foliage-gaia official plugin — wraps github.com/owenyuwono/gaia (procedural grass)
@3jse/flora-dryad official plugin — wraps github.com/owenyuwono/dryad (procedural trees)
@3jse/networking official plugin
@3jse/nav official plugin
@3jse/ai-behavior official plugin
@3jse/ui official plugin
@3jse/character official plugin
@3jse/vehicle official plugin
community/* third-party packages, same manifest shape, no privilege gap
_vendor/* staged Tier B imports (project-local, unpublished, see VENDOR_INTEGRATIONS.md)@3jse/water-poseidon, @3jse/foliage-gaia, and @3jse/flora-dryad replace the earlier placeholder @3jse/water/@3jse/foliage names in this table's first draft — VENDOR_INTEGRATIONS.md has the full case study, licensing verification, and adapter design behind that change. The naming convention (@3jse/<capability>-<upstream>) keeps provenance visible in every project's dependency list permanently, not just in a credits file.
Vendor IntegrationsVENDOR_INTEGRATIONS.md
Why this document exists
PLUGIN_ARCHITECTURE.md names @3jse/water and @3jse/foliage as official plugins to be built. That was written before checking whether they need to be built at all. They mostly don't. The Three.js/WebGPU ecosystem already has individual developers shipping water and vegetation work that is better than what a small core team would produce from scratch in the same timeframe — this document replaces "someday we'll build these" with a concrete policy for wrapping that work instead, plus an in-editor mechanism for pulling in the next one without waiting for a core-team release cycle.
This is ARCHITECTURE.md principle 4 ("plugins are first-class") and the build/wrap/adopt framework in PLUGIN_ARCHITECTURE.md, made concrete against real repositories instead of a hypothetical table. A third case study extends the same discipline to the adjacent engine itself: Babylon.js — what 3JSE differentiates against, and what its permissively-licensed tooling stack offers as reference.
Case study: github.com/owenyuwono
Checked directly against the live GitHub API rather than assumed. Findings:
| Repo | Stars | Stack | License (as declared) | What it is |
|---|---|---|---|---|
| poseidon | 272 | JS, Three.js + WebGPU/TSL | MIT | GPU-driven real-time FFT (Tessendorf) ocean, three IFFT cascades as WebGPU compute shaders |
gaia (grassgen) | 37 | JS, Three.js | MIT | Deterministic procedural grass — genome + seed → geometry, zero authored assets |
| dryad | 31 | JS, Three.js | MIT | Deterministic procedural trees — same genome/seed approach as gaia, shared author, compatible design |
| demiurge | 33 | TS, Three.js + WebGPU | MIT | Tectonic-plate procedural planet: uplift → erosion → climate → biome, no heightmap |
| apate | 17 | GLSL, Three.js | MIT | A comparison of four surface-relief techniques (normal map / POM / SPOM / real displacement) on one shared shader |
| tiamat | 33 | TS, Three.js | MIT — but see below | 100k-particle SPH fluid simulation, raymarched water |
| minos | 5 | Rust + Vulkan (ash) | MIT | A different runtime entirely — native planet/terrain/ocean/character engine, not a Three.js codebase |
The tiamat case is the reason this document insists on human verification, not automated trust: GitHub's repository metadata API reports tiamat's license as NOASSERTION — its automatic license detector could not confidently classify it. Reading the actual LICENSE file directly shows a completely standard MIT license; the detector almost certainly chokes on a leading UTF-8 byte-order-mark character before the text. Trusting the API field alone would have wrongly routed a permissively-licensed, bundle-eligible package into the "contact the author first" tier. The registry pipeline below always reads and stores the literal license file text, and requires a human (or the Curator agent, AI_AGENT_API.md) to confirm it, never the platform's auto-classification alone.
minos is included for completeness and is explicitly not an integration candidate at the code level — it's Rust targeting Vulkan directly, a different runtime from the browser/Three.js stack this entire engine is built on (ARCHITECTURE.md principle 1). It's valuable as an algorithm reference: its tectonic-plate terrain model and its Rust port of dryad's tree generator are worth reading when @3jse/terrain and @3jse/flora-dryad are implemented, even though zero code crosses over.
Case study: github.com/galacean/editor-ui
A second, differently-shaped case, worth documenting precisely because it doesn't fit the pattern above and clarifies where the line is.
Galacean is a mature, actively-maintained TypeScript 3D engine (5,800+ stars, MIT, Alibaba-backed) with its own professional editor. @galacean/editor-ui and @galacean/gui are the React component libraries that editor's Inspector/panel UI is built from, published as standalone packages: ColorPicker, BezierCurveEditor, GradientSlider, ParticleSlider, AssetPicker, and typed property-form components (FormItemVector3, FormItemColor, …). Checked directly: both packages are MIT, and — confirmed by reading packages/ui/package.json and packages/gui/package.json, not assumed from the README — their only runtime/peer dependencies are React, React-DOM, Radix UI primitives, and Stitches. Neither package depends on @galacean/engine at runtime; that only appears as a devDependency of the monorepo's demo app. This is a genuinely engine-agnostic UI library, not a Galacean-coupled one — adopting it does not pull in another engine's rendering or scene-graph assumptions.
Why this is Tier A but doesn't go through the @3jse/vendor registry: the registry and the @3jse/<capability>-<upstream> wrapping convention exist for project-facing content and gameplay plugins — things a game built in 3JSE optionally depends on (water, foliage, terrain). An editor UI toolkit is a foundational dependency of @3jse/editor itself, the same category as Monaco for the Code Editor panel (PLUGIN_ARCHITECTURE.md's build/wrap/adopt table) — every 3JSE project uses it or none do, there's no per-project opt-in decision, and it never ships inside a game's Publish build at all (BUILD_DEPLOYMENT.md's tree-shaking already excludes the entire editor). Routing it through the same registry/staging/attribution machinery built for game-content plugins would be the wrong mechanism for the right instinct. It's adopted once, directly, as documented in EDITOR.md's "UI implementation" section — full credit given there and in the engine's own THIRD_PARTY_NOTICES, same as any other adopted dependency, but without a Tier A/Tier B decision to make per project.
The one real commitment this adoption forces, stated plainly: it pins the editor's UI layer to React. ARCHITECTURE.md and EDITOR.md previously left that framework choice open; this is the concrete reason to close it now rather than defer it further — a library this well-matched to the exact problem (built by a team that has already shipped a professional 3D editor's Inspector) is worth the commitment, and Tauri's webview hosting model (EDITOR.md) is indifferent to which framework runs inside it.
Case study: Babylon.js — the adjacent engine
The two case studies above cover small demo repositories and an editor UI library. This one covers the one project actually adjacent to 3JSE itself, and it exists for a different reason than either. Babylon.js (Apache-2.0, Microsoft-backed, first released 2013) is the closest thing to 3JSE in the world — a TypeScript, WebGPU-capable engine with a deep tooling stack. That means two jobs: (1) pin the differentiation hard enough that 3JSE never drifts into rebuilding Babylon, and (2) inventory what to adopt, because well over a decade of permissively-licensed tooling is the best free reference stack in web 3D — ignoring it would violate the same build/wrap/adopt discipline this document exists for.
What Babylon actually is
Checked against the public repository and docs, not assumed:
| Piece | What it is | License |
|---|---|---|
@babylonjs/core + ~30 satellite packages | Monolithic engine; satellites are tightly coupled to core internals | Apache-2.0 |
| Own renderer | WebGL2 + WebGPU paths maintained in-house, plus Babylon Native (JSI-based native runtime for iOS/Android/desktop) | Apache-2.0 |
| Playground | Browser REPL with shareable snippet IDs — their community and docs engine | Apache-2.0 |
| Inspector | Runtime debug overlay: picking, property readout, render stats | Apache-2.0 |
| Node Material Editor (NME) | Visual shader authoring with frame nodes and previews — materials only, no gameplay logic | Apache-2.0 |
| glTF sandbox / validator | Asset-checking tooling, environment studio, Draco/KTX2/BasisU handling | Apache-2.0 |
| Physics plugins | Ammo, Cannon, Havok (WASM), Oimo behind one plugin interface | Apache-2.0 |
| Scene serialization | Engine-coupled .babylon format with its own versioning history | — |
| Governance | Yearly majors, long deprecation warnings, public breaking-changes policy | — |
How 3JSE differs — pinned
Babylon is the best renderer the web has. 3JSE is everything a renderer needs around it to become a platform. That is a different layer, not a better renderer — VISION.md's non-goals apply to Babylon exactly as they apply to Unreal:
- Platform-first vs engine-first. Babylon's primary authoring surface is code; its serialization is engine-coupled. 3JSE's primary authoring surface is the editor (
EDITOR.md), and the runtime is one standalone layer of ten (ARCHITECTURE.md). - One IR, four frontends vs code-only plus materials-only graphs. NME is excellent at shaders and says nothing about gameplay. 3JSE Graph compiles to the same IR as hand-written TypeScript (
GAMEPLAY_IR.md,VISUAL_SCRIPTING.md), bidirectionally — there is no Babylon equivalent to editing logic in a graph and reading it back as code. - AI-native vs library. An agent operating Babylon writes JavaScript against a library, the same posture as raw Three.js. An agent operating 3JSE uses the editor's own command surface and verifies by running the game (
AI_AGENT_API.md). Nothing about Babylon's architecture prevents this — it simply was not designed in, and retrofitting it onto a monolith is a different project from designing it in from layer 0. - Project format.
.babylonis an engine artifact; 3JSE projects are readable, deterministic, git-diffable text (PROJECT_FORMAT.md). - Renderer posture. Babylon's financing went into owning the renderer — that is its bet and its moat. 3JSE's bet is the opposite: Three.js as an upgradable dependency, never a fork (
ARCHITECTURE.mdprinciple 1), fighting everywhere the renderer isn't. - Governance and coupling. Microsoft-backed MIT vs independent GPL-3.0; a monolith with coupled satellites vs a small core with first-class plugins (
PLUGIN_ARCHITECTURE.md). Both are coherent; they produce different guarantees.
What to adopt — the inventory
- The Playground mechanism (adopt the mechanism, Phase 2). Snippet IDs in URLs, save-to-gist, docs/forum integration. 3JSE's editor-in-a-tab is already half a playground; shareable project-link mechanics turn "share a project by URL" (
EDITOR.md) from a convenience into a community engine. No Babylon code is needed — the mechanism is the asset. - Inspector → reference for a Viewport debug overlay (reference). Picking, property readout, and draw-call stats as a dev-time overlay fit the Profiler/Console panel family (
EDITOR.md) directly; port the pattern, never the code (engine-coupled to@babylonjs/core). - NME → the Material/Shader Graph's UX reference (reference). Frame nodes, preview thumbnails, subgraphs —
RENDERING.md's TSL-compiling graph gets its interaction model from NME the wayapatecontributed techniques below: as documented pattern ports, never imported code. - glTF sandbox/validator → the Asset Pipeline's analyze checklist. Their validation list, environment-studio conventions, and Draco/KTX2/BasisU matrix are a ready-made spec for
ASSET_PIPELINE.md's analyze-and-suggest step. - Multi-backend physics plugin API → validation for
@3jse/physics-rapier. Ammo/Cannon/Havok/Oimo behind one interface (PHYSICS.md) proves the abstraction; when a second backend arrives it slots in the same way — the registry's physics capability notes should flag this for the day that happens. - GPU particle architecture → Phase 5 VFX graph reference. Compute-based, per-particle data textures — the architecture
ROADMAP.mdPhase 5's VFX graph should adopt rather than CPU-reinvent. - Babylon Native → input for
BUILD_DEPLOYMENT.md's mobile/desktop story. Their JSI shell is the alternative to the Tauri-plus-wrapper route; studying it either validates the current bet or changes it cheaply, beforeBUILD_DEPLOYMENT.md's wrapper phase locks in. - Serialization and versioning history → free hardening for
PROJECT_FORMAT.md. A decade-plus of "what breaks between versions," plus a public yearly-major deprecation policy, are the two inputsPROJECT_FORMAT.md's migration design andPLUGIN_ARCHITECTURE.md's stability guarantees should be checked against. - Docs discipline. Every Babylon feature page carries a live Playground snippet. Once the Playground mechanism lands, 3JSE docs should require the same — the manual is design-strong and example-thin today.
Registry entries — a third disposition: reference
The two adoptable codebases (Inspector, NME) are Apache-2.0 and pass the license gate, but Tier A's criterion — "adaptable without forking the upstream project wholesale" — they fail: both are wired into @babylonjs/core internals, and extracting them is a rewrite, not a wrap. Tier B's project-level staging is the wrong mechanism for the same reason the Galacean adoption above is: engine-team reference material is not a per-project opt-in decision. The registry therefore gains a third disposition, reference, formalizing the precedent minos and apate already set informally:
{
"id": "babylon-nme",
"source": "github.com/BabylonJS/Babylon.js",
"pinnedCommit": "<reviewed-commit>",
"license": { "spdx": "Apache-2.0", "verifiedBy": "human", "verifiedAt": "2026-08-24" },
"stack": { "renderer": "webgl2+webgpu", "framework": "babylon.js" },
"tier": "reference",
"package": null,
"capability": "material-graph-ux",
"notes": "Reference only. The frame-node/preview/subgraph interaction model is the adoptable core; port patterns into RENDERING.md's Material Graph, never import. Engine-coupled to @babylonjs/core."
}Reference entries appear in the Open Source panel with a "Reference" badge and attribution, have no import button, and cannot be staged into a project. They exist so that a human or an agent porting patterns has the pinned, license-verified source attached to the task — the same plan → act → verify loop as a Tier B adaptation, minus the project-local staging. babylon-inspector is the second entry; the Playground, glTF-sandbox, physics-API, and serialization rows above are adoption notes, not entries — there is no code to stage.
What deliberately is not adopted
- The community Babylon.js Editor. An editor bolted onto a code-first engine, operating outside the engine's own command surface — precisely the "parallel, drifting authority" failure mode
ARCHITECTURE.mdprinciple 3 exists to prevent. It is the clearest available evidence that 3JSE's editor-as-GUI-for-the-command-API design is the correct bet, not a stylistic choice. - The monolith's coupling model. Satellite packages reaching into core internals is how one well-funded team ships fast; it is also the opposite of the plugin boundary
PLUGIN_ARCHITECTURE.mdneeds. Adopt their output, not their structure. - The renderer war. Babylon maintains WebGL2, WebGPU, and a native runtime in-house. 3JSE rides Three.js and its WebGPU migration (
PERFORMANCE.md's dual-path posture) — matching Babylon's renderer investment is a non-goal (VISION.md), not a gap.
Assemble-first posture
Scaffold, then assemble. It is 2026 — the Three.js ecosystem ships better parts, faster, than any small team builds from scratch, and cutting-edge AI projects appear weekly. The default for every new capability is therefore the build/wrap/adopt ladder, in this order: adopt (import a battle-tested dependency), wrap (extract a demo's core into an @3jse/ package — the Tier A job), and only build when nothing good exists. "The AI will build it" is the last resort, not the first step; the Agent API exists to assemble* these parts correctly, fast.
The first wave is @3jse/extras: three-mesh-bvh (picking/raycast acceleration), troika-three-text (SDF text), postprocessing (composable effects), maath (standardized math helpers), and three-stdlib (modern addons) — all MIT, all adopted as dependencies, each with a doc comment naming what 3JSE uses it for.
The license notebook — bookkeeping, not archaeology
Licensing headaches disappear by recording licenses, not by avoiding third-party code. packages/vendor/licenses.json is the machine-readable notebook for everything the workspace depends on, generated by tools/license-scan.mjs — run it after any dependency change:
- Workspace dependencies — every installed package's license + repo, read from the actually installed
package.json(the pnpm store, not the declared range).verifiedBy: "installed-package-json". - Vendor registry entries — merged with their human-verified status, so the notebook shows the full picture in one place.
- Human overrides — packages whose npm metadata lacks a license field but whose repo LICENSE was read by a human (the Galacean case is the first entry).
License posture, stated plainly: MIT / Apache-2.0 / BSD / Zlib — adopt freely. GPL — adopt freely; 3JSE is GPL-3.0 and the copyleft flowing onward is a feature, not a bug. AGPL — adopt with eyes open: network-use obligations travel. Unlicensed or NOASSERTION — the BOM rule applies (tiamat's case above): read the LICENSE file; if none exists, treat the work as all-rights-reserved regardless of what the platform's API field says. Cutting-edge AI projects enter through the same door as everything else — Shop entry or Tier B staging, license recorded, nothing executed at import.
Two integration tiers
Tier A — Bundled official plugin
Criteria: permissively licensed (MIT/BSD/Apache-2.0/CC0, human-verified per above), technically adaptable into the Component/System/Graph-node shape (PLUGIN_ARCHITECTURE.md's extension points) without forking the upstream project wholesale, and not dependent on a runtime 3JSE doesn't already target.
What "adapted" means here matters. None of poseidon, gaia, dryad, demiurge, or apate are npm libraries — they are, in the authors' own words, "browser prototypes": a Vite app with its own main.ts, its own camera rig, its own scene bootstrap, built to be run and looked at, not imported. Tier A is not npm install poseidon-ocean — it's extracting the reusable core (the compute pass, the material, the generation algorithm) out of the demo shell and re-homing it as a @3jse/* package that registers a Component, a System, and Graph/Material-Graph nodes the way PLUGIN_ARCHITECTURE.md specifies, crediting the upstream source in the package itself. That extraction is real, non-trivial engineering per package — this document is not claiming otherwise.
Naming convention: @3jse/<capability>-<upstream-name>, so the origin stays visible in every package.json and every dependency graph, permanently — e.g. @3jse/water-poseidon, @3jse/foliage-gaia, @3jse/flora-dryad.
Tier B — Fetch-on-demand community import
Criteria: everything else — license unclear or not yet human-verified, not yet adapted, or simply not curated into Tier A yet. This is the default landing tier for anything new; graduating to Tier A is a deliberate, reviewed step, never automatic.
Tier B packages are never bundled into the default install or a shipped Publish build. They are pulled into a specific project on explicit user action inside the editor, staged as visible, attributed reference source, and left for a human or an AI agent to adapt — the Agent API's plan → act → verify loop (AI_AGENT_API.md) applies directly here: "adapt the staged tiamat fluid sim into a FluidVolume component" is a legitimate agent task once a human has confirmed the license is acceptable for the project.
A third disposition, reference, covers engine-team reference material that is neither a per-project import nor a wrap — defined in the Babylon.js case study above, formalizing the minos/apate precedent. Reference entries are listed for attribution and attachable to agent tasks, but have no import button and never stage into a project.
The in-app fetcher: @3jse/vendor
A new package and a new Content Browser sub-panel ("Open Source," alongside the project's own assets — EDITOR.md), doing three things:
1. Registry
A versioned JSON manifest — itself just a file under version control, editable by PR the same way any other part of 3JSE is — listing known repos with the fields the tier decision and the fetcher UI both need:
{
"id": "poseidon",
"source": "github.com/owenyuwono/poseidon",
"pinnedCommit": "a3f9e21",
"license": { "spdx": "MIT", "verifiedBy": "human", "verifiedAt": "2026-08-24" },
"stack": { "renderer": "webgpu-only", "framework": "three.js" },
"tier": "A",
"package": "@3jse/water-poseidon",
"capability": "water",
"notes": "No WebGL2 path upstream — 3JSE plugin must supply a WebGL2 fallback shader (see RENDERING.md)."
}Entries start life added by anyone (a developer, a curator, a future Curator-agent scanning GitHub the way an earlier draft of this project's marketplace concept proposed) but a Tier-A entry's license.verifiedBy: "human" field is a hard gate the fetcher UI enforces — an unverified or auto-detected-only entry cannot be marked Tier A, full stop, regardless of what the upstream API field says.
2. Browse → Import flow
- Browse: the panel lists registry entries with license, stars, a screenshot/preview where the upstream repo has one, tier, and — for Tier A — the wrapping package's install button.
- Import (Tier A): installs the
@3jse/wrapper package normally (PLUGIN_ARCHITECTURE.md's manifest/extension-point mechanism); nothing new architecturally, this is* an ordinary plugin install, just discovered through this panel instead of a bare package name. - Import (Tier B): fetches a pinned-commit tarball (not a live git clone, not a floating branch — reproducibility and supply-chain hygiene both depend on a fixed commit) via the GitHub API, and stages it under
/plugins/_vendor/<id>/in the project (PROJECT_FORMAT.md's/pluginsdirectory, exactly as specified there). ATHIRD_PARTY_NOTICESentry is generated automatically: source URL, pinned commit, license text, author.
3. Sandboxing on import
Fetched Tier B source is never executed in the editor process at import time. It's treated exactly like an Asset Pipeline import (ASSET_PIPELINE.md's analyze-and-suggest pattern) — static inspection (what does it import, what does it touch) surfaces as information in the panel, not as running code. It only becomes live, executing code once a human or an agent explicitly wires it into a registered plugin extension point, at which point it inherits the same capability-scoped sandbox every plugin runs under (PLUGIN_ARCHITECTURE.md's "Sandboxing and trust" section) — a staged vendor import gets no more ambient access than a hand-written plugin would.
Worked examples, against the real registry entries
Vendoring status (2026-08-24): the full Owen pantheon is vendored into this repository at pinned commits under packages/vendor/upstream/ — poseidon (671053b), gaia (f23a32d), dryad (e85729b), demiurge (cb3e178), tiamat (e389a99, Tier B reference — license pending the BOM read), apate (ae62cac, reference), minos (ea8f76e, reference). The four Tier A wraps exist as real workspace packages — @3jse/water-poseidon, @3jse/foliage-gaia, @3jse/flora-dryad, @3jse/terrain-demiurge — each re-exporting the pure core now (generation math, no Three.js import) with the rendering half as the editor-slice step, exactly as described below. Registry entries carry pinnedCommit + vendored fields; tools/license-scan.mjs records every vendored LICENSE in the notebook.
poseidon→@3jse/water-poseidon(Tier A). The FFT ocean compute pass and its TSL material become aWaterVolumeComponent + System, matchingRENDERING.md's "compile into Three's own TSL" posture almost for free, since poseidon is already TSL-native. The one adaptationRENDERING.md's dual-backend requirement forces: poseidon is WebGPU-only with no WebGL2 path, so the plugin must ship a simpler built-in fallback shader for the WebGL2 case (PERFORMANCE.md's permanent-second-render-path posture) — the registry'snotesfield flags this explicitly so it isn't discovered late.gaia/dryad→@3jse/foliage-gaia,@3jse/flora-dryad(Tier A). Both authors' own READMEs already separate "generation" (pure ESM, Node-testable, no Three.js import) from "rendering" (Three.js-specific) — which happens to mirror 3JSE's own frontend/backend split inGAMEPLAY_IR.mdalmost exactly. The generation half becomes a deterministic Component/Resource (genome + seed in, skeleton graph out); the rendering half becomes a System building anInstancedMesh. Because both are procedural with zero authored mesh/texture assets, they sidestep the Asset Pipeline's import step (ASSET_PIPELINE.md) entirely — a designer paints aFoliageFieldand the geometry is generated at edit time and again at runtime from the same seed, never shipped as binary mesh data. This is the vegetation half ofTEMPLATES.md's Open World template's real content source, not a placeholder.demiurge→@3jse/terrain-demiurge(Tier A, Phase 5+). A procedural mode for@3jse/terrainalongside hand-authored heightfields — relevant onceWORLD_SYSTEM.md's World Partition large-world story is in active use. Also WebGPU-only upstream; same fallback-shader obligation as poseidon.tiamat(Tier B, pending re-verification). Its actual license is MIT (confirmed above), so once a human marksverifiedBy: "human"in the registry it's eligible to graduate to Tier A as a future@3jse/fluid-tiamat— SPH particle fluid feeding@3jse/physics-rapierinteractions and a raymarched surface. Until that verification step happens, it sits in Tier B exactly as the policy requires, which is the entire point of not trusting the platform's ownNOASSERTIONfield as a final answer in either direction.apate— not a plugin. A shader-technique comparison, not a reusable system. Its four relief techniques (with credit) become reference implementations feeding the Material Graph's node library (RENDERING.md) — aParallax Occlusionand aSilhouette POMnode, contributed as documented technique ports rather than an installable package.minos— reference only, not an integration. Different runtime (Rust/Vulkan); see above.
Licensing and attribution posture
- A Publish build (
BUILD_DEPLOYMENT.md) auto-generates aTHIRD_PARTY_NOTICESfile from every installed Tier A package's and every staged Tier B import's registry entry, and the editor offers a Credits UI block (GAMEPLAY_FRAMEWORK.md's UI system) a project can drop straight into a menu. - No Tier B import is ever silently included in a Publish build — the build step fails loudly (not just a warning) if unresolved Tier B source is referenced by anything that would actually ship, forcing the explicit "yes, adapt this into a proper plugin, with attribution" step first.
- Registry entries are re-checked periodically (a Curator-agent task, in the spirit of the community-scanning idea explored for the plugin ecosystem —
ROADMAP.mdPhase 6) because upstream license terms, default branches, and repository visibility can all change after an entry is added; a stale, unverified entry is treated as no better than a brand-new unverified one.
Roadmap placement
@3jse/vendor (the fetcher and registry panel) belongs in Phase 3, alongside 3JSE Graph's plugin extension points (ROADMAP.md) — deliberately earlier than the Tier A plugins it enables. A developer should be able to browse and stage the best available open-source work long before an official core-team adapter exists for it; Tier B staging plus the Agent API's assist loop is what makes that useful even before Phase 5, when @3jse/water-poseidon, @3jse/foliage-gaia, and @3jse/flora-dryad are the actual planned graduations into @3jse/terrain/@3jse/water/@3jse/foliage's Phase 5 delivery (ROADMAP.md).
The Babylon.js reference entries land with the same Phase 3 delivery (the Open Source panel's "Reference" badge exists from day one), and the Playground-mechanism adoption is a Phase 2-adjacent EDITOR.md item rather than a registry concern — no code crosses over. The GPU-particle architecture is read when Phase 5's VFX graph starts, not before.
Project modulesVENDOR_PROJECT_MODULES.md
Unreal asks which plugins a project loads. Godot asks which addons a project enables. 3JSE does the same thing at New Project time: a checklist of capabilities, each backed by one or more @3jse/vendor registry entries. Checking a box writes ordinary package dependencies into project.json (TEMPLATES.md, PROJECT_FORMAT.md) — never a second, hidden project format.
The live catalog is packages/vendor/registry.json. This page is the policy for how those rows become checkboxes, and the case notes for the wave added 2026-08-24.
How a checkbox behaves
| User action | What actually happens |
|---|---|
| Check a Tier A module | Install the @3jse/<capability>-<upstream> wrapper. The game depends on the wrapper, not the upstream Vite app. |
| Check a Tier B module | Fetch the pinned-commit tarball into /plugins/_vendor/<id>/, write THIRD_PARTY_NOTICES, do not execute the source. A human or agent still has to adapt it onto an extension point before Play or Publish. |
| A reference row | Visible in the Open Source panel with a Reference badge. No checkbox. No staging. |
| Uncheck before first Play | Drop the dependency / delete the staged folder. |
| Leave a Tier B staged and referenced at Publish | Build fails loud (VENDOR_INTEGRATIONS.md). |
Editor-only modules (editorOnly: true in the registry) never appear in a Publish graph. Text-to-motion is the first of those.
Module ↔ template defaults
These are defaults, not locks — a Third Person project can still enable water later.
| Template | Pre-checked modules |
|---|---|
| Third Person / First Person / Platformer | motion-gen (editor tool, off unless the machine can run it) |
| Surfing | water (poseidon) |
| Open World | water, foliage, flora, terrain |
| FPS / RPG | vfx |
| Physics Sandbox | fluid |
| Walking Simulator | foliage |
Wave added 2026-08-24
Kimodo — text-to-motion as an editor tool, not a runtime
Sources:
- NVIDIA upstream: github.com/nv-tlabs/kimodo — Apache-2.0 code. Checkpoints are a different license: SOMA/G1 = NVIDIA Open Model (commercial-friendly);
Kimodo-SMPLX-RP-v1= NVIDIA R&D Model. Llama-family text encoder has its own Hugging Face terms. - LocalAI port: github.com/localai-org/kimodo.cpp — C++/GGML, CPU or Vulkan, C API emits SMPL-X22 local rotations + root translation. Write-up: 3dxdev.com … kimodo-cpp. No LICENSE file in the tree as of pin
e55a42a. That is why it is Tier B withverifiedByempty, even though the NVIDIA repo is Apache-2.0. Do not inherit a license across repositories.
3JSE shape: an Animation panel action, "Generate clip from prompt." Inference runs in a Tauri sidecar (or a user-provided LocalAI endpoint), the clip is retargeted onto @3jse/character, and the weights stay on disk. Nothing about Kimodo is a game-side System. A WASM/GGML in-page path is a later experiment, gated on the cpp license read.
Prefer SOMA-RP-v1.1 over the SMPL-X R&D checkpoint for anything that might ship near a commercial project.
Chiro Elemental Sandbox — Niagara-class ability VFX, still a demo shell
Sources:
- Canonical: github.com/achrefelouafi/LinearAbiltyCastingThreeJS — MIT, LICENSE read 2026-08-24, pin
ba61847. - Expansion fork: github.com/majidmanzarpour/threejs-vfx — same MIT text.
- Live: linearabilityextthreejs.pages.dev
- Signal: x.com/TokenGremlin/status/2091967294582727005, author x.com/chirovisuals
What it actually is: hand-written GLSL, GPU instanced particles, procedural geometry, ten abilities (radials, boosts, portals, one linear cast), and a pause-and-sculpt slider bank. No textures, no sprite sheets, no baked effect meshes.
Same extraction job as poseidon. The reusable core is the emitter + shader graph for each ability, not the character controller and not the 938-slider debug chrome. Planned wrap: @3jse/vfx-chiro. Stays Tier B until that extraction exists and a WebGPU/TSL path is sketched — upstream is WebGL/GLSL.
The interaction model (freeze a spell mid-frame, reshape timing and silhouette) is what Phase 5's VFX graph should feel like. That part is a pattern port even if the GLSL is later rewritten.
Complement, not duplicate: mustache-dev/Three-VFX is the closer-to-a-library GPU particle engine (MIT file present, verifiedBy still pending). Chiro is the ability pack; Three-VFX is the particle backend candidate.
Quantum Core — look-dev only
Source: CodePen / sabosugi, signal x.com/sabosugi/status/2091589195626328506.
No GitHub mirror, no LICENSE. Registry tier is reference. The Open Source panel may link the pen for art-direction reference. It must not stage, import, or paste CodePen source. If the author publishes a repo under MIT/Apache/BSD/CC0, reopen as Tier B.
Already on the books (Owen pantheon)
Unchanged policy, now also addressable as project-module checkboxes:
| Checkbox | Upstream | Wrap |
|---|---|---|
| Water / Ocean | owenyuwono/poseidon | @3jse/water-poseidon |
| Foliage / Grass | owenyuwono/gaia | @3jse/foliage-gaia |
| Trees / Flora | owenyuwono/dryad | @3jse/flora-dryad |
| Terrain / Planet | owenyuwono/demiurge | @3jse/terrain-demiurge |
| Particle fluids | owenyuwono/tiamat | staged until LICENSE BOM verification is marked human |
apate and minos stay reference.
Deliberately not a module
Three.js Water Pro (paid store asset) — same capability as poseidon, proprietary license. 3JSE does not vendor store assets.
Curator queue
Before any of the new B rows can move:
- Read
localai-org/kimodo.cppNOTICE + source headers; write an SPDX or keep it B forever. - Flip
tiamat.license.verifiedBytohuman(LICENSE is MIT; detector is wrong). - Read
mustache-dev/Three-VFX/LICENSE.mdandmatsuoka-601/WebGPU-OceanLICENSE. - Pin
dryad/demiurge/tiamatto full SHAs the way poseidon already is. - Watch for a licensed GitHub mirror of Quantum Core — do not chase the pen.
Verse CompatibilityVERSE_COMPATIBILITY.md
Framing
Verse is Epic's programming language for UEFN, designed around determinism, concurrency primitives suited to gameplay, and a strong type system. It is not open, not portable outside Epic's ecosystem today, and its runtime is not something 3JSE can or should depend on. The question this document answers is narrower than "should 3JSE support Verse": it's which parts of Verse's design are worth 3JSE deliberately resembling, independent of Epic's implementation.
The six levels, evaluated
| Level | Description | Verdict for 3JSE |
|---|---|---|
| 0 — No compatibility | 3JSE's scripting concepts owe nothing to Verse | Rejected — not because Verse compatibility is a goal in itself, but because Level 1 costs nothing and has real upside (below) |
| 1 — Conceptual mapping | 3JSE's concepts (events, typed data flow, entities/components) map cleanly onto Verse's mental model, even though nothing compiles between them | Adopt. This is close to free: 3IR already has typed events, effect-ordered execution, and entity references (GAMEPLAY_IR.md) — the same shape Verse gameplay code uses. A developer who knows Verse should recognize 3JSE Graph and the Component model within minutes, the same way VISION.md asks for Blueprint/Unity/Godot developers |
| 2 — Verse-inspired syntax → 3IR | A textual frontend using Verse-like syntax (not Verse itself) compiles into 3JSE Gameplay IR, the same way the TypeScript adapter does | Adopt as a future frontend, not required for MVP. 3IR's frontend-agnostic design (GAMEPLAY_IR.md) already anticipates exactly this; it's a new IR-producer, not a re-architecture. Real usefulness: developers who like Verse's failure-as-control-flow and concurrency-block idioms get a home for that style without 3JSE forking Verse's spec |
| 3 — Import a portable Verse subset | Parse a genuinely portable subset of real Verse source (no UEFN-specific API calls) into 3IR | Investigate, don't commit. Feasibility depends entirely on Verse's actual grammar being separable from its standard library and licensing terms allowing redistribution of a parser — neither is something to assume favorably without checking Epic's published spec and license at implementation time. Treated as a research spike (ROADMAP.md Phase 0), not a planned deliverable |
| 4 — Emulate selected Verse APIs | Ship @3jse/verse-compat-style shims for specific well-known Verse standard-library functions/effects | Reject as a priority. This is the highest-cost, lowest-value level: it requires tracking Epic's evolving standard library indefinitely for a compatibility promise that only pays off for code that also depends on UEFN-specific systems 3JSE doesn't have (Fortnite-specific devices, etc.) — the emulation would be compatible with syntax but not with the surrounding platform, which is most of what makes a Verse script actually run |
| 5 — Full Verse runtime compatibility | Run actual Verse programs, unmodified, against 3JSE | Reject. Requires depending on Epic's runtime semantics and likely licensing terms 3JSE cannot control, for a payoff (running existing UEFN Verse content) that is a different product from what VISION.md defines. This would also quietly re-introduce the exact problem ARCHITECTURE.md principle 2 exists to prevent — a second, competing execution engine alongside 3IR |
The recommendation
Target Levels 1–3; do not build 4 or 5. This matches the instinct stated in the brief, and the reasoning holds up under scrutiny: Levels 1–2 are essentially free extensions of decisions 3IR already made for unrelated reasons (a typed, frontend-agnostic IR was going to exist regardless of Verse), Level 3 is worth a scoped research spike but not a commitment, and Levels 4–5 would make 3JSE strategically dependent on Epic's roadmap and licensing to deliver a compatibility promise that can't actually be kept in full (a Verse script's behavior depends on UEFN's surrounding platform, not just its syntax).
Concept mapping (Level 1, concrete)
| Verse concept | 3JSE equivalent |
|---|---|
class with var/const fields | Component schema (ENTITY_COMPONENT_MODEL.md) |
Effects (<transacts>, <varies>, etc.) | 3IR's pure vs. impure node distinction (GAMEPLAY_IR.md) |
spawn / concurrency blocks | 3JSE Graph async nodes (Timer, Await Signal) / coroutine-style yields |
Failure as control flow (? operator) | Branch nodes plus a defined "optional" pin type in 3IR |
| Verse Devices | 3JSE Behaviors attached to Entities (ENTITY_COMPONENT_MODEL.md) |
| UEFN's persistent/weak-persistent storage | @3jse/save's tagged-Component persistence (GAMEPLAY_FRAMEWORK.md) |
This table is documentation, not a compatibility shim — its value is entirely in making a Verse-literate developer's existing mental model transfer to 3JSE quickly, which is the actual goal VISION.md sets, not source-level interoperability with Epic's ecosystem.
3JSE Harness — v0.2HARNESS.md
What this is
The 3JSE Harness is an agent-native Three.js/WebGPU game-development harness that turns a general coding agent — Claude Code today, other coding agents by design — into a reference-first game-development agent. It is the today-half of the 3JSE project: a working system, not a design document. Source lives in 3JSE_Harness_v0.2/ — canonical agent instructions under .agents/, a Claude Code adapter under .claude/, deterministic scripts under scripts/.
It supplies eight things:
- capability decomposition
- provider selection
- reference/source routing
- asset sourcing and provenance rules
- reusable recipes
- project-aware context loading
- quality gates and evidence requirements
- durable project learnings
Tandem with the engine plan
3JSE is two tracks, one bet.
| Track | Status | What it is |
|---|---|---|
| 3JSE Harness (this page) | Working today, v0.2 | Agent-native development system: coordination, routing, reuse doctrine, quality gates, evidence requirements, guard rails. |
3JSE Engine (VISION.md → ROADMAP.md) | Design package | The platform the harness's games converge on: object model, Gameplay IR, editor, Agent API, deployment. |
The harness's governing idea is deliberately the inverse of a traditional engine:
3JSE is not an editor. The coding agent is the editor. Visual tools are added only when repeated work proves they are necessary.
The graphical surface is a witness to project state that the agent and the structured project data already own. This is the same "AI-native means legible to both the AI and the human" posture as VISION.md — applied today with disciplined prompting and gates, rather than tomorrow with a typed command surface. The harness is where the plan's claims get tested against reality first; the engine is where they become first-class machinery.
Core doctrine
Do not invent what can be found. Do not generate what can be reused. Do not rebuild what can be adapted.
Reference implementations, working code, legal reusable assets, executable examples, tests, screenshots, and measured evidence outrank additional prose.
The reuse ladder
Before implementing any non-trivial system or asset, the agent routes through, in order:
| Rung | Source | Notes |
|---|---|---|
| 0 | Current project implementation | Existing working code in the repo always wins. |
| 1 | Current project asset | Existing models, textures, audio in the project. |
| 2 | 3JSE curated provider / shared asset | Named providers in the registry (below). |
| 3 | Proven reference implementation | Working examples — code > test > demo > video > screenshot > docs > prose. |
| 4 | Licensed external asset | With recorded provenance and license. |
| 5 | Procedural generation provider | Deterministic procedural systems (grass, trees, ocean…). |
| 6 | Adjacent implementation, adapted | Port or adapt a relevant subsystem. |
| 7 | Custom implementation | Last resort — and only with written justification. |
The agent must justify skipping an earlier applicable rung. Named providers outrank generic primitives when they satisfy the capability — e.g. Poseidon before PlaneGeometry + MeshPhysicalMaterial for ocean, Gaia before hand-written instanced grass, Dryad before ad-hoc cone trees, OSM/map3d before hand-built city blocks.
Architecture: coordination is the product
The harness owns coordination and institutional knowledge. External providers own specialized rendering/simulation capabilities whenever they already solve the problem well.
- Worker model — keep it small. Five roles: Director, Gameplay, Graphics, Assets/References, QA/Performance. Most specialization loads as Skills, not as dozens of persistent personas.
- Context routing. Only load skills relevant to the capabilities the current task actually needs. Never inject the entire library into context.
- Canonical directories.
- .agents/skills/ — canonical skill source (24 skills) - .agents/registry/ — provider / capability / mechanic / security registries - .agents/recipes/ — reusable game archetypes (5 recipes) - .agents/hooks/ — deterministic quality gates - .claude/skills/ — Claude Code mirror/adapter of .agents/skills/ - .claude/hooks/ — Claude Code guard hooks (destructive-git, clean-code) - evidence/ — reports, screenshots, metrics, playtest notes - wip/ — git-ignored local bench: verification captures, probes, handoff notes
The mandatory route for broad game tasks
For any request to create, upgrade, finish, polish, debug, or extend a game:
- Read the 3JSE Director skill.
- Resolve requested capabilities with the Capability Resolver.
- Route each capability through the Vendor Router.
- Search existing project code/assets before introducing a new dependency or primitive.
- Use the appropriate provider skill(s).
- Build a playable vertical slice before broad content production.
- Run gameplay, visual, runtime-error, and performance verification before claiming completion.
Skill catalog (24)
3jse-director · capability-resolver · vendor-router · asset-broker · reference-broker · safe-repo-inspector · project-learning · mechanics-harness · engine-package · threejs-runtime · webgpu · gltf-pipeline · gameplay-qa · visual-qa · performance-qa · provider-poseidon · provider-gaia · provider-dryad · provider-tiamat · provider-demiurge · provider-apate · provider-map3d · provider-react-three-map · provider-3dtiles
mechanics-harness (feel-as-numbers / headless checks / invariant soak / player-agent QA, from the reference games) and engine-package (conventions for building the @3jse/* engine packages themselves, as opposed to games) are both loaded on demand.
Provider registry (14)
| Provider | Tier | Mode | Capabilities |
|---|---|---|---|
Poseidon (owenyuwono/poseidon) | A | provider | Large outdoor oceans, waves, underwater, surf environments — WebGPU spectral ocean. |
Gaia (owenyuwono/gaia) | A | provider | Procedural deterministic grass, lawns, meadows, field vegetation. |
Dryad (owenyuwono/dryad) | A | provider | Procedural trees, shrubs, forests, plant wind. |
Tiamat (owenyuwono/tiamat) | A/B | provider/reference | Bounded dynamic fluids, splashing, flooding, GPU fluid — not open ocean. |
map3d (cartesiancs/map3d) | A/B | provider | OSM-derived real-city buildings and roads; preferred real-city route. |
react-three-map (wendylabsinc/react-three-map) | A/B | provider | R3F/Three content aligned with MapLibre/Mapbox geography. |
3DTilesRendererJS (NASA-AMMOS/3DTilesRendererJS) | A | provider | Streamed 3D Tiles / large geospatial 3D. |
Demiurge (owenyuwono/demiurge) | B | reference | Procedural terrain, erosion, climate, weather, clouds, atmosphere, planet LOD — study/adapt subsystems. |
Apate (owenyuwono/apate) | B | reference | Surface relief: POM/SPOM/displacement before multiplying geometry. |
Minos (owenyuwono/minos) | B | reference | Terrain LOD, voxel terrain, floating origin — Rust/Vulkan; port algorithms, don't import blindly. |
AgentMaps (noncomputable/AgentMaps) | B | reference | Agents on real maps, contagion/social simulation patterns. |
| JollyPixel editor | B | reference | ECS patterns, event store, collaborative scene editing — study internals, don't adopt as the 3JSE editor shell. |
GameStudio (bullish0x/GameStudio) | D | harness reference | Canonical .agents layout and provider-neutral adapters — avoid the persona/skill zoo. |
threejs-game-skills (majidmanzarpour/threejs-game-skills) | D | harness reference | Director loop, visual gate, completion gates — 3JSE uses reuse-first ordering. |
Modes matter: provider may be integrated; reference_implementation is studied/ported selectively; harness_reference is studied for patterns only.
Recipes (5)
- Third-Person Platformer — character controller, camera, ground detection.
- Surf / Kite / Wake Game — ocean/waves → Poseidon, rigged humanoid, board/kite/tow mechanics.
- Open-World Hub (Sector-Based Metaspace) — connected sectors over one enormous always-live world.
- Isometric / Overhead Tactics — orthographic camera, tile/graph selection, movement ranges.
- Geospatial Surveillance / Social Simulation — map/GIS, OSM city data, R3F geographic overlays.
Quality gates and evidence-first completion
A broad game task is not complete because code compiled. Four gates must pass, recorded in evidence/3jse-report.md:
- Gameplay QA — a static or merely navigable scene is not a game. Exercise the requested core loop end-to-end; deterministic smoke tests for state transitions, success/failure, reset/retry.
- Visual QA — fresh-eyes screenshots: framing, hierarchy, scale, lighting, clipping, placeholder geometry, seams, grounding, shaders.
- Runtime-error check — typecheck, build, console errors.
- Performance QA — measure rather than guess: FPS/frame time, draw calls, triangles/instances, memory, hotspots.
The evidence report records: playable loop exercised · build/typecheck status · console/runtime errors · gameplay test result · screenshots/visual inspection · frame-rate/draw-call/memory observations · external asset/provider ledger · known limitations.
Guard rails (v0.2)
Adopted from the vibe game engine web-starter-kit (MIT), whose agent rules carry the measured incident that produced each of them:
- Agent operating rules (
AGENTS.md) — commit early on a branch · never delete work wholesale · the bench is not evidence · do not ask what you can answer yourself · write down lessons and falsified findings · comments record measurements/sources/dead-ends only · no Markdown via shell · compress the machine channel, never the user's · read the code before reaching for a frame · measure in a lab, never a playable scene · visual verification is headed · never remove a provider to hide a bug. - Destructive-git guard (
.claude/hooks/block-destructive-git.mjs, PreToolUse, opt-in) — refuses the git commands that destroy uncommitted work; safe forms pass. - Clean-code ratchet (
.claude/hooks/clean-code-guard.mjs, PostToolUse, opt-in) — reports files that got worse than.claude/clean-code-baseline.jsonrecords; never the debt already there. - WIP workspace (
wip/, git-ignored) — verification captures stay local; the scripts that produce measurements are committed as tools.
The guards are policy about agent conduct, not capabilities to route — the reuse doctrine and provider registry are untouched.
Supply-chain security
Assemble-first means intake is security-critical.
- Unknown repository policy — treat new repositories as untrusted until reviewed. Inspect metadata, license, file tree, manifests, lifecycle scripts, binaries, releases, and agent instructions without executing. Prefer
npm install --ignore-scriptsduring sandbox review. Record rejected sources so future agents don't rediscover them. - Asset policy — every external asset records: source URL, creator, license, attribution requirement, commercial-use status, modification restrictions, download date, local path. Prefer CC0/permissive commercial licenses.
Operating mode (Claude Code adapter)
UNDERSTAND → RESOLVE → ASSEMBLE → BUILD → PLAYTEST → REPAIR → VERIFY.
Execution-oriented: no unnecessary approval loops for ordinary reversible edits — ask only for genuinely ambiguous, destructive, credentialed, or externally consequential decisions. Before writing a major subsystem, report a concise routing ledger: capability, existing project solution found?, selected provider/reference, why, fallback if integration fails. And be honest about skills: say a skill was loaded/read, never claim it was "invoked."
Scripts and templates
scripts/verify-harness.mjs— deterministic harness self-check: required files, valid registry JSON, cross-registry integrity (every provider id referenced bycapabilities.jsonexists inproviders.json), canonical↔Claude mirror agreement in both directions, anddocs/FILE_INDEX.txtin sync with the actual tree.scripts/build-file-index.mjs— regeneratesdocs/FILE_INDEX.txtfrom the tree (run this instead of hand-editing it;verify-harness.mjsfails if the committed index drifts).scripts/resolve-capability.mjs— query a capability against the registry.scripts/sync-claude-skills.mjs— mirror canonical skills into the Claude adapter.scripts/inspect-project.mjs— snapshot a repo's stack before proposing architecture.scripts/clean-code-baseline.mjs [--scope <dir>]— records today's clean-code numbers so the guard reports regressions only.scripts/lib/cleanCode.mjs— the shared measurement the guard and the baseline script both call..claude/settings.example.json— opt-in wiring for the two guard hooks.templates/PROJECT_3JSE.md— project manifest: experience goal, core-loop contract, required capabilities, selected providers.templates/ASSET_REGISTRY.example.json— provenance ledger per asset.templates/EVIDENCE_REPORT.example.md— the completion report shape.
Self-improvement loop
The harness is maintained by agents through bootstrap-claude-prompt.md: audit before modifying, run verify-harness.mjs, identify the three highest-leverage missing capabilities or weak skills, improve them without increasing always-loaded context, keep .agents/ canonical and mirror to .claude/, and add deterministic verification for every meaningful change. A harness change is not done until the registry remains valid, the mirror agrees, the security policy is preserved, and a realistic sample request still routes to sensible providers.
Convergence with the engine plan
The harness's practices today prefigure the engine's machinery tomorrow:
| Harness piece (today) | Engine machinery it converges toward (plan) |
|---|---|
| Director workflow, mandatory route | AI_AGENT_API.md — observe → plan → act → verify as a built-in loop |
| Evidence report fields | runtime.getConsole · runtime.getPerf · runtime.captureState + buildEvidenceReport() — the verify step as engine APIs (headless subset live in @3jse/agent; pixel captureFrame still owed) |
| Gameplay/Visual/Performance QA gates | build.runTests + Profiler panel (PERFORMANCE.md) |
| Asset Broker + provenance ledger | ASSET_PIPELINE.md analysis passes, metadata, dependency tracking |
| Capability Resolver + Vendor Router | PLUGIN_ARCHITECTURE.md extension points — capabilities as registrable contracts |
| Provider registry (14, tiered) | Phase 6 registry/discovery (ROADMAP.md) |
| Recipes (5) | TEMPLATES.md catalog |
| Reuse ladder | ARCHITECTURE.md's build/wrap/adopt framework (PLUGIN_ARCHITECTURE.md) |
| Safe Repository Inspector, sandbox intake | PLUGIN_ARCHITECTURE.md sandboxing + AI_AGENT_API.md capability scoping |
| Project Learning Distiller | Durable learnings → engine-side agent project understanding (AI_AGENT_API.md) |
| Three.js Runtime skill | RUNTIME.md |
| glTF pipeline skill | ASSET_PIPELINE.md glTF-first posture |
The harness is the first working slice of the engine's AI-native layer — and the engine's design documents are, in part, the harness's practices promoted from convention into construction.
3JSE Atlas3JSE_ATLAS_FULL_PLAN.md
Semantic Game Atlas, FeelSpec System, and Agent-Native Visual Development Interface
Status: Product / architecture specification Project: 3JSE Harness Purpose: Replace traditional visual scripting / Blueprint-style authoring with a clearer semantic navigation, tuning, and agent-control system for games built with Three.js / WebGPU and the 3JSE Harness.
1. Executive Summary
3JSE Atlas is not a visual programming language and should never become one.
Its purpose is to make a game understandable, navigable, tunable, debuggable, and editable through an AI agent without forcing the human to work directly in code or reconnect hundreds of execution wires.
Traditional Blueprint systems expose implementation:
Event → Branch → Variable → Function → Cast → Tick → Set Value
Atlas exposes meaning:
Player → Movement → Jump → Landing → Camera → Animation → Score
The core distinction is:
- Code is for agents.
- Graphs are for understanding.
- FeelSpec is for intent and tuning.
- The viewport is a witness.
- Tests and runtime probes prove changes.
Atlas is generated primarily from the real project. It is not the canonical source of program logic. The TypeScript / JavaScript source remains ordinary source code. Atlas builds a semantic model on top of it from:
- declared 3JSE system metadata,
- imports and dependency analysis,
- ECS components,
- events and signals,
- state stores,
- providers,
- assets,
- scene hierarchy,
- tests,
- profiling,
- runtime telemetry,
- FeelSpec,
- recipes,
- mechanic profiles,
- git history,
- agent change history.
The human navigates this model visually, selects a system, and either:
- directly changes safe exposed parameters, or
- tells the agent what should change.
The agent receives narrowly scoped context, modifies the real project, runs verification, and Atlas updates automatically.
This is intended to be simpler than Blueprints while still giving the user greater visibility into the game.
2. Core Design Principles
2.1 Atlas must not become another programming language
The graph is not source code.
Never require the user to manually construct low-level execution logic such as:
Tick
→ Branch
→ Get Component
→ Add Vector
→ Set PositionIf Atlas begins requiring hundreds of interconnected execution nodes, it has failed.
Atlas nodes represent semantic systems and meaningful design concepts, for example:
PLAYER
├── Movement
├── Jump
├── Camera
├── Animation
├── Combat
└── InventoryDrilling into Jump may reveal:
JUMP
├── Takeoff
├── Air Control
├── Apex
├── Double Jump
└── LandingDrilling into Landing may reveal tunable parameters and implementation references.
2.2 Progressive disclosure is mandatory
The user should see only the amount of detail needed at the current zoom level.
The semantic zoom hierarchy is:
GAME
↓
DOMAIN
↓
SYSTEM
↓
MECHANIC
↓
SUBSYSTEM
↓
TUNING PARAMETERS
↓
FILES / TESTS
↓
CODEExamples:
GAME
→ Traversal
→ Player
→ Jump
→ Landing
→ landingTolerance
→ landing.tsThe user should never be forced to start from source files.
2.3 Atlas is generated from the project
The user should not have to redraw Atlas after code changes.
The Atlas compiler builds its model from:
defineSystem()registrations,- FeelSpec declarations,
- file ownership,
- static import graph,
- events / signals,
- ECS relationships,
- state store selectors,
- scene registration,
- provider metadata,
- asset registry,
- tests,
- runtime instrumentation.
Manual graph authoring should be exceptional.
2.4 The viewport is a witness
The viewport answers:
What does the game currently look and feel like?
Atlas answers:
What is this game made of? Why did this happen? What controls it? What depends on it? What should I change?
The viewport and Atlas should be linked but conceptually separate.
2.5 Every meaningful node is an agent control surface
Selecting a node should expose:
- purpose,
- status,
- dependencies,
- dependents,
- provider,
- owned files,
- tests,
- current runtime cost,
- FeelSpec controls,
- recent history,
- agent actions.
Every node should support:
- Explain
- Tune
- Ask Agent
- Test
- Profile
- Show Dependencies
- Show Events
- Show Assets
- Show History
- Open Files
- View Code
- Replace Provider where applicable
3. Atlas User Model
Atlas assumes three classes of change.
3.1 Direct parameter change
Safe, known tuning values can be changed directly.
Examples:
Jump height 1.7 → 2.0
Camera distance 5.5 → 6.2
Drift assist 0.62 → 0.70
Bloom intensity 0.40 → 0.25
Grass density 0.80 → 0.65These should update live where possible.
3.2 Semantic / structural change
The user describes the goal.
Example:
Make clean landings preserve almost all momentum, but punish sideways landings much harder.
Atlas scopes the agent to:
player.tricks.landing
player.physics
combo
animation
related tests
current FeelSpecThe agent edits source code.
3.3 Provider change
The user changes a major implementation source.
Example:
WATER
Current provider: SimpleWater
Suggested provider: PoseidonAtlas shows:
- expected benefits,
- dependencies,
- compatibility,
- performance impact,
- migration plan,
- affected systems.
The agent performs the migration.
4. Semantic System Model
Atlas requires a lightweight semantic contract.
A system may declare:
defineSystem({
id: "player.tricks",
label: "Trick System",
domain: "gameplay",
purpose: "Controls aerial tricks, landing quality, combo continuity, and scoring.",
owns: [
"src/gameplay/tricks/**"
],
requires: [
"player.physics",
"input.actions",
"player.animation"
],
emits: [
"trick.started",
"trick.completed",
"combo.changed"
],
listens: [
"player.airborne",
"player.landed"
],
knobs: {
airControl: {
type: "number",
min: 0,
max: 1,
default: 0.72,
category: "air"
},
landingTolerance: {
type: "number",
min: 5,
max: 90,
unit: "degrees",
default: 32,
category: "landing"
}
},
tests: [
"tests/tricks/**"
]
})This does not define the implementation.
It defines how Atlas understands the implementation.
5. Atlas Graph Types
Atlas should provide multiple visual lenses over the same project.
Users switch views rather than trying to encode everything into one graph.
5.1 System Map
Default view.
Answers:
What systems exist and how are they connected?
Example:
PLAYER
│
┌─────────────┼────────────┐
▼ ▼ ▼
PHYSICS ANIMATION CAMERA
│
▼
TRICKS
│
▼
COMBONode size may communicate importance or runtime cost.
Edges should be typed:
- dependency,
- event,
- state,
- ownership,
- provider,
- asset,
- data flow.
Edges should not all look identical.
5.2 Gameplay Flow View
Shows player-facing sequence and game design logic.
Example:
LEVEL START
↓
SPAWN
↓
SURF SECTION
/ | \
/ | \
TRICKS FISHING SHARK ATTACK
\ | /
CHECKPOINT
↓
FINISHThis is not control flow.
It is design flow.
5.3 State Machine View
Used only where state machines are actually meaningful.
Example:
GROUNDED
│ jump
▼
AIRBORNE
│ grind
▼
GRINDING
│ detach
▼
AIRBORNE
│ land
▼
GROUNDEDTransitions show conditions and emitted events.
5.4 Event / Signal View
Shows event relationships.
Example:
input.jump
↓
player.jump.requested
↓
player.airborne
↓
trick.window.open
↓
camera.airborneWhen live mode is enabled, event pulses animate along the graph.
5.5 Runtime Trace View
Atlas records the last configurable period of gameplay.
Example:
00:04.21 input.jump
00:04.22 player.airborne
00:04.28 trick.started
00:05.11 collision.detected
00:05.12 landing.failed
00:05.13 combo.cancelledSelecting an event highlights:
- originating system,
- downstream systems,
- relevant state values,
- affected entities.
The user can ask:
Why did the combo break here?
Atlas prepares the trace and asks the agent.
5.6 Asset Graph
Shows which assets support which systems.
Example:
SURFER
├── Body GLB
├── Rig
├── Animation Set
├── Board
├── Materials
└── AudioOr:
WORLD
├── Water → Poseidon
├── Trees → Dryad
├── Grass → Gaia
├── City → OSM/map3d
└── Traffic → vehicle library5.7 Provider Graph
Shows reusable technologies.
Example:
ENVIRONMENT
├── Ocean → Poseidon
├── Grass → Gaia
├── Flora → Dryad
├── Terrain → Demiurge
└── Surface Relief → ApateSelecting a provider displays:
- source,
- license,
- version,
- health,
- capabilities,
- integration skill,
- alternatives,
- dependent systems.
5.8 Style Graph
Shows the visual identity of the game.
Example:
VISUAL PROFILE
├── Geometry
│ └── PS1/N64 low-poly
├── Shading
│ └── Cel/PBR hybrid
├── Water
│ └── Photoreal Poseidon
├── Vegetation
│ └── Stylized procedural
├── Lighting
│ └── Saturated coastal
└── Post
├── Bloom
├── Color grade
└── Pixel treatmentThis graph is heavily linked to FeelSpec.
5.9 Performance Graph
Systems can be sized by runtime cost.
Example:
POSEIDON 5.3 ms
DRYAD 2.1 ms
TRAFFIC 1.4 ms
HUD 0.5 msThe user can select Poseidon and ask:
Reduce this by 25% without noticeably affecting surfing quality.
The agent receives performance data and relevant provider instructions.
5.10 World Graph
Shows world / region hierarchy.
Example:
ANDREAS ARCHIPELAGO
├── Capital
│ ├── Castle
│ ├── Museum
│ ├── Skyneedle
│ └── City
├── Suburbs
├── Forest
└── Uncanny ValleyA region node can expose:
- scene files,
- quests,
- music,
- NPCs,
- environmental providers,
- assets,
- mechanics.
5.11 Rig Graph
Rigging should receive a dedicated semantic view.
Instead of showing only bones:
HUMANOID RIG
├── Skeleton
│ ├── Spine
│ ├── Arms
│ ├── Legs
│ ├── Hands
│ └── Face
│
├── Motion
│ ├── Locomotion
│ ├── Foot IK
│ ├── Look-at
│ ├── Aim
│ ├── Procedural Lean
│ └── Secondary Motion
│
└── Animation
├── Idle
├── Walk
├── Run
├── Jump
└── LandRig graph overlays may show:
- active constraints,
- animation blend weights,
- IK contacts,
- bone stress / unexpected rotation,
- missing mappings,
- retarget quality.
The Three.js witness viewport can render the rig alongside the semantic graph.
6. FeelSpec
FeelSpec is a machine-readable representation of mechanical and aesthetic intent.
It exists because game feel is rarely captured by one value.
A jump is not simply jump velocity.
A car is not simply acceleration.
A camera is not simply distance.
FeelSpec describes systems in multidimensional design spaces.
7. FeelSpec Goals
FeelSpec must:
- describe game feel in human-understandable dimensions;
- support reference profiles inspired by well-known game families;
- allow blending between profiles;
- preserve protected values during transformations;
- expose safe direct tuning controls;
- provide the agent with semantic constraints;
- support A/B auditioning;
- create reusable personal / project presets;
- connect changes to automated tests;
- remain implementation-independent.
FeelSpec should describe intent.
Source code realizes that intent.
8. FeelSpec Schema
Example:
version: 1
system: vehicle.arcade
profile:
id: xirtus-arcade-driving-v3
label: Xirtus Arcade Driving v3
references:
burnout_like: 0.50
outrun_like: 0.30
heavy_openworld_like: 0.20
intent:
arcadeSimulation: 0.82
weight: 0.61
steeringResponse: 0.78
stability: 0.72
driftAssist: 0.66
accelerationDrama: 0.91
collisionDrama: 0.88
cameraAggression: 0.76
protected:
- acceleration.topSpeed
- acceleration.zeroToSixty
overrides:
steering.highSpeedDamping: 0.58
suspension.bodyRoll: 0.62
tests:
- driving.slalom
- driving.highSpeed
- driving.collision9. Feel Dimensions
Each system type has an associated FeelSpec vocabulary.
9.1 Driving FeelSpec
Suggested dimensions:
Steering
- steering response
- low-speed assist
- high-speed damping
- countersteer assist
- steering saturation
- steering return rate
Grip
- base grip
- lateral grip
- longitudinal grip
- traction breakaway
- drift initiation
- drift recovery
Weight
- body mass feel
- body roll
- pitch
- suspension travel
- weight transfer
- airborne inertia
Acceleration
- initial acceleration
- midrange acceleration
- top speed
- throttle response
- boost response
Braking
- braking strength
- handbrake authority
- lockup behavior
- brake turn assist
Collision
- collision severity
- momentum retention
- camera impulse
- vehicle deformation abstraction
- recovery assistance
Air
- air steering
- pitch control
- roll control
- landing stabilization
Camera
- follow distance
- rotation lag
- velocity lead
- FOV response
- shake
- collision reaction
Traffic
- traffic density
- unpredictability
- avoidance assistance
- near-miss scoring
9.2 Platforming FeelSpec
- acceleration
- deceleration
- turn responsiveness
- coyote time
- input buffer
- jump impulse
- time to apex
- apex hang
- fall acceleration
- air control
- double-jump authority
- landing forgiveness
- landing squash
- momentum preservation
- slope behavior
- ledge behavior
- camera response
9.3 Trick System FeelSpec
- trick input window
- rotation acceleration
- spin damping
- flip authority
- grind snap
- grind balance difficulty
- manual balance difficulty
- combo timeout
- multiplier growth
- landing tolerance
- clean landing reward
- crash severity
- special meter rate
- camera drama
9.4 Surf FeelSpec
- board looseness
- rail bite
- water coupling
- wave attraction
- carve authority
- pumping power
- tube stability
- aerial launch
- aerial control
- landing forgiveness
- wipeout threshold
- drag
- kite influence if applicable
- tow influence if applicable
- camera aggression
9.5 Camera FeelSpec
- distance
- height
- pitch
- follow lag
- rotational lag
- look-ahead
- target anticipation
- collision avoidance
- FOV
- speed FOV
- landing impulse
- acceleration impulse
- shake
- lock-on influence
- horizon stabilization
9.6 Rig / Locomotion FeelSpec
- stride length
- stride frequency
- foot locking
- turn anticipation
- upper-body lag
- pelvis bounce
- lean
- ground adaptation
- slope adaptation
- step height
- jump anticipation
- landing compression
- arm swing
- procedural head tracking
- IK strength
- animation responsiveness
9.7 AI FeelSpec
- perception radius
- perception certainty
- reaction delay
- memory duration
- prediction
- aggression
- risk tolerance
- group coordination
- flanking preference
- retreat threshold
- persistence
- curiosity
- communication delay
10. Reference Profiles
FeelSpec may include named reference profiles.
These profiles are not proprietary code copies.
They are documented design approximations derived from:
- gameplay analysis,
- legally available source references,
- measurement,
- timing analysis,
- testing,
- known mechanic structures.
Example:
driving_profiles:
arcade_crash_racer:
steeringResponse: 0.86
collisionDrama: 0.95
stability: 0.76
bodyRoll: 0.44
smooth_arcade_tourer:
steeringResponse: 0.72
collisionDrama: 0.42
stability: 0.84
bodyRoll: 0.52
heavy_openworld:
steeringResponse: 0.51
collisionDrama: 0.68
stability: 0.56
bodyRoll: 0.86Atlas may display friendly labels, but implementation metadata should distinguish between:
- exact reusable code,
- legal source reference,
- mechanic analysis,
- aesthetic reference.
11. Feel Blending
FeelSpec should support weighted blending.
Example:
Arcade Crash Racer 50%
Smooth Tourer 30%
Heavy Openworld 20%The resolver calculates a target feel.
Blending does not necessarily mean linear averaging.
Some parameters may use:
- weighted interpolation,
- categorical resolution,
- bounded curves,
- mutually exclusive rules,
- agent-mediated synthesis.
The system must distinguish:
Numeric blendable properties
Example: cameraLag
Structural properties
Example: manualTrickSystemEnabled
Structural conflicts require agent resolution.
12. Natural-Language Feel Transformations
The user should be able to say:
More dangerous, heavier body roll, less snap steering, but do not make it slower.
Atlas produces a proposed delta:
Body roll 0.42 → 0.66
High-speed steering 0.81 → 0.69
Collision drama 0.72 → 0.89
Protected:
Acceleration unchanged
Top speed unchangedThe user can:
- accept,
- reject,
- edit,
- A/B audition.
13. Protected Intent
FeelSpec supports explicit protected constraints.
Example:
protected:
- topSpeed
- jumpHeight
- waveHeightIf a requested change would likely violate them, Atlas warns:
Requested transformation may reduce jump height.
Protected parameter:
jumpHeight = 2.1 m
Proceed using alternate tuning?The agent should search for alternate solutions first.
14. FeelSpec Inheritance
Profiles should support inheritance.
Example:
BASE ARCADE VEHICLE
↓
XIRTUS DRIVING BASE
↓
KAITOSAFIN SHARK-TOW VEHICLEOnly deltas are stored.
This encourages reusable design vocabulary.
15. Personal Feel Libraries
Users should be able to save:
XIRTUS-ARCADE-DRIVING
XIRTUS-CRASH-CAMERA
XIRTUS-PS1-HUMANOID
XIRTUS-THPS-COMBO
XIRTUS-SURF-FEELFuture projects can reuse them.
The harness gradually becomes a personal game-design instrument.
16. A/B Auditioning
A/B comparison is a first-class Atlas feature.
Every FeelSpec-compatible system should support snapshots where technically feasible.
Example:
A = current driving
B = proposed drivingInstant switch:
[A] [B]The user can respond:
Keep B's steering but A's suspension.
Atlas generates a merged FeelSpec.
17. Feel Lab
Atlas should include focused test environments rather than forcing the user to test every mechanic inside a full game.
17.1 Vehicle Feel Lab
Preset scenarios:
- slalom,
- figure eight,
- high-speed straight,
- hairpin,
- drift circle,
- jump,
- collision,
- traffic lane,
- emergency braking.
Measured outputs:
- 0–60 time,
- braking distance,
- steering latency,
- maximum lateral acceleration,
- drift duration,
- body roll,
- recovery time,
- air rotation,
- collision momentum loss.
17.2 Character Feel Lab
Scenarios:
- run,
- stop,
- rapid turn,
- jump,
- double jump,
- ledge,
- stairs,
- slope,
- moving platform,
- narrow platform,
- wall collision.
Measured:
- turn time,
- jump arc,
- landing error,
- foot sliding,
- slope stability,
- camera lag.
17.3 Rig Lab
Scenarios:
- idle,
- walk,
- run,
- sprint,
- crouch,
- reach,
- look-at,
- uneven ground,
- stairs,
- slope,
- jump,
- landing.
Visualization:
- skeleton,
- contact points,
- IK targets,
- blend weights,
- root motion,
- joint limits.
17.4 Surf Lab
Scenarios:
- small wave,
- large wave,
- tube,
- aerial,
- hard carve,
- wipeout,
- tow,
- kite pull,
- variable wind.
18. Three.js Visual Navigation
Atlas should use Three.js where 3D materially improves understanding.
It should not make every graph 3D merely because Three.js is available.
The interface uses a hybrid:
React / HTML
+
2D graph layer
+
Three.js semantic visualization
+
Three.js witness viewport19. Visual Navigation Modes
19.1 2D Semantic Graph
Primary navigation for ordinary system maps.
Recommended implementation:
- React Flow or equivalent,
- deterministic layout,
- typed edges,
- semantic zoom,
- groups,
- minimap,
- search,
- filters.
2D is superior for dense information.
19.2 2.5D Atlas Mode
Use Three.js to turn domains into spatial layers.
Example:
STYLE
▲
│
WORLD ◀── GAME CORE ──▶ GAMEPLAY
│
▼
PLATFORMDomains can be visually separated in depth without free-floating chaos.
Use constrained axes.
Do not permit arbitrary spaghetti positioning.
19.3 System Constellation
For large projects, systems can appear as an orderly constellation.
Design rules:
- fixed semantic neighborhoods,
- color-coded domains,
- limited edge visibility,
- focus-based expansion,
- non-selected nodes fade,
- selected node pulls related nodes forward,
- dependencies form arcs,
- runtime pulses travel only on active edges.
Avoid showing the entire dependency graph simultaneously.
20. Color System
Atlas must be colorful but disciplined.
Suggested semantic colors:
Gameplay amber/orange
Physics blue
Animation violet
World green
AI magenta
UI cyan
Audio rose
Assets gold
Providers teal
Tests lime
Performance red/orange
Style purpleRules:
- color communicates domain, not decoration;
- selected nodes may brighten;
- errors use a separate red state;
- warnings use amber;
- passing tests use green;
- unknown state uses neutral gray;
- avoid rainbow edges;
- no more than one dominant hue per node.
21. Node Design
Every node should be visually simple.
Default node:
┌──────────────────────────┐
│ TRICK SYSTEM │
│ Gameplay │
│ │
│ ● Healthy 18/18 │
│ 0.21 ms │
└──────────────────────────┘Expanded:
┌──────────────────────────┐
│ TRICK SYSTEM │
│ │
│ Provider: Custom │
│ Tests: 18/18 │
│ CPU: 0.21 ms │
│ │
│ Air Control 0.72 │
│ Landing Tol. 32° │
│ Combo Timeout 1.2 s │
│ │
│ [Tune] [Ask Agent] │
└──────────────────────────┘Avoid huge node interiors.
Detail belongs in the inspector panel.
22. Graph Layout Rules
Atlas should actively prevent chaos.
Hard rules
- nodes snap to semantic regions;
- automatic layout is default;
- manually moved nodes retain position only when intentional;
- edges bundle when crossing domains;
- dependency direction is consistent;
- hidden nodes collapse into grouped summaries;
- graphs open focused around current selection;
- labels stay horizontal;
- distant nodes simplify;
- no edge animations unless live trace is active.
23. Semantic Zoom
At far zoom:
PLAYER
WORLD
AI
UIMid zoom:
PLAYER
├── Movement
├── Camera
└── AnimationClose zoom:
MOVEMENT
├── Ground
├── Jump
├── Air
└── LandingVery close:
Landing tolerance 32°
Momentum 0.84
Tests 6/6This is essential to avoiding Blueprint chaos.
24. Focus Mode
Double-clicking a node enters Focus Mode.
All unrelated systems dim or disappear.
Example:
TRICKS
├── Player Physics
├── Input
├── Animation
├── Combo
└── CameraThe user now works in a small comprehensible graph.
Exit returns to project context.
25. Three.js Witness Integration
The witness viewport and graph should cross-highlight.
Select a system:
vehicle.suspension
Viewport highlights:
- selected vehicle,
- suspension bones / wheel contacts,
- force vectors if enabled.
Select:
dryad.forest
Viewport highlights:
- generated flora,
- biome region,
- LOD bounds.
Select:
rig.footIK
Viewport highlights:
- feet,
- IK targets,
- ground contact rays.
This makes the abstract graph concrete.
26. Runtime Pulses
Live mode can animate system activity.
Example:
Input
↓ pulse
Player
↓ pulse
Physics
↓ pulse
AnimationPulse density should be aggregated.
Do not render every individual event at full speed.
Use:
- throttling,
- event grouping,
- sampling,
- importance filters.
27. Time Scrubbing
Atlas runtime history should support a time slider:
00:00 ─────────────●──────────── 00:10Scrubbing updates:
- graph activity,
- entity state,
- selected metrics,
- witness viewport where replay state is available.
The user can inspect failures after they happen.
28. Agent Integration
Atlas should never dump the entire project into the agent context.
Selecting a node creates a scoped context package.
Example:
{
"system": "player.tricks.landing",
"intent": "Make clean landings preserve more momentum.",
"neighbors": [
"player.physics",
"player.animation",
"combo"
],
"files": [
"src/gameplay/tricks/landing.ts",
"src/player/movement.ts"
],
"tests": [
"tests/tricks/landing.spec.ts"
],
"feelSpec": "profiles/player-tricks.yaml",
"runtimeEvidence": "traces/trace-0042.json"
}The agent gets only what it needs plus access to the harness if it needs more.
29. Agent Actions
Atlas should support standard actions.
Explain
Explain how this system currently works.
Modify
Change behavior while preserving protected constraints.
Tune
Suggest parameter changes only.
Optimize
Reduce runtime cost while preserving visual / gameplay targets.
Repair
Diagnose failing tests or runtime errors.
Replace
Swap provider or implementation.
Compare
Compare this system to another FeelSpec/reference profile.
Document
Update semantic contract / docs.
30. Change Preview
Before significant structural changes, Atlas can show:
PROPOSED CHANGE
Modify:
player.tricks.landing
Affected:
player.physics
combo
animation
Files:
3
Tests:
8
Protected FeelSpec:
jumpHeight
topSpeed
Estimated risk:
LOWThen execute.
For ordinary low-risk changes, this can be automatic depending on user preference.
31. Verification
Every agent task should close a verification loop.
Minimum:
BUILD
TYPECHECK
TESTS
CONSOLEWhen applicable:
GAMEPLAY TEST
VISUAL CAPTURE
PERFORMANCE
FEELSPEC CONSTRAINTSAtlas displays results directly on the node.
Example:
TRICK SYSTEM
Build PASS
Tests 18/18
Gameplay PASS
Performance 0.22 ms
Visual PASS32. Atlas Health States
Nodes should have clear health.
Healthy
Warning
Failing
Unknown
Modified
Untested
Profiling
Agent WorkingHealth must be derived from evidence.
33. Git / History Integration
Every system can show history.
Example:
TRICK SYSTEM
Recent:
+ landing momentum preservation
+ shark tow scoring
- old spin limiter
Commits:
...The user can ask:
Revert only the spin limiter change.
The agent receives semantic ownership and git context.
34. Provider Swapping
Provider nodes should support swap workflows.
Example:
OCEAN
Current:
Simple Water
Candidate:
Poseidon
Benefits:
+ spectral waves
+ underwater optics
+ foam
Costs:
+ WebGPU
+ higher GPU budget
Affected:
Surfing
Boats
Weather
Underwater Camera
[Ask Agent to Migrate]The harness should use provider skills and capabilities registry.
35. Style Profiles
Atlas should treat style as a structured system.
Example:
style:
geometry:
profile: ps1_n64_modern
shading:
profile: cel_pbr_hybrid
water:
provider: poseidon
style: photoreal
lighting:
saturation: 0.76
contrast: 0.62
post:
bloom: 0.25
chromaticAberration: 0.02
pixelTreatment: 0.18The user can say:
Keep the realistic water but make the rest more Crash 2.
Atlas scopes the agent to relevant style systems.
36. Asset Provenance
Every asset node should expose:
- source,
- creator,
- license,
- attribution,
- imported date,
- modifications,
- poly count,
- texture resolution,
- rig,
- animation set,
- usage.
Example:
SURFER BODY
Source Sketchfab
License CC-BY
Rigged Yes
Triangles 28k
Textures 2k
Used by Player / NPC surfers37. Mechanics Registry Integration
FeelSpec should connect to the 3JSE mechanic registry.
Example:
CAR DRIVING
├── Xirtus Arcade Driving
├── Crash Racer Reference
├── Smooth Tourer Reference
└── Heavy Openworld ReferenceA mechanic profile contains:
- dimensions,
- reference notes,
- tests,
- implementation patterns,
- known examples,
- tuning constraints.
38. Atlas as Project Navigation
Atlas should eventually replace much of manual file navigation.
A user should be able to think:
I want to change shark towing.
Search:
shark towAtlas returns:
Mechanic: Shark Tow
System: Grappling
System: Surf Physics
System: Scoring
Asset: Shark Rig
Tests: shark-tow/*Much easier than knowing file names.
39. Search
Universal search indexes:
- systems,
- mechanics,
- FeelSpec parameters,
- providers,
- assets,
- scenes,
- entities,
- tests,
- files,
- recent changes,
- events.
Search results open relevant Atlas view.
40. Atlas Data Model
Suggested internal model:
type AtlasNode = {
id: string
type: AtlasNodeType
label: string
domain: string
purpose?: string
status: HealthStatus
owns?: string[]
requires?: string[]
dependents?: string[]
emits?: string[]
listens?: string[]
assets?: string[]
providers?: string[]
tests?: string[]
feelSpec?: string
metrics?: RuntimeMetrics
position?: SemanticPosition
}Edges:
type AtlasEdge = {
source: string
target: string
kind:
| "dependency"
| "event"
| "state"
| "asset"
| "provider"
| "ownership"
| "runtime"
strength?: number
}41. Atlas Compiler
The compiler builds Atlas from multiple sources.
Pipeline:
Project
↓
Static analysis
↓
System metadata
↓
FeelSpec
↓
Provider registry
↓
Asset registry
↓
Tests
↓
Scene metadata
↓
Runtime instrumentation
↓
Git history
↓
Atlas Graph Model42. Static Analysis
Extract where possible:
- imports,
- exports,
- function references,
- event registrations,
- Zustand stores,
- ECS component systems,
- scene ownership,
- asset imports,
- test coverage relationships.
Do not rely exclusively on static analysis for semantics.
43. Runtime Instrumentation
Instrumentation can record:
system start/end
events
entity state transitions
performance
exceptions
selected variables
provider statusInstrumentation should have minimal overhead and configurable detail levels.
44. Atlas Manifest
Each 3JSE project can include:
atlas/
systems/
feelspec/
views/
traces/
profiles/Example:
atlas/systems/player.yaml
atlas/feelspec/driving.yaml
atlas/profiles/xirtus-camera.yaml45. Three.js Rendering Architecture
Recommended:
Atlas Shell
├── React
├── React Flow / graph UI
├── Three.js Atlas Canvas
└── Three.js Witness CanvasDo not force Atlas graph rendering into the same canvas as the game.
Independent canvases permit:
- independent camera controls,
- independent performance,
- clean DOM inspectors,
- independent post processing.
46. Three.js Semantic Scene
The Three.js Atlas scene may contain:
- domain islands,
- system nodes,
- dependency arcs,
- runtime pulses,
- miniature asset previews,
- miniature rigs,
- miniature world maps.
But it must remain constrained.
Avoid unrestricted 3D node placement.
47. Spatial Metaphors
Useful metaphors:
Islands
Domains are stable islands.
Floors
Implementation depth is vertical.
Design
↓
Mechanics
↓
Systems
↓
CodeConstellations
Subsystems cluster around parent systems.
Rivers
Event streams animate as paths.
Heat
Performance / runtime pressure appears as glow or temperature.
Choose metaphors deliberately, not simultaneously.
48. Orderliness Rules for 3D Atlas
- camera defaults to an isometric / slightly perspective strategic view;
- domains occupy stable world positions;
- node depth communicates hierarchy only;
- automatic layout controls position;
- no unconstrained force graph as default;
- connection density is aggressively filtered;
- edges disappear at distant zoom;
- labels use billboards / HTML overlays;
- semantic color stays consistent between 2D and 3D;
- clicking a node smoothly frames it.
49. Animation Principles
Atlas animations should help comprehension.
Use animation for:
- selection,
- focus,
- event propagation,
- state change,
- provider replacement,
- performance change,
- graph expansion/collapse.
Avoid ambient motion that makes the graph harder to read.
50. Rigging Visualization in Three.js
Rig mode should support:
Skeleton
Mesh
Weights
IK Targets
Contact Points
Root Motion
Retarget Mapping
Blend WeightsAtlas semantics appear alongside the 3D rig.
Example:
LEFT FOOT IK
Healthy
Contact: true
Offset: 1.2 cm
Weight: 0.94Clicking it highlights the exact rig elements.
51. Mechanics Visualization in Three.js
Driving:
- tire force vectors,
- velocity,
- grip,
- slip angle,
- suspension travel,
- center of mass,
- camera target.
Jumping:
- predicted trajectory,
- apex,
- current input authority,
- landing window.
Surfing:
- wave force,
- board normal,
- water velocity,
- kite force,
- tow force.
These visualizations are optional witnesses, not permanent HUD clutter.
52. Atlas Modes
Suggested top navigation:
GAME
SYSTEM
FLOW
STATE
EVENTS
WORLD
RIG
ASSETS
STYLE
FEEL
PERF
HISTORY53. Default Layout
┌──────────────────────────────────────────────────────────────┐
│ 3JSE ATLAS GAME SYSTEM FLOW FEEL ASSET PERF HISTORY │
├────────────────────────────────────────┬─────────────────────┤
│ │ │
│ │ Selected System │
│ ATLAS VIEW │ │
│ │ purpose │
│ │ status │
│ │ knobs │
│ │ tests │
│ │ │
│ │ [Ask Agent] │
├────────────────────────────────────────┴─────────────────────┤
│ Live Trace / Timeline / Test Results │
└──────────────────────────────────────────────────────────────┘Optional split:
Atlas | Witness54. MVP Scope
Atlas v0.1 should not attempt everything.
Minimum useful version:
- system registry;
- semantic system map;
- node inspector;
- FeelSpec numeric tuning;
- system search;
- agent-scoped task generation;
- test links;
- provider links;
- asset links;
- runtime health badges;
- basic witness linking.
55. Atlas v0.2
Add:
- runtime event pulses,
- trace recording,
- performance graph,
- A/B FeelSpec,
- Feel Lab,
- state machine view,
- world graph,
- style graph.
56. Atlas v0.3
Add:
- rig graph,
- rig witness,
- provider swapping,
- visual regression,
- time scrubber,
- git semantic history,
- asset provenance UI.
57. Atlas v1.0
A successful Atlas 1.0 should allow a non-programmer to:
- open a complex 3JSE game;
- understand its major systems within minutes;
- locate a mechanic without knowing filenames;
- understand what controls that mechanic;
- change simple tuning values directly;
- ask the agent for a structural change;
- watch the agent scope the task correctly;
- see verification;
- A/B the new feel;
- revert or keep the result.
58. Anti-Goals
Atlas is not:
- Blender,
- Unreal Editor,
- Unity Editor,
- a general-purpose visual programming language,
- a source-code replacement,
- a node-based shader editor initially,
- an unrestricted graph drawing tool,
- a level editor by default,
- a giant inspector for every variable.
59. Failure Conditions
Atlas has failed if:
- graphs routinely exceed comprehensible density;
- users need to manually connect low-level execution nodes;
- graph metadata becomes harder to maintain than source code;
- semantics drift from implementation;
- users must understand file structure to navigate;
- changes cannot be verified;
- FeelSpec becomes a collection of meaningless sliders;
- named reference profiles become vague marketing labels;
- 3D navigation is harder to understand than 2D;
- visual richness reduces readability.
60. Core Doctrine
Atlas should carry these rules prominently:
The graph is not the program. The graph is the explanation of the program.
The human edits intent. The agent edits implementation.
Expose systems before files, mechanics before functions, and feel before constants.
Use progressive disclosure to make complexity navigable.
Color communicates meaning; movement communicates change.
Never recreate Blueprint spaghetti in a different color palette.
Every change must be witnessed and verified.
61. Final Product Vision
A user opens a game.
Atlas initially shows:
WORLD
PLAYER
GAMEPLAY
AI
STYLE
AUDIO
UIThe user enters PLAYER.
Movement
Camera
Animation
Tricks
CombatThey open Tricks.
Air
Grind
Landing
ComboThey select Landing.
Atlas shows:
Landing tolerance 32°
Momentum retention 0.84
Hard landing 7.5
Tests 6/6The witness viewport shows the player landing a trick.
The user says:
Keep the existing jump exactly as it is. Make clean landings feel much faster and more satisfying, but sideways landings should punish momentum more.
Atlas creates the scoped agent task.
The agent modifies the implementation.
Tests run.
A/B appears.
A Current
B ProposedThe user tries both.
Keep B.
Atlas stores the new FeelSpec profile and project state.
No Blueprint graph was authored.
No source file had to be found.
No physics constant was changed blindly.
The user interacted with the game at the level of meaning and feel.
That is the intended role of 3JSE Atlas.
62. Relationship to the 3JSE Harness
Atlas is the visual intelligence layer over the existing harness.
USER
↓
ATLAS
↓
FeelSpec / Semantic Selection
↓
3JSE Director
↓
Capability Resolver
↓
Vendor Router
↓
Agent
↓
Project
↓
Tests / Runtime / Witness
↓
ATLASThe harness remains capable of working headlessly.
Atlas is not required to build games.
Atlas makes the harness understandable and controllable.
63. Recommended First Implementation Task
The best first implementation is not the full 3D Atlas.
Build:
Atlas Semantic Core
defineSystem()- Atlas graph compiler
- FeelSpec parser
- React Flow system map
- node inspector
- direct knob editing
- agent task context exporter
- test status
- provider metadata
- asset metadata
- simple runtime health
Then apply it to one existing 3JSE game.
Use the pain points from that real project to decide which 3D visualizations are genuinely useful.
Only after the semantic core proves useful should the Three.js Atlas navigation layer expand.
The Three.js layer should amplify comprehension, not merely demonstrate that Atlas itself uses Three.js.
3JSE AtlasATLAS.md
The layer-5 visual authoring surface (ARCHITECTURE.md) — the Blueprint / Verse alternative. Full product spec: 3JSE_ATLAS_FULL_PLAN.md. This page is the implementation status.
Code is for agents. Graphs are for understanding. FeelSpec is for intent and tuning. The viewport is a witness. — the graph is the explanation of the program, never the program.
Atlas is generated from the project — declared semantic-system metadata plus static/runtime evidence — and is never the source of program logic. The node-graph machinery of VISUAL_SCRIPTING.md stays underneath as the execution architecture and one Atlas lens.
Implemented — Atlas Semantic Core (@3jse/atlas, headless)
3JSE_ATLAS_FULL_PLAN.md §54 / §63. All headless, 31 tests.
| Piece | Module | Notes |
|---|---|---|
defineSystem() semantic contract | defineSystem.ts | id · label · domain · purpose · owns · requires · emits · listens · knobs · tests · providers · assets · feelSpec · mechanic · parent. Module-scope systemRegistry like ComponentRegistry. |
| Atlas graph compiler | compile.ts | compileAtlas(input) → AtlasModel: typed nodes + typed edges (dependency / event / provider / asset), reverse-dependency index, dangling refs surfaced not swallowed. focusDomain + childrenOf for progressive disclosure. |
| FeelSpec | feelspec.ts | §8 parse/validate · resolveInheritance (§14 deltas, cycle-guarded) · resolveFeel (§11 weighted reference blend) · checkProtected (§13) · feelDelta (§12 preview). |
| System-map layout | layout.ts | Deterministic layered DAG (§22): dependency flow left→right, event edges lateral, cycle-guarded. Not a force graph. |
| Node inspector data | (compiled AtlasNode) | purpose, health, requires/dependents, emits/listens, tests, files, knobs, feelSpec, mechanic. |
| Direct knob editing | editor AtlasPanel + sampleAtlas.applyAtlasKnob | Number knobs on player.movement / player.camera / world.props write straight to the live component field (CharacterController / CameraRig / Spin / Movable) — §3.1 "update live where possible", real. |
| Agent task-context exporter | agentContext.ts | exportAgentContext(model, nodeId, intent) → §28 1-ring scoped package (system, neighbours, files, tests, feelSpec, knobs, runtime pointer). previewChange → §30 blast radius + coarse risk. |
| Test status | health.ts | deriveHealth(evidence) → §32 states. Status is a pure function of harness evidence (tests / perf / console / dirty / agent-working) — never invented. |
| Provider / asset metadata | compile.ts ProviderMeta / AssetMeta | Injected registry Record (keeps @3jse/atlas fs-free); unknown ids still get a bare node flagged "not in registry". |
| Simple runtime health | health.ts + AtlasNode.cpuMs | ms/frame surfaced on the node when evidence supplies it. |
| Universal search | search.ts | searchAtlas(model, query) across systems / knobs / events / providers / assets / tests / mechanics — ranked, deterministic, no search dep. §38 "shark tow" → the mechanic, its system, its tests. |
| Semantic colors | colors.ts | §20 domain hues + health badge colors/glyphs, shared 2D/3D. |
Editor panel
apps/editor/src/panels/AtlasPanel.tsx (center tab Atlas, active). Hand-rolled SVG system map (no react-flow — same posture as GraphCanvas): layered layout, domain-colored nodes, typed edges, health badges, focus dimming on select. Right pane: the node inspector with live knob inputs, search, and the §28/§30 agent-scoping section. "Ask agent" assembles the scoped task package and, when a provider is configured in the AI Providers panel (@3jse/llm), sends it to that model and prints the plan inline; with no provider it falls back to the editor log + clipboard so the task can be pasted into any chat.
Model content = sampleAtlas.ts, the semantic declarations of the Third Person template (@3jse/templates) — §63 "apply it to one existing 3JSE game".
Implemented — v0.2
| Piece | Module | Notes | ||
|---|---|---|---|---|
| Additional lenses | lenses.ts | eventLens (§5.4), performanceLens (§5.9), providerLens (§5.7), assetLens (§5.6), stateMachineLens (§5.3), gameplayFlowLens (§5.2), worldLens (§5.10 — defineRegion hierarchy), styleLens (§5.8 — a VISUAL PROFILE from StyleProfile), traceLens + TraceRecorder + pulseCounts (§5.5 / §26 — a windowed event trace, feeds the time scrubber), rigLens (§5.11 — bones grouped by limb + Motion + Animation). Each a pure transform of the AtlasModel; the panel's lens switcher swaps which one feeds the map. | ||
| Node canvas | editor AtlasPanel via @3jse/graph NodeCanvas | The System Map now renders through a reusable pan / zoom / drag node canvas (@3jse/graph), dragged positions overriding the auto-layout per lens. | ||
| A/B FeelSpec | feelAB.ts | feelABTable (both values + delta per dimension, sorted by \ | Δ\ | ), mergeFeel (per-dimension A/B pick → merged intent, §16), feelABSummary (§12 preview line). |
atlas/ project manifest | manifest.ts | parseAtlasManifest(files) over a virtual filesystem — loads atlas/systems/.json → AtlasSystemSpec[] and atlas/feelspec/.json → FeelSpec[], reports malformed files instead of throwing, feeds compileAtlas directly (§44). JSON now; a YAML front-end is a swappable parse step. |
The Trace lens has a wired time scrubber (§26–27): a play/pause rAF sweep and a seek slider over the recorder's span, revealing event nodes up to the playhead and pulsing (◉, bright accent) the ones that fired in the last 0.3 s, with a per-system density strip from pulseCounts. AtlasPanel.tsx → TraceScrubber; sampleScene.ts seeds a short burst and the CinematicSystem appends live.
Not built yet
- 2.5D / Three.js Atlas navigation (§18–19, §45–51) — deliberately deferred until the 2D core's
pain points justify it (§63).
- Feel Lab (§17), personal feel libraries (§15).
- Agent ACT stage behind "Ask agent" — the model now returns a plan (via
@3jse/llm+ the
AI Providers panel), but executing that plan's tool calls stays human-driven until AI_AGENT_API.md's trust tiers exist.
- FeelSpec YAML on disk (the manifest loader takes JSON today).
- Provider swap workflow UI (§34) and git/history integration (§33).
RoadmapROADMAP.md
Dependency-ordered, not calendar-ordered — each phase specifies what it needs from the previous one and what it unlocks for the next. The overall sequencing bet: ship something that already beats hand-rolled Three.js before visual scripting exists, ship visual scripting before AI depends on it, ship AI before ecosystem/marketplace features need a userbase and content that don't exist yet, and treat "professional tooling" (terrain, cinematics, VFX graphs) as depth to layer in once the foundation is proven, not a prerequisite for anything else.
Tandem note: this roadmap is the engine track. The harness track — 3JSE Harness v0.1 — is already live (
HARNESS.md) and serves as a working field test of Phase 4's AI-native thesis before that phase is built, feeding design decisions back into every earlier phase. The harness track's visual layer is 3JSE Atlas (3JSE_ATLAS_FULL_PLAN.md), which supersedes Phase 3's node-wiring canvas while keeping that phase's compiler deliverables.
Phase 0 — Technical experiments
Goals: de-risk the decisions the rest of the roadmap depends on, before committing architecture to them.
Prerequisites: none.
Architecture affected: validates or revises GAMEPLAY_IR.md, ENTITY_COMPONENT_MODEL.md, VERSE_COMPATIBILITY.md.
Deliverables:
- A throwaway 3IR prototype: hand-write ~5 IR node kinds, a JS emitter, and an interpreter; confirm the source-map round-trip (
GAMEPLAY_IR.md's bidirectional-editing claim) actually works on a small recognized TS subset before it's load-bearing for the whole engine. - A minimal ECS-over-
Object3Dspike: confirm archetype storage plus a Transform-as-Object3D bridge performs acceptably (target: 10k entities, steady 60fps on a mid-range laptop) and doesn't fight Three.js's own scene-graph update internals. - A Verse-spec research spike (
VERSE_COMPATIBILITY.mdLevel 3): read Epic's published grammar/license terms and produce a written go/no-go, not an implementation. - A Tauri-vs-Electron spike for the editor shell (
EDITOR.md): confirm WebGPU access, file-system permissions, and multi-window behavior meet the editor's needs in Tauri before committing to it as primary.
Tests: benchmarks (entity count vs. frame time), a working (if ugly) graph↔code round-trip demo, a written feasibility memo per spike.
Exit criteria: no open question from GAMEPLAY_IR.md or ENTITY_COMPONENT_MODEL.md remains unvalidated by a working prototype; Verse Level-3 go/no-go is decided; editor shell technology is chosen.
Phase 1 — 3JSE Editor MVP
Goals: enough to visually construct a simple Three.js game without writing a scene-setup script by hand.
Prerequisites: Phase 0's ECS/Object3D bridge and editor-shell decision.
Architecture affected: RUNTIME.md, EDITOR.md, ENTITY_COMPONENT_MODEL.md, PROJECT_FORMAT.md (all first real implementations).
Deliverables: @3jse/runtime (World/Level/Entity/Component, no Systems scheduler complexity yet beyond fixed/variable tick); Viewport, Hierarchy, Inspector, Content Browser, basic transform gizmos; Play/Pause (no Modify-while-paused yet); local project save/load in the PROJECT_FORMAT.md layout; @3jse/assets v1 (glTF/GLB import, thumbnails, basic metadata — no LOD/collider generation yet).
Tests: hand-build a small static scene (a room, some props, a camera) entirely in-editor with zero hand-written code; project round-trips through save/load/Git-diff cleanly.
Exit criteria: a non-programmer can place and arrange a scene using only the editor; the project file is readable and diffs sensibly in Git.
Phase 2 — Gameplay Engine
Goals: components, prefabs, physics, input, saves, animation — the engine becomes capable of an actual game, not just a scene.
Prerequisites: Phase 1's Entity/Component runtime and editor.
Architecture affected: RUNTIME.md's full scheduler, PHYSICS.md, ANIMATION.md, AUDIO.md, first slice of GAMEPLAY_FRAMEWORK.md (@3jse/character, @3jse/save, @3jse/spawning).
Deliverables: Prefab system with variant overrides; @3jse/physics-rapier integration + Collision Editor panel; InputManager; @3jse/character CharacterController + CameraRig; Animation Graph MVP (state machine + blend tree, no IK yet); @3jse/save; hot reload for hand-written TypeScript systems (RUNTIME.md's function-swap mechanism, first real use).
Tests: build the Third Person template (TEMPLATES.md) end-to-end using only Phase 1–2 features; verify hot reload preserves live Play-mode state across a code edit.
Exit criteria: the Third Person template is playable, tunable via Inspector, and its logic hot-reloads without restarting Play.
Phase 3 — 3JSE Graph
Goals: visual gameplay scripting, built on a real 3IR, not a shortcut.
Prerequisites: Phase 0's validated IR prototype; Phase 2's Entity/Component/System runtime to compile against.
Architecture affected: GAMEPLAY_IR.md (production implementation), VISUAL_SCRIPTING.md (compiler machinery; the canvas UI is superseded by 3JSE_ATLAS_FULL_PLAN.md), Debugger panel in EDITOR.md.
Deliverables: @3jse/ir production compiler (interpreter + JS/TS backends); @3jse/graph node canvas, core node families (events, flow control, functions, variables, async); live debugging (active wires, breakpoints, watches); bidirectional graph↔code for the recognized TS subset, including the visible "Code node" boundary for anything outside it; @3jse/vendor registry + fetcher (VENDOR_INTEGRATIONS.md) landing here specifically so Tier B open-source staging is available well before any Tier A plugin adapter is ready — a developer shouldn't have to wait for Phase 5 to at least look at the best available open-source work.
Tests: reproduce the kite-surf-style boost/combo worked example from VISUAL_SCRIPTING.md with zero hand-written logic files; confirm the compiled output is readable, idiomatic TypeScript a programmer would not be embarrassed to have written; confirm a graph edit and a code edit of the same logic converge to the same IR.
Exit criteria: a designer with no TypeScript experience can build non-trivial gameplay logic (an event chain with branching, timers, and state) entirely in the graph editor, and a programmer can read the compiled output without needing the graph open.
Opportunistic, not blocking: a Playground — a shareable-URL sandbox holding a snippet id (scene + graph state), modeled directly on Babylon.js's Playground, which is as much that engine's primary community/onboarding mechanism as it is a debugging tool. It becomes buildable the moment @3jse/ir/@3jse/graph exist (this phase), needs no engine-architecture changes to add, and is worth picking up whenever it's convenient rather than gating on it — the adoption target is the mechanism (a snippet id, a save/fork/share flow), not Babylon's implementation. Once it exists, docs gain a companion discipline worth holding to going forward: a feature described in the manual without a live Playground link demonstrating it is treated as documentation debt, the same way an untested code path is.
Phase 4 — AI-native authoring
Goals: agents can reliably create and modify games through the same primitives humans use.
Prerequisites: Phase 2's stable Component/System API and Phase 3's 3IR — the Agent API's tool surface is a thin layer over both, and can't be built reliably against either while they're still shifting.
Architecture affected: AI_AGENT_API.md (production implementation), Agent Panel in EDITOR.md, headless run mode in RUNTIME.md.
Deliverables: @3jse/agent MCP-shaped tool server (full tool list from AI_AGENT_API.md); headless runtime.run/getConsole/getPerf/captureFrame; the observe→plan→act→verify loop; Suggest and Co-pilot trust tiers; Agent Panel UI showing live plan/diff.
Tests: the shark worked example (AI_AGENT_API.md) end-to-end, unattended through ACT/VERIFY, human approval only at plan and final-diff stages; a natural-language project-creation smoke test (a one-sentence prompt producing a browsable, editable project, not an opaque bundle).
Exit criteria: an agent can complete a moderately complex feature request (new Component + Graph + asset import + verified working result) without a human intervening mid-loop, and every artifact it produces opens normally in the ordinary editor panels.
Phase 5 — Professional tools
Goals: the depth that separates "usable" from "a studio would actually ship with this."
Prerequisites: stable core (Phases 1–3); AI layer (Phase 4) is not required by this phase but benefits from it (agents can help build/tune content in these tools too).
Architecture affected: adds to ANIMATION.md (IK, retargeting depth), RENDERING.md (particle/VFX graph), PLUGIN_ARCHITECTURE.md (terrain/water/foliage as shipped official plugins), PERFORMANCE.md (Profiler depth).
Deliverables: @3jse/water-poseidon, @3jse/terrain (with the @3jse/terrain-demiurge procedural mode), @3jse/foliage-gaia, @3jse/flora-dryad — the Tier A vendor-wrapped plugins staged since Phase 3's @3jse/vendor graduate here (VENDOR_INTEGRATIONS.md); cinematic Sequencer/Timeline (@3jse/cinematics); particle/VFX graph; skeletal retargeting + IK; full Profiler (GPU/CPU/memory/network); render/network debuggers; automated testing framework (build.runTests gets real teeth); replay system (building on RUNTIME.md's per-machine determinism).
Tests: build one of each of the Racing, RPG, and Open World templates (TEMPLATES.md) using these tools, exercising terrain, water, cinematics, and VFX in a real (if small) project each.
Exit criteria: the remaining "MVP vs. long-term" gap identified back in ARCHITECTURE.md/EDITOR.md's panel inventory is closed — every panel listed there exists and is usable, not stubbed.
Phase 6 — Ecosystem
Goals: templates, package sharing, and multiplayer support mature from "exists" to "a community can build on it."
Prerequisites: Phase 3's Graph and Phase 5's plugin catalog give the ecosystem something worth packaging; PLUGIN_ARCHITECTURE.md's stability contract needs to have survived at least one real engine version bump (Phase 5) before third parties can trust it.
Architecture affected: PLUGIN_ARCHITECTURE.md (registry/discovery layer added on top of the existing manifest contract), NETWORKING.md (hardened from Phase 2's basics into a documented, template-backed Multiplayer offering), TEMPLATES.md (full catalog).
Deliverables: a package registry/discovery surface for @3jse/* and community packages (versioned, semver-checked against the stability contract); the full template catalog from TEMPLATES.md; the Multiplayer template hardened on @3jse/networking; documentation and a contribution path for third-party plugin authors.
Tests: a third-party developer, external to the core team, publishes a working plugin using only public documentation and the extension-point APIs, with no core-team assistance required.
Exit criteria: at least one community-authored plugin and one community-authored template exist and are installable without manual intervention.
Phase 7 — Unreal-class workflow
Goals: honestly assess what remains between 3JSE and a genuinely professional, general-purpose engine — this phase is a re-evaluation, not a fixed feature list, because the honest answer depends on where Phases 0–6 actually landed.
Prerequisites: all prior phases, plus real usage data from projects built in Phases 4–6.
Architecture affected: revisits the deferred items flagged throughout this design — live multi-user editor collaboration (deferred in EDITOR.md in favor of Git), rollback netcode for competitive genres (deferred in NETWORKING.md), deeper acoustic modeling (deferred in AUDIO.md), Verse Level 3 (contingent on the Phase 0 go/no-go), and rendering-ceiling questions explicitly out of scope in VISION.md (Nanite/Lumen-class techniques, revisited only as Three.js's own roadmap and WebGPU compute capability evolve).
Deliverables: a written gap analysis against Unreal/Unity/Godot for the genres 3JSE's real users are actually shipping in (not a hypothetical full-parity checklist); a decision, per deferred item, to build, continue deferring, or explicitly declare out of scope for the engine's identity as defined in VISION.md.
Status: first pass of the gap analysis written — ENGINE_GAP_ANALYSIS.md (grounded in the repo's actual state: Phase 1–2 core tested, Phase 3–6 partial, the AI-native differentiators ahead; genre-readiness table; a recommended sequencing that puts packaging → audio → UI first). Per-deferred-item build/defer/out-of-scope decisions still owed as Phases 4–6 produce real usage data.
Exit criteria: not "feature parity with Unreal" — parity with a twenty-years-deep engine is not a real target and chasing it would betray VISION.md's own framing. The exit criterion is a credible, evidence-backed answer to the question this entire design package exists to answer: for the genres and teams 3JSE actually serves, is it a better choice than Unreal, Unity, Godot, or a custom web stack — and if not yet, precisely what's missing.
Reference Games — what the projects teach the planREFERENCE_GAMES.md
Six games built on the 3JSE stack already exist as working laboratories: 3JSURF (../3jsurf), ZENDRIVE (../zendrive), UBURT / PULSEHOP (../uburt), DAMN BEAVERS (../dambeavers), BREAKING WAVES (../breaking-waves-demo-main), and MANDELHOP (../mendalhop). Together they validate most of this design package's riskiest claims — and they donate working systems, measured feel anchors, harness tooling, and reusable rigs/animation/asset kits. This page records what each one teaches and where each lesson lands.
The short answer to "can any of this accelerate the project": yes — five things specifically. (1) The headless mechanics-harness pattern (3jsurf's mechcheck.mjs, zendrive's headless races, dambeavers' simulation tests, mendalhop's player agents) is the engine's runtime.run --headless and the Agent API's verify step, already proven in production. (2) Feel measured as numbers (3jsurf's feel.mjs) gives FeelSpec real anchors instead of guesses. (3) Reference implementations for vehicle physics, hop-grammar input, parametric surf, and systemic simulation collapse the risk on four Gameplay Framework packages. (4) Rigs, animation clip libraries, and model kits seed the Shop and templates. (5) Damn Beavers' gate sentences formalize the harness's evidence gate exactly the way build.runTests needs it.
1. 3JSURF — surf mechanics on a spectral ocean
The mechanics of TUBULAR running on Poseidon's WebGPU FFT ocean: 8 breaks from 30 m to 300 m faces, 5 riders, sharks, rival AI, barrel riding. src/render/poseidon/ is vendored (MIT) exactly the way VENDOR_INTEGRATIONS.md prescribes.
What it proves
- Headless mechanics harness.
tools/mechcheck.mjsruns the wave and the surfer with no renderer, no canvas, no DOM — stand-inscene/particles/charstubs, pure JS logic — and its numbers must match the WebGL build ("ride length 26.7s vs 27.6s"). Gameplay logic that is renderer-independent by construction. This isRUNTIME.md's headless mode andAI_AGENT_API.md's verify loop, working today. - Feel as numbers.
tools/feel.mjsmeasures face run, crest→trough time, and peak face speed per break — feel as a table of measurements, not vibes. This is FeelSpec's measurement posture with real anchors: Pen Gu Bay 7.3 m/s peak, Cosmic Reef 19.8 m/s. - Invariant soak.
tools/soak.mjsdrives a scripted pilot through 60-second sessions and samples two invariants every frame: the rider is always on the surface, the camera is never inside the water (riderSunkPct/camBuriedPct≈ 0.0–0.1%), plus a console-error net. This is the harness's gameplay/visual/performance gates as an executable. - Debug isolation.
WAVEDBG=1..7renders one shading term at a time (body, reflection, backlit, glitter, foam, normal, raw attributes) — every "what is painting that?" question answered by a screenshot, not ten guesses. This is the methodology behind Atlas's runtime-trace lens and the Profiler's per-pass attribution.
Design lessons (mechanics-registry knowledge)
- Stations, not metres. Every threshold (stall, foam-ball floater, "over the falls") was a metre count that meant a height on the face. On a 300 m wave the metres mean something else entirely, so thresholds live in
wave.stations— fractions of the wave's geometry. Bare metres do not survive a change of scale or of face shape. - Scaling laws, not scale multipliers. Steering authority scales with √K, drag is quadratic (which is what water does), terminal velocity follows damping time — letting go leaves a rail-hold glide instead of a runaway. World scale is one wrapper (
setWorldScale), not a rewrite of every placement. - Attach by construction, not by lookup. The rider used two different formulas for the same quantity (x-placement + height lookup); on a 150 m wave they disagreed by metres — "surfer inside the wave."
wave.ridePointinverts the profile once and takes both coordinates from that point. - Pickup tests must be swept, not sampled. At 200 km/h the board covers a metre per frame; a sphere test is a coin flip.
- State bugs are geometry bugs. A stale
stats.inTubeflag (written only in_riding, never cleared on wipeout) disabled the exact camera clearance needed during the state where the rider is in the water. Camera burial went 2.7% → 0 when cleared.
WebGPU port lessons (RENDERING.md, PERFORMANCE.md)
- The wave had to be shaded in face space (
afaceattribute: metres of arc down the cross-section × along the wall) — world-XZ UVs smear into vertical streaks on a near-vertical face. The parameterisation is isometric however the face pitches. - Particles are billboards, not points under WebGPU — and the old 26-pixel cap was load-bearing (fine mist vs. whited-out barrel); it's reproduced in world units.
- The barrel interior is a liquid volume (~80 lines of GLSL → TSL): god-ray fan, caustic webs, counter-flow, sea smoke, a "am I seeing this from underneath" per-fragment test — and the FFT ocean drops its sky reflection when the camera is in the pit (inside a barrel there is no sky overhead).
- One photograph, eight breaks: each break's palette is applied as a grade inside
skyColor(), so dome, ocean fresnel, and aerial-perspective fog can never disagree. The Cosmic Reef replaces it outright with a procedural nebula, starfield, and a real gravitational-lensing black hole (deflection ≈ rs/A — three dot products and a normalize).
Reusable assets (Shop kit: "TUBULAR rider kit")
public/assets/: skeleton_rig.glb, man_rigged.glb (two auto-rigged riders), surf_anims.glb (baked Mixamo clip library — paddle, pop, ride, trim, air, airfwd, airbig, flip, spin, cartwheel, kick, slip, tuck, crouch, land, wipeout, swim, fistpump, dance, victory, taunt…), three sharks incl. hammerhead (shark.glb, realistic_shark.glb, model_73a_-_great_hammerhead_shark.glb), three floaties (flamingofloatie, duckfloatie, sharkfloatie), buoy.glb, sky panoramas. Licensing: Mixamo clips (baked), Sketchfab exports, KSPS mechanics public domain, Poseidon MIT.
Where it lands
RUNTIME.md headless · PERFORMANCE.md instancing/billboards · RENDERING.md face-space/volume · ATLAS surf FeelSpec + Feel Lab scenarios · harness mechanics-harness skill and surf recipe · Shop kit.
2. ZENDRIVE — serene velocity racer
Pole Position × zen garden × vaporwave mixtape. Four procedural roads, zero authored assets, and a generative soundtrack that listens to your driving.
What it proves
- Track-space vehicle physics — the reference implementation for
@3jse/vehicle's arcade mode. Cars live in(s = distance along track, x = lateral)coordinates on a self-closing spline with pure-pursuit homing. Corners apply a demand-vs-capacity model:demand = curv · v² · curvePushvs. the steer authority you actually provide — if demand exceeds capacity you slide wide, brake, or commit to the drift. This is a whole, proven arcade-feel model in ~120 lines, and its axes map 1:1 onto Atlas's driving FeelSpec dimensions (steeringResponse,driftAssist,stability,collisionDrama…). Thexirtus-arcade-driving-v3profile in3JSE_ATLAS_FULL_PLAN.mdcould be calibrated from this code. - The provider strategy works. The README credits the techniques: shader ocean ported from poseidon (WebGL-toon counterpart — vertex-displaced bands, shore heightmap baked from the track's own terrain function, fresnel mirroring the exact sky gradient, two-scale sun glitter, Snell-window backface), wind grass from gaia (one instanced mesh, per-vertex sway weights, one draw call for thousands of tufts), trees from dryad, surfaces from apate (world-scaled UV grain, moisture/slope-based terrain blending).
VENDOR_INTEGRATIONS.md's wrap-don't-build policy, demonstrated. - Generative music that listens. Pads/arp/bass/drums scheduled per-16th with swing; speed opens the filter and thickens the arp, drifting bends the tape like a warbling cassette, checkpoints ring FM bells; engine = detuned saws through a load-sensitive lowpass; optional Web MIDI note-out. Gameplay state is the composer's controller data.
- Headless sim tests.
npm test= loop closure + full GP/ZEN races to completion, headless.dev/tour.mjs,dev/themes2.mjs,shots*.mjs= Playwright visual-regression tours of all four roads.?safeand?resetboot flags = cheap resilience. - Deterministic rival AI. Racing line + rubber band, skill/aggro traits,
mulberry32seeded per grid slot —RUNTIME.md's per-machine determinism used for AI, so races reproduce. - HOOD cam cockpit. First-person bodywork is hidden (it yawed into the lens mid-drift); a camera-locked dash takes its place — impossible to clip. The "witness camera" discipline in miniature.
Where it lands
GAMEPLAY_FRAMEWORK.md (@3jse/vehicle arcade mode) · ATLAS driving FeelSpec anchors + Vehicle Feel Lab · AUDIO.md generative section · TEMPLATES.md Racing · PERFORMANCE.md procedural/instancing precedents · harness racing recipe.
3. UBURT / PULSEHOP — Q*bert rebuilt as a musical instrument
The fundamental tile-hopping spatial grammar of Qbert, rebuilt so that *playing well is the music**. Three.js + raw WebAudio, no samples, no build step.
What it proves
- Gameplay-as-music. Every hop is quantized to the 16th-note grid (you can only ever play "in time"); tiles map to scale degrees (rows = octaves, columns walk the scale); fresh tiles are the lead voice, completing one is a chord stab, combos fade in groove layers (kick/hats/snare/bass/echo arps); board clear = ascending glissando + cadence. MIDI out on ch 1/2/3/10 with MIDI clock, and an OSC-over-WebSocket bridge (
/pulsehop/note,/pulsehop/combo,/pulsehop/bpm…) — the game literally sequences a DAW. This is the far end ofAUDIO.md's event-driven triggering: not "sounds respond to events" but "the gameplay IS the score." An Atlas Audio/Style lens should look like this. - Intent-relative input on diagonal boards. WASD means screen directions, not board directions — Left always moves you leftward on screen, momentum keeps you zigzagging, glowing key letters float over the exact tile each key takes you to. Ledge guard: one press toward the void makes Pip teeter, only a repeated press leaps. Input UX patterns for isometric games worth a mechanics-registry entry.
- World-as-sim inside an arcade game. WORLD I is an infinite Mandelbrot-terraced voxel sandbox: water/lava flow downhill as a live cellular automaton with Gerstner-wave surfaces, water + lava = obsidian, grass wears swaying tufts (gaia technique), trees are procedurally seeded (dryad technique), ice slides you, lava bounces you, column height = pitch. WORLD III is a bounded arena of instanced cubes driven by a living Julia set — the terrain breathes as you play.
WORLD_SYSTEM.md's "one mechanism, five shapes" proven at the small end. - Performance discipline. Everything pooled (particles, rings, text sprites) — zero per-frame allocation in the hot loop; bloom at half resolution; DPR capped at 2.
- Call-and-response boss. The Conductor lights a melody, you echo it back — rhythm mechanics as a game system, not a minigame bolted on.
Where it lands
AUDIO.md generative/musical section · GAMEPLAY_FRAMEWORK.md (hop grammar, rhythm/sequencer systems) · WORLD_SYSTEM.md small-world precedent · PERFORMANCE.md pooling · new template "Musical Hopper" · harness recipe.
4. DAMN BEAVERS — Dwarf Fortress-class systemic simulation
A systemic beaver-civilization simulator: hydrology, ecology, engineering, economy, culture, history. 11 phases, 183 tasks, 1,534 tests across 256 files, 9 composed gate tests — all green.
What it proves (the architectural laws, in working code)
- The simulation is authoritative. The renderer, animation system, UI, audio, particles, and Chronicle observe simulation state; they do not own truth. "A mesh is not a tree. A shader is not water. An animation is not work. A particle is not an item. A UI icon is not inventory." The simulation must make sense headlessly. This is
RUNTIME.md's headless mode,ENTITY_COMPONENT_MODEL.md's data-first components, and Atlas's "viewport is a witness" — stated as a law and enforced for a year of development. - Systems, not scripted outcomes.
DamFloodEventandBeaverGetsDrunkare forbidden; you implement water + pressure + flow + obstruction + permeability, liquid composition + ingestion + metabolism + motor control, and the events emerge. "Events may record what happened. Events must not secretly make it happen." - A working ECS that validates the object model almost line-for-line.
ComponentStorewith typed component tokens (defineComponent<T>— identity is the token reference, duplicate names deliberately non-interfering and surfaced), a JSON-plain value contract (primitives, arrays, plain objects, EntityId round-trips as numbers — no functions/Maps/class instances), snapshot/restore with versioning.EntityIdregistry: stable persistent identity for every important entity.SimulationClock: fixed ticks, nanosecond precision, a MAX_SPEED_MULTIPLIER bound so a UI bug can't turn oneadvance()into hundreds of millions of ticks, and corrupted-snapshot rejection on restore. These are the exact choicesENTITY_COMPONENT_MODEL.mdandPROJECT_FORMAT.mdspec — with the edge cases already discovered. - Determinism + counterfactual replay, proven. Seeded
Random, and P11-13 implements fork/alter/diff over snapshots — "what would have happened if the dam had held" as a testable query.RUNTIME.md's per-machine determinism + save/replay, demonstrated in production. - Gate sentences. Every phase ends with a written gate sentence ("The parity matrix has no unexplained red rows…") and a composed gate test that proves both halves — including the honesty rule that non-covered rows are re-marked rather than papered over. This is the harness's evidence gate formalized;
build.runTestsshould adopt the pattern. - The test pyramid. unit / simulation / benchmark (14-family × 7-seed emergence suite) / replay / visual / gate — the full
BUILD_DEPLOYMENT.mdbuild.runTestsvision, already running. - Projection architecture.
sim/is pure;presentation/projection/maps entity → render → chunk. Clean separation that made rendering replaceable while the sim kept passing — the same seam the engine draws between layers 0–1 and everything above. - Grounded explanation with a no-fabrication proof. P11-12: natural-language explanation of sim state that is structurally unable to invent causes. This is exactly what Atlas's Explain action and the Agent API's grounded
scene.queryare for. - Concentric-rings roadmap. "Every completed phase must leave behind a playable game" — the roadmap discipline
ROADMAP.md's exit criteria are written in.
Where it lands
ENTITY_COMPONENT_MODEL.md validation · RUNTIME.md determinism/replay · WORLD_SYSTEM.md watershed streaming · PLUGIN_ARCHITECTURE.md references for @3jse/water/@3jse/terrain · harness gate-sentence discipline · ATLAS Explain/witness · new template "Colony Sim".
5. BREAKING WAVES — parametric first-person surf
A standalone TypeScript demo of the parametric breaking-wave + FFT ocean technology from finalsurf: WebGPU renderer, orbit camera, EXR skybox, Tweakpane controls, and a 2D real-time visualization of the leading wave's parametric profile. This is the first-person counterpart to 3JSURF's third-person game.
What it proves
- Parametric breaking waves composited onto an FFT ocean. The breaking wave is painted by shader, not meshed by hand: a storage buffer holds up to
MAX_WAVESslots;composeWavesruns a winner-take-all loop over active slots;waveProfileblends a trochoidal swell into a breaking shape, rotates the lip, and shrinks the front face inward to open the barrel cavity — returningvec4(dx, dy, dz, foamMask)as the single entry point used by displacement. A full wave timeline (lip onset → geometry fades back to swell → residual → fade-out) lives in shader constants. This isRENDERING.md's "orchestration over Three.js" applied to the hardest surface in web 3D, and the natural upstream for@3jse/water's breaking-wave authoring. - Tweakpane = FeelSpec knobs, already working. Every meaningful parameter — amplitude, wavelength, peel strength, lip thickness, face steepness, curl amount, foam onset, inner-shrink — is a live tweakable control. This is exactly Atlas's "direct parameter change, updated live where possible," running today as a demo rather than a spec.
- The profile visualization is a witness. A 2D real-time plot of the leading wave's cross-section sits beside the 3D view — the abstract graph and the rendered surface cross-checking each other. Atlas's witness doctrine in miniature.
- WebGPU adapter-limit engineering. The assemble pass needs 8 simultaneous storage textures (4 cascades × 2 layers), so the demo requests
requiredLimits: { maxStorageTexturesPerShaderStage: 8 }explicitly — adapters that default lower would otherwise fail to compile. A real, shipped lesson for the render-graph's WebGPU init path (PERFORMANCE.md). - Demo ergonomics. The spawn line is kept close to the break point so the first lip throws within ~7 seconds; the scheduler enforces minimum lateral separation of one wavelength so waves never overlap; each wave retires through a fade-out lifecycle rather than a pop.
Where it lands
RENDERING.md wave compositing · PERFORMANCE.md WebGPU limits · Atlas live-tuning + witness · @3jse/water upstream · surf recipe (first-person variant).
6. MANDELHOP — the infinite frogger descent
An endless frogger journey into a recursive psychedelic garden — then a full temporal platforming campaign (9 worlds × 4 stages + Guardian bosses, 8 progressive powers, 5 time powers). ~120 fps on Apple Silicon, three.js vendored, no internet needed.
What it proves
- Deterministic, unfairness-free core. The stated technique: "all lanes are constant-velocity with seeded generation per run; water waves, bobbing, pulse visuals are render-only. Collision uses grid math on the same numbers you see." Gameplay math and render math are the same numbers — the generalization of 3jsurf's attach-by-construction lesson — and every kill must be reactable (complications unlock with depth, each announced by a banner the first time it can appear). This is
RUNTIME.md's determinism posture and the harness's "no unfair deaths" QA rule as a design principle. - Progressive complication unlocks. Dragonflies at depth 40, sinking lilies at 60, non-Euclidean torus portal rows at 90, sheared space at 120, mirror zones at 150, Mandelbrot-pulse lane speeds at 200, chompers at 250 — difficulty as repertoire, taught one mechanic at a time.
- Time powers through one clock. SLOW / FREEZE / PHASE SHIFT / REVERSE / ACCELERATE all route through
worldDt = dt scale— frog responsive, world scaled, one source of time. The runtime's fixed-step accumulator with a time-scale is exactly this; REVERSE (rebuild fallen ruins) is the counterfactual replay of dambeavers as a player power*. - 12 Hz ghost replay. TIME RUN records every run at 12 Hz and replays the best as a translucent frog with a fractal ribbon. Ghost racing, replays, and time-travel debugging need nothing fancier — recorded input/state at 12 Hz is enough (
RUNTIME.md's save/replay claims, demonstrated). - Player agents as QA.
qa/bot.mjsdrives the real game with heuristic hoppers (new/pro skill), reports deaths, completion, and — critically — classifies whether any death was "unfair" (camera/system fault) vs. the player's own mistake. A QA suite of 26 scripts: smoke error sweep, screenshot tours, boss kill-path E2E, state traces. This is the harness's gameplay-qa gate with teeth, and a pattern themechanics-harnessskill should adopt everywhere. - Model third-party notices.
LICENSES.mddocuments the two adapted techniques (poseidon spectral water, gaia grass genomes/wind) with the MIT text reproduced and the adaptation described — the exact provenance disciplineVENDOR_INTEGRATIONS.mdandSECURITY.mdrequire. - Infinite generation on a budget. Rows generated 45 ahead / pooled 25 behind; vegetation in 24-row chunks keyed to biome genomes; water as one world-anchored plane masked per-row by a sliding 128-row DataTexture; biomes cross-fade sky, water, flora, traffic, and the music's root every 30 rows.
WORLD_SYSTEM.md's streaming, at arcade scale. - Generative audio as progression. Hops climb a pentatonic ladder, biome crossings swell, dragonfly telegraphs glissando, wormholes swoop, checkpoints resolve the phrase — and FLOW STATE turns rhythm-chained landings into generative percussion with score ×2. No recordings.
Where it lands
RUNTIME.md determinism/time-scale/replay · WORLD_SYSTEM.md streaming · AUDIO.md generative section · harness mechanics-harness skill (player-agent pattern) + frogger recipe · new template "Endless Hopper" (TEMPLATES.md).
What the harness incorporates now
The following are already incorporated into 3JSE_Harness_v0.2/:
- Mechanics registry (
mechanics.json) — six new entries:surf_feel(3jsurf's measured numbers + scaling laws),first_person_surf(breaking-waves' parametric compositing + live knobs),arcade_racing(zendrive's demand-capacity model + drift feel),hop_grammar(pulsehop's intent-relative input + rhythm),endless_hopper(mendalhop's unfairness-free core + time powers + ghost replay),systemic_sim(dambeavers' laws: sim-authoritative, systems-not-scripts, gate sentences). - Recipes — four new:
arcade-racer.md(zendrive),musical-hopper.md(pulsehop),frogger-endless.md(mendalhop),colony-sim.md(dambeavers);surf-game.mdupdated to cite 3jsurf as its canonical reference implementation and breaking-waves as the first-person variant. - New skill
mechanics-harness— the reference-game tooling promoted to standard practice: a headless mechanics check (gameplay logic runs with no renderer/canvas/DOM and its numbers are asserted), feel measured as numbers, per-frame invariant soaks with a scripted pilot, single-term debug isolation, and heuristic player agents (mendalhop'sbot.mjspattern: drive the real game, report deaths, classify "unfair" deaths as system faults). Applies to every project, not just surf games. docs/FILE_INDEX.txtupdated;node scripts/verify-harness.mjsremains green.
What this means for Atlas
- Driving FeelSpec has real anchors: zendrive's demand-vs-capacity model is the
stability/driftAssist/steeringResponseaxes, and its PROG/palette system is a Style Graph dataset. - Surf FeelSpec has measured anchors: 3jsurf's
feel.mjstable (face run, crossing time, peak speed per break) is the measurement the Feel Lab should produce. - Feel Lab scenarios already exist as executables: 3jsurf's
feel.mjs/soak.mjs/tubeshot.mjsand zendrive'sdev/tours are exactly the "focused test environments"3JSE_ATLAS_FULL_PLAN.md§17 specifies. - The witness is already real: dambeavers proves the sim-authoritative seam, 3jsurf's soak invariants prove per-frame witness checks catch the bugs screenshots miss, and breaking-waves' live 2D profile plot is the witness beside the viewport.
- Live tuning and replays are already real: breaking-waves' Tweakpane panel is Atlas's direct-parameter-change tier, and mendalhop's 12 Hz ghost replay is the time-scrubbing/history lens with a fraction of the machinery.
Asset inventory — what can be shared today
| Asset | Source | Notes |
|---|---|---|
| Surf rig + baked clip library | 3jsurf public/assets/ (skeleton_rig.glb, man_rigged.glb, surf_anims.glb) | Mixamo clips baked; retarget-ready per ANIMATION.md's humanoid standard |
| Sharks ×3, floaties ×3, buoy | 3jsurf public/assets/ | Sketchfab exports — license/attribution ledger required per SECURITY.md |
| Sky panoramas ×2 | 3jsurf public/sky/ | Baked HDRI-style |
| Poseidon ocean (vendored) | 3jsurf src/render/poseidon/ | MIT — already matches VENDOR_INTEGRATIONS.md's pinned-vendor policy |
| Arcade vehicle model | zendrive js/physics.js | ~120-line track-space physics — reference for @3jse/vehicle |
| Shader ocean / wind grass / trees / surfaces | zendrive js/ | WebGL-toon ports of the Owen pantheon — reference implementations |
| Sequencer + MIDI/OSC bridge | pulsehop js/audio/ | Gameplay-as-music architecture |
| Voxel CA fluids, living-fractal world | pulsehop js/world/ | World-as-sim patterns |
| ECS core (ComponentStore/Clock/EntityId) | dambeavers src/sim/core/ | The object-model spec, already implemented |
| Hydrology/economy sims | dambeavers src/sim/ | Reference for @3jse/water/economy gameplay packages |
| Parametric breaking-wave compositor | breaking-waves src/ocean/ | TypeScript/TSL — storage-buffer wave slots, lip rotation, barrel cavity; upstream for @3jse/water |
| EXR skybox + fallback | breaking-waves assets/skybox.exr | Gradient fallback path |
| Time powers / ghost replay / player-agent QA | mendalhop js/timemagic.js js/ghost.js qa/ | One-clock time scaling, 12 Hz replay, unfair-death classification |
| Infinite-track generation | mendalhop js/world.js js/flow.js | 45-ahead/25-behind pooling, biome genomes, DataTexture water mask |
The six projects are not merely demos — they are the plan's Phase 1–4 exit criteria running ahead of schedule: the harness is the development system, these games are the evidence, and the engine's job is to make both first-class.
Gap Analysis vs. Unreal / Unity / GodotENGINE_GAP_ANALYSIS.md
Phase: 7 (ROADMAP.md). Purpose: an honest, grounded assessment of where 3JSE stands against the incumbents, per genre a real developer actually ships in — not a feature-checkbox race. Scored against what is in this repo today, not the design docs.
Legend: ✅ shipped & tested · 🟡 partial / headless-only / needs a viewport to validate · ⬜ not started · ➖ deliberate non-goal.
1. The honest position
Update (2026-09-02): the nine net-new subsystems this document's §6 sequenced are now built as **headless-first
@3jse/packages with tests —@3jse/packaging,@3jse/audio,@3jse/ui, animation retargeting in@3jse/animation,@3jse/materials,@3jse/terrain+@3jse/foliage,@3jse/nav, priority/lag-comp/WebSocket in@3jse/networking,@3jse/vfx. The editor has live panels for Packaging, Material Graph, Particles, Sequencer, Profiler, Atlas, Packages, plus Animation/Terrain views. What remains for each is depth + the GPU/ viewport half* (chunk meshing to BufferGeometry, a GPU particle path, a real audio backend, a polygon navmesh, a relay/matchmaking service), not the core mechanism. The tables below keep their original 🟡/⬜ marks with a trailing note where a package now exists.
3JSE today is a headless-first web game runtime + an editor shell + an agent-native development harness, with roughly Phase 1–2 of a traditional engine's core built and tested, Phase 3–6 partially, and the differentiators (Atlas, the Agent API, the reuse harness) further along than a normal engine would have them at this stage.
What that means concretely:
- You can build a small third-person / top-down / first-person game today, entirely through
tested @3jse/* packages, and tune + hot-reload it in the editor. The Third Person template is a real, playable, headless-verified vertical slice.
- You cannot yet ship a content-heavy 3D game — no streaming/level-partitioning, no
lightmap/GI bake, no material graph, no particle system, no nav-mesh, no animation retargeting UI, no build/packaging pipeline. Those are the bulk of Phase 3–6.
- The parts that are ahead of a normal Phase-2 engine: an agent tool server with real
headless perf/state probes (@3jse/agent), a semantic authoring layer (@3jse/atlas, the Blueprint alternative), a plugin system with versioned extension points (@3jse/plugins), deterministic input replay (@3jse/replay), and a reuse-first harness that turns a coding agent into a reference-first game dev.
2. Core engine subsystems
| Subsystem | Unreal | Unity | Godot | 3JSE today | Gap |
|---|---|---|---|---|---|
| Scene/entity model | Actors/Components | GameObject/Component (+ DOTS) | Nodes | ✅ ECS-over-Object3D, archetype-indexed query, generational handles, snapshot/restore | Storage is still per-entity Map (no SoA columns) — fine to ~10k entities per the Phase 0 bench, not to 100k |
| Scheduler / tick | Tick groups | PlayerLoop / Update phases | _process/_physics_process | ✅ fixed/variable/late stages, registration-order-sensitive, headless-driven | No job graph / parallelism; single-threaded |
| Rendering | Nanite/Lumen, deferred, RHI | HDRP/URP/BiRP, SRP | Forward+/Vulkan | ➖ adopt Three.js WebGPURenderer/TSL — see PLUGIN_ARCHITECTURE.md. Viewport renders; no render-graph, shadows-only lighting | Material graph ⬜, post-process stack ⬜, GI/lightmaps ⬜, virtualized geometry ➖ (not a web target) |
| Physics | Chaos | PhysX / Havok | Jolt / Godot Physics | 🟡 @3jse/physics-rapier — rigid bodies, colliders, kinematic character; 4 tests | No joints/constraints UI, no vehicle/cloth/soft-body, no continuous-collision tuning surface |
| Animation | AnimBP, Control Rig, retargeting | Mecanim, Animation Rigging | AnimationTree, SkeletonIK | 🟡 @3jse/animation state machine + blend tree + TwoBoneIK (18 tests); no editor graph UI, no retargeting, no root-motion extraction UI | Retargeting is the big one for using marketplace animations |
| Audio | MetaSounds, submixes | FMOD/Wwise-class + built-in | AudioStreamPlayer, buses | ⬜ AUDIO.md designed, nothing built | Whole subsystem |
| Input | Enhanced Input | Input System package | InputMap/actions | ✅ InputManager axis/action binding, headless-driveable, deterministic; editor Input Mapping panel | No runtime rebinding UI, no device hot-swap, no touch/gesture layer |
| Navigation | NavMesh + smart objects | NavMesh + AI Navigation | NavigationServer | ⬜ @3jse/nav named, not built | Whole subsystem |
| Networking | Replication graph, Push Model | Netcode for GameObjects / FishNet | MultiplayerSynchronizer | 🟡 @3jse/networking — replication, authority, prediction/reconciliation, RPC, loopback transport (7 tests). No real transport, no relay/matchmaking, no lag comp | Transport + a bandwidth/priority model |
| Save / serialization | SaveGame objects | JsonUtility / ScriptableObjects | ResourceSaver | ✅ @3jse/save (tagged-component snapshots, 5 tests) + @3jse/runtime snapshot/restore + @3jse/project byte-identical round-trip | No migration tooling UI, no binary format |
3. Editor & workflow
| Capability | Incumbents | 3JSE today | Gap |
|---|---|---|---|
| Scene editing | Mature, gizmos, snapping, multi-select | ✅ Viewport + Hierarchy + Inspector + transform gizmos, click-to-select, prefab create/instantiate | No multi-select, no snapping/grid, no undo/redo stack |
| Play-in-editor | One-click, hot state | ✅ Play/Pause, no modify-while-paused, on-screen hot-reload of hand-written Systems (function-swap, no state loss) | Hot-reload is Systems only; component-schema edits still reload |
| Visual scripting | Blueprint / Visual Scripting / GDScript+VisualScript | 🟡 @3jse/graph renders 3IR graphs read-only; @3jse/atlas is the primary surface (semantic map + FeelSpec tuning + agent scoping) — see ATLAS.md | Graph editing (drag/wire/palette) ⬜; Atlas v0.2 lenses ⬜ |
| Material authoring | Full node graph → HLSL | ⬜ Material Graph panel is a placeholder | Whole subsystem (compiles to TSL when built) |
| Particles / VFX | Niagara / VFX Graph / GPUParticles | ⬜ Particles panel is a placeholder; @3jse/extras vendors three-vfx | Whole subsystem |
| Terrain / foliage | Landscape + Foliage / Terrain Tools / GridMap+HeightMap | 🟡 generation cores re-exported from vendored MIT upstreams (poseidon/gaia/dryad/demiurge); no runtime Systems or editor tools | The InstancedMesh/chunk-mesher/TSL-material runtime + the paint tools |
| Profiler | Unreal Insights / Profiler / Godot profiler | ✅ Profiler panel — real runtime.getPerf (CPU/sim timing + scene census) fed by the live render loop | No GPU timing, no draw-call/triangle counts (needs render-pass instrumentation), no flame graph |
| Sequencer / cinematics | Sequencer / Timeline / AnimationPlayer | ✅ Sequencer panel over @3jse/cinematics (property/event/activation tracks, scrub, event log) | No curve editor, no camera-cut track, no sub-sequences |
| Asset pipeline | Import presets, LOD gen, texture streaming | 🟡 @3jse/assets — glTF/GLB import, thumbnails, metadata, character detection (41 tests). No LOD gen, no texture compression pass wired, no dependency graph UI | Draco/meshopt/KTX2 passes exist as libs (@3jse/extras), not wired into an import flow |
| Build / packaging | BuildConfiguration, platform targets | ⬜ Packaging panel is a placeholder | BUILD_DEPLOYMENT.md designed; nothing emits a shippable bundle |
| Source control | Perforce/Git plugins, diff tools | ✅ @3jse/project produces Git-diff-friendly, byte-identical-round-trip project files; no in-editor VCS panel | Diff/merge UI; the format is deliberately text-first so external Git works |
| Multi-user editing | Multi-User Editing / (none) / (none) | ➖ not built — Git instead (EDITOR.md) | Intentional |
4. Where 3JSE is deliberately different (and ahead)
| Capability | Incumbents | 3JSE |
|---|---|---|
| Agent-native development | Bolt-on AI plugins | The coding agent is the primary editor (VISION.md); @3jse/agent exposes the editor's own command API as MCP tools with real headless verify probes (runtime.getPerf / runtime.captureState) + buildEvidenceReport() |
| Semantic authoring | Blueprint exposes implementation | Atlas exposes meaning — systems before files, mechanics before functions, feel before constants (ATLAS.md); the human edits intent + FeelSpec, the agent edits code, the viewport witnesses |
| Reuse doctrine | "build it in-engine" | The 3JSE Harness — a reuse ladder (project → provider → reference → licensed asset → procedural → adapt → custom), a curated provider registry, and quality gates that make "don't reinvent the wheel" an enforced workflow, not advice |
| Extension model | Plugin API with a privileged core | @3jse/plugins — versioned extension-point APIs, no private tier; an official package and a community/* one register through the exact same manifest (PLUGIN_ARCHITECTURE.md) |
| Determinism for tooling | Varies | Per-machine deterministic fixed-step + @3jse/replay (input edge recording → identical replay) + snapshot/restore → counterfactual debugging is a first-class primitive |
| Distribution | Large native runtime | Web-first: the runtime is headless-capable, the "editor is a witness", and a game is a static bundle (when packaging lands) |
5. Genre readiness (ship a real game in…)
| Genre | Readiness | What's missing to ship |
|---|---|---|
| 3D platformer / third-person action | 🟡 slice playable | animation retargeting + graph UI, checkpoints/objectives package, VFX, audio, packaging |
| Top-down / twin-stick | 🟡 slice playable | click-to-move/twin-stick input variant, projectiles/@3jse/combat, audio, packaging |
| First-person | 🟡 slice playable | mouse-look, weapon viewmodel + @3jse/combat, audio, packaging |
| Racing | ⬜ | @3jse/vehicle (physics), track tooling, lap/checkpoint @3jse/match, audio |
| Open world | ⬜ | world partitioning/streaming, terrain runtime + tools, foliage runtime, LOD, nav |
| RTS / tactics | ⬜ | orbit/isometric camera preset ✅, but unit selection/command, @3jse/nav group pathing, fog-of-war |
| RPG | ⬜ | @3jse/inventory / @3jse/dialogue / @3jse/quests, save-migration tooling, UI framework |
| Multiplayer (any of the above) | 🟡 core only | a real transport, relay/matchmaking, lag compensation, a replication priority/bandwidth model |
| Narrative / walking sim | 🟡 closest to shippable | audio, a UI/HUD framework, @3jse/dialogue, packaging |
6. Recommended sequencing to close the biggest gaps
Ordered by "unblocks the most genres per unit of work". Status after 2026-09-02: items 1–9 have a shipped headless core + (mostly) an editor panel; the trailing work is depth + the GPU/viewport/service half.
- ✅ Packaging (
BUILD_DEPLOYMENT.md) —@3jse/packaging: plan/gate/publish, tree-shake, asset finalize, manifest, notices, generated static-host bundle. Editor Packaging panel.@3jse/cli3jse publishnow runs a real esbuild bundle (stdin entry,threeexternal). Left:* Tauri/Steam/mobile wrappers. - ✅ Audio (
AUDIO.md) —@3jse/audio: bus mixer + ducking, AudioSource/Listener/ReverbZone, event router, musical grid + MIDI/OSC. Left: the Web Audio backend, a Project-Settings mixer panel, reverb-zone occlusion. - ✅ UI / HUD framework —
@3jse/ui: retained tree, flexbox-subset layout, data binding, hit-test, renderer seam. Left: the DOM/canvas renderer, an editor UI editor, a widget library. - ✅ Animation retargeting —
retargetClip/autoMapSkeletonin@3jse/animation; editor Animation panel with a live retarget demo. Left: a full anim-graph editing canvas, root-motion extraction UI, cross-side-convention bone matching. - ✅ Material Graph → TSL —
@3jse/materials: model, validation,compileToTSL, CPU reference evaluator. Editor Material Graph panel. Left: a drag/wire node canvas, the live GPU preview. - ✅ Terrain/foliage runtime —
@3jse/terrain(heightfield/mesher/LOD/streamer + splat maps +paintSplatbrush) +@3jse/foliage(constrained scatter → instance matrices).@3jse/renderchunk mesh → BufferGeometry +terrainSplatMaterial(TSL channel-mix) live in the viewport. Editor Terrain panel. Left: CSG, an in-viewport paint UI. - ✅ Nav-mesh —
@3jse/nav: grid bake, octile A + string-pull, flow field (group pathing), NavAgent.@3jse/nav-recastbakeRecastNavMeshbakes a real polygon navmesh from THREE geometry via recast-navigation-js. Left:* off-mesh links, a bake panel. - ✅ Networking transport + priority —
PriorityAccumulator,HistoryBuffer(lag comp),WebSocketTransportin@3jse/networking. Left: a relay/matchmaking service, a binary codec. - ✅ Particles/VFX —
@3jse/vfx: CPU SoA sim, curves/gradients over life, ParticleEmitter component/system.@3jse/renderGpuParticleRenderer(TSLPointsNodeMaterial, per-particle size + soft sprite, storage buffers) is the GPU render path; editor Viewport uses it. Left: a full GPU-compute re-sim, a VFX node graph. - 🟡 Atlas v0.2 remaining lenses + live agent planning — all §5 lenses done (state/flow/world/style/trace/rig), plus a wired Trace time scrubber (rAF sweep + seek slider + node pulses +
pulseCountsstrip). Left (deliberate): a live LLM behind "Ask agent" (§28 export + §30 preview are real; planning waits on an actual LLM), Feel Lab, the 2.5D/Three.js layer.
7. One-paragraph summary
3JSE has a tested, honest Phase 1–2 core (entity model, scheduler, input, physics wrap, character + camera presets, animation state machine, save/snapshot, three genre templates) and genuinely novel Phase 4–5 differentiators (agent tool server with real verify probes, the Atlas semantic authoring layer, a no-privileged-tier plugin system, deterministic replay). It is not a drop-in Unreal/Unity/Godot replacement: the content-production half of an engine — packaging, audio, UI, material/particle authoring, terrain/foliage runtime, nav, animation retargeting — is largely unbuilt. The path to "ship a real game" runs through packaging → audio → UI first, then the authoring subsystems, with the AI-native layer compounding value the whole way.
3JSE WebsiteWEBSITE.md
What this is
3jse.com is the official website of the 3JSE project. The domain is owned by the project, the site is live, and — like everything else in this repository — it is part of the project and kept updated alongside the engine. It is not an external marketing artifact; it ships with the repo.
The site has two jobs:
- Promotional landing page (
site/index.html) — the public pitch, in the editor's own visual identity: a live Three.js hero inside a framed "Viewport" panel, the comparison table, the four frontends, the ten-layer architecture, the panel inventory, and the roadmap. - The design manual (
site/manual.html) — all ofdocs/, baked into a single cross-linked page, generated from the markdown so it can never drift from the source of truth.
Where it lives
Everything is under site/ in this repository, alongside the engine code:
| Path | What it is | Edit it? |
|---|---|---|
site/index.html | Promotional landing page | Yes — directly |
site/manual.html | Generated design manual | No — generated by the script below |
site/build-manual.mjs | The doc-to-manual baker | Yes |
site/assets/css/site.css | Shared stylesheet (landing + manual) | Yes |
site/assets/js/main.js | Three.js hero scene (bloom, particles, parallax) | Yes |
site/assets/img/ | Logo, banner, architecture SVGs | Yes |
site/README-DEPLOY.md | Deployment and maintenance runbook | Yes |
Keeping it updated — the policy
The website is updated by the same PR process as the engine. Concretely:
- Docs changes update the manual automatically in practice: after editing anything under
docs/, runnode site/build-manual.mjsand commit the regeneratedsite/manual.htmlin the same change. The build script is a plain Node script with no dependencies. - Positioning changes update the landing page in the same PR. The comparison table, the roadmap phases, the panel inventory, and the pitch copy on
index.htmlmirrorREADME.mdand the relevant docs — when one changes, the other changes with it, in the same commit. A PR that updatesdocs/VISION.mdwithout checkingsite/index.htmlis incomplete. - Design changes inherit from the editor. The site's palette tokens are the editor's own (
#0c0d11background,#15171dsurface,#262b36borders, cyan/violet/magenta brand gradient — seeapps/editor/src/App.css), and the visual language is the editor's panel/dock chrome. If the editor's identity evolves, the site evolves with it. - The manual is a snapshot, not a separate docs host. There is no second editing surface —
manual.htmlis always regenerated fromdocs/. If the manual on the site is stale, the fix is running the script and committing, not editing HTML by hand.
Deployment
Static files, no build step, no server code. Upload the contents of site/ (index.html, manual.html, assets/) to the web root of the 3jse.com host over SFTP — the full runbook, including the self-hosting option for the Three.js CDN dependency, is in site/README-DEPLOY.md. The site's Three.js hero loads three@0.170.0 from jsdelivr; it degrades to the static SVG banner when WebGL or the CDN is unavailable.
Posture
The site is promotional in tone, but it is honest by policy — the same policy as VISION.md: the comparison table concedes the rendering ceiling, the roadmap states the pre-alpha status plainly, and every claim traces to a doc in the manual. The website is the storefront, not a second source of truth.
3JSE ShopSHOP.md
What this is
The Shop is 3JSE's content marketplace — examples, kits, templates, and community games, browsable in the editor and on 3jse.com. Its defining rule is link-first: the app ships metadata and pointers, never content. The editor stays lightweight; the internet is the CDN. Where the vendor registry (VENDOR_INTEGRATIONS.md) exists for capabilities — code worth wrapping into @3jse/ packages — the Shop exists for content*: things to learn from, remix, play, or start from. The two cross-link whenever both apply (poseidon is both a water capability and a kit).
Design principles
- Link-first. An entry is metadata plus URLs: source repo, homepage, live demo, and — for the freshest work — a social signal (an x.com post, the way
chiro-elemental's registry entry already recordsx.com/TokenGremlin/status/…and its author). Nothing is mirrored or re-hosted by default. Pulling happens on demand through the same pinned-commit staging machinery the vendor fetcher already uses (VENDOR_INTEGRATIONS.md, Tier B) — a fixed SHA, never a floating branch. - The Shop states licensing; it never adjudicates it. Every entry carries the license as declared by the creator, with the registry's
verifiedBystatus. The Shop's legal posture is disclosure and attribution, not warranty. What users build with a kit is their own responsibility — this is written into the Terms of Use, and the Terms ask users to be ethical: credit the humans, respect the declared terms, don't repackage someone else's game as your own. - Everything is a project. Any example, kit, or community game can be staged as a read-only project, run in the editor, inspected — then "Save as my project" forks it locally. There is no second way to consume content; the editor's normal project flow (
PROJECT_FORMAT.md) is the only way. - Curated, not a firehose. Scrapers generate candidates; humans and the Curator agent graduate them. X/Twitter drops are the freshest and riskiest signal class — they always land as candidates, never auto-published, and staged content never executes at import time (
VENDOR_INTEGRATIONS.md's sandboxing section applies unchanged). - First-party shelf is templates only. The one shelf 3JSE itself maintains is
TEMPLATES.md's template catalog — every other shelf is someone else's work, attributed and linked, never absorbed.
Categories
| Category | What belongs | Canonical example |
|---|---|---|
| Examples | Technique demos, reference scenes, the official Three.js examples (indexed wholesale from threejs.org/examples/files.json, pinned to the current Three.js release tag) | webgl_animation_keyframes |
| Kits | Reusable packs: shader/effect collections, character rigs, environment kits — the Owen pantheon, Chiro Elemental, Three-VFX | poseidon, chiro-elemental |
| Templates | Official 3JSE templates (TEMPLATES.md) — the only first-party shelf | template-third-person |
| Community games | Finished or playable games, including the AI-generated wave — links to where the creator published: GitHub, an x.com post, itch.io, a personal site | a game the creator posted on X |
| Portals | Discovery feeds, not entries: CodePen's three-js tag, itch.io's webgl tag, an x.com search — rendered as browse-out links | — |
Sources and scraping
- Official examples shelf —
tools/shop-scan.mjsindexesthreejs.org/examples/files.json(the same index the official examples page loads) and emits one candidate per example: live URLthreejs.org/examples/#<slug>, source atgithub.com/mrdoob/three.js/blob/<release>/examples/<slug>.html. Three.js is MIT; the shelf is the single largest free selection the Shop can offer and it costs us one HTTP fetch. - GitHub discovery — the same tool queries
gh api search/repositories(topic:threejs, stars threshold, license field from the API as a hint only) and emits candidates withlicense.verifiedByempty. The API's license field is a hint, never a verdict — the registry's BOM case (tiamat,VENDOR_INTEGRATIONS.md) is exactly why. - Social drops (x.com et al.) — no automated scraping: the platforms' APIs are closed or paid, and the content is the riskiest class. Captured manually (or by a human-supervised Curator agent) into candidates with the post id and author recorded as the
signalfield — the pattern already established in the registry. - Everything lands in
packages/vendor/shop-candidates.jsonfirst. Publishing topackages/vendor/shop.jsonis a deliberate, reviewed step — the same graduation discipline as Tier B → Tier A, applied to content.
Entry schema (packages/vendor/shop.json)
{
"id": "webgl-animation-keyframes",
"category": "example",
"title": "Animation — keyframes",
"author": "Three.js project",
"source": {
"repo": "github.com/mrdoob/three.js",
"pinnedCommit": "r185",
"liveDemo": "https://threejs.org/examples/#webgl_animation_keyframes"
},
"license": { "spdx": "MIT", "verifiedBy": "human", "verifiedAt": "2026-08-24" },
"tags": ["animation", "skinning"],
"aiGenerated": false,
"registryId": null,
"notes": ""
}Fields: id (globally unique with the registry), category, title, author, source (repo/homepage/liveDemo/signal), pinnedCommit, license (as declared + verification status), tags, aiGenerated (the AI-game wave gets flagged in the UI with "license uncertain — check with the creator"), registryId (cross-link when the same work is a capability), notes. signal records { platform, url, author } for social drops.
Licensing and ethics — the paperwork
- The Shop states what the creator declared.
verifiedBy: "human"remains a hard gate for anything the editor imports into a user's machine; a link-only entry (live demo, homepage) can ship withverifiedByempty and is rendered with an "as declared" badge instead of a verdict. - Users are responsible for what they build. The Terms of Use (
site/terms.html, linked from the Shop in editor and on the web) state it plainly: each entry's license governs its use; commercial use must be checked independently; creators must be attributed; the Shop is a directory and licensor of nothing; no warranty, express or implied. - The Terms ask users to be ethical. Credit the humans. Respect the declared terms. Don't pass off others' work — AI-generated or not — as your own. The Shop makes great software; how people use it is their own responsibility, and the Terms say so without pretending to police it.
- Take-down. Any creator can have their work removed from the Shop by issue or email; removals happen promptly, no questions required. The Shop is a service to creators, not a claim on their work.
Editor integration
The Content Browser gains a Shop panel (Phase 3, alongside the Open Source panel — same @3jse/vendor machinery, different shelf):
- Browse — cards with screenshot, license badge, category tabs, search,
aiGeneratedflag. - Preview — stages the pinned tarball into
/plugins/_vendor/shop/<id>/read-only and runs it sandboxed. Never executes at import time. - Open as project — materializes a normal project folder; Play works; "Save as my project" forks it. The AI-generated wave is consumable here like everything else: as a project to learn from and remix.
- Install — exists only for registry-cross-linked entries (
registryId), where it behaves exactly like the Open Source panel's install button. - Live demo — opens the creator's canonical link. The creator's page is the entry's home, always.
Website integration
site/shop.html is the public Shop — the same shop.json, baked by site/build-shop.mjs (generated, never hand-edited, like the manual). It renders the shelves, license badges, the ethics/legal band, and a deep-link placeholder (3jse://open?entry=<id>) that becomes live once the editor registers the protocol. Terms live at site/terms.html.
Roadmap placement
- Phase 3 — Shop panel, Preview/Open-as-project staging (reuses the vendor fetcher), the official examples shelf (the files.json index is an immediate, zero-risk win), and the candidates queue.
- Phase 4 — the Curator agent graduates candidates → entries under human review, exactly like registry curation.
- Phase 6 — community submissions UI, ratings, the take-down workflow, and the
3jse://deep-link protocol. No payment rails — the Shop is free and open; a paid marketplace is explicitly out of scope.
What the Shop is not
- Not a payment marketplace. No money rails, no storefront for selling assets — free and open, now and later.
- Not a license adjudicator. The Shop discloses; it does not decide disputes, and it will not guess licenses the creator never declared.
- Not a hosting service. Creators' links stay canonical; the Shop mirrors nothing publicly (staging is local and pinned, never re-served).