@jgengine/editor 0.11.0 → 0.13.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 (171) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +12 -0
  3. package/dist/AssetBrowser.d.ts +33 -1
  4. package/dist/AssetBrowser.js +64 -2
  5. package/dist/AssetDropZone.d.ts +9 -0
  6. package/dist/AssetDropZone.js +65 -0
  7. package/dist/CatalogsPanel.d.ts +4 -2
  8. package/dist/CatalogsPanel.js +162 -9
  9. package/dist/CityPreview.d.ts +11 -0
  10. package/dist/CityPreview.js +45 -0
  11. package/dist/CollectionsPanel.js +5 -5
  12. package/dist/DebugDraw.d.ts +3 -1
  13. package/dist/DebugDraw.js +37 -19
  14. package/dist/EditorApp.d.ts +15 -1
  15. package/dist/EditorApp.js +147 -35
  16. package/dist/EditorChrome.d.ts +27 -6
  17. package/dist/EditorChrome.js +314 -130
  18. package/dist/InspectorPanel.d.ts +17 -7
  19. package/dist/InspectorPanel.js +173 -27
  20. package/dist/LightingPanel.d.ts +11 -0
  21. package/dist/LightingPanel.js +99 -0
  22. package/dist/MaterialsWorkspacePanel.d.ts +12 -0
  23. package/dist/MaterialsWorkspacePanel.js +86 -0
  24. package/dist/ParentPickerMenu.d.ts +13 -0
  25. package/dist/ParentPickerMenu.js +33 -0
  26. package/dist/PerfProbe.js +33 -0
  27. package/dist/PrefabsPanel.js +5 -5
  28. package/dist/RuntimePlayBridge.d.ts +5 -3
  29. package/dist/RuntimePlayBridge.js +6 -13
  30. package/dist/ScatterPreview.d.ts +3 -1
  31. package/dist/ScatterPreview.js +10 -7
  32. package/dist/SchemaInspector.js +21 -8
  33. package/dist/ScriptingPanel.d.ts +15 -0
  34. package/dist/ScriptingPanel.js +46 -0
  35. package/dist/SelectionGizmo.js +114 -30
  36. package/dist/StandaloneEditor.d.ts +16 -9
  37. package/dist/StandaloneEditor.js +19 -20
  38. package/dist/TerrainPanel.d.ts +3 -2
  39. package/dist/TerrainPanel.js +16 -5
  40. package/dist/TerrainSculpt.js +98 -59
  41. package/dist/agent/AgentPanel.d.ts +5 -2
  42. package/dist/agent/AgentPanel.js +11 -6
  43. package/dist/agent/toolBridge.js +5 -0
  44. package/dist/assetImport.d.ts +36 -0
  45. package/dist/assetImport.js +66 -0
  46. package/dist/authoredComponentMeta.d.ts +25 -0
  47. package/dist/authoredComponentMeta.js +65 -0
  48. package/dist/gizmoPivot.d.ts +4 -0
  49. package/dist/gizmoPivot.js +34 -0
  50. package/dist/handlers/catalogs.d.ts +3 -0
  51. package/dist/handlers/catalogs.js +137 -0
  52. package/dist/handlers/collections.d.ts +3 -0
  53. package/dist/handlers/collections.js +57 -0
  54. package/dist/handlers/context.d.ts +36 -0
  55. package/dist/handlers/context.js +1 -0
  56. package/dist/handlers/document.d.ts +3 -0
  57. package/dist/handlers/document.js +350 -0
  58. package/dist/handlers/grids.d.ts +3 -0
  59. package/dist/handlers/grids.js +142 -0
  60. package/dist/handlers/hierarchy.d.ts +3 -0
  61. package/dist/handlers/hierarchy.js +55 -0
  62. package/dist/handlers/index.d.ts +8 -0
  63. package/dist/handlers/index.js +25 -0
  64. package/dist/handlers/minimap.d.ts +9 -0
  65. package/dist/handlers/minimap.js +32 -0
  66. package/dist/handlers/runtime.d.ts +3 -0
  67. package/dist/handlers/runtime.js +191 -0
  68. package/dist/handlers/streets.d.ts +3 -0
  69. package/dist/handlers/streets.js +159 -0
  70. package/dist/handlers/terrain.d.ts +3 -0
  71. package/dist/handlers/terrain.js +204 -0
  72. package/dist/index.d.ts +3 -2
  73. package/dist/index.js +3 -2
  74. package/dist/listDocumentTriggers.d.ts +42 -0
  75. package/dist/listDocumentTriggers.js +49 -0
  76. package/dist/materialAssignments.d.ts +63 -0
  77. package/dist/materialAssignments.js +84 -0
  78. package/dist/mcp/fieldSpec.d.ts +32 -0
  79. package/dist/mcp/fieldSpec.js +174 -0
  80. package/dist/mcp/rpcRequest.d.ts +8 -5
  81. package/dist/mcp/rpcRequest.js +72 -93
  82. package/dist/mcp/tools.js +105 -912
  83. package/dist/networkSnapshot.d.ts +82 -0
  84. package/dist/networkSnapshot.js +73 -0
  85. package/dist/parentCandidates.d.ts +12 -0
  86. package/dist/parentCandidates.js +25 -0
  87. package/dist/session.d.ts +91 -4
  88. package/dist/session.js +36 -1017
  89. package/dist/shell/AnimationPanel.d.ts +17 -0
  90. package/dist/shell/AnimationPanel.js +134 -0
  91. package/dist/shell/AssetThumbnail.d.ts +12 -0
  92. package/dist/shell/AssetThumbnail.js +23 -0
  93. package/dist/shell/BottomDock.d.ts +25 -0
  94. package/dist/shell/BottomDock.js +40 -0
  95. package/dist/shell/CommandPalette.d.ts +12 -0
  96. package/dist/shell/CommandPalette.js +56 -0
  97. package/dist/shell/ConsolePanel.d.ts +8 -0
  98. package/dist/shell/ConsolePanel.js +45 -0
  99. package/dist/shell/ContentBrowser.d.ts +21 -0
  100. package/dist/shell/ContentBrowser.js +130 -0
  101. package/dist/shell/HierarchyPanel.d.ts +26 -0
  102. package/dist/shell/HierarchyPanel.js +387 -0
  103. package/dist/shell/NetworkWorkspacePanel.d.ts +11 -0
  104. package/dist/shell/NetworkWorkspacePanel.js +49 -0
  105. package/dist/shell/PlayModeBar.d.ts +12 -0
  106. package/dist/shell/PlayModeBar.js +27 -0
  107. package/dist/shell/ProfilerPanel.d.ts +10 -0
  108. package/dist/shell/ProfilerPanel.js +41 -0
  109. package/dist/shell/SceneToolbar.d.ts +43 -0
  110. package/dist/shell/SceneToolbar.js +122 -0
  111. package/dist/shell/StatusBar.d.ts +18 -0
  112. package/dist/shell/StatusBar.js +41 -0
  113. package/dist/shell/TopAppBar.d.ts +35 -0
  114. package/dist/shell/TopAppBar.js +64 -0
  115. package/dist/shell/ViewportOverlays.d.ts +23 -0
  116. package/dist/shell/ViewportOverlays.js +136 -0
  117. package/dist/shell/WorkspaceRail.d.ts +20 -0
  118. package/dist/shell/WorkspaceRail.js +31 -0
  119. package/dist/shell/cameraTelemetry.d.ts +27 -0
  120. package/dist/shell/cameraTelemetry.js +24 -0
  121. package/dist/shell/commandRegistry.d.ts +58 -0
  122. package/dist/shell/commandRegistry.js +133 -0
  123. package/dist/shell/consoleSink.d.ts +11 -0
  124. package/dist/shell/consoleSink.js +17 -0
  125. package/dist/shell/consoleStore.d.ts +27 -0
  126. package/dist/shell/consoleStore.js +43 -0
  127. package/dist/shell/fields.d.ts +39 -0
  128. package/dist/shell/fields.js +104 -0
  129. package/dist/shell/formatSavedRelative.d.ts +2 -0
  130. package/dist/shell/formatSavedRelative.js +14 -0
  131. package/dist/shell/glbThumbnailCache.d.ts +45 -0
  132. package/dist/shell/glbThumbnailCache.js +241 -0
  133. package/dist/shell/hierarchyA11y.d.ts +21 -0
  134. package/dist/shell/hierarchyA11y.js +35 -0
  135. package/dist/shell/icons.d.ts +13 -0
  136. package/dist/shell/icons.js +85 -0
  137. package/dist/shell/layoutStore.d.ts +68 -0
  138. package/dist/shell/layoutStore.js +156 -0
  139. package/dist/shell/pathFlythrough.d.ts +37 -0
  140. package/dist/shell/pathFlythrough.js +54 -0
  141. package/dist/shell/perfHistory.d.ts +70 -0
  142. package/dist/shell/perfHistory.js +130 -0
  143. package/dist/shell/renameObject.d.ts +3 -0
  144. package/dist/shell/renameObject.js +25 -0
  145. package/dist/shell/theme.d.ts +36 -0
  146. package/dist/shell/theme.js +37 -0
  147. package/dist/shell/ui.d.ts +84 -0
  148. package/dist/shell/ui.js +90 -0
  149. package/dist/shell/useGlbThumbnail.d.ts +8 -0
  150. package/dist/shell/useGlbThumbnail.js +19 -0
  151. package/dist/uiStore.d.ts +27 -0
  152. package/dist/uiStore.js +10 -0
  153. package/dist/viewportContextMenu.d.ts +4 -2
  154. package/dist/viewportContextMenu.js +5 -1
  155. package/package.json +4 -4
  156. package/skills/jgengine/SKILL.md +8 -4
  157. package/skills/jgengine/api.md +182 -81
  158. package/skills/jgengine/capabilities.md +104 -2
  159. package/skills/jgengine/recipes/minimal-game.md +88 -0
  160. package/skills/jgengine-editor/SKILL.md +18 -3
  161. package/skills/jgengine-editor/api.md +403 -20
  162. package/skills/jgengine-editor/capabilities.md +46 -0
  163. package/skills/jgengine-editor/reference.md +87 -0
  164. package/skills/level-design/SKILL.md +54 -0
  165. package/skills/level-design/agents/openai.yaml +4 -0
  166. package/skills/level-design/references/application-playbook.md +192 -0
  167. package/skills/level-design/references/field-guide.md +337 -0
  168. package/skills/level-design/references/live-editor-loop.md +179 -0
  169. package/dist/OutlinerPanel.d.ts +0 -14
  170. package/dist/OutlinerPanel.js +0 -84
  171. package/skills/jgengine/reference-cartridge.md +0 -72
@@ -3,7 +3,7 @@ export declare const RIGHT_CLICK_SLOP_PX = 4;
3
3
  /** @internal True when the pointer released within the drag-vs-click threshold of its down position. */
4
4
  export declare function isPointerClick(startX: number, startY: number, endX: number, endY: number, thresholdPx?: number): boolean;
5
5
  /** @internal One entry in the editor viewport context menu. */
6
- export type EditorContextActionId = "frame" | "frameAll" | "duplicate" | "delete" | "createPrefab" | "copy" | "paste" | "addMarker" | "addVolume" | "addPath" | "addNote" | "openAssets";
6
+ export type EditorContextActionId = "frame" | "frameAll" | "duplicate" | "delete" | "createPrefab" | "parentTo" | "unparent" | "copy" | "paste" | "addMarker" | "addVolume" | "addPath" | "addNote" | "openAssets";
7
7
  /** @internal Label + id for one editor context-menu verb. */
8
8
  export interface EditorContextAction {
9
9
  id: EditorContextActionId;
@@ -16,9 +16,11 @@ export interface BuildEditorContextMenuInput {
16
16
  hitId: string | null;
17
17
  selection: readonly string[];
18
18
  canPaste: boolean;
19
+ /** True when at least one selected/hit object has a parent (offers Unparent). */
20
+ canUnparent?: boolean;
19
21
  }
20
22
  /**
21
23
  * @internal Selection-aware editor context verbs (#866). Hit/selection → frame/duplicate/delete/copy/prefab;
22
- * empty ground → place tools + paste when clipboard has content.
24
+ * empty ground → place tools + paste when clipboard has content. Shared by viewport and hierarchy rows.
23
25
  */
24
26
  export declare function buildEditorContextMenu(input: BuildEditorContextMenuInput): readonly EditorContextAction[];
@@ -6,7 +6,7 @@ export function isPointerClick(startX, startY, endX, endY, thresholdPx = RIGHT_C
6
6
  }
7
7
  /**
8
8
  * @internal Selection-aware editor context verbs (#866). Hit/selection → frame/duplicate/delete/copy/prefab;
9
- * empty ground → place tools + paste when clipboard has content.
9
+ * empty ground → place tools + paste when clipboard has content. Shared by viewport and hierarchy rows.
10
10
  */
11
11
  export function buildEditorContextMenu(input) {
12
12
  const hasSelection = input.selection.length > 0 || input.hitId !== null;
@@ -17,6 +17,10 @@ export function buildEditorContextMenu(input) {
17
17
  { id: "copy", label: "Copy" },
18
18
  { id: "delete", label: "Delete", separatorBefore: true },
19
19
  { id: "createPrefab", label: "Create prefab…", separatorBefore: true },
20
+ { id: "parentTo", label: "Parent to…", separatorBefore: true },
21
+ ...(input.canUnparent === true
22
+ ? [{ id: "unparent", label: "Unparent" }]
23
+ : []),
20
24
  { id: "paste", label: "Paste", disabled: !input.canPaste, separatorBefore: true },
21
25
  ];
22
26
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jgengine/editor",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "Scene/world/asset editor for JGengine — loaded lazily by the runner; never import from game entrypoints.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -31,9 +31,9 @@
31
31
  "test": "bun test src"
32
32
  },
33
33
  "dependencies": {
34
- "@jgengine/core": "^0.11.0",
35
- "@jgengine/react": "^0.11.0",
36
- "@jgengine/shell": "^0.11.0"
34
+ "@jgengine/core": "^0.13.0",
35
+ "@jgengine/react": "^0.13.0",
36
+ "@jgengine/shell": "^0.13.0"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@react-three/drei": "^10.0.0",
@@ -9,16 +9,16 @@ Read the repository [README](../../../README.md) for package truth, commands, la
9
9
 
10
10
  ## 1. Establish the target
11
11
 
12
- Capture only decisions that change architecture:
12
+ Treat the pitch as a unique composition of needs, not a genre to fill in — never reach for a genre kit, preset, archetype, or class template ("default sports car", "default RPG", "default FPS") in the SDK or skills (see [AGENTS.md](../../../AGENTS.md)). Use `game-design` to turn the pitch into a testable player promise, verbs, loops, progression, failure, and completion scenario. Use `level-design` when play depends on authored spaces, routes, encounters, exploration, or spatial pacing. Capture only decisions that change architecture:
13
13
 
14
14
  - player point of view and controls
15
15
  - world shape and authored content
16
16
  - core loop, interaction, combat, and progression
17
17
  - solo, local, hosted, or persistent multiplayer
18
- - HUD/menu states and art direction
18
+ - HUD/menu states and **custom** UI art direction (every game owns its presentation — no stock drop-in face)
19
19
  - one observable completion scenario
20
20
 
21
- For a new in-repo game, scaffold with `bun run new:game <id> --name "Title"`. Outside this monorepo, start with `npx jgengine create`; never copy `Games/*`.
21
+ For a new in-repo game, scaffold with `bun run new:game "<id-or-title>"` (thin script alias for `jgengine create`, auto-detects the in-repo variant). Outside this monorepo, start with `npx jgengine create`; never copy `Games/*`.
22
22
 
23
23
  ## 2. Select domains
24
24
 
@@ -26,6 +26,8 @@ Load only rows the target needs. Do not preload every domain.
26
26
 
27
27
  | Need | Skill | Owner |
28
28
  | --- | --- | --- |
29
+ | player promise, pillars, verbs, loops, economy, progression, balance | `game-design` | experience and rule intent |
30
+ | metrics, topology, encounters, navigation, spatial pacing | `level-design` | playable space intent |
29
31
  | scene placement, terrain painting, paths, asset authoring | `jgengine-editor` | editor document and authoring tools |
30
32
  | runtime world, movement, input, interaction, AI, navigation, audio | `jgengine-world` | spatial simulation and world runtime |
31
33
  | game state, systems, inventory, crafting, quests, economy, turns | `jgengine-gameplay` | non-combat rules and state |
@@ -34,15 +36,17 @@ Load only rows the target needs. Do not preload every domain.
34
36
  | models, sprites, materials, audio files, source licensing | `jgengine-assets` | asset discovery and catalogs |
35
37
  | authority, transport, replication, sessions, host persistence | `jgengine-multiplayer` | network topology and persistence adapters |
36
38
 
37
- Scenes normally require both `jgengine-editor` for authoring and `jgengine-world` for runtime consumption. Combat and multiplayer are opt-in, not default intake.
39
+ World content routes editor-first: any request that adds, moves, restyles, or removes something visible in the world — however phrased ("design this world", "place the enemies", "make it look better") — starts in `jgengine-editor`; the other domains consume the authored document. Scenes normally require both `jgengine-editor` for authoring and `jgengine-world` for runtime consumption. Combat and multiplayer are opt-in, not default intake.
38
40
 
39
41
  ## 3. Discover before designing
40
42
 
41
43
  Within each selected domain:
42
44
 
45
+ 0. Fastest start for a common composition: `npx jgengine recipe <name>` prints a vetted, SDK-typechecked snippet (imports + wired code) for `combat-loop`, `boss-telegraph`, `loot`, `quest`, `coop-presence`, `third-person-camera`; `npx jgengine recipe` lists them. Copy that instead of reconning per-file.
43
46
  1. Search `capabilities.md` by intent; it maps needs to imports.
44
47
  2. Open `api.md` only when exact signatures or export inventory are needed.
45
48
  3. Open the linked reference only for a deeper recipe or trap.
49
+ 4. For how several primitives wire into a running loop, read the domain's `recipes/` — connected, genre-free walkthroughs organized by composition seam; this skill's own [recipes/minimal-game.md](recipes/minimal-game.md) is the default whole-game walkthrough. Prefer a recipe over reading a game's source; the games under `Games/*` are not templates or references, and a hybrid game is just a different composition of the same primitives.
46
50
 
47
51
  If no capability fits, identify the upstream package seam before writing game-local code. In this repository, implement a reusable primitive with its first adopter; if editor-owned content cannot be expressed, file the editor gap first.
48
52
 
@@ -6,15 +6,15 @@
6
6
 
7
7
  - `CHANGELOG` (const): const CHANGELOG: Record<string, ChangelogEntry> — Per-version engine changelog keyed by semver string (e.g. `"0.10.0"`).
8
8
  - `ChangelogEntry` (interface): interface ChangelogEntry — One release's migrate steps plus added/changed/removed notes (typed mirror of CHANGELOG.md).
9
- - `VERSION` (const): const VERSION: "0.11.0" — Installed `@jgengine/core` semver — compare against {@link CHANGELOG} keys when migrating.
9
+ - `VERSION` (const): const VERSION: "0.13.0" — Installed `@jgengine/core` semver — compare against {@link CHANGELOG} keys when migrating.
10
10
 
11
11
  ## @jgengine/core/authoring
12
12
 
13
13
  - `ActionCodesMap` (type): type ActionCodesMap<TAction extends string = string, TCode extends string = string> = Record< TAction, ActionCodes<TCode> > — Maps each game action name to the input codes (hold/toggle keys, repeat rate) that trigger it.
14
14
  - `AuthoredProvenance` (interface): interface AuthoredProvenance — A first-class entry in the scene document — the editor fully owns and persists it.
15
15
  - `Drop` (interface): interface Drop — A resolved loot outcome — one item or currency grant with its rolled count.
16
- - `GameDefinition` (interface): interface GameDefinition<TAssetRef extends ModelAssetRef = ModelAssetRef, TMultiplayer = unknown> — Fully-resolved game description produced by {@link defineGame} — assets, scene, and opted-in subsystems.
17
- - `GameDefinitionConfig` (type): type GameDefinitionConfig<TAssetRef extends ModelAssetRef = ModelAssetRef, TMultiplayer = unknown> = Omit<GameDefinition<TAssetRef, TMultiplayer>, "scene" | "assets"> & { assets?: AssetCatalog<TAssetRef>; } — Input to {@link defineGame} — a `GameDefinition` with `scene` derived and `assets` optional.
16
+ - `GameDefinition` (interface): interface GameDefinition<TAssetRef extends ModelAssetRef = ModelAssetRef, TMultiplayer = unknown> — Fully-resolved game description produced by {@link defineGameDefinition} — assets, scene, and opted-in subsystems.
17
+ - `GameDefinitionConfig` (type): type GameDefinitionConfig<TAssetRef extends ModelAssetRef = ModelAssetRef, TMultiplayer = unknown> = Omit<GameDefinition<TAssetRef, TMultiplayer>, "scene" | "assets"> & { assets?: AssetCatalog<TAssetRef>; } — Input to {@link defineGameDefinition} — a `GameDefinition` with `scene` derived and `assets` optional.
18
18
  - `GameLoop` (interface): interface GameLoop<TContext = unknown> — Lifecycle hooks a game implements to drive init, per-tick simulation, and player join/leave.
19
19
  - `GameServerConfig` (type): type GameServerConfig = "persistent" | { mode: string; [key: string]: unknown } — Hosting mode for a game's multiplayer server: `"persistent"`, or a custom mode with its own options.
20
20
  - `GeneratedProvenance` (interface): interface GeneratedProvenance — An object derived from an authored document object — instances scattered from a painted layer, walls extruded from an authored footprint. Edits belong on the source object, not the generated instance.
@@ -35,15 +35,14 @@
35
35
  - `SpawnPointDistanceBias` (type): type SpawnPointDistanceBias = "near" | "far" | "none" — Preference for picking a spawn point relative to `avoid` positions: closer, farther, or unweighted.
36
36
  - `SpawnPointSelectionOptions` (interface): interface SpawnPointSelectionOptions — Semantic options for selecting a spawn point without exposing weighting internals.
37
37
  - `TransientProvenance` (interface): interface TransientProvenance — An ephemeral simulation object — a spawned agent, projectile, or particle that never persists.
38
- - `WorldFeature` (type): type WorldFeature = | ({ kind: "biomes" } & BiomesWorldConfig) | ({ kind: "voxel" } & VoxelWorldConfig) | ({ kind: "plots" } & PlotsWorldConfig) | ({ kind: "tilemap" } & TilemapWorldConfig) | EnvironmentWorldFeature | { kind: "flat" } — A declared world shape — biomes, voxel grid, plots, tilemap, environment, or flat — passed to `defineGame`.
38
+ - `WorldFeature` (type): type WorldFeature = | PlaceWorldFeature | ({ kind: "biomes" } & BiomesWorldConfig) | ({ kind: "voxel" } & VoxelWorldConfig) | ({ kind: "plots" } & PlotsWorldConfig) | ({ kind: "tilemap" } & TilemapWorldConfig) | EnvironmentWorldFeature | { kind: "flat" } — A declared world shape passed to `defineGame`. The preferred model is the place feature from `world()` (`@jgengine/core/world/place`): substrate + laws, with all dressing authored in the editor. The remaining members — biomes, voxel grid, plots, tilemap, environment, flat — are the legacy code-declared shapes kept for existing games.
39
39
  - `auditManifest` (function): function auditManifest(manifest: SceneOwnershipManifest): OwnershipDiagnostic[] — Audit every declaration in a manifest, keying diagnostics by each object's provenance id. An empty result means the manifest declares all of its content cleanly — every object is authored, generated, bakeable, or a reasoned runtime/transient object.
40
40
  - `biomes` (function): function biomes(config: BiomesWorldConfig): WorldFeature — Declares a biome-painted world — the whole-world alternative to a single `environment()` terrain.
41
- - `building` (function): function building(config: BuildingEnvironmentConfig = {}): BuildingEnvironmentDescriptor — Declares a cluster of procedurally-massed buildings for `environment()` — count, footprint, stories, style.
41
+ - `building` (function): function building(config: BuildingEnvironmentConfig = {}): BuildingEnvironmentDescriptor — Declares a cluster of procedurally-massed buildings for `environment()` — count, footprint, stories, style. Pass `along` to line road frontage instead of gridding around `position`.
42
42
  - `classifyOwnership` (function): function classifyOwnership(declaration: SceneOwnershipDeclaration): OwnershipVerdict — Resolve one declaration into a single boundary verdict.
43
43
  - `collectOwnershipDiagnostics` (function): function collectOwnershipDiagnostics(entries: Iterable<readonly [string, SceneOwnershipDeclaration]>): OwnershipDiagnostic[] — Audit a keyed set of declarations and return one diagnostic per object that breaks the boundary contract (a `reject` verdict carrying a `violation`). Deterministic: diagnostics come back in the iteration order of `entries`.
44
44
  - `contextVerb` (function): function contextVerb(label: string, command: string, args?: Record<string, unknown>): ContextVerb — Builds a {@link ContextVerb} for a right-click menu entry.
45
- - `defineGame` (function): function defineGame<TAssetRef extends ModelAssetRef, TMultiplayer>(config: GameDefinitionConfig<TAssetRef, TMultiplayer>): GameDefinition<TAssetRef, TMultiplayer> — Task-first entry point for authoring a game: fills in `scene` and default `assets`, validates `name`, OR-merges `features` from installed systems, and composes `loop` from `systems` + any classic hooks.
46
- - `environment` (function): function environment(config: EnvironmentWorldConfig = {}): EnvironmentWorldFeature — Composes an `environment()` world feature from terrain, sky, weather, vegetation, water, structures, roads, and pads.
45
+ - `environment` (function): function environment(config: EnvironmentWorldConfig = {}): EnvironmentWorldFeature — Composes an `environment()` feature from terrain, sky, weather, vegetation, water, structures, roads, and pads.
47
46
  - `flat` (function): function flat(): WorldFeature — Declares an empty flat world — the minimal `WorldFeature` for games with no terrain of their own.
48
47
  - `grass` (function): function grass(config: GrassEnvironmentConfig = {}): GrassEnvironmentDescriptor — Declares a grass vegetation patch for `environment()` — area, blade sizing, density, and colors.
49
48
  - `isSceneOwnershipManifest` (function): function isSceneOwnershipManifest(value: unknown): value is SceneOwnershipManifest — Narrow unknown parsed JSON to a {@link SceneOwnershipManifest}. Structural only — verifies the version, the declarations array, and each declaration's provenance shape; it does not judge whether declarations satisfy the boundary (use {@link auditManifest} for that).
@@ -70,34 +69,40 @@
70
69
  - `CommandResult` (type): type CommandResult<TState> = | { status: "applied"; state: TState } | { status: "rejected"; reason: string } | { status: "unknown-command" } — ⚠ undocumented
71
70
  - `createCommandRegistry` (function): function createCommandRegistry<TState>(): CommandRegistry<TState> — ⚠ undocumented
72
71
 
72
+ ## @jgengine/core/devtools/controls
73
+
74
+ - `ControlRecord` (interface): interface ControlRecord — Internal mutable record backing a registered control: schema metadata, current value, and change listeners.
75
+ - `ControlsModule` (interface): interface ControlsModule — Controls subsystem: the public controls facade plus internal register/write helpers and the record map.
76
+ - `createControlsModule` (const): const createControlsModule: (deps: { signal: ChangeSignal; }) => ControlsModule — Create the controls subsystem that registers, validates, and mutates tunable controls, notifying on change.
77
+
73
78
  ## @jgengine/core/devtools/devtools
74
79
 
75
80
  - `AngleUnit` (type): type AngleUnit = "rad" | "deg" — ⚠ undocumented
76
81
  - `CONTROL_SCHEMA_VERSION` (const): const CONTROL_SCHEMA_VERSION: 1 — ⚠ undocumented
77
- - `Devtools` (interface): interface Devtools — ⚠ undocumented
78
- - `DevtoolsControl` (interface): interface DevtoolsControl — ⚠ undocumented
82
+ - `Devtools` (interface): interface Devtools — Top-level devtools facade aggregating frame, profile, render, logs, latency, controls, discover, overrides, and probes.
83
+ - `DevtoolsControl` (interface): interface DevtoolsControl — Registered tunable control with its resolved schema metadata and read/write/reset accessors.
79
84
  - `DevtoolsControlKind` (type): type DevtoolsControlKind = | "slider" | "toggle" | "color" | "select" | "text" | "vec2" | "vec3" | "vec4" | "interval" | "angle" | "enum" — ⚠ undocumented
80
- - `DevtoolsLogEntry` (interface): interface DevtoolsLogEntry — ⚠ undocumented
81
- - `DevtoolsLogLevel` (type): type DevtoolsLogLevel = "log" | "info" | "warn" | "error" — ⚠ undocumented
85
+ - `DevtoolsLogEntry` (interface): interface DevtoolsLogEntry — A single captured log line with timestamp, level, and formatted message.
86
+ - `DevtoolsLogLevel` (type): type DevtoolsLogLevel = "log" | "info" | "warn" | "error" — Severity level for a captured devtools log entry.
82
87
  - `DevtoolsOverrides` (interface): interface DevtoolsOverrides — ⚠ undocumented
83
- - `DevtoolsSnapshot` (interface): interface DevtoolsSnapshot — ⚠ undocumented
84
- - `DiscoveredEntry` (interface): interface DiscoveredEntry — ⚠ undocumented
88
+ - `DevtoolsSnapshot` (interface): interface DevtoolsSnapshot — Serializable point-in-time snapshot of devtools state: frame, render, latency, logs, controls, and discovered fields.
89
+ - `DiscoveredEntry` (interface): interface DiscoveredEntry — A control auto-discovered by scanning an object/table, with its binding metadata and current reader.
85
90
  - `DiscoverySkip` (interface): interface DiscoverySkip — ⚠ undocumented
86
- - `FrameRecordSample` (interface): interface FrameRecordSample — ⚠ undocumented
87
- - `FrameStats` (interface): interface FrameStats — ⚠ undocumented
88
- - `LONG_FRAME_MS` (const): const LONG_FRAME_MS: 33.4 — ⚠ undocumented
89
- - `LatencyStats` (interface): interface LatencyStats — ⚠ undocumented
90
- - `LongFrameEvent` (interface): interface LongFrameEvent — ⚠ undocumented
91
+ - `FrameRecordSample` (interface): interface FrameRecordSample — Per-frame timing input recorded by callers: total frame time, sim time, and optional named phase durations.
92
+ - `FrameStats` (interface): interface FrameStats — Aggregated frame-timing statistics over the recent sampling window, including per-phase breakdown.
93
+ - `LONG_FRAME_MS` (const): const LONG_FRAME_MS: 33.4 — Frame duration in milliseconds above which a frame is recorded as a long-frame spike (~30fps budget).
94
+ - `LatencyStats` (interface): interface LatencyStats — Aggregated latency statistics (last/avg/min/max) over recorded latency samples.
95
+ - `LongFrameEvent` (interface): interface LongFrameEvent — Recorded spike event for a frame that exceeded the long-frame threshold, with culprit attribution.
91
96
  - `NormalizedColor` (interface): interface NormalizedColor — ⚠ undocumented
92
97
  - `OVERRIDES_FORMAT_VERSION` (const): const OVERRIDES_FORMAT_VERSION: 1 — ⚠ undocumented
93
98
  - `OverrideApplyDiagnostic` (interface): interface OverrideApplyDiagnostic — ⚠ undocumented
94
- - `OverrideApplyResult` (interface): interface OverrideApplyResult — ⚠ undocumented
95
- - `PhaseStats` (interface): interface PhaseStats — ⚠ undocumented
96
- - `RenderSample` (interface): interface RenderSample — ⚠ undocumented
99
+ - `OverrideApplyResult` (interface): interface OverrideApplyResult — Outcome of applying a devtools overrides payload: counts of applied and skipped entries plus diagnostics.
100
+ - `PhaseStats` (interface): interface PhaseStats — Timing summary for a single named profiling phase across the sampling window.
101
+ - `RenderSample` (interface): interface RenderSample — Snapshot of renderer resource counts (draw calls, triangles, geometries, textures) for a frame.
97
102
  - `ScanFieldMeta` (interface): interface ScanFieldMeta extends TunableOptions — ⚠ undocumented
98
103
  - `ScanMeta` (type): type ScanMeta = Readonly<Record<string, ScanFieldMeta>> — ⚠ undocumented
99
- - `Tunable` (interface): interface Tunable<T> — ⚠ undocumented
100
- - `TunableAccessor` (interface): interface TunableAccessor — ⚠ undocumented
104
+ - `Tunable` (interface): interface Tunable<T> — Typed handle to a registered control, exposing its live value and subscribe/set/reset operations.
105
+ - `TunableAccessor` (interface): interface TunableAccessor — Get/set accessor pair plus initial value used to bind a discovered field to a control.
101
106
  - `TunableChoice` (interface): interface TunableChoice<T = unknown> — ⚠ undocumented
102
107
  - `TunableInterval` (type): type TunableInterval = { min: number; max: number } — ⚠ undocumented
103
108
  - `TunableOptions` (interface): interface TunableOptions<T = unknown> — ⚠ undocumented
@@ -106,12 +111,48 @@
106
111
  - `TunableVec4` (type): type TunableVec4 = [number, number, number, number] — ⚠ undocumented
107
112
  - `createDevtools` (function): function createDevtools(): Devtools — ⚠ undocumented
108
113
  - `devtools` (const): const devtools: Devtools — ⚠ undocumented
109
- - `formatLogMessage` (function): function formatLogMessage(args: readonly unknown[]): string — ⚠ undocumented
114
+ - `formatLogMessage` (function): function formatLogMessage(args: readonly unknown[]): string — Format an array of console arguments into a single truncated log message string.
110
115
  - `instrumentLatency` (function): function instrumentLatency<T extends object>(target: T, methods: readonly (keyof T)[], record: (ms: number) => void = devtools.latency.record): T — ⚠ undocumented
111
116
  - `measureProfile` (function): function measureProfile<T>(name: string, fn: () => T): T — ⚠ undocumented
112
117
  - `snapshotDevtools` (function): function snapshotDevtools(): DevtoolsSnapshot — ⚠ undocumented
113
118
  - `tunable` (function): function tunable<T>(name: string, initial: T, options?: TunableOptions<T>): Tunable<T> — ⚠ undocumented
114
119
 
120
+ ## @jgengine/core/devtools/discover
121
+
122
+ - `DiscoverModule` (interface): interface DiscoverModule — Discovery subsystem: the public discover and probes facades plus internal record map and helpers.
123
+ - `DiscoveredRecord` (interface): interface DiscoveredRecord — Internal record for an auto-discovered field: identity, kind, initial value, source object, and get/set accessors.
124
+ - `createDiscoverModule` (const): const createDiscoverModule: (deps: { signal: ChangeSignal; register: <T>(name: string, initial: T, options?: TunableOptions<T> | undefined) => Tunable<T>; controlRecords: Map<string, ControlRecord>; }) => DiscoverModule — Create the discovery subsystem that scans objects/tables for tunable fields and binds them as controls and probes.
125
+
126
+ ## @jgengine/core/devtools/fallbackSeams
127
+
128
+ - `FallbackCause` (type): type FallbackCause = "omittedMapping" | "unpulledPack" | "noScene" — Why a seam fell back: `omittedMapping` (no mapping supplied — often intended), `unpulledPack` (a mapping was supplied but its asset pack is not pulled/indexed), `noScene` (nothing authored — e.g. no environment component).
129
+ - `FallbackSeam` (type): type FallbackSeam = "ground" | "entity" | "object" | "scatter" — Render seams that can resolve to a placeholder FALLBACK instead of authored content: `ground` (default green terrain), `entity`/`object` (primitive capsule/box actors), `scatter` (stylized proxy foliage).
130
+ - `FallbackSeamCounts` (type): type FallbackSeamCounts = Record<FallbackSeam, Record<FallbackCause, number>> — A per-seam, per-cause count table. Serializable, allocation-stable (keys never change).
131
+ - `FallbackSeamsReport` (type): type FallbackSeamsReport = Partial<Record<FallbackSeam, Partial<Record<FallbackCause, number>>>> — Non-zero-only view of {@link FallbackSeamCounts} returned by {@link fallbackSeamsSnapshot}.
132
+ - `armFallbackSeams` (function): function armFallbackSeams(on: boolean): void — Arm or disarm the fallback-seam diagnostic. Off by default; the shell arms it only when devtools is enabled (dev builds), so production is a pure no-op. Toggling clears all counts so a fresh observation starts empty and the opt-out path reports nothing.
133
+ - `beginFallbackPass` (function): function beginFallbackPass(): void — Zero every seam's tally. Used to bracket a whole observation batch (e.g. in tests). No-op when disarmed.
134
+ - `beginFallbackSeam` (function): function beginFallbackSeam(seam: FallbackSeam): void — Zero one seam's tally before it re-reports (per-seam frame boundary). No-op when disarmed.
135
+ - `endFallbackPass` (function): function endFallbackPass(): void — Close an observation pass: when the set of active fallbacks changes to a non-empty signature, emit ONE deduped warn line (never per-frame — the signature dedup suppresses repeats). No-op when disarmed.
136
+ - `fallbackSeamsSnapshot` (function): function fallbackSeamsSnapshot(): FallbackSeamsReport — Snapshot the current fallback tally as a compact, serializable object (non-zero entries only; empty when nothing fell back). Flows into the devtools `fallbacks` probe and the `debug_snapshot` RPC.
137
+ - `reportFallbackSeam` (function): function reportFallbackSeam(seam: FallbackSeam, cause: FallbackCause): void — Record that a render seam CHOSE a placeholder fallback (called at the choice site). A pure, allocation-free no-op when disarmed — the disarmed guard returns before touching any table.
138
+
139
+ ## @jgengine/core/devtools/frame
140
+
141
+ - `FrameModule` (interface): interface FrameModule — Frame subsystem exposing the frame-timing, profiling, and render-sample facades.
142
+ - `LONG_FRAME_MS` (const): const LONG_FRAME_MS: 33.4 — Frame duration in milliseconds above which a frame is recorded as a long-frame spike (~30fps budget).
143
+ - `createFrameModule` (const): const createFrameModule: (deps: { readProbes: () => Record<string, unknown>; }) => FrameModule — Create the frame subsystem that records frame/sim/phase timings, computes stats, and captures long-frame events.
144
+
145
+ ## @jgengine/core/devtools/logs
146
+
147
+ - `LogsModule` (interface): interface LogsModule — Logs subsystem exposing the log-capture and latency-tracking facades.
148
+ - `createLogsModule` (const): const createLogsModule: (deps: { signal: ChangeSignal; }) => LogsModule — Create the logs subsystem that buffers captured console output and records latency samples.
149
+ - `formatLogMessage` (function): function formatLogMessage(args: readonly unknown[]): string — Format an array of console arguments into a single truncated log message string.
150
+
151
+ ## @jgengine/core/devtools/overrides
152
+
153
+ - `OverridesModule` (interface): interface OverridesModule — Overrides subsystem exposing the export/apply facade for persisting and restoring control values.
154
+ - `createOverridesModule` (const): const createOverridesModule: (deps: { signal: ChangeSignal; controlRecords: Map<string, ControlRecord>; writeControl: (record: ControlRecord, raw: unknown) => boolean; discoveredRecords: Map<string, DiscoveredRecord>; enableDiscovered: (id: string) => void; }) => OverridesModule — Create the overrides subsystem that serializes changed control values and re-applies a saved overrides payload.
155
+
115
156
  ## @jgengine/core/devtools/rewriteTunables
116
157
 
117
158
  - `TunableDelta` (interface): interface TunableDelta — One changed tunable to write back into game source: which table, key path, and new value.
@@ -150,11 +191,36 @@
150
191
  - `TunableVec3` (type): type TunableVec3 = [number, number, number] — ⚠ undocumented
151
192
  - `TunableVec4` (type): type TunableVec4 = [number, number, number, number] — ⚠ undocumented
152
193
 
194
+ ## @jgengine/core/devtools/types
195
+
196
+ - `Devtools` (interface): interface Devtools — Top-level devtools facade aggregating frame, profile, render, logs, latency, controls, discover, overrides, and probes.
197
+ - `DevtoolsControl` (interface): interface DevtoolsControl — Registered tunable control with its resolved schema metadata and read/write/reset accessors.
198
+ - `DevtoolsLogEntry` (interface): interface DevtoolsLogEntry — A single captured log line with timestamp, level, and formatted message.
199
+ - `DevtoolsLogLevel` (type): type DevtoolsLogLevel = "log" | "info" | "warn" | "error" — Severity level for a captured devtools log entry.
200
+ - `DevtoolsSnapshot` (interface): interface DevtoolsSnapshot — Serializable point-in-time snapshot of devtools state: frame, render, latency, logs, controls, and discovered fields.
201
+ - `DiscoveredEntry` (interface): interface DiscoveredEntry — A control auto-discovered by scanning an object/table, with its binding metadata and current reader.
202
+ - `FrameRecordSample` (interface): interface FrameRecordSample — Per-frame timing input recorded by callers: total frame time, sim time, and optional named phase durations.
203
+ - `FrameStats` (interface): interface FrameStats — Aggregated frame-timing statistics over the recent sampling window, including per-phase breakdown.
204
+ - `LatencyStats` (interface): interface LatencyStats — Aggregated latency statistics (last/avg/min/max) over recorded latency samples.
205
+ - `LongFrameEvent` (interface): interface LongFrameEvent — Recorded spike event for a frame that exceeded the long-frame threshold, with culprit attribution.
206
+ - `OverrideApplyResult` (interface): interface OverrideApplyResult — Outcome of applying a devtools overrides payload: counts of applied and skipped entries plus diagnostics.
207
+ - `PhaseStats` (interface): interface PhaseStats — Timing summary for a single named profiling phase across the sampling window.
208
+ - `RenderSample` (interface): interface RenderSample — Snapshot of renderer resource counts (draw calls, triangles, geometries, textures) for a frame.
209
+ - `Tunable` (interface): interface Tunable<T> — Typed handle to a registered control, exposing its live value and subscribe/set/reset operations.
210
+ - `TunableAccessor` (interface): interface TunableAccessor — Get/set accessor pair plus initial value used to bind a discovered field to a control.
211
+
212
+ ## @jgengine/core/devtools/urlFlags
213
+
214
+ - `readUrlFlag` (function): function readUrlFlag(param: string): boolean — True when `param` is present and not an explicit off value (`0`/`false`/`off`/`no`).
215
+ - `readUrlParam` (function): function readUrlParam(param: string): string | null — The current query value of `param`, or null when absent (or no DOM).
216
+ - `subscribeUrlChange` (function): function subscribeUrlChange(listener: () => void): () => void — Fires `listener` whenever the query string may have changed out from under a flag — browser back/forward (`popstate`). Manual address-bar edits reload the page, so initial reads cover those; this keeps in-app state honest across history navigation. Returns an unsubscribe.
217
+ - `writeUrlParam` (function): function writeUrlParam(param: string, value: string | null): void — Sets `param` to `value`, or removes it when `value` is null, rewriting the URL in place with `history.replaceState` so the rest of the query and the hash survive and no history entry is pushed. No-ops without a DOM, and skips the write when the URL already matches.
218
+
153
219
  ## @jgengine/core/meta/changelog
154
220
 
155
221
  - `CHANGELOG` (const): const CHANGELOG: Record<string, ChangelogEntry> — Per-version engine changelog keyed by semver string (e.g. `"0.10.0"`).
156
222
  - `ChangelogEntry` (interface): interface ChangelogEntry — One release's migrate steps plus added/changed/removed notes (typed mirror of CHANGELOG.md).
157
- - `VERSION` (const): const VERSION: "0.11.0" — Installed `@jgengine/core` semver — compare against {@link CHANGELOG} keys when migrating.
223
+ - `VERSION` (const): const VERSION: "0.13.0" — Installed `@jgengine/core` semver — compare against {@link CHANGELOG} keys when migrating.
158
224
 
159
225
  ## @jgengine/core/runtime/adapter
160
226
 
@@ -171,8 +237,8 @@
171
237
  - `isServerAuthoritative` (function): function isServerAuthoritative(multiplayer: unknown): boolean — True when the adapter opts into host-authoritative world replication (`authority: "server"`).
172
238
  - `lan` (function): function lan(config?: { topology?: MultiplayerTopology; port?: number; path?: string; authority?: MultiplayerAuthority; }): MultiplayerAdapterConfig — ⚠ undocumented
173
239
  - `multiplayerAdapterKind` (function): function multiplayerAdapterKind(multiplayer: unknown): string | null — ⚠ undocumented
174
- - `offline` (function): function offline(): MultiplayerAdapterConfig — ⚠ undocumented
175
- - `p2p` (function): function p2p(config?: { topology?: MultiplayerTopology; room?: string; authority?: MultiplayerAuthority }): MultiplayerAdapterConfig — ⚠ undocumented
240
+ - `offline` (function): function offline(): MultiplayerAdapterConfig — Explicit single-player adapter. Solo games never need this — omitting `multiplayer` in the shell `defineGame` already defaults to offline; pass it only where an adapter value is structurally required.
241
+ - `p2p` (function): function p2p(config?: { topology?: MultiplayerTopology; room?: string; authority?: MultiplayerAuthority }): MultiplayerAdapterConfig — Serverless peer-to-peer (WebRTC) session — one peer hosts, friends join by room code.
176
242
  - `resolveAuthority` (function): function resolveAuthority(multiplayer: unknown): MultiplayerAuthority | null — Resolved authority for a multiplayer config. - `offline` / missing adapter → `null` (single-player; not multiplayer authority). - unset or `"client"` → `"client"` (presence-only; each client ticks). - `"server"` → host-authoritative shared sim.
177
243
  - `servers` (function): function servers(config: ServersPoolConfig): ServersPoolConfig — ⚠ undocumented
178
244
  - `socketIo` (function): function socketIo(config?: { topology?: MultiplayerTopology; url?: string; authority?: MultiplayerAuthority }): MultiplayerAdapterConfig — ⚠ undocumented
@@ -194,8 +260,8 @@
194
260
 
195
261
  - `CatalogEntityRole` (type): type CatalogEntityRole = "player" | "enemy" | "hostile" | "npc" | "vehicle" — ⚠ undocumented
196
262
  - `FloatTextInput` (interface): interface FloatTextInput — ⚠ undocumented
197
- - `GameAudio` (interface): interface GameAudio — Reachable audio seam on `ctx.game`: `play`, `music`, and `resume` route through the `audio.play`/`audio.music`/`audio.resume` events the shell's audio engine listens on, so game code triggers sound without importing the shell.
198
- - `GameContext` (interface): interface GameContext — ⚠ undocumented
263
+ - `GameAudio` (interface): interface GameAudio — Reachable audio seam on `ctx.game`: `play`, `music`, and `resume` route through the `audio.play`/`audio.music`/`audio.resume` events the shell's audio engine listens on, so game code triggers sound without importing the shell. Retained `loop`/`setLoop`/`stopLoop` add id-keyed loops with live pitch/gain control over `audio.loopStart`/`audio.loopSet`/`audio.loopStop` (#1051).
264
+ - `GameContext` (interface): interface GameContext — The live engine handle a game's loop, systems, commands, and UI read and mutate — entities, objects, the reactive store, opted-in `game.*` subsystems, world queries, and the sim clock. One context = one running world.
199
265
  - `GameContextCards` (interface): interface GameContextCards — ⚠ undocumented
200
266
  - `GameContextCommands` (interface): interface GameContextCommands — ⚠ undocumented
201
267
  - `GameContextContent` (interface): interface GameContextContent — ⚠ undocumented
@@ -205,6 +271,7 @@
205
271
  - `GameContextItemEntry` (interface): interface GameContextItemEntry — ⚠ undocumented
206
272
  - `GameContextItemUse` (interface): interface GameContextItemUse — ⚠ undocumented
207
273
  - `GameContextLoot` (interface): interface GameContextLoot — ⚠ undocumented
274
+ - `GameContextModels` (interface): interface GameContextModels — Per-kind render-model lookup for {@link GameContextOptions.models}; a resolved `ModelConfig` satisfies {@link ModelBodySource} structurally.
208
275
  - `GameContextObjectEntry` (interface): interface GameContextObjectEntry — ⚠ undocumented
209
276
  - `GameContextOptions` (interface): interface GameContextOptions<TAssetRef extends ModelAssetRef = ModelAssetRef, TMultiplayer = unknown> — ⚠ undocumented
210
277
  - `GameContextRace` (interface): interface GameContextRace — ⚠ undocumented
@@ -216,10 +283,40 @@
216
283
  - `SceneObjectContext` (interface): interface SceneObjectContext extends ObjectStore — ⚠ undocumented
217
284
  - `SceneWorldItemContext` (interface): interface SceneWorldItemContext — ⚠ undocumented
218
285
  - `TelegraphInput` (interface): interface TelegraphInput — ⚠ undocumented
219
- - `VfxInput` (interface): interface VfxInput — Request a transient spell/ability VFX burst; `from`/`to` accept an instance id or a world point, `color` is a `0xRRGGBB` tint, and `durationMs` defaults per `kind`.
286
+ - `VfxInput` (interface): interface VfxInput — Request a transient spell/ability VFX burst. The easy path is a named `preset` — `vfx({ preset: "arrow", from: caster, to: enemy })` renders a visible bolt with no color or archetype tuning; `"lightning"`, `"web"`, `"slash"`, `"shield"`, `"heal"`, `"explosion"` and the rest of {@link vfxPresets} likewise just work. `from`/`to` accept an instance id (the shell follows its live pose) or a fixed world point. Anything you also pass — `kind`, `color` (`0xRRGGBB`), `radius`, `durationMs` — overrides the preset; supply `kind` + `color` yourself for a fully custom burst with no preset. `durationMs` defaults per `kind`.
220
287
  - `WorldItemPickupResult` (type): type WorldItemPickupResult = | { status: "ok"; record: WorldItemRecord } | { status: "rejected"; reason: string } — ⚠ undocumented
221
288
  - `createGameContext` (function): function createGameContext<TAssetRef extends ModelAssetRef, TMultiplayer>(options: GameContextOptions<TAssetRef, TMultiplayer>): GameContext — ⚠ undocumented
222
289
 
290
+ ## @jgengine/core/runtime/gameContextTypes
291
+
292
+ - `CatalogEntityRole` (type): type CatalogEntityRole = "player" | "enemy" | "hostile" | "npc" | "vehicle" — ⚠ undocumented
293
+ - `FloatTextInput` (interface): interface FloatTextInput — ⚠ undocumented
294
+ - `GameAudio` (interface): interface GameAudio — Reachable audio seam on `ctx.game`: `play`, `music`, and `resume` route through the `audio.play`/`audio.music`/`audio.resume` events the shell's audio engine listens on, so game code triggers sound without importing the shell. Retained `loop`/`setLoop`/`stopLoop` add id-keyed loops with live pitch/gain control over `audio.loopStart`/`audio.loopSet`/`audio.loopStop` (#1051).
295
+ - `GameContext` (interface): interface GameContext — The live engine handle a game's loop, systems, commands, and UI read and mutate — entities, objects, the reactive store, opted-in `game.*` subsystems, world queries, and the sim clock. One context = one running world.
296
+ - `GameContextCards` (interface): interface GameContextCards — ⚠ undocumented
297
+ - `GameContextCommands` (interface): interface GameContextCommands — ⚠ undocumented
298
+ - `GameContextContent` (interface): interface GameContextContent — ⚠ undocumented
299
+ - `GameContextEconomy` (interface): interface GameContextEconomy — ⚠ undocumented
300
+ - `GameContextEntityEntry` (interface): interface GameContextEntityEntry — ⚠ undocumented
301
+ - `GameContextFeed` (interface): interface GameContextFeed extends Omit<GameFeed, "bind"> — ⚠ undocumented
302
+ - `GameContextItemEntry` (interface): interface GameContextItemEntry — ⚠ undocumented
303
+ - `GameContextItemUse` (interface): interface GameContextItemUse — ⚠ undocumented
304
+ - `GameContextLoot` (interface): interface GameContextLoot — ⚠ undocumented
305
+ - `GameContextModels` (interface): interface GameContextModels — Per-kind render-model lookup for {@link GameContextOptions.models}; a resolved `ModelConfig` satisfies {@link ModelBodySource} structurally.
306
+ - `GameContextObjectEntry` (interface): interface GameContextObjectEntry — ⚠ undocumented
307
+ - `GameContextOptions` (interface): interface GameContextOptions<TAssetRef extends ModelAssetRef = ModelAssetRef, TMultiplayer = unknown> — ⚠ undocumented
308
+ - `GameContextRace` (interface): interface GameContextRace — ⚠ undocumented
309
+ - `GameContextTurn` (interface): interface GameContextTurn — ⚠ undocumented
310
+ - `GameContextWorld` (interface): interface GameContextWorld — ⚠ undocumented
311
+ - `HitReactionInput` (interface): interface HitReactionInput — ⚠ undocumented
312
+ - `MoveTowardCommitOptions` (interface): interface MoveTowardCommitOptions extends MoveTowardOptions — Options for {@link SceneEntityContext.moveTowardCommit}: {@link MoveTowardOptions} plus an optional facing turn.
313
+ - `SceneEntityContext` (interface): interface SceneEntityContext — ⚠ undocumented
314
+ - `SceneObjectContext` (interface): interface SceneObjectContext extends ObjectStore — ⚠ undocumented
315
+ - `SceneWorldItemContext` (interface): interface SceneWorldItemContext — ⚠ undocumented
316
+ - `TelegraphInput` (interface): interface TelegraphInput — ⚠ undocumented
317
+ - `VfxInput` (interface): interface VfxInput — Request a transient spell/ability VFX burst. The easy path is a named `preset` — `vfx({ preset: "arrow", from: caster, to: enemy })` renders a visible bolt with no color or archetype tuning; `"lightning"`, `"web"`, `"slash"`, `"shield"`, `"heal"`, `"explosion"` and the rest of {@link vfxPresets} likewise just work. `from`/`to` accept an instance id (the shell follows its live pose) or a fixed world point. Anything you also pass — `kind`, `color` (`0xRRGGBB`), `radius`, `durationMs` — overrides the preset; supply `kind` + `color` yourself for a fully custom burst with no preset. `durationMs` defaults per `kind`.
318
+ - `WorldItemPickupResult` (type): type WorldItemPickupResult = | { status: "ok"; record: WorldItemRecord } | { status: "rejected"; reason: string } — ⚠ undocumented
319
+
223
320
  ## @jgengine/core/runtime/gameRuntime
224
321
 
225
322
  - `GameRuntime` (type): type GameRuntime = { gameId: string; save: SaveConfig; hydrate: (input: HydrateInput) => GameRuntimeSnapshot; runCommand: ( snapshot: GameRuntimeSnapshot, actorUserId: string, commandName: string, input: unknown, ) => ReturnType<typeof runCommand>; tick: (snapshot: GameRuntimeSnapshot, dtSeconds: nu… — ⚠ undocumented
@@ -232,6 +329,7 @@
232
329
 
233
330
  ## @jgengine/core/runtime/headlessRunner
234
331
 
332
+ - `HeadlessCommandInterface` (interface): interface HeadlessCommandInterface — Canvas-free command/intent surface for {@link HeadlessRunner} — invoke a game's registered UI commands and read the resulting reactive state off `ctx`.
235
333
  - `HeadlessInput` (interface): interface HeadlessInput — One step's worth of player intent handed to {@link HeadlessRunner.step} — the held-action set and pointer state the shell would otherwise publish from the browser each frame.
236
334
  - `HeadlessRunner` (interface): interface HeadlessRunner — A renderer-free driver for a game loop: builds a {@link GameContext} from a {@link GameDefinition}, runs the init hooks, then advances the simulation one step at a time from injected input. No React, R3F, or three.js — the whole play path (time, input, `onTick`, behaviour nav, optional player movement) runs from `core` primitives alone, so a non-React host (a server tick, a test, a CLI replay) can play a real game and read its world snapshot. The shell's FrameDriver is one such driver bolted to `useFrame`; this is the same step distilled out of the render tree.
237
335
  - `HeadlessRunnerOptions` (interface): interface HeadlessRunnerOptions<TAssetRef extends ModelAssetRef, TMultiplayer> — ⚠ undocumented
@@ -258,6 +356,18 @@
258
356
  - `ToServerListingOptions` (type): type ToServerListingOptions = { includeJoinCode?: boolean; } — ⚠ undocumented
259
357
  - `WorldChunkRecord` (type): type WorldChunkRecord = { serverId: string; chunkKey: string; snapshot: RuntimeChunkRow; updatedAt: number; } — ⚠ undocumented
260
358
 
359
+ ## @jgengine/core/runtime/hostPolicy
360
+
361
+ - `canJoinPrivateServer` (function): function canJoinPrivateServer(args: { isMember: boolean; joinCode: string | undefined; suppliedCode: string | undefined; }): boolean — Private-server join-code gate. Existing members always pass; non-members must present a matching `joinCode` (loose-normalized via {@link normalizeJoinCode}). Callers still decide whether the server is private — this only answers the code/membership half.
362
+ - `isAutoJoinCandidate` (function): function isAutoJoinCandidate(args: { memberUserIds: readonly string[]; slotsPerServer: number; visibility: SessionVisibility | undefined; userId: string; }): boolean — Auto-match candidate when no `serverId` is supplied: already a member, or a public room with free capacity. Private rooms are never auto-picked (join-by-code / direct id only).
363
+ - `isListablePublicly` (function): function isListablePublicly(visibility: SessionVisibility | undefined): boolean — True when a server's `visibility` should surface in public listings / browse results.
364
+ - `isPrivateJoinBlocked` (function): function isPrivateJoinBlocked(args: { visibility: SessionVisibility | undefined; memberUserIds: readonly string[]; userId: string; joinCode: string | undefined; suppliedCode: string | undefined; }): boolean — Whether a private-visibility server blocks this join (non-member without a matching code). Public / undefined visibility never blocks.
365
+ - `isServerFull` (function): function isServerFull(memberUserIds: readonly string[], slotsPerServer: number, userId: string): boolean — True when the server has no free slots for a non-member. Existing members never count as "full" so rejoin/leave cycles keep working.
366
+ - `isServerMember` (function): function isServerMember(memberUserIds: readonly string[], userId: string): boolean — Whether `userId` is already on the server's member roster.
367
+ - `statusAfterLeave` (function): function statusAfterLeave(remainingMemberCount: number, currentStatus: GameServerStatus): GameServerStatus — Status after a leave: empty rooms reopen; non-empty rooms keep their current status.
368
+ - `withJoinedMember` (function): function withJoinedMember(memberUserIds: readonly string[], userId: string): string[] — Roster after a successful join: unchanged when already a member, else appended.
369
+ - `withoutMember` (function): function withoutMember(memberUserIds: readonly string[], userId: string): string[] — Roster after a leave: `userId` removed; order of remaining members preserved.
370
+
261
371
  ## @jgengine/core/runtime/hostedGameRunner
262
372
 
263
373
  - `HostedGameRunner` (interface): interface HostedGameRunner — The GameContext-loop equivalent of the pure-reducer `createGameHost`: one authoritative `createGameContext` per world, driven server-side. `onInit` runs once at construction; `onNewPlayer`/`onPlayerLeave` fire per join/leave; `tick` advances `onTick` then commits a revision. Clients pull a full {@link WorldSnapshot} baseline once, then per-tick {@link WorldDiff}s from their last revision. Games ship only normal GameContext code — the runner adds no per-game surface.
@@ -381,54 +491,45 @@
381
491
  - `SnapshotViewer` (interface): interface SnapshotViewer — Who a host→client snapshot is being projected for — the identity a {@link SnapshotModule.project} filters against.
382
492
  - `WorldSnapshot` (type): type WorldSnapshot = Record<string, unknown> — Full world baseline keyed by {@link SnapshotModule.key} — one entry per opted-in subsystem.
383
493
 
384
- ## @jgengine/shell/cartridge
385
-
386
- - `CartridgeAbilitySlot` (interface): interface CartridgeAbilitySlot — ⚠ undocumented
387
- - `CartridgeConfig` (type): type CartridgeConfig = CartridgeSpec & { name: string; panels: CartridgePanels; hud: { storageKey?: string; panels: readonly CartridgeHudPanelSpec[] }; screens: CartridgeScreens; theme?: Record<string, string>; world?: GameConfig["world"]; physics?: GameConfig["physics"]; assets?: GameConfig["assets… — ⚠ undocumented
388
- - `CartridgeHudPanelSpec` (interface): interface CartridgeHudPanelSpec — ⚠ undocumented
389
- - `CartridgePanelItem` (type): type CartridgePanelItem = | { kind: "vital"; stat: string; label: string; tone?: string; width?: number } | { kind: "xp"; width?: number } | { kind: "timer"; label: string } | { kind: "score"; source: "kills"; label: string; digits?: number } | { kind: "abilityBar"; icons: Record<string, string> } |… — ⚠ undocumented
390
- - `CartridgePanels` (interface): interface CartridgePanels — ⚠ undocumented
391
- - `CartridgeResultLine` (type): type CartridgeResultLine = { label: string; accent?: boolean } & ( | { source: "kills" | "level" } | { value: string | number } ) — ⚠ undocumented
392
- - `CartridgeScreens` (interface): interface CartridgeScreens — ⚠ undocumented
393
- - `cartridge` (function): function cartridge(config: CartridgeConfig): PlayableGame — ⚠ undocumented
394
-
395
- ## @jgengine/shell/cartridge/runtime
396
-
397
- - `CartridgeRuntime` (interface): interface CartridgeRuntime — ⚠ undocumented
398
- - `createCartridge` (function): function createCartridge(spec: CartridgeSpec): CartridgeRuntime — ⚠ undocumented
399
-
400
- ## @jgengine/shell/cartridge/spec
401
-
402
- - `BoltFx` (interface): interface BoltFx — ⚠ undocumented
403
- - `CartridgeEnemy` (interface): interface CartridgeEnemy — ⚠ undocumented
404
- - `CartridgeFlow` (interface): interface CartridgeFlow — ⚠ undocumented
405
- - `CartridgePhase` (type): type CartridgePhase = "start" | "countdown" | "playing" | "won" | "lost" — ⚠ undocumented
406
- - `CartridgePlayer` (interface): interface CartridgePlayer — ⚠ undocumented
407
- - `CartridgeProgression` (interface): interface CartridgeProgression — ⚠ undocumented
408
- - `CartridgeRules` (interface): interface CartridgeRules — ⚠ undocumented
409
- - `CartridgeRun` (interface): interface CartridgeRun — ⚠ undocumented
410
- - `CartridgeSpawning` (interface): interface CartridgeSpawning — ⚠ undocumented
411
- - `CartridgeSpec` (interface): interface CartridgeSpec — ⚠ undocumented
412
- - `CartridgeUpgrade` (interface): interface CartridgeUpgrade — ⚠ undocumented
413
- - `CartridgeWeapon` (type): type CartridgeWeapon = | (WeaponCommon & { kind: "projectile"; range: number; speed: number }) | (WeaponCommon & { kind: "orbit"; blades: Leveled; radius: Leveled; hitRadius: number; angularSpeed: number; }) | (WeaponCommon & { kind: "pulse"; radius: Leveled; durationSeconds: number }) | (WeaponComm… — ⚠ undocumented
414
- - `CartridgeXpGems` (interface): interface CartridgeXpGems — ⚠ undocumented
415
- - `HIT_EFFECT` (const): const HIT_EFFECT: "hit" — ⚠ undocumented
416
- - `Leveled` (type): type Leveled = | number | { base: number; perLevel: number; min?: number; max?: number } | { table: readonly number[] } — ⚠ undocumented
417
- - `PulseFx` (interface): interface PulseFx — ⚠ undocumented
418
- - `UpgradeEffect` (type): type UpgradeEffect = | { kind: "weaponLevel"; weapon: string } | { kind: "statBonus"; stat: string; amount: number } | { kind: "fieldAdd"; field: string; amount: number } | { kind: "fieldMultiply"; field: string; factor: number } | { kind: "custom"; apply(ctx: GameContext, run: CartridgeRun, stacks:… — ⚠ undocumented
419
- - `WASD_KEYBINDS` (const): const WASD_KEYBINDS: ActionCodesMap — ⚠ undocumented
420
- - `WeaponCommon` (interface): interface WeaponCommon — ⚠ undocumented
421
- - `WeaponFireArgs` (interface): interface WeaponFireArgs — ⚠ undocumented
422
- - `XP_GEM_BASE_TYPE` (const): const XP_GEM_BASE_TYPE: "xp_gem" — ⚠ undocumented
423
- - `leveled` (function): function leveled(value: Leveled, level: number): number — ⚠ undocumented
424
-
425
- ## @jgengine/shell/cartridge/testkit
426
-
427
- - `CartridgeSmokeOptions` (interface): interface CartridgeSmokeOptions — ⚠ undocumented
428
- - `bootCartridge` (function): function bootCartridge(spec: CartridgeSpec & { name?: string; world?: WorldFeature; physics?: PhysicsConfig }): { ctx: GameContext; cart: CartridgeRuntime } — ⚠ undocumented
429
- - `cartridgeSmokeTest` (function): function cartridgeSmokeTest(spec: CartridgeSpec & { name?: string; world?: WorldFeature; physics?: PhysicsConfig }, options?: CartridgeSmokeOptions): void — ⚠ undocumented
430
- - `tickCartridge` (function): function tickCartridge(ctx: GameContext, cart: CartridgeRuntime, seconds: number, step = 0.1): void — ⚠ undocumented
431
-
432
- ## @jgengine/shell/cartridge/validate
433
-
434
- - `validateCartridge` (function): function validateCartridge(spec: CartridgeSpec): string[] — ⚠ undocumented
494
+ ## @jgengine/shell/GameHost
495
+
496
+ - `EditorSummonModule` (interface): interface EditorSummonModule — Structural shape of the module `GameHost`'s `editor` loader resolves — `import("@jgengine/editor")` satisfies it.
497
+ - `GameHost` (function): function GameHost({ playable, gameId, wsUrl, multiplayer, resolveMultiplayer, editor }: GameHostProps): React.JSX.Element — The one documented mount: resolves multiplayer for the playable and renders the shell. With the `editor` loader prop it also owns the whole editor summon (F2+E, `?mode=editor`, dev save endpoint).
498
+ - `GameHostProps` (interface): interface GameHostProps — Props for {@link GameHost}: the playable, optional multiplayer overrides, and the optional editor loader that enables the engine-owned F2+E summon.
499
+
500
+ ## @jgengine/shell/defineGame
501
+
502
+ - `GameConfig` (type): type GameConfig<TAssetRef extends ModelAssetRef = ModelAssetRef> = EngineFields<TAssetRef> & PresentationFields — ⚠ undocumented
503
+ - `defineGame` (function): function defineGame<TAssetRef extends ModelAssetRef = ModelAssetRef>(config: GameConfig<TAssetRef>): PlayableGame — The one public authoring entry point: compose engine fields (systems, world, physics, input) and presentation fields (camera, HUD, audio, authored scene) into a `PlayableGame` ready for `GameHost`. Defaults to solo/offline multiplayer; `editorLayers` auto-mounts the authored scene document.
504
+
505
+ ## @jgengine/shell/gameKit
506
+
507
+ - `Clock` (function): function Clock({ format, showDay, controls, style, className, }: { format?: "24h" | "12h"; showDay?: boolean; controls?: boolean; style?: CSSProperties; className?: string; }): JSX.Element — A time-of-day clock reading the sim calendar — `Day N · HH:MM`, 24h or 12h. `controls` adds pause + the game's speed multipliers as clickable pills (the "fast-forward" bar), off by default so a game opts into letting the player scrub time.
508
+ - `Coins` (function): function Coins({ currencyId, icon, style, className, }: { currencyId: string; icon?: ReactNode; style?: CSSProperties; className?: string; }): JSX.Element — A currency counter — an icon (emoji/char, default a coin) plus the live amount for `currencyId`. *
509
+ - `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.
510
+ - `EditorDocument` (interface): interface EditorDocument — The full authored scene: every marker, volume, path, note, and sculpted terrain for a game.
511
+ - `EditorSummonModule` (interface): interface EditorSummonModule — Structural shape of the module `GameHost`'s `editor` loader resolves — `import("@jgengine/editor")` satisfies it.
512
+ - `GameCameraConfig` (interface): interface GameCameraConfig — Camera tuning for the shell's rig stack: pick the rig via `rig`, then tune it through its matching config block. All fields optional — the default is the third-person orbit rig.
513
+ - `GameConfig` (type): type GameConfig<TAssetRef extends ModelAssetRef = ModelAssetRef> = EngineFields<TAssetRef> & PresentationFields — ⚠ undocumented
514
+ - `GameContext` (interface): interface GameContext — The live engine handle a game's loop, systems, commands, and UI read and mutate — entities, objects, the reactive store, opted-in `game.*` subsystems, world queries, and the sim clock. One context = one running world.
515
+ - `GameHost` (function): function GameHost({ playable, gameId, wsUrl, multiplayer, resolveMultiplayer, editor }: GameHostProps): React.JSX.Element — The one documented mount: resolves multiplayer for the playable and renders the shell. With the `editor` loader prop it also owns the whole editor summon (F2+E, `?mode=editor`, dev save endpoint).
516
+ - `GameHostProps` (interface): interface GameHostProps — Props for {@link GameHost}: the playable, optional multiplayer overrides, and the optional editor loader that enables the engine-owned F2+E summon.
517
+ - `GameLoop` (interface): interface GameLoop<TContext = unknown> — Lifecycle hooks a game implements to drive init, per-tick simulation, and player join/leave.
518
+ - `Hotbar` (function): function Hotbar({ inventoryId, activeSlot, keys, slotSize, itemIcon, style, className, }: { inventoryId: string; activeSlot?: number; keys?: readonly string[]; slotSize?: number; /** Caller-supplied item id → icon registry; return null/undefined to fall back to the default glyph. */ itemIcon?: (item… — A numbered hotbar bound to an inventory — painted iconed slots (a `GameIcon` glyph over a school-keyed gradient with a count badge, #1035), an active-slot highlight, and a keycap per slot. Place it and pass the `inventoryId`; `activeSlot` highlights the equipped one. Supply `itemIcon` to map your item ids to your own glyphs — the default resolves a `GameIcon` from the item id.
519
+ - `HudCanvas` (function): function HudCanvas({ layout, editChord, compactScale, showDuring, className, style, children, }: { layout: HudLayoutStore; editChord?: HudEditChord | false; /** Zoom applied to the whole HUD on compact displays. Default 0.85. */ compactScale?: number; /** Opt-in play-phase gate: render the HUD only … — Full-viewport HUD surface. Panels declared with `HudPanel` flow into nine anchor regions and stack automatically with a gap — no per-panel pixel offsets, no manual clearance for sibling panels, the touch-control dock (`--jg-hud-dock-clearance`), or device safe areas. On compact displays the whole surface scales down and each panel applies its `compact` behavior.
520
+ - `HudPanel` (function): function HudPanel({ id, anchor, order, compact: compactMode, chip, interactive, inset, locked, showDuring, priority, mobileBehavior, allowOverlapWith, collisionGroup, region, width, height, type, className, style, children, }: { id: string; anchor?: HudAnchor; /** Stack position within the region, a… — A HUD block that lives in one of the nine anchor regions. Panels sharing a region stack outward from the screen edge in ascending `order`. On fine pointers panels stay draggable through the edit chord; a dragged panel leaves the flow and keeps its custom placement. On compact displays custom placements are ignored and the `compact` behavior applies.
521
+ - `PlayableGame` (type): type PlayableGame = EnginePlayableGame< ComponentType, ComponentType, RenderEntity, RenderObject, ComponentType<ViewmodelProps>, ComponentType<WorldOverlayProps> > — The concrete React-bound playable a shell `defineGame` returns and `GameHost` mounts — the one PlayableGame games handle.
522
+ - `StatBar` (function): function StatBar({ statId, entityId, tone, label, showValue, width, icon, style, className, }: { statId?: string; entityId?: string; tone?: StatTone; label?: string; showValue?: boolean; width?: number; icon?: ReactNode; style?: CSSProperties; className?: string; }): JSX.Element | null — A polished stat bar (health/mana/stamina/shield/xp) — a rounded, glassy meter with a tone-colored fill and an optional value readout. Reads `statId` off `entityId` (defaults to the local player). Renders nothing until the stat exists.
523
+ - `StoreHandle` (interface): interface StoreHandle<T> — A typed, cast-free handle onto one slot of the reactive game store (`ctx.game.store`). The single type parameter is fixed at definition; `read`/`write`/`update` never widen to `unknown`, so no call site repeats `store.get(key) as T`. Writes flow through the engine store, so they bump `ctx.version()`, serialize into a {@link WorldSnapshot}, and replay under host authority — the same guarantees a hand-rolled `store.get`/`store.set` pair gives up the moment it forks run state into a module-level singleton.
524
+ - `SystemDefinition` (interface): interface SystemDefinition — A reusable game capability — lifecycle, timing, events, and optional save / replication / reset / disposal. Pass instances via `defineGame({ systems })`. Prefer one system per meaningful capability (`combat`, `quests`), not per micro-tick.
525
+ - `authoredSpawnPosition` (function): function authoredSpawnPosition(document: AuthoredSpawnDocumentLike, options?: AuthoredSpawnOptions): [number, number, number] | null — Position of the authored spawn marker as a spawn-ready `[x, y, z]` tuple, or null when the document has none. Reads the first `player_spawn` marker by default, so dragging the marker in the editor moves where players spawn — no coordinates copied into game code.
526
+ - `collectAuthoredTriggers` (function): function collectAuthoredTriggers(document: SceneDocumentLike): AuthoredTrigger[] — Collect every authored trigger on a document's markers and volumes. Pure — no runtime state. Action params use the live {@link registerTriggerAction} registry when present.
527
+ - `defineGame` (function): function defineGame<TAssetRef extends ModelAssetRef = ModelAssetRef>(config: GameConfig<TAssetRef>): PlayableGame — The one public authoring entry point: compose engine fields (systems, world, physics, input) and presentation fields (camera, HUD, audio, authored scene) into a `PlayableGame` ready for `GameHost`. Defaults to solo/offline multiplayer; `editorLayers` auto-mounts the authored scene document.
528
+ - `defineKeyedStore` (function): function defineKeyedStore<T>(keyFor: (id: string) => string, initial: T | (() => T)): KeyedStoreHandle<T> — Define a typed per-owner keyed family on the game store: game code expresses `read(ctx, userId)`/`write(ctx, userId, v)`/`update(...)` with the value type it means, and both the `` `prefix:${id}` `` key composition and the `unknown → T` cast live once, here, behind the boundary. Reach for this over N separate `defineStore` calls whenever the owning id varies at runtime (per-user class, per-instance auras) — `defineStore` stays the right call for a single fixed slot.
529
+ - `defineStore` (function): function defineStore<T>(key: string, initial: T | (() => T)): StoreHandle<T> — Define a typed slot on the game store: game code expresses `read(ctx)`/`write(ctx, v)`/`update(...)` with the value type it means, and the `unknown → T` cast lives once, here, behind the boundary. Pass a factory for `initial` when the fallback is a fresh mutable object; the factory runs at most once and its result is reused, so an unwritten slot keeps a stable identity across reads (no per-read churn for a React selector, no allocation on a hot path).
530
+ - `defineSystem` (function): function defineSystem(definition: SystemDefinition): SystemDefinition — Declare a composable game system. Pure data + hooks — the engine compiles the schedule and installs lifecycle when the game boots.
531
+ - `environment` (function): function environment(config?: EnvironmentWorldConfig): EnvironmentWorldFeature — Composes an `environment()` feature from terrain, sky, weather, vegetation, water, structures, roads, and pads.
532
+ - `environmentContentFromDocument` (function): function environmentContentFromDocument(doc: EditorDocument, options?: EnvironmentContentOptions): EnvironmentContent — Derives the coordinate/placement content of an `environment()` world from its scene document: terrain footprint (via {@link terrainBoundsFromDocument}), ground clearings under authored spawns/POIs (via `clearanceZonesFrom`), and the document's sculpt snapshot. This is the seam that lets a game author its world footprint and flatten regions in the editor instead of hardcoding them — the `world.ts` that consumes it carries only engine tuning.
533
+ - `offline` (function): function offline(): MultiplayerAdapterConfig — Explicit single-player adapter. Solo games never need this — omitting `multiplayer` in the shell `defineGame` already defaults to offline; pass it only where an adapter value is structurally required.
534
+ - `seededRng` (function): function seededRng(seed: string | number): () => number — Deterministic pseudo-random generator seeded from a string or number — same seed, same sequence.
535
+ - `useHudLayout` (function): function useHudLayout(options?: { storageKey?: string; snap?: number; locked?: boolean; /** * Scene-document `ui` section — source of truth for panel placement/size. * When provided, hydrates the layout store (and wins over legacy localStorage). */ documentUi?: EditorUiDocument; /** * When true (def… — Layout state for `HudCanvas` — panel placements, edit-mode drag/resize, and per-game persistence.