@jgengine/editor 0.18.1 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/CHANGELOG.md +504 -7
  2. package/dist/ClipPreviewLayer.d.ts +2 -3
  3. package/dist/ClipPreviewLayer.js +24 -26
  4. package/dist/CreatorApp.d.ts +12 -0
  5. package/dist/CreatorApp.js +107 -0
  6. package/dist/DebugDraw.js +3 -1
  7. package/dist/EditorApp.d.ts +14 -2
  8. package/dist/EditorApp.js +29 -14
  9. package/dist/EditorChrome.d.ts +9 -1
  10. package/dist/EditorChrome.js +61 -35
  11. package/dist/InspectorPanel.d.ts +3 -1
  12. package/dist/InspectorPanel.js +12 -8
  13. package/dist/LightingPanel.js +5 -1
  14. package/dist/MaterialAssetEditor.d.ts +13 -0
  15. package/dist/MaterialAssetEditor.js +109 -0
  16. package/dist/MaterialPreview.d.ts +16 -0
  17. package/dist/MaterialPreview.js +41 -0
  18. package/dist/MaterialsWorkspacePanel.d.ts +14 -2
  19. package/dist/MaterialsWorkspacePanel.js +78 -4
  20. package/dist/RuntimePlayBridge.js +1 -6
  21. package/dist/SelectionGizmo.js +23 -14
  22. package/dist/SimulationInspector.d.ts +9 -0
  23. package/dist/SimulationInspector.js +47 -0
  24. package/dist/TerrainSculpt.js +3 -1
  25. package/dist/agent/toolBridge.js +2 -0
  26. package/dist/authoringPlacement.d.ts +21 -0
  27. package/dist/authoringPlacement.js +34 -0
  28. package/dist/handlers/context.d.ts +1 -0
  29. package/dist/handlers/document.d.ts +1 -1
  30. package/dist/handlers/document.js +31 -1
  31. package/dist/handlers/hierarchy.d.ts +1 -1
  32. package/dist/handlers/hierarchy.js +4 -0
  33. package/dist/handlers/navmesh.d.ts +2 -0
  34. package/dist/handlers/navmesh.js +16 -4
  35. package/dist/handlers/runtime.js +20 -17
  36. package/dist/handlers/terrain.js +52 -12
  37. package/dist/index.d.ts +2 -1
  38. package/dist/index.js +1 -0
  39. package/dist/materialControls.d.ts +32 -0
  40. package/dist/materialControls.js +79 -0
  41. package/dist/mcp/fieldSpec.d.ts +1 -1
  42. package/dist/mcp/fieldSpec.js +13 -4
  43. package/dist/mcp/importOptionalGameModule.d.ts +2 -0
  44. package/dist/mcp/importOptionalGameModule.js +13 -0
  45. package/dist/mcp/loadGameCatalogs.js +5 -12
  46. package/dist/mcp/rpcRequest.d.ts +3 -3
  47. package/dist/mcp/rpcRequest.js +10 -4
  48. package/dist/mcp/tools.js +13 -4
  49. package/dist/modelAnimationAuthoring.d.ts +49 -6
  50. package/dist/modelAnimationAuthoring.js +118 -64
  51. package/dist/session.d.ts +64 -0
  52. package/dist/session.js +58 -7
  53. package/dist/shell/AnimationGraphPanel.d.ts +16 -0
  54. package/dist/shell/AnimationGraphPanel.js +180 -0
  55. package/dist/shell/AnimationPanel.d.ts +3 -1
  56. package/dist/shell/AnimationPanel.js +9 -7
  57. package/dist/shell/PlayModeBar.d.ts +2 -1
  58. package/dist/shell/PlayModeBar.js +2 -2
  59. package/dist/shell/SceneToolbar.d.ts +2 -1
  60. package/dist/shell/SceneToolbar.js +5 -4
  61. package/dist/shell/TopAppBar.d.ts +2 -1
  62. package/dist/shell/TopAppBar.js +2 -2
  63. package/dist/shell/WorkspaceRail.js +1 -1
  64. package/dist/shell/animGraphPreview.d.ts +58 -0
  65. package/dist/shell/animGraphPreview.js +95 -0
  66. package/dist/shell/clipPreview.d.ts +9 -0
  67. package/dist/useDocumentSave.d.ts +20 -0
  68. package/dist/useDocumentSave.js +33 -0
  69. package/package.json +6 -5
  70. package/skills/ce-handoff/SKILL.md +2 -2
  71. package/skills/jgengine/SKILL.md +28 -6
  72. package/skills/jgengine/api.md +139 -99
  73. package/skills/jgengine/capabilities.md +28 -0
  74. package/skills/jgengine/recipes/minimal-game.md +10 -2
  75. package/skills/jgengine-editor/SKILL.md +12 -2
  76. package/skills/jgengine-editor/api.md +120 -16
  77. package/skills/jgengine-editor/capabilities.md +40 -0
  78. package/skills/jgengine-editor/reference.md +161 -3
  79. package/skills/jgengine-editor/references/live-sync.md +15 -0
  80. package/skills/level-design/SKILL.md +1 -1
@@ -12,6 +12,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
12
12
 
13
13
  - `collectAuthoredTriggers` (function) · `import { collectAuthoredTriggers } from "@jgengine/shell/gameKit"`
14
14
 
15
+ ## chase-view-cycle — cycle a vehicle camera between chase, hood and cockpit views at runtime
16
+
17
+ - `nextChaseView` (function) · `import { nextChaseView } from "@jgengine/core/runtime/cameraDirector"`
18
+
15
19
  ## client-side — input prediction with replay reconciliation
16
20
 
17
21
  - `createPredictionBuffer` (function) · `import { createPredictionBuffer } from "@jgengine/core/runtime/prediction"`
@@ -20,6 +24,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
20
24
 
21
25
  - `GameContextModels` (interface) · `import { GameContextModels } from "@jgengine/core/runtime/gameContext"`
22
26
 
27
+ ## command-number — validate finite, bounded numbers and integers at command boundaries
28
+
29
+ - `readInputNumber` (function) · `import { readInputNumber } from "@jgengine/core/runtime/commandInput"`
30
+
31
+ ## command-parse — parse untrusted command input once so every command stage sees typed, bounded values
32
+
33
+ - `defineCommand` (function) · `import { defineCommand } from "@jgengine/core/runtime/commandRunner"`
34
+
23
35
  ## command-quantity — validate bounded whole-item counts at command boundaries
24
36
 
25
37
  - `readQuantity` (function) · `import { readQuantity } from "@jgengine/core/runtime/commandInput"`
@@ -40,6 +52,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
40
52
 
41
53
  - `EditorCatalogDefinition` (interface) · `import { EditorCatalogDefinition } from "@jgengine/shell/gameKit"`
42
54
 
55
+ ## fire-input — bind a key or mouse button to a named action that runs the same-named command with the aim; repeatMs auto-fires while held
56
+
57
+ - `ActionCodesMap` (type) · `import { ActionCodesMap } from "@jgengine/core/authoring"`
58
+
43
59
  ## game-system — declare a composable capability with its own schedule and lifecycle
44
60
 
45
61
  - `SystemDefinition` (interface) · `import { SystemDefinition } from "@jgengine/shell/gameKit"`
@@ -96,6 +112,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
96
112
 
97
113
  - `createInputRecorder` (function) · `import { createInputRecorder } from "@jgengine/core/runtime/inputRecorder"`
98
114
 
115
+ ## local-players — Couch co-op seats: devices hot-join into slots, each with its own user id and input snapshot.
116
+
117
+ - `createLocalPlayers` (function) · `import { createLocalPlayers } from "@jgengine/core/runtime/localPlayers"`
118
+
99
119
  ## loot-table — validate a loot table definition for use with the registry
100
120
 
101
121
  - `lootTable` (function) · `import { lootTable } from "@jgengine/core/authoring"`
@@ -178,6 +198,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
178
198
 
179
199
  - `defineStore` (function) · `import { defineStore } from "@jgengine/shell/gameKit"`
180
200
 
201
+ ## warn-once — emit a dev-only warning a single time per call site
202
+
203
+ - `warnOnce` (function) · `import { warnOnce } from "@jgengine/core/devtools/warnOnce"`
204
+
181
205
  ## world-chunk-key — map world positions to persisted chunk keys at a declared cell size
182
206
 
183
207
  - `chunkKeyOf` (function) · `import { chunkKeyOf } from "@jgengine/core/runtime/worldChunks"`
@@ -193,3 +217,7 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
193
217
  ## world-environment — compose editor/preset-derived outdoor dressing — terrain, weather, water, structures — into a legacy environment feature
194
218
 
195
219
  - `environment` (function) · `import { environment } from "@jgengine/shell/gameKit"`
220
+
221
+ ## world-item-pickup — pick up dropped items: ctx.scene.worldItem nearestInRadius → pickup into the player's inventory
222
+
223
+ - `SceneWorldItemContext` (interface) · `import { SceneWorldItemContext } from "@jgengine/core/runtime/gameContext"`
@@ -6,6 +6,11 @@ authored scene edited in the browser, one system, one store slot, an empty-canva
6
6
  and a win condition. Every new game starts here; add combat, multiplayer, or deeper
7
7
  world features only after this loop plays.
8
8
 
9
+ Every extension follows the [framework-first decision](../SKILL.md#framework-first-decisions):
10
+ compose an installed SDK capability, improve its upstream contract if needed, then
11
+ remove superseded game glue after published adoption. The game owns its rules and art;
12
+ it should not recreate input, model lifecycle, storage or UI accessibility machinery.
13
+
9
14
  ## 1. Scaffold
10
15
 
11
16
  `npx jgengine create <name>` (inside the engine monorepo: `bun run new:game "<id-or-title>"`).
@@ -45,6 +50,9 @@ spatial place. When the game *is* a place, declare only substrate + laws with `w
45
50
  `@jgengine/core/world/place` (e.g. `{ id, ground: { mode: "flat", size: { x: Infinity, z: Infinity } }, physics: { gravity: -24 } }`,
46
51
  or `mode: "board"` for 2D). Never seed, sky, or vegetation in `world` — the engine renders its
47
52
  default sky until you author one in the editor, and foliage is editor scatter over the ground.
53
+ A created 3D game instead ships hills as a terrain sculpt in `editor.scene.json` and a `world.ts`
54
+ that consumes it with `environment({ sculpt })` via `environmentContentFromDocument`; the file
55
+ holds only the ground palette. Reshape the hills in the editor, not in code.
48
56
 
49
57
 
50
58
  ```ts
@@ -77,8 +85,8 @@ direction. Compose the shipped building blocks the moment you need them (`StatBa
77
85
  `Coins`, `InventoryGrid`, `CharacterSheet`, window shells from `jgengine-ui`), then reskin via
78
86
  `HudTheme` tokens. Reaching for those is using the engine correctly, not incomplete work. What
79
87
  the engine does not ship is a whole finished game *face* or genre theme preset — do not leave an
80
- unarranged, unskinned generic dashboard as the product. Hand-roll markup only where no building
81
- block fits (see `jgengine-ui`).
88
+ unarranged, unskinned generic dashboard as the product. Custom markup can use headless
89
+ SDK behavior; a missing reusable behavior is an upstream gap (see `jgengine-ui`).
82
90
 
83
91
  ## 3. Author, play, win
84
92
 
@@ -17,7 +17,7 @@ Every editor-visible object has an explicit provenance — `authored`, `generate
17
17
 
18
18
  ## Headless fast path
19
19
 
20
- Inspect, mutate, and persist a game's scene in single commands — no GUI session and no reference reading needed for basic authoring:
20
+ Inspect, mutate, and persist a game's scene in single commands — no GUI session and no reference reading needed for basic authoring (monorepo):
21
21
 
22
22
  ```sh
23
23
  bun packages/editor/src/mcp/cli.ts --game <id> --tools # verb inventory with descriptions
@@ -28,6 +28,10 @@ bun packages/editor/src/mcp/cli.ts --game <id> \
28
28
 
29
29
  Repeat `--rpc` to batch several mutations on one session; `--save` then writes the document back to `Games/<id>/src/editor.scene.json` in the same format as the GUI's Ctrl+S, and a failed RPC aborts the batch before anything is saved.
30
30
 
31
+ For a multi-object authoring operation, use `push_document_patch` with a `commands` patch and the current `document_revision` as `baseRevision`. The command batch stages atomically, produces one undo step and one document publication, and reports a zero-based failing command index without leaving earlier edits behind. Use stable caller-owned object ids so later commands can reference earlier placements; same-kind adds upsert, while cross-kind collisions fail. See [reference.md](reference.md#atomic-authoring-batches) for a complete request. Repeated independent `--rpc` calls still produce separate undo steps.
32
+
33
+ That CLI exists only in the monorepo (`npx jgengine editor-mcp` says so). In a created project the same verbs run on the live page through the agent bridge: `bun run drive -- --rpc '{"method":"editor_summon"}' --rpc '<verb json>' --rpc '{"method":"save_scene"}'`. `editor_summon` resolves once the editor has mounted, so the verbs after it in the same batch reach it.
34
+
31
35
  ## Canonical workflow
32
36
 
33
37
  1. Inspect the current scene and available editor capabilities.
@@ -38,7 +42,13 @@ Repeat `--rpc` to batch several mutations on one session; `--save` then writes t
38
42
 
39
43
  Scaffolded games start editor-wired: `npx jgengine create` (also what `bun run new:game` runs in-repo) uses one template that ships `src/editor.scene.json` + `editorLayers.ts`, passes the document to play mode and F2+E through `defineGame({ editorLayers })` (auto-mounted `AuthoredScene`), and spawns at the authored marker — extend the shipped document instead of re-wiring or hardcoding. To promote a scene authored in the standalone editor (`npx jgengine editor`) into a runnable game, `npx jgengine create "<Name>" --from-scene <folder>` bakes that folder's `editor.scene.json` in as the new game's scene (adding a `player_spawn` at the origin only if the authored scene lacks one), so the built game walks the scene that was just authored. Once promoted, an editor asset import (drop a `.glb`/`.gltf`) no longer scans a model folder: the host detects the typed `src/game/assets.ts` catalog, copies the bytes into the game's `public/<basePath>/imported/`, and rewrites `assets.ts` to add a durable `extras` entry (`buildCatalog({ extras })`), so the shipped game resolves the imported id through its own catalog. The rewrite is idempotent — re-importing the same id collapses to one entry — and falls back to the folder-scan import if `assets.ts` can't be safely rewritten.
40
44
 
41
- Use `capabilities.md` to discover editor/runtime imports and `api.md` for signatures. Open [reference.md](reference.md) for RPC/CLI operations, embedded-agent behavior, scene schema details, and troubleshooting.
45
+ Use `capabilities.md` to discover editor/runtime imports and `api.md` for signatures. Open [reference.md](reference.md) for RPC/CLI operations, embedded-agent behavior, scene schema details, and troubleshooting. Use [live-sync reconnect](references/live-sync.md) when a client resumes beyond retained patch or runtime-delta history.
46
+
47
+ ### Player creation and durable playtests
48
+
49
+ For a production Create/Edit surface, use `GameHost`'s controlled `creatorOpen`/`onCreatorOpenChange` from the game's own menu and pass `creator` configuration with injected `CreatorDocumentStorage`, `CreatorPolicy`, `initialDocument`, and `createPlayable(document)`. `createCreatorDocumentStorage` (`@jgengine/core/editor/creatorStorage`) adapts an injected key/value backend to named versioned saves with optimistic revision checks. Save failure and stale revisions stay visible; reopening loads durable content, independently of developer recovery drafts. The policy bounds documents, bytes, objects, paths, grids, terrain and approved kinds/assets/catalog ids; optional simulation budgets and `validate` apply game rules. Creator documents use explicit placements, without prefab/directive expansion or external asset URLs.
50
+
51
+ Build each playtest through `createPlayable` from the captured current document, including unsaved edits. The editor retains its authored document and undo history, and each playtest gets a fresh shell and runtime live-sync bus. Returning discards that runtime state. The player flow uses normal buttons and does not require the developer global host, keyboard chords, agent RPC or a development save server. See [reference.md](reference.md#production-creator) for the host composition.
42
52
 
43
53
  ## Traps
44
54
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  ## @jgengine/core/editor
6
6
 
7
- - `ApplyDocumentPatchResult` (type): type ApplyDocumentPatchResult = | { ok: true; document: EditorDocument; revision: number; patch: DocumentPatch } | { ok: false; error: string } — Result of applying a {@link DocumentPatch} to a document + revision pair.
7
+ - `ApplyDocumentPatchResult` (type): type ApplyDocumentPatchResult = | { ok: true; document: EditorDocument; revision: number; patch: DocumentPatch } | { ok: false; error: string; commandIndex?: number } — Result of applying a {@link DocumentPatch} to a document + revision pair.
8
8
  - `AsciiGridExportOptions` (interface): interface AsciiGridExportOptions — Options for rendering a grid layer back out as an ASCII/glyph map.
9
9
  - `AsciiGridImportOptions` (interface): interface AsciiGridImportOptions — Options for importing an ASCII/glyph map into a grid layer. Provide `glyphMap` (char → value id) or a `palette` whose entries carry `glyph`s (or both — `glyphMap` wins on conflict). Any glyph not mapped, and any short-row padding, resolves to `empty`.
10
10
  - `CURRENT_GRID_SCHEMA_VERSION` (const): const CURRENT_GRID_SCHEMA_VERSION: 1 — The grid-layer cell-schema version this build writes and migrates toward.
@@ -17,7 +17,7 @@
17
17
  - `DocumentBakeOptions` (interface): interface DocumentBakeOptions extends MinimapBakeOptions — Options for {@link bakeMinimapFromDocument}.
18
18
  - `DocumentLiveEvent` (interface): interface DocumentLiveEvent — Event emitted when the authoritative document changes on a {@link DocumentLiveSync}.
19
19
  - `DocumentLiveSync` (interface): interface DocumentLiveSync — Two-way live-sync bus: document patches out, runtime state deltas back.
20
- - `DocumentPatch` (type): type DocumentPatch = | { type: "snapshot"; revision?: number; baseRevision: number; document: EditorDocument; } | { type: "commands"; revision?: number; baseRevision: number; commands: readonly EditorCommand[]; } — One versioned document mutation on the live-sync stream. `snapshot` replaces the whole document; `commands` replays structural editor commands onto the current document. `baseRevision` must match the receiver's current revision unless `force` is set (document authority from the editor).
20
+ - `DocumentPatch` (type): type DocumentPatch = | { type: "snapshot"; revision?: number; baseRevision: number; document: EditorDocument; } | { type: "commands"; revision?: number; baseRevision: number; commands: readonly EditorCommand[]; } — One versioned document mutation on the live-sync stream. `snapshot` replaces the whole document; `commands` replays structural editor commands onto the current document. `baseRevision` must match the receiver's current revision unless `force` is set (document authority from the editor). `revision` preserves the authority cursor when replaying: snapshots may jump forward for reconnect recovery; commands must be the next revision.
21
21
  - `ENTITY_CATALOG_ID` (const): const ENTITY_CATALOG_ID: "entities" — Well-known catalog id for authored entity definitions. A `mob`/`boss` marker's `catalogId` references an entry (row) in this catalog, and {@link entityEntryFromCatalog} turns that row into the runtime {@link GameContextEntityEntry} a spawn consumes — so an entity's stats and speed are authored in the editor Data tab, not hardcoded in game TS.
22
22
  - `EditorCatalogData` (interface): interface EditorCatalogData — Persisted values for one gameplay data catalog (weapons, waves, economy, …). Schemas are not stored here — they come from the game's `editorCatalogs` export and drive SchemaInspector.
23
23
  - `EditorCatalogDefinition` (interface): interface EditorCatalogDefinition — Game-exported catalog definition: a `ParamSchema` plus default entries. Schemas stay in code; entry values merge into `document.catalogs` and are what the editor/RPC edits and saves.
@@ -53,6 +53,7 @@
53
53
  - `EditorSessionState` (interface): interface EditorSessionState — The document plus current selection at a point in editor history.
54
54
  - `EditorSkyPreset` (type): type EditorSkyPreset = "day" | "dusk" | "night" — Named sky look stored on the scene document; matches runtime `SkyEnvironmentConfig.preset`.
55
55
  - `EditorTerrain` (type): type EditorTerrain = TerraformSnapshot — A sculpted heightfield authored in the editor: the {@link TerraformSnapshot} of offset deltas over the game's base ground. Serializes with the scene; a game rebuilds the field with `editableTerrainFromSnapshot`.
56
+ - `EditorTransactionResult` (type): type EditorTransactionResult = | { ok: true; state: EditorSessionState; changed: boolean } | { ok: false; error: string; commandIndex?: number } — Atomic command-batch outcome; a failure identifies the zero-based command index.
56
57
  - `EditorUiDocument` (interface): interface EditorUiDocument — Scene-document HUD section: panel id → layout. Single source of truth for placement.
57
58
  - `EditorUiPanelLayout` (interface): interface EditorUiPanelLayout — Authored layout for one HUD panel inside `editor.scene.json` → `ui.panels`.
58
59
  - `EditorVec3` (type): type EditorVec3 = { x: number; y: number; z: number } — A world-space point used across editor markers, volumes, and paths.
@@ -166,6 +167,18 @@
166
167
  - `EditorDispatchOptions` (interface): interface EditorDispatchOptions — Per-dispatch options; `coalesce` merges consecutive same-key edits into one undo step.
167
168
  - `EditorSession` (interface): interface EditorSession — Stateful, undoable handle for driving scene edits from UI or an MCP agent.
168
169
  - `EditorSessionState` (interface): interface EditorSessionState — The document plus current selection at a point in editor history.
170
+ - `EditorTransactionResult` (type): type EditorTransactionResult = | { ok: true; state: EditorSessionState; changed: boolean } | { ok: false; error: string; commandIndex?: number } — Atomic command-batch outcome; a failure identifies the zero-based command index.
171
+
172
+ ## @jgengine/core/editor/creatorStorage
173
+
174
+ - `CreatorConfig` (interface): interface CreatorConfig<TPlayable> — Creator configuration shared by a host and its lazily loaded editor.
175
+ - `CreatorDocument` (interface): interface CreatorDocument — A named scene save with a storage-format version and optimistic revision.
176
+ - `CreatorDocumentStorage` (interface): interface CreatorDocumentStorage — Injected durable storage. Save rejects stale revisions; null creates a new id.
177
+ - `CreatorPolicy` (interface): interface CreatorPolicy — Bounds and catalog permissions for player-authored documents.
178
+ - `createCreatorDocumentStorage` (function): function createCreatorDocumentStorage(config: { storage: KeyValueStorage; key: string; policy: CreatorPolicy }): CreatorDocumentStorage — Durable browser-compatible adapter over injected key/value storage; one atomic catalog write.
179
+ - `exportCreatorDocument` (function): function exportCreatorDocument(document: EditorDocument, policy: CreatorPolicy): string — Exports validated, schema-versioned scene JSON.
180
+ - `importCreatorDocument` (function): function importCreatorDocument(json: string, policy: CreatorPolicy): EditorDocument — Imports scene JSON using the same validation as commands and durable saves.
181
+ - `validateCreatorDocument` (function): function validateCreatorDocument(value: unknown, policy: CreatorPolicy): EditorDocument — Validates schema, finite work budgets, and approved catalog references before cloning.
169
182
 
170
183
  ## @jgengine/core/editor/directives
171
184
 
@@ -250,10 +263,10 @@
250
263
 
251
264
  ## @jgengine/core/editor/liveSync
252
265
 
253
- - `ApplyDocumentPatchResult` (type): type ApplyDocumentPatchResult = | { ok: true; document: EditorDocument; revision: number; patch: DocumentPatch } | { ok: false; error: string } — Result of applying a {@link DocumentPatch} to a document + revision pair.
266
+ - `ApplyDocumentPatchResult` (type): type ApplyDocumentPatchResult = | { ok: true; document: EditorDocument; revision: number; patch: DocumentPatch } | { ok: false; error: string; commandIndex?: number } — Result of applying a {@link DocumentPatch} to a document + revision pair.
254
267
  - `DocumentLiveEvent` (interface): interface DocumentLiveEvent — Event emitted when the authoritative document changes on a {@link DocumentLiveSync}.
255
268
  - `DocumentLiveSync` (interface): interface DocumentLiveSync — Two-way live-sync bus: document patches out, runtime state deltas back.
256
- - `DocumentPatch` (type): type DocumentPatch = | { type: "snapshot"; revision?: number; baseRevision: number; document: EditorDocument; } | { type: "commands"; revision?: number; baseRevision: number; commands: readonly EditorCommand[]; } — One versioned document mutation on the live-sync stream. `snapshot` replaces the whole document; `commands` replays structural editor commands onto the current document. `baseRevision` must match the receiver's current revision unless `force` is set (document authority from the editor).
269
+ - `DocumentPatch` (type): type DocumentPatch = | { type: "snapshot"; revision?: number; baseRevision: number; document: EditorDocument; } | { type: "commands"; revision?: number; baseRevision: number; commands: readonly EditorCommand[]; } — One versioned document mutation on the live-sync stream. `snapshot` replaces the whole document; `commands` replays structural editor commands onto the current document. `baseRevision` must match the receiver's current revision unless `force` is set (document authority from the editor). `revision` preserves the authority cursor when replaying: snapshots may jump forward for reconnect recovery; commands must be the next revision.
257
270
  - `RuntimeEntityState` (interface): interface RuntimeEntityState — One live entity row the runtime may stream to the editor (play-mode inspector feed).
258
271
  - `RuntimeStateDelta` (interface): interface RuntimeStateDelta — Incremental runtime state for the reverse channel. Entity rows upsert by id; `removeIds` drop rows; `tunables` shallow-merge. Ephemeral unless written back as a document patch.
259
272
  - `RuntimeStateSnapshot` (interface): interface RuntimeStateSnapshot — Full ephemeral runtime view held on the reverse channel — never mutates the document.
@@ -265,12 +278,38 @@
265
278
  - `runtimeEntityWriteBackCommand` (function): function runtimeEntityWriteBackCommand(document: EditorDocument, entity: RuntimeEntityState): EditorCommand | null — Builds an undoable document command from an ephemeral runtime entity row (write-back). Returns null when there is nothing to promote. Does not mutate document or clear the override — the caller dispatches the command and then clears the override.
266
279
  - `subscribeDocumentLiveSyncInstall` (function): function subscribeDocumentLiveSyncInstall(listener: () => void): () => void — Subscribe to install/uninstall of the global live-sync bus (AuthoredScene re-attaches when the editor host mounts over a running game).
267
280
 
281
+ ## @jgengine/core/editor/materialAuthoring
282
+
283
+ - `authoredMaterialAssignments` (function): function authoredMaterialAssignments(meta: Record<string, unknown> | undefined): MaterialAssignment[] — Read named assignments from authored marker metadata without inferring whole-model overrides.
284
+ - `modelWithAuthoredMaterials` (function): function modelWithAuthoredMaterials(model: ModelConfig | undefined, document: Pick<EditorDocument, "markers" | "materialAssets">, instanceId: string): ModelConfig | undefined — Apply authored references; document assets and selectors override model defaults of the same identity.
285
+ - `parseEditorMaterialAsset` (function): function parseEditorMaterialAsset(value: unknown): MaterialAsset — Validate and copy a material asset at the editor boundary.
286
+
268
287
  ## @jgengine/core/editor/minimap
269
288
 
270
289
  - `DocumentBakeOptions` (interface): interface DocumentBakeOptions extends MinimapBakeOptions — Options for {@link bakeMinimapFromDocument}.
271
290
  - `bakeMinimapFromDocument` (function): function bakeMinimapFromDocument(doc: EditorDocument, sampleHeight: (x: number, z: number) => number, options: DocumentBakeOptions = {}): { background: string; mapBounds: MinimapBakeBounds } — Bakes a minimap image from a scene document plus a terrain height sampler: sizes the footprint to the authored objects (or an explicit `bounds`), tints biome-colored volumes, and rasterizes the terrain top-down. Returns `{ background, mapBounds }` for the `Minimap` props. The editor runs this as its bake action and stores the result on the document.
272
291
  - `documentBakeZones` (function): function documentBakeZones(doc: EditorDocument): MinimapBakeZone[] — The biome-tint zones a document contributes to a bake: every volume carrying a `color` becomes a polygon tint over its footprint. (The optional stretch from #1036 — a bare bake still reads as terrain without any.)
273
292
 
293
+ ## @jgengine/core/editor/modelNodeVisibility
294
+
295
+ - `authoredHiddenNodes` (function): function authoredHiddenNodes(meta: Record<string, unknown> | undefined): readonly string[] | undefined — Read marker visibility metadata; an empty list clears model defaults.
296
+ - `modelWithAuthoredNodeVisibility` (function): function modelWithAuthoredNodeVisibility(model: ModelConfig | undefined, marker: Pick<EditorMarker, "meta"> | undefined): ModelConfig | undefined — Apply a placement's authored visibility without erasing omitted game model defaults.
297
+ - `parseModelHiddenNodes` (function): function parseModelHiddenNodes(value: unknown): readonly string[] | undefined — Validate and copy exact node names; an empty list selects no hidden subtrees.
298
+
299
+ ## @jgengine/core/editor/movementCatalog
300
+
301
+ - `AuthoredMovementBinding` (interface): interface AuthoredMovementBinding — Stable runtime objects whose numeric getters resolve the current authored document.
302
+ - `AuthoredMovementConfig` (interface): interface AuthoredMovementConfig — Only authored values, ready to overlay on a game's existing movement and physics policy.
303
+ - `AuthoredMovementDefaults` (interface): interface AuthoredMovementDefaults — Game-owned callbacks, collision and physics settings retained beneath authored numeric controls.
304
+ - `AuthoredMovementDiagnostic` (interface): interface AuthoredMovementDiagnostic — A persisted movement value rejected before it can replace the game's current setting.
305
+ - `AuthoredMovementResult` (interface): interface AuthoredMovementResult — Valid partial tuning plus located rejected values; absent rows leave game defaults intact.
306
+ - `AuthoredMovementValues` (interface): interface AuthoredMovementValues — Numeric character controls a game elects to author through its own named catalog rows.
307
+ - `MovementCatalogDocumentLike` (interface): interface MovementCatalogDocumentLike — Structural authored catalog input; an immutable EditorDocument satisfies it.
308
+ - `bindAuthoredMovement` (function): function bindAuthoredMovement(read: () => AuthoredMovementResult, defaults: AuthoredMovementDefaults): AuthoredMovementBinding — Binds live authored numeric controls onto stable runtime objects, preserving the game's callbacks, collision, backend and other policy. The movement controller reads these getters each step.
309
+ - `createAuthoredMovementReader` (function): function createAuthoredMovementReader(getDocument: () => MovementCatalogDocumentLike, catalogId: string, entryId: string): () => AuthoredMovementResult — Memoizes movement resolution by immutable document identity; reads the latest document on every call while catalog lookup and diagnostics run only after authoring changes.
310
+ - `createMovementSchema` (function): function createMovementSchema(defaults: AuthoredMovementValues): ParamSchema — Creates editor/RPC controls only for the values a game supplies, with those game's defaults. Gravity retains the game's sign convention; collision height is positive, other controls nonnegative. Jump release is bounded to 0..1; supplied deeper jump controls share a collapsed response group.
311
+ - `readAuthoredMovement` (function): function readAuthoredMovement(document: MovementCatalogDocumentLike, catalogId: string, entryId: string): AuthoredMovementResult — Reads one game-named row as partial runtime tuning, retaining game defaults for omitted or invalid values. Rejected values include their document path and repair; no policy callbacks are replaced.
312
+
274
313
  ## @jgengine/core/editor/runtimeInspector
275
314
 
276
315
  - `RuntimeInspectorGetResult` (interface): interface RuntimeInspectorGetResult — One resolved runtime field returned by `runtime_get`.
@@ -284,6 +323,20 @@
284
323
  - `runtimeEntityMetaWriteBackCommand` (function): function runtimeEntityMetaWriteBackCommand(document: EditorDocument, entity: RuntimeEntityState): EditorCommand | null — Promotes ephemeral runtime `values` into an undoable meta patch on a document-linked object. Returns null when the id is not in the document or there are no values.
285
324
  - `summarizeRuntimeInspector` (function): function summarizeRuntimeInspector(snapshot: RuntimeStateSnapshot, overrides: Readonly<Record<string, RuntimeEntityState>>, play: RuntimePlayControl): RuntimeInspectorSummary — Builds the compact reverse-channel summary used by the play-mode inspector panel and the `runtime_summary` bridge RPC.
286
325
 
326
+ ## @jgengine/core/editor/simulation
327
+
328
+ - `AuthoredEmitter` (interface): interface AuthoredEmitter — A named emitter authored in metres, with game-owned appearance and attachment ids.
329
+ - `AuthoredFireArea` (interface): interface AuthoredFireArea — A bounded fire grid; fuel and damage policy remain game content.
330
+ - `AuthoredFlockHabitat` (interface): interface AuthoredFlockHabitat — An authored habitat selects a game species and optionally follows a document path.
331
+ - `EditorSimulation` (interface): interface EditorSimulation — Authored simulation inputs. Runtime particles, heat, accumulation and actors save separately.
332
+ - `decodeEditorSimulation` (function): function decodeEditorSimulation(value: unknown, document?: Pick<EditorDocument, "paths">): EditorSimulation — Decode authoring inputs with located diagnostics and bounded work before any document mutation.
333
+
334
+ ## @jgengine/core/editor/staticPrefab
335
+
336
+ - `StaticPrefabBake` (interface): interface StaticPrefabBake — Persisted static export settings; source parts remain editable in the prefab fragment.
337
+ - `StaticPrefabBox` (interface): interface StaticPrefabBox — A solid or clearance volume in the prefab's unnormalized local asset space.
338
+ - `parseStaticPrefabBake` (function): function parseStaticPrefabBake(value: unknown): StaticPrefabBake — Validate and copy static prefab export settings from document or RPC input.
339
+
287
340
  ## @jgengine/core/editor/streamer
288
341
 
289
342
  - `StreamUpdate` (interface): interface StreamUpdate — The residency change produced by one {@link WorldStreamer.update}.
@@ -393,13 +446,15 @@
393
446
  - `AssetBrowser` (function): function AssetBrowser({ assets, session, onPlace, }: { assets: readonly EditorAssetEntry[]; session: EditorSession; onPlace: (entry: EditorAssetEntry) => void; }): React.JSX.Element — Searchable panel for placing catalog assets or an empty marker into the scene.
394
447
  - `AssetImporter` (type): type AssetImporter = (file: File) => Promise<StandaloneAsset | null> — Persists a dropped model file through the editor host so it survives reload as a durable catalog asset, returning the host-assigned id/url (which the manifest scan re-lists on reload). Resolves `null` when no host is listening — a plain browser mount with no dev server — so the caller can fall back to a blob URL.
395
448
  - `BlankPlayableOptions` (interface): interface BlankPlayableOptions — Options for the blank, gameless world the standalone editor authors over.
449
+ - `CreatorApp` (function): function CreatorApp({ gameId, config, onExit }: { gameId: string; config: CreatorConfig; onExit: () => void }): React.JSX.Element — Production creator catalog and embedded editor, reached through the game's menu.
450
+ - `CreatorConfig` (type): type CreatorConfig = CoreCreatorConfig<PlayableGame> — Game-owned creator policy, durable storage and document-to-runtime composition.
396
451
  - `DEFAULT_PAINT_SETTINGS` (const): const DEFAULT_PAINT_SETTINGS: PaintSettings — The terrain tool's default paint controls.
397
452
  - `DEFAULT_SCULPT_SETTINGS` (const): const DEFAULT_SCULPT_SETTINGS: SculptSettings — The terrain tool's default brush controls.
398
453
  - `EDITOR_AGENT_KEY_ENV` (const): const EDITOR_AGENT_KEY_ENV: "JGENGINE_EDITOR_AGENT_KEY" — Env var name for the optional Bearer token (`JGENGINE_EDITOR_AGENT_KEY`).
399
454
  - `EDITOR_AGENT_KEY_FALLBACK_ENV` (const): const EDITOR_AGENT_KEY_FALLBACK_ENV: "ANTHROPIC_API_KEY" — Fallback API-key env when `JGENGINE_EDITOR_AGENT_KEY` is unset (`ANTHROPIC_API_KEY`).
400
455
  - `EDITOR_AGENT_URL_ENV` (const): const EDITOR_AGENT_URL_ENV: "JGENGINE_EDITOR_AGENT_URL" — Env var name for the remote agent HTTP URL (`JGENGINE_EDITOR_AGENT_URL`).
401
456
  - `EDITOR_MCP_TOOLS` (const): const EDITOR_MCP_TOOLS: readonly EditorMcpTool[] — Full set of MCP tools an agent can call to drive the live scene editor.
402
- - `EditorApp` (function): function EditorApp({ gameId, playable, layers, catalogs, save, modeChip, networkPresence, onExitEditor }: EditorAppProps): React.JSX.Element — Top-level scene editor: author spawns/zones/paths/notes visually over edit, walk, or play modes.
457
+ - `EditorApp` (function): function EditorApp({ gameId, playable, layers, catalogs, save, modeChip, networkPresence, onExitEditor, createPlaytest, validateDocument, playerCreator, allowedAssets, allowedKinds, maxImportBytes, creatorPolicy }: EditorAppProps): React.JSX.Element — Top-level scene editor: author spawns/zones/paths/notes visually over edit, walk, or play modes.
403
458
  - `EditorAppProps` (interface): interface EditorAppProps — Props for mounting the scene editor over a playable game.
404
459
  - `EditorAssetEntry` (interface): interface EditorAssetEntry — A searchable, placeable asset shown in the editor's asset browser panel.
405
460
  - `EditorAssetInfo` (interface): interface EditorAssetInfo — A placeable asset entry offered in the editor's asset browser.
@@ -408,9 +463,12 @@
408
463
  - `EditorBridgeServer` (interface): interface EditorBridgeServer — A running editor bridge server: its bound port, URL, and a stop handle.
409
464
  - `EditorBridgeServerOptions` (interface): interface EditorBridgeServerOptions — Options for starting the editor's HTTP bridge server: host api, port, hostname.
410
465
  - `EditorCameraDriver` (const): const EditorCameraDriver: React.MemoExoticComponent<({ api }: { api: EditorHostApi; }) => null> — Drives the editor orbit camera from the host's focus target. When the target carries only a point, the camera pans to keep it centered (the historical behavior). When it also carries placement (`distance`/`pitch`/`yaw`/`height`), the camera is repositioned to that orbit pose — how `camera_goto`/`camera_frame` compose an aerial without the KeyF-buries-in-terrain problem.
411
- - `EditorChrome` (function): function EditorChrome({ gameId, session, api, assets, ui, baselineDocument, save, networkSnapshot, importAsset = importAssetToHost, onRegisterAsset, onExitEditor, }: { gameId: string; session: EditorSession; api: EditorHostApi; assets: readonly EditorAssetEntry[]; ui: EditorUiStore; /** The document… — The full editor UI shell — global app bar, contextual scene toolbar, workspace rail, resizable hierarchy/inspector docks, tabbed bottom dock (content browser, console, profiler, AI assistant), viewport overlays, and status bar — wired to the session, UI store, layout store, and host RPC. Mounted by `EditorApp`; not a game-author entry point.
466
+ - `EditorChrome` (function): function EditorChrome({ gameId, session, api, assets, ui, baselineDocument, save, networkSnapshot, importAsset = importAssetToHost, onRegisterAsset, onExitEditor, allowedKinds, exitLabel, maxImportBytes, documentSave, draftAutosave = true, creatorPolicy, }: { gameId: string; session: EditorSession; … — The full editor UI shell — global app bar, contextual scene toolbar, workspace rail, resizable hierarchy/inspector docks, tabbed bottom dock (content browser, console, profiler, AI assistant), viewport overlays, and status bar — wired to the session, UI store, layout store, and host RPC. Mounted by `EditorApp`; not a game-author entry point.
412
467
  - `EditorHostApi` (interface): interface EditorHostApi — The live editor's global control surface — session, visibility, camera focus, assets, mode, RPC.
413
468
  - `EditorLayerOverlays` (function): function EditorLayerOverlays({ document, visibility, selection, hoverId = null, onSelect, activePathPoint, groundHeightAt, }: { document: EditorDocument; visibility: EditorKindVisibility; selection: readonly string[]; /** Pre-selection hover id from viewport pointer pick; ignored when already select… — Renders every visible marker, volume, path, and note from a document as in-scene 3D gizmos.
469
+ - `EditorMaterialSlotInfo` (type): type EditorMaterialSlotInfo = Readonly<Omit<ModelMaterialSlotInfo, "uvSets">> & { readonly uvSets: readonly number[] } — Canonical imported slot names and mesh prerequisites reported by the loaded model.
470
+ - `EditorMaterialSlotInventory` (type): type EditorMaterialSlotInventory = EditorMaterialSlotReport & { id: string; sourceUrl?: string } — A marker's current imported-model inventory, including an explicit availability state.
471
+ - `EditorMaterialSlotReport` (type): type EditorMaterialSlotReport = | { status: "ready"; slots: readonly EditorMaterialSlotInfo[] } | { status: "loading" } | { status: "unavailable"; reason: string } — A live model-source observation; loading and unavailable reports never contain fabricated slots.
414
472
  - `EditorMcpTool` (interface): interface EditorMcpTool — One MCP tool descriptor — same verbs as the in-browser host RPC.
415
473
  - `EditorNetworkAdapterKind` (type): type EditorNetworkAdapterKind = MultiplayerAdapterConfig["kind"] | "unknown" — Transport kind declared by the game, or `"unknown"` when the config is unreadable.
416
474
  - `EditorNetworkPresenceActor` (interface): interface EditorNetworkPresenceActor — One online actor from a host-supplied presence feed. Fields mirror {@link PresencePoseRow} so hosts can forward backend rows without inventing shape.
@@ -469,6 +527,11 @@
469
527
  - `MATERIAL_DRAG_MIME` (const): const MATERIAL_DRAG_MIME: "application/x-jgengine-material" — Custom drag mime carrying a material id — read by hierarchy rows and the viewport drop zone.
470
528
  - `assetsFromCatalog` (function): function assetsFromCatalog(ids: readonly string[], resolve?: (id: string) => { url?: string; clips?: readonly string[] } | null): EditorAssetEntry[] — Turns a game's asset catalog ids into editor asset entries for the browser panel.
471
529
 
530
+ ## @jgengine/editor/CreatorApp
531
+
532
+ - `CreatorApp` (function): function CreatorApp({ gameId, config, onExit }: { gameId: string; config: CreatorConfig; onExit: () => void }): React.JSX.Element — Production creator catalog and embedded editor, reached through the game's menu.
533
+ - `CreatorConfig` (type): type CreatorConfig = CoreCreatorConfig<PlayableGame> — Game-owned creator policy, durable storage and document-to-runtime composition.
534
+
472
535
  ## @jgengine/editor/DebugDraw
473
536
 
474
537
  - `EditorLayerOverlays` (function): function EditorLayerOverlays({ document, visibility, selection, hoverId = null, onSelect, activePathPoint, groundHeightAt, }: { document: EditorDocument; visibility: EditorKindVisibility; selection: readonly string[]; /** Pre-selection hover id from viewport pointer pick; ignored when already select… — Renders every visible marker, volume, path, and note from a document as in-scene 3D gizmos.
@@ -476,7 +539,7 @@
476
539
 
477
540
  ## @jgengine/editor/EditorApp
478
541
 
479
- - `EditorApp` (function): function EditorApp({ gameId, playable, layers, catalogs, save, modeChip, networkPresence, onExitEditor }: EditorAppProps): React.JSX.Element — Top-level scene editor: author spawns/zones/paths/notes visually over edit, walk, or play modes.
542
+ - `EditorApp` (function): function EditorApp({ gameId, playable, layers, catalogs, save, modeChip, networkPresence, onExitEditor, createPlaytest, validateDocument, playerCreator, allowedAssets, allowedKinds, maxImportBytes, creatorPolicy }: EditorAppProps): React.JSX.Element — Top-level scene editor: author spawns/zones/paths/notes visually over edit, walk, or play modes.
480
543
  - `EditorAppProps` (interface): interface EditorAppProps — Props for mounting the scene editor over a playable game.
481
544
  - `EditorSaveFn` (type): type EditorSaveFn = (json: string) => Promise<{ ok: boolean; path?: string; error?: string }> — Persists an exported document JSON; resolves with where it landed or why it failed.
482
545
 
@@ -486,7 +549,11 @@
486
549
 
487
550
  ## @jgengine/editor/EditorChrome
488
551
 
489
- - `EditorChrome` (function): function EditorChrome({ gameId, session, api, assets, ui, baselineDocument, save, networkSnapshot, importAsset = importAssetToHost, onRegisterAsset, onExitEditor, }: { gameId: string; session: EditorSession; api: EditorHostApi; assets: readonly EditorAssetEntry[]; ui: EditorUiStore; /** The document… — The full editor UI shell — global app bar, contextual scene toolbar, workspace rail, resizable hierarchy/inspector docks, tabbed bottom dock (content browser, console, profiler, AI assistant), viewport overlays, and status bar — wired to the session, UI store, layout store, and host RPC. Mounted by `EditorApp`; not a game-author entry point.
552
+ - `EditorChrome` (function): function EditorChrome({ gameId, session, api, assets, ui, baselineDocument, save, networkSnapshot, importAsset = importAssetToHost, onRegisterAsset, onExitEditor, allowedKinds, exitLabel, maxImportBytes, documentSave, draftAutosave = true, creatorPolicy, }: { gameId: string; session: EditorSession; … — The full editor UI shell — global app bar, contextual scene toolbar, workspace rail, resizable hierarchy/inspector docks, tabbed bottom dock (content browser, console, profiler, AI assistant), viewport overlays, and status bar — wired to the session, UI store, layout store, and host RPC. Mounted by `EditorApp`; not a game-author entry point.
553
+
554
+ ## @jgengine/editor/MaterialAssetEditor
555
+
556
+ - `MaterialAssetEditorProps` (interface): interface MaterialAssetEditorProps — A callback-driven physical material editor; the host owns persistence, undo and preview rendering.
490
557
 
491
558
  ## @jgengine/editor/PerfProbe
492
559
 
@@ -502,6 +569,10 @@
502
569
  - `SelectionGizmo` (const): const SelectionGizmo: React.MemoExoticComponent<({ session, ui, groundSnap, }: { session: EditorSession; ui: EditorUiStore; groundSnap?: ((x: number, z: number) => number) | undefined; }) => React.JSX.Element | null> — Drag-to-transform gizmo bound to the current selection, dispatching editor commands on release. Mounts the shared shell `TransformGizmo` and maps release poses onto editor commands (multi-select translate, volume scale, path vertex move).
503
570
  - `ViewportSelect` (const): const ViewportSelect: React.MemoExoticComponent<({ api, ui }: { api: EditorHostApi; ui: EditorUiStore; }) => null> — Canvas click-to-select and click-to-place. Document objects pick by screen proximity (registration always matches what you see) with click-cycling through stacked candidates and shift/ctrl additive selection; everything else picks by occlusion-ordered raycast against the tagged scene graph. When a placement tool is armed, clicks author new markers, volumes, notes, or path points at the ground hit instead of selecting.
504
571
 
572
+ ## @jgengine/editor/SimulationInspector
573
+
574
+ - `SimulationInspector` (function): function SimulationInspector({ session, creatorPolicy }: { session: EditorSession; creatorPolicy?: CreatorPolicy }): React.JSX.Element — Production authoring controls share the same validated command and undo history as RPC.
575
+
505
576
  ## @jgengine/editor/StandaloneEditor
506
577
 
507
578
  - `AssetImporter` (type): type AssetImporter = (file: File) => Promise<StandaloneAsset | null> — Persists a dropped model file through the editor host so it survives reload as a durable catalog asset, returning the host-assigned id/url (which the manifest scan re-lists on reload). Resolves `null` when no host is listening — a plain browser mount with no dev server — so the caller can fall back to a blob URL.
@@ -620,7 +691,7 @@
620
691
 
621
692
  ## @jgengine/editor/handlers/hierarchy
622
693
 
623
- - `hierarchyHandlers` (const): const hierarchyHandlers: Pick< HandlerTable, | "set_parent" | "hierarchy" | "list_prefabs" | "create_prefab" | "insert_prefab" | "detach_prefab_instance" | "delete_prefab" > — Parent/child hierarchy and prefab library verbs.
694
+ - `hierarchyHandlers` (const): const hierarchyHandlers: Pick< HandlerTable, | "set_parent" | "hierarchy" | "list_prefabs" | "create_prefab" | "insert_prefab" | "detach_prefab_instance" | "delete_prefab" | "set_prefab_static_bake" > — Parent/child hierarchy and prefab library verbs.
624
695
 
625
696
  ## @jgengine/editor/handlers/minimap
626
697
 
@@ -629,6 +700,7 @@
629
700
  ## @jgengine/editor/handlers/navmesh
630
701
 
631
702
  - `navMeshHandlers` (const): const navMeshHandlers: Pick<HandlerTable, "bakeNavMesh"> — Bake caller-provided indexed geometry into a named document navigation mesh.
703
+ - `warmNavBake` (function): function warmNavBake(): void — Start loading the recast module so the first bake request does not have to wait.
632
704
 
633
705
  ## @jgengine/editor/handlers/runtime
634
706
 
@@ -655,6 +727,14 @@
655
727
  - `MaterialDocumentSlice` (interface): interface MaterialDocumentSlice — Minimal document slice the materials inventory needs.
656
728
  - `MaterialObjectKind` (type): type MaterialObjectKind = "marker" | "volume" | "path" — Document-wide material assignment inventory for the Materials workspace. Reads real `meta.materialId` stamps from placeables — no thumbnails or faked previews.
657
729
 
730
+ ## @jgengine/editor/materialControls
731
+
732
+ - `MaterialControl` (interface): interface MaterialControl — One physical surface field in the material workspace.
733
+ - `MaterialControlGroup` (interface): interface MaterialControlGroup — A family-specific group of primary controls; maps and full physical fields remain available.
734
+ - `advancedMaterialControls` (const): const advancedMaterialControls: readonly MaterialControl[] — Complete supported physical scalar/color fields, independent of the six primary groups.
735
+ - `materialAuthoringNotes` (function): function materialAuthoringNotes(asset: MaterialAsset): readonly string[] — Reports geometry prerequisites and renderer approximations to authors.
736
+ - `materialControlGroups` (function): function materialControlGroups(family: MaterialFamily): readonly MaterialControlGroup[] — Returns six primary groups suited to the material family without hiding the physical model.
737
+
658
738
  ## @jgengine/editor/mcp/bridgeServer
659
739
 
660
740
  - `EditorBridgeServer` (interface): interface EditorBridgeServer — A running editor bridge server: its bound port, URL, and a stop handle.
@@ -671,7 +751,7 @@
671
751
 
672
752
  ## @jgengine/editor/mcp/fieldSpec
673
753
 
674
- - `RPC_FIELD_SCHEMAS` (const): const RPC_FIELD_SCHEMAS: Record<EditorBridgeRequest["method"], readonly RpcFieldSpec[]> — Per-method field type table — the single source of truth for the RPC boundary. A field listed here is type-checked when present (see `decodeEditorBridgeRequest`); existence is left to `EditorHostApi.handle` (whose per-method guards return honest `ok:false` diagnostics for missing/unknown targets). Type-checking presented fields is what keeps a fuzzed value — a string where a number belongs, a scalar where an object belongs — from reaching a live session uncoerced. Unknown extra fields are ignored so a superset payload stays forward-compatible.
754
+ - `RPC_FIELD_SCHEMAS` (const): const RPC_FIELD_SCHEMAS: Record<EditorBridgeRequest["method"], readonly RpcFieldSpec[]> — Per-method field type table — the single source of truth for the RPC boundary. A field listed here is type-checked when present (see `decodeEditorBridgeRequest`); existence is left to `EditorHostApi.handle` (whose per-method guards return honest `ok:false` diagnostics for missing/unknown targets). Type-checking presented fields is what keeps a fuzzed value — a string where a number belongs, a scalar where an object belongs — from reaching a live session uncoerced. Undeclared top-level fields are rejected by the decoder for every method.
675
755
  - `RpcFieldKind` (type): type RpcFieldKind = "string" | "number" | "boolean" | "string[]" | "object" | "object[]" | "vec3" | "value" — The value type a request field is expected to carry.
676
756
  - `RpcFieldSpec` (interface): interface RpcFieldSpec — One field's expected shape in a request; `oneOf`/`nullable`/`required`/`of` refine the check.
677
757
  - `buildInputSchema` (function): function buildInputSchema(method: EditorBridgeRequest["method"]): Record<string, unknown> — Generates the MCP tool `inputSchema` for a method from its {@link RPC_FIELD_SCHEMAS} entry.
@@ -695,7 +775,7 @@
695
775
 
696
776
  - `DecodeRpcRequestResult` (type): type DecodeRpcRequestResult = | { ok: true; request: EditorBridgeRequest } | { ok: false; errors: RpcRequestDiagnostic[] } — Result of {@link decodeEditorBridgeRequest}: a request whose `method` is a real one, or the diagnostic that rejected it.
697
777
  - `RpcRequestDiagnostic` (interface): interface RpcRequestDiagnostic — One field-level failure surfaced while decoding an untrusted RPC request.
698
- - `decodeEditorBridgeRequest` (function): function decodeEditorBridgeRequest(raw: unknown): DecodeRpcRequestResult — Validates an untrusted JSON-decoded RPC payload (from `--rpc`, the HTTP bridge, or an agent tool call) before it reaches `EditorHostApi.handle`: confirms it is a plain object carrying a known `method`, then type-checks every field the method understands against {@link RPC_FIELD_SCHEMAS}. A garbled method, or a field whose value is the wrong type (a string where a number belongs, a scalar where an object belongs), is rejected here with a path-specific diagnostic instead of flowing into a live session on a blind cast. Missing fields and unknown extra fields are left for `handle` to interpret so the boundary stays forward-compatible.
778
+ - `decodeEditorBridgeRequest` (function): function decodeEditorBridgeRequest(raw: unknown): DecodeRpcRequestResult — Validates an untrusted JSON-decoded RPC payload (from `--rpc`, the HTTP bridge, or an agent tool call) before it reaches `EditorHostApi.handle`: confirms it is a plain object carrying a known `method`, then type-checks every field the method understands against {@link RPC_FIELD_SCHEMAS}. A garbled method, or a field whose value is the wrong type (a string where a number belongs, a scalar where an object belongs), or an undeclared field is rejected here with a path-specific diagnostic instead of flowing into a live session on a blind cast. Missing fields are left for `handle` to interpret.
699
779
 
700
780
  ## @jgengine/editor/mcp/stdioServer
701
781
 
@@ -708,6 +788,7 @@
708
788
 
709
789
  ## @jgengine/editor/modelAnimationAuthoring
710
790
 
791
+ - `AnimGraphSource` (type): type AnimGraphSource = "authored" | "locomotion" | "auto" — Where the graph a placement plays comes from.
711
792
  - `AnimationMode` (type): type AnimationMode = "default" | "auto" | "none" | "custom" — Which authoring mode a stored setting represents. `default` = no override key.
712
793
  - `AnimationSetting` (type): type AnimationSetting = AuthoredAnimationConfig | "auto" | "none" — The value stored at `meta.animation`.
713
794
  - `AuthoredAnimationConfig` (interface): interface AuthoredAnimationConfig — Structurally compatible with `ModelAnimationConfig`, but every field optional for authoring.
@@ -719,12 +800,16 @@
719
800
  - `OneShotEvent` (type): type OneShotEvent = (typeof ONE_SHOT_EVENTS)[number] — One-shot animation event a placement can bind a clip to (attack/hit/death/...).
720
801
  - `animationMetaPatch` (function): function animationMetaPatch(setting: AnimationSetting | undefined): { animation: AnimationSetting | undefined } — The meta patch that persists a setting (or clears the override when undefined). Shallow-merges onto `marker.meta` via `setMarker`; an undefined value drops out of the saved JSON document.
721
802
  - `animationMode` (function): function animationMode(setting: AnimationSetting | undefined): AnimationMode — The authoring mode a stored setting maps to.
803
+ - `clearAnimGraph` (function): function clearAnimGraph(setting: AnimationSetting | undefined): AnimationSetting | undefined — Removes a stored graph so `states`/`oneShots` (or clip roles) drive the placement again.
722
804
  - `defaultCustomConfig` (function): function defaultCustomConfig(clips: readonly string[]): AuthoredAnimationConfig — A concrete custom config derived from a rigged asset's clip roles — the `custom` mode seed.
723
- - `readAnimationSetting` (function): function readAnimationSetting(meta: Record<string, unknown> | undefined): AnimationSetting | undefined — Reads and shape-validates the animation override from a marker's meta; undefined when absent/invalid.
805
+ - `effectiveAnimGraph` (function): function effectiveAnimGraph(setting: AnimationSetting | undefined, clips: readonly string[]): { graph: AnimGraph; source: AnimGraphSource } | null — The graph a placement plays at run time: its stored `graph`, else the locomotion graph of its custom `states`/`oneShots`, else the one clip roles derive for `"auto"` and no-override placements. `null` for `"none"`, a single-clip config, or a rig whose clips have no idle.
806
+ - `readAnimationSetting` (function): function readAnimationSetting(meta: Record<string, unknown> | undefined): AnimationSetting | undefined — Reads a whole valid override, retaining authored fields; malformed values return undefined.
724
807
  - `setAnimationMode` (function): function setAnimationMode(setting: AnimationSetting | undefined, mode: AnimationMode, clips: readonly string[] = []): AnimationSetting | undefined — Switches authoring mode. `custom` seeds from the asset's clip-role defaults (so the user starts from a working config, then overrides) when there is no existing object config; the other modes are the bare string/undefined values.
725
- - `setLocomotionClip` (function): function setLocomotionClip(setting: AnimationSetting | undefined, role: LocomotionRole, clipName: string | null): AuthoredAnimationConfig — Sets or clears (null) a locomotion state clip; forces the setting into `custom`.
726
- - `setLocomotionNumber` (function): function setLocomotionNumber(setting: AnimationSetting | undefined, key: LocomotionNumber, value: number | null): AuthoredAnimationConfig — Sets or clears (null) a numeric locomotion tuning.
727
- - `setOneShotClip` (function): function setOneShotClip(setting: AnimationSetting | undefined, event: string, clipName: string | null): AuthoredAnimationConfig — Binds or clears (null) a one-shot event to a clip.
808
+ - `setLocomotionClip` (function): function setLocomotionClip(setting: AnimationSetting | undefined, role: LocomotionRole, clipName: string | null, clips: readonly string[] = []): AuthoredAnimationConfig — Sets or clears (null) a locomotion state clip; forces the setting into `custom`.
809
+ - `setLocomotionNumber` (function): function setLocomotionNumber(setting: AnimationSetting | undefined, key: LocomotionNumber, value: number | null, clips: readonly string[] = []): AuthoredAnimationConfig — Sets or clears (null) a numeric locomotion tuning.
810
+ - `setOneShotClip` (function): function setOneShotClip(setting: AnimationSetting | undefined, event: string, clipName: string | readonly string[] | null): AuthoredAnimationConfig — Binds or clears (null) a one-shot event's clip or variant list.
811
+ - `setTransitionDuration` (function): function setTransitionDuration(setting: AnimationSetting | undefined, graph: AnimGraph, layerId: string, index: number, duration: number): AuthoredAnimationConfig — Sets one transition's crossfade seconds in `graph` and stores the result, so editing a derived graph turns it into an authored one.
812
+ - `storeAnimGraph` (function): function storeAnimGraph(setting: AnimationSetting | undefined, graph: AnimGraph): AuthoredAnimationConfig — Stores `graph` on the placement, keeping its other fields; the stored graph wins at play time.
728
813
 
729
814
  ## @jgengine/editor/networkSnapshot
730
815
 
@@ -762,6 +847,9 @@
762
847
  - `EditorFocusTarget` (interface): interface EditorFocusTarget — Where the editor orbit camera looks, plus optional placement so a single `camera_goto`/ `camera_frame` can compose an aerial. `x/y/z` is the orbit target (pan-only when that is all that is set — the historical behavior); `distance`, `pitch` (degrees above the horizon), `yaw` (degrees), and `height` reposition the camera around that target when provided.
763
848
  - `EditorHostApi` (interface): interface EditorHostApi — The live editor's global control surface — session, visibility, camera focus, assets, mode, RPC.
764
849
  - `EditorKindVisibility` (interface): interface EditorKindVisibility — Per-kind show/hide flags for the editor's layer panel.
850
+ - `EditorMaterialSlotInfo` (type): type EditorMaterialSlotInfo = Readonly<Omit<ModelMaterialSlotInfo, "uvSets">> & { readonly uvSets: readonly number[] } — Canonical imported slot names and mesh prerequisites reported by the loaded model.
851
+ - `EditorMaterialSlotInventory` (type): type EditorMaterialSlotInventory = EditorMaterialSlotReport & { id: string; sourceUrl?: string } — A marker's current imported-model inventory, including an explicit availability state.
852
+ - `EditorMaterialSlotReport` (type): type EditorMaterialSlotReport = | { status: "ready"; slots: readonly EditorMaterialSlotInfo[] } | { status: "loading" } | { status: "unavailable"; reason: string } — A live model-source observation; loading and unavailable reports never contain fabricated slots.
765
853
  - `EditorPerfSample` (interface): interface EditorPerfSample — Rolling frame-rate sample published by the in-canvas PerfProbe.
766
854
  - `EditorRunMode` (type): type EditorRunMode = "edit" | "walk" | "play" | "hud" — How the editor hosts the game: frozen placement view, roamable world, the real game, or HUD-layout authoring.
767
855
  - `EditorSession` (interface): interface EditorSession — Stateful, undoable handle for driving scene edits from UI or an MCP agent.
@@ -806,7 +894,7 @@
806
894
 
807
895
  ## @jgengine/editor/shell/TopAppBar
808
896
 
809
- - `TopAppBar` (function): function TopAppBar({ gameId, onExitToGame, dirty, saveState, lastSavedAt = null, saveAvailable, saveError, canUndo, canRedo, onUndo, onRedo, onSave, onPlay, onWalk, onHud, onImport, onExport, onCopyJson, onOpenPalette, onToggleHelp, onResetLayout, }: { gameId: string; /** When set (editor summoned o… — Global application bar: identity + save state on the left, command palette in the center, history / run controls / document actions on the right. Pause and Step stay disabled in edit mode; Play mode mounts {@link PlayModeBar}, which wires the same controls to the runtime pause/step RPCs so mode switches keep shell chrome.
897
+ - `TopAppBar` (function): function TopAppBar({ gameId, onExitToGame, exitLabel = "Exit to game", dirty, saveState, lastSavedAt = null, saveAvailable, saveError, canUndo, canRedo, onUndo, onRedo, onSave, onPlay, onWalk, onHud, onImport, onExport, onCopyJson, onOpenPalette, onToggleHelp, onResetLayout, }: { gameId: string; /**… — Global application bar: identity + save state on the left, command palette in the center, history / run controls / document actions on the right. Pause and Step stay disabled in edit mode; Play mode mounts {@link PlayModeBar}, which wires the same controls to the runtime pause/step RPCs so mode switches keep shell chrome.
810
898
  - `TopBarSaveState` (type): type TopBarSaveState = "idle" | "saving" | "saved" | "error" — Document save lifecycle mirrored from `useDocumentSave`.
811
899
 
812
900
  ## @jgengine/editor/shell/ViewportOverlays
@@ -820,6 +908,18 @@
820
908
  - `WORKSPACES` (const): const WORKSPACES: readonly RailEntry[] — Rail order and support map. Unsupported modes are visible but disabled — never fake panels.
821
909
  - `WorkspaceRail` (function): function WorkspaceRail({ active, onSelect, }: { active: EditorWorkspace; onSelect: (workspace: EditorWorkspace) => void; }): React.JSX.Element — Narrow left workspace rail. Supported modes activate their home panels; planned modes are disabled with an explanatory tooltip so nothing pretends to work.
822
910
 
911
+ ## @jgengine/editor/shell/animGraphPreview
912
+
913
+ - `GraphParamControl` (interface): interface GraphParamControl — A parameter the preview needs a control for: blend inputs and condition operands.
914
+ - `GraphPreviewFrame` (interface): interface GraphPreviewFrame — What the rig shows at the scrub time.
915
+ - `GraphPreviewInput` (interface): interface GraphPreviewInput — Inputs for {@link simulateGraphPreview}.
916
+ - `MAX_PREVIEW_SECONDS` (const): const MAX_PREVIEW_SECONDS: 20 — Longest preview timeline the scrubber offers, in seconds.
917
+ - `graphClipNames` (function): function graphClipNames(graph: AnimGraph): string[] — Every clip name a graph plays.
918
+ - `graphParamControls` (function): function graphParamControls(graph: AnimGraph): GraphParamControl[] — Parameters a graph reads, with a range covering its blend points and condition values.
919
+ - `graphTriggers` (function): function graphTriggers(graph: AnimGraph): string[] — Every trigger name a graph's transitions listen for, in first-seen order.
920
+ - `recordTrigger` (function): function recordTrigger(triggers: readonly GraphPreviewTrigger[], name: string, at: number): GraphPreviewTrigger[] — Adds a trigger press at `at`, keeping the log in time order.
921
+ - `simulateGraphPreview` (function): function simulateGraphPreview(input: GraphPreviewInput): GraphPreviewFrame — Replays `graph` from its entry states to `time` and reports the pose there.
922
+
823
923
  ## @jgengine/editor/shell/cameraTelemetry
824
924
 
825
925
  - `CameraTelemetry` (interface): interface CameraTelemetry — Per-frame camera orientation channel between the in-canvas probe and the DOM orientation widget. Deliberately a mutable record, not React state: the probe writes every frame and the widget reads on its own rAF loop, applying styles directly — zero shell rerenders.
@@ -969,6 +1069,10 @@
969
1069
  - `createEditorUiStore` (function): function createEditorUiStore(): EditorUiStore — Creates the shared UI store the editor chrome and viewport both drive.
970
1070
  - `newPlacementId` (function): function newPlacementId(prefix: string): string — Generates a fresh scene-object id for a placement tool click.
971
1071
 
1072
+ ## @jgengine/editor/useDocumentSave
1073
+
1074
+ - `EditorDocumentSave` (interface): interface EditorDocumentSave — Document save lifecycle owned by the mounted authoring session, across viewport modes.
1075
+
972
1076
  ## @jgengine/editor/useF2Chord
973
1077
 
974
1078
  - `useF2Chord` (function): function useF2Chord(code: string, onChord: () => void): void — Listens for the engine's F2+<key> chord family and fires on the given code (e.g. "KeyE").
@@ -4,6 +4,18 @@
4
4
 
5
5
  Reach for these before hand-rolling. Each row is *the thing you need* → *the primitive that already does it*.
6
6
 
7
+ ## authored-material-slots — read validated material assignments from editor marker metadata
8
+
9
+ - `authoredMaterialAssignments` (function) · `import { authoredMaterialAssignments } from "@jgengine/core/editor/materialAuthoring"`
10
+
11
+ ## creator-export — export validated player scenes with approved catalogs and finite budgets
12
+
13
+ - `exportCreatorDocument` (function) · `import { exportCreatorDocument } from "@jgengine/core/editor/creatorStorage"`
14
+
15
+ ## creator-storage — save and reopen named versioned player creations through injected durable storage
16
+
17
+ - `createCreatorDocumentStorage` (function) · `import { createCreatorDocumentStorage } from "@jgengine/core/editor/creatorStorage"`
18
+
7
19
  ## editor-catalogs — Persist gameplay tuning rows on the scene document.
8
20
 
9
21
  - `EditorCatalogData` (interface) · `import { EditorCatalogData } from "@jgengine/core/editor"`
@@ -68,6 +80,18 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
68
80
  - `createDocumentLiveSync` (function) · `import { createDocumentLiveSync } from "@jgengine/core/editor"`
69
81
  - `runtimeEntityWriteBackCommand` (function) · `import { runtimeEntityWriteBackCommand } from "@jgengine/core/editor"`
70
82
 
83
+ ## editor-material-controls — Explain geometry prerequisites and approximations for a material asset.
84
+
85
+ - `materialAuthoringNotes` (function) · `import { materialAuthoringNotes } from "@jgengine/editor/materialControls"`
86
+ - `materialControlGroups` (function) · `import { materialControlGroups } from "@jgengine/editor/materialControls"`
87
+
88
+ ## editor-movement — bind live character tuning while preserving distinctive game policy
89
+
90
+ - `bindAuthoredMovement` (function) · `import { bindAuthoredMovement } from "@jgengine/core/editor/movementCatalog"`
91
+ - `createAuthoredMovementReader` (function) · `import { createAuthoredMovementReader } from "@jgengine/core/editor/movementCatalog"`
92
+ - `createMovementSchema` (function) · `import { createMovementSchema } from "@jgengine/core/editor/movementCatalog"`
93
+ - `readAuthoredMovement` (function) · `import { readAuthoredMovement } from "@jgengine/core/editor/movementCatalog"`
94
+
71
95
  ## editor-runtime-inspector — gate a play-mode frame against pause/step control
72
96
 
73
97
  - `consumeRuntimePlayStep` (function) · `import { consumeRuntimePlayStep } from "@jgengine/core/editor"`
@@ -82,6 +106,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
82
106
  - `bakeMinimapFromDocument` (function) · `import { bakeMinimapFromDocument } from "@jgengine/core/editor"`
83
107
  - `documentBakeZones` (function) · `import { documentBakeZones } from "@jgengine/core/editor"`
84
108
 
109
+ ## model-node-visibility — read authored per-placement model subtree selections
110
+
111
+ - `authoredHiddenNodes` (function) · `import { authoredHiddenNodes } from "@jgengine/core/editor/modelNodeVisibility"`
112
+
113
+ ## player-creator — create, edit, save, playtest and reopen bounded player scenes through the production editor
114
+
115
+ - `CreatorApp` (function) · `import { CreatorApp } from "@jgengine/editor"`
116
+
85
117
  ## scene-ownership — audit a whole ownership manifest for boundary violations
86
118
 
87
119
  - `auditManifest` (function) · `import { auditManifest } from "@jgengine/core/scene/sceneOwnership"`
@@ -90,6 +122,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
90
122
  - `isSceneOwnershipManifest` (function) · `import { isSceneOwnershipManifest } from "@jgengine/core/scene/sceneOwnership"`
91
123
  - `ownershipKey` (function) · `import { ownershipKey } from "@jgengine/core/scene/sceneOwnership"`
92
124
 
125
+ ## simulation-inspector — author weather schedules, effects, fire, wind zones, forces and habitats with validated undoable controls
126
+
127
+ - `SimulationInspector` (function) · `import { SimulationInspector } from "@jgengine/editor/SimulationInspector"`
128
+
129
+ ## validate-simulation — diagnose authored weather, effect, fire, force and habitat documents before publication
130
+
131
+ - `decodeEditorSimulation` (function) · `import { decodeEditorSimulation } from "@jgengine/core/editor/simulation"`
132
+
93
133
  ## world-convergence — derive environment coordinate content from the scene document
94
134
 
95
135
  - `environmentContentFromDocument` (function) · `import { environmentContentFromDocument } from "@jgengine/core/editor"`