@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,791 @@
1
+ /**
2
+ * SetupThreeRootAdapter — the first-party implementer of {@link RootAdapter}
3
+ * that mounts ONE three root from an imperative `setup(ctx)` function.
4
+ *
5
+ * This is where Rapier lives now: the host no longer knows about it.
6
+ * `mount(host)` builds the full first-party runtime (the body
7
+ * that used to live inline in `create-runtime.ts`) from a neutral
8
+ * {@link ThreeHostContext}, runs the game's `setup`, and returns a
9
+ * {@link MountedThreeRoot}. First-party content is now just one implementer of
10
+ * the same interface an unmodified external game implements (Phase B).
11
+ *
12
+ * It was `VgaiSceneGameAdapter` until WO-9 tasks #6/#9. Both halves of that
13
+ * name had stopped being true: it loads no scene (the `.vscn.json` branches
14
+ * went with the format in WO-8 — `setup` is the only mount path left), and what
15
+ * it mounts is one three ROOT, not a game (a game is the manifest's whole set
16
+ * of roots). The R3F/TSX world root is a SEPARATE adapter; this one is
17
+ * specifically the `fromSetup` path.
18
+ *
19
+ * `GameSetupFn` / `GameContext` are imported ONLY here (and in the example
20
+ * `fromSetup` wrappers) — never by the host. That confinement is the inversion.
21
+ */
22
+ import RAPIER from '@dimforge/rapier3d-compat';
23
+ import * as THREE from 'three';
24
+ import { clearAssetCaches } from '../asset-loaders';
25
+ import { createSeededRandom, DEFAULT_SEEDED_RANDOM_SEED, getSeededRandom, } from '../core/seeded-random';
26
+ import { createSimClock, getSimClock } from '../core/sim-clock';
27
+ import { createSystemRunner } from '../core/system-runner';
28
+ import { createDebugDraw } from '../dev/debug-draw';
29
+ import { createRenderDebugAdapter, frameCaptureContextFor, } from '../dev/render-debug-adapter';
30
+ import { collectRenderMemory } from '../dev/render-memory';
31
+ import { createWebGLFrameCapture } from '../dev/webgl-frame-capture';
32
+ import { createWebGLGpuTimer } from '../dev/webgl-gpu-timer';
33
+ import { createSceneIndex } from '../ecs/scene-index';
34
+ import { getUserData, hasUserData, setUserData } from '../ecs/user-data';
35
+ import { InputManager } from '../input/input-manager';
36
+ import { setAssetPrefix } from '../loader';
37
+ import { createCollisionSystem } from '../physics/collision-system';
38
+ import { createPhysicsRegistry } from '../physics/physics-registry';
39
+ import { createTransformWriter } from '../physics/transform-writer';
40
+ import { updateSceneLODs } from '../render/lod';
41
+ import { disposeSparkRendererWhenIdle, SPARK_DISCOVERY_INTERVAL_MS, sceneHasGaussianSplat, shouldDiscoverGaussianSplat, } from '../render/spark-renderer-lifecycle';
42
+ import { ViewportShadingRenderer } from '../render/viewport-shading';
43
+ import { createDebugRegistry, getDebugRegistry, } from '../runtime/debug-registry';
44
+ import { disposeDebrisSubtree } from '../runtime/game';
45
+ import { setupAudio } from '../setup/setup-audio';
46
+ import { setupParticles } from '../setup/setup-particles';
47
+ import { setupPhysics, updatePhysicsDebug } from '../setup/setup-physics';
48
+ import { createSceneView } from '../setup/setup-renderer';
49
+ import { createAudioSystemAdapter, releaseAudioMeters } from './first-party-systems';
50
+ import { createRapierPhysicsAdapter } from './rapier-physics-adapter';
51
+ /** Minimal stand-in for the GPU composer when mounting headlessly. */
52
+ function headlessComposer(renderer) {
53
+ return {
54
+ render: () => { },
55
+ setSize: () => { },
56
+ dispose: () => { },
57
+ addPass: () => { },
58
+ removeAllPasses: () => { },
59
+ passes: [],
60
+ getRenderer: () => renderer,
61
+ };
62
+ }
63
+ /**
64
+ * Wrap a first-party `setup` function as a {@link RootAdapter}. This is how every
65
+ * first-party example becomes an implementer of the same interface an external
66
+ * game implements — with no change to the setup's body.
67
+ */
68
+ export function fromSetup(id, setup) {
69
+ return new SetupThreeRootAdapter({ id, setup });
70
+ }
71
+ export class SetupThreeRootAdapter {
72
+ config;
73
+ id;
74
+ constructor(config = {}) {
75
+ this.config = config;
76
+ this.id = config.id ?? 'setup-three';
77
+ }
78
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: one cohesive first-party bootstrap (moved verbatim from create-runtime); splitting it would obscure the ordering contract
79
+ async mount(host) {
80
+ const { setup, editorPreview, inputMapPath = '/inputmaps/default.inputmap.json', assetPrefix = '/', } = this.config;
81
+ const headless = host.headless === true;
82
+ const { width, height } = host.surface;
83
+ const renderer = host.renderer;
84
+ setAssetPrefix(assetPrefix);
85
+ // --- Scene view (scene/camera/composer). Browser: the canonical builder, so
86
+ // behavior is byte-identical to the old create-runtime. Headless: plain
87
+ // scene/camera + a no-op composer (no GPU). ---
88
+ let scene;
89
+ let camera;
90
+ let composer;
91
+ if (headless) {
92
+ scene = new THREE.Scene();
93
+ scene.background = new THREE.Color(0x1a1a2e);
94
+ camera = new THREE.PerspectiveCamera(60, width / height || 1, 0.1, 1000);
95
+ camera.position.set(0, 5, 10);
96
+ camera.lookAt(0, 0, 0);
97
+ composer = headlessComposer(renderer);
98
+ }
99
+ else {
100
+ const view = createSceneView(renderer, width, height);
101
+ scene = view.scene;
102
+ camera = view.camera;
103
+ composer = view.composer;
104
+ }
105
+ // --- Rapier physics ---
106
+ await RAPIER.init();
107
+ const physics = setupPhysics(RAPIER, scene);
108
+ const physicsRegistry = createPhysicsRegistry();
109
+ const writeTransforms = createTransformWriter(physicsRegistry, scene);
110
+ // --- Input (InputManager attaches window listeners; stub it headlessly) ---
111
+ const ownsInput = !host.game;
112
+ const input = host.game?.input ?? (headless ? headlessInput() : new InputManager());
113
+ if (!headless) {
114
+ if (host.game)
115
+ await host.game.loadInputMap(inputMapPath);
116
+ else
117
+ await input.loadMap(inputMapPath);
118
+ }
119
+ // --- Collision system ---
120
+ const collisions = createCollisionSystem(physics.rapierWorld, physics.eventQueue);
121
+ // --- Audio (Web Audio — browser only) ---
122
+ const audio = headless ? headlessAudio() : setupAudio(camera);
123
+ // --- Particles (three.quarks BatchedRenderer) ---
124
+ const particles = setupParticles(scene);
125
+ // --- Debug draw / assets ---
126
+ const debugDraw = createDebugDraw(scene);
127
+ const assets = host.assets;
128
+ // Test/headless adapters may provide the renderer surface needed by the
129
+ // runtime without a real WebGL context. GPU timing is optional diagnostics:
130
+ // degrade honestly when the renderer/context cannot expose extensions.
131
+ const rendererContext = typeof renderer.getContext === 'function' ? renderer.getContext() : undefined;
132
+ const gpuTimer = !headless && rendererContext && typeof rendererContext.getExtension === 'function'
133
+ ? createWebGLGpuTimer(rendererContext)
134
+ : null;
135
+ // W4b (F11 frame debugger): first-party WebGL2 frame capture, constructed
136
+ // under the SAME real-context guard as gpuTimer — a headless/stub mount
137
+ // (`frameCaptureContextFor` returns null) never builds it and never
138
+ // registers `renderDebug`, so the capability is honestly absent there. The
139
+ // capture only patches the context WHILE a `captureFrame()` is armed (see
140
+ // beginPass/endPass in the render system below); every non-capture frame
141
+ // is zero-overhead.
142
+ const frameCaptureContext = frameCaptureContextFor(headless, rendererContext);
143
+ const frameCapture = frameCaptureContext ? createWebGLFrameCapture(frameCaptureContext) : null;
144
+ const renderDebugWiring = frameCapture
145
+ ? createRenderDebugAdapter({
146
+ capture: frameCapture,
147
+ scene,
148
+ memory: () => collectRenderMemory(scene, renderer.info),
149
+ })
150
+ : null;
151
+ const viewportShading = new ViewportShadingRenderer();
152
+ let viewportShadingMode = 'solid';
153
+ // --- System runner (engine-level systems) ---
154
+ const systems = createSystemRunner(host.game?.profiler.systemObserver, 'three');
155
+ // D15/T-D15.3/.5: pass the LIVE shared game tick (not a locally-counted
156
+ // one) into every `poll()` call — `debugRegistry` is declared further
157
+ // down in this same `mount()` (it needs `ctx`/`systemAdapters` to exist
158
+ // first), but this callback only ever executes during real frame
159
+ // ticks, long after `mount()` has fully returned and `debugRegistry` is
160
+ // initialized (a safe closure-over-a-later-const, not a genuine
161
+ // use-before-init). `host.game` gates it: a bare mount with no `Game`
162
+ // shell behind it (test harnesses predating T7.1) has no shared tick to
163
+ // key off, so `InputManager.poll()` falls back to its own internal
164
+ // self-incrementing counter instead (unchanged pre-D15 behavior) rather
165
+ // than being pinned to a constant `0` forever.
166
+ if (ownsInput)
167
+ systems.add('input', () => input.poll(), { name: 'input.poll' });
168
+ systems.add('physics', () => physics.rapierWorld.step(physics.eventQueue), {
169
+ name: 'physics.step',
170
+ });
171
+ systems.add('postPhysics', () => {
172
+ collisions.drain();
173
+ writeTransforms();
174
+ }, { name: 'physics.sync' });
175
+ systems.add('preRender', (dt) => {
176
+ particles.batchedRenderer.update(dt);
177
+ updateSceneLODs(scene, camera);
178
+ sparkDiscoveryElapsedMs += dt * 1_000;
179
+ const shouldDiscover = shouldDiscoverGaussianSplat(0, sparkDiscoveryElapsedMs);
180
+ if (!sparkRenderer && !sparkRendererLoading && !sparkRendererFailed && shouldDiscover) {
181
+ sparkDiscoveryElapsedMs = 0;
182
+ if (!sceneHasGaussianSplat(scene))
183
+ return;
184
+ sparkRendererLoading = true;
185
+ void import('@sparkjsdev/spark')
186
+ .then(({ SparkRenderer }) => {
187
+ if (disposed || sparkRenderer)
188
+ return;
189
+ sparkRenderer = new SparkRenderer({ renderer, enableLod: false });
190
+ sparkRenderer.traverse((node) => setUserData(node, 'engineInternal', true));
191
+ })
192
+ .catch((error) => {
193
+ sparkRendererFailed = true;
194
+ // biome-ignore lint/suspicious/noConsole: A missing renderer chunk must fail once and loudly, not retry every frame.
195
+ console.error('Failed to install SparkRenderer for a live Gaussian splat.', error);
196
+ })
197
+ .finally(() => {
198
+ sparkRendererLoading = false;
199
+ });
200
+ }
201
+ }, { name: 'materials-and-particles' });
202
+ if (!headless) {
203
+ systems.add('render', (dt) => {
204
+ if (host.game?.profiler.enabled)
205
+ gpuTimer?.begin();
206
+ if (sparkRenderer)
207
+ scene.add(sparkRenderer);
208
+ // W4b: arm-gated frame capture wraps the real draw calls. beginPass
209
+ // is a no-op unless a captureFrame() armed it; afterRender delivers
210
+ // the assembled capture to a pending captureFrame() and restores the
211
+ // patched context — in the SAME finally as gpuTimer.end(). Spark is
212
+ // added before this so its draws fall inside the captured frame.
213
+ renderDebugWiring?.beforeRender();
214
+ try {
215
+ viewportShading.render(scene, viewportShadingMode, () => composer.render(dt),
216
+ // Scene authoring can temporarily attach editor infrastructure
217
+ // (gizmos/helpers on their own layer) to this same native scene.
218
+ // Only replace materials the actual game camera can render.
219
+ (mesh) => camera.layers.test(mesh.layers));
220
+ }
221
+ finally {
222
+ renderDebugWiring?.afterRender();
223
+ sparkRenderer?.removeFromParent();
224
+ gpuTimer?.end();
225
+ }
226
+ if (physics.debugEnabled)
227
+ updatePhysicsDebug(physics.rapierWorld, physics.debugMesh);
228
+ }, { name: 'three.render' });
229
+ }
230
+ // --- Debug toggle (browser only) ---
231
+ const onDebugToggle = (e) => {
232
+ if (e.code === 'KeyP') {
233
+ physics.debugEnabled = !physics.debugEnabled;
234
+ physics.debugMesh.visible = physics.debugEnabled;
235
+ }
236
+ };
237
+ if (!headless)
238
+ window.addEventListener('keydown', onDebugToggle);
239
+ const postFrame = () => {
240
+ if (ownsInput)
241
+ input.endFrame();
242
+ if (host.game?.profiler.enabled) {
243
+ host.game.profiler.reportRender({
244
+ gpuMs: gpuTimer?.poll() ?? null,
245
+ drawCalls: renderer.info.render.calls,
246
+ triangles: renderer.info.render.triangles,
247
+ geometries: renderer.info.memory.geometries,
248
+ textures: renderer.info.memory.textures,
249
+ });
250
+ }
251
+ };
252
+ // The mounted game's adapter surface (`mounted.systems`). Declared before
253
+ // ctx so `ctx.registerSystemAdapter` can close over it: the engine fills
254
+ // the first-party entries below; GAME-owned capabilities (networking,
255
+ // navigation) are registered by the game's setup through the ctx hook.
256
+ // The editor holds this same object reference (setActiveSystems), so
257
+ // late registrations are visible to its panels at read time.
258
+ const systemAdapters = {};
259
+ // P3 — `ctx.clock`. Same "ONE per Game root, shared across every world"
260
+ // reach-in as `ctx.debug`/`ctx.random` below: `getSimClock(host.game)`
261
+ // returns the clock `createGame` filed, and `runFrameImpl` is what flushes
262
+ // it. A bare mount with no Game shell (headless harness, foreign host) gets
263
+ // a private, mount-local clock so the field is always a real value — but
264
+ // nothing flushes that one, because a mount with no Game has no fixed loop
265
+ // to bind timers to and inventing a wall-clock frontier here is exactly the
266
+ // hazard `core/sim-clock.ts` exists to avoid. Its `disposeAfter` is
267
+ // therefore unreachable; the disposer is still the real one.
268
+ const gameClock = host.game ? getSimClock(host.game) : null;
269
+ const clock = gameClock ?? createSimClock({ dispose: (obj) => disposeDebrisSubtree(obj, [ctx]) });
270
+ /** Only a mount-local fallback is THIS mount's to dispose — see the
271
+ * `clock.dispose` teardown step below for why the game-scoped one is not. */
272
+ const ownsClock = gameClock === null;
273
+ // --- GameContext (the first-party runtime surface) ---
274
+ const ctx = {
275
+ scene,
276
+ camera,
277
+ rapierWorld: physics.rapierWorld,
278
+ rapier: RAPIER,
279
+ physics: physicsRegistry,
280
+ input,
281
+ collisions,
282
+ composer,
283
+ audio,
284
+ particles,
285
+ debugDraw,
286
+ assets,
287
+ systems,
288
+ clock,
289
+ // The live scene index for THIS root (P2 `observe`). Created before
290
+ // setup() runs so a game's own objects are indexed as they are added —
291
+ // it subscribes to three's `childadded`/`childremoved` on the scene, so
292
+ // everything the game builds arrives through it. Disposed in
293
+ // disposeGame() below (a warm restart keeps it: same `scene`, same ctx).
294
+ sceneIndex: createSceneIndex(scene),
295
+ registerSystemAdapter: (kind, adapter) => {
296
+ systemAdapters[kind] = adapter;
297
+ host.game?.notifySystemAdaptersChanged();
298
+ },
299
+ };
300
+ // Game root (T7.1 slice 1): only present once the host has constructed a
301
+ // Game shell (createGameRuntime does this before mount; headless/foreign
302
+ // hosts may omit it — ctx.game/ctx.roots simply stay undefined, which is
303
+ // the documented zero-break behavior). `ctx.roots` is assigned the SAME
304
+ // live array `host.game` mutates via `registerRoot` (not a copy) — the
305
+ // default world is registered AFTER mount returns, and this reference
306
+ // must observe that later push.
307
+ if (host.game) {
308
+ ctx.game = host.game;
309
+ ctx.roots = host.game.roots;
310
+ ctx.playtest = host.game.playtest ?? null;
311
+ }
312
+ // Everything registered above (the engine systems) is "engine" and must
313
+ // survive a warm
314
+ // restart. Everything a game's setup() (below) adds
315
+ // from here on is "game" content that `hotReload` bulk-removes via
316
+ // `systems.removeAllNonEngine()` on every restart (T1.7).
317
+ systems.markEngineBoundary();
318
+ // First-party System adapters over the real subsystems — seeded HERE,
319
+ // BEFORE setup()/scene load runs below, so that a game which registers any
320
+ // of these kinds during its own setup (via `ctx.registerSystemAdapter`)
321
+ // always wins over the engine's first-party entry (see
322
+ // registerSystemAdapter's docstring in runtime/types.ts). `navigation` is
323
+ // ALSO first-party now (R8 item 7): `createNavigationAdapter` wraps the
324
+ // resolves, not here (no NavMeshManager exists yet at this point in the
325
+ // mount). `networking` remains the one game-owned capability with no
326
+ // first-party implementer; it simply starts absent here.
327
+ // P-4: the physics seam is keyed by node id, so the first-party mount
328
+ // supplies the first-party `id → Object3D` map. `userData.entityId` is
329
+ // THIS stack's identity convention (the scene loader stamps it, and the
330
+ // editor's `objectMap`/`hierarchy.object3D` agree on it), which is exactly
331
+ // why the lookup belongs here and not inside `rapier-physics-adapter.ts`.
332
+ // Memoized because the gizmo/inspector ask repeatedly for one selection;
333
+ // a miss (or an object since detached) re-walks once and re-caches.
334
+ const nodeObjectCache = new Map();
335
+ const resolveNodeObject = (nodeId) => {
336
+ const cached = nodeObjectCache.get(nodeId);
337
+ if (cached?.parent)
338
+ return cached;
339
+ let found = null;
340
+ scene.traverse((o) => {
341
+ if (!found && getUserData(o, 'entityId') === nodeId)
342
+ found = o;
343
+ });
344
+ if (found)
345
+ nodeObjectCache.set(nodeId, found);
346
+ else
347
+ nodeObjectCache.delete(nodeId);
348
+ return found;
349
+ };
350
+ systemAdapters.physics = createRapierPhysicsAdapter(physicsRegistry, physics, resolveNodeObject);
351
+ // D10/T7.6: the audio seam `Game.play.pause()` silences on pause. Works
352
+ // against the headless stand-in too (`headlessAudio()`'s plain
353
+ // `masterGain.gain` object) — this world's `pause()` mutes it harmlessly.
354
+ systemAdapters.audio = createAudioSystemAdapter(audio);
355
+ // Debug/synthetic-player seam (T1.1): ONE registry per Game root, shared
356
+ // across every world that mounts onto it — `getDebugRegistry(host.game)`
357
+ // reaches the SAME accumulator `createGame` filed, so a second/third
358
+ // world's `ctx.debug` feeds it too (see debug-registry.ts's module doc
359
+ // for the provenance/id note). A mount with no Game shell at all (bare
360
+ // test harnesses predating T7.1) gets a private, mount-local registry
361
+ // instead — same absence precedent as `ctx.game`/`ctx.roots` above.
362
+ const debugRegistry = (host.game ? getDebugRegistry(host.game) : null) ??
363
+ createDebugRegistry({ getTick: () => 0, getSimT: () => 0 });
364
+ systemAdapters.debug = debugRegistry.adapter;
365
+ // W4b: the render-debug capability is engine-owned and first-party, seeded
366
+ // here (like physics/input/assets) BEFORE the engineAdapterKinds snapshot
367
+ // below so a warm restart / stop never mistakes it for game content. Only
368
+ // present when a real WebGL2 context backed the mount (renderDebugWiring).
369
+ if (renderDebugWiring)
370
+ systemAdapters.renderDebug = renderDebugWiring.adapter;
371
+ ctx.debug = debugRegistry.forRoot(this.id);
372
+ // T1.2: the InputManager is a first-party per-world handle the registry
373
+ // has no other way to reach — wired as a lazy supplier (not a direct
374
+ // read here), scoped to THIS world's id, so the built-in `input.actions`
375
+ // provider always reflects the CURRENT action set, not a snapshot taken
376
+ // at mount time. Per-world (not a single last-writer-wins slot) since
377
+ // D15/T-D15.5 — see `debug-registry.ts`'s `setInputActionsSource` doc.
378
+ debugRegistry.setInputActionsSource(this.id, () => typeof input.actionNames === 'function'
379
+ ? input.actionNames().map((name) => ({ name, valueType: input.getActionValueType(name) }))
380
+ : []);
381
+ // D15/T-D15.5 — same lazy-supplier pattern (and same headless-stand-in
382
+ // guard) as `setInputActionsSource` immediately above: the built-in
383
+ // `input.trace` provider always reads the CURRENT recorded trace, never
384
+ // a snapshot taken at mount time. `seed`/`fixedDt` are assembled here
385
+ // (not inside `InputManager`, which has no business knowing about
386
+ // `ctx.random` or the loop) — the two replay-critical metadata fields
387
+ // the design doc's format sketch (§2.c) calls for beside the raw
388
+ // per-tick deltas; `null` only absent a Game/ctx.random behind this
389
+ // mount, matching every other "no Game" fallback in this file.
390
+ debugRegistry.setInputTraceSource(this.id, () => {
391
+ const raw = typeof input.getInputTrace === 'function'
392
+ ? input.getInputTrace()
393
+ : { version: 1, ticks: [] };
394
+ const seed = (host.game ? getSeededRandom(host.game) : null)?.seed ?? null;
395
+ const fixedDt = host.game?.loop.fixedDt ?? null;
396
+ return { version: raw.version, seed, fixedDt, ticks: raw.ticks };
397
+ });
398
+ // Task 2.1 — the same InputManager instance, wired as the debug bridge's
399
+ // actuation target (`runtime/debug-bridge.ts`'s `input.*` methods) at the
400
+ // same seed spot as `setInputActionsSource` above. Per-world (D15 review
401
+ // objection 2 fix) — see `debug-registry.ts`'s `setVirtualInputTarget`
402
+ // doc for why this used to be a single last-writer-wins slot.
403
+ debugRegistry.setVirtualInputTarget(this.id, {
404
+ setVirtualAction: (action, value) => input.setVirtualAction(action, value),
405
+ tapVirtualAction: (action) => input.tapVirtualAction(action),
406
+ clearVirtualActions: () => input.clearVirtualActions(),
407
+ scheduleActionAtTick: (tick, action, value) => input.scheduleActionAtTick(tick, action, value),
408
+ startInputRecording: () => input.startInputRecording(),
409
+ stopInputRecording: () => input.stopInputRecording(),
410
+ isInputRecording: () => input.isInputRecording(),
411
+ injectAxis: (sourceId, value) => input.injectAxis(sourceId, value),
412
+ injectVector2: (sourceId, value) => input.injectVector2(sourceId, value),
413
+ injectPointerDelta: (sourceId, delta) => input.injectPointerDelta(sourceId, delta),
414
+ injectPointerPosition: (sourceId, value) => input.injectPointerPosition(sourceId, value),
415
+ });
416
+ // R4-class fix — wire the InputManager's `'input.schedule.dropped'` sink
417
+ // to THIS world's debug registry, same seed spot/precedent as
418
+ // `setInputActionsSource`/`setVirtualInputTarget` above (typeof-guarded:
419
+ // a headless `InputManager` stand-in may have no `setDebugEmit`).
420
+ if (!host.game && typeof input.setDebugEmit === 'function') {
421
+ input.setDebugEmit((event, detail) => ctx.debug?.emit(event, detail));
422
+ }
423
+ // D15 (T-D15.1) — same "ONE per Game root, shared across every world"
424
+ // pattern as the debug registry immediately above: `getSeededRandom
425
+ // (host.game)` reaches the SAME `SeededRandom` `createGame` filed (boot-
426
+ // seeded by the manifest-aware mount path, `mount-manifest.ts`, before
427
+ // ANY world's `mount()`/`setup()` runs — see `createGame`'s own doc
428
+ // comment), so every world's `ctx.random` is the identical instance, not
429
+ // a per-world copy. Same absence precedent as `ctx.debug`: a mount with
430
+ // no Game shell at all gets a private, mount-local surface instead.
431
+ ctx.random =
432
+ (host.game ? getSeededRandom(host.game) : null) ??
433
+ createSeededRandom(DEFAULT_SEEDED_RANDOM_SEED);
434
+ // Snapshot of the engine-owned adapter kinds, taken right after seeding
435
+ // and before any setup() has had a chance to run. `hotReload`/`disposeGame`
436
+ // use this to strip every GAME-registered kind (including an override of a
437
+ // first-party kind) left over from the outgoing game, so a warm restart or
438
+ // a full stop never exposes a disposed game's networking/etc. adapter to
439
+ // the next setup.
440
+ const engineAdapterKinds = new Set(Object.keys(systemAdapters));
441
+ // 'navigation' is engine-owned too (R8 item 7), but the scene load that
442
+ // populates it (below, `applySceneNavigation`) happens AFTER this
443
+ // snapshot — add it explicitly so the generic "strip every non-engine
444
+ // kind" step (hotReload/disposeGame) never mistakes a first-party
445
+ // navigation adapter for game-registered content and deletes it. (The
446
+ // adapter is still kept in sync with the CURRENT scene's NavMeshManager
447
+ // via the dedicated `clear navigation adapter` teardown step below, which
448
+ // runs independently of this snapshot.)
449
+ engineAdapterKinds.add('navigation');
450
+ // --- Scene / game setup ---
451
+ const engineSceneChildren = new Set(scene.children.slice());
452
+ // Tag engine-owned infra (particle BatchedRenderer, debug-draw + subtrees) so
453
+ // the editor's play-mode hierarchy skips them — they're not game entities.
454
+ for (const c of engineSceneChildren) {
455
+ c.traverse((n) => setUserData(n, 'engineInternal', true));
456
+ }
457
+ let currentCleanup = null;
458
+ let sparkRenderer = null;
459
+ let sparkRendererLoading = false;
460
+ let sparkRendererFailed = false;
461
+ // Discovery is render-loop scheduling, so advance it from the loop's `dt`
462
+ // instead of introducing a second wall-clock frontier into engine code.
463
+ // Start at the threshold so the first rendered frame discovers eager splats.
464
+ let sparkDiscoveryElapsedMs = SPARK_DISCOVERY_INTERVAL_MS;
465
+ if (!setup) {
466
+ throw new Error('SetupThreeRootAdapter: no `setup` supplied. The `.vscn.json` scene branches ' +
467
+ '(`scenePath` / `sceneData`) were removed with the format; a first-party three root ' +
468
+ 'is either an imperative ' +
469
+ '`setup(ctx)` (wrap it with `fromSetup(id, setup)`) or a TSX/R3F world root ' +
470
+ '(`entry` pointing at a .tsx module — mounted by the R3F adapter, not this one).');
471
+ }
472
+ // Headless is legal here: `createSceneView` was skipped above, the composer
473
+ // is a no-op stand-in, and `setup` gets a real `THREE.Scene`/camera. It used
474
+ // to throw because headless existed only for the `.vscn` `sceneData` branch;
475
+ // with the format gone (WO-8) `setup` is the only mount path, and headless
476
+ // unit mounts are what exercise the Game/roots/frame machinery without WebGL.
477
+ currentCleanup = await setup(ctx, editorPreview);
478
+ // Warm the GPU program cache before the first visible frame. A mount gets
479
+ // a fresh WebGL context, so without this every scene material compiles
480
+ // lazily INSIDE the first draw calls — measured as ~0.5s of main-thread
481
+ // driver stalls on every editor play press. Gated on
482
+ // KHR_parallel_shader_compile: with the extension, compileAsync overlaps
483
+ // the compiles with the play transition; WITHOUT it (software
484
+ // rasterizers — SwiftShader in CI) compileAsync degenerates into one big
485
+ // synchronous compile that delays mount by whole seconds, strictly worse
486
+ // than the lazy first-draw path it was replacing. Best-effort: lazy
487
+ // compilation stays correct if it throws, and test hosts pass renderer
488
+ // stubs without these methods.
489
+ const glContext = typeof renderer.getContext === 'function' ? renderer.getContext() : undefined;
490
+ const parallelCompile = !!glContext &&
491
+ typeof glContext.getExtension === 'function' &&
492
+ !!glContext.getExtension('KHR_parallel_shader_compile');
493
+ if (!headless && parallelCompile && typeof renderer.compileAsync === 'function') {
494
+ try {
495
+ await renderer.compileAsync(scene, camera);
496
+ }
497
+ catch {
498
+ // Fall back to lazy compilation.
499
+ }
500
+ }
501
+ // Idempotency guard for disposeGame — see below. Declared here (not inside
502
+ // disposeGame) so hotReload can also refuse to run on an already-disposed
503
+ // adapter.
504
+ let disposed = false;
505
+ // Run one teardown step in isolation: a throwing step (e.g. a game's own
506
+ // cleanup misbehaving, or a WASM free() panicking) must
507
+ // not abort the remaining steps — otherwise a single bad step leaks
508
+ // the Rapier world and skips input.dispose() with no way to retry (a
509
+ // second call is a no-op once `disposed` is set). Logs and continues.
510
+ const safeStep = (label, fn) => {
511
+ try {
512
+ fn();
513
+ }
514
+ catch (err) {
515
+ console.error(`SetupThreeRootAdapter: teardown step "${label}" threw (continuing)`, err);
516
+ }
517
+ };
518
+ const disposeGame = () => {
519
+ // A second stop() must be a safe no-op — do NOT double-free the Rapier
520
+ // world/EventQueue (WASM handles panic/throw on a second free) or
521
+ // double-run teardown side effects.
522
+ if (disposed)
523
+ return;
524
+ disposed = true;
525
+ safeStep('currentCleanup.dispose', () => {
526
+ currentCleanup?.dispose();
527
+ currentCleanup = null;
528
+ });
529
+ safeStep('sparkRenderer.dispose', () => {
530
+ if (!sparkRenderer)
531
+ return;
532
+ sparkRenderer.removeFromParent();
533
+ disposeSparkRendererWhenIdle(sparkRenderer);
534
+ sparkRenderer = null;
535
+ });
536
+ // The scene instance's NavMeshManager (if any) was just disposed above
537
+ // (currentCleanup.dispose calls `inst.navMesh?.dispose(scene)`) — clear
538
+ // the wrapper too, or `mounted.systems.navigation` would keep pointing
539
+ // at a freed manager (R8 item 7). Unconditional: harmless if navigation
540
+ // was never set.
541
+ safeStep('clear navigation adapter', () => {
542
+ delete systemAdapters.navigation;
543
+ });
544
+ if (!headless) {
545
+ safeStep('removeEventListener(keydown)', () => window.removeEventListener('keydown', onDebugToggle));
546
+ }
547
+ // P3 — the MOUNT-LOCAL clock only, and only when this mount created one
548
+ // (a bare mount with no Game shell). The game-scoped clock is disposed by
549
+ // `GameInternal.dispose()`, which `create-runtime.ts` runs after every
550
+ // root has torn down — because disposing ONE world's mount is a supported
551
+ // way to end a sub-session while the Game keeps running, and destroying a
552
+ // shared clock there froze `now()` and killed the sibling worlds' timers.
553
+ // The asymmetry is the tell: `seededRandom` and `debugRegistry` are
554
+ // game-scoped too, and this teardown destroys neither (it strips only its
555
+ // OWN slice of the registry, a few steps below).
556
+ //
557
+ // Sim timers still go BEFORE the Rapier world they would touch: a pending
558
+ // `disposeAfter`/`after` fires into a live Rapier world, and once that is
559
+ // gone it would operate on freed WASM handles.
560
+ // Disposing cancels every timer and rejects every pending `delay` with an
561
+ // `AbortError` (which awaiting game code is documented to tolerate,
562
+ // exactly like an aborted `fetch`).
563
+ if (ownsClock)
564
+ safeStep('clock.dispose', () => clock.dispose());
565
+ // Before the scene is emptied below: dropping the listeners
566
+ // first means the teardown's ~N `scene.remove()` calls do no index
567
+ // bookkeeping, and — the failure mode this exists to prevent — no
568
+ // `childadded` listener is left behind on a disposed scene.
569
+ safeStep('sceneIndex.dispose', () => ctx.sceneIndex.dispose());
570
+ safeStep('remove rigid bodies', () => {
571
+ const handles = [];
572
+ physics.rapierWorld.forEachRigidBody((b) => handles.push(b.handle));
573
+ for (const h of handles) {
574
+ const b = physics.rapierWorld.getRigidBody(h);
575
+ if (b)
576
+ physics.rapierWorld.removeRigidBody(b);
577
+ }
578
+ });
579
+ safeStep('rapierWorld.free', () => physics.rapierWorld.free());
580
+ safeStep('eventQueue.free', () => physics.eventQueue.free()); // WASM handle — must be freed manually
581
+ safeStep('physicsRegistry.clear', () => physicsRegistry.clear());
582
+ safeStep('scene children dispose', () => {
583
+ for (const obj of [...scene.children]) {
584
+ scene.remove(obj);
585
+ obj.traverse((node) => {
586
+ if (node instanceof THREE.Mesh) {
587
+ if (!hasUserData(node, '__sharedGeometry'))
588
+ node.geometry?.dispose();
589
+ if (Array.isArray(node.material))
590
+ node.material.forEach((m) => {
591
+ m.dispose();
592
+ });
593
+ else
594
+ node.material?.dispose();
595
+ }
596
+ });
597
+ }
598
+ scene.fog = null;
599
+ scene.background = null;
600
+ scene.environment = null;
601
+ });
602
+ safeStep('clearAssetCaches', () => clearAssetCaches());
603
+ safeStep('debugDraw.clear', () => debugDraw.clear());
604
+ // R8 item 7 (C) — disposeGame (Stop) used to skip both of these, unlike
605
+ // hotReload (warm restart), which already ran them: a game lifecycle
606
+ // system registered via `ctx.systems.register(...)` never had its
607
+ // `dispose()` hook called on a full Stop, and a game-registered
608
+ // systemAdapters kind (e.g. a `setup`-registered 'networking') survived
609
+ // a Stop and would be visible on a STALE `mounted.systems` even though
610
+ // the game that owned it is gone. Same two steps, same relative
611
+ // ordering as hotReload (before the
612
+ // engine-owned audio/input teardown below, which hotReload doesn't
613
+ // touch at all since it warm-restarts rather than tearing engine
614
+ // subsystems down).
615
+ safeStep('systems.removeAllNonEngine', () => systems.removeAllNonEngine());
616
+ safeStep('strip game-registered systemAdapters', () => {
617
+ for (const kind of Object.keys(systemAdapters)) {
618
+ if (!engineAdapterKinds.has(kind))
619
+ delete systemAdapters[kind];
620
+ }
621
+ });
622
+ // A game-hosted mount owns only its world-scoped registrations; sibling
623
+ // roots remain alive during root replacement. A bare standalone adapter
624
+ // owns the registry and can clear it globally.
625
+ safeStep('debugRegistry.strip', () => host.game ? debugRegistry.strip(this.id) : debugRegistry.strip());
626
+ // Release analyser taps BEFORE the audio teardown below. A consumer
627
+ // (the editor's meter poll) should dispose its own handle, but Stop must
628
+ // never leak taps regardless.
629
+ //
630
+ // This used to ride on the Tone introspection module's disposer, which
631
+ // meant a game that never touched Tone leaked them — the module was
632
+ // never loaded, so nothing ever called this. `acquireMeters` belongs to
633
+ // the base adapter (535d248dc), so its release does too, and the world
634
+ // that created the adapter is what disposes it.
635
+ safeStep('audio meters release', () => {
636
+ const audioAdapter = systemAdapters.audio;
637
+ if (audioAdapter)
638
+ releaseAudioMeters(audioAdapter);
639
+ });
640
+ if (!headless) {
641
+ safeStep('audio teardown', () => {
642
+ audio.masterGain.gain.value = 0;
643
+ audio.listener.context.suspend();
644
+ camera.remove(audio.listener);
645
+ composer.dispose();
646
+ });
647
+ }
648
+ if (ownsInput)
649
+ safeStep('input.dispose', () => input.dispose());
650
+ // W4b: restore any pending capture wrappers and reject a capture in
651
+ // flight (a Stop mid-capture must not leave the context patched).
652
+ safeStep('renderDebug.dispose', () => renderDebugWiring?.dispose());
653
+ safeStep('gpuTimer.dispose', () => gpuTimer?.dispose());
654
+ safeStep('viewportShading.dispose', () => viewportShading.dispose());
655
+ };
656
+ const hotReload = async (newSetup, newEditorPreview) => {
657
+ if (disposed) {
658
+ throw new Error('SetupThreeRootAdapter: cannot hotReload after dispose()/stop()');
659
+ }
660
+ // Full parity with disposeGame for the parts a warm restart rebuilds:
661
+ // game cleanup, component batch teardown (in that
662
+ // ordering, BEFORE bodies are pulled from the world — see disposeGame),
663
+ // scene-UI dispose (React root unmount), and bulk system removal. Each
664
+ // step isolated the same way as disposeGame — one throwing step (e.g. a
665
+ // component dispose) must not abort the rest of the warm restart.
666
+ safeStep('currentCleanup.dispose', () => {
667
+ currentCleanup?.dispose();
668
+ currentCleanup = null;
669
+ });
670
+ // Clear any navigation adapter a previous `setup` registered: `hotReload`'s
671
+ // `newSetup` (below) never auto-wires a replacement, so leaving the old
672
+ // wrapper would point at a disposed manager. A `newSetup` that wants navigation may
673
+ // register its own via `ctx.registerSystemAdapter('navigation', ...)`.
674
+ safeStep('clear navigation adapter', () => {
675
+ delete systemAdapters.navigation;
676
+ });
677
+ safeStep('remove rigid bodies', () => {
678
+ const handles = [];
679
+ physics.rapierWorld.forEachRigidBody((b) => handles.push(b.handle));
680
+ for (const h of handles) {
681
+ const b = physics.rapierWorld.getRigidBody(h);
682
+ if (b)
683
+ physics.rapierWorld.removeRigidBody(b);
684
+ }
685
+ physicsRegistry.clear();
686
+ });
687
+ safeStep('scene children dispose', () => {
688
+ for (const obj of [...scene.children]) {
689
+ if (engineSceneChildren.has(obj))
690
+ continue;
691
+ scene.remove(obj);
692
+ obj.traverse((node) => {
693
+ if (node instanceof THREE.Mesh) {
694
+ if (!hasUserData(node, '__sharedGeometry'))
695
+ node.geometry?.dispose();
696
+ if (Array.isArray(node.material))
697
+ node.material.forEach((m) => {
698
+ m.dispose();
699
+ });
700
+ else
701
+ node.material?.dispose();
702
+ }
703
+ });
704
+ }
705
+ scene.fog = null;
706
+ scene.background = null;
707
+ scene.environment = null;
708
+ });
709
+ safeStep('debugDraw.clear', () => debugDraw.clear());
710
+ // Bulk-remove every system the outgoing game registered (this restart's
711
+ // predecessor) so warm restarts never accumulate duplicate systems —
712
+ // engine systems registered before mount()'s boundary mark are untouched.
713
+ safeStep('systems.removeAllNonEngine', () => systems.removeAllNonEngine());
714
+ // Strip every GAME-registered systemAdapters kind left by the outgoing
715
+ // game (including any override of a first-party kind) so the disposed
716
+ // game's networking/etc. adapter is never exposed to the next setup —
717
+ // see registerSystemAdapter's docstring in runtime/types.ts. ('navigation'
718
+ // is engine-kind and is NOT touched here — it's a first-party adapter now,
719
+ // kept in sync with the current scene's NavMeshManager by the dedicated
720
+ // `clear navigation adapter` step above instead.) The new setup below
721
+ // either re-registers a kind or it stays absent.
722
+ safeStep('strip game-registered systemAdapters', () => {
723
+ for (const kind of Object.keys(systemAdapters)) {
724
+ if (!engineAdapterKinds.has(kind))
725
+ delete systemAdapters[kind];
726
+ }
727
+ });
728
+ // Hot-reload re-seed (spec §3.1): the incoming game's setup (below)
729
+ // re-registers its providers/commands under the SAME worldId — strip()
730
+ // clears the outgoing game's registrations first so that re-seed is
731
+ // silent (no stale duplicate-name warning) rather than "replacing" a
732
+ // dead game's entries. Defect 2 fix: scoped to THIS mount's worldId
733
+ // (`this.id`) — a blind global strip() here wiped every OTHER live
734
+ // world's registrations on every warm restart of just this one, plus
735
+ // every react-door registration (whose `useEffect` cleanup never
736
+ // re-fires to restore them after someone else's strip).
737
+ safeStep('debugRegistry.strip', () => debugRegistry.strip(this.id));
738
+ currentCleanup = await newSetup(ctx, newEditorPreview);
739
+ };
740
+ return {
741
+ kind: 'three',
742
+ scene,
743
+ camera,
744
+ firstParty: true,
745
+ drivesOwnLoop: false,
746
+ update: (dt) => {
747
+ systems.run(dt);
748
+ postFrame();
749
+ },
750
+ resize: (w, h) => {
751
+ const safeWidth = Math.max(1, w);
752
+ const safeHeight = Math.max(1, h);
753
+ composer.setSize(safeWidth, safeHeight);
754
+ camera.aspect = safeWidth / safeHeight;
755
+ camera.updateProjectionMatrix();
756
+ },
757
+ dispose: disposeGame,
758
+ systems: systemAdapters,
759
+ ctx,
760
+ composer: headless ? null : composer,
761
+ setViewportShadingMode: (mode) => {
762
+ viewportShadingMode = mode;
763
+ },
764
+ hotReload,
765
+ frame: {
766
+ runPhase: (phase, dt) => systems.runPhase(phase, dt),
767
+ endFrame: postFrame,
768
+ },
769
+ };
770
+ }
771
+ }
772
+ /** Headless input stand-in — `InputManager` attaches `window` listeners in its
773
+ * constructor, which Node lacks. A headless mount never reads input. */
774
+ function headlessInput() {
775
+ return {
776
+ poll: () => { },
777
+ endFrame: () => { },
778
+ dispose: () => { },
779
+ loadMap: async () => { },
780
+ isPressed: () => false,
781
+ getAxis: () => 0,
782
+ };
783
+ }
784
+ /** Headless audio stand-in (no Web Audio). Only the fields the mount/cleanup
785
+ * touch are present. */
786
+ function headlessAudio() {
787
+ return {
788
+ listener: undefined,
789
+ masterGain: { gain: { value: 1 } },
790
+ };
791
+ }