@vgai/engine 0.5.12 → 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
@@ -8,15 +8,21 @@ function kindOf(o) {
8
8
  return 'text';
9
9
  return 'container';
10
10
  }
11
+ /** Deterministic structural-path ids: `w2d:<path>:<kind>:<label>`. */
12
+ export const STRUCTURAL_CANVAS_IDENTITY = {
13
+ idFor: (object, path) => `w2d:${path.join('/')}:${kindOf(object)}:${object.label ?? ''}`,
14
+ };
11
15
  export class AuthoringAdapter2D {
12
16
  root;
13
17
  byId = new Map();
14
18
  overlay = {};
15
19
  dirty = false;
20
+ identity;
16
21
  constructor(root, opts = {}) {
17
22
  this.root = root;
18
23
  if (opts.overlay)
19
24
  this.overlay = opts.overlay;
25
+ this.identity = opts.identity ?? STRUCTURAL_CANVAS_IDENTITY;
20
26
  this.refresh();
21
27
  }
22
28
  /**
@@ -30,21 +36,22 @@ export class AuthoringAdapter2D {
30
36
  */
31
37
  reindex() {
32
38
  this.byId.clear();
39
+ this.identity.beginWalk?.();
33
40
  let count = 0;
34
41
  let sprites = 0;
35
42
  const visit = (o, path) => {
36
- const id = `w2d:${path}:${kindOf(o)}:${o.label ?? ''}`;
43
+ const id = this.identity.idFor(o, path);
37
44
  o.__authId = id;
38
45
  this.byId.set(id, o);
39
46
  count++;
40
47
  if (kindOf(o).includes('sprite'))
41
48
  sprites++;
42
49
  o.children.forEach((c, i) => {
43
- visit(c, `${path}/${i}`);
50
+ visit(c, [...path, i]);
44
51
  });
45
52
  };
46
53
  this.root.children.forEach((c, i) => {
47
- visit(c, `${i}`);
54
+ visit(c, [i]);
48
55
  });
49
56
  return { count, sprites };
50
57
  }
@@ -7,7 +7,7 @@
7
7
  * in-realm mount, the live display-tree authoring adapter, and the
8
8
  * Rapier-2D handle registry the editor's transform coordination reads.
9
9
  */
10
- export { AuthoringAdapter2D, type EditorNode2D, type Overlay2D, type Override2D, type Property2D, type Transform2DValue, } from './authoring';
10
+ export { AuthoringAdapter2D, type CanvasIdentity, type EditorNode2D, type Overlay2D, type Override2D, type Property2D, STRUCTURAL_CANVAS_IDENTITY, type Transform2DValue, } from './authoring';
11
11
  export { type IngestGame2D, type IngestMount2D, mountIngestGame2D } from './ingest';
12
12
  export { createPhysics2DRegistry, type Physics2DRefs, type Physics2DRegistry, } from './physics-registry';
13
13
  export { type CapturedRuntime2D, installSceneCapture2D, type SceneCapture2DHandle, } from './scene-capture';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pixi/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,kBAAkB,EAClB,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,gBAAgB,GACtB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACpF,OAAO,EACL,uBAAuB,EACvB,KAAK,aAAa,EAClB,KAAK,iBAAiB,GACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,iBAAiB,EACtB,qBAAqB,EACrB,KAAK,oBAAoB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,sBAAsB,EAAE,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pixi/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,kBAAkB,EAClB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,UAAU,EACf,0BAA0B,EAC1B,KAAK,gBAAgB,GACtB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACpF,OAAO,EACL,uBAAuB,EACvB,KAAK,aAAa,EAClB,KAAK,iBAAiB,GACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,iBAAiB,EACtB,qBAAqB,EACrB,KAAK,oBAAoB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,sBAAsB,EAAE,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -7,7 +7,7 @@
7
7
  * in-realm mount, the live display-tree authoring adapter, and the
8
8
  * Rapier-2D handle registry the editor's transform coordination reads.
9
9
  */
10
- export { AuthoringAdapter2D, } from './authoring';
10
+ export { AuthoringAdapter2D, STRUCTURAL_CANVAS_IDENTITY, } from './authoring';
11
11
  export { mountIngestGame2D } from './ingest';
12
12
  export { createPhysics2DRegistry, } from './physics-registry';
13
13
  export { installSceneCapture2D, } from './scene-capture';
@@ -1,3 +1,4 @@
1
+ import type { VisibleCaptureWindow } from '../adapter/ingest/visible-capture-window';
1
2
  import { type SceneCapture2DHandle } from './scene-capture';
2
3
  /** A registered unmodified PixiJS game (the Pixi analog of `IngestGame`). */
3
4
  export interface IngestGame2D {
@@ -22,8 +23,15 @@ export interface IngestMount2D {
22
23
  * instance, runs the game's `load()`, waits for the game to render its first
23
24
  * frame (capturing its live stage), and exposes loop gating + cleanup. A game
24
25
  * whose pixi the trap cannot reach never captures, and the mount FAILS by name.
26
+ *
27
+ * `onWait` is the three lane's own seam (`ingest-root-adapter.ts` passes
28
+ * `setCaptureWait`): the capture window PARKS while the tab is hidden, and a
29
+ * parked wait is otherwise indistinguishable from a hung mount at every door.
30
+ * Threading it here is what lets `vgai status` say "waiting for the first
31
+ * visible frame — the tab is hidden" over a canvas ingest too.
25
32
  */
26
33
  export declare function mountIngestGame2D(pixiNamespace: unknown, game: IngestGame2D, opts?: {
27
34
  captureTimeoutMs?: number;
35
+ onWait?: (wait: VisibleCaptureWindow | null) => void;
28
36
  }): Promise<IngestMount2D>;
29
37
  //# sourceMappingURL=ingest.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ingest.d.ts","sourceRoot":"","sources":["../../src/pixi/ingest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEnF,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,yCAAyC;IACzC,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,oBAAoB,CAAC;IAC9B,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,OAAO,EACtB,IAAI,EAAE,YAAY,EAClB,IAAI,GAAE;IAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAO,GACvC,OAAO,CAAC,aAAa,CAAC,CAwBxB"}
1
+ {"version":3,"file":"ingest.d.ts","sourceRoot":"","sources":["../../src/pixi/ingest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AACrF,OAAO,EAAyB,KAAK,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEnF,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,yCAAyC;IACzC,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,oBAAoB,CAAC;IAC9B,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,OAAO,EACtB,IAAI,EAAE,YAAY,EAClB,IAAI,GAAE;IACJ,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,oBAAoB,GAAG,IAAI,KAAK,IAAI,CAAC;CACjD,GACL,OAAO,CAAC,aAAa,CAAC,CA2BxB"}
@@ -5,6 +5,12 @@ import { installSceneCapture2D } from './scene-capture';
5
5
  * instance, runs the game's `load()`, waits for the game to render its first
6
6
  * frame (capturing its live stage), and exposes loop gating + cleanup. A game
7
7
  * whose pixi the trap cannot reach never captures, and the mount FAILS by name.
8
+ *
9
+ * `onWait` is the three lane's own seam (`ingest-root-adapter.ts` passes
10
+ * `setCaptureWait`): the capture window PARKS while the tab is hidden, and a
11
+ * parked wait is otherwise indistinguishable from a hung mount at every door.
12
+ * Threading it here is what lets `vgai status` say "waiting for the first
13
+ * visible frame — the tab is hidden" over a canvas ingest too.
8
14
  */
9
15
  export async function mountIngestGame2D(pixiNamespace, game, opts = {}) {
10
16
  const capture = installSceneCapture2D(pixiNamespace);
@@ -17,7 +23,10 @@ export async function mountIngestGame2D(pixiNamespace, game, opts = {}) {
17
23
  }
18
24
  const timeout = opts.captureTimeoutMs ?? game.captureTimeoutMs ?? 8000;
19
25
  try {
20
- const rt = await capture.waitForCapture(timeout);
26
+ const rt = await capture.waitForCapture({
27
+ timeoutMs: timeout,
28
+ ...(opts.onWait ? { onWait: opts.onWait } : {}),
29
+ });
21
30
  return {
22
31
  stage: rt.stage,
23
32
  capture,
@@ -0,0 +1,56 @@
1
+ /**
2
+ * The render-pass BRACKET on the Pixi surface — the canvas-substrate answer to
3
+ * the question the three lane answers with the render accessor-trap's
4
+ * `setRenderPassHooks` (`adapter/ingest/scene-capture.ts`): *when does this
5
+ * renderer's pass begin and end?*
6
+ *
7
+ * ## Why the renderer's own runners, and not another wrap
8
+ *
9
+ * Pixi's `AbstractRenderer.render()` emits five runners in a fixed order —
10
+ * `prerender → renderStart → render → renderEnd → postrender` (verified in the
11
+ * installed pixi.js 8.19,
12
+ * `rendering/renderers/shared/system/AbstractRenderer.mjs`). EVERY GL draw the
13
+ * pass issues happens between the first and the last: the batcher draws under
14
+ * `render`, and even the back-buffer blit, the one draw that is easy to miss,
15
+ * runs under `renderStart`/`renderEnd` (`gl/GlBackBufferSystem.mjs`). So a
16
+ * listener added to `prerender` and `postrender` brackets the whole pass using
17
+ * the renderer's OWN published seam — no instance shadowing, no prototype
18
+ * patch, no ordering assumption beyond the one Pixi itself guarantees.
19
+ *
20
+ * `SystemRunner.add(item)` binds by METHOD NAME (`item[runnerName]` must
21
+ * exist) and `remove(item)` takes it back off, so installing and uninstalling
22
+ * is symmetric and touches nothing else on the renderer.
23
+ *
24
+ * ## Honest absence
25
+ *
26
+ * A renderer that publishes no such runners is not bracketed by guesswork:
27
+ * this returns `null`, and the caller treats that exactly like a missing
28
+ * WebGL2 context — the capability is absent, never faked.
29
+ */
30
+ import type { RenderPassHooks } from '../adapter/ingest/scene-capture';
31
+ /**
32
+ * Bracket a Pixi renderer's render pass with `hooks.before`/`hooks.after`.
33
+ *
34
+ * Returns the uninstall function, or `null` when this renderer publishes no
35
+ * `prerender`/`postrender` runners — the honest "cannot bracket this", which
36
+ * the caller reads as "no render-debug capability here".
37
+ *
38
+ * Neither hook may throw — the same contract the three lane's `RenderPassHooks`
39
+ * carries, and for a sharper reason here: these run as listeners on the
40
+ * renderer's own runners, so a throwing `before` aborts the game's frame AND
41
+ * skips the `postrender` emit that would have closed the pass. The assembly
42
+ * point (`ingest/ingest-render-debug.ts`) is where that contract is kept.
43
+ */
44
+ export declare function installPixiRenderPassBracket(renderer: unknown, hooks: RenderPassHooks): (() => void) | null;
45
+ /**
46
+ * The captured Pixi renderer's real WebGL2 context, or `undefined`.
47
+ *
48
+ * `WebGLRenderer.gl` is the renderer's own published field — `GlContextSystem`
49
+ * assigns it (`this._renderer.gl = gl`,
50
+ * `rendering/renderers/gl/context/GlContextSystem.mjs`) as part of
51
+ * initialisation, and `WebGLRenderer.d.ts` declares it. A WebGPU renderer, or
52
+ * a renderer that has not initialised a context, simply has none — which is the
53
+ * answer, not an error.
54
+ */
55
+ export declare function pixiRenderingContext(renderer: unknown): unknown;
56
+ //# sourceMappingURL=render-pass-bracket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-pass-bracket.d.ts","sourceRoot":"","sources":["../../src/pixi/render-pass-bracket.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AA0BvE;;;;;;;;;;;;GAYG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,OAAO,EACjB,KAAK,EAAE,eAAe,GACrB,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CA6BrB;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAG/D"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * The render-pass BRACKET on the Pixi surface — the canvas-substrate answer to
3
+ * the question the three lane answers with the render accessor-trap's
4
+ * `setRenderPassHooks` (`adapter/ingest/scene-capture.ts`): *when does this
5
+ * renderer's pass begin and end?*
6
+ *
7
+ * ## Why the renderer's own runners, and not another wrap
8
+ *
9
+ * Pixi's `AbstractRenderer.render()` emits five runners in a fixed order —
10
+ * `prerender → renderStart → render → renderEnd → postrender` (verified in the
11
+ * installed pixi.js 8.19,
12
+ * `rendering/renderers/shared/system/AbstractRenderer.mjs`). EVERY GL draw the
13
+ * pass issues happens between the first and the last: the batcher draws under
14
+ * `render`, and even the back-buffer blit, the one draw that is easy to miss,
15
+ * runs under `renderStart`/`renderEnd` (`gl/GlBackBufferSystem.mjs`). So a
16
+ * listener added to `prerender` and `postrender` brackets the whole pass using
17
+ * the renderer's OWN published seam — no instance shadowing, no prototype
18
+ * patch, no ordering assumption beyond the one Pixi itself guarantees.
19
+ *
20
+ * `SystemRunner.add(item)` binds by METHOD NAME (`item[runnerName]` must
21
+ * exist) and `remove(item)` takes it back off, so installing and uninstalling
22
+ * is symmetric and touches nothing else on the renderer.
23
+ *
24
+ * ## Honest absence
25
+ *
26
+ * A renderer that publishes no such runners is not bracketed by guesswork:
27
+ * this returns `null`, and the caller treats that exactly like a missing
28
+ * WebGL2 context — the capability is absent, never faked.
29
+ */
30
+ function runnerPair(renderer) {
31
+ if (!renderer || typeof renderer !== 'object')
32
+ return null;
33
+ const runners = renderer.runners;
34
+ const pre = runners?.prerender;
35
+ const post = runners?.postrender;
36
+ if (!pre || typeof pre.add !== 'function' || typeof pre.remove !== 'function')
37
+ return null;
38
+ if (!post || typeof post.add !== 'function' || typeof post.remove !== 'function')
39
+ return null;
40
+ return { pre, post };
41
+ }
42
+ /**
43
+ * Bracket a Pixi renderer's render pass with `hooks.before`/`hooks.after`.
44
+ *
45
+ * Returns the uninstall function, or `null` when this renderer publishes no
46
+ * `prerender`/`postrender` runners — the honest "cannot bracket this", which
47
+ * the caller reads as "no render-debug capability here".
48
+ *
49
+ * Neither hook may throw — the same contract the three lane's `RenderPassHooks`
50
+ * carries, and for a sharper reason here: these run as listeners on the
51
+ * renderer's own runners, so a throwing `before` aborts the game's frame AND
52
+ * skips the `postrender` emit that would have closed the pass. The assembly
53
+ * point (`ingest/ingest-render-debug.ts`) is where that contract is kept.
54
+ */
55
+ export function installPixiRenderPassBracket(renderer, hooks) {
56
+ const pair = runnerPair(renderer);
57
+ if (!pair)
58
+ return null;
59
+ // One object per runner: `SystemRunner.add` binds by method name, so the
60
+ // `prerender` listener and the `postrender` listener cannot be the same
61
+ // object unless it answers to both — keeping them separate makes each
62
+ // `remove()` exact.
63
+ const preListener = {
64
+ prerender() {
65
+ hooks.before();
66
+ },
67
+ };
68
+ const postListener = {
69
+ postrender() {
70
+ hooks.after();
71
+ },
72
+ };
73
+ pair.pre.add(preListener);
74
+ pair.post.add(postListener);
75
+ let uninstalled = false;
76
+ return () => {
77
+ if (uninstalled)
78
+ return;
79
+ uninstalled = true;
80
+ pair.pre.remove(preListener);
81
+ pair.post.remove(postListener);
82
+ };
83
+ }
84
+ /**
85
+ * The captured Pixi renderer's real WebGL2 context, or `undefined`.
86
+ *
87
+ * `WebGLRenderer.gl` is the renderer's own published field — `GlContextSystem`
88
+ * assigns it (`this._renderer.gl = gl`,
89
+ * `rendering/renderers/gl/context/GlContextSystem.mjs`) as part of
90
+ * initialisation, and `WebGLRenderer.d.ts` declares it. A WebGPU renderer, or
91
+ * a renderer that has not initialised a context, simply has none — which is the
92
+ * answer, not an error.
93
+ */
94
+ export function pixiRenderingContext(renderer) {
95
+ if (!renderer || typeof renderer !== 'object')
96
+ return undefined;
97
+ return renderer.gl;
98
+ }
@@ -17,6 +17,20 @@
17
17
  * instance, so it is trapped; a game bundling its own pixi cannot be captured at
18
18
  * all, and its mount fails by name.
19
19
  */
20
+ import { type VisibilityClock, type VisibleCaptureWindow } from '../adapter/ingest/visible-capture-window';
21
+ /**
22
+ * Options for {@link SceneCapture2DHandle.waitForCapture} — the same shape the
23
+ * three lane's `CaptureWaitOptions` has, because it is the same wait. Passing a
24
+ * bare number is `{ timeoutMs }`, which is what every existing caller does.
25
+ */
26
+ export interface CaptureWait2DOptions {
27
+ /** The capture window, in VISIBLE milliseconds (default 10s). */
28
+ timeoutMs?: number | undefined;
29
+ /** Injected in tests; defaults to the document's own visibility. */
30
+ visibility?: VisibilityClock | undefined;
31
+ /** Live view of the wait while it runs, `null` the moment it ends. */
32
+ onWait?: ((wait: VisibleCaptureWindow | null) => void) | undefined;
33
+ }
20
34
  /** A live Pixi runtime captured from an external PixiJS game. */
21
35
  export interface CapturedRuntime2D {
22
36
  /** The game's root stage Container. */
@@ -28,7 +42,24 @@ export interface CapturedRuntime2D {
28
42
  }
29
43
  export interface SceneCapture2DHandle {
30
44
  readonly captured: CapturedRuntime2D | null;
31
- waitForCapture(timeoutMs?: number): Promise<CapturedRuntime2D>;
45
+ /**
46
+ * Resolve once the game's stage is captured.
47
+ *
48
+ * The timeout is a budget of **VISIBLE** time, not wall-clock time — the same
49
+ * rule the three lane has had since `visible-capture-window.ts`, and for the
50
+ * same measured reason: a hidden document cannot render (the browser parks
51
+ * rAF), so counting hidden time against the game counts time it was not
52
+ * allowed to use. MEASURED on the bubbo-bubbo ingest with a plain
53
+ * `setTimeout` here: the mount succeeded when the auto-opened tab happened to
54
+ * be in front and died terminally 8s later when it was behind — "canvas
55
+ * ingest: game … rendered no capturable frame", with foregrounding the tab
56
+ * afterwards changing nothing. The normal HUMAN path is the backgrounded one.
57
+ *
58
+ * So the wait PARKS while hidden, the trap stays installed, and the first
59
+ * frame the tab draws after it comes forward is trapped exactly as it would
60
+ * have been at boot. Rejects only when the window is spent while VISIBLE.
61
+ */
62
+ waitForCapture(options?: number | CaptureWait2DOptions): Promise<CapturedRuntime2D>;
32
63
  getDrawCount(): number;
33
64
  /** Pause/resume the captured game's own ticker (loop-host gating). */
34
65
  setPaused(paused: boolean): void;
@@ -1 +1 @@
1
- {"version":3,"file":"scene-capture.d.ts","sourceRoot":"","sources":["../../src/pixi/scene-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,iEAAiE;AACjE,MAAM,WAAW,iBAAiB;IAChC,uCAAuC;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,kCAAkC;IAClC,QAAQ,EAAE,OAAO,CAAC;IAClB,wEAAwE;IACxE,GAAG,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC5C,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC/D,YAAY,IAAI,MAAM,CAAC;IACvB,sEAAsE;IACtE,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,SAAS,IAAI,IAAI,CAAC;CACnB;AAMD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,OAAO,GAAG,oBAAoB,CAoElF"}
1
+ {"version":3,"file":"scene-capture.d.ts","sourceRoot":"","sources":["../../src/pixi/scene-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,oBAAoB,EAC1B,MAAM,0CAA0C,CAAC;AAElD;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,oEAAoE;IACpE,UAAU,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IACzC,sEAAsE;IACtE,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,oBAAoB,GAAG,IAAI,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CACpE;AAED,iEAAiE;AACjE,MAAM,WAAW,iBAAiB;IAChC,uCAAuC;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,kCAAkC;IAClC,QAAQ,EAAE,OAAO,CAAC;IAClB,wEAAwE;IACxE,GAAG,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC5C;;;;;;;;;;;;;;;;OAgBG;IACH,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,oBAAoB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACpF,YAAY,IAAI,MAAM,CAAC;IACvB,sEAAsE;IACtE,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,SAAS,IAAI,IAAI,CAAC;CACnB;AAMD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,OAAO,GAAG,oBAAoB,CAgFlF"}
@@ -17,6 +17,7 @@
17
17
  * instance, so it is trapped; a game bundling its own pixi cannot be captured at
18
18
  * all, and its mount fails by name.
19
19
  */
20
+ import { documentVisibilityClock, startVisibleCaptureWindow, } from '../adapter/ingest/visible-capture-window';
20
21
  /**
21
22
  * Install the render trap on `pixiNamespace.Application.prototype.render`. Pass the
22
23
  * host's `pixi.js` namespace so a shared-instance game is trapped. Install once per
@@ -60,22 +61,33 @@ export function installSceneCapture2D(pixiNamespace) {
60
61
  else
61
62
  app.ticker.start();
62
63
  },
63
- waitForCapture(timeoutMs = 10_000) {
64
+ waitForCapture(options) {
65
+ const opts = typeof options === 'number' ? { timeoutMs: options } : (options ?? {});
66
+ const timeoutMs = opts.timeoutMs ?? 10_000;
64
67
  if (captured)
65
68
  return Promise.resolve(captured);
66
69
  return new Promise((resolve, reject) => {
67
- const timer = setTimeout(() => {
68
- const i = waiters.indexOf(wrapped);
69
- if (i >= 0)
70
- waiters.splice(i, 1);
71
- reject(new Error(`pixi scene capture timed out after ${timeoutMs}ms — the game never ` +
72
- `rendered, or it bundles its own (un-shared) copy of pixi.js.`));
73
- }, timeoutMs);
70
+ const captureWindow = startVisibleCaptureWindow({
71
+ budgetMs: timeoutMs,
72
+ clock: opts.visibility ?? documentVisibilityClock(),
73
+ onExpire: () => {
74
+ const i = waiters.indexOf(wrapped);
75
+ if (i >= 0)
76
+ waiters.splice(i, 1);
77
+ opts.onWait?.(null);
78
+ reject(new Error(`pixi scene capture timed out after ${timeoutMs}ms of VISIBLE time ` +
79
+ `(${Math.round(captureWindow.elapsedHiddenMs())}ms hidden, which is not counted — ` +
80
+ 'a hidden tab cannot render) — the game never rendered, or it bundles its own ' +
81
+ '(un-shared) copy of pixi.js.'));
82
+ },
83
+ });
74
84
  const wrapped = (rt) => {
75
- clearTimeout(timer);
85
+ captureWindow.cancel();
86
+ opts.onWait?.(null);
76
87
  resolve(rt);
77
88
  };
78
89
  waiters.push(wrapped);
90
+ opts.onWait?.(captureWindow);
79
91
  });
80
92
  },
81
93
  uninstall() {
@@ -5,12 +5,41 @@ import type { Physics2DRegistry } from './physics-registry';
5
5
  * Lets the editor coordinate editing of a Rapier-2D-driven entity WITHOUT owning the
6
6
  * simulation: report transform ownership, then freeze → commit → unfreeze so a drag
7
7
  * sticks instead of being stomped by the next physics step.
8
+ *
9
+ * KEYED BY THE DISPLAY OBJECT, and that is this surface's own vocabulary rather
10
+ * than a shortcut: the canvas gizmo's real caller
11
+ * (`editor/src/authoring/pixi-live-write-target.ts`) resolves node id → display
12
+ * itself before it asks, so there is no node-id hop on this lane at all.
13
+ *
14
+ * `keyedBy` is REQUIRED here and optional on the 3D {@link PhysicsAdapter} —
15
+ * see that interface's doc comment for why the union has to be tagged, and why
16
+ * the newcomer is the shape obliged to say so.
8
17
  */
9
18
  export interface PhysicsAdapter2D {
19
+ /** Discriminates this shape from the node-id-keyed {@link PhysicsAdapter}
20
+ * inside `SystemAdapters['physics']`. */
21
+ readonly keyedBy: 'display';
10
22
  ownerOf(display: Container): 'physics' | 'none';
11
23
  freeze(display: Container): void;
12
24
  commit(display: Container, position: [number, number], rotation: number): void;
13
25
  unfreeze(display: Container): void;
14
26
  }
15
27
  export declare function createPhysicsAdapter2D(physics: Physics2DRegistry): PhysicsAdapter2D;
28
+ /**
29
+ * ONE carrier over several, each owning a DIFFERENT set of display objects.
30
+ *
31
+ * The canvas ingest mount is the case: the host always builds a registry-backed
32
+ * carrier for objects the editor itself created, and an ingested game may ALSO
33
+ * declare one over its own simulation's objects. Neither is a superset of the
34
+ * other and neither can answer for the other's objects, so the composition is
35
+ * ownership-routed rather than layered — `ownerOf` asks each in order and the
36
+ * FIRST to claim the object handles every other call for it. A display object
37
+ * nobody claims answers `'none'` and the freeze/commit/unfreeze trio no-ops,
38
+ * which is exactly what a single unclaiming carrier already does.
39
+ *
40
+ * Order is precedence: earlier carriers win a (never-expected) double claim,
41
+ * so the caller states its own preference instead of this function inventing
42
+ * one.
43
+ */
44
+ export declare function composePhysicsAdapters2D(carriers: readonly PhysicsAdapter2D[]): PhysicsAdapter2D;
16
45
  //# sourceMappingURL=system-adapters.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"system-adapters.d.ts","sourceRoot":"","sources":["../../src/pixi/system-adapters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IAChD,MAAM,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI,CAAC;IACjC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/E,QAAQ,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI,CAAC;CACpC;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAgCnF"}
1
+ {"version":3,"file":"system-adapters.d.ts","sourceRoot":"","sources":["../../src/pixi/system-adapters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,gBAAgB;IAC/B;8CAC0C;IAC1C,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAC5B,OAAO,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IAChD,MAAM,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI,CAAC;IACjC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/E,QAAQ,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI,CAAC;CACpC;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAiCnF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,GAAG,gBAAgB,CAUhG"}
@@ -2,6 +2,7 @@ export function createPhysicsAdapter2D(physics) {
2
2
  // Remember each frozen body's prior type so unfreeze restores it.
3
3
  const frozen = new WeakMap();
4
4
  return {
5
+ keyedBy: 'display',
5
6
  ownerOf(display) {
6
7
  const refs = physics.get(display);
7
8
  if (!refs)
@@ -35,3 +36,29 @@ export function createPhysicsAdapter2D(physics) {
35
36
  },
36
37
  };
37
38
  }
39
+ /**
40
+ * ONE carrier over several, each owning a DIFFERENT set of display objects.
41
+ *
42
+ * The canvas ingest mount is the case: the host always builds a registry-backed
43
+ * carrier for objects the editor itself created, and an ingested game may ALSO
44
+ * declare one over its own simulation's objects. Neither is a superset of the
45
+ * other and neither can answer for the other's objects, so the composition is
46
+ * ownership-routed rather than layered — `ownerOf` asks each in order and the
47
+ * FIRST to claim the object handles every other call for it. A display object
48
+ * nobody claims answers `'none'` and the freeze/commit/unfreeze trio no-ops,
49
+ * which is exactly what a single unclaiming carrier already does.
50
+ *
51
+ * Order is precedence: earlier carriers win a (never-expected) double claim,
52
+ * so the caller states its own preference instead of this function inventing
53
+ * one.
54
+ */
55
+ export function composePhysicsAdapters2D(carriers) {
56
+ const ownerFor = (display) => carriers.find((carrier) => carrier.ownerOf(display) === 'physics') ?? null;
57
+ return {
58
+ keyedBy: 'display',
59
+ ownerOf: (display) => (ownerFor(display) ? 'physics' : 'none'),
60
+ freeze: (display) => ownerFor(display)?.freeze(display),
61
+ commit: (display, position, rotation) => ownerFor(display)?.commit(display, position, rotation),
62
+ unfreeze: (display) => ownerFor(display)?.unfreeze(display),
63
+ };
64
+ }
@@ -1,7 +1,9 @@
1
1
  /**
2
2
  * Converts ParticlesDescriptor JSON → three.quarks ParticleSystem.
3
3
  *
4
- * Shared between the editor entity-factory and the runtime scene-loader.
4
+ * A published engine entry point (the export map is the wildcard `./*`): the
5
+ * one in-repo caller is the godot-compat capability's `createCpuParticles3D`,
6
+ * and user games outside this repo reach it directly.
5
7
  * The schema mirrors quarks' native JSON format, so most fields pass through
6
8
  * directly to quarks' fromJSON or constructor methods.
7
9
  */
@@ -19,7 +21,7 @@ export interface ParticleSystemResult {
19
21
  * The non-JSON companion to a {@link ParticlesDescriptor} — the runtime objects
20
22
  * a JSON document cannot carry, and an authoring toggle. Every field is
21
23
  * optional and the whole argument is optional, so existing single-argument
22
- * callers (the editor entity-factory, the runtime scene-loader) are unchanged.
24
+ * callers are unchanged.
23
25
  *
24
26
  * This is how a caller with fidelity a plain descriptor cannot express reaches
25
27
  * the SAME factory instead of hand-building its own `new ParticleSystem(...)`:
@@ -86,10 +88,22 @@ export declare function applyParticlesDataLive(system: ParticleSystem, data: Par
86
88
  export declare function scrubParticleSystemTo(system: ParticleSystem, time: number, step?: number): void;
87
89
  /**
88
90
  * Register a particle system with a BatchedRenderer.
91
+ *
92
+ * This is also the ONE seat that arms the scene-depth prepass: a system built
93
+ * with `softParticles` compiles its batch with three.quarks' `SOFT_PARTICLES`
94
+ * define, which samples a `depthTexture` uniform nothing else in this engine
95
+ * would ever fill (see `render/soft-particle-depth.ts` for what an unfilled one
96
+ * does to the frame). Arming here — rather than in
97
+ * {@link createParticleSystemFromData} — is what makes it correct: the uniform
98
+ * lives on the BATCH, and no batch exists until a renderer is handed the
99
+ * system.
89
100
  */
90
101
  export declare function registerParticleSystem(batchedRenderer: BatchedRenderer, system: ParticleSystem): void;
91
102
  /**
92
103
  * Unregister a particle system from a BatchedRenderer.
104
+ *
105
+ * Disarms the depth prepass — one decrement against the arming above, so a
106
+ * renderer hosting several soft systems stays armed until its last one leaves.
93
107
  */
94
108
  export declare function unregisterParticleSystem(batchedRenderer: BatchedRenderer, system: ParticleSystem): void;
95
109
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"particles-factory.d.ts","sourceRoot":"","sources":["../../src/render/particles-factory.ts"],"names":[],"mappings":"AACA;;;;;;GAMG;AAEH,OAAO,EAQL,KAAK,YAAY,EAmBlB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,KAAK,eAAe,EAAE,cAAc,EAAc,MAAM,cAAc,CAAC;AAChF,OAAO,KAAK,EAIV,mBAAmB,EAEpB,MAAM,4BAA4B,CAAC;AAyNpC,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC;IACxB,kEAAkE;IAClE,MAAM,EAAE,cAAc,CAAC;CACxB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC;IAC1C;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;GAMG;AAEH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,mBAAmB,EACzB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,oBAAoB,CA6DtB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAsB9F;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,SAAS,GAAG,IAAI,CAU/F;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,eAAe,EAAE,eAAe,EAChC,MAAM,EAAE,cAAc,GACrB,IAAI,CAEN;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,eAAe,EAAE,eAAe,EAChC,MAAM,EAAE,cAAc,GACrB,IAAI,CAEN;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,mBAAmB,CA6B1D"}
1
+ {"version":3,"file":"particles-factory.d.ts","sourceRoot":"","sources":["../../src/render/particles-factory.ts"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AAEH,OAAO,EAQL,KAAK,YAAY,EAmBlB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,KAAK,eAAe,EAAE,cAAc,EAAc,MAAM,cAAc,CAAC;AAChF,OAAO,KAAK,EAIV,mBAAmB,EAEpB,MAAM,4BAA4B,CAAC;AA4RpC,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC;IACxB,kEAAkE;IAClE,MAAM,EAAE,cAAc,CAAC;CACxB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC;IAC1C;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;GAMG;AAEH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,mBAAmB,EACzB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,oBAAoB,CA6DtB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAsB9F;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,SAAS,GAAG,IAAI,CAU/F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,eAAe,EAAE,eAAe,EAChC,MAAM,EAAE,cAAc,GACrB,IAAI,CAGN;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,eAAe,EAAE,eAAe,EAChC,MAAM,EAAE,cAAc,GACrB,IAAI,CAGN;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,mBAAmB,CA6B1D"}