@vgai/engine 0.5.5 → 0.5.6

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 (446) hide show
  1. package/dist/adapter/adapter-surface.d.ts +30 -0
  2. package/dist/adapter/adapter-surface.d.ts.map +1 -0
  3. package/dist/adapter/adapter-surface.js +18 -0
  4. package/dist/adapter/authoring.d.ts +597 -0
  5. package/dist/adapter/authoring.d.ts.map +1 -0
  6. package/dist/adapter/authoring.js +22 -0
  7. package/dist/adapter/colyseus-networking-adapter.d.ts +77 -0
  8. package/dist/adapter/colyseus-networking-adapter.d.ts.map +1 -0
  9. package/dist/adapter/colyseus-networking-adapter.js +76 -0
  10. package/dist/adapter/first-party-systems.d.ts +23 -0
  11. package/dist/adapter/first-party-systems.d.ts.map +1 -0
  12. package/dist/adapter/first-party-systems.js +196 -0
  13. package/dist/adapter/host-context.d.ts +194 -0
  14. package/dist/adapter/host-context.d.ts.map +1 -0
  15. package/dist/adapter/host-context.js +80 -0
  16. package/dist/adapter/index.d.ts +33 -0
  17. package/dist/adapter/index.d.ts.map +1 -0
  18. package/dist/adapter/index.js +25 -0
  19. package/dist/adapter/ingest/game-contract.d.ts +53 -0
  20. package/dist/adapter/ingest/game-contract.d.ts.map +1 -0
  21. package/dist/adapter/ingest/game-contract.js +30 -0
  22. package/dist/adapter/ingest/scene-capture.d.ts +121 -0
  23. package/dist/adapter/ingest/scene-capture.d.ts.map +1 -0
  24. package/dist/adapter/ingest/scene-capture.js +270 -0
  25. package/dist/adapter/ingest/structural-ids.d.ts +64 -0
  26. package/dist/adapter/ingest/structural-ids.d.ts.map +1 -0
  27. package/dist/adapter/ingest/structural-ids.js +110 -0
  28. package/dist/adapter/ingest/upstream-pin.d.ts +44 -0
  29. package/dist/adapter/ingest/upstream-pin.d.ts.map +1 -0
  30. package/dist/adapter/ingest/upstream-pin.js +47 -0
  31. package/dist/adapter/loop-gate-report.d.ts +34 -0
  32. package/dist/adapter/loop-gate-report.d.ts.map +1 -0
  33. package/dist/adapter/loop-gate-report.js +37 -0
  34. package/dist/adapter/rapier-physics-adapter.d.ts +69 -0
  35. package/dist/adapter/rapier-physics-adapter.d.ts.map +1 -0
  36. package/dist/adapter/rapier-physics-adapter.js +135 -0
  37. package/dist/adapter/root-adapter.d.ts +195 -0
  38. package/dist/adapter/root-adapter.d.ts.map +1 -0
  39. package/dist/adapter/root-adapter.js +25 -0
  40. package/dist/adapter/setup-three-root-adapter.d.ts +87 -0
  41. package/dist/adapter/setup-three-root-adapter.d.ts.map +1 -0
  42. package/dist/adapter/setup-three-root-adapter.js +791 -0
  43. package/dist/adapter/system-adapter.d.ts +453 -0
  44. package/dist/adapter/system-adapter.d.ts.map +1 -0
  45. package/dist/adapter/system-adapter.js +13 -0
  46. package/dist/adapter/transform.d.ts +18 -0
  47. package/dist/adapter/transform.d.ts.map +1 -0
  48. package/dist/adapter/transform.js +1 -0
  49. package/dist/ai/navigation.d.ts +78 -0
  50. package/dist/ai/navigation.d.ts.map +1 -0
  51. package/dist/ai/navigation.js +152 -0
  52. package/dist/animation/anim-graph-types.d.ts +25 -0
  53. package/dist/animation/anim-graph-types.d.ts.map +1 -0
  54. package/dist/animation/anim-graph-types.js +1 -0
  55. package/dist/animation/animation-clock.d.ts +213 -0
  56. package/dist/animation/animation-clock.d.ts.map +1 -0
  57. package/dist/animation/animation-clock.js +301 -0
  58. package/dist/animation/blend-node.d.ts +22 -0
  59. package/dist/animation/blend-node.d.ts.map +1 -0
  60. package/dist/animation/blend-node.js +97 -0
  61. package/dist/animation/camera-ownership.d.ts +249 -0
  62. package/dist/animation/camera-ownership.d.ts.map +1 -0
  63. package/dist/animation/camera-ownership.js +169 -0
  64. package/dist/animation/cinematic-cues.d.ts +200 -0
  65. package/dist/animation/cinematic-cues.d.ts.map +1 -0
  66. package/dist/animation/cinematic-cues.js +213 -0
  67. package/dist/animation/clip-map.d.ts +12 -0
  68. package/dist/animation/clip-map.d.ts.map +1 -0
  69. package/dist/animation/clip-map.js +31 -0
  70. package/dist/animation/cubic-spline-interpolant.d.ts +54 -0
  71. package/dist/animation/cubic-spline-interpolant.d.ts.map +1 -0
  72. package/dist/animation/cubic-spline-interpolant.js +111 -0
  73. package/dist/animation/theatre-clock-binding.d.ts +89 -0
  74. package/dist/animation/theatre-clock-binding.d.ts.map +1 -0
  75. package/dist/animation/theatre-clock-binding.js +29 -0
  76. package/dist/animation/theatre-director.d.ts +277 -0
  77. package/dist/animation/theatre-director.d.ts.map +1 -0
  78. package/dist/animation/theatre-director.js +248 -0
  79. package/dist/animation/theatre-object-binding.d.ts +305 -0
  80. package/dist/animation/theatre-object-binding.d.ts.map +1 -0
  81. package/dist/animation/theatre-object-binding.js +351 -0
  82. package/dist/animation/xstate-animation-binding.d.ts +119 -0
  83. package/dist/animation/xstate-animation-binding.d.ts.map +1 -0
  84. package/dist/animation/xstate-animation-binding.js +349 -0
  85. package/dist/animation/xstate-animation-meta.d.ts +266 -0
  86. package/dist/animation/xstate-animation-meta.d.ts.map +1 -0
  87. package/dist/animation/xstate-animation-meta.js +252 -0
  88. package/dist/asset-formats/camera.d.ts +15 -0
  89. package/dist/asset-formats/camera.d.ts.map +1 -0
  90. package/dist/asset-formats/camera.js +15 -0
  91. package/dist/asset-formats/collider.d.ts +21 -0
  92. package/dist/asset-formats/collider.d.ts.map +1 -0
  93. package/dist/asset-formats/collider.js +53 -0
  94. package/dist/asset-formats/index.d.ts +46 -0
  95. package/dist/asset-formats/index.d.ts.map +1 -0
  96. package/dist/asset-formats/index.js +36 -0
  97. package/dist/asset-formats/instances.d.ts +17 -0
  98. package/dist/asset-formats/instances.d.ts.map +1 -0
  99. package/dist/asset-formats/instances.js +31 -0
  100. package/dist/asset-formats/light.d.ts +21 -0
  101. package/dist/asset-formats/light.d.ts.map +1 -0
  102. package/dist/asset-formats/light.js +35 -0
  103. package/dist/asset-formats/material.d.ts +129 -0
  104. package/dist/asset-formats/material.d.ts.map +1 -0
  105. package/dist/asset-formats/material.js +88 -0
  106. package/dist/asset-formats/mesh.d.ts +22 -0
  107. package/dist/asset-formats/mesh.d.ts.map +1 -0
  108. package/dist/asset-formats/mesh.js +64 -0
  109. package/dist/asset-formats/parse.d.ts +20 -0
  110. package/dist/asset-formats/parse.d.ts.map +1 -0
  111. package/dist/asset-formats/parse.js +34 -0
  112. package/dist/asset-formats/particles.d.ts +1390 -0
  113. package/dist/asset-formats/particles.d.ts.map +1 -0
  114. package/dist/asset-formats/particles.js +319 -0
  115. package/dist/asset-formats/render-env.d.ts +387 -0
  116. package/dist/asset-formats/render-env.d.ts.map +1 -0
  117. package/dist/asset-formats/render-env.js +300 -0
  118. package/dist/asset-formats/tuples.d.ts +12 -0
  119. package/dist/asset-formats/tuples.d.ts.map +1 -0
  120. package/dist/asset-formats/tuples.js +14 -0
  121. package/dist/asset-loaders.d.ts +97 -0
  122. package/dist/asset-loaders.d.ts.map +1 -0
  123. package/dist/asset-loaders.js +209 -0
  124. package/dist/asset-parse-error.d.ts +24 -0
  125. package/dist/asset-parse-error.d.ts.map +1 -0
  126. package/dist/asset-parse-error.js +29 -0
  127. package/dist/asset-registry.d.ts +38 -0
  128. package/dist/asset-registry.d.ts.map +1 -0
  129. package/dist/asset-registry.js +66 -0
  130. package/dist/assets.d.ts +26 -0
  131. package/dist/assets.d.ts.map +1 -0
  132. package/dist/assets.js +55 -0
  133. package/dist/audio/wav-encode.d.ts +38 -0
  134. package/dist/audio/wav-encode.d.ts.map +1 -0
  135. package/dist/audio/wav-encode.js +97 -0
  136. package/dist/canvas-react/engine-bridge.d.ts +45 -0
  137. package/dist/canvas-react/engine-bridge.d.ts.map +1 -0
  138. package/dist/canvas-react/engine-bridge.js +45 -0
  139. package/dist/canvas-react/index.d.ts +42 -0
  140. package/dist/canvas-react/index.d.ts.map +1 -0
  141. package/dist/canvas-react/index.js +41 -0
  142. package/dist/canvas-react/pixi-primitive.d.ts +85 -0
  143. package/dist/canvas-react/pixi-primitive.d.ts.map +1 -0
  144. package/dist/canvas-react/pixi-primitive.js +181 -0
  145. package/dist/canvas-react/pixi-react-adapter.d.ts +71 -0
  146. package/dist/canvas-react/pixi-react-adapter.d.ts.map +1 -0
  147. package/dist/canvas-react/pixi-react-adapter.js +229 -0
  148. package/dist/canvas-react/pixi-react-root-factory.d.ts +56 -0
  149. package/dist/canvas-react/pixi-react-root-factory.d.ts.map +1 -0
  150. package/dist/canvas-react/pixi-react-root-factory.js +73 -0
  151. package/dist/canvas-react/world-context.d.ts +88 -0
  152. package/dist/canvas-react/world-context.d.ts.map +1 -0
  153. package/dist/canvas-react/world-context.js +212 -0
  154. package/dist/config.d.ts +9 -0
  155. package/dist/config.d.ts.map +1 -0
  156. package/dist/config.js +8 -0
  157. package/dist/core/frame-pacing.d.ts +90 -0
  158. package/dist/core/frame-pacing.d.ts.map +1 -0
  159. package/dist/core/frame-pacing.js +89 -0
  160. package/dist/core/game-loop.d.ts +62 -0
  161. package/dist/core/game-loop.d.ts.map +1 -0
  162. package/dist/core/game-loop.js +189 -0
  163. package/dist/core/seeded-random.d.ts +69 -0
  164. package/dist/core/seeded-random.d.ts.map +1 -0
  165. package/dist/core/seeded-random.js +121 -0
  166. package/dist/core/sim-clock.d.ts +199 -0
  167. package/dist/core/sim-clock.d.ts.map +1 -0
  168. package/dist/core/sim-clock.js +291 -0
  169. package/dist/core/system-runner.d.ts +96 -0
  170. package/dist/core/system-runner.d.ts.map +1 -0
  171. package/dist/core/system-runner.js +253 -0
  172. package/dist/core/types.d.ts +111 -0
  173. package/dist/core/types.d.ts.map +1 -0
  174. package/dist/core/types.js +25 -0
  175. package/dist/data/data-asset.d.ts +101 -0
  176. package/dist/data/data-asset.d.ts.map +1 -0
  177. package/dist/data/data-asset.js +122 -0
  178. package/dist/data/data-check-core.d.ts +109 -0
  179. package/dist/data/data-check-core.d.ts.map +1 -0
  180. package/dist/data/data-check-core.js +177 -0
  181. package/dist/data/data-ref.d.ts +79 -0
  182. package/dist/data/data-ref.d.ts.map +1 -0
  183. package/dist/data/data-ref.js +130 -0
  184. package/dist/data/vite-plugin-data.d.ts +79 -0
  185. package/dist/data/vite-plugin-data.d.ts.map +1 -0
  186. package/dist/data/vite-plugin-data.js +217 -0
  187. package/dist/defaults.d.ts +233 -0
  188. package/dist/defaults.d.ts.map +1 -0
  189. package/dist/defaults.js +137 -0
  190. package/dist/dev/chrome-trace.d.ts +45 -0
  191. package/dist/dev/chrome-trace.d.ts.map +1 -0
  192. package/dist/dev/chrome-trace.js +114 -0
  193. package/dist/dev/console-bridge.d.ts +22 -0
  194. package/dist/dev/console-bridge.d.ts.map +1 -0
  195. package/dist/dev/console-bridge.js +71 -0
  196. package/dist/dev/debug-draw.d.ts +24 -0
  197. package/dist/dev/debug-draw.d.ts.map +1 -0
  198. package/dist/dev/debug-draw.js +73 -0
  199. package/dist/dev/instruments.d.ts +133 -0
  200. package/dist/dev/instruments.d.ts.map +1 -0
  201. package/dist/dev/instruments.js +231 -0
  202. package/dist/dev/logger.d.ts +30 -0
  203. package/dist/dev/logger.d.ts.map +1 -0
  204. package/dist/dev/logger.js +90 -0
  205. package/dist/dev/performance-profiler.d.ts +111 -0
  206. package/dist/dev/performance-profiler.d.ts.map +1 -0
  207. package/dist/dev/performance-profiler.js +215 -0
  208. package/dist/dev/render-debug-adapter.d.ts +57 -0
  209. package/dist/dev/render-debug-adapter.d.ts.map +1 -0
  210. package/dist/dev/render-debug-adapter.js +141 -0
  211. package/dist/dev/render-memory.d.ts +53 -0
  212. package/dist/dev/render-memory.d.ts.map +1 -0
  213. package/dist/dev/render-memory.js +190 -0
  214. package/dist/dev/webgl-frame-capture.d.ts +134 -0
  215. package/dist/dev/webgl-frame-capture.d.ts.map +1 -0
  216. package/dist/dev/webgl-frame-capture.js +270 -0
  217. package/dist/dev/webgl-gpu-timer.d.ts +8 -0
  218. package/dist/dev/webgl-gpu-timer.d.ts.map +1 -0
  219. package/dist/dev/webgl-gpu-timer.js +52 -0
  220. package/dist/ecs/scene-index.d.ts +179 -0
  221. package/dist/ecs/scene-index.d.ts.map +1 -0
  222. package/dist/ecs/scene-index.js +331 -0
  223. package/dist/ecs/scene-query.d.ts +6 -0
  224. package/dist/ecs/scene-query.d.ts.map +1 -0
  225. package/dist/ecs/scene-query.js +40 -0
  226. package/dist/ecs/user-data.d.ts +193 -0
  227. package/dist/ecs/user-data.d.ts.map +1 -0
  228. package/dist/ecs/user-data.js +145 -0
  229. package/dist/index.d.ts +35 -0
  230. package/dist/index.d.ts.map +1 -0
  231. package/dist/index.js +29 -0
  232. package/dist/input/input-manager.d.ts +944 -0
  233. package/dist/input/input-manager.d.ts.map +1 -0
  234. package/dist/input/input-manager.js +2209 -0
  235. package/dist/input/input-types.d.ts +174 -0
  236. package/dist/input/input-types.d.ts.map +1 -0
  237. package/dist/input/input-types.js +1 -0
  238. package/dist/input/prompt-labels.d.ts +21 -0
  239. package/dist/input/prompt-labels.d.ts.map +1 -0
  240. package/dist/input/prompt-labels.js +121 -0
  241. package/dist/input/rebind-controller.d.ts +59 -0
  242. package/dist/input/rebind-controller.d.ts.map +1 -0
  243. package/dist/input/rebind-controller.js +85 -0
  244. package/dist/input/schema.d.ts +16 -0
  245. package/dist/input/schema.d.ts.map +1 -0
  246. package/dist/input/schema.js +228 -0
  247. package/dist/loader.d.ts +76 -0
  248. package/dist/loader.d.ts.map +1 -0
  249. package/dist/loader.js +114 -0
  250. package/dist/manifest/editor-port.d.ts +53 -0
  251. package/dist/manifest/editor-port.d.ts.map +1 -0
  252. package/dist/manifest/editor-port.js +67 -0
  253. package/dist/manifest/filename.d.ts +14 -0
  254. package/dist/manifest/filename.d.ts.map +1 -0
  255. package/dist/manifest/filename.js +43 -0
  256. package/dist/manifest/index.d.ts +6 -0
  257. package/dist/manifest/index.d.ts.map +1 -0
  258. package/dist/manifest/index.js +9 -0
  259. package/dist/manifest/load-file.d.ts +7 -0
  260. package/dist/manifest/load-file.d.ts.map +1 -0
  261. package/dist/manifest/load-file.js +23 -0
  262. package/dist/manifest/load.d.ts +161 -0
  263. package/dist/manifest/load.d.ts.map +1 -0
  264. package/dist/manifest/load.js +269 -0
  265. package/dist/manifest/locate.d.ts +24 -0
  266. package/dist/manifest/locate.d.ts.map +1 -0
  267. package/dist/manifest/locate.js +48 -0
  268. package/dist/manifest/schema.d.ts +293 -0
  269. package/dist/manifest/schema.d.ts.map +1 -0
  270. package/dist/manifest/schema.js +633 -0
  271. package/dist/physics/collider-dimensions.d.ts +63 -0
  272. package/dist/physics/collider-dimensions.d.ts.map +1 -0
  273. package/dist/physics/collider-dimensions.js +98 -0
  274. package/dist/physics/collision-system.d.ts +41 -0
  275. package/dist/physics/collision-system.d.ts.map +1 -0
  276. package/dist/physics/collision-system.js +64 -0
  277. package/dist/physics/physics-registry.d.ts +45 -0
  278. package/dist/physics/physics-registry.d.ts.map +1 -0
  279. package/dist/physics/physics-registry.js +65 -0
  280. package/dist/physics/transform-writer.d.ts +16 -0
  281. package/dist/physics/transform-writer.d.ts.map +1 -0
  282. package/dist/physics/transform-writer.js +38 -0
  283. package/dist/pixi/authoring.d.ts +93 -0
  284. package/dist/pixi/authoring.d.ts.map +1 -0
  285. package/dist/pixi/authoring.js +207 -0
  286. package/dist/pixi/index.d.ts +16 -0
  287. package/dist/pixi/index.d.ts.map +1 -0
  288. package/dist/pixi/index.js +15 -0
  289. package/dist/pixi/ingest-iframe.d.ts +82 -0
  290. package/dist/pixi/ingest-iframe.d.ts.map +1 -0
  291. package/dist/pixi/ingest-iframe.js +166 -0
  292. package/dist/pixi/ingest.d.ts +97 -0
  293. package/dist/pixi/ingest.d.ts.map +1 -0
  294. package/dist/pixi/ingest.js +40 -0
  295. package/dist/pixi/physics-registry.d.ts +24 -0
  296. package/dist/pixi/physics-registry.d.ts.map +1 -0
  297. package/dist/pixi/physics-registry.js +38 -0
  298. package/dist/pixi/scene-capture.d.ts +43 -0
  299. package/dist/pixi/scene-capture.d.ts.map +1 -0
  300. package/dist/pixi/scene-capture.js +92 -0
  301. package/dist/pixi/system-adapters.d.ts +16 -0
  302. package/dist/pixi/system-adapters.d.ts.map +1 -0
  303. package/dist/pixi/system-adapters.js +37 -0
  304. package/dist/react/unmanaged-root-detector.d.ts +18 -0
  305. package/dist/react/unmanaged-root-detector.d.ts.map +1 -0
  306. package/dist/react/unmanaged-root-detector.js +70 -0
  307. package/dist/react/use-data.d.ts +60 -0
  308. package/dist/react/use-data.d.ts.map +1 -0
  309. package/dist/react/use-data.js +101 -0
  310. package/dist/react/use-selection.d.ts +54 -0
  311. package/dist/react/use-selection.d.ts.map +1 -0
  312. package/dist/react/use-selection.js +71 -0
  313. package/dist/react/world-state.d.ts +154 -0
  314. package/dist/react/world-state.d.ts.map +1 -0
  315. package/dist/react/world-state.js +220 -0
  316. package/dist/render/auto-batcher.d.ts +34 -0
  317. package/dist/render/auto-batcher.d.ts.map +1 -0
  318. package/dist/render/auto-batcher.js +140 -0
  319. package/dist/render/instance-mesh.d.ts +5 -0
  320. package/dist/render/instance-mesh.d.ts.map +1 -0
  321. package/dist/render/instance-mesh.js +19 -0
  322. package/dist/render/light-camera-factory.d.ts +24 -0
  323. package/dist/render/light-camera-factory.d.ts.map +1 -0
  324. package/dist/render/light-camera-factory.js +71 -0
  325. package/dist/render/lod.d.ts +13 -0
  326. package/dist/render/lod.d.ts.map +1 -0
  327. package/dist/render/lod.js +16 -0
  328. package/dist/render/material-factory.d.ts +15 -0
  329. package/dist/render/material-factory.d.ts.map +1 -0
  330. package/dist/render/material-factory.js +186 -0
  331. package/dist/render/mesh-shadow.d.ts +11 -0
  332. package/dist/render/mesh-shadow.d.ts.map +1 -0
  333. package/dist/render/mesh-shadow.js +19 -0
  334. package/dist/render/particles-factory.d.ts +99 -0
  335. package/dist/render/particles-factory.d.ts.map +1 -0
  336. package/dist/render/particles-factory.js +361 -0
  337. package/dist/render/render-batch-system.d.ts +33 -0
  338. package/dist/render/render-batch-system.d.ts.map +1 -0
  339. package/dist/render/render-batch-system.js +223 -0
  340. package/dist/render/render-features.d.ts +47 -0
  341. package/dist/render/render-features.d.ts.map +1 -0
  342. package/dist/render/render-features.js +105 -0
  343. package/dist/render/render-settings.d.ts +35 -0
  344. package/dist/render/render-settings.d.ts.map +1 -0
  345. package/dist/render/render-settings.js +51 -0
  346. package/dist/render/spark-renderer-lifecycle.d.ts +18 -0
  347. package/dist/render/spark-renderer-lifecycle.d.ts.map +1 -0
  348. package/dist/render/spark-renderer-lifecycle.js +57 -0
  349. package/dist/render/viewport-shading.d.ts +17 -0
  350. package/dist/render/viewport-shading.d.ts.map +1 -0
  351. package/dist/render/viewport-shading.js +87 -0
  352. package/dist/runtime/create-runtime.d.ts +259 -0
  353. package/dist/runtime/create-runtime.d.ts.map +1 -0
  354. package/dist/runtime/create-runtime.js +666 -0
  355. package/dist/runtime/debug-bridge.d.ts +288 -0
  356. package/dist/runtime/debug-bridge.d.ts.map +1 -0
  357. package/dist/runtime/debug-bridge.js +277 -0
  358. package/dist/runtime/debug-registry.d.ts +287 -0
  359. package/dist/runtime/debug-registry.d.ts.map +1 -0
  360. package/dist/runtime/debug-registry.js +528 -0
  361. package/dist/runtime/dev-layers.d.ts +34 -0
  362. package/dist/runtime/dev-layers.d.ts.map +1 -0
  363. package/dist/runtime/dev-layers.js +40 -0
  364. package/dist/runtime/frame-selector-cache.d.ts +41 -0
  365. package/dist/runtime/frame-selector-cache.d.ts.map +1 -0
  366. package/dist/runtime/frame-selector-cache.js +65 -0
  367. package/dist/runtime/game.d.ts +576 -0
  368. package/dist/runtime/game.d.ts.map +1 -0
  369. package/dist/runtime/game.js +1003 -0
  370. package/dist/runtime/gameplay-rng-trap.d.ts +47 -0
  371. package/dist/runtime/gameplay-rng-trap.d.ts.map +1 -0
  372. package/dist/runtime/gameplay-rng-trap.js +95 -0
  373. package/dist/runtime/input-router.d.ts +78 -0
  374. package/dist/runtime/input-router.d.ts.map +1 -0
  375. package/dist/runtime/input-router.js +171 -0
  376. package/dist/runtime/mount-game.d.ts +126 -0
  377. package/dist/runtime/mount-game.d.ts.map +1 -0
  378. package/dist/runtime/mount-game.js +159 -0
  379. package/dist/runtime/mount-manifest.d.ts +174 -0
  380. package/dist/runtime/mount-manifest.d.ts.map +1 -0
  381. package/dist/runtime/mount-manifest.js +304 -0
  382. package/dist/runtime/presentation.d.ts +85 -0
  383. package/dist/runtime/presentation.d.ts.map +1 -0
  384. package/dist/runtime/presentation.js +92 -0
  385. package/dist/runtime/render-audio-control.d.ts +126 -0
  386. package/dist/runtime/render-audio-control.d.ts.map +1 -0
  387. package/dist/runtime/render-audio-control.js +116 -0
  388. package/dist/runtime/render-control.d.ts +347 -0
  389. package/dist/runtime/render-control.d.ts.map +1 -0
  390. package/dist/runtime/render-control.js +317 -0
  391. package/dist/runtime/render-seed.d.ts +56 -0
  392. package/dist/runtime/render-seed.d.ts.map +1 -0
  393. package/dist/runtime/render-seed.js +73 -0
  394. package/dist/runtime/state-bridge.d.ts +60 -0
  395. package/dist/runtime/state-bridge.d.ts.map +1 -0
  396. package/dist/runtime/state-bridge.js +62 -0
  397. package/dist/runtime/types.d.ts +285 -0
  398. package/dist/runtime/types.d.ts.map +1 -0
  399. package/dist/runtime/types.js +1 -0
  400. package/dist/runtime/unexported-game-trap.d.ts +36 -0
  401. package/dist/runtime/unexported-game-trap.d.ts.map +1 -0
  402. package/dist/runtime/unexported-game-trap.js +80 -0
  403. package/dist/setup/setup-audio.d.ts +20 -0
  404. package/dist/setup/setup-audio.d.ts.map +1 -0
  405. package/dist/setup/setup-audio.js +41 -0
  406. package/dist/setup/setup-particles.d.ts +17 -0
  407. package/dist/setup/setup-particles.d.ts.map +1 -0
  408. package/dist/setup/setup-particles.js +16 -0
  409. package/dist/setup/setup-physics.d.ts +25 -0
  410. package/dist/setup/setup-physics.d.ts.map +1 -0
  411. package/dist/setup/setup-physics.js +51 -0
  412. package/dist/setup/setup-renderer.d.ts +82 -0
  413. package/dist/setup/setup-renderer.d.ts.map +1 -0
  414. package/dist/setup/setup-renderer.js +381 -0
  415. package/dist/world3d-react/engine-bridge.d.ts +47 -0
  416. package/dist/world3d-react/engine-bridge.d.ts.map +1 -0
  417. package/dist/world3d-react/engine-bridge.js +48 -0
  418. package/dist/world3d-react/index.d.ts +47 -0
  419. package/dist/world3d-react/index.d.ts.map +1 -0
  420. package/dist/world3d-react/index.js +46 -0
  421. package/dist/world3d-react/r3f-adapter.d.ts +51 -0
  422. package/dist/world3d-react/r3f-adapter.d.ts.map +1 -0
  423. package/dist/world3d-react/r3f-adapter.js +368 -0
  424. package/dist/world3d-react/r3f-root-factory.d.ts +62 -0
  425. package/dist/world3d-react/r3f-root-factory.d.ts.map +1 -0
  426. package/dist/world3d-react/r3f-root-factory.js +79 -0
  427. package/dist/world3d-react/rapier-physics-bridge.d.ts +76 -0
  428. package/dist/world3d-react/rapier-physics-bridge.d.ts.map +1 -0
  429. package/dist/world3d-react/rapier-physics-bridge.js +120 -0
  430. package/dist/world3d-react/renderer-config.d.ts +58 -0
  431. package/dist/world3d-react/renderer-config.d.ts.map +1 -0
  432. package/dist/world3d-react/renderer-config.js +96 -0
  433. package/dist/world3d-react/world-context.d.ts +123 -0
  434. package/dist/world3d-react/world-context.d.ts.map +1 -0
  435. package/dist/world3d-react/world-context.js +204 -0
  436. package/dist-config/config.js +303 -0
  437. package/dist-config/config.js.map +7 -0
  438. package/package.json +14 -3
  439. package/src/adapter/rapier-physics-adapter.ts +77 -34
  440. package/src/config.ts +8 -0
  441. package/src/core/frame-pacing.ts +26 -0
  442. package/src/core/game-loop.ts +4 -3
  443. package/src/dev/instruments.ts +302 -0
  444. package/src/setup/setup-renderer.ts +2 -0
  445. package/src/world3d-react/index.ts +9 -0
  446. package/src/world3d-react/rapier-physics-bridge.tsx +137 -0
@@ -0,0 +1,666 @@
1
+ import * as THREE from 'three';
2
+ import { assertNever } from '../adapter/adapter-surface';
3
+ import { createAssetCache } from '../assets';
4
+ import { createGameLoop } from '../core/game-loop';
5
+ import { createHostRenderer } from '../setup/setup-renderer';
6
+ // TYPE-ONLY: `create-runtime.ts` must never value-import `pixi.js` — a canvas
7
+ // `RootMountSpec`'s `adapter` is supplied ALREADY-CONSTRUCTED by the caller, so
8
+ // the host only ever needs the seam's types.
9
+ import { createGame, createRootInstance, isFirstPartyMounted, } from './game';
10
+ import { createInputRouter, stackOrder } from './input-router';
11
+ import { installRenderControlHarness, isRenderModeRequested } from './render-control';
12
+ /**
13
+ * Register a three world for a freshly-mounted game onto the Game shell. Shared
14
+ * by `createGameRuntime` and every headless test harness
15
+ * (`test/game-root.test.ts`, `test/frame-order.test.ts`,
16
+ * `test/game-two-roots.test.ts`) so there is exactly one code path for this
17
+ * wiring (T7.1 slice 1, id-generalized in slice 3 for the two-world proof — stage
18
+ * 3) — `physics`/`collisions`/`camera`/ `frame` are populated from the mount's
19
+ * first-party `GameContext`/ `MountedSetupThreeRoot` when available, left
20
+ * `undefined` otherwise (an external adapter's mount has none of these
21
+ * first-party handles — `frame` in particular is what makes
22
+ * `GameInternal.runFrame` (T7.1 slice 2) fall back to a single opaque
23
+ * `mounted.update` call per substep for such a world).
24
+ */
25
+ function firstPartyExtras(mounted) {
26
+ if (!isFirstPartyMounted(mounted))
27
+ return {};
28
+ return {
29
+ physics: mounted.ctx.physics,
30
+ collisions: mounted.ctx.collisions,
31
+ camera: mounted.ctx.camera,
32
+ frame: mounted.frame,
33
+ };
34
+ }
35
+ /**
36
+ * Register a three world onto the Game shell. `opts.id` defaults to
37
+ * `'main'` — the single-world callers (`createGameRuntime`, slice-1/2 tests)
38
+ * are unaffected; a second/third world (T7.1 slice 3's two-world proof, and
39
+ * real multi-world manifests later) pass an explicit id. This is the ONE
40
+ * registration code path for a three world, whatever its id.
41
+ */
42
+ export function registerThreeRoot(game, adapter, mounted, opts) {
43
+ const world = createRootInstance({
44
+ id: opts?.id ?? 'main',
45
+ kind: 'three',
46
+ pausable: opts?.pausable ?? true,
47
+ adapter,
48
+ mounted,
49
+ scene: mounted.scene,
50
+ ...firstPartyExtras(mounted),
51
+ });
52
+ game.registerRoot(world);
53
+ return world;
54
+ }
55
+ /**
56
+ * Register a canvas world onto the Game shell — the pixi analog of
57
+ * {@link registerThreeRoot}. `adapter` is the seam's own
58
+ * `RootAdapter<'canvas'>`; `RootInstance.adapter` itself only needs `.id`
59
+ * (`AdapterHandle`, `runtime/game.ts`), so this passes through with zero cast.
60
+ * `stage` is the one field every `MountedPixiRoot` actually carries.
61
+ */
62
+ export function registerPixiRoot(game, adapter, mounted, opts) {
63
+ const id = opts?.id ?? 'main';
64
+ const world = createRootInstance({
65
+ id,
66
+ kind: 'canvas',
67
+ pausable: opts?.pausable ?? true,
68
+ adapter,
69
+ mounted,
70
+ stage: mounted.stage,
71
+ });
72
+ game.registerRoot(world);
73
+ return world;
74
+ }
75
+ /**
76
+ * Register a react world onto the Game shell (T6.2 slice 1) — the react
77
+ * analog of {@link registerThreeRoot}/{@link registerPixiRoot}. A react
78
+ * world has no `frame` hooks (react's own
79
+ * `createRoot` schedules its commits; `GameInternal.runFrame` correctly
80
+ * leaves a world with no `frame` untouched by its opaque-`update` fallback
81
+ * too, since `MountedReactGame` declares no `update`). `adapter` is typed
82
+ * as the real {@link ReactRootAdapter} shape (T7.5, same reasoning as
83
+ * `registerPixiRoot`'s doc comment above) — `RootInstance.adapter` only
84
+ * needs `.id`, so this passes through with zero cast.
85
+ */
86
+ export function registerReactRoot(game, adapter, mounted, container, opts) {
87
+ const world = createRootInstance({
88
+ id: opts?.id ?? 'main',
89
+ kind: 'dom',
90
+ pausable: opts?.pausable ?? true,
91
+ adapter,
92
+ mounted,
93
+ container,
94
+ });
95
+ game.registerRoot(world);
96
+ return world;
97
+ }
98
+ /**
99
+ * Bootstrap the game host and mount a game adapter.
100
+ *
101
+ * `createGameRuntime` is the universal HOST: it owns the root surfaces,
102
+ * renderers, loop, and asset cache. Every game — including a one-root game —
103
+ * uses the same explicit adapter-root path.
104
+ */
105
+ export async function createGameRuntime(config) {
106
+ return createRootsGameRuntime(config);
107
+ }
108
+ // ---------------------------------------------------------------------------
109
+ // Worlds path (T6.1 slice 1)
110
+ // ---------------------------------------------------------------------------
111
+ /** A stand-in `THREE.WebGLRenderer` for headless (`headless:true`) three
112
+ * roots — mirrors `SetupThreeRootAdapter.mount`'s own `headlessComposer`
113
+ * pattern (`adapter/setup-three-root-adapter.ts`): a headless first-party
114
+ * mount never calls a render-phase method on `host.renderer` at all, so
115
+ * this only needs to satisfy the handful of calls THIS file itself makes
116
+ * (`setPixelRatio`/`setClearColor`/`setSize` at mount, `dispose`/
117
+ * `forceContextLoss` at teardown) — never a real GL call. Node conformance
118
+ * tests only; never used when `headless` is left `false`/absent. */
119
+ function createHeadlessRendererStub() {
120
+ return {
121
+ setPixelRatio() { },
122
+ setClearColor() { },
123
+ setSize() { },
124
+ dispose() { },
125
+ forceContextLoss() { },
126
+ };
127
+ }
128
+ /** Mount one three `RootMountSpec` (canvas + renderer construction, per
129
+ * D5 §1/§4, then `registerThreeRoot`). Split out of
130
+ * `createRootsGameRuntime` purely to keep that function's own branching
131
+ * simple — see `mountOnePixiRoot` for the canvas sibling. */
132
+ async function mountOneThreeRoot(spec, ctx) {
133
+ const { game, canvas, w, h, dpr, isBottom, headless, assets } = ctx;
134
+ const renderer = headless
135
+ ? createHeadlessRendererStub()
136
+ : createHostRenderer(canvas, w, h, undefined, {
137
+ alpha: !isBottom,
138
+ preserveDrawingBuffer: true,
139
+ });
140
+ renderer.setSize(w, h, false); // backing resolution only — CSS stacking owns layout size
141
+ // Defect E4.R1 (Fable review): `createHostRenderer`'s OWN construction-time
142
+ // `setSize` call (`setup-renderer.ts`, `updateStyle` defaulting `true` —
143
+ // unchanged there on purpose, see below) stamps `canvas.style.width`/
144
+ // `.height` to literal `${w}px`/`${h}px` the moment the renderer is built,
145
+ // OVERWRITING the container-relative `100%`/`100%` the surface-stacking
146
+ // loop above just set. The `renderer.setSize(w, h, false)` line right above
147
+ // this comment does NOT undo that stamp (updateStyle:false only skips
148
+ // TOUCHING style, it can't un-stamp a previous call) — so without this
149
+ // re-assertion, every roots-path three canvas' on-screen size was
150
+ // permanently pinned to whatever `w`/`h` it happened to mount at (usually
151
+ // the manifest's `resolution`, since standalone builds mount before a real
152
+ // container size is known — see `mount-manifest.ts`). Re-asserting here
153
+ // makes the CSS layout size and the render-buffer resolution fully
154
+ // independent, exactly like the react DOM world layer already is: this
155
+ // fixes the template-standalone bug (broken at any viewport other than the
156
+ // manifest's `resolution`, which is also Playwright's DEFAULT viewport —
157
+ // why it went unnoticed) and, for free, tri-world's pre-existing
158
+ // resize-staleness (the roots-path `resize()` below always calls
159
+ // `setSize(rw, rh, false)`, so nothing else was ever going to update this
160
+ // canvas' CSS after mount). `createHostRenderer`'s own default
161
+ // (`updateStyle:true`) is intentionally left alone — the LEGACY
162
+ // single-canvas path (editor play-mode's non-multi-world branch) still
163
+ // relies on that construction-time stamp + its own later `updateStyle:true`
164
+ // resizes for byte-identical behavior; this fix touches only the
165
+ // roots-path canvas, after the fact.
166
+ canvas.style.width = '100%';
167
+ canvas.style.height = '100%';
168
+ renderer.setPixelRatio(dpr);
169
+ if (!isBottom)
170
+ renderer.setClearColor(0x000000, 0); // D5 §1: alpha-clear above the bottom layer
171
+ const host = {
172
+ three: THREE,
173
+ surface: { canvas, width: w, height: h },
174
+ renderer,
175
+ assets,
176
+ headless,
177
+ game,
178
+ };
179
+ const mounted = await spec.adapter.mount(host);
180
+ registerThreeRoot(game, spec.adapter, mounted, { id: spec.id, pausable: spec.pausable });
181
+ return {
182
+ mountedEntry: { id: spec.id, kind: 'three', element: canvas, mounted, renderer },
183
+ routerEntry: { id: spec.id, zOrder: spec.zOrder ?? 0, canvas, hitTest: spec.hitTest },
184
+ };
185
+ }
186
+ /** Mount one canvas `RootMountSpec` (via its own `CanvasHostContext`, per D5
187
+ * §1/§3/§4, then `registerPixiRoot`) — the pixi sibling of
188
+ * `mountOneThreeRoot` above.
189
+ *
190
+ * Unlike `mountOneThreeRoot`, this needs no explicit `canvas.style.width`/
191
+ * `.height` re-assertion (E4.R1). `pixi-surface.ts` constructs its
192
+ * `Application` with `autoDensity: true`, which makes PIXI ITSELF re-stamp
193
+ * `canvas.style.width`/`.height` (real CSS px, matching the LOGICAL
194
+ * width/height passed to `resize()`) on every `app.renderer.resize()` call —
195
+ * including the one this world's `mounted.resize?.()` triggers from the
196
+ * roots-path `resize()` below. So while a pixi world's canvas can start
197
+ * pinned to the mount-time `w`/`h` (same as three, until PIXI's own
198
+ * construction-time resize runs), it self-heals the moment ANY real
199
+ * `session.resize(rw, rh)` fires — every shipped standalone entry
200
+ * (`packages/editor/template/src/main.ts`, `examples/tri-world/src/main.ts`)
201
+ * already calls `session.resize()` unconditionally right after mount, so
202
+ * this never surfaces as a lasting bug the way three' buffer-only resize
203
+ * did (never self-healing, by design — see above). */
204
+ async function mountOnePixiRoot(spec, ctx) {
205
+ const { game, canvas, w, h, dpr, headless, isBottom } = ctx;
206
+ const pixiHost = {
207
+ canvas,
208
+ width: w,
209
+ height: h,
210
+ game,
211
+ headless,
212
+ dpr,
213
+ transparent: !isBottom,
214
+ preserveDrawingBuffer: true,
215
+ };
216
+ const mounted = await spec.adapter.mount(pixiHost);
217
+ registerPixiRoot(game, spec.adapter, mounted, {
218
+ id: spec.id,
219
+ pausable: spec.pausable,
220
+ });
221
+ return {
222
+ mountedEntry: {
223
+ id: spec.id,
224
+ kind: 'canvas',
225
+ element: canvas,
226
+ mounted,
227
+ renderer: undefined,
228
+ },
229
+ routerEntry: {
230
+ id: spec.id,
231
+ zOrder: spec.zOrder ?? 0,
232
+ canvas,
233
+ hitTest: spec.hitTest,
234
+ },
235
+ };
236
+ }
237
+ /**
238
+ * Mount one react `RootMountSpec` (T6.2 slice 1) — the react sibling of
239
+ * `mountOneThreeRoot`/`mountOnePixiRoot`. Unlike its canvas-backed siblings
240
+ * this returns NO `routerEntry`: a react world's DOM-root layer participates in
241
+ * D5's z-order/box stacking (the caller still creates and positions its `<div>`
242
+ * exactly like a canvas — see `createRootsGameRuntime`'s stack-building loop)
243
+ * but needs no entry in the delegating router's hit-test loop (§1.C — "DOM
244
+ * layers need no entry in the router's hit-test loop"): the layer's own
245
+ * `pointer-events` discipline (this file sets `none` on the layer by default;
246
+ * the mounted React tree opts specific elements back in with
247
+ * `pointer-events:auto`) is what lets its interactive elements claim events
248
+ * NATIVELY, via the real DOM, with zero router involvement — and lets a click
249
+ * over its non-interactive (transparent) area fall through to the canvas below
250
+ * it via the SAME native DOM hit-testing (a `pointer-events:none` element is
251
+ * invisible to hit-testing entirely, so the click lands on whatever real DOM
252
+ * element is beneath it — the router's normal canvas-vs-canvas forwarding,
253
+ * unaffected by this layer's presence).
254
+ */
255
+ async function mountOneReactRoot(spec, game,
256
+ /** The ALREADY-created, already-stacked (position/z-index set, appended to
257
+ * `container`) DOM-root layer for this world — see
258
+ * `createRootsGameRuntime`'s surface-stack loop, which builds a `<div>`
259
+ * for every react-kind spec up front, in the SAME pass that builds every
260
+ * other world's canvas. This function must reuse that exact element (never
261
+ * create its own) so `RootInstance.reactRoot()` returns the SAME node
262
+ * that is actually positioned in the stack. */
263
+ layer) {
264
+ layer.style.pointerEvents = 'none';
265
+ // An absolutely-positioned layer with no width/height collapses to zero
266
+ // content size, so a child's
267
+ // own position:absolute offsets resolve against a degenerate containing
268
+ // block (found by the T6.2 slice-3 e2e — clicks landed outside the game).
269
+ layer.style.width = '100%';
270
+ layer.style.height = '100%';
271
+ const reactHost = { container: layer, game };
272
+ const mounted = await spec.adapter.mount(reactHost);
273
+ registerReactRoot(game, spec.adapter, mounted, layer, {
274
+ id: spec.id,
275
+ pausable: spec.pausable,
276
+ });
277
+ return {
278
+ mountedEntry: {
279
+ id: spec.id,
280
+ kind: 'dom',
281
+ element: layer,
282
+ mounted,
283
+ renderer: undefined,
284
+ },
285
+ };
286
+ }
287
+ /**
288
+ * The roots-path implementer behind {@link createGameRuntime} (T6.1 slice
289
+ * 1; react roots added T6.2 slice 1). Builds ONE surface per world — a
290
+ * canvas for three/canvas, a DOM-root `<div>` layer for react — stacked
291
+ * per D5 §1, z-order/ties exactly matching
292
+ * `manifest/load.ts`'s sort, ONE `Game`, and registers every world onto it
293
+ * via `registerThreeRoot`/`registerPixiRoot`/`registerReactRoot` — the
294
+ * SAME wiring `test/game-three-plus-pixi.test.ts` proves by hand for the
295
+ * three/pixi pair. Worlds MOUNT in `roots` ARRAY order ("manifest
296
+ * declaration order" — the frame/registration axis), independent of
297
+ * `zOrder` (the canvas-stacking/rendering axis) — the two orders can differ
298
+ * and both are honored correctly.
299
+ */
300
+ /**
301
+ * Dev/e2e-only `window.__vgaiScene`/`__vgaiCamera` exposure for the roots
302
+ * path's DEFAULT world (E4) — split out of `createRootsGameRuntime` purely
303
+ * to keep that function's own cyclomatic complexity down. Mirrors the
304
+ * legacy single-world path's identical exposure (above, in this same file),
305
+ * using the SAME "first three world, else none" default-world rule the
306
+ * `GameSession.scene`/`.camera` getters alias (`Game.defaultRoot`): a
307
+ * non-threejs default world (or none at all) publishes neither global,
308
+ * exactly like those getters return `undefined` in that case. Returns a
309
+ * retraction callback — identity-guarded (a newer session's globals must
310
+ * never be clobbered by an older session's stop, same reason the legacy
311
+ * path's own cleanup guards it) — that is a no-op when nothing was
312
+ * published (non-DEV build, or non-threejs default world).
313
+ */
314
+ function installDefaultRootDevGlobals(game) {
315
+ if (!import.meta.env?.DEV)
316
+ return () => { };
317
+ const defaultMounted = game.defaultRoot.mounted;
318
+ if (defaultMounted.kind !== 'three')
319
+ return () => { };
320
+ const scene = defaultMounted.scene;
321
+ const w = window;
322
+ w['__vgaiScene'] = scene;
323
+ // An ACCESSOR, not a value read once: a world may replace its camera after
324
+ // mount (fiber's `set({ camera })` — drei's `makeDefault`, or a translated
325
+ // Godot world installing the camera its `.tscn` authors), and a snapshot
326
+ // here reads as authoritative to the probe that reaches for it while naming
327
+ // a camera the frame no longer uses. The retraction guard compares the
328
+ // GETTER's identity, which is the same "don't clobber a newer session"
329
+ // rule the value comparison was.
330
+ const readCamera = () => defaultMounted.camera;
331
+ Object.defineProperty(w, '__vgaiCamera', {
332
+ get: readCamera,
333
+ configurable: true,
334
+ enumerable: true,
335
+ });
336
+ return () => {
337
+ if (w['__vgaiScene'] === scene)
338
+ delete w['__vgaiScene'];
339
+ if (Object.getOwnPropertyDescriptor(w, '__vgaiCamera')?.get === readCamera)
340
+ delete w['__vgaiCamera'];
341
+ };
342
+ }
343
+ /**
344
+ * Mount + register every world spec, in ARRAY (declaration) order — split
345
+ * out of `createRootsGameRuntime` purely to keep that function's own
346
+ * cyclomatic complexity down (E4, same reason `mountOneThreeRoot`/
347
+ * `mountOnePixiRoot` are already split out). React roots contribute NO
348
+ * router entry ("DOM layers need no entry in the router's hit-test loop"):
349
+ * their layer's own `pointer-events` discipline handles claim/fall-through
350
+ * natively, with zero router involvement (see `mountOneReactRoot`'s doc
351
+ * comment).
352
+ */
353
+ async function mountAllRootSpecs(mountSpecs, bottomId, inputs) {
354
+ const { surfacesById, ...shared } = inputs;
355
+ const mountedEntries = [];
356
+ const routerEntries = [];
357
+ for (const spec of mountSpecs) {
358
+ const isBottom = spec.id === bottomId;
359
+ if (spec.kind === 'dom') {
360
+ const layer = surfacesById.get(spec.id);
361
+ const { mountedEntry } = await mountOneReactRoot(spec, shared.game, layer);
362
+ mountedEntries.push(mountedEntry);
363
+ continue;
364
+ }
365
+ const canvas = surfacesById.get(spec.id);
366
+ const oneCtx = { ...shared, canvas, isBottom };
367
+ let mountedEntry;
368
+ let routerEntry;
369
+ if (spec.kind === 'three') {
370
+ ({ mountedEntry, routerEntry } = await mountOneThreeRoot(spec, oneCtx));
371
+ }
372
+ else if (spec.kind === 'canvas') {
373
+ ({ mountedEntry, routerEntry } = await mountOnePixiRoot(spec, oneCtx));
374
+ }
375
+ else {
376
+ // Exhaustiveness guard (§7.4-2): 'react' was already handled by the
377
+ // early `continue` above, so only a hypothetical 4th `AdapterSurface` can
378
+ // reach here — fail loudly rather than silently defaulting. `spec`
379
+ // itself (not `spec.kind`) is what TS has narrowed to `never`, since
380
+ // `RootMountSpec` is a discriminated union at the object level.
381
+ assertNever(spec, 'create-runtime mount loop');
382
+ }
383
+ mountedEntries.push(mountedEntry);
384
+ routerEntries.push(routerEntry);
385
+ }
386
+ return { mountedEntries, routerEntries };
387
+ }
388
+ /**
389
+ * G3/FT-11 — publish the render-control harness (`render-control.ts`) for a
390
+ * live session, returning its retraction (wired into the session's own
391
+ * `stop()`, same leave-nothing-live rule as the debug bridge's `uninstall()`
392
+ * in mount-manifest.ts — render-control has no uninstall surface of its own,
393
+ * a render page being a single-load host by design, so the retraction is
394
+ * the publication's inverse). Split out of `createRootsGameRuntime` purely
395
+ * to keep that function's cyclomatic complexity down (the same reason
396
+ * `mountAllRootSpecs`/`installDefaultRootDevGlobals` are split out).
397
+ *
398
+ * The clock is a documented no-op: a manifest-mounted game has no global
399
+ * cinematic AnimationClock to seek (a cinematic fixture that HAS one
400
+ * installs its own harness with the real clock, e.g.
401
+ * packages/engine/e2e/render-cinematic/main.ts) — the meaningful advance
402
+ * path for a plain game is `simulateSubsteps` (I5 `--simulate`), which
403
+ * drives `game.runFrame`.
404
+ */
405
+ function installSessionRenderHarness(game, location, targetOverride) {
406
+ const target = targetOverride ??
407
+ (typeof window !== 'undefined' ? window : undefined);
408
+ if (target === undefined)
409
+ return undefined;
410
+ installRenderControlHarness({
411
+ game,
412
+ clock: {
413
+ seek() {
414
+ /* no global cinematic clock on a manifest-mounted game — see above */
415
+ },
416
+ seekFrame() {
417
+ /* intentional no-op, as seek() */
418
+ },
419
+ },
420
+ readiness: {
421
+ // Mount is complete by the time this harness exists (the install site
422
+ // in `createRootsGameRuntime` is after `mountAllRootSpecs`
423
+ // resolved) — the hook resolving immediately IS the readiness
424
+ // statement, not an assumption.
425
+ scene() { },
426
+ },
427
+ location,
428
+ target,
429
+ });
430
+ return () => {
431
+ delete target['__vgaiRender'];
432
+ };
433
+ }
434
+ async function createRootsGameRuntime(config) {
435
+ const { container, roots: specs, width, height, headless = false, seed, playtest } = config;
436
+ if (specs.length === 0) {
437
+ throw new Error('createGameRuntime: `roots` must contain at least one root.');
438
+ }
439
+ const mountSpecs = specs;
440
+ const w = Math.max(1, width ?? container.clientWidth ?? 0);
441
+ const h = Math.max(1, height ?? container.clientHeight ?? 0);
442
+ const dpr = headless
443
+ ? 1
444
+ : Math.min(typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1, 2);
445
+ if (!container.style.position)
446
+ container.style.position = 'relative';
447
+ // --- Surface stack (D5 §1): DOM/z-order follows zOrder, ties -> array order
448
+ // — computed FIRST (bottom -> top) so both the z-index assignment below and
449
+ // the router's default-claim rule share one definition. A react world's
450
+ // DOM-root layer shares this SAME stacking pass (T6.2 slice 1 — "one
451
+ // stacking model, no special case") even though it is a `<div>`, not a
452
+ // canvas, and carries no `hitTest` (the router never sees react entries at
453
+ // all — see the dispatch loop below). ---
454
+ // Dev layers sit TOPMOST, above every non-dev root, whatever zOrder either
455
+ // declares: a dev GUI the game can paint over is not a dev GUI. Expressed as
456
+ // two independent `stackOrder` passes concatenated rather than a magic
457
+ // zOrder value, so `stackOrder`'s one rule (ascending zOrder, ties -> array
458
+ // order) still governs WITHIN each band and nothing has to reason about what
459
+ // number is "high enough".
460
+ const claimEntries = mountSpecs.map((spec) => ({
461
+ id: spec.id,
462
+ zOrder: spec.zOrder ?? 0,
463
+ hitTest: spec.hitTest,
464
+ dev: spec.dev === true,
465
+ }));
466
+ const stacked = [
467
+ ...stackOrder(claimEntries.filter((e) => !e.dev)),
468
+ ...stackOrder(claimEntries.filter((e) => e.dev)),
469
+ ];
470
+ const bottomId = stacked[0]?.id;
471
+ const kindById = new Map(mountSpecs.map((spec) => [spec.id, spec.kind]));
472
+ const surfacesById = new Map();
473
+ stacked.forEach((entry, i) => {
474
+ const isReact = kindById.get(entry.id) === 'dom';
475
+ const surface = document.createElement(isReact ? 'div' : 'canvas');
476
+ surface.dataset['vgaiRootSurface'] = 'true';
477
+ // The capture's marker (`composite-screenshot.ts` reads exactly this
478
+ // attribute): a dev layer is excluded from a play capture unless the
479
+ // capture asks for it, because a contaminated "does the game look right"
480
+ // frame is worthless.
481
+ if (entry.dev)
482
+ surface.dataset['vgaiDevLayer'] = 'true';
483
+ if (!isReact) {
484
+ const canvas = surface;
485
+ canvas.width = w;
486
+ canvas.height = h;
487
+ }
488
+ // Defect E4.R1 (Fable review): layout size is ALWAYS container-relative
489
+ // (`width:100%;height:100%`), fully decoupled from the surface's
490
+ // intrinsic buffer resolution (`w`/`h`, set on the canvas element's
491
+ // `width`/`height` ATTRIBUTES above — a device-pixel/render-resolution
492
+ // concern only). Without this, a canvas with no CSS size falls back to
493
+ // its `width`/`height` attribute as its CSS layout size too, so whatever
494
+ // stamped those attributes (`createHostRenderer`'s construction-time
495
+ // `setSize`, `mountOneThreeRoot` below) pins the ON-SCREEN size — see
496
+ // that function's doc comment for the concrete bug this caused (template
497
+ // standalone at any viewport ≠ the manifest resolution). Setting it HERE
498
+ // too (not just in `mountOneThreeRoot`) means every surface, whatever
499
+ // kind, starts container-relative from its very first paint, before any
500
+ // per-kind mount work has even run.
501
+ // `contain:layout paint` makes each surface the CONTAINING BLOCK for
502
+ // `position:fixed` descendants (and clips overflow to the world's
503
+ // rectangle): full-screen game UI written the natural way (`fixed;
504
+ // inset:0`) then fills the WORLD, not the page. Without it, `fixed` UI
505
+ // looks correct standalone (surface == window) but escapes over the
506
+ // editor chrome whenever the surface is a sub-rectangle of the page —
507
+ // and toggles behavior when any ancestor gains a transform (e.g. the
508
+ // editor's space-pan). Dogfooded 2026-07-12 via a react shell world.
509
+ surface.style.cssText = `position:absolute;top:0;left:0;width:100%;height:100%;z-index:${i + 1};contain:layout paint;`;
510
+ container.appendChild(surface);
511
+ surfacesById.set(entry.id, surface);
512
+ });
513
+ const assets = createAssetCache();
514
+ // Every manifest/host-mounted game is a deterministic-capture candidate —
515
+ // the render-control seam (`?vgai-render=1`, render-control.ts) is wired
516
+ // HERE, at the one host every boot path shares (mountGameFromManifest,
517
+ // mountManifestRoots, and direct createGameRuntime callers all reach this
518
+ // function), instead of asking every project's entry page to install it
519
+ // the way the e2e fixtures do. Production-protected twice over:
520
+ // `isRenderModeRequested` gates on the query param, and
521
+ // `installRenderControlHarness` re-checks it internally (its AC 4), so a
522
+ // normal gameplay page sees zero change.
523
+ const renderModeLocation = config.renderControl?.location ?? (typeof window !== 'undefined' ? window.location : undefined);
524
+ const renderMode = renderModeLocation !== undefined && isRenderModeRequested(renderModeLocation);
525
+ let started = false;
526
+ const loop = createGameLoop({
527
+ fixedTimestep: 1 / 60,
528
+ maxSubSteps: 8,
529
+ // Render mode runs the loop in EXTERNAL-DRIVE mode (game-loop.ts, I2):
530
+ // no RAF is ever armed, so nothing advances gameplay between the capture
531
+ // host's explicit `simulateSubsteps`/`renderOnce` calls — wall-clock time
532
+ // passing while a screenshot is taken must not move the world.
533
+ externalDrive: renderMode,
534
+ // WO-P13 — sim and presentation are wired to different callbacks here:
535
+ // `update` runs the gameplay phases once per consumed fixed substep with
536
+ // `preRender`/`render` withheld, and `render` runs those two once per real
537
+ // display frame with the interpolation alpha. Both closures are invoked
538
+ // only from the loop's own rAF arm, which `externalDrive` never arms — so
539
+ // a capture/offline-export page (`renderMode`) reaches neither, and its
540
+ // `simulateSubsteps` → `game.runFrame(fixedDt)` path stays frame-exact,
541
+ // rendering inside the substep exactly as it did before this flip.
542
+ update: (dt) => {
543
+ if (started)
544
+ game.runFrame(dt, { skipRenderPhases: true });
545
+ },
546
+ render: (alpha, displayDt) => {
547
+ if (started)
548
+ game.runRenderFrame(alpha, displayDt);
549
+ },
550
+ });
551
+ const game = createGame({ loop, assets, seed, playtest });
552
+ // --- Mount + register every world, in ARRAY (declaration) order. ---
553
+ // Split out into its own top-level function purely to keep
554
+ // `createRootsGameRuntime`'s own cyclomatic complexity down (E4) — same
555
+ // reason `mountOneThreeRoot`/`mountOnePixiRoot` are already split out
556
+ // below.
557
+ const { mountedEntries, routerEntries } = await mountAllRootSpecs(mountSpecs, bottomId, {
558
+ game,
559
+ surfacesById,
560
+ w,
561
+ h,
562
+ dpr,
563
+ headless,
564
+ assets,
565
+ });
566
+ // --- Delegating input router (D5 §2a) ---
567
+ const router = createInputRouter(container, routerEntries);
568
+ started = true;
569
+ loop.start();
570
+ // Expose scene & camera for dev tools / e2e tests — mirrors the legacy
571
+ // single-world path's identical dev-only exposure above, generalized to
572
+ // the roots path's DEFAULT world (E4): `mountGameFromManifest`/
573
+ // `mountManifestRoots` route every caller (including a
574
+ // single-threejs-world scaffold project) through THIS path, so a caller
575
+ // migrating off the legacy `{canvas, adapter}` call must not silently
576
+ // lose `window.__vgaiScene`/`__vgaiCamera` — real e2e/dev tooling
577
+ // depends on them
578
+ // (`packages/editor/e2e/tests/04-standalone-game.spec.ts`). Split into
579
+ // its own top-level helper (with its retraction counterpart below)
580
+ // purely to keep this function's own cyclomatic complexity down.
581
+ const retractDevGlobals = installDefaultRootDevGlobals(game);
582
+ // G3/FT-11 — publish `window.__vgaiRender` for the deterministic capture
583
+ // host. Installed at the TAIL of the mount (same position as
584
+ // mount-manifest.ts's debug bridge): every world's `mount()`/`setup()` has
585
+ // resolved by now, so the harness's `scene` readiness hook reporting ready
586
+ // is truthful. See `installSessionRenderHarness` below.
587
+ const retractRenderHarness = renderMode && renderModeLocation !== undefined
588
+ ? installSessionRenderHarness(game, renderModeLocation, config.renderControl?.target)
589
+ : undefined;
590
+ function fullCleanup() {
591
+ loop.stop();
592
+ router.dispose();
593
+ for (const entry of mountedEntries) {
594
+ entry.mounted.dispose();
595
+ entry.renderer?.dispose();
596
+ entry.renderer?.forceContextLoss();
597
+ // Remove from the element's CURRENT parent, not the mount-time
598
+ // `container`: the editor's Game panel re-parents the live surfaces
599
+ // when its mount element swaps (fill <-> device preset, W2c), and
600
+ // `container.removeChild` would throw NotFoundError after such a move.
601
+ // `container` remains the fallback for hosts whose element stand-ins
602
+ // never wire `parentNode` (headless unit fixtures); an element already
603
+ // detached by such a host is a no-op via the catch.
604
+ try {
605
+ (entry.element.parentNode ?? container).removeChild(entry.element);
606
+ }
607
+ catch {
608
+ /* already detached — nothing to remove */
609
+ }
610
+ }
611
+ game.dispose();
612
+ retractDevGlobals();
613
+ retractRenderHarness?.();
614
+ }
615
+ return {
616
+ stop: fullCleanup,
617
+ // D10/T7.6: `Game.play` fans out per-world pausable/loop-gate/audio-gate
618
+ // semantics itself now (see the legacy path's identical comment above) —
619
+ // a `pausable: false` world (a menu/HUD world) keeps ticking while every
620
+ // other world freezes, which the old blind `for (const entry of
621
+ // mountedEntries) entry.mounted.setPaused?.(true)` fan-out (with no
622
+ // `pausable` check at all) could never express.
623
+ pause() {
624
+ game.play.pause();
625
+ },
626
+ resume() {
627
+ game.play.resume();
628
+ },
629
+ step() {
630
+ game.play.step();
631
+ },
632
+ resize(rw, rh, pixelRatio) {
633
+ const safeWidth = Math.max(1, rw);
634
+ const safeHeight = Math.max(1, rh);
635
+ for (const entry of mountedEntries) {
636
+ // W2c device preview: re-pin DPR before setSize so the drawing
637
+ // buffer (and the first-party composer, whose `mounted.resize` reads
638
+ // `getDrawingBufferSize`) picks it up in this same pass. Pixi/react
639
+ // worlds have no `entry.renderer` and keep their own resolution.
640
+ if (pixelRatio !== undefined)
641
+ entry.renderer?.setPixelRatio(pixelRatio);
642
+ entry.renderer?.setSize(safeWidth, safeHeight, false);
643
+ entry.mounted.resize?.(safeWidth, safeHeight);
644
+ }
645
+ },
646
+ // `GameSession.scene`/`.camera`/`.mounted` alias `Game.defaultRoot` (T6.1
647
+ // slice 1's "first three world, else first world" rule) — a legacy
648
+ // convenience shaped for the threejs-only past. T7.5 narrows the read via
649
+ // the `kind` discriminant instead of a blind `.scene`/`.camera` cast
650
+ // through a nonexistent property (identical behavior to before: still
651
+ // `undefined` for a roots-path session whose default world isn't
652
+ // three — real per-world surface routing for that case is T7.6's).
653
+ get scene() {
654
+ const m = game.defaultRoot.mounted;
655
+ return (m.kind === 'three' ? m.scene : undefined);
656
+ },
657
+ get camera() {
658
+ const m = game.defaultRoot.mounted;
659
+ return (m.kind === 'three' ? m.camera : undefined);
660
+ },
661
+ get mounted() {
662
+ return game.defaultRoot.mounted;
663
+ },
664
+ game,
665
+ };
666
+ }