@vgai/engine 0.5.21 → 0.5.23

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 (339) hide show
  1. package/README.md +6 -3
  2. package/dist/adapter/adapter-module.d.ts.map +1 -1
  3. package/dist/adapter/adapter-module.js +2 -4
  4. package/dist/adapter/adapter-surface.d.ts +1 -1
  5. package/dist/adapter/adapter-surface.js +1 -1
  6. package/dist/adapter/authoring.d.ts +19 -21
  7. package/dist/adapter/authoring.d.ts.map +1 -1
  8. package/dist/adapter/authoring.js +2 -2
  9. package/dist/adapter/binding.d.ts +341 -0
  10. package/dist/adapter/binding.d.ts.map +1 -0
  11. package/dist/adapter/binding.js +148 -0
  12. package/dist/adapter/colyseus-networking-adapter.d.ts.map +1 -1
  13. package/dist/adapter/colyseus-networking-adapter.js +23 -4
  14. package/dist/adapter/entrypoint-selection-readers.d.ts +24 -0
  15. package/dist/adapter/entrypoint-selection-readers.d.ts.map +1 -0
  16. package/dist/adapter/entrypoint-selection-readers.js +63 -0
  17. package/dist/adapter/entrypoint-selection-source.d.ts.map +1 -1
  18. package/dist/adapter/entrypoint-selection-source.js +1 -44
  19. package/dist/adapter/finders/scenes-from-entrypoint-selection.d.ts.map +1 -1
  20. package/dist/adapter/finders/scenes-from-entrypoint-selection.js +1 -52
  21. package/dist/adapter/host-context.d.ts +46 -15
  22. package/dist/adapter/host-context.d.ts.map +1 -1
  23. package/dist/adapter/host-context.js +2 -9
  24. package/dist/adapter/index.d.ts +11 -12
  25. package/dist/adapter/index.d.ts.map +1 -1
  26. package/dist/adapter/index.js +9 -10
  27. package/dist/adapter/ingest/game-contract.d.ts +0 -3
  28. package/dist/adapter/ingest/game-contract.d.ts.map +1 -1
  29. package/dist/adapter/ingest/game-contract.js +0 -3
  30. package/dist/adapter/ingest/scene-capture.d.ts +19 -23
  31. package/dist/adapter/ingest/scene-capture.d.ts.map +1 -1
  32. package/dist/adapter/ingest/scene-capture.js +143 -17
  33. package/dist/adapter/ingest/visible-capture-window.d.ts +34 -0
  34. package/dist/adapter/ingest/visible-capture-window.d.ts.map +1 -1
  35. package/dist/adapter/manifest-interpreter.d.ts +59 -0
  36. package/dist/adapter/manifest-interpreter.d.ts.map +1 -0
  37. package/dist/adapter/manifest-interpreter.js +50 -0
  38. package/dist/adapter/native-debug-module.d.ts +71 -3
  39. package/dist/adapter/native-debug-module.d.ts.map +1 -1
  40. package/dist/adapter/native-debug-module.js +146 -10
  41. package/dist/adapter/rapier-physics-adapter.d.ts +31 -1
  42. package/dist/adapter/rapier-physics-adapter.d.ts.map +1 -1
  43. package/dist/adapter/rapier-physics-adapter.js +50 -36
  44. package/dist/adapter/renderer-config.d.ts +3 -3
  45. package/dist/adapter/renderer-config.js +3 -3
  46. package/dist/adapter/root-adapter.d.ts +7 -7
  47. package/dist/adapter/root-adapter.js +4 -4
  48. package/dist/adapter/system-adapter.d.ts +45 -7
  49. package/dist/adapter/system-adapter.d.ts.map +1 -1
  50. package/dist/adapter/system-seam-contract.d.ts +3 -3
  51. package/dist/adapter/system-seam-contract.js +3 -3
  52. package/dist/adapter/system-slot.d.ts +168 -0
  53. package/dist/adapter/system-slot.d.ts.map +1 -0
  54. package/dist/adapter/system-slot.js +229 -0
  55. package/dist/adapter/transform.d.ts +11 -1
  56. package/dist/adapter/transform.d.ts.map +1 -1
  57. package/dist/ai/navigation.d.ts +17 -1
  58. package/dist/ai/navigation.d.ts.map +1 -1
  59. package/dist/ai/navigation.js +26 -5
  60. package/dist/animation/anim-graph-types.d.ts +11 -3
  61. package/dist/animation/anim-graph-types.d.ts.map +1 -1
  62. package/dist/animation/theatre-clock-binding.d.ts +4 -4
  63. package/dist/animation/theatre-clock-binding.js +4 -4
  64. package/dist/animation/xstate-animation-binding.d.ts.map +1 -1
  65. package/dist/animation/xstate-animation-binding.js +2 -2
  66. package/dist/animation/xstate-animation-meta.d.ts +13 -0
  67. package/dist/animation/xstate-animation-meta.d.ts.map +1 -1
  68. package/dist/animation/xstate-animation-meta.js +14 -0
  69. package/dist/asset-formats/index.d.ts +4 -7
  70. package/dist/asset-formats/index.d.ts.map +1 -1
  71. package/dist/asset-formats/index.js +4 -7
  72. package/dist/asset-formats/render-env.d.ts +5 -8
  73. package/dist/asset-formats/render-env.d.ts.map +1 -1
  74. package/dist/asset-formats/render-env.js +3 -6
  75. package/dist/asset-parse-error.d.ts +2 -5
  76. package/dist/asset-parse-error.d.ts.map +1 -1
  77. package/dist/asset-parse-error.js +2 -5
  78. package/dist/audio/bus-mixer.d.ts +101 -0
  79. package/dist/audio/bus-mixer.d.ts.map +1 -0
  80. package/dist/audio/bus-mixer.js +115 -0
  81. package/dist/canvas-react/index.d.ts +5 -12
  82. package/dist/canvas-react/index.d.ts.map +1 -1
  83. package/dist/canvas-react/index.js +5 -12
  84. package/dist/canvas-react/pixi-react-root-factory.d.ts +34 -21
  85. package/dist/canvas-react/pixi-react-root-factory.d.ts.map +1 -1
  86. package/dist/canvas-react/pixi-react-root-factory.js +274 -36
  87. package/dist/core/countdown-timer.d.ts +118 -0
  88. package/dist/core/countdown-timer.d.ts.map +1 -0
  89. package/dist/core/countdown-timer.js +137 -0
  90. package/dist/core/deferred-commands.d.ts +127 -0
  91. package/dist/core/deferred-commands.d.ts.map +1 -0
  92. package/dist/core/deferred-commands.js +132 -0
  93. package/dist/core/frame-pacing.d.ts +1 -1
  94. package/dist/core/frame-pacing.js +2 -2
  95. package/dist/core/game-loop.d.ts +1 -3
  96. package/dist/core/game-loop.d.ts.map +1 -1
  97. package/dist/core/game-loop.js +1 -3
  98. package/dist/core/seeded-random.d.ts +1 -1
  99. package/dist/core/sim-clock.d.ts +19 -8
  100. package/dist/core/sim-clock.d.ts.map +1 -1
  101. package/dist/core/sim-clock.js +18 -7
  102. package/dist/core/types.d.ts +1 -3
  103. package/dist/core/types.d.ts.map +1 -1
  104. package/dist/defaults.d.ts +6 -14
  105. package/dist/defaults.d.ts.map +1 -1
  106. package/dist/defaults.js +6 -14
  107. package/dist/dev/instruments.d.ts +38 -11
  108. package/dist/dev/instruments.d.ts.map +1 -1
  109. package/dist/dev/instruments.js +81 -11
  110. package/dist/dev/register-render-vitals.d.ts +1 -4
  111. package/dist/dev/register-render-vitals.d.ts.map +1 -1
  112. package/dist/dev/register-render-vitals.js +1 -4
  113. package/dist/dev/render-debug-adapter.d.ts +2 -3
  114. package/dist/dev/render-debug-adapter.d.ts.map +1 -1
  115. package/dist/dev/render-debug-adapter.js +2 -3
  116. package/dist/dev/render-vitals.d.ts +3 -3
  117. package/dist/dev/render-vitals.js +3 -3
  118. package/dist/dev/webgl-frame-capture.d.ts +1 -1
  119. package/dist/dev/webgl-frame-capture.js +1 -1
  120. package/dist/index.d.ts +2 -5
  121. package/dist/index.d.ts.map +1 -1
  122. package/dist/index.js +2 -4
  123. package/dist/input/host-pointer.d.ts +122 -0
  124. package/dist/input/host-pointer.d.ts.map +1 -0
  125. package/dist/input/host-pointer.js +160 -0
  126. package/dist/input/input-manager.d.ts +33 -5
  127. package/dist/input/input-manager.d.ts.map +1 -1
  128. package/dist/input/input-manager.js +48 -13
  129. package/dist/input/rebind-controller.d.ts.map +1 -1
  130. package/dist/input/rebind-controller.js +6 -8
  131. package/dist/input/schema.d.ts.map +1 -1
  132. package/dist/input/schema.js +56 -28
  133. package/dist/manifest/filename.d.ts.map +1 -1
  134. package/dist/manifest/filename.js +8 -12
  135. package/dist/manifest/load.d.ts +10 -10
  136. package/dist/manifest/load.d.ts.map +1 -1
  137. package/dist/manifest/load.js +9 -6
  138. package/dist/manifest/schema.d.ts +17 -21
  139. package/dist/manifest/schema.d.ts.map +1 -1
  140. package/dist/manifest/schema.js +45 -35
  141. package/dist/physics/collider-dimensions.d.ts +8 -12
  142. package/dist/physics/collider-dimensions.d.ts.map +1 -1
  143. package/dist/physics/collider-dimensions.js +8 -12
  144. package/dist/pixi/scene-capture.d.ts +11 -13
  145. package/dist/pixi/scene-capture.d.ts.map +1 -1
  146. package/dist/react/world-state.d.ts +1 -1
  147. package/dist/react/world-state.d.ts.map +1 -1
  148. package/dist/render/directional-shadow-fit.d.ts +88 -0
  149. package/dist/render/directional-shadow-fit.d.ts.map +1 -0
  150. package/dist/render/directional-shadow-fit.js +133 -0
  151. package/dist/render/environment-capture.d.ts +68 -0
  152. package/dist/render/environment-capture.d.ts.map +1 -0
  153. package/dist/render/environment-capture.js +90 -0
  154. package/dist/render/ibl-override-material.d.ts +97 -0
  155. package/dist/render/ibl-override-material.d.ts.map +1 -0
  156. package/dist/render/ibl-override-material.js +114 -0
  157. package/dist/render/light-camera-factory.d.ts +5 -7
  158. package/dist/render/light-camera-factory.d.ts.map +1 -1
  159. package/dist/render/light-camera-factory.js +8 -11
  160. package/dist/render/material-factory.js +1 -1
  161. package/dist/render/render-batch-system.d.ts.map +1 -1
  162. package/dist/render/render-features.d.ts +17 -6
  163. package/dist/render/render-features.d.ts.map +1 -1
  164. package/dist/render/render-features.js +0 -28
  165. package/dist/runtime/create-runtime.d.ts +34 -25
  166. package/dist/runtime/create-runtime.d.ts.map +1 -1
  167. package/dist/runtime/create-runtime.js +218 -93
  168. package/dist/runtime/debug-registry.d.ts +77 -8
  169. package/dist/runtime/debug-registry.d.ts.map +1 -1
  170. package/dist/runtime/debug-registry.js +3 -3
  171. package/dist/runtime/dev-build.d.ts +2 -2
  172. package/dist/runtime/dev-build.js +2 -2
  173. package/dist/runtime/game-input-seams.d.ts +51 -0
  174. package/dist/runtime/game-input-seams.d.ts.map +1 -0
  175. package/dist/runtime/game-input-seams.js +86 -0
  176. package/dist/runtime/game.d.ts +104 -40
  177. package/dist/runtime/game.d.ts.map +1 -1
  178. package/dist/runtime/game.js +119 -61
  179. package/dist/runtime/mount-game.d.ts +0 -16
  180. package/dist/runtime/mount-game.d.ts.map +1 -1
  181. package/dist/runtime/mount-game.js +26 -41
  182. package/dist/runtime/mount-manifest.d.ts +22 -14
  183. package/dist/runtime/mount-manifest.d.ts.map +1 -1
  184. package/dist/runtime/mount-manifest.js +22 -20
  185. package/dist/runtime/playtest.d.ts +22 -0
  186. package/dist/runtime/playtest.d.ts.map +1 -0
  187. package/dist/runtime/playtest.js +12 -0
  188. package/dist/runtime/state-bridge.d.ts +2 -3
  189. package/dist/runtime/state-bridge.d.ts.map +1 -1
  190. package/dist/runtime/state-bridge.js +1 -0
  191. package/dist/setup/setup-audio.d.ts +12 -0
  192. package/dist/setup/setup-audio.d.ts.map +1 -1
  193. package/dist/setup/setup-audio.js +9 -10
  194. package/dist/setup/setup-renderer.d.ts +2 -25
  195. package/dist/setup/setup-renderer.d.ts.map +1 -1
  196. package/dist/setup/setup-renderer.js +2 -31
  197. package/dist/world3d-react/index.d.ts +15 -25
  198. package/dist/world3d-react/index.d.ts.map +1 -1
  199. package/dist/world3d-react/index.js +15 -25
  200. package/dist/world3d-react/r3f-root-factory.d.ts +28 -34
  201. package/dist/world3d-react/r3f-root-factory.d.ts.map +1 -1
  202. package/dist/world3d-react/r3f-root-factory.js +403 -57
  203. package/dist/world3d-react/rapier-physics-bridge.d.ts +30 -17
  204. package/dist/world3d-react/rapier-physics-bridge.d.ts.map +1 -1
  205. package/dist/world3d-react/rapier-physics-bridge.js +143 -58
  206. package/package.json +1 -1
  207. package/schemas/engine-capabilities.json +16 -14
  208. package/schemas/vgai-project.schema.json +35 -26
  209. package/src/adapter/adapter-module.ts +2 -4
  210. package/src/adapter/adapter-surface.ts +1 -1
  211. package/src/adapter/authoring.ts +19 -21
  212. package/src/adapter/binding.ts +468 -0
  213. package/src/adapter/colyseus-networking-adapter.ts +20 -5
  214. package/src/adapter/entrypoint-selection-readers.ts +66 -0
  215. package/src/adapter/entrypoint-selection-source.ts +1 -40
  216. package/src/adapter/finders/scenes-from-entrypoint-selection.ts +1 -48
  217. package/src/adapter/host-context.ts +45 -15
  218. package/src/adapter/index.ts +23 -11
  219. package/src/adapter/ingest/game-contract.ts +0 -3
  220. package/src/adapter/ingest/scene-capture.ts +190 -39
  221. package/src/adapter/ingest/visible-capture-window.ts +35 -0
  222. package/src/adapter/manifest-interpreter.ts +64 -0
  223. package/src/adapter/native-debug-module.ts +248 -15
  224. package/src/adapter/rapier-physics-adapter.ts +76 -20
  225. package/src/adapter/renderer-config.ts +3 -3
  226. package/src/adapter/root-adapter.ts +7 -7
  227. package/src/adapter/system-adapter.ts +43 -8
  228. package/src/adapter/system-seam-contract.ts +3 -3
  229. package/src/adapter/system-slot.ts +291 -0
  230. package/src/adapter/transform.ts +18 -1
  231. package/src/ai/navigation.ts +30 -3
  232. package/src/animation/anim-graph-types.ts +11 -3
  233. package/src/animation/theatre-clock-binding.ts +4 -4
  234. package/src/animation/xstate-animation-binding.ts +2 -2
  235. package/src/animation/xstate-animation-meta.ts +16 -0
  236. package/src/asset-formats/index.ts +4 -7
  237. package/src/asset-formats/render-env.ts +3 -6
  238. package/src/asset-parse-error.ts +2 -5
  239. package/src/audio/bus-mixer.ts +161 -0
  240. package/src/canvas-react/index.ts +5 -21
  241. package/src/canvas-react/pixi-react-root-factory.tsx +301 -39
  242. package/src/core/countdown-timer.ts +188 -0
  243. package/src/core/deferred-commands.ts +174 -0
  244. package/src/core/frame-pacing.ts +2 -2
  245. package/src/core/game-loop.ts +1 -3
  246. package/src/core/seeded-random.ts +1 -1
  247. package/src/core/sim-clock.ts +19 -8
  248. package/src/core/types.ts +1 -3
  249. package/src/defaults.ts +6 -14
  250. package/src/dev/instruments.ts +108 -11
  251. package/src/dev/register-render-vitals.ts +1 -4
  252. package/src/dev/render-debug-adapter.ts +2 -3
  253. package/src/dev/render-vitals.ts +3 -3
  254. package/src/dev/webgl-frame-capture.ts +1 -1
  255. package/src/index.ts +2 -5
  256. package/src/input/host-pointer.ts +230 -0
  257. package/src/input/input-manager.ts +49 -13
  258. package/src/input/input-types.ts +1 -1
  259. package/src/input/rebind-controller.ts +6 -8
  260. package/src/input/schema.ts +216 -188
  261. package/src/manifest/filename.ts +8 -12
  262. package/src/manifest/load.ts +17 -13
  263. package/src/manifest/schema.ts +55 -47
  264. package/src/physics/collider-dimensions.ts +8 -12
  265. package/src/pixi/scene-capture.ts +12 -15
  266. package/src/react/world-state.tsx +1 -1
  267. package/src/render/directional-shadow-fit.ts +156 -0
  268. package/src/render/environment-capture.ts +102 -0
  269. package/src/render/ibl-override-material.ts +170 -0
  270. package/src/render/light-camera-factory.ts +8 -11
  271. package/src/render/material-factory.ts +1 -1
  272. package/src/render/render-batch-system.ts +14 -6
  273. package/src/render/render-features.ts +17 -35
  274. package/src/runtime/create-runtime.ts +270 -108
  275. package/src/runtime/debug-registry.ts +84 -8
  276. package/src/runtime/dev-build.ts +2 -2
  277. package/src/runtime/game-input-seams.ts +108 -0
  278. package/src/runtime/game.ts +231 -85
  279. package/src/runtime/mount-game.ts +31 -57
  280. package/src/runtime/mount-manifest.ts +47 -36
  281. package/src/runtime/playtest.ts +22 -0
  282. package/src/runtime/state-bridge.ts +3 -3
  283. package/src/setup/setup-audio.ts +21 -11
  284. package/src/setup/setup-renderer.ts +2 -61
  285. package/src/world3d-react/index.ts +15 -31
  286. package/src/world3d-react/r3f-root-factory.tsx +451 -60
  287. package/src/world3d-react/rapier-physics-bridge.tsx +154 -58
  288. package/dist/adapter/setup-three-root-adapter.d.ts +0 -86
  289. package/dist/adapter/setup-three-root-adapter.d.ts.map +0 -1
  290. package/dist/adapter/setup-three-root-adapter.js +0 -908
  291. package/dist/animation/clip-map.d.ts +0 -12
  292. package/dist/animation/clip-map.d.ts.map +0 -1
  293. package/dist/animation/clip-map.js +0 -31
  294. package/dist/asset-registry.d.ts +0 -38
  295. package/dist/asset-registry.d.ts.map +0 -1
  296. package/dist/asset-registry.js +0 -66
  297. package/dist/canvas-react/engine-bridge.d.ts +0 -45
  298. package/dist/canvas-react/engine-bridge.d.ts.map +0 -1
  299. package/dist/canvas-react/engine-bridge.js +0 -45
  300. package/dist/canvas-react/pixi-react-adapter.d.ts +0 -77
  301. package/dist/canvas-react/pixi-react-adapter.d.ts.map +0 -1
  302. package/dist/canvas-react/pixi-react-adapter.js +0 -294
  303. package/dist/canvas-react/world-context.d.ts +0 -98
  304. package/dist/canvas-react/world-context.d.ts.map +0 -1
  305. package/dist/canvas-react/world-context.js +0 -173
  306. package/dist/dev/debug-draw.d.ts +0 -24
  307. package/dist/dev/debug-draw.d.ts.map +0 -1
  308. package/dist/dev/debug-draw.js +0 -73
  309. package/dist/render/auto-batcher.d.ts +0 -34
  310. package/dist/render/auto-batcher.d.ts.map +0 -1
  311. package/dist/render/auto-batcher.js +0 -140
  312. package/dist/render/lod.d.ts +0 -13
  313. package/dist/render/lod.d.ts.map +0 -1
  314. package/dist/render/lod.js +0 -16
  315. package/dist/runtime/types.d.ts +0 -303
  316. package/dist/runtime/types.d.ts.map +0 -1
  317. package/dist/runtime/types.js +0 -1
  318. package/dist/world3d-react/engine-bridge.d.ts +0 -47
  319. package/dist/world3d-react/engine-bridge.d.ts.map +0 -1
  320. package/dist/world3d-react/engine-bridge.js +0 -73
  321. package/dist/world3d-react/r3f-adapter.d.ts +0 -58
  322. package/dist/world3d-react/r3f-adapter.d.ts.map +0 -1
  323. package/dist/world3d-react/r3f-adapter.js +0 -634
  324. package/dist/world3d-react/world-context.d.ts +0 -182
  325. package/dist/world3d-react/world-context.d.ts.map +0 -1
  326. package/dist/world3d-react/world-context.js +0 -235
  327. package/src/adapter/setup-three-root-adapter.ts +0 -1032
  328. package/src/animation/clip-map.ts +0 -34
  329. package/src/asset-registry.ts +0 -89
  330. package/src/canvas-react/engine-bridge.ts +0 -59
  331. package/src/canvas-react/pixi-react-adapter.tsx +0 -356
  332. package/src/canvas-react/world-context.ts +0 -253
  333. package/src/dev/debug-draw.ts +0 -80
  334. package/src/render/auto-batcher.ts +0 -168
  335. package/src/render/lod.ts +0 -17
  336. package/src/runtime/types.ts +0 -328
  337. package/src/world3d-react/engine-bridge.ts +0 -86
  338. package/src/world3d-react/r3f-adapter.tsx +0 -717
  339. package/src/world3d-react/world-context.ts +0 -358
@@ -1,12 +0,0 @@
1
- import type * as THREE from 'three';
2
- /**
3
- * Build the clip lookup shared by runtime and editor.
4
- *
5
- * GLTF exporters disagree about case and may prefix animation names with an
6
- * armature (`Armature|Idle`). Keep the exact exported suffix while also
7
- * exposing a lowercase lookup, then apply aliases case-insensitively. This
8
- * lets authored graphs use either `Idle_Loop` or `idle_loop` without silently
9
- * falling back to the bind pose.
10
- */
11
- export declare function buildClipMap(animations: THREE.AnimationClip[], aliases?: Record<string, string>): Map<string, THREE.AnimationClip>;
12
- //# sourceMappingURL=clip-map.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"clip-map.d.ts","sourceRoot":"","sources":["../../src/animation/clip-map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAEpC;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,KAAK,CAAC,aAAa,EAAE,EACjC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACnC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,CAmBlC"}
@@ -1,31 +0,0 @@
1
- /**
2
- * Build the clip lookup shared by runtime and editor.
3
- *
4
- * GLTF exporters disagree about case and may prefix animation names with an
5
- * armature (`Armature|Idle`). Keep the exact exported suffix while also
6
- * exposing a lowercase lookup, then apply aliases case-insensitively. This
7
- * lets authored graphs use either `Idle_Loop` or `idle_loop` without silently
8
- * falling back to the bind pose.
9
- */
10
- export function buildClipMap(animations, aliases = {}) {
11
- const clips = new Map();
12
- const canonical = new Map();
13
- for (const clip of animations) {
14
- const raw = clip.name.split('|').pop()?.trim() || clip.name;
15
- canonical.set(raw.toLowerCase(), clip);
16
- if (!clips.has(raw))
17
- clips.set(raw, clip);
18
- if (!clips.has(raw.toLowerCase()))
19
- clips.set(raw.toLowerCase(), clip);
20
- }
21
- for (const [source, alias] of Object.entries(aliases)) {
22
- const clip = canonical.get(source.toLowerCase());
23
- if (!clip)
24
- continue;
25
- if (!clips.has(alias))
26
- clips.set(alias, clip);
27
- if (!clips.has(alias.toLowerCase()))
28
- clips.set(alias.toLowerCase(), clip);
29
- }
30
- return clips;
31
- }
@@ -1,38 +0,0 @@
1
- /**
2
- * Central asset registry — stores per-asset metadata (import corrections, etc.).
3
- *
4
- * Loaded once via fetch(), cached in memory. Both the runtime scene loader
5
- * and editor entity factory import from this module.
6
- */
7
- import * as THREE from 'three';
8
- export interface ImportCorrection {
9
- /** Uniform scale factor applied to the GLTF clone before entity transform. */
10
- scale?: number;
11
- /** Euler rotation in degrees [x, y, z] applied to the GLTF clone before entity transform. */
12
- rotation?: [number, number, number];
13
- }
14
- export interface AssetMeta {
15
- importCorrection?: ImportCorrection;
16
- }
17
- /**
18
- * Apply an asset's visual-only import correction to the loaded GLTF content.
19
- * Call this on the model child, before placing it under the entity wrapper, so
20
- * gameplay transforms, physics, cameras, and movement remain in VGAI's Y-up /
21
- * -Z-forward coordinate contract.
22
- */
23
- export declare function applyImportCorrection(content: THREE.Object3D, correction: ImportCorrection | undefined): void;
24
- type AssetRegistry = Record<string, AssetMeta>;
25
- /**
26
- * Fetch and cache the asset registry. Safe to call multiple times —
27
- * returns the cached result after the first successful load.
28
- */
29
- export declare function loadRegistry(): Promise<AssetRegistry>;
30
- /** Get metadata for an asset path, or undefined if not in the registry. */
31
- export declare function getAssetMeta(path: string): AssetMeta | undefined;
32
- /**
33
- * Update the in-memory cache directly (used by the editor after saving
34
- * import settings, to avoid a re-fetch).
35
- */
36
- export declare function setRegistryCache(data: AssetRegistry): void;
37
- export {};
38
- //# sourceMappingURL=asset-registry.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"asset-registry.d.ts","sourceRoot":"","sources":["../src/asset-registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,MAAM,WAAW,gBAAgB;IAC/B,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,SAAS;IACxB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,KAAK,CAAC,QAAQ,EACvB,UAAU,EAAE,gBAAgB,GAAG,SAAS,GACvC,IAAI,CAUN;AAED,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAU/C;;;GAGG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAAC,aAAa,CAAC,CAgBrD;AAED,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAIhE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAG1D"}
@@ -1,66 +0,0 @@
1
- /**
2
- * Central asset registry — stores per-asset metadata (import corrections, etc.).
3
- *
4
- * Loaded once via fetch(), cached in memory. Both the runtime scene loader
5
- * and editor entity factory import from this module.
6
- */
7
- import * as THREE from 'three';
8
- import { resolveUrl } from './loader';
9
- /**
10
- * Apply an asset's visual-only import correction to the loaded GLTF content.
11
- * Call this on the model child, before placing it under the entity wrapper, so
12
- * gameplay transforms, physics, cameras, and movement remain in VGAI's Y-up /
13
- * -Z-forward coordinate contract.
14
- */
15
- export function applyImportCorrection(content, correction) {
16
- if (!correction)
17
- return;
18
- if (correction.scale !== undefined)
19
- content.scale.multiplyScalar(correction.scale);
20
- if (correction.rotation) {
21
- content.rotation.set(THREE.MathUtils.degToRad(correction.rotation[0]), THREE.MathUtils.degToRad(correction.rotation[1]), THREE.MathUtils.degToRad(correction.rotation[2]));
22
- }
23
- }
24
- let registryCache = null;
25
- let registryPromise = null;
26
- /** Normalize asset path for registry lookup (strip leading slash). */
27
- function normalize(path) {
28
- return path.startsWith('/') ? path.slice(1) : path;
29
- }
30
- /**
31
- * Fetch and cache the asset registry. Safe to call multiple times —
32
- * returns the cached result after the first successful load.
33
- */
34
- export function loadRegistry() {
35
- if (registryCache)
36
- return Promise.resolve(registryCache);
37
- if (registryPromise)
38
- return registryPromise;
39
- registryPromise = fetch(resolveUrl('asset-registry.json'))
40
- .then((res) => {
41
- if (!res.ok)
42
- return {};
43
- return res.json();
44
- })
45
- .catch(() => ({}))
46
- .then((data) => {
47
- registryCache = data;
48
- return data;
49
- });
50
- return registryPromise;
51
- }
52
- /** Get metadata for an asset path, or undefined if not in the registry. */
53
- export function getAssetMeta(path) {
54
- if (!registryCache)
55
- return undefined;
56
- // Try exact match first, then normalized
57
- return registryCache[path] ?? registryCache[normalize(path)];
58
- }
59
- /**
60
- * Update the in-memory cache directly (used by the editor after saving
61
- * import settings, to avoid a re-fetch).
62
- */
63
- export function setRegistryCache(data) {
64
- registryCache = data;
65
- registryPromise = null;
66
- }
@@ -1,45 +0,0 @@
1
- /**
2
- * `@engine/canvas-react` — the React context that carries a canvas world's
3
- * engine runtime into its `@pixi/react` tree: the world's `GameContext`, read
4
- * with {@link useGameContext}.
5
- *
6
- * The bridge value is built by `createPixiReactAdapter`'s `mount()`
7
- * (./pixi-react-adapter.tsx), whose `update(dt)` runs this world's phases under
8
- * the HOST loop — so registered systems tick in engine phase order, pause
9
- * included (no update while the world is frozen).
10
- *
11
- * Behavior in a canvas world is components + hooks: `useGameContext` reaches
12
- * engine services, `@pixi/react`'s own `useTick` is the per-frame hook, and
13
- * `useApplication` is the door to the live `Application`.
14
- */
15
- import type { CanvasGameContext } from './world-context';
16
- export interface EngineBridgeValue {
17
- /** This root's `CanvasGameContext` — `input`, `debug`, `random`, `clock`, `game`,
18
- * `roots`, `systems`, `registerSystemAdapter`. Present so ordinary
19
- * components can reach engine services with a HOOK (see
20
- * {@link useGameContext}). */
21
- readonly ctx?: CanvasGameContext | undefined;
22
- }
23
- export declare const EngineBridge: import("react").Context<EngineBridgeValue | null>;
24
- /**
25
- * This canvas root's `CanvasGameContext`, for use inside any component in the tree.
26
- *
27
- * An ordinary component does what a model would write:
28
- *
29
- * ```tsx
30
- * function Player({ speed = 220 }) {
31
- * const { input } = useGameContext();
32
- * const ref = useRef<Sprite>(null);
33
- * useTick(({ deltaMS }) => {
34
- * if (input?.isPressed('move_right')) ref.current!.x += speed * (deltaMS / 1000);
35
- * });
36
- * return <pixiSprite ref={ref} texture={Texture.WHITE} />;
37
- * }
38
- * ```
39
- *
40
- * Throws when called outside a canvas root mounted by
41
- * `createPixiReactAdapter` — absent context is a wiring bug, and a silent
42
- * `null` would surface as a mystery `undefined` deep in a tick callback.
43
- */
44
- export declare function useGameContext(): CanvasGameContext;
45
- //# sourceMappingURL=engine-bridge.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"engine-bridge.d.ts","sourceRoot":"","sources":["../../src/canvas-react/engine-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,MAAM,WAAW,iBAAiB;IAChC;;;mCAG+B;IAC/B,QAAQ,CAAC,GAAG,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;CAC9C;AAED,eAAO,MAAM,YAAY,mDAAgD,CAAC;AAE1E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,IAAI,iBAAiB,CAUlD"}
@@ -1,45 +0,0 @@
1
- /**
2
- * `@engine/canvas-react` — the React context that carries a canvas world's
3
- * engine runtime into its `@pixi/react` tree: the world's `GameContext`, read
4
- * with {@link useGameContext}.
5
- *
6
- * The bridge value is built by `createPixiReactAdapter`'s `mount()`
7
- * (./pixi-react-adapter.tsx), whose `update(dt)` runs this world's phases under
8
- * the HOST loop — so registered systems tick in engine phase order, pause
9
- * included (no update while the world is frozen).
10
- *
11
- * Behavior in a canvas world is components + hooks: `useGameContext` reaches
12
- * engine services, `@pixi/react`'s own `useTick` is the per-frame hook, and
13
- * `useApplication` is the door to the live `Application`.
14
- */
15
- import { createContext, useContext } from 'react';
16
- export const EngineBridge = createContext(null);
17
- /**
18
- * This canvas root's `CanvasGameContext`, for use inside any component in the tree.
19
- *
20
- * An ordinary component does what a model would write:
21
- *
22
- * ```tsx
23
- * function Player({ speed = 220 }) {
24
- * const { input } = useGameContext();
25
- * const ref = useRef<Sprite>(null);
26
- * useTick(({ deltaMS }) => {
27
- * if (input?.isPressed('move_right')) ref.current!.x += speed * (deltaMS / 1000);
28
- * });
29
- * return <pixiSprite ref={ref} texture={Texture.WHITE} />;
30
- * }
31
- * ```
32
- *
33
- * Throws when called outside a canvas root mounted by
34
- * `createPixiReactAdapter` — absent context is a wiring bug, and a silent
35
- * `null` would surface as a mystery `undefined` deep in a tick callback.
36
- */
37
- export function useGameContext() {
38
- const bridge = useContext(EngineBridge);
39
- if (!bridge?.ctx) {
40
- throw new Error('useGameContext(): no engine root context. This hook only works inside a canvas ' +
41
- 'root mounted by createPixiReactAdapter (@engine/canvas-react) — check that the ' +
42
- 'component is rendered inside your world entry, not in a standalone <Application>.');
43
- }
44
- return bridge.ctx;
45
- }
@@ -1,77 +0,0 @@
1
- /**
2
- * `createPixiReactAdapter` — wraps a `@pixi/react` tree as a first-party
3
- * `RootAdapter<'canvas'>` so a Pixi world mounts as an ordinary
4
- * `surface: "canvas"` root: the engine hands `mount()` a `CanvasHostContext`
5
- * (its own canvas + size + compositing hints, per `../adapter/host-context.ts`);
6
- * this returns a `MountedPixiRoot` (`../adapter/root-adapter.ts`) whose `stage`
7
- * is the REAL `PIXI.Container` the reconciler renders into.
8
- *
9
- * This is the canvas surface's sibling of `world3d-react`'s
10
- * `createR3FAdapter`, with `@pixi/react` where that one has
11
- * react-three-fiber. The explicit factory still supplies the engine context
12
- * used by the current first-party Canvas examples while their app-owned input
13
- * and debugger migration remains tracked in `docs/WORK.md`; `useTick` hooks
14
- * stay registered on Pixi's real ticker throughout that migration.
15
- *
16
- * ## The loop contract
17
- *
18
- * `Application` is initialized with `autoStart: false` and `sharedTicker:
19
- * false`, so it owns a native Pixi ticker that is NEVER started and therefore
20
- * never requests an animation frame. `mounted.update(dt)` is the only thing
21
- * that advances that ticker, and it feeds GAME time, not wall time — which is
22
- * what makes the world freeze exactly when the host freezes it, and what makes
23
- * `game.waitSimTime` work in a hidden tab (a hidden tab has no rAF; the engine
24
- * loop's own catch-up still calls `update`, and Pixi has no independent clock
25
- * to disagree with it).
26
- *
27
- * ## Component catalogue
28
- *
29
- * `@pixi/react` resolves `<pixiSprite>` etc. through a module-global catalogue
30
- * that starts EMPTY — the first intrinsic in an un-extended tree throws
31
- * "X is not part of the PIXI namespace! Did you forget to extend?". This
32
- * module extends it with the whole `pixi.js` namespace once per mount
33
- * (idempotent `Object.assign`), the same thing `createR3FAdapter` does with
34
- * `extend(host.three)`. A world that adds its own classes (`@pixi/tilemap`,
35
- * a custom `Container` subclass) calls `extend`/`useExtend` itself.
36
- */
37
- import type { ApplicationOptions } from 'pixi.js';
38
- import { type ReactNode } from 'react';
39
- import type { RootAdapter } from '../adapter';
40
- /** What {@link createPixiReactAdapter} needs to build one `RootAdapter<'canvas'>`. */
41
- export interface CreatePixiReactAdapterOptions {
42
- /** Stable id (telemetry/registry/conformance) — `RootAdapter.id`. */
43
- readonly id: string;
44
- /** The Pixi tree to mount — `useTick` hooks, `useApplication`, Pixi filters
45
- * and any extended component all work unchanged. */
46
- readonly content: ReactNode;
47
- /** Input map loaded through the game-owned `Game.loadInputMap` (load-once
48
- * across roots). Defaults to the conventional
49
- * `/inputmaps/default.inputmap.json`; `null` opts out (a world with no
50
- * actions). A missing/invalid map degrades loudly without failing the
51
- * mount — see `world-context.ts`. */
52
- readonly inputMapPath?: string | null | undefined;
53
- /**
54
- * Transitional compatibility for component trees that still consume the
55
- * engine context. Native trees opt out once their input, observation and
56
- * debugger state are application-owned.
57
- */
58
- readonly engineRuntime?: boolean | undefined;
59
- /**
60
- * Extra `Application.init` options merged UNDER this adapter's own — e.g.
61
- * `{ antialias: false }`, `{ roundPixels: true }`. The loop-critical ones
62
- * (`autoStart`, `sharedTicker`) and the ones the host owns (size, dpr,
63
- * transparency, `preserveDrawingBuffer`) are applied after this and cannot
64
- * be overridden: a world that starts its own ticker or clears an opaque
65
- * background under a stacked sibling breaks the host's contract, not just
66
- * its own frame.
67
- */
68
- readonly applicationOptions?: Partial<ApplicationOptions> | undefined;
69
- }
70
- /**
71
- * Build a `RootAdapter<'canvas'>` that mounts `options.content` through
72
- * `@pixi/react`, gated entirely by the host's own loop and rendering into the
73
- * host's own canvas — never a second canvas, never a second
74
- * `requestAnimationFrame` loop.
75
- */
76
- export declare function createPixiReactAdapter(options: CreatePixiReactAdapterOptions): RootAdapter<'canvas'>;
77
- //# sourceMappingURL=pixi-react-adapter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pixi-react-adapter.d.ts","sourceRoot":"","sources":["../../src/canvas-react/pixi-react-adapter.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAGH,OAAO,KAAK,EAAe,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAE/D,OAAO,EAA2B,KAAK,SAAS,EAA8B,MAAM,OAAO,CAAC;AAC5F,OAAO,KAAK,EAAsC,WAAW,EAAE,MAAM,YAAY,CAAC;AA2BlF,sFAAsF;AACtF,MAAM,WAAW,6BAA6B;IAC5C,qEAAqE;IACrE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;yDACqD;IACrD,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAC5B;;;;0CAIsC;IACtC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClD;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7C;;;;;;;;OAQG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,SAAS,CAAC;CACvE;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,6BAA6B,GACrC,WAAW,CAAC,QAAQ,CAAC,CAwPvB"}
@@ -1,294 +0,0 @@
1
- /**
2
- * `createPixiReactAdapter` — wraps a `@pixi/react` tree as a first-party
3
- * `RootAdapter<'canvas'>` so a Pixi world mounts as an ordinary
4
- * `surface: "canvas"` root: the engine hands `mount()` a `CanvasHostContext`
5
- * (its own canvas + size + compositing hints, per `../adapter/host-context.ts`);
6
- * this returns a `MountedPixiRoot` (`../adapter/root-adapter.ts`) whose `stage`
7
- * is the REAL `PIXI.Container` the reconciler renders into.
8
- *
9
- * This is the canvas surface's sibling of `world3d-react`'s
10
- * `createR3FAdapter`, with `@pixi/react` where that one has
11
- * react-three-fiber. The explicit factory still supplies the engine context
12
- * used by the current first-party Canvas examples while their app-owned input
13
- * and debugger migration remains tracked in `docs/WORK.md`; `useTick` hooks
14
- * stay registered on Pixi's real ticker throughout that migration.
15
- *
16
- * ## The loop contract
17
- *
18
- * `Application` is initialized with `autoStart: false` and `sharedTicker:
19
- * false`, so it owns a native Pixi ticker that is NEVER started and therefore
20
- * never requests an animation frame. `mounted.update(dt)` is the only thing
21
- * that advances that ticker, and it feeds GAME time, not wall time — which is
22
- * what makes the world freeze exactly when the host freezes it, and what makes
23
- * `game.waitSimTime` work in a hidden tab (a hidden tab has no rAF; the engine
24
- * loop's own catch-up still calls `update`, and Pixi has no independent clock
25
- * to disagree with it).
26
- *
27
- * ## Component catalogue
28
- *
29
- * `@pixi/react` resolves `<pixiSprite>` etc. through a module-global catalogue
30
- * that starts EMPTY — the first intrinsic in an un-extended tree throws
31
- * "X is not part of the PIXI namespace! Did you forget to extend?". This
32
- * module extends it with the whole `pixi.js` namespace once per mount
33
- * (idempotent `Object.assign`), the same thing `createR3FAdapter` does with
34
- * `extend(host.three)`. A world that adds its own classes (`@pixi/tilemap`,
35
- * a custom `Container` subclass) calls `extend`/`useExtend` itself.
36
- */
37
- import { createRoot, extend } from '@pixi/react';
38
- import * as PIXI from 'pixi.js';
39
- import { createElement, Fragment, useEffect, useLayoutEffect } from 'react';
40
- import { WorldProvider } from '../react/world-state';
41
- import { getDebugRegistry } from '../runtime/debug-registry';
42
- import { EngineBridge } from './engine-bridge';
43
- import { createCanvasRootContext } from './world-context';
44
- /** How long `mount()` waits for the tree's first commit before failing loudly
45
- * rather than hanging (and wedging every root declared after this one, since
46
- * roots mount sequentially). */
47
- const FIRST_COMMIT_TIMEOUT_MS = 10_000;
48
- /**
49
- * `@pixi/react` keys its reconciler roots off the canvas element in a
50
- * module-global map, and its own unmount path (which would clear that key) is
51
- * not exported. So a canvas this lane has already mounted must never be handed
52
- * to a second mount: `createRoot` would silently hand back the FIRST root,
53
- * whose `Application` this lane already destroyed. Every host in this repo
54
- * builds a fresh canvas per mount, so this only ever fires on a genuine bug —
55
- * and it fires as a named error rather than as a dead world.
56
- */
57
- const MOUNTED_CANVASES = new WeakSet();
58
- /**
59
- * Build a `RootAdapter<'canvas'>` that mounts `options.content` through
60
- * `@pixi/react`, gated entirely by the host's own loop and rendering into the
61
- * host's own canvas — never a second canvas, never a second
62
- * `requestAnimationFrame` loop.
63
- */
64
- export function createPixiReactAdapter(options) {
65
- const { id, content, inputMapPath, engineRuntime = true, applicationOptions } = options;
66
- return {
67
- id,
68
- async mount(host) {
69
- const runtime = engineRuntime ? createCanvasRootContext(host, { id, inputMapPath }) : null;
70
- const bridge = runtime ? { ctx: runtime.ctx } : null;
71
- // Actions must exist before any component's first tick reads them — wait
72
- // for the (never-rejecting) input-map load before the first commit.
73
- await runtime?.inputMapReady;
74
- const canvas = host.canvas;
75
- if (MOUNTED_CANVASES.has(canvas)) {
76
- runtime?.dispose();
77
- throw new Error(`createPixiReactAdapter: root "${id}" was handed a canvas this lane has already ` +
78
- 'mounted. @pixi/react keys its reconciler roots off the canvas element, so re-using ' +
79
- 'one would resurrect a root whose Application is destroyed. Hand each mount a fresh ' +
80
- 'canvas (every vgai host already does).');
81
- }
82
- MOUNTED_CANVASES.add(canvas);
83
- // The catalogue is module-global and starts empty; this is idempotent.
84
- extend(PIXI);
85
- let resolveCommitted;
86
- const committed = new Promise((resolve) => {
87
- resolveCommitted = resolve;
88
- });
89
- let resolveEffectsReady;
90
- const effectsReady = new Promise((resolve) => {
91
- resolveEffectsReady = resolve;
92
- });
93
- let resolveUnmounted;
94
- const unmounted = new Promise((resolve) => {
95
- resolveUnmounted = resolve;
96
- });
97
- /**
98
- * Signals the tree's FIRST COMMIT and its LAST. A layout effect,
99
- * deliberately, and rendered as the LAST child, deliberately:
100
- *
101
- * - mount: layout effects run synchronously inside the commit, before
102
- * any passive effect and before any tick can be scheduled;
103
- * - unmount: React commits deletion effects in tree order, each node
104
- * before its own children, so the LAST sibling's cleanup is the last
105
- * to run. That is what makes this a reliable "every component has
106
- * finished tearing down" signal — and it is load-bearing, because
107
- * `useTick`'s own cleanup calls `ticker.remove()`. Destroying the
108
- * Application before that cleanup lands throws inside React's commit
109
- * on every teardown of any world with a tick hook.
110
- */
111
- function Lifecycle() {
112
- useLayoutEffect(() => {
113
- resolveCommitted();
114
- return resolveUnmounted;
115
- }, []);
116
- // This component is the last sibling. Reaching its passive effect
117
- // means the initial tree's useDebugProvider/useDebugCommand effects
118
- // have registered, so mount() can truthfully back Play's ack.
119
- useEffect(resolveEffectsReady, []);
120
- return null;
121
- }
122
- // The React seam every dom root already has — `useWorldState`,
123
- // `useDebugProvider`/`useDebugCommand`/`useDebugEmit`
124
- // (`../react/world-state`) — works identically inside a canvas root
125
- // because a canvas root IS React. `host.game` is genuinely absent in
126
- // bare/foreign hosts, so the provider is conditional and those hooks
127
- // stay the inert no-ops they already document themselves to be.
128
- //
129
- // READ FROM `host.game`, NEVER FROM `runtime` — the same rule, and the
130
- // same reasoning, as the three lane's (`../world3d-react/r3f-adapter.tsx`,
131
- // beside its own `const game = host.game`). The two providers answer
132
- // different questions: `EngineBridge` rides `bridge` (the vgai runtime
133
- // CONTEXT, which must not enter an ecosystem-native tree), `WorldProvider`
134
- // rides the Game handle the host already holds. Keyed off `runtime`, a
135
- // world mounted with `engineRuntime: false` gets no `WorldProvider` at
136
- // all and every `useDebugProvider` in it no-ops IN SILENCE — no error, and
137
- // `vgai eval 'await game.providers()'` lists only the built-ins. That is
138
- // exactly what happened on the three lane. It has never fired here only
139
- // because `pixi-react-root-factory.tsx` still leaves the runtime on;
140
- // that flag is the tracked component-root migration's to flip, and this
141
- // seam must not be waiting for it.
142
- const game = host.game;
143
- const world = createElement(Fragment, null, content, createElement(Lifecycle));
144
- const provided = game ? createElement(WorldProvider, { game }, world) : world;
145
- const element = bridge
146
- ? createElement(EngineBridge.Provider, { value: bridge }, provided)
147
- : provided;
148
- const root = createRoot(canvas);
149
- // The host owns size, dpr, transparency and capture cost; the loop
150
- // contract owns `autoStart`/`sharedTicker`. Both are applied AFTER the
151
- // caller's own options so neither can be overridden from a world file.
152
- const initOptions = {
153
- antialias: true,
154
- ...applicationOptions,
155
- width: host.width,
156
- height: host.height,
157
- resolution: host.dpr ?? globalThis.devicePixelRatio ?? 1,
158
- autoDensity: true,
159
- // Stacked ABOVE a sibling root -> clear with alpha 0 so the layer below
160
- // shows through (COMPOSITION-DESIGN D5 §1).
161
- backgroundAlpha: host.transparent ? 0 : 1,
162
- preserveDrawingBuffer: host.preserveDrawingBuffer ?? false,
163
- autoStart: false,
164
- sharedTicker: false,
165
- };
166
- // Install the reconcile-error listener BEFORE `root.render`: Pixi hands
167
- // the Application back after `init()` but React can already have thrown
168
- // during that same turn. Attaching after the await loses the real error
169
- // and turns it into a misleading ten-second timeout.
170
- let reportReconcileFailure;
171
- const reconcileFailure = new Promise((resolve) => {
172
- reportReconcileFailure = resolve;
173
- });
174
- const onError = (event) => {
175
- reportReconcileFailure(`the Pixi tree crashed before its first commit — ${event.message} ` +
176
- '(mount() fails loudly instead of hanging)');
177
- };
178
- globalThis.addEventListener?.('error', onError);
179
- let app;
180
- let timer;
181
- try {
182
- // `root.render` is async: it awaits `Application.init()` (which is what
183
- // creates the renderer) and only then hands the tree to the reconciler.
184
- // A crash inside init rejects here, which is the loud failure we want.
185
- const renderedApp = await root.render(element, initOptions);
186
- app = renderedApp;
187
- runtime?.setApplication(renderedApp);
188
- // A reconcile-time crash (e.g. an un-extended component) surfaces as
189
- // an uncaught window error and the first commit never lands. Race that
190
- // exact signal against the commit and the last-resort ceiling.
191
- const timeout = new Promise((resolve) => {
192
- timer = setTimeout(() => resolve(`no first commit within ${FIRST_COMMIT_TIMEOUT_MS / 1000}s ` +
193
- '(mount() fails loudly instead of hanging)'), FIRST_COMMIT_TIMEOUT_MS);
194
- });
195
- const failure = await Promise.race([
196
- Promise.all([committed, effectsReady]).then(() => null),
197
- reconcileFailure,
198
- timeout,
199
- ]);
200
- if (failure !== null) {
201
- throw new Error(`createPixiReactAdapter: root "${id}" — ${failure}`);
202
- }
203
- }
204
- catch (error) {
205
- try {
206
- app?.destroy(false, { children: true });
207
- }
208
- catch {
209
- /* the world never fully came up; teardown failure must not mask why */
210
- }
211
- runtime?.dispose();
212
- throw error;
213
- }
214
- finally {
215
- if (timer !== undefined)
216
- clearTimeout(timer);
217
- globalThis.removeEventListener?.('error', onError);
218
- }
219
- // `app` is assigned before the first-commit race. Reaching here proves
220
- // both initialization and commit succeeded, so narrow once for the live
221
- // mounted-root methods below.
222
- if (app === undefined) {
223
- runtime?.dispose();
224
- throw new Error(`createPixiReactAdapter: root "${id}" initialized without an Application`);
225
- }
226
- const mountedApp = app;
227
- // Pin the ticker's clock to GAME time. `Ticker.lastTime` starts at -1, so
228
- // without this the first `update()` would report a 1ms phantom delta on
229
- // top of the real one. From here every `deltaMS` a `useTick` callback
230
- // sees is exactly the `dt` the host handed us — no wall clock anywhere,
231
- // which is what makes a paused world's resume frame ordinary rather than
232
- // one giant catch-up step.
233
- mountedApp.ticker.lastTime = 0;
234
- let elapsedMs = 0;
235
- let disposed = false;
236
- const registry = host.game ? getDebugRegistry(host.game) : null;
237
- const systemAdapters = runtime?.systemAdapters ?? (registry ? { debug: registry.adapter } : {});
238
- const disposeComplete = unmounted.then(() => {
239
- mountedApp.destroy(false, { children: true });
240
- });
241
- return {
242
- kind: 'canvas',
243
- // The reconciler's real root container — the same `PIXI.Container`
244
- // `RootInstance.pixiStage()` hands the editor.
245
- stage: mountedApp.stage,
246
- drivesOwnLoop: false,
247
- // Adapter surface: the host's shared debug registry. A native component
248
- // tree registers nothing; its entry-module `debug` export is projected
249
- // after mount by the shared native adapter.
250
- systems: systemAdapters,
251
- disposeComplete,
252
- update(dt) {
253
- if (disposed)
254
- return;
255
- elapsedMs += dt * 1000;
256
- // The optional legacy runtime drains first when explicitly enabled;
257
- // the native path has none. The real Pixi ticker remains the one
258
- // scheduler `useTick` observes, and the host only gates/advances it.
259
- runtime?.systems.run(dt);
260
- mountedApp.ticker.update(elapsedMs);
261
- },
262
- resize(width, height) {
263
- if (disposed)
264
- return;
265
- // `autoDensity: true` makes Pixi re-stamp `canvas.style.width`/
266
- // `.height` from this call, so the on-screen box follows the logical
267
- // size with no explicit CSS write from the host.
268
- mountedApp.renderer.resize(width, height);
269
- },
270
- dispose() {
271
- if (disposed)
272
- return;
273
- disposed = true;
274
- // Pixi's EventSystem owns document.pointermove + window.pointerup
275
- // (and its event ticker's global listener). React's deletion commit
276
- // is asynchronous, so waiting to destroy the Application leaves
277
- // those listeners live when the host audits this game realm. Detach
278
- // the input target synchronously; the later Application.destroy()
279
- // repeats this idempotently after every useTick cleanup has landed.
280
- mountedApp.renderer.events.setTargetElement(null);
281
- // Rendering `null` children is the only unmount path `@pixi/react`
282
- // exposes publicly (its `unmountRoot` helper is internal), and React
283
- // commits that deletion on its own schedule — NOT synchronously. So
284
- // the Application is destroyed on the `Lifecycle` cleanup signal
285
- // instead of inline: `useTick`'s cleanup calls `ticker.remove()`, and
286
- // a ticker destroyed before it lands throws inside React's commit.
287
- // `removeView` stays false — the canvas belongs to the HOST.
288
- void root.render(null, initOptions);
289
- runtime?.dispose();
290
- },
291
- };
292
- },
293
- };
294
- }