@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
@@ -4,11 +4,9 @@
4
4
  *
5
5
  * WHY IT EXISTS. `SystemAdapters.physics` is what the editor's transform
6
6
  * coordination (`freeze → apply → unfreeze`) and the universal
7
- * "Colliders drawn" instrument (`@engine/dev/instruments`) read. The
8
- * first-party imperative three root registers one from
9
- * `../adapter/setup-three-root-adapter.ts`; an R3F world builds no first-party
10
- * Rapier runtime at all (see `R3FGameContext`'s doc comment) — it does physics
11
- * with `@react-three/rapier` INSIDE the fiber tree, where nothing engine-side
7
+ * "Colliders drawn" instrument (`@engine/dev/instruments`) read. An R3F world
8
+ * builds no first-party Rapier runtime at all it does physics with
9
+ * `@react-three/rapier` INSIDE the fiber tree, where nothing engine-side
12
10
  * can see it. Result, before this: the colliders instrument read `null` (an
13
11
  * em-dash) and its toggle threw "no physics adapter" in every shipped example
14
12
  * and every scaffolded game.
@@ -40,18 +38,23 @@
40
38
  * is how a `SystemAdapters` member says "not supported".
41
39
  *
42
40
  * ── RESOURCE OWNERSHIP, STATED ONCE ─────────────────────────────────────────
43
- * OWNER: this component owns exactly ONE `SystemAdapters.physics` registration,
44
- * on the R3F root it is mounted in. It allocates nothing else no timers, no
45
- * subscriptions, no per-frame work (see the phase note below), and no Rapier
46
- * objects: the bodies it edits belong to `<Physics>`.
47
- * SHARERS: every reader of `game.systemAdapters.physics` the
48
- * colliders instrument, the editor's transform coordination. They read; they
49
- * never dispose.
50
- * TEARDOWN: the effect's cleanup, and nothing else — it clears the SAME key it
51
- * set (`registerSystemAdapter('physics', undefined)`, which
52
- * `Game.computeSystemAdapters` skips), so a play stop/start, a hot restart, or
53
- * a world that unmounts `<Physics>` leaves no stale adapter behind. Two
54
- * bridges in one root would fight over that one key; mount exactly one.
41
+ * OWNER: this component owns one physics ADAPTER, published onto the ONE
42
+ * module-scoped slot `rapierPhysicsSystem()` forwards to (GAME-GLOBALthe
43
+ * entry's static `systems.physics` declaration cannot be per-root). It allocates nothing
44
+ * else no timers, no subscriptions, no per-frame work (see the phase note
45
+ * below), and no Rapier objects: the bodies it edits belong to `<Physics>`.
46
+ * SHARERS: every reader of `game.systemAdapters.physics` the colliders
47
+ * instrument, the editor's transform coordination. They read; they never
48
+ * dispose.
49
+ * TEARDOWN: the effect's cleanup, and nothing else — it clears the SAME key
50
+ * and the slot it set (identity-guarded), so a play stop/start, a hot
51
+ * restart, or a world that unmounts `<Physics>` leaves no stale adapter
52
+ * behind. Because the slot is PAGE-global (see its doc below an engine
53
+ * module is shared across the editor's Play instances), mount exactly ONE
54
+ * bridge per PAGE: with two — a scene that mounts two, or two Play instances
55
+ * of one rapier world — the later mount wins the slot and the later unmount
56
+ * clears it while the earlier bridge is still live. That state is reported
57
+ * loudly the moment it starts (`warnOnContendedMount`).
55
58
  *
56
59
  * PHASE ORDERING: none to respect — this component registers pull-only
57
60
  * callbacks and runs no per-frame work. Every method it exposes is invoked
@@ -64,6 +67,7 @@ import { useEffect } from 'react';
64
67
  import * as THREE from 'three';
65
68
  import {
66
69
  createRapierBodyEditing,
70
+ type RapierBodyLookup,
67
71
  type RapierEditableBody,
68
72
  } from '../adapter/rapier-physics-adapter';
69
73
  import type {
@@ -73,7 +77,7 @@ import type {
73
77
  PhysicsJointSnapshot,
74
78
  PhysicsJointType,
75
79
  } from '../adapter/system-adapter';
76
- import { useGameContext } from './engine-bridge';
80
+ import { createSystemSlot } from '../adapter/system-slot';
77
81
 
78
82
  export interface RapierPhysicsBridgeProps {
79
83
  /**
@@ -123,57 +127,60 @@ function owningBody(
123
127
  * `useRapier()`). Renders nothing.
124
128
  */
125
129
  export function RapierPhysicsBridge({ onDebugChange }: RapierPhysicsBridgeProps): null {
126
- const ctx = useGameContext();
130
+ // This bridge publishes the module slot below, which the entry's
131
+ // `systems.physics` declaration (`rapierPhysicsSystem()`) forwards to —
132
+ // that declaration is the ONE path the host reads this world's physics
133
+ // through.
127
134
  const { colliderStates, rapier, rigidBodyStates, world } = useRapier();
128
- const registerSystemAdapter = ctx.registerSystemAdapter;
129
135
 
130
136
  useEffect(() => {
131
- if (!registerSystemAdapter) return;
132
-
133
137
  /**
134
- * node id → the Rapier body driving it, in two hops the library and the
135
- * engine each already own:
136
- *
137
- * 1. id `Object3D`, through the live scene index `userData.entityId`
138
- * is this stack's identity convention (the editor's R3F authoring
139
- * adapter stamps it; `../adapter/setup-three-root-adapter.ts` resolves
140
- * the same way for the imperative root).
141
- * 2. `Object3D` → body, through `rigidBodyStates` — the library's OWN
142
- * body↔object map, carried on the `RapierContext` `useRapier()`
143
- * returns. Walking ANCESTORS matters: `<RigidBody>` owns a subtree, so
144
- * the selected mesh is usually a descendant of the object the state
145
- * names.
138
+ * node id → the Rapier body driving it, entirely through the library's
139
+ * OWN body↔object map (`rigidBodyStates`, carried on the `RapierContext`
140
+ * `useRapier()` returns): resolve `userData.entityId` — this stack's
141
+ * identity convention, stamped by the editor's R3F authoring adapter
142
+ * inside the body-owned subtrees, then walk ANCESTORS to the owning body
143
+ * (`<RigidBody>` owns a subtree, so the selected mesh is usually a
144
+ * descendant of the object the state names).
146
145
  *
147
- * Both maps are live, so this is computed per call rather than cached —
146
+ * The map is live, so this is computed per call rather than cached —
148
147
  * calls arrive at gesture rate (a gizmo drag start/end, a dev command),
149
- * never per frame. `ctx.sceneIndex` is read AT CALL TIME, never captured:
150
- * the R3F root backfills it once fiber resolves the scene, which can land
151
- * after this component's first effect (`world-context.ts`'s
152
- * `setSceneCamera`), so a destructured copy would be permanently absent.
148
+ * never per frame, and only objects under a `<RigidBody>` can have a body
149
+ * at all, so the body subtrees are the complete search space.
153
150
  */
154
151
  const bodyFor = (nodeId: string): RapierEditableBody | undefined => {
155
- const indexed = ctx.sceneIndex?.byEntityId(nodeId);
156
- const object = indexed ?? lateEntityObject(rigidBodyStates.values(), nodeId);
157
- if (!indexed && object) {
158
- // The editor assigns its stable authoring entity ids AFTER Fiber's
159
- // first commit, while the root's SceneIndex is constructed during
160
- // that commit. Resolve the one late id inside the library-owned body
161
- // subtrees and immediately reindex it; subsequent gestures take the
162
- // normal indexed path. This is the SceneIndex's documented escape
163
- // hatch for a userData id written after construction, not a parallel
164
- // scene mirror.
165
- ctx.sceneIndex?.reindex(object);
166
- }
152
+ const object = lateEntityObject(rigidBodyStates.values(), nodeId);
167
153
  if (!object) return undefined;
168
154
  return owningBody(object, rigidBodyStates.values());
169
155
  };
170
156
 
157
+ /**
158
+ * The same question, with the two negative answers KEPT APART for the
159
+ * editing protocol — see {@link RapierBodyLookup}. This world's search
160
+ * space is the `<RigidBody>` subtrees, so "no object here" really is "not a
161
+ * node of mine", not "a node of mine without physics".
162
+ */
163
+ const bodyLookup = (nodeId: string): RapierBodyLookup => {
164
+ const object = lateEntityObject(rigidBodyStates.values(), nodeId);
165
+ if (!object) return { kind: 'unresolved' };
166
+ const body = owningBody(object, rigidBodyStates.values());
167
+ return body ? { kind: 'body', body } : { kind: 'no-body' };
168
+ };
169
+
170
+ /** Rapier's own name for a shape type, via the enum's reverse mapping —
171
+ * so an unprojected collider reports WHICH shape it is (`TriMesh`,
172
+ * `HeightField`, …) instead of a bare number, and a shape added by a
173
+ * future rapier still names itself. */
174
+ const rapierShapeName = (shapeType: number): string =>
175
+ (rapier.ShapeType as unknown as Record<number, string | undefined>)[shapeType] ??
176
+ `shapeType ${shapeType}`;
177
+
171
178
  const colliderShape = (collider: {
172
179
  shapeType(): number;
173
180
  halfExtents(): { x: number; y: number; z: number };
174
181
  radius(): number;
175
182
  halfHeight(): number;
176
- }): PhysicsColliderShape | null => {
183
+ }): PhysicsColliderShape => {
177
184
  switch (collider.shapeType()) {
178
185
  case rapier.ShapeType.Cuboid: {
179
186
  const halfExtents = collider.halfExtents();
@@ -187,8 +194,13 @@ export function RapierPhysicsBridge({ onDebugChange }: RapierPhysicsBridgeProps)
187
194
  halfHeight: collider.halfHeight(),
188
195
  radius: collider.radius(),
189
196
  };
197
+ // Rapier has many more shapes than this seam projects (TriMesh,
198
+ // HeightField, ConvexPolyhedron, Cylinder, Cone, …). The collider is
199
+ // REAL; only our plain-data projection of it is missing, so it is
200
+ // reported as itself rather than dropped — a body whose only collider
201
+ // is a trimesh used to inspect as a body with no colliders at all.
190
202
  default:
191
- return null;
203
+ return { type: 'unsupported', kind: rapierShapeName(collider.shapeType()) };
192
204
  }
193
205
  };
194
206
 
@@ -199,7 +211,6 @@ export function RapierPhysicsBridge({ onDebugChange }: RapierPhysicsBridgeProps)
199
211
  for (const state of colliderStates.values()) {
200
212
  if (state.collider.parent()?.handle !== body.handle) continue;
201
213
  const shape = colliderShape(state.collider);
202
- if (!shape) continue;
203
214
  state.object.updateWorldMatrix(true, false);
204
215
  const position = state.collider.translation();
205
216
  const rotation = state.collider.rotation();
@@ -236,6 +247,11 @@ export function RapierPhysicsBridge({ onDebugChange }: RapierPhysicsBridgeProps)
236
247
  collider.setHalfHeight(shape.halfHeight);
237
248
  collider.setRadius(shape.radius);
238
249
  break;
250
+ // A shape this seam does not project has no dimensions to write back.
251
+ // `colliders()` reports it so the body's physics is not invisible; that
252
+ // is a READ, and it does not make the shape editable.
253
+ case 'unsupported':
254
+ break;
239
255
  }
240
256
  };
241
257
 
@@ -360,16 +376,96 @@ export function RapierPhysicsBridge({ onDebugChange }: RapierPhysicsBridgeProps)
360
376
  };
361
377
 
362
378
  const adapter: PhysicsAdapter = {
363
- ...createRapierBodyEditing(bodyFor),
379
+ ...createRapierBodyEditing(bodyLookup),
364
380
  setDebugDrawEnabled: (enabled) => onDebugChange(enabled),
365
381
  colliders,
366
382
  previewCollider,
367
383
  joints,
368
384
  previewJointAnchor,
369
385
  };
370
- registerSystemAdapter('physics', adapter);
371
- return () => registerSystemAdapter('physics', undefined);
372
- }, [colliderStates, ctx, onDebugChange, rapier, registerSystemAdapter, rigidBodyStates, world]);
386
+ warnOnContendedMount();
387
+ const detach = physicsSlot.attach(adapter);
388
+ return () => {
389
+ liveBridgeCount -= 1;
390
+ detach();
391
+ };
392
+ }, [colliderStates, onDebugChange, rapier, rigidBodyStates, world]);
373
393
 
374
394
  return null;
375
395
  }
396
+
397
+ // ---------------------------------------------------------------------------
398
+ // The entry-declaration half
399
+ // ---------------------------------------------------------------------------
400
+
401
+ /**
402
+ * The bridge's slot. Module-scoped on purpose: the entry's `systems`
403
+ * declaration is static, the rapier world is not, and this slot is the seam
404
+ * between the two. Module scope here means one per PAGE, not one per game:
405
+ * this file is an ENGINE module, reached by bare specifier, so the editor's
406
+ * multi-instance Play (which stamps mount ids onto PROJECT-owned specifiers
407
+ * only — `server/project-module-instance.ts`) shares this one slot across
408
+ * every mounted instance. Two live instances of a rapier world therefore
409
+ * contend for it: the LAST bridge to mount wins every instance's declared
410
+ * `systems.physics`, and the loser's detach is dropped by the identity guard.
411
+ * {@link warnOnContendedMount} makes that state loud at the moment it
412
+ * happens; making the slot instance-scoped needs a per-mount rendezvous the
413
+ * context-free declaration (`rapierPhysicsSystem()` at project-module scope)
414
+ * does not yet have.
415
+ *
416
+ * Every member is an ACTION: each one either edits the sim or reads a live
417
+ * Rapier handle, and all of them arrive at gesture rate (a gizmo drag, an
418
+ * instrument command), never from a per-frame loop — so refusing by name is
419
+ * always the right answer, and a fabricated empty never is.
420
+ * `debugDraw`/`contactPoints` are OMITTED, not stubbed, for the anti-shim
421
+ * reason stated at the top of this file; a member the config does not list
422
+ * does not exist on the slot.
423
+ */
424
+ let liveBridgeCount = 0;
425
+
426
+ /** The page-scope contention above, made LOUD instead of silent (never a
427
+ * silent degrade): a second concurrent bridge mount — a scene that mounted
428
+ * two, or a second Play instance of a rapier world — is reported the moment
429
+ * it happens, naming what breaks and until when. */
430
+ function warnOnContendedMount(): void {
431
+ liveBridgeCount += 1;
432
+ if (liveBridgeCount <= 1) return;
433
+ // biome-ignore lint/suspicious/noConsole: the standing-warning channel for a capability the adapter cannot reach — the editor console surfaces it during play
434
+ console.warn(
435
+ `[rapierPhysicsSystem] ${liveBridgeCount} <RapierPhysicsBridge> mounts are live on this ` +
436
+ 'page, but the declared physics slot is one per page (engine modules are shared across ' +
437
+ "Play instances). Every instance's `systems.physics` now forwards to the LAST bridge " +
438
+ 'mounted, so physics gizmo edits and instruments address that world — not necessarily ' +
439
+ 'the one selected — until the extra mounts unmount.',
440
+ );
441
+ }
442
+
443
+ const physicsSlot = createSystemSlot<PhysicsAdapter>({
444
+ name: 'rapierPhysicsSystem',
445
+ unattachedMessage:
446
+ 'no <RapierPhysicsBridge> is mounted inside a live <Physics> right now — the world is not ' +
447
+ 'playing, or the scene never mounted the bridge.',
448
+ members: {
449
+ ownerOf: { kind: 'action' },
450
+ freeze: { kind: 'action' },
451
+ commit: { kind: 'action' },
452
+ unfreeze: { kind: 'action' },
453
+ setDebugDrawEnabled: { kind: 'action' },
454
+ colliders: { kind: 'action' },
455
+ previewCollider: { kind: 'action' },
456
+ joints: { kind: 'action' },
457
+ previewJointAnchor: { kind: 'action' },
458
+ },
459
+ });
460
+
461
+ /**
462
+ * The `systems.physics` slot for a default-exported world — declare it from
463
+ * the entry (`export const systems = { physics: rapierPhysicsSystem() }`) and
464
+ * keep `<RapierPhysicsBridge />` mounted inside `<Physics>`. Every call
465
+ * forwards to the LIVE bridge adapter, so the static declaration answers with
466
+ * the running world's physics; while none is mounted, every call refuses by
467
+ * name rather than fabricating.
468
+ */
469
+ export function rapierPhysicsSystem(): PhysicsAdapter {
470
+ return physicsSlot.slot;
471
+ }
@@ -1,86 +0,0 @@
1
- /**
2
- * SetupThreeRootAdapter — the first-party implementer of {@link RootAdapter}
3
- * that mounts ONE three root from an imperative `setup(ctx)` function.
4
- *
5
- * This is where Rapier lives now: the host no longer knows about it.
6
- * `mount(host)` builds the full first-party runtime (the body
7
- * that used to live inline in `create-runtime.ts`) from a neutral
8
- * {@link ThreeHostContext}, runs the game's `setup`, and returns a
9
- * {@link MountedThreeRoot}. First-party content is now just one implementer of
10
- * the same interface an unmodified external game implements (Phase B).
11
- *
12
- * It was `VgaiSceneGameAdapter` until WO-9 tasks #6/#9. Both halves of that
13
- * name had stopped being true: it loads no scene (the `.vscn.json` branches
14
- * went with the format in WO-8 — `setup` is the only mount path left), and what
15
- * it mounts is one three ROOT, not a game (a game is the manifest's whole set
16
- * of roots). The R3F/TSX world root is a SEPARATE adapter; this one is
17
- * specifically the `fromSetup` path.
18
- *
19
- * `GameSetupFn` / `GameContext` are imported ONLY here (and in the example
20
- * `fromSetup` wrappers) — never by the host. That confinement is the inversion.
21
- */
22
- import type { EffectComposer } from 'postprocessing';
23
- import { type ViewportShadingMode } from '../render/viewport-shading';
24
- import { type RootFrameHooks } from '../runtime/game';
25
- import type { EditorPreview, GameContext, GameSetupFn } from '../runtime/types';
26
- import type { ThreeHostContext } from './host-context';
27
- import type { MountedThreeRoot, RootAdapter } from './root-adapter';
28
- /** How a {@link SetupThreeRootAdapter} builds its game (the former RuntimeConfig). */
29
- export interface SetupThreeRootConfig {
30
- /** Game setup function — registers systems and loads scenes. */
31
- setup?: GameSetupFn | undefined;
32
- /** Editor context — passed to setup() when launched from the editor. */
33
- editorPreview?: EditorPreview | undefined;
34
- /** Input map JSON path. Defaults to 'inputmaps/default.inputmap.json'. */
35
- inputMapPath?: string | undefined;
36
- /** URL prefix for relative asset paths. Defaults to '/'. */
37
- assetPrefix?: string | undefined;
38
- /** Stable adapter id (for registry/conformance). Defaults to 'setup-three'. */
39
- id?: string | undefined;
40
- }
41
- /**
42
- * The first-party `MountedThreeRoot`, with concrete extras the editor host uses for
43
- * first-party features (HMR, physics sync) that are NOT part of the neutral
44
- * interface. The generic host only touches the `MountedThreeRoot` surface.
45
- */
46
- export interface MountedSetupThreeRoot extends MountedThreeRoot {
47
- /**
48
- * First-party brand (checklist item 1 / T7.3 lookahead): a plain `'ctx' in
49
- * mounted` structural check misfires against any foreign mount that happens
50
- * to carry an unrelated `ctx` key. This literal-`true`
51
- * property is what `isFirstPartyMounted` (`runtime/game.ts`) actually
52
- * checks; `game.ts` reads it via a structural `{ firstParty?: unknown }`
53
- * probe so it never needs a value import of this module (the existing
54
- * import is type-only and must stay that way).
55
- */
56
- readonly firstParty: true;
57
- readonly ctx: GameContext;
58
- readonly composer: EffectComposer | null;
59
- /** Render-only developer view; native game materials are restored before the frame returns. */
60
- setViewportShadingMode(mode: ViewportShadingMode): void;
61
- /** Warm-restart: dispose the current game, re-run a new setup on the same ctx. */
62
- hotReload(newSetup: GameSetupFn, editorPreview?: EditorPreview): Promise<void>;
63
- /**
64
- * Phase-partitioned frame entry point (T7.1 slice 2) — wired onto this
65
- * world's `RootInstance` by `registerThreeRoot` (`create-runtime.ts`).
66
- * `Game.runFrame` is the CANONICAL driver going forward: it calls
67
- * `frame.runPhase` once per (phase, substep) for every world, then
68
- * `frame.endFrame` once per substep after all roots finish all phases.
69
- * `update` is the direct entry point to the same `SystemRunner` for hosts
70
- * that do not partition phases themselves.
71
- */
72
- readonly frame: RootFrameHooks;
73
- }
74
- /**
75
- * Wrap a first-party `setup` function as a {@link RootAdapter}. This is how every
76
- * first-party example becomes an implementer of the same interface an external
77
- * game implements — with no change to the setup's body.
78
- */
79
- export declare function fromSetup(id: string, setup: GameSetupFn): RootAdapter;
80
- export declare class SetupThreeRootAdapter implements RootAdapter {
81
- private readonly config;
82
- readonly id: string;
83
- constructor(config?: SetupThreeRootConfig);
84
- mount(host: ThreeHostContext): Promise<MountedSetupThreeRoot>;
85
- }
86
- //# sourceMappingURL=setup-three-root-adapter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"setup-three-root-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/setup-three-root-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAoCrD,OAAO,EAAE,KAAK,mBAAmB,EAA2B,MAAM,4BAA4B,CAAC;AAO/F,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,KAAK,EAAE,aAAa,EAAe,WAAW,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAM7F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGpE,sFAAsF;AACtF,MAAM,WAAW,oBAAoB;IACnC,gEAAgE;IAChE,KAAK,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAChC,wEAAwE;IACxE,aAAa,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IAC1C,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,+EAA+E;IAC/E,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACzB;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAsB,SAAQ,gBAAgB;IAC7D;;;;;;;;OAQG;IACH,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAC;IACzC,+FAA+F;IAC/F,sBAAsB,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACxD,kFAAkF;IAClF,SAAS,CAAC,QAAQ,EAAE,WAAW,EAAE,aAAa,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E;;;;;;;;OAQG;IACH,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;CAChC;AAeD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,WAAW,CAErE;AAED,qBAAa,qBAAsB,YAAW,WAAW;IAE3C,OAAO,CAAC,QAAQ,CAAC,MAAM;IADnC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;gBACS,MAAM,GAAE,oBAAyB;IAKxD,KAAK,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAq1BpE"}