@vgai/engine 0.3.0 → 0.4.0-canary.20260715.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 (559) hide show
  1. package/package.json +8 -2
  2. package/schemas/engine-api.json +124 -0
  3. package/schemas/engine-api.md +53 -0
  4. package/schemas/engine-capabilities.json +124 -0
  5. package/schemas/inputmap.schema.json +314 -0
  6. package/schemas/mat.schema.json +286 -0
  7. package/schemas/prefab.schema.json +10148 -0
  8. package/schemas/scn2d.schema.json +475 -0
  9. package/schemas/vgai-game.schema.json +383 -0
  10. package/schemas/vscn.schema.json +11007 -0
  11. package/src/adapter/{world-kind.ts → adapter-surface.ts} +6 -6
  12. package/src/adapter/authoring.ts +67 -0
  13. package/src/adapter/game-adapter.ts +8 -8
  14. package/src/adapter/host-context.ts +2 -4
  15. package/src/adapter/index.ts +3 -1
  16. package/src/adapter/system-adapter.ts +73 -0
  17. package/src/adapter/vgai-scene-game-adapter.ts +239 -180
  18. package/src/animation/xstate-animation-binding.ts +300 -262
  19. package/src/animation/xstate-animation-meta.ts +50 -13
  20. package/src/character/cloth-sim.ts +533 -0
  21. package/src/character/spring-chain.ts +307 -0
  22. package/src/core/game-loop.ts +41 -3
  23. package/src/core/seeded-random.ts +161 -0
  24. package/src/core/system-runner.ts +20 -3
  25. package/src/core/types.ts +37 -0
  26. package/src/data/data-asset.ts +1 -1
  27. package/src/dev/performance-profiler.ts +213 -0
  28. package/src/dev/webgl-gpu-timer.ts +53 -0
  29. package/src/ecs/component-manager.ts +45 -12
  30. package/src/ecs/game-component.ts +95 -11
  31. package/src/humanoid/bake.operation.ts +326 -0
  32. package/src/humanoid/body.ts +663 -0
  33. package/src/humanoid/clips.ts +149 -0
  34. package/src/humanoid/compose.ts +209 -0
  35. package/src/humanoid/generate.ts +189 -0
  36. package/src/humanoid/index.ts +36 -0
  37. package/src/humanoid/schema.ts +108 -0
  38. package/src/humanoid/skeleton.ts +345 -0
  39. package/src/index.ts +5 -5
  40. package/src/input/input-manager.ts +701 -22
  41. package/src/input/input-types.ts +5 -2
  42. package/src/manifest/index.ts +5 -5
  43. package/src/manifest/load.ts +125 -72
  44. package/src/manifest/schema.ts +362 -255
  45. package/src/react/game-state.tsx +135 -32
  46. package/src/react/root-adapter.tsx +49 -0
  47. package/src/react/unmanaged-root-detector.ts +66 -0
  48. package/src/react/use-data.ts +12 -2
  49. package/src/runtime/create-runtime.ts +100 -282
  50. package/src/runtime/debug-bridge.ts +483 -0
  51. package/src/runtime/debug-registry.ts +856 -0
  52. package/src/runtime/game.ts +342 -93
  53. package/src/runtime/gameplay-rng-trap.ts +134 -0
  54. package/src/runtime/input-router.ts +7 -7
  55. package/src/runtime/mount-game.ts +40 -38
  56. package/src/runtime/mount-manifest.ts +169 -37
  57. package/src/runtime/render-control.ts +13 -13
  58. package/src/runtime/render-seed.ts +1 -1
  59. package/src/runtime/state-bridge.ts +24 -10
  60. package/src/runtime/types.ts +110 -28
  61. package/src/scene/asset-registry.ts +22 -0
  62. package/src/scene/component-registry.ts +14 -3
  63. package/src/scene/defaults.ts +1 -0
  64. package/src/scene/light-camera-factory.ts +11 -3
  65. package/src/scene/scene-apply.ts +55 -4
  66. package/src/scene/scene-loader.ts +10 -27
  67. package/src/scene/scene-types.ts +0 -1
  68. package/src/scene/schema/index.ts +0 -34
  69. package/src/scene/schema/light.ts +16 -1
  70. package/src/scene/schema/material.ts +96 -91
  71. package/src/scene/schema/scene-file.ts +1 -7
  72. package/src/scene/user-data.ts +14 -1
  73. package/src/setup/setup-renderer.ts +1 -1
  74. package/src/tools/define-tool.ts +50 -11
  75. package/src/world2d/authoring-2d.ts +17 -1
  76. package/src/world2d/collision-2d.ts +1 -1
  77. package/src/world2d/pixi-game-adapter.ts +19 -17
  78. package/src/world2d/scene2d-loader.ts +1 -0
  79. package/src/world2d/types.ts +8 -2
  80. package/dist/adapter/authoring.d.ts +0 -404
  81. package/dist/adapter/authoring.d.ts.map +0 -1
  82. package/dist/adapter/authoring.js +0 -22
  83. package/dist/adapter/colyseus-networking-adapter.d.ts +0 -43
  84. package/dist/adapter/colyseus-networking-adapter.d.ts.map +0 -1
  85. package/dist/adapter/colyseus-networking-adapter.js +0 -38
  86. package/dist/adapter/first-party-systems.d.ts +0 -38
  87. package/dist/adapter/first-party-systems.d.ts.map +0 -1
  88. package/dist/adapter/first-party-systems.js +0 -77
  89. package/dist/adapter/game-adapter.d.ts +0 -133
  90. package/dist/adapter/game-adapter.d.ts.map +0 -1
  91. package/dist/adapter/game-adapter.js +0 -10
  92. package/dist/adapter/host-context.d.ts +0 -73
  93. package/dist/adapter/host-context.d.ts.map +0 -1
  94. package/dist/adapter/host-context.js +0 -16
  95. package/dist/adapter/index.d.ts +0 -22
  96. package/dist/adapter/index.d.ts.map +0 -1
  97. package/dist/adapter/index.js +0 -15
  98. package/dist/adapter/ingest/game-contract.d.ts +0 -53
  99. package/dist/adapter/ingest/game-contract.d.ts.map +0 -1
  100. package/dist/adapter/ingest/game-contract.js +0 -30
  101. package/dist/adapter/ingest/overlay-applier.d.ts +0 -118
  102. package/dist/adapter/ingest/overlay-applier.d.ts.map +0 -1
  103. package/dist/adapter/ingest/overlay-applier.js +0 -132
  104. package/dist/adapter/ingest/overlay-apply.d.ts +0 -60
  105. package/dist/adapter/ingest/overlay-apply.d.ts.map +0 -1
  106. package/dist/adapter/ingest/overlay-apply.js +0 -101
  107. package/dist/adapter/ingest/overlay-file.d.ts +0 -79
  108. package/dist/adapter/ingest/overlay-file.d.ts.map +0 -1
  109. package/dist/adapter/ingest/overlay-file.js +0 -66
  110. package/dist/adapter/ingest/overlay-report.d.ts +0 -113
  111. package/dist/adapter/ingest/overlay-report.d.ts.map +0 -1
  112. package/dist/adapter/ingest/overlay-report.js +0 -103
  113. package/dist/adapter/ingest/scene-capture.d.ts +0 -97
  114. package/dist/adapter/ingest/scene-capture.d.ts.map +0 -1
  115. package/dist/adapter/ingest/scene-capture.js +0 -248
  116. package/dist/adapter/ingest/upstream-pin.d.ts +0 -47
  117. package/dist/adapter/ingest/upstream-pin.d.ts.map +0 -1
  118. package/dist/adapter/ingest/upstream-pin.js +0 -50
  119. package/dist/adapter/loop-gate-report.d.ts +0 -34
  120. package/dist/adapter/loop-gate-report.d.ts.map +0 -1
  121. package/dist/adapter/loop-gate-report.js +0 -37
  122. package/dist/adapter/rapier-physics-adapter.d.ts +0 -12
  123. package/dist/adapter/rapier-physics-adapter.d.ts.map +0 -1
  124. package/dist/adapter/rapier-physics-adapter.js +0 -46
  125. package/dist/adapter/system-adapter.d.ts +0 -133
  126. package/dist/adapter/system-adapter.d.ts.map +0 -1
  127. package/dist/adapter/system-adapter.js +0 -13
  128. package/dist/adapter/transform.d.ts +0 -18
  129. package/dist/adapter/transform.d.ts.map +0 -1
  130. package/dist/adapter/transform.js +0 -1
  131. package/dist/adapter/vgai-scene-game-adapter.d.ts +0 -116
  132. package/dist/adapter/vgai-scene-game-adapter.d.ts.map +0 -1
  133. package/dist/adapter/vgai-scene-game-adapter.js +0 -714
  134. package/dist/adapter/world-kind.d.ts +0 -30
  135. package/dist/adapter/world-kind.d.ts.map +0 -1
  136. package/dist/adapter/world-kind.js +0 -18
  137. package/dist/ai/navigation.d.ts +0 -64
  138. package/dist/ai/navigation.d.ts.map +0 -1
  139. package/dist/ai/navigation.js +0 -133
  140. package/dist/animation/anim-graph-types.d.ts +0 -25
  141. package/dist/animation/anim-graph-types.d.ts.map +0 -1
  142. package/dist/animation/anim-graph-types.js +0 -1
  143. package/dist/animation/animation-clock.d.ts +0 -213
  144. package/dist/animation/animation-clock.d.ts.map +0 -1
  145. package/dist/animation/animation-clock.js +0 -301
  146. package/dist/animation/blend-node.d.ts +0 -22
  147. package/dist/animation/blend-node.d.ts.map +0 -1
  148. package/dist/animation/blend-node.js +0 -97
  149. package/dist/animation/camera-ownership.d.ts +0 -250
  150. package/dist/animation/camera-ownership.d.ts.map +0 -1
  151. package/dist/animation/camera-ownership.js +0 -169
  152. package/dist/animation/cinematic-cues.d.ts +0 -200
  153. package/dist/animation/cinematic-cues.d.ts.map +0 -1
  154. package/dist/animation/cinematic-cues.js +0 -213
  155. package/dist/animation/clip-map.d.ts +0 -12
  156. package/dist/animation/clip-map.d.ts.map +0 -1
  157. package/dist/animation/clip-map.js +0 -37
  158. package/dist/animation/gsap-registration.d.ts +0 -119
  159. package/dist/animation/gsap-registration.d.ts.map +0 -1
  160. package/dist/animation/gsap-registration.js +0 -92
  161. package/dist/animation/theatre-clock-binding.d.ts +0 -89
  162. package/dist/animation/theatre-clock-binding.d.ts.map +0 -1
  163. package/dist/animation/theatre-clock-binding.js +0 -29
  164. package/dist/animation/theatre-director.d.ts +0 -242
  165. package/dist/animation/theatre-director.d.ts.map +0 -1
  166. package/dist/animation/theatre-director.js +0 -235
  167. package/dist/animation/theatre-object-binding.d.ts +0 -305
  168. package/dist/animation/theatre-object-binding.d.ts.map +0 -1
  169. package/dist/animation/theatre-object-binding.js +0 -351
  170. package/dist/animation/xstate-animation-binding.d.ts +0 -111
  171. package/dist/animation/xstate-animation-binding.d.ts.map +0 -1
  172. package/dist/animation/xstate-animation-binding.js +0 -307
  173. package/dist/animation/xstate-animation-meta.d.ts +0 -228
  174. package/dist/animation/xstate-animation-meta.d.ts.map +0 -1
  175. package/dist/animation/xstate-animation-meta.js +0 -221
  176. package/dist/assets.d.ts +0 -26
  177. package/dist/assets.d.ts.map +0 -1
  178. package/dist/assets.js +0 -55
  179. package/dist/audio/index.d.ts +0 -4
  180. package/dist/audio/index.d.ts.map +0 -1
  181. package/dist/audio/index.js +0 -24
  182. package/dist/audio/tone-clock-binding.d.ts +0 -75
  183. package/dist/audio/tone-clock-binding.d.ts.map +0 -1
  184. package/dist/audio/tone-clock-binding.js +0 -29
  185. package/dist/audio/tone-context.d.ts +0 -114
  186. package/dist/audio/tone-context.d.ts.map +0 -1
  187. package/dist/audio/tone-context.js +0 -39
  188. package/dist/audio/tone-offline-render.d.ts +0 -90
  189. package/dist/audio/tone-offline-render.d.ts.map +0 -1
  190. package/dist/audio/tone-offline-render.js +0 -56
  191. package/dist/audio/wav-encode.d.ts +0 -38
  192. package/dist/audio/wav-encode.d.ts.map +0 -1
  193. package/dist/audio/wav-encode.js +0 -97
  194. package/dist/core/game-loop.d.ts +0 -21
  195. package/dist/core/game-loop.d.ts.map +0 -1
  196. package/dist/core/game-loop.js +0 -130
  197. package/dist/core/system-runner.d.ts +0 -120
  198. package/dist/core/system-runner.d.ts.map +0 -1
  199. package/dist/core/system-runner.js +0 -286
  200. package/dist/core/types.d.ts +0 -58
  201. package/dist/core/types.d.ts.map +0 -1
  202. package/dist/core/types.js +0 -25
  203. package/dist/data/data-asset.d.ts +0 -101
  204. package/dist/data/data-asset.d.ts.map +0 -1
  205. package/dist/data/data-asset.js +0 -122
  206. package/dist/data/data-check-core.d.ts +0 -110
  207. package/dist/data/data-check-core.d.ts.map +0 -1
  208. package/dist/data/data-check-core.js +0 -178
  209. package/dist/data/data-ref.d.ts +0 -79
  210. package/dist/data/data-ref.d.ts.map +0 -1
  211. package/dist/data/data-ref.js +0 -130
  212. package/dist/data/vite-plugin-data.d.ts +0 -79
  213. package/dist/data/vite-plugin-data.d.ts.map +0 -1
  214. package/dist/data/vite-plugin-data.js +0 -217
  215. package/dist/dev/console-bridge.d.ts +0 -22
  216. package/dist/dev/console-bridge.d.ts.map +0 -1
  217. package/dist/dev/console-bridge.js +0 -71
  218. package/dist/dev/debug-draw.d.ts +0 -24
  219. package/dist/dev/debug-draw.d.ts.map +0 -1
  220. package/dist/dev/debug-draw.js +0 -73
  221. package/dist/dev/logger.d.ts +0 -30
  222. package/dist/dev/logger.d.ts.map +0 -1
  223. package/dist/dev/logger.js +0 -90
  224. package/dist/ecs/component-manager.d.ts +0 -189
  225. package/dist/ecs/component-manager.d.ts.map +0 -1
  226. package/dist/ecs/component-manager.js +0 -676
  227. package/dist/ecs/game-component.d.ts +0 -97
  228. package/dist/ecs/game-component.d.ts.map +0 -1
  229. package/dist/ecs/game-component.js +0 -80
  230. package/dist/ecs/hmr-swap-report.d.ts +0 -53
  231. package/dist/ecs/hmr-swap-report.d.ts.map +0 -1
  232. package/dist/ecs/hmr-swap-report.js +0 -55
  233. package/dist/index.d.ts +0 -37
  234. package/dist/index.d.ts.map +0 -1
  235. package/dist/index.js +0 -30
  236. package/dist/input/input-manager.d.ts +0 -596
  237. package/dist/input/input-manager.d.ts.map +0 -1
  238. package/dist/input/input-manager.js +0 -1564
  239. package/dist/input/input-types.d.ts +0 -171
  240. package/dist/input/input-types.d.ts.map +0 -1
  241. package/dist/input/input-types.js +0 -1
  242. package/dist/input/prompt-labels.d.ts +0 -21
  243. package/dist/input/prompt-labels.d.ts.map +0 -1
  244. package/dist/input/prompt-labels.js +0 -121
  245. package/dist/input/rebind-controller.d.ts +0 -59
  246. package/dist/input/rebind-controller.d.ts.map +0 -1
  247. package/dist/input/rebind-controller.js +0 -85
  248. package/dist/input/schema.d.ts +0 -16
  249. package/dist/input/schema.d.ts.map +0 -1
  250. package/dist/input/schema.js +0 -228
  251. package/dist/loader.d.ts +0 -43
  252. package/dist/loader.d.ts.map +0 -1
  253. package/dist/loader.js +0 -59
  254. package/dist/manifest/index.d.ts +0 -5
  255. package/dist/manifest/index.d.ts.map +0 -1
  256. package/dist/manifest/index.js +0 -8
  257. package/dist/manifest/load-file.d.ts +0 -4
  258. package/dist/manifest/load-file.d.ts.map +0 -1
  259. package/dist/manifest/load-file.js +0 -14
  260. package/dist/manifest/load.d.ts +0 -117
  261. package/dist/manifest/load.d.ts.map +0 -1
  262. package/dist/manifest/load.js +0 -255
  263. package/dist/manifest/schema.d.ts +0 -173
  264. package/dist/manifest/schema.d.ts.map +0 -1
  265. package/dist/manifest/schema.js +0 -302
  266. package/dist/physics/collision-system.d.ts +0 -41
  267. package/dist/physics/collision-system.d.ts.map +0 -1
  268. package/dist/physics/collision-system.js +0 -64
  269. package/dist/physics/physics-registry.d.ts +0 -45
  270. package/dist/physics/physics-registry.d.ts.map +0 -1
  271. package/dist/physics/physics-registry.js +0 -65
  272. package/dist/physics/transform-writer.d.ts +0 -16
  273. package/dist/physics/transform-writer.d.ts.map +0 -1
  274. package/dist/physics/transform-writer.js +0 -38
  275. package/dist/physics/trigger-dispatch.d.ts +0 -24
  276. package/dist/physics/trigger-dispatch.d.ts.map +0 -1
  277. package/dist/physics/trigger-dispatch.js +0 -80
  278. package/dist/react/game-state.d.ts +0 -105
  279. package/dist/react/game-state.d.ts.map +0 -1
  280. package/dist/react/game-state.js +0 -144
  281. package/dist/react/use-data.d.ts +0 -60
  282. package/dist/react/use-data.d.ts.map +0 -1
  283. package/dist/react/use-data.js +0 -96
  284. package/dist/react/use-selection.d.ts +0 -75
  285. package/dist/react/use-selection.d.ts.map +0 -1
  286. package/dist/react/use-selection.js +0 -90
  287. package/dist/render/auto-batcher.d.ts +0 -34
  288. package/dist/render/auto-batcher.d.ts.map +0 -1
  289. package/dist/render/auto-batcher.js +0 -140
  290. package/dist/render/render-batch-system.d.ts +0 -33
  291. package/dist/render/render-batch-system.d.ts.map +0 -1
  292. package/dist/render/render-batch-system.js +0 -230
  293. package/dist/render/render-features.d.ts +0 -47
  294. package/dist/render/render-features.d.ts.map +0 -1
  295. package/dist/render/render-features.js +0 -105
  296. package/dist/render/render-settings.d.ts +0 -36
  297. package/dist/render/render-settings.d.ts.map +0 -1
  298. package/dist/render/render-settings.js +0 -51
  299. package/dist/runtime/create-runtime.d.ts +0 -280
  300. package/dist/runtime/create-runtime.d.ts.map +0 -1
  301. package/dist/runtime/create-runtime.js +0 -795
  302. package/dist/runtime/frame-selector-cache.d.ts +0 -41
  303. package/dist/runtime/frame-selector-cache.d.ts.map +0 -1
  304. package/dist/runtime/frame-selector-cache.js +0 -65
  305. package/dist/runtime/game.d.ts +0 -433
  306. package/dist/runtime/game.d.ts.map +0 -1
  307. package/dist/runtime/game.js +0 -569
  308. package/dist/runtime/input-router.d.ts +0 -78
  309. package/dist/runtime/input-router.d.ts.map +0 -1
  310. package/dist/runtime/input-router.js +0 -171
  311. package/dist/runtime/mount-game.d.ts +0 -129
  312. package/dist/runtime/mount-game.d.ts.map +0 -1
  313. package/dist/runtime/mount-game.js +0 -152
  314. package/dist/runtime/mount-manifest.d.ts +0 -119
  315. package/dist/runtime/mount-manifest.d.ts.map +0 -1
  316. package/dist/runtime/mount-manifest.js +0 -204
  317. package/dist/runtime/render-audio-control.d.ts +0 -110
  318. package/dist/runtime/render-audio-control.d.ts.map +0 -1
  319. package/dist/runtime/render-audio-control.js +0 -111
  320. package/dist/runtime/render-control.d.ts +0 -291
  321. package/dist/runtime/render-control.d.ts.map +0 -1
  322. package/dist/runtime/render-control.js +0 -264
  323. package/dist/runtime/render-seed.d.ts +0 -57
  324. package/dist/runtime/render-seed.d.ts.map +0 -1
  325. package/dist/runtime/render-seed.js +0 -74
  326. package/dist/runtime/scene-ui-bridge.d.ts +0 -69
  327. package/dist/runtime/scene-ui-bridge.d.ts.map +0 -1
  328. package/dist/runtime/scene-ui-bridge.js +0 -23
  329. package/dist/runtime/scene-ui-data.d.ts +0 -13
  330. package/dist/runtime/scene-ui-data.d.ts.map +0 -1
  331. package/dist/runtime/scene-ui-data.js +0 -92
  332. package/dist/runtime/state-bridge.d.ts +0 -47
  333. package/dist/runtime/state-bridge.d.ts.map +0 -1
  334. package/dist/runtime/state-bridge.js +0 -53
  335. package/dist/runtime/types.d.ts +0 -179
  336. package/dist/runtime/types.d.ts.map +0 -1
  337. package/dist/runtime/types.js +0 -1
  338. package/dist/scene/asset-loaders.d.ts +0 -79
  339. package/dist/scene/asset-loaders.d.ts.map +0 -1
  340. package/dist/scene/asset-loaders.js +0 -141
  341. package/dist/scene/asset-paths.d.ts +0 -11
  342. package/dist/scene/asset-paths.d.ts.map +0 -1
  343. package/dist/scene/asset-paths.js +0 -108
  344. package/dist/scene/asset-ref-check.d.ts +0 -88
  345. package/dist/scene/asset-ref-check.d.ts.map +0 -1
  346. package/dist/scene/asset-ref-check.js +0 -214
  347. package/dist/scene/asset-registry.d.ts +0 -30
  348. package/dist/scene/asset-registry.d.ts.map +0 -1
  349. package/dist/scene/asset-registry.js +0 -50
  350. package/dist/scene/collider-dimensions.d.ts +0 -63
  351. package/dist/scene/collider-dimensions.d.ts.map +0 -1
  352. package/dist/scene/collider-dimensions.js +0 -98
  353. package/dist/scene/component-registry.d.ts +0 -17
  354. package/dist/scene/component-registry.d.ts.map +0 -1
  355. package/dist/scene/component-registry.js +0 -28
  356. package/dist/scene/defaults.d.ts +0 -252
  357. package/dist/scene/defaults.d.ts.map +0 -1
  358. package/dist/scene/defaults.js +0 -151
  359. package/dist/scene/geometries/index.d.ts +0 -8
  360. package/dist/scene/geometries/index.d.ts.map +0 -1
  361. package/dist/scene/geometries/index.js +0 -7
  362. package/dist/scene/geometries/terrain.d.ts +0 -2
  363. package/dist/scene/geometries/terrain.d.ts.map +0 -1
  364. package/dist/scene/geometries/terrain.js +0 -37
  365. package/dist/scene/geometry-registry.d.ts +0 -24
  366. package/dist/scene/geometry-registry.d.ts.map +0 -1
  367. package/dist/scene/geometry-registry.js +0 -20
  368. package/dist/scene/instance-registry.d.ts +0 -36
  369. package/dist/scene/instance-registry.d.ts.map +0 -1
  370. package/dist/scene/instance-registry.js +0 -55
  371. package/dist/scene/instancers/grid.d.ts +0 -2
  372. package/dist/scene/instancers/grid.d.ts.map +0 -1
  373. package/dist/scene/instancers/grid.js +0 -36
  374. package/dist/scene/instancers/index.d.ts +0 -8
  375. package/dist/scene/instancers/index.d.ts.map +0 -1
  376. package/dist/scene/instancers/index.js +0 -7
  377. package/dist/scene/light-camera-factory.d.ts +0 -23
  378. package/dist/scene/light-camera-factory.d.ts.map +0 -1
  379. package/dist/scene/light-camera-factory.js +0 -68
  380. package/dist/scene/material-factory.d.ts +0 -17
  381. package/dist/scene/material-factory.d.ts.map +0 -1
  382. package/dist/scene/material-factory.js +0 -197
  383. package/dist/scene/material-registry.d.ts +0 -40
  384. package/dist/scene/material-registry.d.ts.map +0 -1
  385. package/dist/scene/material-registry.js +0 -44
  386. package/dist/scene/materials/index.d.ts +0 -8
  387. package/dist/scene/materials/index.d.ts.map +0 -1
  388. package/dist/scene/materials/index.js +0 -7
  389. package/dist/scene/materials/water.d.ts +0 -2
  390. package/dist/scene/materials/water.d.ts.map +0 -1
  391. package/dist/scene/materials/water.js +0 -54
  392. package/dist/scene/parse.d.ts +0 -23
  393. package/dist/scene/parse.d.ts.map +0 -1
  394. package/dist/scene/parse.js +0 -179
  395. package/dist/scene/particles-factory.d.ts +0 -33
  396. package/dist/scene/particles-factory.d.ts.map +0 -1
  397. package/dist/scene/particles-factory.js +0 -282
  398. package/dist/scene/scene-apply.d.ts +0 -109
  399. package/dist/scene/scene-apply.d.ts.map +0 -1
  400. package/dist/scene/scene-apply.js +0 -326
  401. package/dist/scene/scene-diff-schema.d.ts +0 -285
  402. package/dist/scene/scene-diff-schema.d.ts.map +0 -1
  403. package/dist/scene/scene-diff-schema.js +0 -92
  404. package/dist/scene/scene-diff-types.d.ts +0 -40
  405. package/dist/scene/scene-diff-types.d.ts.map +0 -1
  406. package/dist/scene/scene-diff-types.js +0 -14
  407. package/dist/scene/scene-loader.d.ts +0 -177
  408. package/dist/scene/scene-loader.d.ts.map +0 -1
  409. package/dist/scene/scene-loader.js +0 -1213
  410. package/dist/scene/scene-query.d.ts +0 -11
  411. package/dist/scene/scene-query.d.ts.map +0 -1
  412. package/dist/scene/scene-query.js +0 -63
  413. package/dist/scene/scene-types.d.ts +0 -10
  414. package/dist/scene/scene-types.d.ts.map +0 -1
  415. package/dist/scene/scene-types.js +0 -8
  416. package/dist/scene/scene-version.d.ts +0 -26
  417. package/dist/scene/scene-version.d.ts.map +0 -1
  418. package/dist/scene/scene-version.js +0 -34
  419. package/dist/scene/schema/animation.d.ts +0 -8
  420. package/dist/scene/schema/animation.d.ts.map +0 -1
  421. package/dist/scene/schema/animation.js +0 -42
  422. package/dist/scene/schema/audio.d.ts +0 -13
  423. package/dist/scene/schema/audio.d.ts.map +0 -1
  424. package/dist/scene/schema/audio.js +0 -22
  425. package/dist/scene/schema/camera.d.ts +0 -28
  426. package/dist/scene/schema/camera.d.ts.map +0 -1
  427. package/dist/scene/schema/camera.js +0 -17
  428. package/dist/scene/schema/collider.d.ts +0 -40
  429. package/dist/scene/schema/collider.d.ts.map +0 -1
  430. package/dist/scene/schema/collider.js +0 -55
  431. package/dist/scene/schema/entity-ref.d.ts +0 -31
  432. package/dist/scene/schema/entity-ref.d.ts.map +0 -1
  433. package/dist/scene/schema/entity-ref.js +0 -61
  434. package/dist/scene/schema/entity.d.ts +0 -1036
  435. package/dist/scene/schema/entity.d.ts.map +0 -1
  436. package/dist/scene/schema/entity.js +0 -153
  437. package/dist/scene/schema/environment.d.ts +0 -425
  438. package/dist/scene/schema/environment.d.ts.map +0 -1
  439. package/dist/scene/schema/environment.js +0 -357
  440. package/dist/scene/schema/index.d.ts +0 -39
  441. package/dist/scene/schema/index.d.ts.map +0 -1
  442. package/dist/scene/schema/index.js +0 -20
  443. package/dist/scene/schema/instances.d.ts +0 -14
  444. package/dist/scene/schema/instances.d.ts.map +0 -1
  445. package/dist/scene/schema/instances.js +0 -28
  446. package/dist/scene/schema/joint.d.ts +0 -23
  447. package/dist/scene/schema/joint.d.ts.map +0 -1
  448. package/dist/scene/schema/joint.js +0 -23
  449. package/dist/scene/schema/light.d.ts +0 -38
  450. package/dist/scene/schema/light.d.ts.map +0 -1
  451. package/dist/scene/schema/light.js +0 -26
  452. package/dist/scene/schema/material.d.ts +0 -199
  453. package/dist/scene/schema/material.d.ts.map +0 -1
  454. package/dist/scene/schema/material.js +0 -99
  455. package/dist/scene/schema/mesh.d.ts +0 -48
  456. package/dist/scene/schema/mesh.d.ts.map +0 -1
  457. package/dist/scene/schema/mesh.js +0 -82
  458. package/dist/scene/schema/particles.d.ts +0 -2178
  459. package/dist/scene/schema/particles.d.ts.map +0 -1
  460. package/dist/scene/schema/particles.js +0 -321
  461. package/dist/scene/schema/physics.d.ts +0 -56
  462. package/dist/scene/schema/physics.d.ts.map +0 -1
  463. package/dist/scene/schema/physics.js +0 -37
  464. package/dist/scene/schema/scene-file.d.ts +0 -304
  465. package/dist/scene/schema/scene-file.d.ts.map +0 -1
  466. package/dist/scene/schema/scene-file.js +0 -262
  467. package/dist/scene/schema/shadow.d.ts +0 -28
  468. package/dist/scene/schema/shadow.d.ts.map +0 -1
  469. package/dist/scene/schema/shadow.js +0 -20
  470. package/dist/scene/schema/spline.d.ts +0 -25
  471. package/dist/scene/schema/spline.d.ts.map +0 -1
  472. package/dist/scene/schema/spline.js +0 -15
  473. package/dist/scene/schema/tuples.d.ts +0 -12
  474. package/dist/scene/schema/tuples.d.ts.map +0 -1
  475. package/dist/scene/schema/tuples.js +0 -14
  476. package/dist/scene/schema/ui.d.ts +0 -880
  477. package/dist/scene/schema/ui.d.ts.map +0 -1
  478. package/dist/scene/schema/ui.js +0 -506
  479. package/dist/scene/user-data.d.ts +0 -171
  480. package/dist/scene/user-data.d.ts.map +0 -1
  481. package/dist/scene/user-data.js +0 -137
  482. package/dist/setup/setup-audio.d.ts +0 -20
  483. package/dist/setup/setup-audio.d.ts.map +0 -1
  484. package/dist/setup/setup-audio.js +0 -41
  485. package/dist/setup/setup-particles.d.ts +0 -17
  486. package/dist/setup/setup-particles.d.ts.map +0 -1
  487. package/dist/setup/setup-particles.js +0 -16
  488. package/dist/setup/setup-physics.d.ts +0 -25
  489. package/dist/setup/setup-physics.d.ts.map +0 -1
  490. package/dist/setup/setup-physics.js +0 -51
  491. package/dist/setup/setup-renderer.d.ts +0 -69
  492. package/dist/setup/setup-renderer.d.ts.map +0 -1
  493. package/dist/setup/setup-renderer.js +0 -363
  494. package/dist/tools/define-tool.d.ts +0 -105
  495. package/dist/tools/define-tool.d.ts.map +0 -1
  496. package/dist/tools/define-tool.js +0 -82
  497. package/dist/world2d/authoring-2d.d.ts +0 -76
  498. package/dist/world2d/authoring-2d.d.ts.map +0 -1
  499. package/dist/world2d/authoring-2d.js +0 -176
  500. package/dist/world2d/capture-to-scene2d.d.ts +0 -5
  501. package/dist/world2d/capture-to-scene2d.d.ts.map +0 -1
  502. package/dist/world2d/capture-to-scene2d.js +0 -49
  503. package/dist/world2d/collision-2d.d.ts +0 -52
  504. package/dist/world2d/collision-2d.d.ts.map +0 -1
  505. package/dist/world2d/collision-2d.js +0 -70
  506. package/dist/world2d/components-2d.d.ts +0 -47
  507. package/dist/world2d/components-2d.d.ts.map +0 -1
  508. package/dist/world2d/components-2d.js +0 -77
  509. package/dist/world2d/index.d.ts +0 -34
  510. package/dist/world2d/index.d.ts.map +0 -1
  511. package/dist/world2d/index.js +0 -32
  512. package/dist/world2d/ingest-iframe-2d.d.ts +0 -82
  513. package/dist/world2d/ingest-iframe-2d.d.ts.map +0 -1
  514. package/dist/world2d/ingest-iframe-2d.js +0 -166
  515. package/dist/world2d/ingest2d.d.ts +0 -97
  516. package/dist/world2d/ingest2d.d.ts.map +0 -1
  517. package/dist/world2d/ingest2d.js +0 -40
  518. package/dist/world2d/physics2d-registry.d.ts +0 -24
  519. package/dist/world2d/physics2d-registry.d.ts.map +0 -1
  520. package/dist/world2d/physics2d-registry.js +0 -38
  521. package/dist/world2d/pixi-game-adapter.d.ts +0 -107
  522. package/dist/world2d/pixi-game-adapter.d.ts.map +0 -1
  523. package/dist/world2d/pixi-game-adapter.js +0 -211
  524. package/dist/world2d/pixi-surface.d.ts +0 -39
  525. package/dist/world2d/pixi-surface.d.ts.map +0 -1
  526. package/dist/world2d/pixi-surface.js +0 -47
  527. package/dist/world2d/scene-capture-2d.d.ts +0 -43
  528. package/dist/world2d/scene-capture-2d.d.ts.map +0 -1
  529. package/dist/world2d/scene-capture-2d.js +0 -92
  530. package/dist/world2d/scene2d-loader.d.ts +0 -27
  531. package/dist/world2d/scene2d-loader.d.ts.map +0 -1
  532. package/dist/world2d/scene2d-loader.js +0 -274
  533. package/dist/world2d/schema/entity2d.d.ts +0 -102
  534. package/dist/world2d/schema/entity2d.d.ts.map +0 -1
  535. package/dist/world2d/schema/entity2d.js +0 -119
  536. package/dist/world2d/schema/physics2d.d.ts +0 -46
  537. package/dist/world2d/schema/physics2d.d.ts.map +0 -1
  538. package/dist/world2d/schema/physics2d.js +0 -45
  539. package/dist/world2d/schema/sprite.d.ts +0 -42
  540. package/dist/world2d/schema/sprite.d.ts.map +0 -1
  541. package/dist/world2d/schema/sprite.js +0 -63
  542. package/dist/world2d/schema/tilemap.d.ts +0 -15
  543. package/dist/world2d/schema/tilemap.d.ts.map +0 -1
  544. package/dist/world2d/schema/tilemap.js +0 -19
  545. package/dist/world2d/schema/tuples2d.d.ts +0 -20
  546. package/dist/world2d/schema/tuples2d.d.ts.map +0 -1
  547. package/dist/world2d/schema/tuples2d.js +0 -19
  548. package/dist/world2d/system-adapters-2d.d.ts +0 -16
  549. package/dist/world2d/system-adapters-2d.d.ts.map +0 -1
  550. package/dist/world2d/system-adapters-2d.js +0 -37
  551. package/dist/world2d/transform-writer-2d.d.ts +0 -16
  552. package/dist/world2d/transform-writer-2d.d.ts.map +0 -1
  553. package/dist/world2d/transform-writer-2d.js +0 -22
  554. package/dist/world2d/types.d.ts +0 -53
  555. package/dist/world2d/types.d.ts.map +0 -1
  556. package/dist/world2d/types.js +0 -1
  557. package/src/runtime/scene-ui-bridge.ts +0 -86
  558. package/src/runtime/scene-ui-data.ts +0 -119
  559. package/src/scene/schema/ui.ts +0 -602
@@ -1,4 +1,5 @@
1
1
  import * as THREE from 'three';
2
+ import { assertNever } from '../adapter/adapter-surface';
2
3
  import type {
3
4
  GameAdapter,
4
5
  MountedGame,
@@ -6,8 +7,6 @@ import type {
6
7
  MountedWorld,
7
8
  } from '../adapter/game-adapter';
8
9
  import type { HostContext, LoopHandle } from '../adapter/host-context';
9
- import { type VgaiSceneConfig, VgaiSceneGameAdapter } from '../adapter/vgai-scene-game-adapter';
10
- import { assertNever } from '../adapter/world-kind';
11
10
  import { createAssetCache } from '../assets';
12
11
  import { createGameLoop } from '../core/game-loop';
13
12
  import { createHostRenderer } from '../setup/setup-renderer';
@@ -25,7 +24,7 @@ import {
25
24
  isFirstPartyMounted,
26
25
  type WorldInstance,
27
26
  } from './game';
28
- import { createInputRouter, type RouterWorldEntry, stackOrder } from './input-router';
27
+ import { createInputRouter, type RouterAdapterRoot, stackOrder } from './input-router';
29
28
 
30
29
  // Re-export the camera-precedence helper from its new home so existing importers
31
30
  // (`import { adoptSceneCamera } from '@engine/runtime/create-runtime'`) keep working.
@@ -35,7 +34,7 @@ export { adoptSceneCamera } from '../adapter/vgai-scene-game-adapter';
35
34
  * Register a threejs world for a freshly-mounted game onto the Game shell.
36
35
  * Shared by `createGameRuntime` and every headless test harness
37
36
  * (`test/game-root.test.ts`, `test/frame-order.test.ts`,
38
- * `test/game-two-worlds.test.ts`) so there is exactly one code path for this
37
+ * `test/game-two-roots.test.ts`) so there is exactly one code path for this
39
38
  * wiring (T7.1 slice 1, id-generalized in slice 3 for the two-world proof —
40
39
  * `docs/GAME-ROOT-DESIGN.md` §8 stage 3) — `physics`/`collisions`/`camera`/
41
40
  * `frame` are populated from the mount's first-party `GameContext`/
@@ -94,25 +93,14 @@ export function registerThreeWorld(
94
93
  return world;
95
94
  }
96
95
 
97
- /** Thin alias kept for existing single-world callers (`createGameRuntime`,
98
- * `test/game-root.test.ts`, `test/frame-order.test.ts`) — registers the
99
- * default `'main'` world via the SAME `registerThreeWorld` code path. */
100
- export function registerDefaultThreeWorld(
101
- game: GameInternal,
102
- adapter: GameAdapter,
103
- mounted: MountedGame,
104
- ): WorldInstance {
105
- return registerThreeWorld(game, adapter, mounted);
106
- }
107
-
108
96
  /**
109
97
  * Register a pixijs world onto the Game shell — the pixi analog of
110
98
  * {@link registerThreeWorld}, mirroring the wiring
111
99
  * `world2d/pixi-game-adapter.ts`'s `createWorld2DRuntime` performs for its
112
100
  * OWN (separate) Game, and `test/game-three-plus-pixi.test.ts` performs by
113
- * hand onto a SHARED Game. `createGameRuntime`'s worlds path
101
+ * hand onto a SHARED Game. `createGameRuntime`'s roots path
114
102
  * (T6.1 slice 1) is the first PRODUCTION caller that registers a pixijs
115
- * world alongside other worlds on one Game; this is its one wiring code
103
+ * world alongside other roots on one Game; this is its one wiring code
116
104
  * path, so a second/third pixijs world (or a future caller) never
117
105
  * re-derives it. `adapter` is typed as the real {@link Pixi2DGameAdapter}
118
106
  * shape (T7.5 — previously the generic `GameAdapter`, which forced a cast at
@@ -132,7 +120,7 @@ export function registerDefaultThreeWorld(
132
120
  * only via `adapter as unknown as Pixi2DGameAdapter` (a custom module's actual
133
121
  * return value is merely `MountedPixiWorld`-shaped, T7.5's cross-kind union),
134
122
  * so the "never actually fire" premise no longer holds the moment a custom
135
- * pixi module world reaches the worlds path. Rather than keep the throw (which
123
+ * pixi module world reaches the roots path. Rather than keep the throw (which
136
124
  * would re-create exactly the kind of dead end D-X6 named and D-Y1 exists to
137
125
  * remove), this now degrades EXACTLY like `registerThreeWorld`'s own foreign-
138
126
  * mount handling above (`firstPartyExtras`): `physics2d`/`collisions2d`/
@@ -194,13 +182,13 @@ export function registerPixiWorld(
194
182
  * its commits; `GameInternal.runFrame` correctly leaves a world with no
195
183
  * `frame` untouched by its opaque-`update` fallback too, since
196
184
  * `MountedReactGame` declares no `update`). `adapter` is typed as the real
197
- * {@link ReactWorldAdapter} shape (T7.5, same reasoning as
185
+ * {@link ReactRootAdapter} shape (T7.5, same reasoning as
198
186
  * `registerPixiWorld`'s doc comment above) — `WorldInstance.adapter` only
199
187
  * needs `.id`, so this passes through with zero cast.
200
188
  */
201
189
  export function registerReactWorld(
202
190
  game: GameInternal,
203
- adapter: ReactWorldAdapter,
191
+ adapter: ReactRootAdapter,
204
192
  mounted: MountedReactGame,
205
193
  container: HTMLElement,
206
194
  opts?: { id?: string | undefined; pausable?: boolean | undefined },
@@ -217,28 +205,6 @@ export function registerReactWorld(
217
205
  return world;
218
206
  }
219
207
 
220
- /**
221
- * Configuration for {@link createGameRuntime}.
222
- *
223
- * The host depends on a {@link GameAdapter}. For convenience, the legacy
224
- * first-party fields (`setup`/`scenePath`/`sceneData`/…) are accepted and wrapped
225
- * in a {@link VgaiSceneGameAdapter} when no explicit `adapter` is given — so the
226
- * host's default implementer is first-party, but the host itself only ever
227
- * mounts "a GameAdapter".
228
- *
229
- * This is the LEGACY (single-world) shape — preserved byte-for-byte (T6.1
230
- * slice 1, docs/MULTI-WORLD-DESIGN.md §1.A): every existing caller and test
231
- * passes this shape unmodified. See {@link WorldsRuntimeConfig} for the new
232
- * multi-world alternative and {@link RuntimeConfig} for the union.
233
- */
234
- export interface LegacyRuntimeConfig extends VgaiSceneConfig {
235
- canvas: HTMLCanvasElement;
236
- width?: number | undefined;
237
- height?: number | undefined;
238
- /** An explicit game adapter to mount (first-party OR external). */
239
- adapter?: GameAdapter | undefined;
240
- }
241
-
242
208
  /**
243
209
  * A pixijs-shaped adapter — the structural contract `WorldMountSpec`'s
244
210
  * `pixijs` variant requires. `PixiSceneGameAdapter` (`world2d/
@@ -252,17 +218,17 @@ export interface Pixi2DGameAdapter {
252
218
  }
253
219
 
254
220
  /**
255
- * One world to mount in the {@link WorldsRuntimeConfig} worlds path (T6.1
221
+ * One world to mount in the {@link WorldsRuntimeConfig} roots path (T6.1
256
222
  * slice 1) — the host-facing mirror of `manifest/load.ts`'s
257
- * `ResolvedWorldEntry` (same `id`/`zOrder`/`pausable`/`loop` fields; the
223
+ * `ResolvedAdapterRoot` (same `id`/`zOrder`/`pausable`/`loop` fields; the
258
224
  * manifest-to-host translation itself is the editor's job, not this file's).
259
225
  *
260
226
  * `react` (T6.2 slice 1, `docs/REACT-WORLD-DESIGN.md`) mounts as a DOM-root
261
227
  * layer `<div>` in the SAME stack instead of a canvas — see
262
- * {@link ReactWorldMountSpec}/{@link ReactWorldAdapter} below.
228
+ * {@link ReactWorldMountSpec}/{@link ReactRootAdapter} below.
263
229
  */
264
230
  export interface WorldMountSpecBase {
265
- /** Manifest id — must be unique within one `worlds` array. */
231
+ /** Manifest id — must be unique within one `roots` array. */
266
232
  readonly id: string;
267
233
  /** Canvas stacking order (COMPOSITION-DESIGN D5 §1); ties broken by array
268
234
  * order, mirroring `manifest/load.ts`'s `loadGameManifest` sort. Defaults
@@ -272,7 +238,7 @@ export interface WorldMountSpecBase {
272
238
  readonly pausable?: boolean | undefined;
273
239
  /** `'gated'` (host-driven, default) or `'self-driven'` (this world drives
274
240
  * its own loop — D5's "composited, unsynchronized" tier). Carried through
275
- * for parity with `ResolvedWorldEntry`; T6.1 slice 1 does not yet
241
+ * for parity with `ResolvedAdapterRoot`; T6.1 slice 1 does not yet
276
242
  * validate it against the mounted adapter's actual `drivesOwnLoop` (that
277
243
  * cross-check, if ever needed, is T7.6's loop-gate surface). */
278
244
  readonly loop?: 'gated' | 'self-driven' | undefined;
@@ -300,7 +266,7 @@ export interface PixiWorldMountSpec extends WorldMountSpecBase {
300
266
  }
301
267
 
302
268
  /**
303
- * The host-facing surface handed to a {@link ReactWorldAdapter}'s `mount`
269
+ * The host-facing surface handed to a {@link ReactRootAdapter}'s `mount`
304
270
  * (T6.2 slice 1, `docs/REACT-WORLD-DESIGN.md` §1.B) — the react analog of
305
271
  * {@link World2DHost}. `container` is the absolutely-positioned, z-ordered
306
272
  * DOM-root layer `<div>` the host already created and stacked (same box/
@@ -334,7 +300,7 @@ export interface ReactWorldHost {
334
300
 
335
301
  /**
336
302
  * A live, mounted react world (T6.2 slice 1) — the react analog of
337
- * {@link MountedGame2D}. React worlds host no ticking components (D8 —
303
+ * {@link MountedGame2D}. React roots host no ticking components (D8 —
338
304
  * `ecs/component-manager.ts` already throws on any attach to a react-kind
339
305
  * manager) and render from game state via the T7.4 bridge instead of a
340
306
  * per-frame `update`, so this shape carries no `update`/`fixedUpdate`/
@@ -361,7 +327,7 @@ export interface ReactWorldHost {
361
327
  * game-adapter.ts`) — `container` is the SAME `ReactWorldHost.container` the
362
328
  * adapter's `mount` was handed (identity matters, mirroring `threeRoot()`/
363
329
  * `pixiRoot()`'s "same instance the adapter mounted" contract); every
364
- * `ReactWorldAdapter` implementer echoes it back here so `mounted` alone
330
+ * `ReactRootAdapter` implementer echoes it back here so `mounted` alone
365
331
  * (with no separately-threaded `container`) satisfies the union
366
332
  * `WorldInstanceInit.mounted`/`WorldInstance.mounted` with zero cast.
367
333
  */
@@ -376,35 +342,30 @@ export interface MountedReactGame extends MountedReactWorld {
376
342
  * `default-react` resolver branch, T6.2's editor-side follow-up) can satisfy
377
343
  * this shape without this file importing react-dom or any editor code.
378
344
  */
379
- export interface ReactWorldAdapter {
345
+ export interface ReactRootAdapter {
380
346
  readonly id: string;
381
347
  mount(host: ReactWorldHost): Promise<MountedReactGame>;
382
348
  }
383
349
 
384
350
  export interface ReactWorldMountSpec extends WorldMountSpecBase {
385
351
  readonly kind: 'react';
386
- readonly adapter: ReactWorldAdapter;
352
+ readonly adapter: ReactRootAdapter;
387
353
  }
388
354
 
389
355
  export type WorldMountSpec = ThreeWorldMountSpec | PixiWorldMountSpec | ReactWorldMountSpec;
390
356
 
391
357
  /**
392
- * The NEW multi-world alternative to {@link LegacyRuntimeConfig} (T6.1 slice
393
- * 1, docs/MULTI-WORLD-DESIGN.md §1.A; react worlds T6.2 slice 1,
394
- * docs/REACT-WORLD-DESIGN.md §1.B): mount N worlds (threejs + pixijs + react)
358
+ * Mount N adapter roots (threejs + pixijs + react)
395
359
  * on ONE `Game`, stacked in `container` per COMPOSITION-DESIGN D5 §1.
396
- * Internally the legacy signature maps to a one-element worlds list —
397
- * `worlds[0]` (by `Game.defaultWorld`'s existing "first threejs world, else
398
- * first world" rule) is the default world, so
399
- * `GameSession.scene`/`.camera`/`.mounted` keep aliasing exactly as they do
400
- * today.
360
+ * `roots[0]` participates in `Game.defaultWorld`'s existing "first threejs
361
+ * root, else first root" rule.
401
362
  */
402
363
  export interface WorldsRuntimeConfig {
403
364
  /** The host creates one absolutely-positioned surface per world inside
404
365
  * this element (D5 §1) — a canvas for threejs/pixijs, a DOM-root `<div>`
405
366
  * layer for react — plus one shared UI overlay above all of them. */
406
367
  container: HTMLElement;
407
- worlds: WorldMountSpec[];
368
+ roots: WorldMountSpec[];
408
369
  width?: number | undefined;
409
370
  height?: number | undefined;
410
371
  /**
@@ -412,18 +373,20 @@ export interface WorldsRuntimeConfig {
412
373
  * real `WebGLRenderer` construction for every threejs world in this
413
374
  * session (a stand-in renderer is used instead, exactly as
414
375
  * `VgaiSceneGameAdapter.mount` already special-cases `host.headless`
415
- * internally). Pixijs worlds are unaffected — Pixi already falls back to
376
+ * internally). Pixijs roots are unaffected — Pixi already falls back to
416
377
  * a 2D canvas renderer with no GPU. Never set `true` in a real host.
417
378
  */
418
379
  headless?: boolean | undefined;
419
- }
420
-
421
- /** The full config union `createGameRuntime` accepts — the legacy
422
- * single-`{canvas, adapter}` shape, or the new worlds path. */
423
- export type RuntimeConfig = LegacyRuntimeConfig | WorldsRuntimeConfig;
424
-
425
- function isWorldsConfig(config: RuntimeConfig): config is WorldsRuntimeConfig {
426
- return 'worlds' in config;
380
+ /** D15 (T-D15.1) — the root seed `ctx.random` boots from on every world
381
+ * mounted onto this session's Game, forwarded to `createGame` BEFORE any
382
+ * world's `mount()`/`setup()` runs (this function constructs the Game
383
+ * first — see `createWorldsGameRuntime`). The manifest-aware boot path
384
+ * (`mount-manifest.ts`'s `mountManifestWorlds`) is the real caller that
385
+ * resolves this from `manifest.determinism`/`?vgai-seed=`/its own
386
+ * explicit-config leg; a caller building `WorldsRuntimeConfig` by hand
387
+ * (a test, a bespoke host) may also set it directly. Omitting it falls
388
+ * back to `createGame`'s own fixed default. */
389
+ seed?: number | undefined;
427
390
  }
428
391
 
429
392
  /**
@@ -434,9 +397,8 @@ function isWorldsConfig(config: RuntimeConfig): config is WorldsRuntimeConfig {
434
397
  * warm-restart hot reload) are reached by casting `mounted` to `VgaiMountedGame`
435
398
  * (the editor does this for HMR/physics-sync — those are inherently first-party).
436
399
  *
437
- * `scene`/`camera`/`mounted` alias the Game's `defaultWorld` (T6.1 slice 1):
438
- * for the legacy single-world path this is the only world, byte-identical to
439
- * before; for the worlds path it is the first threejs world (else the first
400
+ * `scene`/`camera`/`mounted` alias the Game's `defaultWorld`: it is the first
401
+ * threejs root (else the first
440
402
  * world) by DECLARATION order, per `Game.defaultWorld`'s existing rule —
441
403
  * independent of `zOrder`/canvas stacking, which is a rendering-only concern.
442
404
  */
@@ -451,7 +413,7 @@ export interface GameSession {
451
413
  /** The mounted game (interface surface). Cast to `VgaiMountedGame` for first-party extras. */
452
414
  readonly mounted: MountedGame;
453
415
  /** The Game root (T6.1 slice 1) — the multi-world entry point
454
- * (`game.worlds`/`game.world(id)`/`game.queryByComponent`) for callers
416
+ * (`game.roots`/`game.world(id)`/`game.queryByComponent`) for callers
455
417
  * that need more than the default-world aliases above. */
456
418
  readonly game: Game;
457
419
  }
@@ -459,156 +421,12 @@ export interface GameSession {
459
421
  /**
460
422
  * Bootstrap the game host and mount a game adapter.
461
423
  *
462
- * `createGameRuntime` is the HOST: it owns the canvas/renderer(s), the loop,
463
- * the UI overlay, and the asset cache, and it mounts a {@link GameAdapter}
464
- * (or several, via the worlds path — T6.1 slice 1) against that context. It
465
- * knows nothing about `.vscn`, `GameComponent`, Rapier, or `GameSetupFn` —
466
- * those live inside the first-party {@link VgaiSceneGameAdapter}, which is
467
- * the default implementer when no explicit `adapter` is supplied on the
468
- * legacy path. Dispatches on `config`'s shape: {@link WorldsRuntimeConfig}
469
- * (`worlds` present) goes through {@link createWorldsGameRuntime};
470
- * everything else is the byte-compatible legacy single-world path.
424
+ * `createGameRuntime` is the universal HOST: it owns the root surfaces,
425
+ * renderers, loop, and asset cache. Every game — including a one-root game —
426
+ * uses the same explicit adapter-root path.
471
427
  */
472
- export async function createGameRuntime(config: RuntimeConfig): Promise<GameSession> {
473
- if (isWorldsConfig(config)) {
474
- return createWorldsGameRuntime(config);
475
- }
476
- const { canvas, width, height, adapter, ...sceneConfig } = config;
477
- const w = Math.max(1, width ?? canvas.width);
478
- const h = Math.max(1, height ?? canvas.height);
479
-
480
- // --- Host primitives (neutral — no first-party assumptions) ---
481
- const renderer = createHostRenderer(canvas, w, h);
482
- const assets = createAssetCache();
483
-
484
- let uiContainer: HTMLDivElement;
485
- const existingUi = document.getElementById('example-ui');
486
- if (existingUi instanceof HTMLDivElement) {
487
- uiContainer = existingUi;
488
- } else {
489
- uiContainer = document.createElement('div');
490
- uiContainer.id = 'example-ui';
491
- uiContainer.style.cssText =
492
- 'position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:2;';
493
- (canvas.parentElement ?? document.getElementById('ui-overlay') ?? document.body).appendChild(
494
- uiContainer,
495
- );
496
- }
497
-
498
- const extraUpdaters = new Set<(dt: number) => void>();
499
- const loopHandle: LoopHandle = {
500
- onUpdate(fn) {
501
- extraUpdaters.add(fn);
502
- return () => extraUpdaters.delete(fn);
503
- },
504
- };
505
-
506
- // --- Game root (T7.1 slice 1 + slice 2) ---
507
- // The loop's update callback used to close directly over `mounted`, which
508
- // only exists after `game.mount(host)` resolves. The Game shell (and thus
509
- // its `loop`) must exist BEFORE mount so the mount can see `host.game` — so
510
- // the callback instead consults a mutable ref, set once mount resolves.
511
- // Behavior is identical: `loop.start()` still only runs after mount, same
512
- // pause/step/stop semantics below. `drivesOwnLoop` handling now lives
513
- // INSIDE `game.runFrame` (T7.1 slice 2) rather than being checked here —
514
- // for today's single first-party (or single opaque host-driven) world this
515
- // is byte-identical to the old `if (!mountedRef.drivesOwnLoop) mountedRef
516
- // .update?.(dt)` guard (see `runFrame`'s doc comment in `runtime/game.ts`).
517
- // `game` is referenced here before its `const` below only textually — this
518
- // closure isn't invoked until `loop.start()`, well after `game` exists.
519
- let mountedRef: MountedGame | null = null;
520
- const loop = createGameLoop({
521
- fixedTimestep: 1 / 60,
522
- maxSubSteps: 8,
523
- update: (dt) => {
524
- if (mountedRef) game.runFrame(dt);
525
- for (const fn of extraUpdaters) fn(dt);
526
- },
527
- });
528
- const game = createGame({ loop, assets });
529
-
530
- const host: HostContext = {
531
- three: THREE,
532
- surface: { canvas, width: w, height: h },
533
- renderer,
534
- loop: loopHandle,
535
- assets,
536
- ui: uiContainer,
537
- game,
538
- requestSystem: () => null,
539
- };
540
-
541
- // --- Mount the game adapter (first-party default, or an explicit adapter) ---
542
- const gameAdapter = adapter ?? new VgaiSceneGameAdapter(sceneConfig);
543
- const mounted = await gameAdapter.mount(host);
544
- mountedRef = mounted;
545
-
546
- // Register the default (and, in this slice, only) threejs world now that
547
- // mount has produced a MountedGame — the world's `threeRoot()` must return
548
- // the SAME scene instance the adapter mounted (identity is the contract).
549
- registerDefaultThreeWorld(game, gameAdapter, mounted);
550
-
551
- // Expose scene & camera for dev tools / e2e tests
552
- if (import.meta.env?.DEV) {
553
- const w = window as unknown as Record<string, unknown>;
554
- w['__vgaiScene'] = mounted.scene;
555
- w['__vgaiCamera'] = mounted.camera;
556
- }
557
-
558
- loop.start();
559
-
560
- function fullCleanup(): void {
561
- loop.stop();
562
- mounted.dispose();
563
- renderer.dispose();
564
- renderer.forceContextLoss();
565
- // Retract the dev/e2e globals THIS session published (identity-guarded so
566
- // a newer session's globals are never clobbered by an older session's
567
- // stop). Leaving them dangling let e2e waits pass vacuously against a
568
- // stopped game's scene/camera.
569
- if (import.meta.env?.DEV) {
570
- const w = window as unknown as Record<string, unknown>;
571
- if (w['__vgaiScene'] === mounted.scene) delete w['__vgaiScene'];
572
- if (w['__vgaiCamera'] === mounted.camera) delete w['__vgaiCamera'];
573
- }
574
- }
575
-
576
- return {
577
- stop: fullCleanup,
578
- // D10/T7.6: `Game.play` (`runtime/game.ts`) is the real control surface —
579
- // it fans out over every `pausable` world (just the one default world on
580
- // this legacy single-world path) via its loop-gate/audio-gate capability,
581
- // reporting honestly wherever a world can't actually be gated, and keeps
582
- // `render` running every substep while paused (the old `loop.timeScale =
583
- // 0` here starved the accumulator entirely — per D1, zero substeps means
584
- // zero renders too — which is the bug this replaces, not a behavior to
585
- // preserve).
586
- pause() {
587
- game.play.pause();
588
- },
589
- resume() {
590
- game.play.resume();
591
- },
592
- step() {
593
- game.play.step();
594
- },
595
- resize(rw: number, rh: number) {
596
- const safeWidth = Math.max(1, rw);
597
- const safeHeight = Math.max(1, rh);
598
- renderer.setSize(safeWidth, safeHeight);
599
- mounted.resize?.(safeWidth, safeHeight);
600
- },
601
- get scene() {
602
- return mounted.scene as THREE.Scene;
603
- },
604
- get camera() {
605
- return mounted.camera as THREE.PerspectiveCamera;
606
- },
607
- get mounted() {
608
- return mounted;
609
- },
610
- game,
611
- };
428
+ export async function createGameRuntime(config: WorldsRuntimeConfig): Promise<GameSession> {
429
+ return createWorldsGameRuntime(config);
612
430
  }
613
431
 
614
432
  // ---------------------------------------------------------------------------
@@ -616,7 +434,7 @@ export async function createGameRuntime(config: RuntimeConfig): Promise<GameSess
616
434
  // ---------------------------------------------------------------------------
617
435
 
618
436
  /** A stand-in `THREE.WebGLRenderer` for headless (`headless:true`) threejs
619
- * worlds — mirrors `VgaiSceneGameAdapter.mount`'s own `headlessComposer`
437
+ * roots — mirrors `VgaiSceneGameAdapter.mount`'s own `headlessComposer`
620
438
  * pattern (`adapter/vgai-scene-game-adapter.ts`): a headless first-party
621
439
  * mount never calls a render-phase method on `host.renderer` at all, so
622
440
  * this only needs to satisfy the handful of calls THIS file itself makes
@@ -656,11 +474,26 @@ function derivePixiHitTest(
656
474
  ): ((x: number, y: number) => boolean) | undefined {
657
475
  if ((mounted as { firstParty?: unknown }).firstParty !== true) return undefined;
658
476
  const app = (mounted.ctx as unknown as { app?: unknown }).app as
659
- | { renderer?: { events?: { rootBoundary?: { hitTest?: (x: number, y: number) => unknown } } } }
477
+ | {
478
+ renderer?: {
479
+ events?: {
480
+ rootBoundary?: {
481
+ rootTarget?: unknown;
482
+ hitTest?: (x: number, y: number) => unknown;
483
+ };
484
+ };
485
+ };
486
+ }
660
487
  | undefined;
661
488
  const rootBoundary = app?.renderer?.events?.rootBoundary;
662
489
  if (!rootBoundary || typeof rootBoundary.hitTest !== 'function') return undefined;
663
- return (x: number, y: number) => rootBoundary.hitTest!(x, y) != null;
490
+ // Pixi assigns `rootTarget` lazily on the first render. Pointer movement
491
+ // can reach the host router during that small window (or while a world is
492
+ // tearing down); EventBoundary.hitTest dereferences it unconditionally.
493
+ // An unready boundary cannot claim input, so degrade to no hit instead of
494
+ // surfacing Pixi's internal `undefined.eventMode` exception.
495
+ return (x: number, y: number) =>
496
+ rootBoundary.rootTarget != null && rootBoundary.hitTest!(x, y) != null;
664
497
  }
665
498
 
666
499
  /** One already-mounted world, tracked for disposal + the router. `element`
@@ -668,18 +501,18 @@ function derivePixiHitTest(
668
501
  * pixijs, or the DOM-root layer `<div>` for react (T6.2 slice 1) — kept
669
502
  * under one field name so `fullCleanup`'s disposal loop stays kind-generic
670
503
  * (`container.removeChild(entry.element)` needs no branch). */
671
- interface MountedWorldEntry {
504
+ interface MountedAdapterRoot {
672
505
  readonly id: string;
673
506
  readonly kind: 'threejs' | 'pixijs' | 'react';
674
507
  readonly element: HTMLElement;
675
508
  readonly mounted: MountedWorld;
676
- /** Only threejs worlds own a renderer this file constructed. */
509
+ /** Only threejs roots own a renderer this file constructed. */
677
510
  readonly renderer: THREE.WebGLRenderer | undefined;
678
511
  }
679
512
 
680
513
  interface OneWorldResult {
681
- readonly mountedEntry: MountedWorldEntry;
682
- readonly routerEntry: RouterWorldEntry;
514
+ readonly mountedEntry: MountedAdapterRoot;
515
+ readonly routerEntry: RouterAdapterRoot;
683
516
  }
684
517
 
685
518
  /** Shared per-world mount inputs, computed once in `createWorldsGameRuntime`'s
@@ -694,7 +527,6 @@ interface OneWorldContext {
694
527
  readonly dpr: number;
695
528
  readonly isBottom: boolean;
696
529
  readonly headless: boolean;
697
- readonly uiContainer: HTMLDivElement;
698
530
  readonly loopHandle: LoopHandle;
699
531
  readonly assets: ReturnType<typeof createAssetCache>;
700
532
  }
@@ -707,7 +539,7 @@ async function mountOneThreeWorld(
707
539
  spec: ThreeWorldMountSpec,
708
540
  ctx: OneWorldContext,
709
541
  ): Promise<OneWorldResult> {
710
- const { game, canvas, w, h, dpr, isBottom, headless, uiContainer, loopHandle, assets } = ctx;
542
+ const { game, canvas, w, h, dpr, isBottom, headless, loopHandle, assets } = ctx;
711
543
  const renderer = headless
712
544
  ? createHeadlessRendererStub()
713
545
  : createHostRenderer(canvas, w, h, undefined, {
@@ -723,7 +555,7 @@ async function mountOneThreeWorld(
723
555
  // loop above just set. The `renderer.setSize(w, h, false)` line right above
724
556
  // this comment does NOT undo that stamp (updateStyle:false only skips
725
557
  // TOUCHING style, it can't un-stamp a previous call) — so without this
726
- // re-assertion, every worlds-path threejs canvas' on-screen size was
558
+ // re-assertion, every roots-path threejs canvas' on-screen size was
727
559
  // permanently pinned to whatever `w`/`h` it happened to mount at (usually
728
560
  // the manifest's `resolution`, since standalone builds mount before a real
729
561
  // container size is known — see `mount-manifest.ts`). Re-asserting here
@@ -732,14 +564,14 @@ async function mountOneThreeWorld(
732
564
  // fixes the template-standalone bug (broken at any viewport other than the
733
565
  // manifest's `resolution`, which is also Playwright's DEFAULT viewport —
734
566
  // why it went unnoticed) and, for free, tri-world's pre-existing
735
- // resize-staleness (the worlds-path `resize()` below always calls
567
+ // resize-staleness (the roots-path `resize()` below always calls
736
568
  // `setSize(rw, rh, false)`, so nothing else was ever going to update this
737
569
  // canvas' CSS after mount). `createHostRenderer`'s own default
738
570
  // (`updateStyle:true`) is intentionally left alone — the LEGACY
739
571
  // single-canvas path (editor play-mode's non-multi-world branch) still
740
572
  // relies on that construction-time stamp + its own later `updateStyle:true`
741
573
  // resizes for byte-identical behavior; this fix touches only the
742
- // worlds-path canvas, after the fact.
574
+ // roots-path canvas, after the fact.
743
575
  canvas.style.width = '100%';
744
576
  canvas.style.height = '100%';
745
577
  renderer.setPixelRatio(dpr);
@@ -751,7 +583,6 @@ async function mountOneThreeWorld(
751
583
  renderer,
752
584
  loop: loopHandle,
753
585
  assets,
754
- ui: uiContainer,
755
586
  headless,
756
587
  game,
757
588
  requestSystem: () => null,
@@ -775,7 +606,7 @@ async function mountOneThreeWorld(
775
606
  * `canvas.style.width`/`.height` (real CSS px, matching the LOGICAL
776
607
  * width/height passed to `resize()`) on every `app.renderer.resize()` call —
777
608
  * including the one this world's `mounted.resize?.()` triggers from the
778
- * worlds-path `resize()` below. So while a pixi world's canvas can start
609
+ * roots-path `resize()` below. So while a pixi world's canvas can start
779
610
  * pinned to the mount-time `w`/`h` (same as threejs, until PIXI's own
780
611
  * construction-time resize runs), it self-heals the moment ANY real
781
612
  * `session.resize(rw, rh)` fires — every shipped standalone entry
@@ -787,12 +618,12 @@ async function mountOnePixiWorld(
787
618
  spec: PixiWorldMountSpec,
788
619
  ctx: Omit<OneWorldContext, 'headless' | 'loopHandle' | 'assets'>,
789
620
  ): Promise<OneWorldResult> {
790
- const { game, canvas, w, h, dpr, isBottom, uiContainer } = ctx;
621
+ const { game, canvas, w, h, dpr, isBottom } = ctx;
791
622
  const pixiHost: World2DHost = {
792
623
  canvas,
793
624
  width: w,
794
625
  height: h,
795
- ui: uiContainer,
626
+ game,
796
627
  dpr,
797
628
  transparent: !isBottom,
798
629
  preserveDrawingBuffer: true,
@@ -828,8 +659,7 @@ async function mountOnePixiWorld(
828
659
  * `createWorldsGameRuntime`'s stack-building loop) but needs no entry in the
829
660
  * delegating router's hit-test loop (§1.C — "DOM layers need no entry in the
830
661
  * router's hit-test loop"): the layer's own `pointer-events` discipline
831
- * (this file sets `none` on the layer by default, mirroring the existing
832
- * `uiContainer`/HUD rule; the mounted react tree opts specific elements back
662
+ * (this file sets `none` on the layer by default; the mounted React tree opts specific elements back
833
663
  * in with `pointer-events:auto`) is what lets its interactive elements claim
834
664
  * events NATIVELY, via the real DOM, with zero router involvement — and lets
835
665
  * a click over its non-interactive (transparent) area fall through to the
@@ -849,10 +679,10 @@ async function mountOneReactWorld(
849
679
  * create its own) so `WorldInstance.reactRoot()` returns the SAME node
850
680
  * that is actually positioned in the stack. */
851
681
  layer: HTMLElement,
852
- ): Promise<{ mountedEntry: MountedWorldEntry }> {
682
+ ): Promise<{ mountedEntry: MountedAdapterRoot }> {
853
683
  layer.style.pointerEvents = 'none';
854
- // Size the layer like the shared uiContainer does: an absolutely-positioned
855
- // layer with no width/height collapses to zero content size, so a child's
684
+ // An absolutely-positioned layer with no width/height collapses to zero
685
+ // content size, so a child's
856
686
  // own position:absolute offsets resolve against a degenerate containing
857
687
  // block (found by the T6.2 slice-3 e2e — clicks landed outside the game).
858
688
  layer.style.width = '100%';
@@ -875,21 +705,21 @@ async function mountOneReactWorld(
875
705
  }
876
706
 
877
707
  /**
878
- * The worlds-path implementer behind {@link createGameRuntime} (T6.1 slice
879
- * 1; react worlds added T6.2 slice 1). Builds ONE surface per world — a
708
+ * The roots-path implementer behind {@link createGameRuntime} (T6.1 slice
709
+ * 1; react roots added T6.2 slice 1). Builds ONE surface per world — a
880
710
  * canvas for threejs/pixijs, a DOM-root `<div>` layer for react — stacked
881
711
  * per COMPOSITION-DESIGN D5 §1, z-order/ties exactly matching
882
712
  * `manifest/load.ts`'s sort, ONE `Game`, and registers every world onto it
883
713
  * via `registerThreeWorld`/`registerPixiWorld`/`registerReactWorld` — the
884
714
  * SAME wiring `test/game-three-plus-pixi.test.ts` proves by hand for the
885
- * three/pixi pair. Worlds MOUNT in `worlds` ARRAY order (GAME-ROOT-DESIGN §4's
715
+ * three/pixi pair. Worlds MOUNT in `roots` ARRAY order (GAME-ROOT-DESIGN §4's
886
716
  * "manifest declaration order" — the frame/registration axis), independent of
887
717
  * `zOrder` (the canvas-stacking/rendering axis) — the two orders can differ
888
718
  * and both are honored correctly.
889
719
  */
890
720
 
891
721
  /**
892
- * Dev/e2e-only `window.__vgaiScene`/`__vgaiCamera` exposure for the worlds
722
+ * Dev/e2e-only `window.__vgaiScene`/`__vgaiCamera` exposure for the roots
893
723
  * path's DEFAULT world (E4) — split out of `createWorldsGameRuntime` purely
894
724
  * to keep that function's own cyclomatic complexity down. Mirrors the
895
725
  * legacy single-world path's identical exposure (above, in this same file),
@@ -925,15 +755,15 @@ interface MountAllWorldsInputs extends Omit<OneWorldContext, 'canvas' | 'isBotto
925
755
  }
926
756
 
927
757
  interface MountAllWorldsResult {
928
- readonly mountedEntries: MountedWorldEntry[];
929
- readonly routerEntries: RouterWorldEntry[];
758
+ readonly mountedEntries: MountedAdapterRoot[];
759
+ readonly routerEntries: RouterAdapterRoot[];
930
760
  }
931
761
 
932
762
  /**
933
763
  * Mount + register every world spec, in ARRAY (declaration) order — split
934
764
  * out of `createWorldsGameRuntime` purely to keep that function's own
935
765
  * cyclomatic complexity down (E4, same reason `mountOneThreeWorld`/
936
- * `mountOnePixiWorld` are already split out). React worlds contribute NO
766
+ * `mountOnePixiWorld` are already split out). React roots contribute NO
937
767
  * router entry (docs/REACT-WORLD-DESIGN.md §1.C — "DOM layers need no entry
938
768
  * in the router's hit-test loop"): their layer's own `pointer-events`
939
769
  * discipline handles claim/fall-through natively, with zero router
@@ -945,8 +775,8 @@ async function mountAllWorldSpecs(
945
775
  inputs: MountAllWorldsInputs,
946
776
  ): Promise<MountAllWorldsResult> {
947
777
  const { surfacesById, ...shared } = inputs;
948
- const mountedEntries: MountedWorldEntry[] = [];
949
- const routerEntries: RouterWorldEntry[] = [];
778
+ const mountedEntries: MountedAdapterRoot[] = [];
779
+ const routerEntries: RouterAdapterRoot[] = [];
950
780
 
951
781
  for (const spec of mountSpecs) {
952
782
  const isBottom = spec.id === bottomId;
@@ -958,15 +788,15 @@ async function mountAllWorldSpecs(
958
788
  }
959
789
  const canvas = surfacesById.get(spec.id)! as HTMLCanvasElement;
960
790
  const oneCtx: OneWorldContext = { ...shared, canvas, isBottom };
961
- let mountedEntry: MountedWorldEntry;
962
- let routerEntry: RouterWorldEntry;
791
+ let mountedEntry: MountedAdapterRoot;
792
+ let routerEntry: RouterAdapterRoot;
963
793
  if (spec.kind === 'threejs') {
964
794
  ({ mountedEntry, routerEntry } = await mountOneThreeWorld(spec, oneCtx));
965
795
  } else if (spec.kind === 'pixijs') {
966
796
  ({ mountedEntry, routerEntry } = await mountOnePixiWorld(spec, oneCtx));
967
797
  } else {
968
798
  // Exhaustiveness guard (§7.4-2): 'react' was already handled by the
969
- // early `continue` above, so only a hypothetical 4th `WorldKind` can
799
+ // early `continue` above, so only a hypothetical 4th `AdapterSurface` can
970
800
  // reach here — fail loudly rather than silently defaulting. `spec`
971
801
  // itself (not `spec.kind`) is what TS has narrowed to `never`, since
972
802
  // `WorldMountSpec` is a discriminated union at the object level.
@@ -979,9 +809,9 @@ async function mountAllWorldSpecs(
979
809
  }
980
810
 
981
811
  async function createWorldsGameRuntime(config: WorldsRuntimeConfig): Promise<GameSession> {
982
- const { container, worlds: specs, width, height, headless = false } = config;
812
+ const { container, roots: specs, width, height, headless = false, seed } = config;
983
813
  if (specs.length === 0) {
984
- throw new Error('createGameRuntime: `worlds` must contain at least one world.');
814
+ throw new Error('createGameRuntime: `roots` must contain at least one root.');
985
815
  }
986
816
  const mountSpecs = specs as (ThreeWorldMountSpec | PixiWorldMountSpec | ReactWorldMountSpec)[];
987
817
 
@@ -1034,29 +864,19 @@ async function createWorldsGameRuntime(config: WorldsRuntimeConfig): Promise<Gam
1034
864
  // too (not just in `mountOneThreeWorld`) means every surface, whatever
1035
865
  // kind, starts container-relative from its very first paint, before any
1036
866
  // per-kind mount work has even run.
1037
- surface.style.cssText = `position:absolute;top:0;left:0;width:100%;height:100%;z-index:${i + 1};`;
867
+ // `contain:layout paint` makes each surface the CONTAINING BLOCK for
868
+ // `position:fixed` descendants (and clips overflow to the world's
869
+ // rectangle): full-screen game UI written the natural way (`fixed;
870
+ // inset:0`) then fills the WORLD, not the page. Without it, `fixed` UI
871
+ // looks correct standalone (surface == window) but escapes over the
872
+ // editor chrome whenever the surface is a sub-rectangle of the page —
873
+ // and toggles behavior when any ancestor gains a transform (e.g. the
874
+ // editor's space-pan). Dogfooded 2026-07-12 via a react shell world.
875
+ surface.style.cssText = `position:absolute;top:0;left:0;width:100%;height:100%;z-index:${i + 1};contain:layout paint;`;
1038
876
  container.appendChild(surface);
1039
877
  surfacesById.set(entry.id, surface);
1040
878
  });
1041
879
 
1042
- // One shared UI overlay, above every canvas. I8 render-integration seam
1043
- // (docs/AI-NATIVE-AUTHORING-IMPLEMENTATION-SPEC.md §15 I8, C1 review note):
1044
- // the legacy single-world path (above) reuses/stamps a stable `#example-ui`
1045
- // id so a capture host has a reliable selector for "the HUD/letterbox
1046
- // overlay" — this worlds path had no such id at all, so a render-mode page
1047
- // built on `createWorldsGameRuntime` (multi-world manifests, including a
1048
- // react-HUD-over-threejs cinematic) had no stable selector to composite-
1049
- // screenshot. `vgai-ui-overlay` is deliberately a DIFFERENT id than the
1050
- // legacy path's `example-ui` (not reused/aliased) — the two runtime paths
1051
- // mount genuinely different DOM subtrees, and collapsing them onto one id
1052
- // would make a caller's selector ambiguous about which mount produced it.
1053
- const uiContainer = document.createElement('div');
1054
- uiContainer.id = 'vgai-ui-overlay';
1055
- uiContainer.style.cssText =
1056
- `position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;` +
1057
- `z-index:${stacked.length + 1};`;
1058
- container.appendChild(uiContainer);
1059
-
1060
880
  const assets = createAssetCache();
1061
881
  const extraUpdaters = new Set<(dt: number) => void>();
1062
882
  const loopHandle: LoopHandle = {
@@ -1074,7 +894,7 @@ async function createWorldsGameRuntime(config: WorldsRuntimeConfig): Promise<Gam
1074
894
  for (const fn of extraUpdaters) fn(dt);
1075
895
  },
1076
896
  });
1077
- const game = createGame({ loop, assets });
897
+ const game = createGame({ loop, assets, seed });
1078
898
 
1079
899
  // --- Mount + register every world, in ARRAY (declaration) order. ---
1080
900
  // Split out into its own top-level function purely to keep
@@ -1088,7 +908,6 @@ async function createWorldsGameRuntime(config: WorldsRuntimeConfig): Promise<Gam
1088
908
  h,
1089
909
  dpr,
1090
910
  headless,
1091
- uiContainer,
1092
911
  loopHandle,
1093
912
  assets,
1094
913
  });
@@ -1101,7 +920,7 @@ async function createWorldsGameRuntime(config: WorldsRuntimeConfig): Promise<Gam
1101
920
 
1102
921
  // Expose scene & camera for dev tools / e2e tests — mirrors the legacy
1103
922
  // single-world path's identical dev-only exposure above, generalized to
1104
- // the worlds path's DEFAULT world (E4, docs/unified-world-editor/
923
+ // the roots path's DEFAULT world (E4, docs/unified-world-editor/
1105
924
  // 27-visual-react-editing.md §7 E4): `mountGameFromManifest`/
1106
925
  // `mountManifestWorlds` route every caller (including a single-threejs-
1107
926
  // world scaffold project) through THIS path, so a caller migrating off
@@ -1121,7 +940,6 @@ async function createWorldsGameRuntime(config: WorldsRuntimeConfig): Promise<Gam
1121
940
  entry.renderer?.forceContextLoss();
1122
941
  container.removeChild(entry.element);
1123
942
  }
1124
- container.removeChild(uiContainer);
1125
943
  retractDevGlobals();
1126
944
  }
1127
945
 
@@ -1155,7 +973,7 @@ async function createWorldsGameRuntime(config: WorldsRuntimeConfig): Promise<Gam
1155
973
  // convenience shaped for the threejs-only past. T7.5 narrows the read via
1156
974
  // the `kind` discriminant instead of a blind `.scene`/`.camera` cast
1157
975
  // through a nonexistent property (identical behavior to before: still
1158
- // `undefined` for a worlds-path session whose default world isn't
976
+ // `undefined` for a roots-path session whose default world isn't
1159
977
  // threejs — real per-world surface routing for that case is T7.6's).
1160
978
  get scene() {
1161
979
  const m = game.defaultWorld.mounted;