@vgai/engine 0.5.2 → 0.5.4

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 (185) hide show
  1. package/README.md +18 -11
  2. package/package.json +10 -6
  3. package/schemas/engine-api.json +1 -68
  4. package/schemas/engine-api.md +1 -32
  5. package/schemas/engine-capabilities.json +30 -42
  6. package/schemas/{vgai-game.schema.json → vgai-project.schema.json} +52 -34
  7. package/src/adapter/adapter-surface.ts +5 -5
  8. package/src/adapter/authoring.ts +168 -226
  9. package/src/adapter/colyseus-networking-adapter.ts +44 -5
  10. package/src/adapter/first-party-systems.ts +156 -42
  11. package/src/adapter/host-context.ts +177 -46
  12. package/src/adapter/index.ts +47 -51
  13. package/src/adapter/ingest/game-contract.ts +2 -2
  14. package/src/adapter/ingest/scene-capture.ts +18 -19
  15. package/src/adapter/ingest/structural-ids.ts +127 -0
  16. package/src/adapter/ingest/upstream-pin.ts +9 -12
  17. package/src/adapter/loop-gate-report.ts +11 -11
  18. package/src/adapter/rapier-physics-adapter.ts +27 -9
  19. package/src/adapter/root-adapter.ts +217 -0
  20. package/src/adapter/{vgai-scene-game-adapter.ts → setup-three-root-adapter.ts} +173 -351
  21. package/src/adapter/system-adapter.ts +80 -63
  22. package/src/ai/navigation.ts +1 -1
  23. package/src/animation/animation-clock.ts +1 -1
  24. package/src/animation/camera-ownership.ts +1 -2
  25. package/src/animation/cubic-spline-interpolant.ts +132 -0
  26. package/src/animation/theatre-clock-binding.ts +2 -2
  27. package/src/animation/theatre-object-binding.ts +4 -4
  28. package/src/animation/xstate-animation-binding.ts +75 -5
  29. package/src/{scene/schema → asset-formats}/camera.ts +2 -5
  30. package/src/{scene/schema → asset-formats}/collider.ts +2 -5
  31. package/src/asset-formats/index.ts +54 -0
  32. package/src/{scene/schema → asset-formats}/instances.ts +10 -6
  33. package/src/{scene/schema → asset-formats}/light.ts +3 -6
  34. package/src/{scene/schema → asset-formats}/material.ts +4 -7
  35. package/src/{scene/schema → asset-formats}/mesh.ts +4 -7
  36. package/src/asset-formats/parse.ts +39 -0
  37. package/src/{scene/schema → asset-formats}/particles.ts +3 -6
  38. package/src/{scene/schema/environment.ts → asset-formats/render-env.ts} +23 -86
  39. package/src/{scene/schema → asset-formats}/tuples.ts +1 -1
  40. package/src/{scene/asset-loaders.ts → asset-loaders.ts} +8 -9
  41. package/src/asset-parse-error.ts +33 -0
  42. package/src/{scene/asset-registry.ts → asset-registry.ts} +1 -1
  43. package/src/assets.ts +1 -1
  44. package/src/audio/wav-encode.ts +9 -9
  45. package/src/canvas-react/engine-bridge.ts +59 -0
  46. package/src/canvas-react/index.ts +50 -0
  47. package/src/canvas-react/pixi-primitive.tsx +202 -0
  48. package/src/canvas-react/pixi-react-adapter.tsx +290 -0
  49. package/src/canvas-react/pixi-react-root-factory.tsx +88 -0
  50. package/src/canvas-react/world-context.ts +328 -0
  51. package/src/core/frame-pacing.ts +100 -0
  52. package/src/core/game-loop.ts +50 -28
  53. package/src/core/seeded-random.ts +7 -7
  54. package/src/core/sim-clock.ts +388 -0
  55. package/src/core/system-runner.ts +17 -63
  56. package/src/core/types.ts +34 -15
  57. package/src/data/data-asset.ts +3 -3
  58. package/src/data/data-check-core.ts +6 -7
  59. package/src/data/data-ref.ts +11 -11
  60. package/src/data/vite-plugin-data.ts +10 -10
  61. package/src/{scene/defaults.ts → defaults.ts} +18 -40
  62. package/src/dev/render-debug-adapter.ts +1 -1
  63. package/src/dev/webgl-frame-capture.ts +1 -1
  64. package/src/ecs/scene-index.ts +439 -0
  65. package/src/ecs/scene-query.ts +43 -0
  66. package/src/{scene → ecs}/user-data.ts +17 -36
  67. package/src/index.ts +7 -9
  68. package/src/input/input-manager.ts +29 -32
  69. package/src/input/input-types.ts +2 -2
  70. package/src/input/schema.ts +5 -5
  71. package/src/loader.ts +57 -0
  72. package/src/manifest/editor-port.ts +69 -0
  73. package/src/manifest/filename.ts +49 -0
  74. package/src/manifest/index.ts +8 -2
  75. package/src/manifest/load-file.ts +11 -0
  76. package/src/manifest/load.ts +65 -77
  77. package/src/manifest/locate.ts +55 -0
  78. package/src/manifest/schema.ts +400 -233
  79. package/src/{scene → physics}/collider-dimensions.ts +3 -3
  80. package/src/physics/physics-registry.ts +1 -1
  81. package/src/{world2d/authoring-2d.ts → pixi/authoring.ts} +24 -11
  82. package/src/pixi/index.ts +43 -0
  83. package/src/{world2d/ingest-iframe-2d.ts → pixi/ingest-iframe.ts} +9 -9
  84. package/src/{world2d/ingest2d.ts → pixi/ingest.ts} +28 -28
  85. package/src/{world2d/physics2d-registry.ts → pixi/physics-registry.ts} +1 -1
  86. package/src/{world2d/scene-capture-2d.ts → pixi/scene-capture.ts} +3 -3
  87. package/src/{world2d/system-adapters-2d.ts → pixi/system-adapters.ts} +2 -2
  88. package/src/react/unmanaged-root-detector.ts +26 -1
  89. package/src/react/use-data.ts +5 -5
  90. package/src/react/use-selection.tsx +15 -42
  91. package/src/react/{game-state.tsx → world-state.tsx} +44 -46
  92. package/src/render/auto-batcher.ts +1 -2
  93. package/src/{scene → render}/instance-mesh.ts +1 -1
  94. package/src/{scene → render}/light-camera-factory.ts +14 -13
  95. package/src/render/lod.ts +17 -0
  96. package/src/{scene → render}/material-factory.ts +8 -7
  97. package/src/{scene → render}/particles-factory.ts +62 -12
  98. package/src/render/render-batch-system.ts +14 -41
  99. package/src/render/render-features.ts +1 -1
  100. package/src/render/render-settings.ts +1 -2
  101. package/src/render/spark-renderer-lifecycle.ts +1 -1
  102. package/src/runtime/create-runtime.ts +352 -463
  103. package/src/runtime/debug-bridge.ts +148 -93
  104. package/src/runtime/debug-registry.ts +79 -54
  105. package/src/runtime/dev-layers.ts +40 -0
  106. package/src/runtime/frame-selector-cache.ts +4 -4
  107. package/src/runtime/game.ts +618 -369
  108. package/src/runtime/gameplay-rng-trap.ts +6 -7
  109. package/src/runtime/input-router.ts +11 -11
  110. package/src/runtime/mount-game.ts +54 -55
  111. package/src/runtime/mount-manifest.ts +154 -150
  112. package/src/runtime/presentation.ts +141 -0
  113. package/src/runtime/render-audio-control.ts +64 -53
  114. package/src/runtime/render-control.ts +45 -51
  115. package/src/runtime/render-seed.ts +3 -4
  116. package/src/runtime/state-bridge.ts +17 -18
  117. package/src/runtime/types.ts +94 -61
  118. package/src/setup/setup-renderer.ts +11 -6
  119. package/src/world3d-react/engine-bridge.ts +46 -33
  120. package/src/world3d-react/index.ts +31 -26
  121. package/src/world3d-react/r3f-adapter.tsx +211 -96
  122. package/src/world3d-react/r3f-root-factory.tsx +91 -0
  123. package/src/world3d-react/renderer-config.ts +137 -0
  124. package/src/world3d-react/world-context.ts +141 -111
  125. package/schemas/entity2d.schema.json +0 -468
  126. package/schemas/prefab.schema.json +0 -9992
  127. package/schemas/scn2d.schema.json +0 -494
  128. package/schemas/vscn.schema.json +0 -10851
  129. package/src/adapter/game-adapter.ts +0 -164
  130. package/src/adapter/ingest/overlay-applier.ts +0 -207
  131. package/src/adapter/ingest/overlay-apply.ts +0 -168
  132. package/src/adapter/ingest/overlay-file.ts +0 -126
  133. package/src/adapter/ingest/overlay-report.ts +0 -176
  134. package/src/animation/gsap-registration.ts +0 -184
  135. package/src/audio/audio-introspection.ts +0 -290
  136. package/src/audio/index.ts +0 -39
  137. package/src/audio/tone-clock-binding.ts +0 -98
  138. package/src/audio/tone-context.ts +0 -175
  139. package/src/audio/tone-offline-render.ts +0 -167
  140. package/src/ecs/component-manager.ts +0 -814
  141. package/src/ecs/game-component.ts +0 -260
  142. package/src/ecs/hmr-swap-report.ts +0 -65
  143. package/src/physics/trigger-dispatch.ts +0 -97
  144. package/src/react/root-adapter.tsx +0 -49
  145. package/src/scene/asset-paths.ts +0 -121
  146. package/src/scene/asset-ref-check.ts +0 -248
  147. package/src/scene/component-registry.ts +0 -51
  148. package/src/scene/parse.ts +0 -204
  149. package/src/scene/scene-apply.ts +0 -407
  150. package/src/scene/scene-diff-schema.ts +0 -115
  151. package/src/scene/scene-diff-types.ts +0 -29
  152. package/src/scene/scene-loader.ts +0 -1526
  153. package/src/scene/scene-query.ts +0 -63
  154. package/src/scene/scene-types.ts +0 -33
  155. package/src/scene/scene-version.ts +0 -40
  156. package/src/scene/schema/animation.ts +0 -46
  157. package/src/scene/schema/audio.ts +0 -25
  158. package/src/scene/schema/entity-ref.ts +0 -78
  159. package/src/scene/schema/entity.ts +0 -189
  160. package/src/scene/schema/index.ts +0 -51
  161. package/src/scene/schema/joint.ts +0 -26
  162. package/src/scene/schema/physics.ts +0 -49
  163. package/src/scene/schema/scene-file.ts +0 -292
  164. package/src/scene/schema/shadow.ts +0 -24
  165. package/src/scene/schema/spline.ts +0 -21
  166. package/src/world2d/asset-paths2d.ts +0 -44
  167. package/src/world2d/capture-to-scene2d.ts +0 -52
  168. package/src/world2d/collision-2d.ts +0 -99
  169. package/src/world2d/entity2d-asset.ts +0 -22
  170. package/src/world2d/index.ts +0 -91
  171. package/src/world2d/physics2d-transform.ts +0 -173
  172. package/src/world2d/physics2d-units.ts +0 -10
  173. package/src/world2d/pixi-game-adapter.ts +0 -439
  174. package/src/world2d/pixi-surface.ts +0 -78
  175. package/src/world2d/scene2d-identity.ts +0 -49
  176. package/src/world2d/scene2d-loader.ts +0 -433
  177. package/src/world2d/schema/entity2d.ts +0 -163
  178. package/src/world2d/schema/physics2d.ts +0 -64
  179. package/src/world2d/schema/sprite.ts +0 -99
  180. package/src/world2d/schema/tilemap.ts +0 -39
  181. package/src/world2d/schema/tuples2d.ts +0 -25
  182. package/src/world2d/transform-writer-2d.ts +0 -42
  183. package/src/world2d/types.ts +0 -74
  184. package/src/world3d-react/behavior.tsx +0 -146
  185. /package/src/{scene → render}/mesh-shadow.ts +0 -0
@@ -1,10 +1,9 @@
1
1
  /**
2
- * D15 — the dev-mode `Math.random` phase trap (`docs/D15-DETERMINISM-DESIGN.md`
3
- * §2.a enforcer 3, T-D15.3). A project that declares
4
- * `determinism.seededRandom` is claiming ALL gameplay RNG flows through
5
- * `ctx.random` — the burn-down scan (`test/gameplay-rng-ban.test.ts`) catches
6
- * raw `Math.random()`/`Date.now()`/`performance.now()` call sites it can
7
- * SEE in source; this trap catches what the scan structurally can't: a
2
+ * The dev-mode `Math.random` phase trap (enforcer 3, T-D15.3). A project that
3
+ * declares `determinism.seededRandom` is claiming ALL gameplay RNG flows
4
+ * through `ctx.random` the burn-down scan (`test/gameplay-rng-ban.test.ts`)
5
+ * catches raw `Math.random()`/`Date.now()`/`performance.now()` call sites it
6
+ * can SEE in source; this trap catches what the scan structurally can't: a
8
7
  * TRANSITIVE draw made by a third-party library the game calls into during a
9
8
  * gameplay tick.
10
9
  *
@@ -69,7 +68,7 @@ export function createGameplayRngTrap(
69
68
  // this warning STRING would otherwise false-positive against itself.
70
69
  '[determinism] the global Math.random generator was drawn from during a gameplay frame ' +
71
70
  'while this project declares determinism.seededRandom — use ctx.random() / ' +
72
- `ctx.random.stream(name) instead (docs/D15-DETERMINISM-DESIGN.md). Call site:\n${site}`,
71
+ `ctx.random.stream(name) instead. Call site:\n${site}`,
73
72
  );
74
73
  }
75
74
  // `previous` is always set by the time `trapped` can run — `enable()`
@@ -1,22 +1,22 @@
1
1
  /**
2
- * The delegating input router (COMPOSITION-DESIGN.md D5 §2a) —
3
- * `createGameRuntime`'s roots path (T6.1 slice 1,
4
- * docs/MULTI-WORLD-DESIGN.md §1.C) uses this to route pointer input across
5
- * N stacked world canvases with exactly ONE root listener.
2
+ * The delegating input router (D5 §2a) —
3
+ * `createGameRuntime`'s roots path (T6.1 slice 1) uses this to route
4
+ * pointer input across N stacked world canvases with exactly ONE root
5
+ * listener.
6
6
  *
7
7
  * Split into two layers so the decision logic is unit-testable with plain
8
8
  * fake roots — no real DOM/canvas needed:
9
9
  *
10
- * - `stackOrder` / `resolveClaimingWorld`: pure functions over
10
+ * - `stackOrder` / `resolveClaimingRoot`: pure functions over
11
11
  * `{id, zOrder, hitTest?}` — "who claims this point".
12
12
  * - `applyPointerEventsStacking` / `createInputRouter`: the DOM wiring —
13
13
  * sets `pointer-events` CSS per D5 §2a and forwards a claimed event to
14
14
  * the claiming world's own canvas.
15
15
  *
16
16
  * Per-event fall-through (D5 §2b — the sanctioned mechanism for an
17
- * authoring surface's own interior drag affordances, e.g. the world2d
18
- * editor's gizmos) is explicitly NOT this file's job (MULTI-WORLD-DESIGN.md
19
- * task 4) — it stays inside whatever authoring surface needs it.
17
+ * authoring surface's own interior drag affordances, e.g. a canvas
18
+ * editor's gizmos) is explicitly NOT this file's job — it stays inside
19
+ * whatever authoring surface needs it.
20
20
  */
21
21
 
22
22
  /** The pure decision inputs — no DOM. */
@@ -59,7 +59,7 @@ export function stackOrder<T extends ClaimEntry>(entries: readonly T[]): T[] {
59
59
  * (or via its own `hitTest`, if it declares one) — "no-claim falls to
60
60
  * bottom". Returns `null` only when `entries` is empty.
61
61
  */
62
- export function resolveClaimingWorld(
62
+ export function resolveClaimingRoot(
63
63
  entries: readonly ClaimEntry[],
64
64
  x: number,
65
65
  y: number,
@@ -191,7 +191,7 @@ export function createInputRouter(
191
191
  const clientY = (evt as unknown as { clientY?: number }).clientY ?? 0;
192
192
  const x = clientX - rect.left;
193
193
  const y = clientY - rect.top;
194
- const claimant = resolveClaimingWorld(entries, x, y);
194
+ const claimant = resolveClaimingRoot(entries, x, y);
195
195
  if (claimant && claimant !== bottomId) {
196
196
  const entry = byId.get(claimant);
197
197
  if (entry) forwardEvent(entry.canvas, evt);
@@ -203,7 +203,7 @@ export function createInputRouter(
203
203
  }
204
204
 
205
205
  return {
206
- resolveClaim: (x, y) => resolveClaimingWorld(entries, x, y),
206
+ resolveClaim: (x, y) => resolveClaimingRoot(entries, x, y),
207
207
  dispose() {
208
208
  for (const type of ROUTED_EVENT_TYPES) {
209
209
  container.removeEventListener?.(type, handler, true);
@@ -1,28 +1,26 @@
1
- // E4 — the S-D composer (docs/unified-world-editor/27-visual-react-editing.md
2
- // §7 E4; design lineage docs/unified-world-editor/26-unified-editor-spec.md
3
- // §5 Stage S-D). Builds ON `mount-manifest.ts`'s `mountManifestWorlds` (never
4
- // duplicates its per-kind dispatch/validation) to add the one thing that
5
- // module deliberately does NOT have: a KIND REGISTRY, so a project doesn't
6
- // have to hand-build an `entries` map inline in its own `main.ts` every time
7
- // — it registers a `AdapterSurfaceFactory` per kind it uses (once, at module load)
8
- // and then mounts with a single `mountGameFromManifest(manifest, host)` call.
1
+ // The S-D composer (design lineage Stage S-D). Builds ON `mount-manifest.ts`'s
2
+ // `mountManifestRoots` (never duplicates its per-kind dispatch/validation) to add
3
+ // the one thing that module deliberately does NOT have: a KIND REGISTRY, so a
4
+ // project doesn't have to hand-build an `entries` map inline in its own `main.ts`
5
+ // every time it registers a `AdapterSurfaceFactory` per kind it uses (once, at
6
+ // module load) and then mounts with a single `mountGameFromManifest(manifest,
7
+ // host)` call.
9
8
  //
10
9
  // Engine-core react/pixi-free discipline (mirrors `mount-manifest.ts`'s own
11
10
  // header comment, and the HARD INVARIANT this file was built under): this
12
11
  // registry is pure mechanism — it holds whatever `AdapterSurfaceFactory` functions
13
12
  // callers register, but it registers NONE itself. In particular there is no
14
- // built-in 'pixijs'/'react' registration here (that would require this file
13
+ // built-in 'canvas'/'react' registration here (that would require this file
15
14
  // to value-import `pixi.js`/`react`/`react-dom`, exactly what `mount-manifest
16
- // .ts` forbids); a project that has a pixijs or react world MUST register a
15
+ // .ts` forbids); a project that has a canvas or react world MUST register a
17
16
  // factory for that kind itself — see `defaultThreeAdapterFactory` below for why
18
- // even the 'threejs' convenience export is a plain function the CALLER
17
+ // even the 'three' convenience export is a plain function the CALLER
19
18
  // registers, not something this module wires up automatically.
20
19
 
21
- import type { GameAdapter } from '../adapter/game-adapter';
20
+ import type { RootAdapter } from '../adapter/root-adapter';
22
21
  import type { ResolvedAdapterRoot } from '../manifest/load';
23
- import type { ComponentRegistry } from '../scene/component-registry';
24
22
  import type { GameSession } from './create-runtime';
25
- import { type MountEntry, mountManifestWorlds, resolveManifest } from './mount-manifest';
23
+ import { type MountEntry, mountManifestRoots, resolveManifest } from './mount-manifest';
26
24
  import type { GameSetupFn } from './types';
27
25
 
28
26
  // ---------------------------------------------------------------------------
@@ -37,7 +35,7 @@ import type { GameSetupFn } from './types';
37
35
  */
38
36
  export interface ManifestHost {
39
37
  /** The host creates one absolutely-positioned surface per world inside
40
- * this element — see `WorldsRuntimeConfig.container`. */
38
+ * this element — see `RootsRuntimeConfig.container`. */
41
39
  readonly container: HTMLElement;
42
40
  /**
43
41
  * Resolve a manifest-declared `entry` (a project-relative module path,
@@ -62,7 +60,7 @@ export interface ManifestHost {
62
60
  readonly width?: number | undefined;
63
61
  readonly height?: number | undefined;
64
62
  /** Forwarded to `createGameRuntime` — Node/headless test harnesses only,
65
- * never a real host. See `WorldsRuntimeConfig.headless`. */
63
+ * never a real host. See `RootsRuntimeConfig.headless`. */
66
64
  readonly headless?: boolean | undefined;
67
65
  }
68
66
 
@@ -80,7 +78,7 @@ export interface AdapterSurfaceFactoryContext {
80
78
  /**
81
79
  * A caller-registered per-kind mount strategy: given the world's resolved
82
80
  * manifest entry and the loaded entry module (if any), produce the
83
- * `MountEntry` `mountManifestWorlds` needs to mount it (exactly what a
81
+ * `MountEntry` `mountManifestRoots` needs to mount it (exactly what a
84
82
  * project used to hand-build inline as its own `entries[id]` — see
85
83
  * `examples/tri-world/src/main.ts`'s pre-E4 shape). May be async (loading an
86
84
  * asset, fetching a scene file, etc.).
@@ -97,8 +95,8 @@ export type AdapterSurfaceFactory = (
97
95
  const registry = new Map<string, AdapterSurfaceFactory>();
98
96
 
99
97
  /**
100
- * Register a `AdapterSurfaceFactory` for a manifest world `kind` (`'threejs'` /
101
- * `'pixijs'` / `'react'`, or any future kind the manifest schema grows).
98
+ * Register a `AdapterSurfaceFactory` for a manifest world `kind` (`'three'` /
99
+ * `'canvas'` / `'react'`, or any future kind the manifest schema grows).
102
100
  * Call once, at module load — mirrors `registerSceneUIRenderer()`'s existing
103
101
  * "call before mounting" convention (`packages/editor/template/src/main.ts`).
104
102
  *
@@ -148,33 +146,29 @@ export function __clearAdapterSurfaceRegistryForTests(): void {
148
146
  * (an explicit world entry module, including `examples/*` projects'
149
147
  * `src/index.ts` — see CLAUDE.md's "Adding an example project"). */
150
148
  interface ThreeEntryModuleExports {
151
- readonly adapter?: GameAdapter;
149
+ readonly adapter?: RootAdapter;
152
150
  readonly setup?: GameSetupFn;
153
- readonly componentRegistry?: ComponentRegistry;
154
151
  }
155
152
 
156
153
  /**
157
- * A ready-to-register {@link AdapterSurfaceFactory} for `kind: 'threejs'` roots
154
+ * A ready-to-register {@link AdapterSurfaceFactory} for `kind: 'three'` roots
158
155
  * that follow the first-party entry-module convention (`export const
159
- * adapter` and/or `export async function setup`) or are plain scene files
160
- * with an optional named `componentRegistry` export. Threejs is safe to
161
- * ship as an exported convenience (unlike pixijs/react) because `three`/
162
- * `VgaiSceneGameAdapter` are already unconditional engine dependencies —
156
+ * adapter` and/or `export async function setup`). Threejs is safe to
157
+ * ship as an exported convenience (unlike canvas/react) because `three`/
158
+ * `SetupThreeRootAdapter` are already unconditional engine dependencies
163
159
  * see `mount-manifest.ts`'s header comment. Still never auto-registered:
164
160
  * the registry itself stays zero-policy (see this file's header comment) —
165
- * a caller opts in with `registerAdapter('threejs', defaultThreeAdapterFactory)`.
161
+ * a caller opts in with `registerAdapter('three', defaultThreeAdapterFactory)`.
166
162
  *
167
163
  * Resolution mirrors `mount-manifest.ts`'s own `resolveThreeAdapter` branch
168
164
  * order: an entry module's `adapter` export wins outright; else its `setup`
169
- * export (wrapping via `fromSetup` happens inside `mountManifestWorlds`
170
- * itself — this factory just returns the `MountEntry` shape); else (no
171
- * `entry` at all) a scene-driven world, forwarding `componentRegistry` if
172
- * the entry module supplied one.
165
+ * export (wrapping via `fromSetup` happens inside `mountManifestRoots`
166
+ * itself — this factory just returns the `MountEntry` shape).
173
167
  */
174
168
  export const defaultThreeAdapterFactory: AdapterSurfaceFactory = (world, ctx) => {
175
169
  const mod = ctx.entryModule as ThreeEntryModuleExports | undefined;
176
- if (mod?.adapter) return { kind: 'threejs', adapter: mod.adapter };
177
- if (mod?.setup) return { kind: 'threejs', setup: mod.setup };
170
+ if (mod?.adapter) return { kind: 'three', adapter: mod.adapter };
171
+ if (mod?.setup) return { kind: 'three', setup: mod.setup };
178
172
  if (world.entry !== undefined) {
179
173
  throw new Error(
180
174
  `defaultThreeAdapterFactory: entry module "${world.entry}" for world "${world.id}" exports ` +
@@ -182,7 +176,10 @@ export const defaultThreeAdapterFactory: AdapterSurfaceFactory = (world, ctx) =>
182
176
  '(export one from the declared entry module).',
183
177
  );
184
178
  }
185
- return { kind: 'threejs', componentRegistry: mod?.componentRegistry };
179
+ throw new Error(
180
+ `defaultThreeAdapterFactory: world "${world.id}" declares no \`entry\` — a three root is ` +
181
+ 'authored as a TSX/R3F world module; point `entry` at it.',
182
+ );
186
183
  };
187
184
 
188
185
  // ---------------------------------------------------------------------------
@@ -190,30 +187,32 @@ export const defaultThreeAdapterFactory: AdapterSurfaceFactory = (world, ctx) =>
190
187
  // ---------------------------------------------------------------------------
191
188
 
192
189
  export interface MountGameOptions {
193
- /** Explicit per-world entries, same shape `mountManifestWorlds` accepts —
190
+ /** Explicit per-world entries, same shape `mountManifestRoots` accepts —
194
191
  * ALWAYS wins over a registered kind factory for that world id (backward
195
192
  * compat: a caller mid-migration, or one that just prefers building one
196
193
  * entry by hand, never has to touch the registry at all). */
197
194
  readonly entries?: Readonly<Record<string, MountEntry>> | undefined;
198
195
  }
199
196
 
200
- /** True for the one shape `mountManifestWorlds` can ALREADY mount with zero
201
- * `entries[id]` at all (a plain `default`-adapter, scene-driven, no-`entry`
202
- * threejs world — `resolveThreeAdapter`'s own scene branch, which needs
203
- * nothing beyond the manifest itself). Every other shape (pixijs, react, an
204
- * entry-declaring or module/ingest-adapter threejs world) needs SOMETHING
205
- * in `entries[id]` to succeed. */
206
- function worldIsSelfSufficient(world: ResolvedAdapterRoot): boolean {
207
- return (
208
- world.surface === 'threejs' && world.adapter.type === 'builtin' && world.entry === undefined
209
- );
197
+ /** True for the one shape `mountManifestRoots` can ALREADY mount with zero
198
+ * `entries[id]` at all.
199
+ *
200
+ * WO-8: nothing is self-sufficient any more. The one shape that was — a plain
201
+ * `default`-adapter, SCENE-driven, no-`entry` three world, which
202
+ * `resolveThreeAdapter`'s scene branch could mount from the manifest alone —
203
+ * died with the `.vscn.json` format. `load.ts` now rejects a three root with no
204
+ * `entry` outright, so every world needs a registered factory or an explicit
205
+ * entry, and this predicate is retained only to keep the loud-degrade error the
206
+ * documented outcome rather than a silent skip. */
207
+ function worldIsSelfSufficient(_world: ResolvedAdapterRoot): boolean {
208
+ return false;
210
209
  }
211
210
 
212
211
  /**
213
- * Mount every world declared by a `vgai.game.json` manifest onto `host
212
+ * Mount every world declared by a `vgai.project.json` manifest onto `host
214
213
  * .container`, resolving each world's kind through the `registerAdapter`
215
214
  * registry — falling back to an explicit `opts.entries[id]` where supplied,
216
- * exactly like `mountManifestWorlds` (so a caller can migrate one world at a
215
+ * exactly like `mountManifestRoots` (so a caller can migrate one world at a
217
216
  * time, or never touch the registry if it prefers hand-building entries).
218
217
  *
219
218
  * This is the "one call" scaffold/example projects mount through (E4
@@ -222,11 +221,11 @@ function worldIsSelfSufficient(world: ResolvedAdapterRoot): boolean {
222
221
  * `packages/editor/template/src/main.ts` for the worked single-world
223
222
  * example and `examples/tri-world/src/main.ts` for a multi-kind one.
224
223
  *
225
- * Degrades loudly (`docs/WAVE3-ADAPTER-PLUMBING-DESIGN.md` D-Z2, carried
226
- * into E4): a world whose kind has no registered factory AND no explicit
227
- * entry, and which cannot self-mount from the manifest alone, throws a named
228
- * `Error` identifying the world id + kind and BOTH ways to fix it
229
- * (`registerAdapter` or `opts.entries`) — never a silent skip.
224
+ * Degrades loudly (carried into E4): a world whose kind has no registered
225
+ * factory AND no explicit entry, and which cannot self-mount from the
226
+ * manifest alone, throws a named `Error` identifying the world id + kind and
227
+ * BOTH ways to fix it (`registerAdapter` or `opts.entries`) never a silent
228
+ * skip.
230
229
  */
231
230
  export async function mountGameFromManifest(
232
231
  manifestInput: unknown,
@@ -249,18 +248,18 @@ export async function mountGameFromManifest(
249
248
  continue;
250
249
  }
251
250
 
252
- if (worldIsSelfSufficient(world)) continue; // mountManifestWorlds needs nothing further
251
+ if (worldIsSelfSufficient(world)) continue; // mountManifestRoots needs nothing further
253
252
 
254
253
  throw new Error(
255
254
  `mountGameFromManifest: root "${world.id}" (adapter "${world.adapter.identity}") has no registered ` +
256
255
  `adapter factory and no explicit entries["${world.id}"] — call ` +
257
256
  `registerAdapter("${world.adapter.identity}", factory) before mounting (see ` +
258
- '`defaultThreeAdapterFactory` for a worked threejs example), or pass ' +
257
+ '`defaultThreeAdapterFactory` for a worked three example), or pass ' +
259
258
  `opts.entries["${world.id}"] directly (see mount-manifest.ts's \`MountEntry\`).`,
260
259
  );
261
260
  }
262
261
 
263
- return mountManifestWorlds({
262
+ return mountManifestRoots({
264
263
  manifest,
265
264
  container: host.container,
266
265
  entries,