@vgai/engine 0.5.13 → 0.5.14

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 (192) hide show
  1. package/dist/adapter/adapter-module.d.ts +447 -0
  2. package/dist/adapter/adapter-module.d.ts.map +1 -0
  3. package/dist/adapter/adapter-module.js +308 -0
  4. package/dist/adapter/authoring.d.ts +357 -10
  5. package/dist/adapter/authoring.d.ts.map +1 -1
  6. package/dist/adapter/authoring.js +87 -1
  7. package/dist/adapter/constraint.d.ts +9 -3
  8. package/dist/adapter/constraint.d.ts.map +1 -1
  9. package/dist/adapter/finders/finder-result.d.ts +28 -0
  10. package/dist/adapter/finders/finder-result.d.ts.map +1 -0
  11. package/dist/adapter/finders/finder-result.js +10 -0
  12. package/dist/adapter/finders/index.d.ts +38 -0
  13. package/dist/adapter/finders/index.d.ts.map +1 -0
  14. package/dist/adapter/finders/index.js +41 -0
  15. package/dist/adapter/finders/prefabs-from-stories.d.ts +64 -0
  16. package/dist/adapter/finders/prefabs-from-stories.d.ts.map +1 -0
  17. package/dist/adapter/finders/prefabs-from-stories.js +92 -0
  18. package/dist/adapter/finders/scenes-from-entrypoint-selection.d.ts +67 -0
  19. package/dist/adapter/finders/scenes-from-entrypoint-selection.d.ts.map +1 -0
  20. package/dist/adapter/finders/scenes-from-entrypoint-selection.js +226 -0
  21. package/dist/adapter/first-party-systems.d.ts.map +1 -1
  22. package/dist/adapter/first-party-systems.js +29 -0
  23. package/dist/adapter/index.d.ts +7 -3
  24. package/dist/adapter/index.d.ts.map +1 -1
  25. package/dist/adapter/index.js +5 -2
  26. package/dist/adapter/ingest/contract-system-adapters.d.ts +24 -1
  27. package/dist/adapter/ingest/contract-system-adapters.d.ts.map +1 -1
  28. package/dist/adapter/ingest/contract-system-adapters.js +100 -34
  29. package/dist/adapter/ingest/game-contract.d.ts +188 -2
  30. package/dist/adapter/ingest/game-contract.d.ts.map +1 -1
  31. package/dist/adapter/ingest/game-contract.js +107 -0
  32. package/dist/adapter/ingest/mount-readiness.d.ts +84 -0
  33. package/dist/adapter/ingest/mount-readiness.d.ts.map +1 -0
  34. package/dist/adapter/ingest/mount-readiness.js +81 -0
  35. package/dist/adapter/ingest/scene-capture.d.ts +91 -2
  36. package/dist/adapter/ingest/scene-capture.d.ts.map +1 -1
  37. package/dist/adapter/ingest/scene-capture.js +110 -18
  38. package/dist/adapter/ingest/structural-ids.d.ts +11 -5
  39. package/dist/adapter/ingest/structural-ids.d.ts.map +1 -1
  40. package/dist/adapter/ingest/structural-ids.js +18 -9
  41. package/dist/adapter/ingest/upstream-pin.d.ts +4 -2
  42. package/dist/adapter/ingest/upstream-pin.d.ts.map +1 -1
  43. package/dist/adapter/ingest/upstream-pin.js +4 -2
  44. package/dist/adapter/ingest/visible-capture-window.d.ts +116 -0
  45. package/dist/adapter/ingest/visible-capture-window.d.ts.map +1 -0
  46. package/dist/adapter/ingest/visible-capture-window.js +141 -0
  47. package/dist/adapter/loop-gate-report.d.ts +3 -4
  48. package/dist/adapter/loop-gate-report.d.ts.map +1 -1
  49. package/dist/adapter/loop-gate-report.js +3 -4
  50. package/dist/adapter/root-adapter.d.ts +22 -2
  51. package/dist/adapter/root-adapter.d.ts.map +1 -1
  52. package/dist/adapter/setup-three-root-adapter.d.ts.map +1 -1
  53. package/dist/adapter/setup-three-root-adapter.js +15 -0
  54. package/dist/adapter/system-adapter.d.ts +161 -2
  55. package/dist/adapter/system-adapter.d.ts.map +1 -1
  56. package/dist/adapter/system-adapter.js +18 -1
  57. package/dist/animation/camera-ownership.d.ts +4 -2
  58. package/dist/animation/camera-ownership.d.ts.map +1 -1
  59. package/dist/animation/camera-ownership.js +58 -1
  60. package/dist/animation/runtime-inspection.d.ts +70 -0
  61. package/dist/animation/runtime-inspection.d.ts.map +1 -0
  62. package/dist/animation/runtime-inspection.js +25 -0
  63. package/dist/animation/xstate-animation-binding.d.ts +9 -1
  64. package/dist/animation/xstate-animation-binding.d.ts.map +1 -1
  65. package/dist/animation/xstate-animation-binding.js +48 -1
  66. package/dist/asset-formats/material.d.ts +1 -1
  67. package/dist/asset-formats/mesh.d.ts +1 -1
  68. package/dist/asset-formats/particles.d.ts +13 -0
  69. package/dist/asset-formats/particles.d.ts.map +1 -1
  70. package/dist/asset-formats/particles.js +28 -0
  71. package/dist/behavior/xstate-inspection.d.ts +24 -0
  72. package/dist/behavior/xstate-inspection.d.ts.map +1 -0
  73. package/dist/behavior/xstate-inspection.js +25 -0
  74. package/dist/core/game-loop.d.ts +7 -5
  75. package/dist/core/game-loop.d.ts.map +1 -1
  76. package/dist/core/game-loop.js +39 -18
  77. package/dist/core/types.d.ts +11 -12
  78. package/dist/core/types.d.ts.map +1 -1
  79. package/dist/data/data-asset.js +1 -1
  80. package/dist/dev/instruments.d.ts.map +1 -1
  81. package/dist/dev/instruments.js +5 -1
  82. package/dist/dev/render-debug-adapter.d.ts +19 -2
  83. package/dist/dev/render-debug-adapter.d.ts.map +1 -1
  84. package/dist/dev/render-debug-adapter.js +10 -0
  85. package/dist/ecs/user-data.d.ts +10 -2
  86. package/dist/ecs/user-data.d.ts.map +1 -1
  87. package/dist/ecs/user-data.js +6 -2
  88. package/dist/input/binding-identity.d.ts +10 -0
  89. package/dist/input/binding-identity.d.ts.map +1 -0
  90. package/dist/input/binding-identity.js +36 -0
  91. package/dist/input/input-manager.d.ts +18 -185
  92. package/dist/input/input-manager.d.ts.map +1 -1
  93. package/dist/input/input-manager.js +78 -68
  94. package/dist/manifest/load.d.ts +14 -0
  95. package/dist/manifest/load.d.ts.map +1 -1
  96. package/dist/manifest/load.js +6 -1
  97. package/dist/manifest/schema.d.ts +18 -0
  98. package/dist/manifest/schema.d.ts.map +1 -1
  99. package/dist/manifest/schema.js +64 -7
  100. package/dist/pixi/authoring.d.ts +27 -0
  101. package/dist/pixi/authoring.d.ts.map +1 -1
  102. package/dist/pixi/authoring.js +10 -3
  103. package/dist/pixi/index.d.ts +1 -1
  104. package/dist/pixi/index.d.ts.map +1 -1
  105. package/dist/pixi/index.js +1 -1
  106. package/dist/pixi/ingest.d.ts +8 -0
  107. package/dist/pixi/ingest.d.ts.map +1 -1
  108. package/dist/pixi/ingest.js +10 -1
  109. package/dist/pixi/render-pass-bracket.d.ts +56 -0
  110. package/dist/pixi/render-pass-bracket.d.ts.map +1 -0
  111. package/dist/pixi/render-pass-bracket.js +98 -0
  112. package/dist/pixi/scene-capture.d.ts +32 -1
  113. package/dist/pixi/scene-capture.d.ts.map +1 -1
  114. package/dist/pixi/scene-capture.js +21 -9
  115. package/dist/pixi/system-adapters.d.ts +29 -0
  116. package/dist/pixi/system-adapters.d.ts.map +1 -1
  117. package/dist/pixi/system-adapters.js +27 -0
  118. package/dist/render/particles-factory.d.ts +16 -2
  119. package/dist/render/particles-factory.d.ts.map +1 -1
  120. package/dist/render/particles-factory.js +88 -5
  121. package/dist/render/soft-particle-depth.d.ts +149 -0
  122. package/dist/render/soft-particle-depth.d.ts.map +1 -0
  123. package/dist/render/soft-particle-depth.js +305 -0
  124. package/dist/render/voxel-surface.d.ts +117 -0
  125. package/dist/render/voxel-surface.d.ts.map +1 -0
  126. package/dist/render/voxel-surface.js +263 -0
  127. package/dist/runtime/create-runtime.js +7 -0
  128. package/dist/runtime/debug-bridge.d.ts +15 -15
  129. package/dist/runtime/debug-bridge.d.ts.map +1 -1
  130. package/dist/runtime/debug-bridge.js +27 -26
  131. package/dist/runtime/game.d.ts.map +1 -1
  132. package/dist/runtime/game.js +1 -2
  133. package/dist/setup/setup-particles.d.ts.map +1 -1
  134. package/dist/setup/setup-particles.js +9 -0
  135. package/dist/world3d-react/r3f-adapter.d.ts.map +1 -1
  136. package/dist/world3d-react/r3f-adapter.js +42 -3
  137. package/dist/world3d-react/rapier-physics-bridge.d.ts.map +1 -1
  138. package/dist/world3d-react/rapier-physics-bridge.js +201 -11
  139. package/dist-config/config.js.map +1 -1
  140. package/package.json +4 -2
  141. package/schemas/engine-capabilities.json +12 -12
  142. package/schemas/vgai-project.schema.json +41 -2
  143. package/src/adapter/adapter-module.ts +607 -0
  144. package/src/adapter/authoring.ts +440 -10
  145. package/src/adapter/constraint.ts +10 -3
  146. package/src/adapter/finders/finder-result.ts +29 -0
  147. package/src/adapter/finders/index.ts +62 -0
  148. package/src/adapter/finders/prefabs-from-stories.ts +142 -0
  149. package/src/adapter/finders/scenes-from-entrypoint-selection.ts +304 -0
  150. package/src/adapter/first-party-systems.ts +30 -0
  151. package/src/adapter/index.ts +32 -1
  152. package/src/adapter/ingest/contract-system-adapters.ts +116 -32
  153. package/src/adapter/ingest/game-contract.ts +265 -2
  154. package/src/adapter/ingest/mount-readiness.ts +140 -0
  155. package/src/adapter/ingest/scene-capture.ts +199 -22
  156. package/src/adapter/ingest/structural-ids.ts +21 -9
  157. package/src/adapter/ingest/upstream-pin.ts +4 -2
  158. package/src/adapter/ingest/visible-capture-window.ts +213 -0
  159. package/src/adapter/loop-gate-report.ts +3 -4
  160. package/src/adapter/root-adapter.ts +22 -2
  161. package/src/adapter/setup-three-root-adapter.ts +16 -0
  162. package/src/adapter/system-adapter.ts +188 -2
  163. package/src/animation/camera-ownership.ts +68 -3
  164. package/src/animation/runtime-inspection.ts +104 -0
  165. package/src/animation/xstate-animation-binding.ts +53 -1
  166. package/src/asset-formats/particles.ts +31 -0
  167. package/src/behavior/xstate-inspection.ts +51 -0
  168. package/src/core/game-loop.ts +39 -17
  169. package/src/core/types.ts +11 -12
  170. package/src/data/data-asset.ts +1 -1
  171. package/src/dev/instruments.ts +5 -1
  172. package/src/dev/render-debug-adapter.ts +22 -2
  173. package/src/ecs/user-data.ts +10 -2
  174. package/src/input/binding-identity.ts +37 -0
  175. package/src/input/input-manager.ts +93 -68
  176. package/src/manifest/load.ts +23 -2
  177. package/src/manifest/schema.ts +76 -7
  178. package/src/pixi/authoring.ts +37 -5
  179. package/src/pixi/index.ts +2 -0
  180. package/src/pixi/ingest.ts +15 -2
  181. package/src/pixi/render-pass-bracket.ts +117 -0
  182. package/src/pixi/scene-capture.ts +63 -13
  183. package/src/pixi/system-adapters.ts +41 -0
  184. package/src/render/particles-factory.ts +89 -6
  185. package/src/render/soft-particle-depth.ts +336 -0
  186. package/src/render/voxel-surface.ts +358 -0
  187. package/src/runtime/create-runtime.ts +7 -0
  188. package/src/runtime/debug-bridge.ts +32 -31
  189. package/src/runtime/game.ts +1 -2
  190. package/src/setup/setup-particles.ts +9 -0
  191. package/src/world3d-react/r3f-adapter.tsx +48 -2
  192. package/src/world3d-react/rapier-physics-bridge.tsx +249 -11
@@ -1 +1 @@
1
- {"version":3,"file":"setup-particles.d.ts","sourceRoot":"","sources":["../../src/setup/setup-particles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,eAAe,CAAC;CAClC;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,gBAAgB,CAKnE"}
1
+ {"version":3,"file":"setup-particles.d.ts","sourceRoot":"","sources":["../../src/setup/setup-particles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAG/C,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,eAAe,CAAC;CAClC;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,gBAAgB,CAanE"}
@@ -1,4 +1,5 @@
1
1
  import { BatchedRenderer } from 'three.quarks';
2
+ import { farDepthTexture } from '../render/soft-particle-depth';
2
3
  /**
3
4
  * Creates the three.quarks BatchedRenderer for GPU particle systems.
4
5
  *
@@ -11,6 +12,14 @@ import { BatchedRenderer } from 'three.quarks';
11
12
  */
12
13
  export function setupParticles(scene) {
13
14
  const batchedRenderer = new BatchedRenderer();
15
+ // Seed the soft-particle depth sampler BEFORE any batch exists, so every
16
+ // batch this renderer later builds inherits it (`BatchedRenderer.addSystem`
17
+ // applies `this.depthTexture` to each new batch). A `softParticles` batch
18
+ // whose `depthTexture` uniform is still `null` samples black and multiplies
19
+ // every particle away; the far-depth default makes that same batch render
20
+ // exactly as an unfaded one until a real depth pass supplies the scene's own.
21
+ // See `render/soft-particle-depth.ts`.
22
+ batchedRenderer.setDepthTexture(farDepthTexture());
14
23
  scene.add(batchedRenderer);
15
24
  return { batchedRenderer };
16
25
  }
@@ -1 +1 @@
1
- {"version":3,"file":"r3f-adapter.d.ts","sourceRoot":"","sources":["../../src/world3d-react/r3f-adapter.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AASH,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,KAAK,EAAoB,WAAW,EAAoB,MAAM,YAAY,CAAC;AAalF,OAAO,EAA4B,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAYvF,sEAAsE;AACtE,MAAM,WAAW,uBAAuB;IACtC,qEAAqE;IACrE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;;uBAEmB;IACnB,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAC5B;;;;0CAIsC;IACtC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClD;;;iDAG6C;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;CACrD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,WAAW,CAge9E"}
1
+ {"version":3,"file":"r3f-adapter.d.ts","sourceRoot":"","sources":["../../src/world3d-react/r3f-adapter.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAUH,OAAO,EAA2B,KAAK,SAAS,EAAsB,MAAM,OAAO,CAAC;AACpF,OAAO,KAAK,EAAoB,WAAW,EAAoB,MAAM,YAAY,CAAC;AAclF,OAAO,EAA4B,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AA2CvF,sEAAsE;AACtE,MAAM,WAAW,uBAAuB;IACtC,qEAAqE;IACrE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;;uBAEmB;IACnB,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAC5B;;;;0CAIsC;IACtC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClD;;;iDAG6C;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;CACrD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,WAAW,CA6e9E"}
@@ -18,18 +18,49 @@
18
18
  * project guarantees via its Vite `resolve.dedupe: ['three', 'react',
19
19
  * 'react-dom']` (see `examples/r3f-first-party/vite.config.ts`).
20
20
  */
21
- import { advance, createRoot, extend, events as pointerEvents, } from '@react-three/fiber';
22
- import { createElement } from 'react';
21
+ import { advance, createRoot, extend, events as pointerEvents, useFrame, } from '@react-three/fiber';
22
+ import { createElement, Fragment, useEffect, useMemo } from 'react';
23
23
  import { registerRenderVitals } from '../dev/register-render-vitals';
24
24
  import { createRenderDebugAdapter, frameCaptureContextFor, } from '../dev/render-debug-adapter';
25
25
  import { collectRenderMemory } from '../dev/render-memory';
26
26
  import { RENDER_SUBMIT_PHASE } from '../dev/render-vitals';
27
27
  import { createWebGLFrameCapture } from '../dev/webgl-frame-capture';
28
28
  import { WorldProvider } from '../react/world-state';
29
+ import { createSoftParticleDepthPass } from '../render/soft-particle-depth';
29
30
  import { devLayersEnabled } from '../runtime/dev-layers';
30
31
  import { EngineBridge } from './engine-bridge';
31
32
  import { applyWorldRendererConfig } from './renderer-config';
32
33
  import { createR3FRootContext } from './world-context';
34
+ /**
35
+ * Scene depth for any soft-particle system this world mounted, drawn between
36
+ * gameplay and the draw.
37
+ *
38
+ * `useFrame`'s priority is the whole reason this is a component rather than an
39
+ * engine phase: `systems.run(dt)` below finishes BEFORE `advance()`, and
40
+ * `advance()` is where every `useFrame` gameplay callback moves the frame's
41
+ * transforms — depth taken from an engine phase would be one frame stale.
42
+ * Priority `0` puts it after every negative-priority callback (fiber sorts
43
+ * subscribers by priority) and before both a positive-priority composer and
44
+ * fiber's own `state.gl.render` — and, unlike a positive priority, it does NOT
45
+ * flip fiber into manual-render mode (`internal.priority` only counts
46
+ * subscribers with `priority > 0`), so mounting it can never stop an ordinary
47
+ * world from drawing itself.
48
+ *
49
+ * Rendered as the LAST child of the adapter's tree so its subscription lands
50
+ * after the world's own (React completes children before siblings, and fiber's
51
+ * sort is stable) — the tie-break among priority-0 callbacks is insertion
52
+ * order.
53
+ *
54
+ * Costs nothing while no soft-particle system is armed — see
55
+ * `../render/soft-particle-depth.ts` for what "armed" means and what the pass
56
+ * spends when it is.
57
+ */
58
+ function SoftParticleDepth() {
59
+ const pass = useMemo(() => createSoftParticleDepthPass(), []);
60
+ useEffect(() => () => pass.dispose(), [pass]);
61
+ useFrame(({ gl, scene, camera }) => pass.render(gl, scene, camera), 0);
62
+ return null;
63
+ }
33
64
  /**
34
65
  * Build a `RootAdapter` that mounts `options.content` through
35
66
  * react-three-fiber, gated entirely by the host's own loop and rendering
@@ -214,7 +245,10 @@ export function createR3FAdapter(options) {
214
245
  // hosts, so the provider is conditional and those hooks stay the inert
215
246
  // no-ops they already document themselves to be.
216
247
  const game = runtime.ctx.game;
217
- root.render(createElement(EngineBridge.Provider, { value: bridge }, game ? createElement(WorldProvider, { game }, content) : content));
248
+ // `SoftParticleDepth` trails the world's own tree deliberately see its
249
+ // docblock for why the subscription must land last.
250
+ const world = createElement(Fragment, null, content, createElement(SoftParticleDepth, { key: 'vgai-soft-particle-depth' }));
251
+ root.render(createElement(EngineBridge.Provider, { value: bridge }, game ? createElement(WorldProvider, { game }, world) : world));
218
252
  // A reconcile-time crash (e.g. a missing `extend` catalogue entry)
219
253
  // surfaces as an uncaught window error and `onCreated` never fires —
220
254
  // without this guard, `mount()` would await `statePromise` FOREVER and
@@ -401,6 +435,11 @@ export function createR3FAdapter(options) {
401
435
  return live().camera;
402
436
  },
403
437
  drivesOwnLoop: false,
438
+ // REPORTED for a host that draws this scene with a renderer other than
439
+ // the one it mounted us against — see `MountedThreeRoot.rendererConfig`.
440
+ // It is the same object already applied to `host.renderer` above; the
441
+ // report never applies anything itself.
442
+ rendererConfig: rendererConfig,
404
443
  // Adapter surface: `debug` (the shared game registry) and, when a real
405
444
  // WebGL2 context exists, `renderDebug` are engine-seeded. Game code
406
445
  // adds its own capabilities via `ctx.registerSystemAdapter` exactly
@@ -1 +1 @@
1
- {"version":3,"file":"rapier-physics-bridge.d.ts","sourceRoot":"","sources":["../../src/world3d-react/rapier-physics-bridge.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAYH,MAAM,WAAW,wBAAwB;IACvC;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAClD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,aAAa,EAAE,EAAE,wBAAwB,GAAG,IAAI,CAkDrF"}
1
+ {"version":3,"file":"rapier-physics-bridge.d.ts","sourceRoot":"","sources":["../../src/world3d-react/rapier-physics-bridge.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAkBH,MAAM,WAAW,wBAAwB;IACvC;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAClD;AAkCD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,aAAa,EAAE,EAAE,wBAAwB,GAAG,IAAI,CA0PrF"}
@@ -60,8 +60,32 @@
60
60
  */
61
61
  import { useRapier } from '@react-three/rapier';
62
62
  import { useEffect } from 'react';
63
+ import * as THREE from 'three';
63
64
  import { createRapierBodyEditing, } from '../adapter/rapier-physics-adapter';
64
65
  import { useGameContext } from './engine-bridge';
66
+ function lateEntityObject(states, nodeId) {
67
+ let found;
68
+ for (const state of states) {
69
+ state.object.traverse((candidate) => {
70
+ if (!found && candidate.userData['entityId'] === nodeId)
71
+ found = candidate;
72
+ });
73
+ if (found)
74
+ return found;
75
+ }
76
+ return undefined;
77
+ }
78
+ function owningBody(object, states) {
79
+ const byObject = new Map();
80
+ for (const state of states)
81
+ byObject.set(state.object, state.rigidBody);
82
+ for (let node = object; node; node = node.parent) {
83
+ const body = byObject.get(node);
84
+ if (body)
85
+ return body;
86
+ }
87
+ return undefined;
88
+ }
65
89
  /**
66
90
  * Register this R3F world's `@react-three/rapier` physics as the game's
67
91
  * `SystemAdapters.physics`. Mount it once, INSIDE `<Physics>` (it reads
@@ -69,7 +93,7 @@ import { useGameContext } from './engine-bridge';
69
93
  */
70
94
  export function RapierPhysicsBridge({ onDebugChange }) {
71
95
  const ctx = useGameContext();
72
- const { rigidBodyStates } = useRapier();
96
+ const { colliderStates, rapier, rigidBodyStates, world } = useRapier();
73
97
  const registerSystemAdapter = ctx.registerSystemAdapter;
74
98
  useEffect(() => {
75
99
  if (!registerSystemAdapter)
@@ -96,25 +120,191 @@ export function RapierPhysicsBridge({ onDebugChange }) {
96
120
  * `setSceneCamera`), so a destructured copy would be permanently absent.
97
121
  */
98
122
  const bodyFor = (nodeId) => {
99
- const object = ctx.sceneIndex?.byEntityId(nodeId);
123
+ const indexed = ctx.sceneIndex?.byEntityId(nodeId);
124
+ const object = indexed ?? lateEntityObject(rigidBodyStates.values(), nodeId);
125
+ if (!indexed && object) {
126
+ // The editor assigns its stable authoring entity ids AFTER Fiber's
127
+ // first commit, while the root's SceneIndex is constructed during
128
+ // that commit. Resolve the one late id inside the library-owned body
129
+ // subtrees and immediately reindex it; subsequent gestures take the
130
+ // normal indexed path. This is the SceneIndex's documented escape
131
+ // hatch for a userData id written after construction, not a parallel
132
+ // scene mirror.
133
+ ctx.sceneIndex?.reindex(object);
134
+ }
100
135
  if (!object)
101
136
  return undefined;
102
- const byObject = new Map();
103
- for (const state of rigidBodyStates.values())
104
- byObject.set(state.object, state.rigidBody);
105
- for (let node = object; node; node = node.parent) {
106
- const body = byObject.get(node);
107
- if (body)
108
- return body;
137
+ return owningBody(object, rigidBodyStates.values());
138
+ };
139
+ const colliderShape = (collider) => {
140
+ switch (collider.shapeType()) {
141
+ case rapier.ShapeType.Cuboid: {
142
+ const halfExtents = collider.halfExtents();
143
+ return { type: 'cuboid', halfExtents: [halfExtents.x, halfExtents.y, halfExtents.z] };
144
+ }
145
+ case rapier.ShapeType.Ball:
146
+ return { type: 'ball', radius: collider.radius() };
147
+ case rapier.ShapeType.Capsule:
148
+ return {
149
+ type: 'capsule',
150
+ halfHeight: collider.halfHeight(),
151
+ radius: collider.radius(),
152
+ };
153
+ default:
154
+ return null;
155
+ }
156
+ };
157
+ const colliders = (nodeId) => {
158
+ const body = bodyFor(nodeId);
159
+ if (!body)
160
+ return [];
161
+ const result = [];
162
+ for (const state of colliderStates.values()) {
163
+ if (state.collider.parent()?.handle !== body.handle)
164
+ continue;
165
+ const shape = colliderShape(state.collider);
166
+ if (!shape)
167
+ continue;
168
+ state.object.updateWorldMatrix(true, false);
169
+ const position = state.collider.translation();
170
+ const rotation = state.collider.rotation();
171
+ const scale = state.object.getWorldScale(new THREE.Vector3());
172
+ result.push({
173
+ id: String(state.collider.handle),
174
+ shape,
175
+ position: [position.x, position.y, position.z],
176
+ rotation: [rotation.x, rotation.y, rotation.z, rotation.w],
177
+ scale: [Math.abs(scale.x), Math.abs(scale.y), Math.abs(scale.z)],
178
+ sensor: state.collider.isSensor(),
179
+ });
180
+ }
181
+ return result.sort((a, b) => Number(a.id) - Number(b.id));
182
+ };
183
+ const previewCollider = (colliderId, shape) => {
184
+ const collider = [...colliderStates.values()].find((state) => String(state.collider.handle) === colliderId)?.collider;
185
+ if (!collider || colliderShape(collider)?.type !== shape.type)
186
+ return;
187
+ switch (shape.type) {
188
+ case 'cuboid':
189
+ collider.setHalfExtents({
190
+ x: shape.halfExtents[0],
191
+ y: shape.halfExtents[1],
192
+ z: shape.halfExtents[2],
193
+ });
194
+ break;
195
+ case 'ball':
196
+ collider.setRadius(shape.radius);
197
+ break;
198
+ case 'capsule':
199
+ collider.setHalfHeight(shape.halfHeight);
200
+ collider.setRadius(shape.radius);
201
+ break;
109
202
  }
110
- return undefined;
203
+ };
204
+ const jointType = (type) => {
205
+ switch (type) {
206
+ case rapier.JointType.Revolute:
207
+ return 'revolute';
208
+ case rapier.JointType.Fixed:
209
+ return 'fixed';
210
+ case rapier.JointType.Prismatic:
211
+ return 'prismatic';
212
+ case rapier.JointType.Rope:
213
+ return 'rope';
214
+ case rapier.JointType.Spring:
215
+ return 'spring';
216
+ case rapier.JointType.Spherical:
217
+ return 'spherical';
218
+ default:
219
+ return 'generic';
220
+ }
221
+ };
222
+ const tuple3 = (value) => [
223
+ value.x,
224
+ value.y,
225
+ value.z,
226
+ ];
227
+ const tuple4 = (value) => [value.x, value.y, value.z, value.w];
228
+ const worldAnchor = (body, anchor) => {
229
+ const point = new THREE.Vector3(anchor.x, anchor.y, anchor.z)
230
+ .applyQuaternion(new THREE.Quaternion(...tuple4(body.rotation())))
231
+ .add(new THREE.Vector3(...tuple3(body.translation())));
232
+ return tuple3(point);
233
+ };
234
+ const jointLimits = (joint, type) => {
235
+ if (type !== 'revolute' && type !== 'prismatic')
236
+ return {};
237
+ const unit = joint;
238
+ return unit.limitsEnabled()
239
+ ? { limits: { min: unit.limitsMin(), max: unit.limitsMax() } }
240
+ : {};
241
+ };
242
+ const jointAxis = (joint, type, body) => {
243
+ if (type !== 'revolute' && type !== 'prismatic')
244
+ return {};
245
+ const frame = joint.frameX1();
246
+ const axis = new THREE.Vector3(1, 0, 0).applyQuaternion(new THREE.Quaternion(frame.x, frame.y, frame.z, frame.w));
247
+ const worldAxis = axis
248
+ .clone()
249
+ .applyQuaternion(new THREE.Quaternion(...tuple4(body.rotation())));
250
+ return { axis: tuple3(axis), worldAxis: tuple3(worldAxis) };
251
+ };
252
+ const jointSnapshot = (joint) => {
253
+ const body1 = joint.body1();
254
+ const body2 = joint.body2();
255
+ const anchor1 = joint.anchor1();
256
+ const anchor2 = joint.anchor2();
257
+ const type = jointType(joint.type());
258
+ return {
259
+ id: String(joint.handle),
260
+ type,
261
+ body1: String(body1.handle),
262
+ body2: String(body2.handle),
263
+ anchor1: tuple3(anchor1),
264
+ anchor2: tuple3(anchor2),
265
+ worldAnchor1: worldAnchor(body1, anchor1),
266
+ worldAnchor2: worldAnchor(body2, anchor2),
267
+ body1Position: tuple3(body1.translation()),
268
+ body2Position: tuple3(body2.translation()),
269
+ body1Rotation: tuple4(body1.rotation()),
270
+ body2Rotation: tuple4(body2.rotation()),
271
+ ...jointAxis(joint, type, body1),
272
+ ...jointLimits(joint, type),
273
+ contactsEnabled: joint.contactsEnabled(),
274
+ };
275
+ };
276
+ const joints = (nodeId) => {
277
+ const body = bodyFor(nodeId);
278
+ if (!body)
279
+ return [];
280
+ const result = [];
281
+ world.impulseJoints.forEachJointHandleAttachedToRigidBody(body.handle, (handle) => {
282
+ const joint = world.impulseJoints.get(handle);
283
+ if (joint)
284
+ result.push(jointSnapshot(joint));
285
+ });
286
+ return result.sort((a, b) => Number(a.id) - Number(b.id));
287
+ };
288
+ const previewJointAnchor = (jointId, endpoint, anchor) => {
289
+ const joint = world.impulseJoints.get(Number(jointId));
290
+ if (!joint)
291
+ return;
292
+ const value = { x: anchor[0], y: anchor[1], z: anchor[2] };
293
+ if (endpoint === 0)
294
+ joint.setAnchor1(value);
295
+ else
296
+ joint.setAnchor2(value);
111
297
  };
112
298
  const adapter = {
113
299
  ...createRapierBodyEditing(bodyFor),
114
300
  setDebugDrawEnabled: (enabled) => onDebugChange(enabled),
301
+ colliders,
302
+ previewCollider,
303
+ joints,
304
+ previewJointAnchor,
115
305
  };
116
306
  registerSystemAdapter('physics', adapter);
117
307
  return () => registerSystemAdapter('physics', undefined);
118
- }, [ctx, registerSystemAdapter, rigidBodyStates, onDebugChange]);
308
+ }, [colliderStates, ctx, onDebugChange, rapier, registerSystemAdapter, rigidBodyStates, world]);
119
309
  return null;
120
310
  }