@vgai/engine 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (541) hide show
  1. package/README.md +3 -1
  2. package/dist/adapter/authoring.d.ts +404 -0
  3. package/dist/adapter/authoring.d.ts.map +1 -0
  4. package/dist/adapter/authoring.js +22 -0
  5. package/dist/adapter/colyseus-networking-adapter.d.ts +43 -0
  6. package/dist/adapter/colyseus-networking-adapter.d.ts.map +1 -0
  7. package/dist/adapter/colyseus-networking-adapter.js +38 -0
  8. package/dist/adapter/first-party-systems.d.ts +38 -0
  9. package/dist/adapter/first-party-systems.d.ts.map +1 -0
  10. package/dist/adapter/first-party-systems.js +77 -0
  11. package/dist/adapter/game-adapter.d.ts +133 -0
  12. package/dist/adapter/game-adapter.d.ts.map +1 -0
  13. package/dist/adapter/game-adapter.js +10 -0
  14. package/dist/adapter/host-context.d.ts +73 -0
  15. package/dist/adapter/host-context.d.ts.map +1 -0
  16. package/dist/adapter/host-context.js +16 -0
  17. package/dist/adapter/index.d.ts +22 -0
  18. package/dist/adapter/index.d.ts.map +1 -0
  19. package/dist/adapter/index.js +15 -0
  20. package/dist/adapter/ingest/game-contract.d.ts +53 -0
  21. package/dist/adapter/ingest/game-contract.d.ts.map +1 -0
  22. package/dist/adapter/ingest/game-contract.js +30 -0
  23. package/dist/adapter/ingest/overlay-applier.d.ts +118 -0
  24. package/dist/adapter/ingest/overlay-applier.d.ts.map +1 -0
  25. package/dist/adapter/ingest/overlay-applier.js +132 -0
  26. package/dist/adapter/ingest/overlay-apply.d.ts +60 -0
  27. package/dist/adapter/ingest/overlay-apply.d.ts.map +1 -0
  28. package/dist/adapter/ingest/overlay-apply.js +101 -0
  29. package/dist/adapter/ingest/overlay-file.d.ts +79 -0
  30. package/dist/adapter/ingest/overlay-file.d.ts.map +1 -0
  31. package/dist/adapter/ingest/overlay-file.js +66 -0
  32. package/dist/adapter/ingest/overlay-report.d.ts +113 -0
  33. package/dist/adapter/ingest/overlay-report.d.ts.map +1 -0
  34. package/dist/adapter/ingest/overlay-report.js +103 -0
  35. package/dist/adapter/ingest/scene-capture.d.ts +97 -0
  36. package/dist/adapter/ingest/scene-capture.d.ts.map +1 -0
  37. package/dist/adapter/ingest/scene-capture.js +248 -0
  38. package/dist/adapter/ingest/upstream-pin.d.ts +47 -0
  39. package/dist/adapter/ingest/upstream-pin.d.ts.map +1 -0
  40. package/dist/adapter/ingest/upstream-pin.js +50 -0
  41. package/dist/adapter/loop-gate-report.d.ts +34 -0
  42. package/dist/adapter/loop-gate-report.d.ts.map +1 -0
  43. package/dist/adapter/loop-gate-report.js +37 -0
  44. package/dist/adapter/rapier-physics-adapter.d.ts +12 -0
  45. package/dist/adapter/rapier-physics-adapter.d.ts.map +1 -0
  46. package/dist/adapter/rapier-physics-adapter.js +46 -0
  47. package/dist/adapter/system-adapter.d.ts +133 -0
  48. package/dist/adapter/system-adapter.d.ts.map +1 -0
  49. package/dist/adapter/system-adapter.js +13 -0
  50. package/dist/adapter/transform.d.ts +18 -0
  51. package/dist/adapter/transform.d.ts.map +1 -0
  52. package/dist/adapter/transform.js +1 -0
  53. package/dist/adapter/vgai-scene-game-adapter.d.ts +116 -0
  54. package/dist/adapter/vgai-scene-game-adapter.d.ts.map +1 -0
  55. package/dist/adapter/vgai-scene-game-adapter.js +714 -0
  56. package/dist/adapter/world-kind.d.ts +30 -0
  57. package/dist/adapter/world-kind.d.ts.map +1 -0
  58. package/dist/adapter/world-kind.js +18 -0
  59. package/dist/ai/navigation.d.ts +64 -0
  60. package/dist/ai/navigation.d.ts.map +1 -0
  61. package/dist/ai/navigation.js +133 -0
  62. package/dist/animation/anim-graph-types.d.ts +25 -0
  63. package/dist/animation/anim-graph-types.d.ts.map +1 -0
  64. package/dist/animation/anim-graph-types.js +1 -0
  65. package/dist/animation/animation-clock.d.ts +213 -0
  66. package/dist/animation/animation-clock.d.ts.map +1 -0
  67. package/dist/animation/animation-clock.js +301 -0
  68. package/dist/animation/blend-node.d.ts +22 -0
  69. package/dist/animation/blend-node.d.ts.map +1 -0
  70. package/dist/animation/blend-node.js +97 -0
  71. package/dist/animation/camera-ownership.d.ts +250 -0
  72. package/dist/animation/camera-ownership.d.ts.map +1 -0
  73. package/dist/animation/camera-ownership.js +169 -0
  74. package/dist/animation/cinematic-cues.d.ts +200 -0
  75. package/dist/animation/cinematic-cues.d.ts.map +1 -0
  76. package/dist/animation/cinematic-cues.js +213 -0
  77. package/dist/animation/clip-map.d.ts +12 -0
  78. package/dist/animation/clip-map.d.ts.map +1 -0
  79. package/dist/animation/clip-map.js +37 -0
  80. package/dist/animation/gsap-registration.d.ts +119 -0
  81. package/dist/animation/gsap-registration.d.ts.map +1 -0
  82. package/dist/animation/gsap-registration.js +92 -0
  83. package/dist/animation/theatre-clock-binding.d.ts +89 -0
  84. package/dist/animation/theatre-clock-binding.d.ts.map +1 -0
  85. package/dist/animation/theatre-clock-binding.js +29 -0
  86. package/dist/animation/theatre-director.d.ts +242 -0
  87. package/dist/animation/theatre-director.d.ts.map +1 -0
  88. package/dist/animation/theatre-director.js +235 -0
  89. package/dist/animation/theatre-object-binding.d.ts +305 -0
  90. package/dist/animation/theatre-object-binding.d.ts.map +1 -0
  91. package/dist/animation/theatre-object-binding.js +351 -0
  92. package/dist/animation/xstate-animation-binding.d.ts +111 -0
  93. package/dist/animation/xstate-animation-binding.d.ts.map +1 -0
  94. package/dist/animation/xstate-animation-binding.js +307 -0
  95. package/dist/animation/xstate-animation-meta.d.ts +228 -0
  96. package/dist/animation/xstate-animation-meta.d.ts.map +1 -0
  97. package/dist/animation/xstate-animation-meta.js +221 -0
  98. package/dist/assets.d.ts +26 -0
  99. package/dist/assets.d.ts.map +1 -0
  100. package/dist/assets.js +55 -0
  101. package/dist/audio/index.d.ts +4 -0
  102. package/dist/audio/index.d.ts.map +1 -0
  103. package/dist/audio/index.js +24 -0
  104. package/dist/audio/tone-clock-binding.d.ts +75 -0
  105. package/dist/audio/tone-clock-binding.d.ts.map +1 -0
  106. package/dist/audio/tone-clock-binding.js +29 -0
  107. package/dist/audio/tone-context.d.ts +114 -0
  108. package/dist/audio/tone-context.d.ts.map +1 -0
  109. package/dist/audio/tone-context.js +39 -0
  110. package/dist/audio/tone-offline-render.d.ts +90 -0
  111. package/dist/audio/tone-offline-render.d.ts.map +1 -0
  112. package/dist/audio/tone-offline-render.js +56 -0
  113. package/dist/audio/wav-encode.d.ts +38 -0
  114. package/dist/audio/wav-encode.d.ts.map +1 -0
  115. package/dist/audio/wav-encode.js +97 -0
  116. package/dist/core/game-loop.d.ts +21 -0
  117. package/dist/core/game-loop.d.ts.map +1 -0
  118. package/dist/core/game-loop.js +130 -0
  119. package/dist/core/system-runner.d.ts +120 -0
  120. package/dist/core/system-runner.d.ts.map +1 -0
  121. package/dist/core/system-runner.js +286 -0
  122. package/dist/core/types.d.ts +58 -0
  123. package/dist/core/types.d.ts.map +1 -0
  124. package/dist/core/types.js +25 -0
  125. package/dist/data/data-asset.d.ts +101 -0
  126. package/dist/data/data-asset.d.ts.map +1 -0
  127. package/dist/data/data-asset.js +122 -0
  128. package/dist/data/data-check-core.d.ts +110 -0
  129. package/dist/data/data-check-core.d.ts.map +1 -0
  130. package/dist/data/data-check-core.js +178 -0
  131. package/dist/data/data-ref.d.ts +79 -0
  132. package/dist/data/data-ref.d.ts.map +1 -0
  133. package/dist/data/data-ref.js +130 -0
  134. package/dist/data/vite-plugin-data.d.ts +79 -0
  135. package/dist/data/vite-plugin-data.d.ts.map +1 -0
  136. package/dist/data/vite-plugin-data.js +217 -0
  137. package/dist/dev/console-bridge.d.ts +22 -0
  138. package/dist/dev/console-bridge.d.ts.map +1 -0
  139. package/dist/dev/console-bridge.js +71 -0
  140. package/dist/dev/debug-draw.d.ts +24 -0
  141. package/dist/dev/debug-draw.d.ts.map +1 -0
  142. package/dist/dev/debug-draw.js +73 -0
  143. package/dist/dev/logger.d.ts +30 -0
  144. package/dist/dev/logger.d.ts.map +1 -0
  145. package/dist/dev/logger.js +90 -0
  146. package/dist/ecs/component-manager.d.ts +189 -0
  147. package/dist/ecs/component-manager.d.ts.map +1 -0
  148. package/dist/ecs/component-manager.js +676 -0
  149. package/dist/ecs/game-component.d.ts +97 -0
  150. package/dist/ecs/game-component.d.ts.map +1 -0
  151. package/dist/ecs/game-component.js +80 -0
  152. package/dist/ecs/hmr-swap-report.d.ts +53 -0
  153. package/dist/ecs/hmr-swap-report.d.ts.map +1 -0
  154. package/dist/ecs/hmr-swap-report.js +55 -0
  155. package/dist/index.d.ts +37 -0
  156. package/dist/index.d.ts.map +1 -0
  157. package/dist/index.js +30 -0
  158. package/dist/input/input-manager.d.ts +596 -0
  159. package/dist/input/input-manager.d.ts.map +1 -0
  160. package/dist/input/input-manager.js +1564 -0
  161. package/dist/input/input-types.d.ts +171 -0
  162. package/dist/input/input-types.d.ts.map +1 -0
  163. package/dist/input/input-types.js +1 -0
  164. package/dist/input/prompt-labels.d.ts +21 -0
  165. package/dist/input/prompt-labels.d.ts.map +1 -0
  166. package/dist/input/prompt-labels.js +121 -0
  167. package/dist/input/rebind-controller.d.ts +59 -0
  168. package/dist/input/rebind-controller.d.ts.map +1 -0
  169. package/dist/input/rebind-controller.js +85 -0
  170. package/dist/input/schema.d.ts +16 -0
  171. package/dist/input/schema.d.ts.map +1 -0
  172. package/dist/input/schema.js +228 -0
  173. package/dist/loader.d.ts +43 -0
  174. package/dist/loader.d.ts.map +1 -0
  175. package/dist/loader.js +59 -0
  176. package/dist/manifest/index.d.ts +5 -0
  177. package/dist/manifest/index.d.ts.map +1 -0
  178. package/dist/manifest/index.js +8 -0
  179. package/dist/manifest/load-file.d.ts +4 -0
  180. package/dist/manifest/load-file.d.ts.map +1 -0
  181. package/dist/manifest/load-file.js +14 -0
  182. package/dist/manifest/load.d.ts +117 -0
  183. package/dist/manifest/load.d.ts.map +1 -0
  184. package/dist/manifest/load.js +255 -0
  185. package/dist/manifest/schema.d.ts +173 -0
  186. package/dist/manifest/schema.d.ts.map +1 -0
  187. package/dist/manifest/schema.js +302 -0
  188. package/dist/physics/collision-system.d.ts +41 -0
  189. package/dist/physics/collision-system.d.ts.map +1 -0
  190. package/dist/physics/collision-system.js +64 -0
  191. package/dist/physics/physics-registry.d.ts +45 -0
  192. package/dist/physics/physics-registry.d.ts.map +1 -0
  193. package/dist/physics/physics-registry.js +65 -0
  194. package/dist/physics/transform-writer.d.ts +16 -0
  195. package/dist/physics/transform-writer.d.ts.map +1 -0
  196. package/dist/physics/transform-writer.js +38 -0
  197. package/dist/physics/trigger-dispatch.d.ts +24 -0
  198. package/dist/physics/trigger-dispatch.d.ts.map +1 -0
  199. package/dist/physics/trigger-dispatch.js +80 -0
  200. package/dist/react/game-state.d.ts +105 -0
  201. package/dist/react/game-state.d.ts.map +1 -0
  202. package/dist/react/game-state.js +144 -0
  203. package/dist/react/use-data.d.ts +60 -0
  204. package/dist/react/use-data.d.ts.map +1 -0
  205. package/dist/react/use-data.js +96 -0
  206. package/dist/react/use-selection.d.ts +75 -0
  207. package/dist/react/use-selection.d.ts.map +1 -0
  208. package/dist/react/use-selection.js +90 -0
  209. package/dist/render/auto-batcher.d.ts +34 -0
  210. package/dist/render/auto-batcher.d.ts.map +1 -0
  211. package/dist/render/auto-batcher.js +140 -0
  212. package/dist/render/render-batch-system.d.ts +33 -0
  213. package/dist/render/render-batch-system.d.ts.map +1 -0
  214. package/dist/render/render-batch-system.js +230 -0
  215. package/dist/render/render-features.d.ts +47 -0
  216. package/dist/render/render-features.d.ts.map +1 -0
  217. package/dist/render/render-features.js +105 -0
  218. package/dist/render/render-settings.d.ts +36 -0
  219. package/dist/render/render-settings.d.ts.map +1 -0
  220. package/dist/render/render-settings.js +51 -0
  221. package/dist/runtime/create-runtime.d.ts +280 -0
  222. package/dist/runtime/create-runtime.d.ts.map +1 -0
  223. package/dist/runtime/create-runtime.js +795 -0
  224. package/dist/runtime/frame-selector-cache.d.ts +41 -0
  225. package/dist/runtime/frame-selector-cache.d.ts.map +1 -0
  226. package/dist/runtime/frame-selector-cache.js +65 -0
  227. package/dist/runtime/game.d.ts +433 -0
  228. package/dist/runtime/game.d.ts.map +1 -0
  229. package/dist/runtime/game.js +569 -0
  230. package/dist/runtime/input-router.d.ts +78 -0
  231. package/dist/runtime/input-router.d.ts.map +1 -0
  232. package/dist/runtime/input-router.js +171 -0
  233. package/dist/runtime/mount-game.d.ts +129 -0
  234. package/dist/runtime/mount-game.d.ts.map +1 -0
  235. package/dist/runtime/mount-game.js +152 -0
  236. package/dist/runtime/mount-manifest.d.ts +119 -0
  237. package/dist/runtime/mount-manifest.d.ts.map +1 -0
  238. package/dist/runtime/mount-manifest.js +204 -0
  239. package/dist/runtime/render-audio-control.d.ts +110 -0
  240. package/dist/runtime/render-audio-control.d.ts.map +1 -0
  241. package/dist/runtime/render-audio-control.js +111 -0
  242. package/dist/runtime/render-control.d.ts +291 -0
  243. package/dist/runtime/render-control.d.ts.map +1 -0
  244. package/dist/runtime/render-control.js +264 -0
  245. package/dist/runtime/render-seed.d.ts +57 -0
  246. package/dist/runtime/render-seed.d.ts.map +1 -0
  247. package/dist/runtime/render-seed.js +74 -0
  248. package/dist/runtime/scene-ui-bridge.d.ts +69 -0
  249. package/dist/runtime/scene-ui-bridge.d.ts.map +1 -0
  250. package/dist/runtime/scene-ui-bridge.js +23 -0
  251. package/dist/runtime/scene-ui-data.d.ts +13 -0
  252. package/dist/runtime/scene-ui-data.d.ts.map +1 -0
  253. package/dist/runtime/scene-ui-data.js +92 -0
  254. package/dist/runtime/state-bridge.d.ts +47 -0
  255. package/dist/runtime/state-bridge.d.ts.map +1 -0
  256. package/dist/runtime/state-bridge.js +53 -0
  257. package/dist/runtime/types.d.ts +179 -0
  258. package/dist/runtime/types.d.ts.map +1 -0
  259. package/dist/runtime/types.js +1 -0
  260. package/dist/scene/asset-loaders.d.ts +79 -0
  261. package/dist/scene/asset-loaders.d.ts.map +1 -0
  262. package/dist/scene/asset-loaders.js +141 -0
  263. package/dist/scene/asset-paths.d.ts +11 -0
  264. package/dist/scene/asset-paths.d.ts.map +1 -0
  265. package/dist/scene/asset-paths.js +108 -0
  266. package/dist/scene/asset-ref-check.d.ts +88 -0
  267. package/dist/scene/asset-ref-check.d.ts.map +1 -0
  268. package/dist/scene/asset-ref-check.js +214 -0
  269. package/dist/scene/asset-registry.d.ts +30 -0
  270. package/dist/scene/asset-registry.d.ts.map +1 -0
  271. package/dist/scene/asset-registry.js +50 -0
  272. package/dist/scene/collider-dimensions.d.ts +63 -0
  273. package/dist/scene/collider-dimensions.d.ts.map +1 -0
  274. package/dist/scene/collider-dimensions.js +98 -0
  275. package/dist/scene/component-registry.d.ts +17 -0
  276. package/dist/scene/component-registry.d.ts.map +1 -0
  277. package/dist/scene/component-registry.js +28 -0
  278. package/dist/scene/defaults.d.ts +252 -0
  279. package/dist/scene/defaults.d.ts.map +1 -0
  280. package/dist/scene/defaults.js +151 -0
  281. package/dist/scene/geometries/index.d.ts +8 -0
  282. package/dist/scene/geometries/index.d.ts.map +1 -0
  283. package/dist/scene/geometries/index.js +7 -0
  284. package/dist/scene/geometries/terrain.d.ts +2 -0
  285. package/dist/scene/geometries/terrain.d.ts.map +1 -0
  286. package/dist/scene/geometries/terrain.js +37 -0
  287. package/dist/scene/geometry-registry.d.ts +24 -0
  288. package/dist/scene/geometry-registry.d.ts.map +1 -0
  289. package/dist/scene/geometry-registry.js +20 -0
  290. package/dist/scene/instance-registry.d.ts +36 -0
  291. package/dist/scene/instance-registry.d.ts.map +1 -0
  292. package/dist/scene/instance-registry.js +55 -0
  293. package/dist/scene/instancers/grid.d.ts +2 -0
  294. package/dist/scene/instancers/grid.d.ts.map +1 -0
  295. package/dist/scene/instancers/grid.js +36 -0
  296. package/dist/scene/instancers/index.d.ts +8 -0
  297. package/dist/scene/instancers/index.d.ts.map +1 -0
  298. package/dist/scene/instancers/index.js +7 -0
  299. package/dist/scene/light-camera-factory.d.ts +23 -0
  300. package/dist/scene/light-camera-factory.d.ts.map +1 -0
  301. package/dist/scene/light-camera-factory.js +68 -0
  302. package/dist/scene/material-factory.d.ts +17 -0
  303. package/dist/scene/material-factory.d.ts.map +1 -0
  304. package/dist/scene/material-factory.js +197 -0
  305. package/dist/scene/material-registry.d.ts +40 -0
  306. package/dist/scene/material-registry.d.ts.map +1 -0
  307. package/dist/scene/material-registry.js +44 -0
  308. package/dist/scene/materials/index.d.ts +8 -0
  309. package/dist/scene/materials/index.d.ts.map +1 -0
  310. package/dist/scene/materials/index.js +7 -0
  311. package/dist/scene/materials/water.d.ts +2 -0
  312. package/dist/scene/materials/water.d.ts.map +1 -0
  313. package/dist/scene/materials/water.js +54 -0
  314. package/dist/scene/parse.d.ts +23 -0
  315. package/dist/scene/parse.d.ts.map +1 -0
  316. package/dist/scene/parse.js +179 -0
  317. package/dist/scene/particles-factory.d.ts +33 -0
  318. package/dist/scene/particles-factory.d.ts.map +1 -0
  319. package/dist/scene/particles-factory.js +282 -0
  320. package/dist/scene/scene-apply.d.ts +109 -0
  321. package/dist/scene/scene-apply.d.ts.map +1 -0
  322. package/dist/scene/scene-apply.js +326 -0
  323. package/dist/scene/scene-diff-schema.d.ts +285 -0
  324. package/dist/scene/scene-diff-schema.d.ts.map +1 -0
  325. package/dist/scene/scene-diff-schema.js +92 -0
  326. package/dist/scene/scene-diff-types.d.ts +40 -0
  327. package/dist/scene/scene-diff-types.d.ts.map +1 -0
  328. package/dist/scene/scene-diff-types.js +14 -0
  329. package/dist/scene/scene-loader.d.ts +177 -0
  330. package/dist/scene/scene-loader.d.ts.map +1 -0
  331. package/dist/scene/scene-loader.js +1213 -0
  332. package/dist/scene/scene-query.d.ts +11 -0
  333. package/dist/scene/scene-query.d.ts.map +1 -0
  334. package/dist/scene/scene-query.js +63 -0
  335. package/dist/scene/scene-types.d.ts +10 -0
  336. package/dist/scene/scene-types.d.ts.map +1 -0
  337. package/dist/scene/scene-types.js +8 -0
  338. package/dist/scene/scene-version.d.ts +26 -0
  339. package/dist/scene/scene-version.d.ts.map +1 -0
  340. package/dist/scene/scene-version.js +34 -0
  341. package/dist/scene/schema/animation.d.ts +8 -0
  342. package/dist/scene/schema/animation.d.ts.map +1 -0
  343. package/dist/scene/schema/animation.js +42 -0
  344. package/dist/scene/schema/audio.d.ts +13 -0
  345. package/dist/scene/schema/audio.d.ts.map +1 -0
  346. package/dist/scene/schema/audio.js +22 -0
  347. package/dist/scene/schema/camera.d.ts +28 -0
  348. package/dist/scene/schema/camera.d.ts.map +1 -0
  349. package/dist/scene/schema/camera.js +17 -0
  350. package/dist/scene/schema/collider.d.ts +40 -0
  351. package/dist/scene/schema/collider.d.ts.map +1 -0
  352. package/dist/scene/schema/collider.js +55 -0
  353. package/dist/scene/schema/entity-ref.d.ts +31 -0
  354. package/dist/scene/schema/entity-ref.d.ts.map +1 -0
  355. package/dist/scene/schema/entity-ref.js +61 -0
  356. package/dist/scene/schema/entity.d.ts +1036 -0
  357. package/dist/scene/schema/entity.d.ts.map +1 -0
  358. package/dist/scene/schema/entity.js +153 -0
  359. package/dist/scene/schema/environment.d.ts +425 -0
  360. package/dist/scene/schema/environment.d.ts.map +1 -0
  361. package/dist/scene/schema/environment.js +357 -0
  362. package/dist/scene/schema/index.d.ts +39 -0
  363. package/dist/scene/schema/index.d.ts.map +1 -0
  364. package/dist/scene/schema/index.js +20 -0
  365. package/dist/scene/schema/instances.d.ts +14 -0
  366. package/dist/scene/schema/instances.d.ts.map +1 -0
  367. package/dist/scene/schema/instances.js +28 -0
  368. package/dist/scene/schema/joint.d.ts +23 -0
  369. package/dist/scene/schema/joint.d.ts.map +1 -0
  370. package/dist/scene/schema/joint.js +23 -0
  371. package/dist/scene/schema/light.d.ts +38 -0
  372. package/dist/scene/schema/light.d.ts.map +1 -0
  373. package/dist/scene/schema/light.js +26 -0
  374. package/dist/scene/schema/material.d.ts +199 -0
  375. package/dist/scene/schema/material.d.ts.map +1 -0
  376. package/dist/scene/schema/material.js +99 -0
  377. package/dist/scene/schema/mesh.d.ts +48 -0
  378. package/dist/scene/schema/mesh.d.ts.map +1 -0
  379. package/dist/scene/schema/mesh.js +82 -0
  380. package/dist/scene/schema/particles.d.ts +2178 -0
  381. package/dist/scene/schema/particles.d.ts.map +1 -0
  382. package/dist/scene/schema/particles.js +321 -0
  383. package/dist/scene/schema/physics.d.ts +56 -0
  384. package/dist/scene/schema/physics.d.ts.map +1 -0
  385. package/dist/scene/schema/physics.js +37 -0
  386. package/dist/scene/schema/scene-file.d.ts +304 -0
  387. package/dist/scene/schema/scene-file.d.ts.map +1 -0
  388. package/dist/scene/schema/scene-file.js +262 -0
  389. package/dist/scene/schema/shadow.d.ts +28 -0
  390. package/dist/scene/schema/shadow.d.ts.map +1 -0
  391. package/dist/scene/schema/shadow.js +20 -0
  392. package/dist/scene/schema/spline.d.ts +25 -0
  393. package/dist/scene/schema/spline.d.ts.map +1 -0
  394. package/dist/scene/schema/spline.js +15 -0
  395. package/dist/scene/schema/tuples.d.ts +12 -0
  396. package/dist/scene/schema/tuples.d.ts.map +1 -0
  397. package/dist/scene/schema/tuples.js +14 -0
  398. package/dist/scene/schema/ui.d.ts +880 -0
  399. package/dist/scene/schema/ui.d.ts.map +1 -0
  400. package/dist/scene/schema/ui.js +506 -0
  401. package/dist/scene/user-data.d.ts +171 -0
  402. package/dist/scene/user-data.d.ts.map +1 -0
  403. package/dist/scene/user-data.js +137 -0
  404. package/dist/setup/setup-audio.d.ts +20 -0
  405. package/dist/setup/setup-audio.d.ts.map +1 -0
  406. package/dist/setup/setup-audio.js +41 -0
  407. package/dist/setup/setup-particles.d.ts +17 -0
  408. package/dist/setup/setup-particles.d.ts.map +1 -0
  409. package/dist/setup/setup-particles.js +16 -0
  410. package/dist/setup/setup-physics.d.ts +25 -0
  411. package/dist/setup/setup-physics.d.ts.map +1 -0
  412. package/dist/setup/setup-physics.js +51 -0
  413. package/dist/setup/setup-renderer.d.ts +69 -0
  414. package/dist/setup/setup-renderer.d.ts.map +1 -0
  415. package/dist/setup/setup-renderer.js +363 -0
  416. package/dist/tools/define-tool.d.ts +105 -0
  417. package/dist/tools/define-tool.d.ts.map +1 -0
  418. package/dist/tools/define-tool.js +82 -0
  419. package/dist/world2d/authoring-2d.d.ts +76 -0
  420. package/dist/world2d/authoring-2d.d.ts.map +1 -0
  421. package/dist/world2d/authoring-2d.js +176 -0
  422. package/dist/world2d/capture-to-scene2d.d.ts +5 -0
  423. package/dist/world2d/capture-to-scene2d.d.ts.map +1 -0
  424. package/dist/world2d/capture-to-scene2d.js +49 -0
  425. package/dist/world2d/collision-2d.d.ts +52 -0
  426. package/dist/world2d/collision-2d.d.ts.map +1 -0
  427. package/dist/world2d/collision-2d.js +70 -0
  428. package/dist/world2d/components-2d.d.ts +47 -0
  429. package/dist/world2d/components-2d.d.ts.map +1 -0
  430. package/dist/world2d/components-2d.js +77 -0
  431. package/dist/world2d/index.d.ts +34 -0
  432. package/dist/world2d/index.d.ts.map +1 -0
  433. package/dist/world2d/index.js +32 -0
  434. package/dist/world2d/ingest-iframe-2d.d.ts +82 -0
  435. package/dist/world2d/ingest-iframe-2d.d.ts.map +1 -0
  436. package/dist/world2d/ingest-iframe-2d.js +166 -0
  437. package/dist/world2d/ingest2d.d.ts +97 -0
  438. package/dist/world2d/ingest2d.d.ts.map +1 -0
  439. package/dist/world2d/ingest2d.js +40 -0
  440. package/dist/world2d/physics2d-registry.d.ts +24 -0
  441. package/dist/world2d/physics2d-registry.d.ts.map +1 -0
  442. package/dist/world2d/physics2d-registry.js +38 -0
  443. package/dist/world2d/pixi-game-adapter.d.ts +107 -0
  444. package/dist/world2d/pixi-game-adapter.d.ts.map +1 -0
  445. package/dist/world2d/pixi-game-adapter.js +211 -0
  446. package/dist/world2d/pixi-surface.d.ts +39 -0
  447. package/dist/world2d/pixi-surface.d.ts.map +1 -0
  448. package/dist/world2d/pixi-surface.js +47 -0
  449. package/dist/world2d/scene-capture-2d.d.ts +43 -0
  450. package/dist/world2d/scene-capture-2d.d.ts.map +1 -0
  451. package/dist/world2d/scene-capture-2d.js +92 -0
  452. package/dist/world2d/scene2d-loader.d.ts +27 -0
  453. package/dist/world2d/scene2d-loader.d.ts.map +1 -0
  454. package/dist/world2d/scene2d-loader.js +274 -0
  455. package/dist/world2d/schema/entity2d.d.ts +102 -0
  456. package/dist/world2d/schema/entity2d.d.ts.map +1 -0
  457. package/dist/world2d/schema/entity2d.js +119 -0
  458. package/dist/world2d/schema/physics2d.d.ts +46 -0
  459. package/dist/world2d/schema/physics2d.d.ts.map +1 -0
  460. package/dist/world2d/schema/physics2d.js +45 -0
  461. package/dist/world2d/schema/sprite.d.ts +42 -0
  462. package/dist/world2d/schema/sprite.d.ts.map +1 -0
  463. package/dist/world2d/schema/sprite.js +63 -0
  464. package/dist/world2d/schema/tilemap.d.ts +15 -0
  465. package/dist/world2d/schema/tilemap.d.ts.map +1 -0
  466. package/dist/world2d/schema/tilemap.js +19 -0
  467. package/dist/world2d/schema/tuples2d.d.ts +20 -0
  468. package/dist/world2d/schema/tuples2d.d.ts.map +1 -0
  469. package/dist/world2d/schema/tuples2d.js +19 -0
  470. package/dist/world2d/system-adapters-2d.d.ts +16 -0
  471. package/dist/world2d/system-adapters-2d.d.ts.map +1 -0
  472. package/dist/world2d/system-adapters-2d.js +37 -0
  473. package/dist/world2d/transform-writer-2d.d.ts +16 -0
  474. package/dist/world2d/transform-writer-2d.d.ts.map +1 -0
  475. package/dist/world2d/transform-writer-2d.js +22 -0
  476. package/dist/world2d/types.d.ts +53 -0
  477. package/dist/world2d/types.d.ts.map +1 -0
  478. package/dist/world2d/types.js +1 -0
  479. package/package.json +18 -4
  480. package/src/adapter/authoring.ts +10 -0
  481. package/src/adapter/first-party-systems.ts +23 -34
  482. package/src/adapter/index.ts +1 -3
  483. package/src/adapter/system-adapter.ts +15 -22
  484. package/src/adapter/vgai-scene-game-adapter.ts +5 -14
  485. package/src/animation/anim-graph-types.ts +12 -43
  486. package/src/animation/animation-clock.ts +479 -0
  487. package/src/animation/camera-ownership.ts +467 -0
  488. package/src/animation/cinematic-cues.ts +451 -0
  489. package/src/animation/clip-map.ts +41 -0
  490. package/src/animation/gsap-registration.ts +184 -0
  491. package/src/animation/theatre-clock-binding.ts +111 -0
  492. package/src/animation/theatre-director.ts +347 -0
  493. package/src/animation/theatre-object-binding.ts +661 -0
  494. package/src/animation/xstate-animation-binding.ts +398 -0
  495. package/src/animation/xstate-animation-meta.ts +282 -0
  496. package/src/audio/index.ts +39 -7
  497. package/src/audio/tone-clock-binding.ts +98 -0
  498. package/src/audio/tone-context.ts +129 -0
  499. package/src/audio/tone-offline-render.ts +167 -0
  500. package/src/audio/wav-encode.ts +119 -0
  501. package/src/core/game-loop.ts +17 -0
  502. package/src/core/types.ts +13 -0
  503. package/src/data/data-asset.ts +167 -0
  504. package/src/data/data-check-core.ts +242 -0
  505. package/src/data/data-ref.ts +145 -0
  506. package/src/data/vite-plugin-data.ts +290 -0
  507. package/src/index.ts +48 -0
  508. package/src/input/input-manager.ts +1206 -32
  509. package/src/input/input-types.ts +155 -3
  510. package/src/input/prompt-labels.ts +122 -0
  511. package/src/input/rebind-controller.ts +105 -0
  512. package/src/input/schema.ts +206 -52
  513. package/src/react/use-data.ts +114 -0
  514. package/src/react/use-selection.tsx +135 -0
  515. package/src/runtime/create-runtime.ts +30 -9
  516. package/src/runtime/render-audio-control.ts +168 -0
  517. package/src/runtime/render-control.ts +522 -0
  518. package/src/runtime/render-seed.ts +79 -0
  519. package/src/runtime/types.ts +0 -5
  520. package/src/scene/asset-loaders.ts +10 -36
  521. package/src/scene/asset-paths.ts +0 -2
  522. package/src/scene/asset-ref-check.ts +248 -0
  523. package/src/scene/parse.ts +133 -0
  524. package/src/scene/scene-loader.ts +81 -96
  525. package/src/scene/schema/animation.ts +30 -79
  526. package/src/scene/schema/entity.ts +20 -0
  527. package/src/scene/schema/index.ts +2 -12
  528. package/src/scene/user-data.ts +8 -9
  529. package/src/setup/setup-renderer.ts +9 -2
  530. package/src/tools/define-tool.ts +152 -0
  531. package/src/animation/anim-graph.ts +0 -406
  532. package/src/animation/anim-system.ts +0 -28
  533. package/src/animation/property-track.ts +0 -178
  534. package/src/animation/schema.ts +0 -204
  535. package/src/audio/ambient.ts +0 -300
  536. package/src/audio/impacts.ts +0 -212
  537. package/src/audio/movement.ts +0 -140
  538. package/src/audio/musical.ts +0 -200
  539. package/src/audio/ui-sounds.ts +0 -171
  540. package/src/audio/vehicle.ts +0 -235
  541. package/src/audio/weapons.ts +0 -152
@@ -0,0 +1,676 @@
1
+ import { PHASE_ORDER } from '../core/types';
2
+ import { isFirstPartyMounted } from '../runtime/game';
3
+ import { GameComponent } from './game-component';
4
+ import { logHmrSwapMiss } from './hmr-swap-report';
5
+ /**
6
+ * Find the `WorldInstance` (T7.1, `docs/GAME-ROOT-DESIGN.md`) that owns this
7
+ * manager's `ctx`, for wiring `GameComponent.world` at attach (T7.2, D8 —
8
+ * `docs/GAME-COMPONENT-GENERALIZATION.md` §2). Matches by `mounted.ctx ===
9
+ * ctx` identity (the same probe `isFirstPartyMounted` narrows for) rather
10
+ * than by id, so it works unmodified whether this manager belongs to the
11
+ * default world or a second/third registered world (`test/
12
+ * game-two-worlds.test.ts`).
13
+ *
14
+ * WORLD-WIRING STATE (T7.2 slice 2 — was a KNOWN GAP in slice 1, now closed
15
+ * two ways): `ctx.game`/`ctx.worlds` exist from the start of `mount()`, but
16
+ * the `WorldInstance` itself is constructed by `registerThreeWorld` in
17
+ * `create-runtime.ts` only AFTER `mount()` returns — i.e. AFTER
18
+ * scene-authored components have already been attached by the scene loader
19
+ * during that same `mount()` call. For those attaches, THIS function still
20
+ * resolves to `undefined` (the world genuinely doesn't exist yet — there is
21
+ * no way around that ordering; the `WorldInstance` wraps `mounted`, which
22
+ * only exists once `mount()` returns). What closes the gap is
23
+ * `adoptWorld()` below: `registerThreeWorld` calls it immediately after
24
+ * building the `WorldInstance`, and it backfills `instance.world` for every
25
+ * already-attached instance still missing one — a one-time wiring
26
+ * completion at registration, not a lazy getter and not a per-frame sync.
27
+ * Only a component attached AFTER that backfill and before the NEXT world's
28
+ * registration (there is no such window in the single-manager-per-world
29
+ * architecture) would still see a stale `undefined`; in practice every
30
+ * instance ends up with a defined, correct `world` by the time
31
+ * `createGameRuntime`/`registerThreeWorld` returns.
32
+ */
33
+ function resolveWorldInstance(ctx) {
34
+ if (!ctx.game)
35
+ return undefined;
36
+ for (const w of ctx.game.worlds) {
37
+ if (isFirstPartyMounted(w.mounted) && w.mounted.ctx === ctx)
38
+ return w;
39
+ }
40
+ return undefined;
41
+ }
42
+ /** Best-effort human label for an error message — a node's `label` (PIXI.Container,
43
+ * v8) or `name` (THREE.Object3D, and PIXI's deprecated alias), falling back to a
44
+ * generic placeholder when neither is set. */
45
+ function describeNode(node) {
46
+ const n = node;
47
+ const label = typeof n.label === 'string' && n.label
48
+ ? n.label
49
+ : typeof n.name === 'string' && n.name
50
+ ? n.name
51
+ : undefined;
52
+ return label ? `"${label}"` : '(unnamed entity)';
53
+ }
54
+ /**
55
+ * Manages GameComponent instances attached to entities (Object3Ds).
56
+ *
57
+ * Tracks instances per Object3D and per phase. Registers one tick function per
58
+ * phase via `ctx.systems.setComponentTick(phase, ...)` (T7.1 slice 2) — a
59
+ * dedicated slot, not a bare `add()`ed system. `SystemRunner.runPhase` always
60
+ * runs the componentTick slot after every engine-bucket system and before
61
+ * every game-bucket system in that phase, so component updates interleave
62
+ * correctly with engine systems BY STRUCTURE: an engine system `add()`ed
63
+ * after this manager is constructed still runs before its tick (see
64
+ * `test/system-runs-before-component-tick.test.ts`).
65
+ *
66
+ * Kind (T7.2 slice 2, D8 §3): a manager is constructed for exactly ONE
67
+ * `WorldKind` (`opts.kind`, default `'threejs'` — every existing call site
68
+ * omits it and gets the same manager slice 1 built). `attach()` enforces two
69
+ * rules against that kind, loudly:
70
+ * - a `'react'`-kind manager throws on EVERY attach (react entities host no
71
+ * GameComponents — render from game state via the T7.4 state bridge);
72
+ * - any other kind throws when the component's `static declaredKind` is set
73
+ * and doesn't match this manager's kind (`'any'` is exempt — a
74
+ * kind-agnostic component may attach wherever components are legal).
75
+ * A `'pixijs'`-kind manager wires `rigidBody`/`collider` from `opts.physics2d`
76
+ * (a `Physics2DRegistry`) instead of the 3D `physics: PhysicsRegistry`
77
+ * parameter — the field names match by design (`world2d/types.ts`), so this
78
+ * is a retype of the wiring, not a new shape. `physics` is optional (T7.3
79
+ * slice 2) — a `'pixijs'`-kind manager never reads it (`resolvePhysicsRefs`
80
+ * below only reaches the 3D branch for a non-pixijs manager), so a caller
81
+ * building one no longer has to construct a throwaway 3D `PhysicsRegistry`
82
+ * just to satisfy this signature.
83
+ */
84
+ export function createComponentManager(ctx, physics, opts) {
85
+ const kind = opts?.kind ?? 'threejs';
86
+ const physics2d = opts?.physics2d;
87
+ const byPhase = new Map();
88
+ const byEntity = new Map();
89
+ // --- HMR registry-keyed identity (T5.4) ----------------------------------
90
+ // `hotSwap` used to match live instances by `inst.constructor.name` — fragile
91
+ // under minification, a dev renaming a class, or two distinct classes that
92
+ // happen to share a runtime name. Both trees walked by `applyComponents`
93
+ // (`scene/component-registry.ts`) and `applyComponents2D`
94
+ // (`world2d/scene2d-loader.ts`) now pass the `componentRegistry` name the
95
+ // class was looked up under — plus the raw pre-`schema.parse` authored data —
96
+ // into `attach()`'s optional third argument, recorded here keyed by instance
97
+ // identity (a WeakMap: no explicit cleanup needed, entries die with the
98
+ // instance). An instance attached WITHOUT this info (an ad-hoc, code-attached
99
+ // component — `playground/main.ts`'s `ctx.components.attach(cube, new Cls())`,
100
+ // and this file's own `component-lifecycle.test.ts`) has no registry key on
101
+ // record; `hotSwap` falls back to the legacy `constructor.name` compare for
102
+ // those ONLY, preserving pre-T5.4 behavior for the ad-hoc path exactly (see
103
+ // `hotSwap` below).
104
+ const registryKeyOf = new WeakMap();
105
+ const authoredPropsOf = new WeakMap();
106
+ // --- Frame-boundary init flush (T1.11) -----------------------------------
107
+ // `pendingInit` holds every attached-but-not-yet-initialized instance. An
108
+ // instance is pushed into its phase's `byPhase` list immediately on attach
109
+ // (so getComponents()/hotSwap() see it right away), but the per-phase tick
110
+ // below FILTERS OUT anything still in `pendingInit` — so an instance can
111
+ // never receive update() before its init() has resolved, no matter how many
112
+ // frames init() takes (a real async load included).
113
+ //
114
+ // `initPromises` tracks in-flight init() calls (keyed by instance) so:
115
+ // (a) init() is called exactly once per instance, whether it was started
116
+ // by the automatic per-frame flush below or by an explicit
117
+ // `initAll()` call (they share the same `startInit` helper), and
118
+ // (b) `initAll()` can `await` an init() the automatic flush already
119
+ // kicked off, instead of double-invoking it.
120
+ //
121
+ // Semantics: init() is awaited (via a chained promise) before the instance
122
+ // is removed from `pendingInit`; only then is it eligible for update(). A
123
+ // throwing/rejecting init() is isolated the same way update()/dispose() are
124
+ // (T1.8) — logged loudly, never left to crash the frame loop or wedge the
125
+ // instance out of ticking forever (it's still removed from `pendingInit`
126
+ // after the error, matching "degrade loudly, don't hang").
127
+ const pendingInit = new Set();
128
+ const initPromises = new Map();
129
+ // --- Pending-init re-arm on hotSwap (§7.1-6, probe8) ---------------------
130
+ // `swapOneIfMatched` may land while an instance's init() is still in flight
131
+ // (`initPromises.has(inst)` — the OLD class's init hasn't settled yet). The
132
+ // live instance's prototype is swapped to the NEW class SYNCHRONOUSLY at
133
+ // swap time, but the in-flight promise chain still belongs to the OLD
134
+ // class's init call — its trailing `.then()` below is what clears
135
+ // `pendingInit`/`initPromises` once it settles, and nothing else re-triggers
136
+ // init() for the new class. `pendingReinit` records "a swap landed while
137
+ // this instance's init was in flight" so that SAME trailing `.then()` can,
138
+ // instead of clearing pendingInit, re-kick `startInit` for the (by-then
139
+ // already-swapped) instance — whose `.init` now resolves to the NEW class's
140
+ // method. `pendingInit` membership is deliberately left untouched across the
141
+ // whole handoff: the instance must stay ineligible for update() from the
142
+ // moment the OLD init started until the NEW init resolves, exactly as it
143
+ // was mid-old-init (T1.11's "never before init() resolves" invariant, now
144
+ // spanning a swap instead of being violated by one). A Set, not a Map to a
145
+ // specific class: by the time this fires, the CURRENT prototype (whichever
146
+ // class most recently swapped in) is what `inst.init` resolves to, so
147
+ // multiple swaps mid-flight collapse to exactly one re-kicked init for the
148
+ // LAST class — never a double-invoke, never a lost update.
149
+ const pendingReinit = new Set();
150
+ function startInit(inst) {
151
+ const existing = initPromises.get(inst);
152
+ if (existing)
153
+ return existing;
154
+ const p = Promise.resolve()
155
+ .then(() => inst.init?.(ctx))
156
+ .catch((err) => {
157
+ console.error(`[component-manager] ${inst.constructor.name}.init() threw:`, err);
158
+ })
159
+ .then(() => {
160
+ if (pendingReinit.has(inst)) {
161
+ // A hotSwap landed mid-init (probe8): don't clear pendingInit — the
162
+ // instance must stay un-ticked until the NEW class's init (kicked
163
+ // off below) resolves. Clear initPromises first so the re-kicked
164
+ // startInit doesn't see itself as "already in flight" and return
165
+ // this (already-settling) promise back out.
166
+ pendingReinit.delete(inst);
167
+ initPromises.delete(inst);
168
+ startInit(inst);
169
+ return;
170
+ }
171
+ pendingInit.delete(inst);
172
+ initPromises.delete(inst);
173
+ });
174
+ initPromises.set(inst, p);
175
+ return p;
176
+ }
177
+ /**
178
+ * Kick off init() for anything attached since the last flush that hasn't
179
+ * been started yet. Fire-and-forget (not awaited) — called at the start of
180
+ * every phase tick below, so a component attached mid-frame (e.g. from a
181
+ * trigger callback) gets its init() started as soon as possible without
182
+ * game code ever calling `initAll()` manually. Idempotent / cheap no-op
183
+ * when `pendingInit` is empty or everything in it is already in flight.
184
+ */
185
+ function flushPendingInitAuto() {
186
+ for (const inst of pendingInit)
187
+ startInit(inst);
188
+ }
189
+ // --- In-tick structural-change deferral state ---------------------------
190
+ // A component's update() may call attach()/detach() (a Unity-MonoBehaviour
191
+ // style spawn/despawn-from-update pattern). Mutating `byPhase` mid-iteration
192
+ // would (a) skip a sibling when a splice shifts indices, and (b) tick a fresh
193
+ // instance before its init() ran. So while a phase loop is running we DEFER
194
+ // structural changes and apply them only after the loop completes.
195
+ let isTicking = false;
196
+ // Entities whose detach was requested during the current tick — applied
197
+ // (dispose + removal) after the phase loop completes.
198
+ const pendingDetach = [];
199
+ // Components whose attach was requested during the current tick — applied
200
+ // after the phase loop completes, so they start ticking next frame (never
201
+ // before their init()).
202
+ const pendingAttach = [];
203
+ // Live set of instances detached this tick. The running phase loop iterates a
204
+ // snapshot, so this guard ensures an instance detached earlier in the frame is
205
+ // not update()'d again (use-after-dispose protection).
206
+ const detachedThisTick = new Set();
207
+ for (const phase of PHASE_ORDER) {
208
+ byPhase.set(phase, []);
209
+ }
210
+ function flushPending() {
211
+ // Detaches win within a flush: an attach and a detach of the same entity
212
+ // issued in one tick resolves to detached, regardless of issue order
213
+ // (NOT "resolves in the order the caller issued the two kinds of op" —
214
+ // that was never actually true; see probe7 "attach-detach" finding).
215
+ // Detaches are applied first (as before), and every entity they touch is
216
+ // collected into `detachedEntities` so a same-tick pending attach whose
217
+ // target is in that set can be skipped below rather than landing a
218
+ // component on an entity the caller already despawned this tick.
219
+ let detachedEntities = null;
220
+ if (pendingDetach.length > 0) {
221
+ const batch = pendingDetach.splice(0);
222
+ detachedEntities = new Set(batch);
223
+ for (const node of batch)
224
+ performDetach(node);
225
+ }
226
+ if (pendingAttach.length > 0) {
227
+ const batch = pendingAttach.splice(0);
228
+ for (const { node, instance, registry } of batch) {
229
+ if (detachedEntities?.has(node)) {
230
+ // The target entity was detached in this same flush: the attach
231
+ // never actually happened (it was never pushed into byPhase/
232
+ // byEntity), so there is nothing to detach/dispose here — just
233
+ // purge it from init tracking so it never gets init()'d.
234
+ pendingInit.delete(instance);
235
+ initPromises.delete(instance);
236
+ pendingReinit.delete(instance);
237
+ continue;
238
+ }
239
+ performAttach(node, instance, registry);
240
+ }
241
+ }
242
+ detachedThisTick.clear();
243
+ }
244
+ // Register the ONE component-tick function for each phase, via the
245
+ // dedicated slot (T7.1 slice 2) — NOT ctx.systems.add(). This is what
246
+ // makes "engine systems before component ticks" hold by structure: the
247
+ // slot always runs after the phase's entire engine bucket, regardless of
248
+ // when this manager was constructed relative to other systems.add() calls.
249
+ for (const phase of PHASE_ORDER) {
250
+ ctx.systems.setComponentTick(phase, (dt) => {
251
+ // Frame-boundary init flush (T1.11): every phase tick starts by kicking
252
+ // off init() for anything pending — no manual `initAll()` call required
253
+ // from game code. See `flushPendingInitAuto` above.
254
+ flushPendingInitAuto();
255
+ isTicking = true;
256
+ try {
257
+ // Snapshot the phase list: an in-loop attach must not be ticked this frame,
258
+ // and an in-loop detach (which only marks `detachedThisTick`) must not shift
259
+ // the indices we are iterating and skip a sibling.
260
+ const list = byPhase.get(phase).slice();
261
+ for (let i = 0; i < list.length; i++) {
262
+ const inst = list[i];
263
+ // A component detached earlier this frame must NOT be update()'d again.
264
+ if (detachedThisTick.has(inst))
265
+ continue;
266
+ // A component whose init() hasn't resolved yet must NOT be
267
+ // update()'d — this is the actual guarantee behind T1.11: never
268
+ // before init() resolves, regardless of how it got attached.
269
+ if (pendingInit.has(inst))
270
+ continue;
271
+ // Isolate per component: a throwing update() must not stop siblings
272
+ // in the same phase from ticking, and must not leave the manager
273
+ // wedged (isTicking stuck true, pending attach/detach never
274
+ // flushed). Failures are loud — logged with the component name —
275
+ // never swallowed silently.
276
+ try {
277
+ inst.update(dt, ctx);
278
+ }
279
+ catch (err) {
280
+ console.error(`[component-manager] ${inst.constructor.name}.update() threw:`, err);
281
+ }
282
+ }
283
+ }
284
+ finally {
285
+ // Guaranteed even if something above throws unexpectedly (e.g. a
286
+ // future edit removes the per-component try/catch): isTicking must
287
+ // never get stuck true, and structural changes queued during this
288
+ // tick must still flush before the next tick runs.
289
+ isTicking = false;
290
+ flushPending();
291
+ }
292
+ });
293
+ }
294
+ function migratePhase(inst, from, to) {
295
+ if (from === to)
296
+ return;
297
+ const oldList = byPhase.get(from);
298
+ const idx = oldList.indexOf(inst);
299
+ if (idx !== -1)
300
+ oldList.splice(idx, 1);
301
+ byPhase.get(to).push(inst);
302
+ }
303
+ /**
304
+ * `hotSwap`'s per-instance identity check + swap (T5.4) — split out of
305
+ * `hotSwap` itself purely to keep that function's cognitive complexity
306
+ * down; matching semantics are documented on `hotSwap` above. Returns
307
+ * whether `inst` matched `name` (and was therefore swapped).
308
+ */
309
+ function swapOneIfMatched(inst, name, NewClass) {
310
+ const trackedKey = registryKeyOf.get(inst);
311
+ const isMatch = trackedKey !== undefined ? trackedKey === name : inst.constructor.name === name;
312
+ if (!isMatch)
313
+ return false;
314
+ const oldPhase = inst.constructor.phase ?? 'gameLogic';
315
+ const newPhase = NewClass.phase ?? 'gameLogic';
316
+ Object.setPrototypeOf(inst, NewClass.prototype);
317
+ migratePhase(inst, oldPhase, newPhase);
318
+ reparseSchemaOnSwap(inst, NewClass, name);
319
+ // §7.1-6 / probe8: if this instance's init() is still in flight (attached,
320
+ // startInit already called, promise not yet settled), record that a swap
321
+ // landed mid-init so `startInit`'s trailing `.then()` re-kicks a fresh
322
+ // init() for the NEW class once the OLD one settles, instead of silently
323
+ // clearing `pendingInit` and leaving the new init never invoked. An
324
+ // instance that is merely QUEUED (attached, `startInit` not yet called —
325
+ // `pendingInit.has(inst)` but no `initPromises` entry) needs no help here:
326
+ // its eventual first `startInit` call naturally reads the (already
327
+ // swapped) NEW prototype's `init`. An instance whose init already fully
328
+ // resolved (no `initPromises` entry, `pendingInit` doesn't have it either)
329
+ // is intentionally left alone — a swap is a live-patch, not a remount.
330
+ if (initPromises.has(inst)) {
331
+ pendingReinit.add(inst);
332
+ }
333
+ return true;
334
+ }
335
+ /**
336
+ * Schema re-parse on swap (T5.4, docs/BACKBONE-TASKS.md's T5.4 detail note).
337
+ * `inst` just had its prototype swapped to `NewClass`; if `NewClass` declares
338
+ * a `static schema` AND `inst` was attached with recorded authored props
339
+ * (registry-keyed instances only — ad-hoc instances have none and are
340
+ * skipped, nothing to validate), re-validate those props against the NEW
341
+ * schema:
342
+ * - success: `next = schema.parse(authoredData)`. Merge ONLY fields
343
+ * `next` has that `inst` does NOT already own — i.e. fields the NEW
344
+ * schema added (which get their schema default/authored value) — the
345
+ * merge never touches a field already present on `inst`, so mutated
346
+ * runtime/gameplay state always wins over a re-derived authored value.
347
+ * Authored-VALUE edits (the user changing a field in the inspector)
348
+ * flow through the normal scene-edit path, never through this merge.
349
+ * - failure (old authored data no longer valid against the new schema,
350
+ * e.g. a field's type changed or a new field has no default): loud
351
+ * swap-miss warning, `inst`'s fields are left exactly as they were
352
+ * (last-good props) — never partially or invalidly overwritten.
353
+ */
354
+ function reparseSchemaOnSwap(inst, NewClass, key) {
355
+ const schema = NewClass.schema;
356
+ if (!schema)
357
+ return;
358
+ const authored = authoredPropsOf.get(inst);
359
+ if (authored === undefined)
360
+ return;
361
+ const result = schema.safeParse(authored);
362
+ if (!result.success) {
363
+ logHmrSwapMiss({ key, reason: 'schema-reparse-failed', error: result.error.message });
364
+ return;
365
+ }
366
+ const next = result.data;
367
+ const target = inst;
368
+ for (const [field, value] of Object.entries(next)) {
369
+ if (!Object.hasOwn(target, field)) {
370
+ target[field] = value;
371
+ }
372
+ }
373
+ }
374
+ /**
375
+ * Enforce the attach rules (T7.2 slice 2, D8 §3) BEFORE any structural
376
+ * change happens — called synchronously from the public `attach()`, ahead
377
+ * of the isTicking defer, so the throw always surfaces to the caller of
378
+ * `attach()` and never fires later out of a deferred `flushPending()` (mid
379
+ * -tick attaches are validated up front, at the moment they're requested).
380
+ */
381
+ function validateAttach(node, instance) {
382
+ const ComponentClass = instance.constructor;
383
+ const declaredKind = ComponentClass.declaredKind ?? 'threejs';
384
+ const label = describeNode(node);
385
+ if (kind === 'react') {
386
+ throw new Error(`${ComponentClass.name}: cannot attach to entity ${label} — this manager's world is a ` +
387
+ "'react' world, and react entities host no GameComponents; render from game state " +
388
+ 'via the T7.4 state bridge instead.');
389
+ }
390
+ if (declaredKind !== 'any' && declaredKind !== kind) {
391
+ throw new Error(`${ComponentClass.name}: declared kind '${declaredKind}' does not match entity ` +
392
+ `${label}'s world kind '${kind}' — set \`static declaredKind\` on ${ComponentClass.name} ` +
393
+ "if it is meant to attach in a non-default-kind world (or declare 'any' for a " +
394
+ 'kind-agnostic component).');
395
+ }
396
+ }
397
+ /** Resolve rigidBody/collider refs for `node` from this manager's kind-appropriate
398
+ * registry: `Physics2DRegistry` for a 'pixijs' manager, `PhysicsRegistry` otherwise
399
+ * (`physics` is only optional for a 'pixijs' manager, which never reaches this
400
+ * branch — every real threejs call site still passes it). */
401
+ function resolvePhysicsRefs(node) {
402
+ if (kind === 'pixijs') {
403
+ return physics2d?.get(node);
404
+ }
405
+ return physics?.get(node);
406
+ }
407
+ function performAttach(node, instance, registry) {
408
+ instance.node = node;
409
+ instance.world = resolveWorldInstance(ctx);
410
+ const refs = resolvePhysicsRefs(node);
411
+ instance.rigidBody = refs?.body ?? null;
412
+ instance.collider = refs?.collider ?? null;
413
+ if (registry) {
414
+ registryKeyOf.set(instance, registry.key);
415
+ authoredPropsOf.set(instance, registry.props);
416
+ }
417
+ const phase = instance.constructor.phase ?? 'gameLogic';
418
+ byPhase.get(phase).push(instance);
419
+ let entityList = byEntity.get(node);
420
+ if (!entityList) {
421
+ entityList = [];
422
+ byEntity.set(node, entityList);
423
+ }
424
+ entityList.push(instance);
425
+ pendingInit.add(instance);
426
+ }
427
+ function performDetach(node) {
428
+ const instances = byEntity.get(node);
429
+ if (!instances)
430
+ return;
431
+ for (const inst of instances) {
432
+ // Isolate dispose() the same way as update(): one component's dispose
433
+ // throwing must not stop the rest of this entity's components (or the
434
+ // rest of a pending-detach batch) from being cleaned up and removed.
435
+ try {
436
+ inst.dispose?.(ctx);
437
+ }
438
+ catch (err) {
439
+ console.error(`[component-manager] ${inst.constructor.name}.dispose() threw:`, err);
440
+ }
441
+ const phase = inst.constructor.phase ?? 'gameLogic';
442
+ const phaseList = byPhase.get(phase);
443
+ const idx = phaseList.indexOf(inst);
444
+ if (idx !== -1)
445
+ phaseList.splice(idx, 1);
446
+ // Also drop it from the pending-init tracking so a not-yet-flushed
447
+ // init() never (re)starts on an already-disposed component (keeps
448
+ // detach symmetric with clear()). The in-flight promise, if any, is
449
+ // simply abandoned — its `.then()` continuation is now a no-op since
450
+ // both maps no longer reference this instance. `pendingReinit` too —
451
+ // a swap recorded mid-init on an instance now being detached must not
452
+ // re-kick an init() for a component that no longer exists.
453
+ pendingInit.delete(inst);
454
+ initPromises.delete(inst);
455
+ pendingReinit.delete(inst);
456
+ }
457
+ byEntity.delete(node);
458
+ }
459
+ return {
460
+ /** Attach a component instance to an entity node (Object3D in a threejs
461
+ * world, PIXI.Container in a pixijs world). Validates the attach rules
462
+ * (§3: react-world throw, kind-mismatch throw) synchronously before any
463
+ * structural change, whether or not a phase tick is currently running.
464
+ * `registry` (T5.4, optional) records the `componentRegistry` name +
465
+ * pre-`schema.parse` authored data a scene-authored attach looked the
466
+ * class up under — `hotSwap` keys on it instead of the live
467
+ * `constructor.name`. Omit it for an ad-hoc, code-attached instance (no
468
+ * registry entry) — `hotSwap` falls back to matching those by class name,
469
+ * unchanged from pre-T5.4 behavior. */
470
+ attach(node, instance, registry) {
471
+ validateAttach(node, instance);
472
+ // Called from inside a phase loop (e.g. a spawn-from-update): defer so the
473
+ // new instance starts ticking next frame, after a subsequent initAll().
474
+ if (isTicking) {
475
+ pendingAttach.push({ node, instance, ...(registry ? { registry } : {}) });
476
+ return;
477
+ }
478
+ performAttach(node, instance, registry);
479
+ },
480
+ /**
481
+ * Call init() on all components that haven't been initialized yet, and
482
+ * wait for them to resolve. Components attached since the last call are
483
+ * covered. Safe to call even when the automatic per-frame flush has
484
+ * already started some of them — `startInit` is idempotent per instance,
485
+ * so this awaits the same in-flight promise rather than double-invoking
486
+ * init(). Manual calls remain useful when subsequent code depends on an
487
+ * init()'s side effects having completed synchronously (the automatic
488
+ * flush only guarantees "ticking starts once init resolves", not
489
+ * "resolved by the time this function returns").
490
+ */
491
+ async initAll() {
492
+ const batch = [...pendingInit];
493
+ await Promise.all(batch.map(startInit));
494
+ },
495
+ /** Remove all components from an entity node, calling dispose. */
496
+ detach(node) {
497
+ // Called from inside a phase loop (e.g. a despawn-from-update): mark the
498
+ // entity's instances so the running loop skips them, and defer the actual
499
+ // dispose + removal until the loop completes.
500
+ if (isTicking) {
501
+ const instances = byEntity.get(node);
502
+ if (!instances)
503
+ return;
504
+ for (const inst of instances)
505
+ detachedThisTick.add(inst);
506
+ pendingDetach.push(node);
507
+ return;
508
+ }
509
+ performDetach(node);
510
+ },
511
+ /**
512
+ * Backfill `instance.world` for every already-attached instance whose
513
+ * world is still undefined (T7.2 slice 2 — closes the KNOWN GAP
514
+ * documented on `resolveWorldInstance` above). A ONE-TIME wiring
515
+ * completion, called exactly once by `registerThreeWorld`
516
+ * (`create-runtime.ts`) right after this manager's `WorldInstance` is
517
+ * constructed — NOT a lazy getter, NOT a per-frame sync: a plain
518
+ * backfill pass over the existing `byEntity` bookkeeping, with no
519
+ * ongoing cost once it returns. Idempotent and safe to call more than
520
+ * once (only ever touches instances still missing a world).
521
+ */
522
+ adoptWorld(world) {
523
+ for (const [, instances] of byEntity) {
524
+ for (const inst of instances) {
525
+ if (inst.world === undefined)
526
+ inst.world = world;
527
+ }
528
+ }
529
+ },
530
+ /** Get all component instances for an entity node. */
531
+ getComponents(node) {
532
+ return byEntity.get(node) ?? [];
533
+ },
534
+ /**
535
+ * Query all live attached instances of a given component class within
536
+ * THIS manager — the per-world half of the §5 cross-world query
537
+ * (`docs/GAME-ROOT-DESIGN.md` §5; `Game.queryByComponent` in
538
+ * `runtime/game.ts` is the game-level aggregation over every world's
539
+ * manager).
540
+ *
541
+ * Returns instances (not nodes), `instanceof cls`, in stable attach
542
+ * order — walked from the existing `byEntity` bookkeeping (the same
543
+ * structure `hotSwap`/`clear` iterate), not a new index, so correctness
544
+ * tracks the manager's real attach/detach state rather than a
545
+ * maintained-in-parallel cache. Order note: this is attach order
546
+ * PER ENTITY (the order components were pushed for that Object3D),
547
+ * concatenated in `byEntity`'s insertion order (first-attach order of
548
+ * the entities themselves) — for the common case of each entity
549
+ * attached once this coincides with global chronological attach order;
550
+ * it would not for an entity re-attached to after other entities were
551
+ * attached in between, which this manager does not otherwise track a
552
+ * global order for.
553
+ *
554
+ * Excludes instances pending-detach this tick (`detachedThisTick`) —
555
+ * mirrors the same use-after-dispose guard the phase tick applies, so a
556
+ * query run mid-tick (e.g. from inside a component's `update`) never
557
+ * returns something already torn down this frame.
558
+ */
559
+ queryByComponent(cls) {
560
+ const result = [];
561
+ for (const [, instances] of byEntity) {
562
+ for (const inst of instances) {
563
+ if (detachedThisTick.has(inst))
564
+ continue;
565
+ if (inst instanceof cls)
566
+ result.push(inst);
567
+ }
568
+ }
569
+ return result;
570
+ },
571
+ /**
572
+ * Hot-swap prototypes for every live instance registered under `name`
573
+ * (T5.4). State on `this` survives; method bodies update to the new
574
+ * class. `name` is matched against each instance's RECORDED registry key
575
+ * (`registryKeyOf`, set by `attach()`'s optional `registry` argument) —
576
+ * not the live `constructor.name`, which is fragile under minification, a
577
+ * class rename, or two distinct classes sharing one runtime name (a
578
+ * registry key is stable identity chosen at scene-author time,
579
+ * independent of what the class calls itself). An instance attached
580
+ * WITHOUT a registry key (ad-hoc/code-attached — no `ComponentRegistry`
581
+ * entry) has no such recorded identity, so it falls back to the legacy
582
+ * `constructor.name` compare — this is the ONLY place that fallback
583
+ * applies; a registry-keyed instance never matches by name, so two
584
+ * registry-keyed classes that happen to share a `constructor.name` (e.g.
585
+ * both minified to the same short name) swap independently.
586
+ *
587
+ * Zero matches is a loud swap-miss (`hmr-swap-report.ts`), never a silent
588
+ * no-op — this is "renamed class → loud miss" (docs/BACKBONE-TASKS.md's
589
+ * T5.4 detail note): if a dev renames a component's export, the hot
590
+ * update arrives keyed under the NEW name, no live instance is recorded
591
+ * under it yet (the registry/scene JSON hasn't been re-authored), so
592
+ * nothing matches and the warning fires — the OLD class stays in effect
593
+ * rather than the rename silently doing nothing.
594
+ *
595
+ * GameComponent-subclass guard (§7.1-5, probe7): every editor HMR call
596
+ * site passes any `typeof value === 'function'` module export — that used
597
+ * to include a plain helper function sharing a live component's registry
598
+ * key/name, which this method would happily `Object.setPrototypeOf` onto
599
+ * a live instance, leaving it with no `update()` (a caught-and-logged
600
+ * `TypeError` every frame, forever). `NewClass` is now required to have
601
+ * `GameComponent` somewhere in its prototype chain — anything else is
602
+ * refused OUTRIGHT, loudly, with NO instance touched. This is a second,
603
+ * independent line of defense behind the call-site filter
604
+ * (`play-mode.ts`'s HMR handlers now filter to `value.prototype
605
+ * instanceof GameComponent` before ever calling this) — belt AND
606
+ * suspenders, so a future caller that forgets to filter still can't
607
+ * corrupt a live instance.
608
+ *
609
+ * `opts.warnOnMiss` (default `true`, §7.1-4/probe2b): the multi-world HMR
610
+ * fan-out (`play-mode.ts`'s `hotSwapAcrossWorlds`) calls this once per
611
+ * first-party world and must not let a per-world zero-match here look
612
+ * like "renamed class" when the name simply lives in a DIFFERENT world's
613
+ * manager — the fan-out helper suppresses this method's own warning
614
+ * (`{ warnOnMiss: false }`) and emits the ONE real warning itself only
615
+ * when the total across every world is zero. Every other existing caller
616
+ * (`applyBrowserComponentEdit`, the dev HMR demos, every hotSwap unit
617
+ * test) omits `opts` and keeps today's per-call warn-on-miss behavior
618
+ * unchanged. Returns the number of live instances swapped, so a caller
619
+ * that needs to aggregate across several managers (the fan-out helper)
620
+ * can sum it without re-deriving it from a side-channel.
621
+ */
622
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: the GameComponent-subclass guard (§7.1-5) and the warnOnMiss option are both load-bearing early-exit branches ahead of the existing match loop — splitting them into separate helpers would obscure that hotSwap has exactly one guarded entry point
623
+ hotSwap(name, NewClass, opts) {
624
+ if (typeof NewClass !== 'function' || !(NewClass.prototype instanceof GameComponent)) {
625
+ // biome-ignore lint/suspicious/noConsole: structured, greppable — mirrors logHmrSwapMiss's own deliberate direct console.warn
626
+ console.warn(`[component-manager] hotSwap("${name}"): refused — ` +
627
+ `"${NewClass?.name ?? String(NewClass)}" does not ` +
628
+ 'extend GameComponent (no GameComponent in its prototype chain), so no live instance ' +
629
+ 'was touched. This guards against a plain function/class export sharing a registry ' +
630
+ 'key/name with a real component (§7.1-5, T5.4).');
631
+ return 0;
632
+ }
633
+ let matched = 0;
634
+ for (const [, instances] of byEntity) {
635
+ for (const inst of instances) {
636
+ if (swapOneIfMatched(inst, name, NewClass))
637
+ matched++;
638
+ }
639
+ }
640
+ const warnOnMiss = opts?.warnOnMiss ?? true;
641
+ if (matched === 0 && warnOnMiss) {
642
+ logHmrSwapMiss({ key: name, reason: 'no-live-instance' });
643
+ }
644
+ return matched;
645
+ },
646
+ /** Dispose all components and clear all maps. */
647
+ clear() {
648
+ // Isolate dispose() exactly like performDetach: one throwing dispose
649
+ // must not abort the rest of teardown (the remaining instances still
650
+ // get dispose()'d, and the maps/state below still get reset). A
651
+ // teardown path that aborts partway through is unrecoverable (a retry
652
+ // is a no-op since byEntity etc. are never cleared) — see the probe5
653
+ // "dispose-abort" finding this closes.
654
+ for (const [, instances] of byEntity) {
655
+ for (const inst of instances) {
656
+ try {
657
+ inst.dispose?.(ctx);
658
+ }
659
+ catch (err) {
660
+ console.error(`[component-manager] ${inst.constructor.name}.dispose() threw:`, err);
661
+ }
662
+ }
663
+ }
664
+ byEntity.clear();
665
+ for (const phase of PHASE_ORDER) {
666
+ byPhase.set(phase, []);
667
+ }
668
+ pendingInit.clear();
669
+ initPromises.clear();
670
+ pendingReinit.clear();
671
+ pendingAttach.length = 0;
672
+ pendingDetach.length = 0;
673
+ detachedThisTick.clear();
674
+ },
675
+ };
676
+ }