@vgai/engine 0.5.4 → 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 (448) 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/runtime/mount-game.ts +6 -0
  445. package/src/runtime/unexported-game-trap.ts +82 -0
  446. package/src/setup/setup-renderer.ts +2 -0
  447. package/src/world3d-react/index.ts +9 -0
  448. package/src/world3d-react/rapier-physics-bridge.tsx +137 -0
@@ -0,0 +1,189 @@
1
+ import { clampTimeScale, paceFrame, TIME_SCALE_RANGE } from './frame-pacing';
2
+ /**
3
+ * Fixed-timestep game loop with accumulator pattern — SIM at a fixed rate,
4
+ * PRESENTATION at the display's rate (WO-P13, `docs/WORK.md` §2 P13, which
5
+ * flipped the former D1 "render is fixed-rate too" decision this comment used
6
+ * to state).
7
+ *
8
+ * Per real (rAF) frame:
9
+ *
10
+ * 1. the accumulator absorbs the frame gap (clamped, `timeScale`d) and
11
+ * `config.update(fixedDt)` runs once per WHOLE fixed substep it can
12
+ * consume, up to `maxSubSteps` — unchanged, and still the only thing that
13
+ * advances gameplay, physics, `tick`/`simT` and the sim clock;
14
+ * 2. `config.render(alpha, displayDt)` runs EXACTLY ONCE, whatever step 1
15
+ * did — including zero times. `alpha` is `accumulator / fixedDt` after
16
+ * step 1 (see `core/frame-pacing.ts`): how far presentation sits past the
17
+ * last completed fixed state, in `[0, 1]`.
18
+ *
19
+ * So a 120 Hz display draws 120 frames a second off a 60 Hz simulation, and a
20
+ * frame that consumes zero substeps still presents — which is the whole point:
21
+ * before this, motion presented at SIM rate, so half of every 120 Hz display's
22
+ * frames were duplicates and there was nowhere at all to host
23
+ * `RenderStepped`-shaped per-display-frame code (camera polish, procedural
24
+ * sway). `Game.onRenderStep` (`runtime/game.ts`) is that host, driven from
25
+ * this callback.
26
+ *
27
+ * `config.render` is OPTIONAL, and the hosts that don't pass it keep the old
28
+ * shape exactly: the `render` phase then still runs inside `config.update` as
29
+ * the last phase of `PHASE_ORDER` (`runtime/game.ts` only skips the render
30
+ * phases when its caller asks it to). That is deliberate, because two paths
31
+ * must stay frame-exact and neither goes through the rAF arm at all:
32
+ * `externalDrive` capture/offline export (see `GameLoopConfig.externalDrive`)
33
+ * and `Game.runTicks`, which drives `runFrame` directly.
34
+ */
35
+ export function createGameLoop(config) {
36
+ const fixedDt = config.fixedTimestep ?? 1 / 60;
37
+ // Also the accumulator's hard ceiling — `paceFrame` derives
38
+ // `fixedDt * maxSubSteps` from these two and clamps against it.
39
+ const maxSubSteps = config.maxSubSteps ?? 8;
40
+ // I2 (render-control runtime mode, see `GameLoopConfig.externalDrive`'s
41
+ // doc comment): in this mode `start()` below deliberately skips both the
42
+ // `requestAnimationFrame` arm AND the `visibilitychange` listener install —
43
+ // no wall-clock timing source ever exists for this loop instance, so
44
+ // `config.update` can only ever be invoked by an external driver calling
45
+ // into the render-control seam, never by this file's own `frame()`.
46
+ const externalDrive = config.externalDrive ?? false;
47
+ let accumulator = 0;
48
+ let lastTime = 0;
49
+ let running = false;
50
+ let rafId = 0;
51
+ let timeScale = 1.0;
52
+ // Idle throttle (T2.1): a hidden tab stops the loop outright; becoming
53
+ // visible again restarts it with the accumulator clock resynced to "now" —
54
+ // deliberately no catch-up burst for the wall-clock time spent hidden.
55
+ let hiddenPaused = false;
56
+ let visibilityListenerAttached = false;
57
+ function handleVisibilityChange() {
58
+ if (typeof document === 'undefined')
59
+ return;
60
+ if (document.hidden) {
61
+ if (running) {
62
+ running = false;
63
+ cancelAnimationFrame(rafId);
64
+ hiddenPaused = true;
65
+ }
66
+ }
67
+ else if (hiddenPaused) {
68
+ hiddenPaused = false;
69
+ running = true;
70
+ lastTime = performance.now();
71
+ accumulator = 0;
72
+ rafId = requestAnimationFrame(frame);
73
+ }
74
+ }
75
+ function frame(currentTime) {
76
+ if (!running)
77
+ return;
78
+ rafId = requestAnimationFrame(frame);
79
+ // Convert to seconds
80
+ const rawDt = (currentTime - lastTime) / 1000;
81
+ lastTime = currentTime;
82
+ // All of the pacing arithmetic — frame-gap clamp, timeScale, the
83
+ // spiral-of-death accumulator clamp, the substep count and the
84
+ // interpolation alpha — lives in `core/frame-pacing.ts`, pure and unit
85
+ // tested. The accumulator is written back BEFORE the substeps run so a
86
+ // throwing `update` cannot make the loop re-consume time it already
87
+ // charged for.
88
+ const paced = paceFrame(accumulator, rawDt, timeScale, { fixedDt, maxSubSteps });
89
+ accumulator = paced.accumulator;
90
+ // Fixed-rate: gameplay/physics, once per consumed substep. Zero times on
91
+ // a frame that could not fill one.
92
+ for (let i = 0; i < paced.steps; i++)
93
+ config.update(fixedDt);
94
+ // Display-rate: exactly once per real frame, whatever the substep count
95
+ // was — see the module doc comment. Optional; a host that never passes
96
+ // `render` keeps rendering inside `update`'s phase list.
97
+ config.render?.(paced.alpha, paced.displayDt);
98
+ }
99
+ return {
100
+ start() {
101
+ if (running)
102
+ return;
103
+ running = true;
104
+ // A direct start() call can land while the loop is auto-hidden-paused
105
+ // (`hiddenPaused` true, `running` false, no rAF pending). Without this
106
+ // reset, a later visibilitychange-to-visible would see stale
107
+ // `hiddenPaused === true` and spawn a SECOND rAF chain on top of the
108
+ // one this call is about to start (doubled update()/render() overhead
109
+ // until the next stop() — no sim-speed effect, but wasted work).
110
+ hiddenPaused = false;
111
+ lastTime = performance.now();
112
+ accumulator = 0;
113
+ // External-drive mode (I2): never arm rAF and never install the
114
+ // visibilitychange auto-stop handler. `running` still flips `true`
115
+ // above (so `isRunning`/`stop()` behave normally for a caller that
116
+ // treats this loop as "started"), but nothing will ever call
117
+ // `frame()` — a headless/backgrounded capture page cannot have this
118
+ // loop silently killed by `document.hidden`, because there is no
119
+ // listener to fire in the first place.
120
+ if (externalDrive)
121
+ return;
122
+ // A play session can be started while the editor tab is ALREADY
123
+ // hidden. In that case no future visibilitychange-to-hidden event will
124
+ // arrive, and arming rAF would leave `running=true` forever while the
125
+ // browser executes zero callbacks. Classify and park the loop before
126
+ // arming it so status is truthful and visibility restore can resume it.
127
+ if (!visibilityListenerAttached && typeof document !== 'undefined') {
128
+ document.addEventListener('visibilitychange', handleVisibilityChange);
129
+ visibilityListenerAttached = true;
130
+ }
131
+ if (typeof document !== 'undefined' && document.hidden) {
132
+ running = false;
133
+ hiddenPaused = true;
134
+ return;
135
+ }
136
+ rafId = requestAnimationFrame(frame);
137
+ },
138
+ stop() {
139
+ running = false;
140
+ hiddenPaused = false;
141
+ cancelAnimationFrame(rafId);
142
+ if (visibilityListenerAttached && typeof document !== 'undefined') {
143
+ document.removeEventListener('visibilitychange', handleVisibilityChange);
144
+ visibilityListenerAttached = false;
145
+ }
146
+ },
147
+ get isRunning() {
148
+ return running;
149
+ },
150
+ /**
151
+ * Truthful liveness (issue #175 — see `GameLoopLiveness`'s doc comment
152
+ * in `core/types.ts` for the full contract). Unlike `isRunning` above,
153
+ * this DISTINGUISHES a hidden-tab pause from an actually-stopped loop:
154
+ * `hiddenPaused` is only ever set by `handleVisibilityChange` (T2.1's
155
+ * idle throttle) and cleared by `start()`/`stop()`/visibility-restore,
156
+ * so it can never be true at the same time `running` is true. An
157
+ * `externalDrive` loop never installs the visibility listener at all
158
+ * (see `start()` above), so `hiddenPaused` stays permanently `false` for
159
+ * it — it only ever reports `'running'` or `'stopped'`.
160
+ */
161
+ get liveness() {
162
+ if (hiddenPaused)
163
+ return 'hidden-paused';
164
+ return running ? 'running' : 'stopped';
165
+ },
166
+ set timeScale(value) {
167
+ const clamped = clampTimeScale(value);
168
+ if (clamped !== value) {
169
+ console.warn(`[game-loop] timeScale ${value} is out of range ` +
170
+ `[${TIME_SCALE_RANGE.min}, ${TIME_SCALE_RANGE.max}]; clamped to ${clamped}.`);
171
+ }
172
+ timeScale = clamped;
173
+ },
174
+ get timeScale() {
175
+ return timeScale;
176
+ },
177
+ /**
178
+ * The fixed substep timestep (seconds) this loop's accumulator consumes
179
+ * per `config.update()` call (`config.fixedTimestep ?? 1/60`) — read by
180
+ * `Game.runTicks` (D15, `runtime/game.ts`) so a synchronous fast-forward
181
+ * burst drives `game.runFrame` with the SAME `fixedDt` this loop's own
182
+ * rAF-driven accumulator would have used, without exposing (or
183
+ * `runTicks` needing) any other internal loop state.
184
+ */
185
+ get fixedDt() {
186
+ return fixedDt;
187
+ },
188
+ };
189
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * The seeded-random core (T-D15.1). `ctx.random` is a game-scoped PRNG with
3
+ * NAMED STREAMS: calling the object itself (`ctx.random()`) draws from the
4
+ * `'gameplay'` stream; `ctx.random.stream('vfx')` (or any other name) derives
5
+ * an INDEPENDENT generator, so a cosmetic/VFX draw can never perturb the
6
+ * gameplay draw order — the classic replay-drift trap option B ("one
7
+ * game-scoped PRNG only") would fall into (see the design doc's §2.a option
8
+ * table).
9
+ *
10
+ * Each stream is seeded from `fnv1a(name) ^ rootSeed` — deterministic given
11
+ * the root seed, independent of draw order across streams (drawing from
12
+ * `'vfx'` never advances `'gameplay'`'s generator, since they are two
13
+ * separate mulberry32 instances). `reseed(seed)` re-derives every stream
14
+ * that has EVER been asked for via `.stream(name)` (including the implicit
15
+ * `'gameplay'` stream `ctx.random()` itself draws from) — future draws only:
16
+ * numbers already returned before a `reseed()` call are not (and cannot be)
17
+ * un-returned; this matches `play.seed.set`'s documented semantics (T-D15.6).
18
+ *
19
+ * Deliberately reuses {@link createMulberry32} FROM `runtime/render-seed.ts`
20
+ * (the render/capture door's own generator) rather than duplicating the
21
+ * algorithm — `render-seed.ts` stays a zero-import module itself (this file
22
+ * imports FROM it, never the reverse), so this is a dependency-clean
23
+ * direction: the render/capture door and the gameplay determinism door share
24
+ * one PRNG implementation without either depending on the other's door
25
+ * logic (§2.a: "Kept as-is for the render/capture door only" — the two doors
26
+ * stay orthogonal; only the generator function itself is shared).
27
+ */
28
+ /** The name `ctx.random()` (called with no `.stream(...)`) draws from. */
29
+ export declare const GAMEPLAY_STREAM = "gameplay";
30
+ /** The fixed fallback seed a `SeededRandom` boots with when no explicit seed
31
+ * is supplied (mirrors `render-seed.ts`'s own `DEFAULT_RENDER_SEED` in
32
+ * spirit — an arbitrary but fixed golden-ratio-derived constant, never
33
+ * wall-clock/`Math.random`-derived, so an UNDECLARED project's `ctx.random`
34
+ * is still perfectly reproducible on its own terms even though nothing in
35
+ * the manifest asked for that — it just isn't a documented CONTRACT until
36
+ * `determinism.seededRandom` is declared, per T4.1's "no dead field" rule). */
37
+ export declare const DEFAULT_SEEDED_RANDOM_SEED = 2654435769;
38
+ /**
39
+ * The `ctx.random` surface (`GameContext.random`, `runtime/types.ts`).
40
+ * Callable (draws from the `'gameplay'` stream), plus:
41
+ * - `stream(name)` — an independent named generator, `[0, 1)` floats, same
42
+ * call signature as `Math.random`/the bare `SeededRandom` call itself.
43
+ * - `reseed(seed)` — re-derive every stream ever requested so far (future
44
+ * draws only) from a NEW root seed.
45
+ * - `seed` — the CURRENT root seed (reflects the last `reseed()` call, if
46
+ * any) — a live getter, not a value snapshotted at construction.
47
+ */
48
+ export interface SeededRandom {
49
+ (): number;
50
+ stream(name: string): () => number;
51
+ reseed(seed: number): void;
52
+ readonly seed: number;
53
+ }
54
+ /**
55
+ * Construct a fresh, game-scoped seeded-random surface. `initialSeed` is
56
+ * coerced to an unsigned 32-bit integer the same way `render-seed.ts`'s
57
+ * `installDeterministicRandom` does (`>>> 0`), so any finite JS number is
58
+ * accepted.
59
+ */
60
+ export declare function createSeededRandom(initialSeed: number): SeededRandom;
61
+ /** Called once by `createGame`, right after both the seeded-random surface
62
+ * and the Game shell object exist — mirrors `registerDebugRegistry`. */
63
+ export declare function registerSeededRandom(owner: object, random: SeededRandom): void;
64
+ /** The game-scoped `SeededRandom` backing every world's `ctx.random` — `null`
65
+ * for an owner built without one (there is always one for every real
66
+ * `createGame` call; `null` only for a hand-built `Game`-shaped stand-in a
67
+ * test constructs without going through `createGame`). */
68
+ export declare function getSeededRandom(owner: object): SeededRandom | null;
69
+ //# sourceMappingURL=seeded-random.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seeded-random.d.ts","sourceRoot":"","sources":["../../src/core/seeded-random.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,0EAA0E;AAC1E,eAAO,MAAM,eAAe,aAAa,CAAC;AAE1C;;;;;;gFAMgF;AAChF,eAAO,MAAM,0BAA0B,aAAa,CAAC;AAErD;;;;;;;;;GASG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,MAAM,CAAC;IACX,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,MAAM,CAAC;IACnC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAsBD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,YAAY,CAgDpE;AAeD;yEACyE;AACzE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAE9E;AAED;;;2DAG2D;AAC3D,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAElE"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * The seeded-random core (T-D15.1). `ctx.random` is a game-scoped PRNG with
3
+ * NAMED STREAMS: calling the object itself (`ctx.random()`) draws from the
4
+ * `'gameplay'` stream; `ctx.random.stream('vfx')` (or any other name) derives
5
+ * an INDEPENDENT generator, so a cosmetic/VFX draw can never perturb the
6
+ * gameplay draw order — the classic replay-drift trap option B ("one
7
+ * game-scoped PRNG only") would fall into (see the design doc's §2.a option
8
+ * table).
9
+ *
10
+ * Each stream is seeded from `fnv1a(name) ^ rootSeed` — deterministic given
11
+ * the root seed, independent of draw order across streams (drawing from
12
+ * `'vfx'` never advances `'gameplay'`'s generator, since they are two
13
+ * separate mulberry32 instances). `reseed(seed)` re-derives every stream
14
+ * that has EVER been asked for via `.stream(name)` (including the implicit
15
+ * `'gameplay'` stream `ctx.random()` itself draws from) — future draws only:
16
+ * numbers already returned before a `reseed()` call are not (and cannot be)
17
+ * un-returned; this matches `play.seed.set`'s documented semantics (T-D15.6).
18
+ *
19
+ * Deliberately reuses {@link createMulberry32} FROM `runtime/render-seed.ts`
20
+ * (the render/capture door's own generator) rather than duplicating the
21
+ * algorithm — `render-seed.ts` stays a zero-import module itself (this file
22
+ * imports FROM it, never the reverse), so this is a dependency-clean
23
+ * direction: the render/capture door and the gameplay determinism door share
24
+ * one PRNG implementation without either depending on the other's door
25
+ * logic (§2.a: "Kept as-is for the render/capture door only" — the two doors
26
+ * stay orthogonal; only the generator function itself is shared).
27
+ */
28
+ import { createMulberry32 } from '../runtime/render-seed';
29
+ /** The name `ctx.random()` (called with no `.stream(...)`) draws from. */
30
+ export const GAMEPLAY_STREAM = 'gameplay';
31
+ /** The fixed fallback seed a `SeededRandom` boots with when no explicit seed
32
+ * is supplied (mirrors `render-seed.ts`'s own `DEFAULT_RENDER_SEED` in
33
+ * spirit — an arbitrary but fixed golden-ratio-derived constant, never
34
+ * wall-clock/`Math.random`-derived, so an UNDECLARED project's `ctx.random`
35
+ * is still perfectly reproducible on its own terms even though nothing in
36
+ * the manifest asked for that — it just isn't a documented CONTRACT until
37
+ * `determinism.seededRandom` is declared, per T4.1's "no dead field" rule). */
38
+ export const DEFAULT_SEEDED_RANDOM_SEED = 0x9e3779b9;
39
+ /** fnv1a-32, the standard non-cryptographic string hash — used only to mix a
40
+ * stream NAME into the root seed, never as a determinism primitive on its
41
+ * own (mulberry32 is still what actually produces the `[0,1)` sequence). */
42
+ function fnv1a32(str) {
43
+ let hash = 0x811c9dc5;
44
+ for (let i = 0; i < str.length; i++) {
45
+ hash ^= str.charCodeAt(i);
46
+ hash = Math.imul(hash, 0x01000193);
47
+ }
48
+ return hash >>> 0;
49
+ }
50
+ /**
51
+ * Construct a fresh, game-scoped seeded-random surface. `initialSeed` is
52
+ * coerced to an unsigned 32-bit integer the same way `render-seed.ts`'s
53
+ * `installDeterministicRandom` does (`>>> 0`), so any finite JS number is
54
+ * accepted.
55
+ */
56
+ export function createSeededRandom(initialSeed) {
57
+ let rootSeed = initialSeed >>> 0;
58
+ const streams = new Map();
59
+ function deriveStreamSeed(name) {
60
+ return (fnv1a32(name) ^ rootSeed) >>> 0;
61
+ }
62
+ function getBox(name) {
63
+ let box = streams.get(name);
64
+ if (!box) {
65
+ box = { gen: createMulberry32(deriveStreamSeed(name)) };
66
+ streams.set(name, box);
67
+ }
68
+ return box;
69
+ }
70
+ function streamFn(name) {
71
+ const box = getBox(name);
72
+ return () => box.gen();
73
+ }
74
+ const random = (() => getBox(GAMEPLAY_STREAM).gen());
75
+ Object.defineProperties(random, {
76
+ stream: { value: streamFn, enumerable: true },
77
+ reseed: {
78
+ value: (seed) => {
79
+ rootSeed = seed >>> 0;
80
+ // Re-derive every stream ANYONE has ever asked for (including the
81
+ // implicit 'gameplay' stream, once `random()` or
82
+ // `.stream('gameplay')` has been called at least once) — a handle a
83
+ // caller stashed before this call keeps its identity but now reads
84
+ // from the freshly-seeded generator on its NEXT call (future draws
85
+ // only, per the design doc's `play.seed.set` semantics).
86
+ for (const [name, box] of streams) {
87
+ box.gen = createMulberry32(deriveStreamSeed(name));
88
+ }
89
+ },
90
+ enumerable: true,
91
+ },
92
+ seed: {
93
+ get: () => rootSeed,
94
+ enumerable: true,
95
+ },
96
+ });
97
+ return random;
98
+ }
99
+ // ---------------------------------------------------------------------------
100
+ // Game-scoped registry — mirrors `runtime/debug-registry.ts`'s
101
+ // `registerDebugRegistry`/`getDebugRegistry` WeakMap pattern exactly, but
102
+ // keyed on a bare `object` (not `Game`) so this module never needs to import
103
+ // `runtime/game.ts` even as a type — `core/` stays independent of `runtime/`
104
+ // except for the one explicit, documented `render-seed.ts` reuse above.
105
+ // `createGame` (`runtime/game.ts`) is the one real registrant, passing itself
106
+ // (the `GameInternal` shell) as the key, exactly like it does for
107
+ // `registerDebugRegistry(gameInternal, debugRegistry)`.
108
+ // ---------------------------------------------------------------------------
109
+ const registryByOwner = new WeakMap();
110
+ /** Called once by `createGame`, right after both the seeded-random surface
111
+ * and the Game shell object exist — mirrors `registerDebugRegistry`. */
112
+ export function registerSeededRandom(owner, random) {
113
+ registryByOwner.set(owner, random);
114
+ }
115
+ /** The game-scoped `SeededRandom` backing every world's `ctx.random` — `null`
116
+ * for an owner built without one (there is always one for every real
117
+ * `createGame` call; `null` only for a hand-built `Game`-shaped stand-in a
118
+ * test constructs without going through `createGame`). */
119
+ export function getSeededRandom(owner) {
120
+ return registryByOwner.get(owner) ?? null;
121
+ }
@@ -0,0 +1,199 @@
1
+ /**
2
+ * `SimClock` — P3, the sim-time scheduler (punchlist item P3, rung 4).
3
+ *
4
+ * `await` **is** the scheduler; JS already won that argument. The only thing
5
+ * missing from the engine was *clock binding*: a `delay(seconds)` that resolves
6
+ * on the fixed loop's own accumulator instead of on wall time, so a timer
7
+ * pauses when the game pauses, steps when the game steps, and reproduces
8
+ * exactly in an offline export. That, plus a timed-dispose helper for debris,
9
+ * is this whole module.
10
+ *
11
+ * ## This is NOT `AnimationClock`, and it never will be
12
+ *
13
+ * `animation/animation-clock.ts` is a seekable **cinematic** clock: it plays,
14
+ * pauses, loops, runs in reverse and is `seek()`ed to arbitrary times so
15
+ * Theatre/GSAP timelines and cue evaluators can be scrubbed. `SimClock` is the
16
+ * **monotonic gameplay clock**: it only ever moves forward, one fixed substep
17
+ * at a time, and there is no seek. Both live in one engine because they answer
18
+ * different questions — "where is the cinematic playhead" versus "how much
19
+ * gameplay time has actually elapsed".
20
+ *
21
+ * The reason they can never merge is a fact about Promises: **a Promise cannot
22
+ * un-resolve.** Scrub a seekable clock backwards past a `delay` that already
23
+ * fired and there is no correct behavior — you cannot un-await it. So `delay`
24
+ * binds to the clock that cannot rewind, and cinematic scrubbing stays with the
25
+ * clock that can.
26
+ *
27
+ * ## Two forms, because sync and async are genuinely different here
28
+ *
29
+ * `Game.runTicks` is **synchronous** (`runtime/game.ts`): it runs N substeps in
30
+ * one straight-line loop. A `delay` continuation is a microtask, so under
31
+ * `runTicks` — and under an offline export driven the same way — it does *not*
32
+ * interleave between ticks; it runs when the caller's stack unwinds, after the
33
+ * whole run. Under the ordinary rAF loop each frame yields, so the difference
34
+ * is invisible.
35
+ *
36
+ * Therefore:
37
+ *
38
+ * - `await clock.delay(n)` is the **ergonomic** form. Use it for gameplay.
39
+ * - `clock.after(n, fn)` is the **exact** form: `fn` is invoked inline, during
40
+ * the flush of the exact due tick, under every driver — rAF, `runTicks`,
41
+ * `step()`, offline export.
42
+ * - `clock.disposeAfter(obj, n)` is built on `after`, so debris removal is
43
+ * frame-exact in an offline export rather than "some time after the run".
44
+ *
45
+ * ## Firing rule (deterministic — pinned by `test/sim-clock.test.ts`)
46
+ *
47
+ * - The runtime calls `flush(simT)` immediately after it bumps `tick`/`simT`,
48
+ * inside the same `advanced` guard — so a paused or frozen world fires no
49
+ * timers at all, and `Game.play.step()` fires exactly the timers that one
50
+ * substep makes due.
51
+ * - A timer is due when `simT >= scheduledAt + seconds`.
52
+ * - Due timers run in due-time ascending order, insertion-sequence ascending
53
+ * on ties.
54
+ * - A timer scheduled *during* a flush is never due in that same flush, even
55
+ * at `seconds === 0`. That is what makes a self-rescheduling timer unable to
56
+ * hang the frame.
57
+ *
58
+ * ## Cancellation is `AbortSignal`
59
+ *
60
+ * The same rung-1 web primitive the rest of this program uses. An
61
+ * already-aborted signal makes `delay` reject immediately and `after` a no-op;
62
+ * rejection is a `DOMException` with `name === 'AbortError'`, matching `fetch`.
63
+ * Disposing the clock rejects every pending `delay` the same way — game code
64
+ * awaiting a delay is expected to tolerate rejection exactly as aborted `fetch`
65
+ * callers do.
66
+ *
67
+ * ## Ownership: the clock is GAME-scoped, and only the Game disposes it
68
+ *
69
+ * One clock per `Game`, shared by every world on it (`getSimClock(game)`); a
70
+ * mount with no Game shell builds a private, mount-local one instead. Whoever
71
+ * CREATED a clock disposes it: `GameInternal.dispose()` disposes the
72
+ * game-scoped one — `runtime/create-runtime.ts` calls that after every root has
73
+ * torn down — and a root adapter disposes only its own mount-local fallback.
74
+ * A per-root teardown must NEVER dispose the game-scoped clock: disposing one
75
+ * world's `mounted` is a supported way to end a sub-session while the Game
76
+ * keeps running, and doing so would freeze `now()`, reject every sibling
77
+ * world's pending `delay` and turn its later `after()` calls into silent
78
+ * no-ops. (`seededRandom` and `debugRegistry` are game-scoped the same way, and
79
+ * per-root teardown has never destroyed either — that asymmetry is what
80
+ * exposed the bug.)
81
+ *
82
+ * ## Cancelling your own timers is the GAME's job — warm restart will not
83
+ *
84
+ * A timer outlives the code that scheduled it unless something cancels it, and
85
+ * `hotReload` (warm restart) deliberately does not reach the game-scoped clock:
86
+ * it is per-ROOT, so cancelling here would kill a sibling root's live timers —
87
+ * the same ownership violation as above. There is deliberately no `reset()`.
88
+ *
89
+ * So a stale `after` closure surviving a warm restart is the same hazard class
90
+ * as a stale event listener, and it has the same owner and the same remedy: the
91
+ * game's own cleanup. `hotReload` runs the game's `dispose()` first for exactly
92
+ * this reason, and both `after` and `delay` take an `AbortSignal` so one
93
+ * controller cancels everything a `setup()` scheduled:
94
+ *
95
+ * ```ts
96
+ * export async function setup(ctx: GameContext): Promise<GameCleanup> {
97
+ * const ac = new AbortController();
98
+ * ctx.clock.after(3, () => spawnWave(), { signal: ac.signal });
99
+ * return { dispose: () => ac.abort() }; // cancels timers AND listeners
100
+ * }
101
+ * ```
102
+ *
103
+ * This is the engine-wide "Examples must clean up" contract (CLAUDE.md), not a
104
+ * special rule for timers.
105
+ *
106
+ * ## Deliberately absent
107
+ *
108
+ * - **No `every`/`repeat`/interval.** Nothing needs one, and `after`
109
+ * re-arming itself is three lines the game owns.
110
+ * - **No fiber kernel, no coroutine emulation, no `task.spawn`.** Calling an
111
+ * `async function` *is* `task.spawn` — the language already has it.
112
+ * - **No wall clock.** This module reads no system timer and creates no
113
+ * host timeout; every time value comes from the runtime's own accumulator.
114
+ */
115
+ import type * as THREE from 'three';
116
+ /** Cancel handle returned by {@link SimClock.after}/{@link SimClock.disposeAfter}. */
117
+ export interface SimTimerHandle {
118
+ /** Cancel the timer if it has not fired yet. Idempotent. */
119
+ cancel(): void;
120
+ }
121
+ /** Options accepted by every scheduling call. */
122
+ export interface SimScheduleOptions {
123
+ /** Cancel/reject when this signal aborts (already-aborted is honored too). */
124
+ readonly signal?: AbortSignal | undefined;
125
+ }
126
+ /** The sim clock as GAME CODE sees it — the whole public surface. */
127
+ export interface SimClock {
128
+ /** Sim seconds elapsed: the fixed loop's own accumulator. Monotonic. */
129
+ now(): number;
130
+ /** Completed fixed substeps — the same counter `Game`'s `tick` carries. */
131
+ tickNow(): number;
132
+ /**
133
+ * Resolve after `seconds` of SIM time. The ergonomic form; see the module
134
+ * header for why it is not frame-exact under a synchronous driver.
135
+ * Rejects with an `AbortError` `DOMException` if `opts.signal` aborts (or is
136
+ * already aborted), or if the clock is disposed while it is pending.
137
+ */
138
+ delay(seconds: number, opts?: SimScheduleOptions): Promise<void>;
139
+ /**
140
+ * Invoke `fn` inline during the flush of the exact due tick — the exact
141
+ * form. A no-op if `opts.signal` is already aborted.
142
+ */
143
+ after(seconds: number, fn: () => void, opts?: SimScheduleOptions): SimTimerHandle;
144
+ /**
145
+ * Debris: dispose `obj` after `seconds` of sim time. Built on {@link after},
146
+ * so removal lands on an exact tick. The disposal itself is supplied by the
147
+ * runtime (see {@link SimClockOptions.dispose}) — this module knows nothing
148
+ * about physics or rendering.
149
+ */
150
+ disposeAfter(obj: THREE.Object3D, seconds: number): SimTimerHandle;
151
+ }
152
+ /**
153
+ * The runtime-facing half — NOT for game code. Split off the public
154
+ * {@link SimClock} the same way `runtime/game.ts` splits `GameInternal` off
155
+ * `Game`: `GameContext.clock` is typed as `SimClock`, so game code cannot
156
+ * reach `flush`/`dispose`.
157
+ */
158
+ export interface SimClockInternal extends SimClock {
159
+ /**
160
+ * Advance to `simT` and fire everything now due. Called by `runFrameImpl`
161
+ * immediately after the `tick`/`simT` bump, inside the `advanced` guard.
162
+ * One call === one completed substep, which is why {@link SimClock.tickNow}
163
+ * can simply count them.
164
+ */
165
+ flush(simT: number): void;
166
+ /**
167
+ * Drop every pending timer and reject every pending `delay`. Called by
168
+ * whoever CREATED this clock and by nobody else — `GameInternal.dispose()`
169
+ * for the game-scoped one, the owning mount for a mount-local fallback. See
170
+ * the module header's ownership section.
171
+ */
172
+ dispose(): void;
173
+ }
174
+ export interface SimClockOptions {
175
+ /**
176
+ * How {@link SimClock.disposeAfter} disposes an object. Supplied by the
177
+ * runtime, which is the only layer that knows about physics
178
+ * registries and shared geometry; the clock only knows *when*.
179
+ */
180
+ readonly dispose: (obj: THREE.Object3D) => void;
181
+ }
182
+ /**
183
+ * Build the one sim clock a `Game` owns. See the module header for the
184
+ * contract; `runtime/game.ts` is the only production caller.
185
+ */
186
+ export declare function createSimClock(options: SimClockOptions): SimClockInternal;
187
+ /** Called once by `createGame`, right after the clock and the Game shell exist. */
188
+ export declare function registerSimClock(owner: object, clock: SimClockInternal): void;
189
+ /** The game-scoped clock backing every world's `ctx.clock` — `null` for an
190
+ * owner built without one (a hand-built `Game`-shaped stand-in that never went
191
+ * through `createGame`).
192
+ *
193
+ * Returns the INTERNAL view because this registry is engine-only — but a
194
+ * caller that RESOLVES a clock here is not its owner and must not call
195
+ * `dispose()` on it (module header, ownership). Game code never reaches it at
196
+ * all: `GameContext.clock` is typed as the public {@link SimClock}, which has
197
+ * neither `flush` nor `dispose`, the same way `Game` hides `GameInternal`. */
198
+ export declare function getSimClock(owner: object): SimClockInternal | null;
199
+ //# sourceMappingURL=sim-clock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sim-clock.d.ts","sourceRoot":"","sources":["../../src/core/sim-clock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiHG;AAEH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAEpC,sFAAsF;AACtF,MAAM,WAAW,cAAc;IAC7B,4DAA4D;IAC5D,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,iDAAiD;AACjD,MAAM,WAAW,kBAAkB;IACjC,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAC3C;AAED,qEAAqE;AACrE,MAAM,WAAW,QAAQ;IACvB,wEAAwE;IACxE,GAAG,IAAI,MAAM,CAAC;IACd,2EAA2E;IAC3E,OAAO,IAAI,MAAM,CAAC;IAClB;;;;;OAKG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE;;;OAGG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,IAAI,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,cAAc,CAAC;IAClF;;;;;OAKG;IACH,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,CAAC;CACpE;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAiB,SAAQ,QAAQ;IAChD;;;;;OAKG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;;OAKG;IACH,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC;CACjD;AAyBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,gBAAgB,CAiJzE;AAWD,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAE7E;AAED;;;;;;;;+EAQ+E;AAC/E,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAElE"}