@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
@@ -15,8 +15,14 @@
15
15
  import RAPIER from '@dimforge/rapier3d-compat';
16
16
  import type { EffectComposer } from 'postprocessing';
17
17
  import * as THREE from 'three';
18
+ import {
19
+ createSeededRandom,
20
+ DEFAULT_SEEDED_RANDOM_SEED,
21
+ getSeededRandom,
22
+ } from '../core/seeded-random';
18
23
  import { createSystemRunner } from '../core/system-runner';
19
24
  import { createDebugDraw } from '../dev/debug-draw';
25
+ import { createWebGLGpuTimer } from '../dev/webgl-gpu-timer';
20
26
  import { createComponentManager } from '../ecs/component-manager';
21
27
  import { InputManager } from '../input/input-manager';
22
28
  import { setAssetPrefix } from '../loader';
@@ -26,14 +32,12 @@ import { createTransformWriter } from '../physics/transform-writer';
26
32
  import { createTriggerDispatch } from '../physics/trigger-dispatch';
27
33
  import { RenderBatchSystem } from '../render/render-batch-system';
28
34
  import { type RenderScope, resolveRenderSettings } from '../render/render-settings';
29
- import type { WorldFrameHooks } from '../runtime/game';
30
35
  import {
31
- renderSceneUI,
32
- type SceneUIDataSourceLike,
33
- type SceneUIGameServices,
34
- type SceneUIHandle,
35
- } from '../runtime/scene-ui-bridge';
36
- import { gameStateDataSource } from '../runtime/scene-ui-data';
36
+ createDebugRegistry,
37
+ type DebugRegistry,
38
+ getDebugRegistry,
39
+ } from '../runtime/debug-registry';
40
+ import type { WorldFrameHooks } from '../runtime/game';
37
41
  import type { EditorPreview, GameCleanup, GameContext, GameSetupFn } from '../runtime/types';
38
42
  import type { ComponentRegistry } from '../scene/component-registry';
39
43
  import { tickCustomMaterials } from '../scene/material-registry';
@@ -88,24 +92,6 @@ export interface VgaiSceneConfig {
88
92
  * that sets this today).
89
93
  */
90
94
  componentRegistry?: ComponentRegistry | undefined;
91
- /**
92
- * The project's scene-UI registry (design/24-scene-ui.md D9/D11) —
93
- * `components`/`transforms`/`strings` only, opaque records engine-side (the
94
- * engine never imports `@vgai/scene-ui`'s real `ProjectUIRegistry` type;
95
- * they're React things it never inspects). Threaded per-mount into the
96
- * services `renderSceneUI` receives, mirroring `componentRegistry` above:
97
- * the editor's default-three adapter resolver passes its cached project
98
- * registry here for the editor-play path (D11); a standalone host that
99
- * already registered a static registry via `registerSceneUIRenderer`
100
- * typically omits this (registration-time registry is enough there).
101
- */
102
- uiRegistry?:
103
- | {
104
- components?: Record<string, unknown>;
105
- transforms?: Record<string, unknown>;
106
- strings?: Record<string, Record<string, string>>;
107
- }
108
- | undefined;
109
95
  /** Input map JSON path. Defaults to 'inputmaps/default.inputmap.json'. */
110
96
  inputMapPath?: string | undefined;
111
97
  /** URL prefix for relative asset paths. Defaults to '/'. */
@@ -139,10 +125,10 @@ export interface VgaiMountedGame extends MountedGame {
139
125
  /**
140
126
  * Phase-partitioned frame entry point (T7.1 slice 2,
141
127
  * `docs/GAME-ROOT-DESIGN.md` §4) — wired onto this world's `WorldInstance`
142
- * by `registerDefaultThreeWorld` (`create-runtime.ts`). `Game.runFrame` is
128
+ * by `registerThreeWorld` (`create-runtime.ts`). `Game.runFrame` is
143
129
  * the CANONICAL driver going forward: it calls `frame.runPhase` once per
144
130
  * (phase, substep) for every world, then `frame.endFrame` once per
145
- * substep after all worlds finish all phases. `update` (below) remains
131
+ * substep after all roots finish all phases. `update` (below) remains
146
132
  * the legacy/direct entry point to the exact same `SystemRunner` — direct
147
133
  * callers (editor HMR, adapter conformance tests) keep using it unchanged.
148
134
  */
@@ -185,7 +171,6 @@ export class VgaiSceneGameAdapter implements GameAdapter {
185
171
  scenePath,
186
172
  sceneData,
187
173
  componentRegistry,
188
- uiRegistry,
189
174
  inputMapPath = '/inputmaps/default.inputmap.json',
190
175
  assetPrefix = '/',
191
176
  } = this.config;
@@ -234,31 +219,69 @@ export class VgaiSceneGameAdapter implements GameAdapter {
234
219
  // --- Particles (three.quarks BatchedRenderer) ---
235
220
  const particles = setupParticles(scene);
236
221
 
237
- // --- UI container (host-provided) ---
238
- const uiContainer = host.ui as HTMLDivElement;
239
-
240
222
  // --- Debug draw / assets ---
241
223
  const debugDraw = createDebugDraw(scene);
242
224
  const assets = host.assets;
225
+ // Test/headless adapters may provide the renderer surface needed by the
226
+ // runtime without a real WebGL context. GPU timing is optional diagnostics:
227
+ // degrade honestly when the renderer/context cannot expose extensions.
228
+ const rendererContext =
229
+ typeof renderer.getContext === 'function' ? renderer.getContext() : undefined;
230
+ const gpuTimer =
231
+ !headless && rendererContext && typeof rendererContext.getExtension === 'function'
232
+ ? createWebGLGpuTimer(rendererContext)
233
+ : null;
243
234
 
244
235
  // --- System runner (engine-level systems) ---
245
- const systems = createSystemRunner();
246
- systems.add('input', () => input.poll());
247
- systems.add('physics', () => physics.rapierWorld.step(physics.eventQueue));
248
- systems.add('postPhysics', () => {
249
- collisions.drain();
250
- writeTransforms();
236
+ const systems = createSystemRunner(host.game?.profiler.systemObserver, 'threejs');
237
+ // D15/T-D15.3/.5: pass the LIVE shared game tick (not a locally-counted
238
+ // one) into every `poll()` call — `debugRegistry` is declared further
239
+ // down in this same `mount()` (it needs `ctx`/`systemAdapters` to exist
240
+ // first), but this callback only ever executes during real frame
241
+ // ticks, long after `mount()` has fully returned and `debugRegistry` is
242
+ // initialized (a safe closure-over-a-later-const, not a genuine
243
+ // use-before-init). `host.game` gates it: a bare mount with no `Game`
244
+ // shell behind it (test harnesses predating T7.1) has no shared tick to
245
+ // key off, so `InputManager.poll()` falls back to its own internal
246
+ // self-incrementing counter instead (unchanged pre-D15 behavior) rather
247
+ // than being pinned to a constant `0` forever.
248
+ systems.add('input', () => input.poll(host.game ? debugRegistry.getGameTick() : undefined), {
249
+ name: 'input.poll',
251
250
  });
252
- systems.add('preRender', (dt) => {
253
- particles.batchedRenderer.update(dt);
254
- tickCustomMaterials(scene, dt);
255
- updateSceneLODs(scene, camera);
251
+ systems.add('physics', () => physics.rapierWorld.step(physics.eventQueue), {
252
+ name: 'physics.step',
256
253
  });
254
+ systems.add(
255
+ 'postPhysics',
256
+ () => {
257
+ collisions.drain();
258
+ writeTransforms();
259
+ },
260
+ { name: 'physics.sync' },
261
+ );
262
+ systems.add(
263
+ 'preRender',
264
+ (dt) => {
265
+ particles.batchedRenderer.update(dt);
266
+ tickCustomMaterials(scene, dt);
267
+ updateSceneLODs(scene, camera);
268
+ },
269
+ { name: 'materials-and-particles' },
270
+ );
257
271
  if (!headless) {
258
- systems.add('render', (dt) => {
259
- composer.render(dt);
260
- if (physics.debugEnabled) updatePhysicsDebug(physics.rapierWorld, physics.debugMesh);
261
- });
272
+ systems.add(
273
+ 'render',
274
+ (dt) => {
275
+ if (host.game?.profiler.enabled) gpuTimer?.begin();
276
+ try {
277
+ composer.render(dt);
278
+ } finally {
279
+ gpuTimer?.end();
280
+ }
281
+ if (physics.debugEnabled) updatePhysicsDebug(physics.rapierWorld, physics.debugMesh);
282
+ },
283
+ { name: 'three.render' },
284
+ );
262
285
  }
263
286
 
264
287
  // --- Debug toggle (browser only) ---
@@ -270,7 +293,18 @@ export class VgaiSceneGameAdapter implements GameAdapter {
270
293
  };
271
294
  if (!headless) window.addEventListener('keydown', onDebugToggle);
272
295
 
273
- const postFrame = () => input.endFrame();
296
+ const postFrame = () => {
297
+ input.endFrame();
298
+ if (host.game?.profiler.enabled) {
299
+ host.game.profiler.reportRender({
300
+ gpuMs: gpuTimer?.poll() ?? null,
301
+ drawCalls: renderer.info.render.calls,
302
+ triangles: renderer.info.render.triangles,
303
+ geometries: renderer.info.memory.geometries,
304
+ textures: renderer.info.memory.textures,
305
+ });
306
+ }
307
+ };
274
308
 
275
309
  // The mounted game's adapter surface (`mounted.systems`). Declared before
276
310
  // ctx so `ctx.registerSystemAdapter` can close over it: the engine fills
@@ -280,17 +314,6 @@ export class VgaiSceneGameAdapter implements GameAdapter {
280
314
  // late registrations are visible to its panels at read time.
281
315
  const systemAdapters: SystemAdapters = {};
282
316
 
283
- // Game-registered scene-UI services (design/24-scene-ui.md D2/D7) — a `let`
284
- // bag mutated by `ctx.setSceneUIServices`, declared here (BEFORE `ctx` is
285
- // built) so the closure below has something to capture: a GameComponent
286
- // calling `ctx.setSceneUIServices` from its `init()` runs DURING
287
- // `componentManager.initAll()` (scene-loader.ts), which is awaited before
288
- // `loadScene`/`loadFromData` return below — well before `sceneUIHandle`
289
- // exists — so early calls just accumulate here and are folded into the
290
- // FIRST render (`buildSceneUIServices`, below) rather than routed through
291
- // the late-update path.
292
- let sceneUIServices: SceneUIGameServices = {};
293
-
294
317
  // --- GameContext (the first-party runtime surface) ---
295
318
  const ctx: GameContext = {
296
319
  scene,
@@ -307,38 +330,20 @@ export class VgaiSceneGameAdapter implements GameAdapter {
307
330
  assets,
308
331
  systems,
309
332
  components: null!,
310
- uiContainer,
311
333
  registerSystemAdapter: (kind, adapter) => {
312
334
  systemAdapters[kind] = adapter;
313
335
  },
314
- setSceneUIServices: (incoming) => {
315
- sceneUIServices = { ...sceneUIServices, ...incoming };
316
- // Late call (after the initial mount already resolved a sceneInstance
317
- // and rendered it): route to the live handle instead of just banking
318
- // the services for a mount that already happened (D7).
319
- if (sceneUIHandle && sceneInstance) {
320
- const merged = buildSceneUIServices(sceneInstance);
321
- if (sceneUIHandle.update) {
322
- sceneUIHandle.update(merged);
323
- } else {
324
- sceneUIHandle.dispose();
325
- sceneUIHandle = sceneInstance.ui
326
- ? renderSceneUI(uiContainer, sceneInstance.ui, merged)
327
- : null;
328
- }
329
- }
330
- },
331
336
  };
332
337
  // Game root (T7.1 slice 1): only present once the host has constructed a
333
338
  // Game shell (createGameRuntime does this before mount; headless/foreign
334
- // hosts may omit it — ctx.game/ctx.worlds simply stay undefined, which is
335
- // the documented zero-break behavior). `ctx.worlds` is assigned the SAME
339
+ // hosts may omit it — ctx.game/ctx.roots simply stay undefined, which is
340
+ // the documented zero-break behavior). `ctx.roots` is assigned the SAME
336
341
  // live array `host.game` mutates via `registerWorld` (not a copy) — the
337
342
  // default world is registered AFTER mount returns, and this reference
338
343
  // must observe that later push.
339
344
  if (host.game) {
340
345
  ctx.game = host.game;
341
- ctx.worlds = host.game.worlds;
346
+ ctx.roots = host.game.roots;
342
347
  }
343
348
  ctx.components = createComponentManager(ctx, physicsRegistry);
344
349
  collisions.onCollision(
@@ -370,6 +375,85 @@ export class VgaiSceneGameAdapter implements GameAdapter {
370
375
  // against the headless stand-in too (`headlessAudio()`'s plain
371
376
  // `masterGain.gain` object) — this world's `pause()` mutes it harmlessly.
372
377
  systemAdapters.audio = createAudioSystemAdapter(audio);
378
+ // Debug/synthetic-player seam (T1.1, docs/SYNTHETIC-PLAYER-SPEC.md §3.1):
379
+ // ONE registry per Game root, shared across every world that mounts onto
380
+ // it — `getDebugRegistry(host.game)` reaches the SAME accumulator
381
+ // `createGame` filed, so a second/third world's `ctx.debug` feeds it too
382
+ // (see debug-registry.ts's module doc for the provenance/id note). A
383
+ // mount with no Game shell at all (bare test harnesses predating T7.1)
384
+ // gets a private, mount-local registry instead — same absence precedent
385
+ // as `ctx.game`/`ctx.roots` above.
386
+ const debugRegistry: DebugRegistry =
387
+ (host.game ? getDebugRegistry(host.game) : null) ??
388
+ createDebugRegistry({ getTick: () => 0, getSimT: () => 0 });
389
+ systemAdapters.debug = debugRegistry.adapter;
390
+ ctx.debug = debugRegistry.forWorld(this.id);
391
+ // T1.2: the InputManager is a first-party per-world handle the registry
392
+ // has no other way to reach — wired as a lazy supplier (not a direct
393
+ // read here), scoped to THIS world's id, so the built-in `input.actions`
394
+ // provider always reflects the CURRENT action set, not a snapshot taken
395
+ // at mount time. Per-world (not a single last-writer-wins slot) since
396
+ // D15/T-D15.5 — see `debug-registry.ts`'s `setInputActionsSource` doc.
397
+ debugRegistry.setInputActionsSource(this.id, () =>
398
+ typeof input.actionNames === 'function'
399
+ ? input.actionNames().map((name) => ({ name, valueType: input.getActionValueType(name) }))
400
+ : [],
401
+ );
402
+ // D15/T-D15.5 — same lazy-supplier pattern (and same headless-stand-in
403
+ // guard) as `setInputActionsSource` immediately above: the built-in
404
+ // `input.trace` provider always reads the CURRENT recorded trace, never
405
+ // a snapshot taken at mount time. `seed`/`fixedDt` are assembled here
406
+ // (not inside `InputManager`, which has no business knowing about
407
+ // `ctx.random` or the loop) — the two replay-critical metadata fields
408
+ // the design doc's format sketch (§2.c) calls for beside the raw
409
+ // per-tick deltas; `null` only absent a Game/ctx.random behind this
410
+ // mount, matching every other "no Game" fallback in this file.
411
+ debugRegistry.setInputTraceSource(this.id, () => {
412
+ const raw: { version: 1; ticks: unknown[] } =
413
+ typeof input.getInputTrace === 'function'
414
+ ? input.getInputTrace()
415
+ : { version: 1, ticks: [] };
416
+ const seed = (host.game ? getSeededRandom(host.game) : null)?.seed ?? null;
417
+ const fixedDt = host.game?.loop.fixedDt ?? null;
418
+ return { version: raw.version, seed, fixedDt, ticks: raw.ticks };
419
+ });
420
+ // Task 2.1 — the same InputManager instance, wired as the debug bridge's
421
+ // actuation target (`runtime/debug-bridge.ts`'s `input.*` methods) at the
422
+ // same seed spot as `setInputActionsSource` above. Per-world (D15 review
423
+ // objection 2 fix) — see `debug-registry.ts`'s `setVirtualInputTarget`
424
+ // doc for why this used to be a single last-writer-wins slot.
425
+ debugRegistry.setVirtualInputTarget(this.id, {
426
+ setVirtualAction: (action, value) => input.setVirtualAction(action, value),
427
+ tapVirtualAction: (action) => input.tapVirtualAction(action),
428
+ clearVirtualActions: () => input.clearVirtualActions(),
429
+ scheduleActionAtTick: (tick, action, value) =>
430
+ input.scheduleActionAtTick(tick, action, value),
431
+ startInputRecording: () => input.startInputRecording(),
432
+ stopInputRecording: () => input.stopInputRecording(),
433
+ isInputRecording: () => input.isInputRecording(),
434
+ injectAxis: (sourceId, value) => input.injectAxis(sourceId, value),
435
+ injectVector2: (sourceId, value) => input.injectVector2(sourceId, value),
436
+ injectPointerDelta: (sourceId, delta) => input.injectPointerDelta(sourceId, delta),
437
+ injectPointerPosition: (sourceId, value) => input.injectPointerPosition(sourceId, value),
438
+ });
439
+ // R4-class fix — wire the InputManager's `'input.schedule.dropped'` sink
440
+ // to THIS world's debug registry, same seed spot/precedent as
441
+ // `setInputActionsSource`/`setVirtualInputTarget` above (typeof-guarded:
442
+ // a headless `InputManager` stand-in may have no `setDebugEmit`).
443
+ if (typeof input.setDebugEmit === 'function') {
444
+ input.setDebugEmit((event, detail) => ctx.debug?.emit(event, detail));
445
+ }
446
+ // D15 (T-D15.1) — same "ONE per Game root, shared across every world"
447
+ // pattern as the debug registry immediately above: `getSeededRandom
448
+ // (host.game)` reaches the SAME `SeededRandom` `createGame` filed (boot-
449
+ // seeded by the manifest-aware mount path, `mount-manifest.ts`, before
450
+ // ANY world's `mount()`/`setup()` runs — see `createGame`'s own doc
451
+ // comment), so every world's `ctx.random` is the identical instance, not
452
+ // a per-world copy. Same absence precedent as `ctx.debug`: a mount with
453
+ // no Game shell at all gets a private, mount-local surface instead.
454
+ ctx.random =
455
+ (host.game ? getSeededRandom(host.game) : null) ??
456
+ createSeededRandom(DEFAULT_SEEDED_RANDOM_SEED);
373
457
 
374
458
  // Snapshot of the engine-owned adapter kinds, taken right after seeding
375
459
  // and before any setup() has had a chance to run. `hotReload`/`disposeGame`
@@ -396,13 +480,7 @@ export class VgaiSceneGameAdapter implements GameAdapter {
396
480
  c.traverse((n) => setUserData(n, 'engineInternal', true));
397
481
  }
398
482
  let currentCleanup: GameCleanup | null = null;
399
- let sceneUIHandle: SceneUIHandle | null = null;
400
483
  let batchSystem: RenderBatchSystem | null = null;
401
- // The scenePath/sceneData branch's resolved SceneInstance, if either ran
402
- // (stays undefined for a `setup`-based mount — see the `sceneUI` deriva-
403
- // tion below). Single source of truth for both the scene-graph `ui` tree
404
- // and (potentially, in future) other instance-derived wiring.
405
- let sceneInstance: SceneInstance | undefined;
406
484
 
407
485
  // Apply scene-level render settings + transparent auto-batching after a scene
408
486
  // loads (GPU host only). Gated on the resolved `environment.rendering` cascade
@@ -441,61 +519,6 @@ export class VgaiSceneGameAdapter implements GameAdapter {
441
519
  }
442
520
  };
443
521
 
444
- // Scratch vector for the D5 default worldProjector — reused across calls
445
- // (one per bound world-tracked canvas per render), never allocated per-frame.
446
- const _sceneUIProjectorTmp = new THREE.Vector3();
447
-
448
- // The D4 default data source subscribes to game.state for its whole
449
- // lifetime with no unsubscribe path, so it must be built at most ONCE per
450
- // adapter mount — buildSceneUIServices runs again on every late
451
- // setSceneUIServices call, and rebuilding it there would both leak a
452
- // subscription and force every bound node to resubscribe to a fresh store.
453
- let defaultSceneUIData: SceneUIDataSourceLike | undefined;
454
-
455
- /**
456
- * Assemble the services `renderSceneUI` receives (design/24-scene-ui.md
457
- * D2): engine defaults (D4 data source, D5 worldProjector, D6 onEvent) <-
458
- * the project's per-mount UI registry (D11, editor-play threading) <-
459
- * game-registered services (`ctx.setSceneUIServices`) — per key, each
460
- * later layer winning over the one before it.
461
- */
462
- const buildSceneUIServices = (inst: SceneInstance): SceneUIGameServices => {
463
- const defaults: SceneUIGameServices = {
464
- onEvent: (handlerId) => {
465
- console.warn(
466
- `scene-ui: unhandled UI event "${handlerId}" — register onEvent via ctx.setSceneUIServices`,
467
- );
468
- },
469
- worldProjector: (id) => {
470
- const obj = inst.entities.get(id);
471
- if (!obj) return null;
472
- const projected = obj.getWorldPosition(_sceneUIProjectorTmp).project(camera);
473
- if (projected.z > 1) return null; // behind the camera -> hidden
474
- const w = uiContainer.clientWidth;
475
- const h = uiContainer.clientHeight;
476
- // Rounded (not sub-pixel) — matches CrtScreen's integer-rounding
477
- // (crt-screen.ts), which exists specifically to stop an asymptotic
478
- // camera lerp from shimmering a tracked canvas every frame.
479
- return {
480
- x: Math.round(((projected.x + 1) / 2) * w),
481
- y: Math.round(((1 - projected.y) / 2) * h),
482
- };
483
- },
484
- };
485
- // Lazily and at-most-once; skipped entirely while the game supplies its
486
- // own `data` service (no point subscribing a default nobody reads).
487
- if (!sceneUIServices.data && ctx.game && componentRegistry) {
488
- defaultSceneUIData ??= gameStateDataSource(ctx.game, componentRegistry);
489
- defaults.data = defaultSceneUIData;
490
- }
491
- const registryPortion: SceneUIGameServices = {
492
- ...(uiRegistry?.components ? { components: uiRegistry.components } : {}),
493
- ...(uiRegistry?.transforms ? { transforms: uiRegistry.transforms } : {}),
494
- ...(uiRegistry?.strings ? { strings: uiRegistry.strings } : {}),
495
- };
496
- return { ...defaults, ...registryPortion, ...sceneUIServices };
497
- };
498
-
499
522
  const loadFromData = async (data: SceneFile): Promise<SceneInstance> => {
500
523
  const inst = await loadSceneFromData(data, {
501
524
  scene,
@@ -518,6 +541,9 @@ export class VgaiSceneGameAdapter implements GameAdapter {
518
541
  if (headless) throw new Error('VgaiSceneGameAdapter: setup-based games require a GPU host');
519
542
  currentCleanup = await setup(ctx, editorPreview);
520
543
  } else if (scenePath) {
544
+ // #139: captured BEFORE load so adoptSceneCamera can tell whether a
545
+ // component (e.g. SceneCamera.init) already framed the camera.
546
+ const preLoadPose = captureCameraPose(camera);
521
547
  const inst = await loadScene(scenePath, {
522
548
  scene,
523
549
  rapierWorld: ctx.rapierWorld,
@@ -529,11 +555,10 @@ export class VgaiSceneGameAdapter implements GameAdapter {
529
555
  particleRenderer: ctx.particles.batchedRenderer,
530
556
  ...(headless ? {} : { renderer }),
531
557
  });
532
- applyEditorCamera(editorPreview, camera) || adoptSceneCamera(inst, camera);
558
+ applyEditorCamera(editorPreview, camera) || adoptSceneCamera(inst, camera, preLoadPose);
533
559
  applySceneRendering(inst);
534
560
  applySceneNavigation(inst);
535
561
  ctx.systems.add('postPhysics', (dt) => inst.update(dt));
536
- sceneInstance = inst;
537
562
  // A pre-baked navmesh (sibling .navmesh file — see scene-loader.ts) holds
538
563
  // live recast-navigation WASM handles that leak unless destroyed
539
564
  // explicitly; dispose it alongside the scene instance on teardown.
@@ -544,9 +569,9 @@ export class VgaiSceneGameAdapter implements GameAdapter {
544
569
  },
545
570
  };
546
571
  } else if (sceneData) {
572
+ const preLoadPose = captureCameraPose(camera);
547
573
  const inst = await loadFromData(sceneData);
548
- applyEditorCamera(editorPreview, camera) || adoptSceneCamera(inst, camera);
549
- sceneInstance = inst;
574
+ applyEditorCamera(editorPreview, camera) || adoptSceneCamera(inst, camera, preLoadPose);
550
575
  currentCleanup = {
551
576
  dispose: () => {
552
577
  inst.navMesh?.dispose(scene);
@@ -555,19 +580,6 @@ export class VgaiSceneGameAdapter implements GameAdapter {
555
580
  };
556
581
  }
557
582
 
558
- // Render scene-graph UI (the `ui` tree) into the overlay via the injected React
559
- // renderer (B1). Sourced from the loaded `SceneInstance` — the single source of
560
- // truth for BOTH the scenePath and sceneData branches (R8 item 7 / B: previously
561
- // only sceneData's raw `SceneFile.ui` was read via a `resolvedSceneData` special-
562
- // case, so a scenePath mount's `ui` tree was silently dropped even though
563
- // `loadScene` fully parses it). A `setup`-based mount has no `sceneInstance` at
564
- // all — its game owns any UI mounting itself. No-op if no UI or no renderer
565
- // registered. Engine stays React-free.
566
- const sceneUI = sceneInstance?.ui;
567
- if (sceneUI && sceneInstance && !headless) {
568
- sceneUIHandle = renderSceneUI(uiContainer, sceneUI, buildSceneUIServices(sceneInstance));
569
- }
570
-
571
583
  // Idempotency guard for disposeGame — see below. Declared here (not inside
572
584
  // disposeGame) so hotReload can also refuse to run on an already-disposed
573
585
  // adapter.
@@ -654,13 +666,6 @@ export class VgaiSceneGameAdapter implements GameAdapter {
654
666
  });
655
667
  safeStep('clearAssetCaches', () => clearAssetCaches());
656
668
  safeStep('debugDraw.clear', () => debugDraw.clear());
657
- safeStep('sceneUIHandle.dispose', () => {
658
- sceneUIHandle?.dispose();
659
- sceneUIHandle = null;
660
- });
661
- safeStep('uiContainer reset', () => {
662
- uiContainer.innerHTML = '';
663
- });
664
669
 
665
670
  // R8 item 7 (C) — disposeGame (Stop) used to skip both of these, unlike
666
671
  // hotReload (warm restart), which already ran them: a game lifecycle
@@ -669,7 +674,7 @@ export class VgaiSceneGameAdapter implements GameAdapter {
669
674
  // systemAdapters kind (e.g. a `setup`-registered 'networking') survived
670
675
  // a Stop and would be visible on a STALE `mounted.systems` even though
671
676
  // the game that owned it is gone. Same two steps, same relative
672
- // ordering as hotReload (right after `uiContainer reset`, before the
677
+ // ordering as hotReload (before the
673
678
  // engine-owned audio/input teardown below, which hotReload doesn't
674
679
  // touch at all since it warm-restarts rather than tearing engine
675
680
  // subsystems down).
@@ -679,6 +684,12 @@ export class VgaiSceneGameAdapter implements GameAdapter {
679
684
  if (!engineAdapterKinds.has(kind)) delete systemAdapters[kind as keyof SystemAdapters];
680
685
  }
681
686
  });
687
+ // Defect 2 fix: a full Stop means the whole GAME is going away (every
688
+ // world it mounted, plus any react-door registrations from its HUDs)
689
+ // — unlike hotReload below (a SINGLE mount warm-restarting), so this is
690
+ // the one call site that legitimately wants strip()'s global, no-id
691
+ // form rather than scoping to `this.id`.
692
+ safeStep('debugRegistry.strip', () => debugRegistry.strip());
682
693
 
683
694
  if (!headless) {
684
695
  safeStep('audio teardown', () => {
@@ -689,6 +700,7 @@ export class VgaiSceneGameAdapter implements GameAdapter {
689
700
  });
690
701
  }
691
702
  safeStep('input.dispose', () => input.dispose());
703
+ safeStep('gpuTimer.dispose', () => gpuTimer?.dispose());
692
704
  };
693
705
 
694
706
  const hotReload = async (
@@ -754,20 +766,6 @@ export class VgaiSceneGameAdapter implements GameAdapter {
754
766
  scene.environment = null;
755
767
  });
756
768
  safeStep('debugDraw.clear', () => debugDraw.clear());
757
- safeStep('sceneUIHandle.dispose', () => {
758
- sceneUIHandle?.dispose();
759
- sceneUIHandle = null;
760
- });
761
- // Strip game-registered scene-UI services back to none before the
762
- // incoming game's setup/init runs (D7) — same contract as the
763
- // systemAdapters strip below: a disposed game's onEvent/data/
764
- // worldProjector must never leak onto the next mount.
765
- safeStep('reset sceneUIServices', () => {
766
- sceneUIServices = {};
767
- });
768
- safeStep('uiContainer reset', () => {
769
- uiContainer.innerHTML = '';
770
- });
771
769
 
772
770
  // Bulk-remove every system the outgoing game registered (this restart's
773
771
  // predecessor) so warm restarts never accumulate duplicate systems —
@@ -787,6 +785,16 @@ export class VgaiSceneGameAdapter implements GameAdapter {
787
785
  if (!engineAdapterKinds.has(kind)) delete systemAdapters[kind as keyof SystemAdapters];
788
786
  }
789
787
  });
788
+ // Hot-reload re-seed (spec §3.1): the incoming game's setup (below)
789
+ // re-registers its providers/commands under the SAME worldId — strip()
790
+ // clears the outgoing game's registrations first so that re-seed is
791
+ // silent (no stale duplicate-name warning) rather than "replacing" a
792
+ // dead game's entries. Defect 2 fix: scoped to THIS mount's worldId
793
+ // (`this.id`) — a blind global strip() here wiped every OTHER live
794
+ // world's registrations on every warm restart of just this one, plus
795
+ // every react-door registration (whose `useEffect` cleanup never
796
+ // re-fires to restore them after someone else's strip).
797
+ safeStep('debugRegistry.strip', () => debugRegistry.strip(this.id));
790
798
 
791
799
  currentCleanup = await newSetup(ctx, newEditorPreview);
792
800
  };
@@ -833,17 +841,68 @@ function applyEditorCamera(
833
841
  return true;
834
842
  }
835
843
 
844
+ /** The pose `adoptSceneCamera` compares against to detect that a component
845
+ * already framed the runtime camera during scene load (#139). Capture with
846
+ * `captureCameraPose(camera)` immediately BEFORE `loadScene`. */
847
+ export interface CameraPose {
848
+ position: THREE.Vector3;
849
+ quaternion: THREE.Quaternion;
850
+ }
851
+
852
+ export function captureCameraPose(camera: THREE.PerspectiveCamera): CameraPose {
853
+ return { position: camera.position.clone(), quaternion: camera.quaternion.clone() };
854
+ }
855
+
836
856
  export function adoptSceneCamera(
837
857
  sceneInstance: SceneInstance,
838
858
  runtimeCamera: THREE.PerspectiveCamera,
859
+ preLoadPose?: CameraPose,
839
860
  ): boolean {
840
861
  const sceneCam = sceneInstance.cameras[0];
841
862
  if (!sceneCam) return false;
863
+ // #133 (blind run #4): `camera.type: 'orthographic'` builds a real
864
+ // OrthographicCamera in the scene graph (`createCamera`), but the RUNTIME
865
+ // renders through a hardcoded PerspectiveCamera — the authored projection
866
+ // silently never reached the screen. Until ortho support is ranked
867
+ // (implement-vs-reject, owner call on #133), say so loudly instead of
868
+ // letting a coplanar game render in unexplained perspective.
869
+ if ((sceneCam as THREE.Camera & { isOrthographicCamera?: boolean }).isOrthographicCamera) {
870
+ console.warn(
871
+ "adoptSceneCamera (#133): this scene's camera is ORTHOGRAPHIC, but the runtime camera is " +
872
+ 'perspective-only — the orthographic projection is NOT applied (only the pose is). ' +
873
+ 'Use type: "perspective" (a long-lens fake: far position + small fov) until #133 lands.',
874
+ );
875
+ }
876
+ // #139 (blind run #5): if a GameComponent already positioned/oriented the
877
+ // runtime camera during scene load (`SceneCamera.init`'s
878
+ // `ctx.camera.position.set` + `lookAt` is the blessed shape), the camera
879
+ // ENTITY's transform must not stomp it — an unauthored `transform.rotation`
880
+ // is identity ("stare down −Z"), which silently blanked an entire correct
881
+ // game while every state-based probe spec passed. Components win the pose;
882
+ // the entity still contributes the LENS (fov/near/far below), which
883
+ // `SceneCamera` never sets.
884
+ const componentFramedCamera =
885
+ preLoadPose !== undefined &&
886
+ (!runtimeCamera.position.equals(preLoadPose.position) ||
887
+ !runtimeCamera.quaternion.equals(preLoadPose.quaternion));
842
888
  const parent = sceneCam.parent;
843
- if (parent) {
889
+ if (parent && !componentFramedCamera) {
844
890
  parent.updateMatrixWorld(true);
845
891
  runtimeCamera.position.copy(parent.getWorldPosition(new THREE.Vector3()));
846
- runtimeCamera.quaternion.copy(parent.getWorldQuaternion(new THREE.Quaternion()));
892
+ const worldQuat = parent.getWorldQuaternion(new THREE.Quaternion());
893
+ runtimeCamera.quaternion.copy(worldQuat);
894
+ // Identity orientation on an adopted scene camera is almost never intent
895
+ // (it means "look at the horizon down −Z", not "look at my scene") — the
896
+ // exact silent-blank-viewport footgun above. Adopt it anyway (authored
897
+ // data is truth) but say so loudly, with the two blessed remedies.
898
+ if (Math.abs(1 - Math.abs(worldQuat.w)) < 1e-6) {
899
+ console.warn(
900
+ 'adoptSceneCamera (#139): the scene camera entity has no rotation — the runtime camera ' +
901
+ 'will stare horizontally down −Z and may show nothing. Either attach the SceneCamera ' +
902
+ 'component (position + lookAt, no quaternion math) or author transform.rotation on ' +
903
+ 'the camera entity.',
904
+ );
905
+ }
847
906
  }
848
907
  if (sceneCam instanceof THREE.PerspectiveCamera) {
849
908
  runtimeCamera.fov = sceneCam.fov;