@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,4 +1,9 @@
1
1
  import { clampTimeScale, paceFrame, TIME_SCALE_RANGE } from './frame-pacing';
2
+ /** A visible rAF chain that has produced no callback for this long is not
3
+ * honestly "running" merely because its callback remains armed. One second
4
+ * is far beyond an ordinary dropped frame and short enough for status to
5
+ * report browser starvation while it is still actionable. */
6
+ const LOOP_STARVATION_MS = 1_000;
2
7
  /**
3
8
  * Fixed-timestep game loop with accumulator pattern — SIM at a fixed rate,
4
9
  * PRESENTATION at the display's rate (WO-P13, `docs/WORK.md` §2 P13, which
@@ -52,26 +57,35 @@ export function createGameLoop(config) {
52
57
  // Idle throttle (T2.1): a hidden tab stops the loop outright; becoming
53
58
  // visible again restarts it with the accumulator clock resynced to "now" —
54
59
  // deliberately no catch-up burst for the wall-clock time spent hidden.
55
- let hiddenPaused = false;
60
+ let visibilityPaused = false;
56
61
  let visibilityListenerAttached = false;
57
- function handleVisibilityChange() {
62
+ /** Reconcile the gate against the CURRENT document bit, not merely the
63
+ * last event. Browsers can miss/coalesce visibilitychange around window
64
+ * occlusion and reloads; reading liveness is itself a recovery opportunity,
65
+ * so a stale event can never leave this flag permanently wedged. */
66
+ function reconcileVisibilityGate() {
67
+ if (externalDrive || !visibilityListenerAttached)
68
+ return;
58
69
  if (typeof document === 'undefined')
59
70
  return;
60
71
  if (document.hidden) {
61
72
  if (running) {
62
73
  running = false;
63
74
  cancelAnimationFrame(rafId);
64
- hiddenPaused = true;
75
+ visibilityPaused = true;
65
76
  }
66
77
  }
67
- else if (hiddenPaused) {
68
- hiddenPaused = false;
78
+ else if (visibilityPaused) {
79
+ visibilityPaused = false;
69
80
  running = true;
70
81
  lastTime = performance.now();
71
82
  accumulator = 0;
72
83
  rafId = requestAnimationFrame(frame);
73
84
  }
74
85
  }
86
+ function handleVisibilityChange() {
87
+ reconcileVisibilityGate();
88
+ }
75
89
  function frame(currentTime) {
76
90
  if (!running)
77
91
  return;
@@ -101,13 +115,13 @@ export function createGameLoop(config) {
101
115
  if (running)
102
116
  return;
103
117
  running = true;
104
- // A direct start() call can land while the loop is auto-hidden-paused
105
- // (`hiddenPaused` true, `running` false, no rAF pending). Without this
118
+ // A direct start() call can land while the loop is auto-loop-starved
119
+ // (`visibilityPaused` true, `running` false, no rAF pending). Without this
106
120
  // reset, a later visibilitychange-to-visible would see stale
107
- // `hiddenPaused === true` and spawn a SECOND rAF chain on top of the
121
+ // `visibilityPaused === true` and spawn a SECOND rAF chain on top of the
108
122
  // one this call is about to start (doubled update()/render() overhead
109
123
  // until the next stop() — no sim-speed effect, but wasted work).
110
- hiddenPaused = false;
124
+ visibilityPaused = false;
111
125
  lastTime = performance.now();
112
126
  accumulator = 0;
113
127
  // External-drive mode (I2): never arm rAF and never install the
@@ -130,14 +144,14 @@ export function createGameLoop(config) {
130
144
  }
131
145
  if (typeof document !== 'undefined' && document.hidden) {
132
146
  running = false;
133
- hiddenPaused = true;
147
+ visibilityPaused = true;
134
148
  return;
135
149
  }
136
150
  rafId = requestAnimationFrame(frame);
137
151
  },
138
152
  stop() {
139
153
  running = false;
140
- hiddenPaused = false;
154
+ visibilityPaused = false;
141
155
  cancelAnimationFrame(rafId);
142
156
  if (visibilityListenerAttached && typeof document !== 'undefined') {
143
157
  document.removeEventListener('visibilitychange', handleVisibilityChange);
@@ -145,22 +159,29 @@ export function createGameLoop(config) {
145
159
  }
146
160
  },
147
161
  get isRunning() {
162
+ reconcileVisibilityGate();
148
163
  return running;
149
164
  },
150
165
  /**
151
166
  * Truthful liveness (issue #175 — see `GameLoopLiveness`'s doc comment
152
167
  * in `core/types.ts` for the full contract). Unlike `isRunning` above,
153
- * this DISTINGUISHES a hidden-tab pause from an actually-stopped loop:
154
- * `hiddenPaused` is only ever set by `handleVisibilityChange` (T2.1's
155
- * idle throttle) and cleared by `start()`/`stop()`/visibility-restore,
156
- * so it can never be true at the same time `running` is true. An
168
+ * this distinguishes a starved rAF loop from an actually-stopped loop.
169
+ * `visibilityPaused` records the deliberate `document.hidden` gate, and
170
+ * every read first reconciles that flag against the CURRENT document bit
171
+ * so a missed visibilitychange cannot wedge it. A visible, armed chain
172
+ * also reports starvation when no real frame callback has arrived within
173
+ * {@link LOOP_STARVATION_MS}; "armed" alone is not evidence of progress. An
157
174
  * `externalDrive` loop never installs the visibility listener at all
158
- * (see `start()` above), so `hiddenPaused` stays permanently `false` for
175
+ * (see `start()` above), so `visibilityPaused` stays permanently `false` for
159
176
  * it — it only ever reports `'running'` or `'stopped'`.
160
177
  */
161
178
  get liveness() {
162
- if (hiddenPaused)
163
- return 'hidden-paused';
179
+ reconcileVisibilityGate();
180
+ if (visibilityPaused)
181
+ return 'loop-starved';
182
+ if (running && !externalDrive && performance.now() - lastTime > LOOP_STARVATION_MS) {
183
+ return 'loop-starved';
184
+ }
164
185
  return running ? 'running' : 'stopped';
165
186
  },
166
187
  set timeScale(value) {
@@ -93,19 +93,18 @@ export interface GameLoopConfig {
93
93
  * debug-registry.ts`) can name the union without importing `game-loop.ts`
94
94
  * as a value.
95
95
  *
96
- * - `'running'` — the rAF chain is armed and `config.update` is being
97
- * driven by real frames (or, for an `externalDrive` loop, `start()` has
98
- * been called — see that mode's own liveness note below).
99
- * - `'hidden-paused'` — the T2.1 idle throttle stopped the loop because
100
- * `document.hidden` is true; this is deliberate and reversible (resumes
101
- * automatically on visibility), but ZERO ticks are advancing right now.
96
+ * - `'running'` — a real rAF callback arrived recently (or, for an
97
+ * `externalDrive` loop, `start()` has been called — see that mode's own
98
+ * liveness note below).
99
+ * - `'loop-starved'` — the host loop has made no recent rAF progress: either
100
+ * the T2.1 visibility gate deliberately parked it, or an armed visible-page
101
+ * callback has not arrived within the starvation threshold. This reports
102
+ * the LOOP measurement, never a conclusion about where the browser tab is.
102
103
  * - `'stopped'` — `stop()` was called, or `start()` was never called.
103
104
  *
104
- * `isRunning` collapses `'hidden-paused'` and `'stopped'` into the same
105
- * `false` exactly the ambiguity that let a hidden-paused game report as
106
- * healthy ("playing") through every consumer that only read `isRunning`/
107
- * store-level play state. Read `liveness` wherever "is this game actually
108
- * advancing" matters.
105
+ * `isRunning` says whether the rAF chain is armed; it can therefore remain
106
+ * `true` while a visible browser starves callbacks. Read `liveness` wherever
107
+ * "is this host loop actually advancing" matters.
109
108
  */
110
- export type GameLoopLiveness = 'running' | 'hidden-paused' | 'stopped';
109
+ export type GameLoopLiveness = 'running' | 'loop-starved' | 'stopped';
111
110
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,WAAW;;;;;;;;;CASd,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,CAAC;AAE7E,+BAA+B;AAC/B,eAAO,MAAM,WAAW,EAAE,eAAe,EASxC,CAAC;AAEF,wDAAwD;AACxD,MAAM,MAAM,QAAQ,GAAG,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACvE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACtE;AAED,yDAAyD;AACzD,MAAM,WAAW,SAAS;IACxB,uEAAuE;IACvE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,8CAA8C;IAC9C,KAAK,EAAE,eAAe,CAAC;IACvB,4EAA4E;IAC5E,IAAI,CAAC,IAAI,IAAI,CAAC;IACd,uBAAuB;IACvB,MAAM,EAAE,QAAQ,CAAC;IACjB,8DAA8D;IAC9D,OAAO,CAAC,IAAI,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;OAUG;IACH,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,eAAe,GAAG,SAAS,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,WAAW;;;;;;;;;CASd,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,CAAC;AAE7E,+BAA+B;AAC/B,eAAO,MAAM,WAAW,EAAE,eAAe,EASxC,CAAC;AAEF,wDAAwD;AACxD,MAAM,MAAM,QAAQ,GAAG,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACvE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACtE;AAED,yDAAyD;AACzD,MAAM,WAAW,SAAS;IACxB,uEAAuE;IACvE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,8CAA8C;IAC9C,KAAK,EAAE,eAAe,CAAC;IACvB,4EAA4E;IAC5E,IAAI,CAAC,IAAI,IAAI,CAAC;IACd,uBAAuB;IACvB,MAAM,EAAE,QAAQ,CAAC;IACjB,8DAA8D;IAC9D,OAAO,CAAC,IAAI,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;OAUG;IACH,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,cAAc,GAAG,SAAS,CAAC"}
@@ -57,7 +57,7 @@ export function defineData(schema, initial, sourcePath) {
57
57
  }
58
58
  catch (err) {
59
59
  // Keep the last good value alive — see the JSDoc on DataHandle.hotSwap.
60
- // biome-ignore lint/suspicious/noConsole: deliberate, greppable — a rejected live-tune edit must be loud without crashing the running game (mirrors achieved-tier.ts's direct console use)
60
+ // biome-ignore lint/suspicious/noConsole: deliberate, greppable — a rejected live-tune edit must be loud without crashing the running game
61
61
  console.error(`[data] hot edit rejected, keeping previous values.\n${String(err)}`);
62
62
  return;
63
63
  }
@@ -1 +1 @@
1
- {"version":3,"file":"instruments.d.ts","sourceRoot":"","sources":["../../src/dev/instruments.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;sCAEsC;AACtC,MAAM,MAAM,oBAAoB;AAC9B,oBAAoB;AAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE;AAC9B,0CAA0C;GACxC;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AACtD,6EAA6E;GAC3E;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AACH,sEAAsE;GACpE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9B;;;kBAGkB;AAClB,MAAM,WAAW,mBAAmB;IAClC,iEAAiE;IACjE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC;IAC1B,GAAG,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC;CAC1C;AAED,MAAM,WAAW,aAAa;IAC5B,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sDAAsD;IACtD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACjD,0EAA0E;IAC1E,IAAI,IAAI,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,EAAE,SAAS,aAAa,EAAE,CAAC;IAC/C,4DAA4D;IAC5D,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC;;mCAEmC;AACnC,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,+CAA+C;IAC/C,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,kCAAkC;IAClC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,mEAAmE;AACnE,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,gBAAgB,CAehF;AAcD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,GAAG,gBAAgB,CAwIjE"}
1
+ {"version":3,"file":"instruments.d.ts","sourceRoot":"","sources":["../../src/dev/instruments.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;sCAEsC;AACtC,MAAM,MAAM,oBAAoB;AAC9B,oBAAoB;AAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE;AAC9B,0CAA0C;GACxC;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AACtD,6EAA6E;GAC3E;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AACH,sEAAsE;GACpE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9B;;;kBAGkB;AAClB,MAAM,WAAW,mBAAmB;IAClC,iEAAiE;IACjE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC;IAC1B,GAAG,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC;CAC1C;AAED,MAAM,WAAW,aAAa;IAC5B,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sDAAsD;IACtD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACjD,0EAA0E;IAC1E,IAAI,IAAI,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,EAAE,SAAS,aAAa,EAAE,CAAC;IAC/C,4DAA4D;IAC5D,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC;;mCAEmC;AACnC,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,+CAA+C;IAC/C,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,kCAAkC;IAClC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,mEAAmE;AACnE,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,gBAAgB,CAehF;AAcD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,GAAG,gBAAgB,CA2IjE"}
@@ -49,6 +49,7 @@
49
49
  * collider instruments only drive state that `Game` already owns.
50
50
  */
51
51
  import { z } from 'zod';
52
+ import { nodeKeyedPhysics } from '../adapter/system-adapter';
52
53
  import { clampTimeScale, TIME_SCALE_RANGE } from '../core/frame-pacing';
53
54
  /**
54
55
  * How many display frames the frame-time reading keeps. ~1 second at 60 Hz —
@@ -103,7 +104,10 @@ export function createDevInstruments(game) {
103
104
  // below, which is also the only thing that calls the adapter.
104
105
  let collidersDrawn = false;
105
106
  const colliderDraw = () => {
106
- const adapter = game.systemAdapters.physics;
107
+ // Node-id keyed only — `setDebugDrawEnabled` draws THREE wireframes into
108
+ // the world, which a canvas mount's display-keyed carrier has no analogue
109
+ // for and does not declare.
110
+ const adapter = nodeKeyedPhysics(game.systemAdapters.physics);
107
111
  return adapter?.setDebugDrawEnabled ? adapter : null;
108
112
  };
109
113
  const instruments = [
@@ -18,6 +18,12 @@
18
18
  * `annotation: null` (counted as unattributed) — never a fabricated guess. The
19
19
  * wrappers are all restored when the capture resolves, rejects, times out, or
20
20
  * the adapter is disposed.
21
+ *
22
+ * That attribution is a THREE capability, not a property of frame capture: a
23
+ * surface whose renderer has no per-draw annotation seam omits `scene` entirely
24
+ * (the Pixi ingest lane does — `editor/src/ingest/ingest-render-debug.ts`), and
25
+ * every draw is then recorded unattributed. The capture itself is GL-level and
26
+ * unchanged either way; only the names beside the draws go away.
21
27
  */
22
28
  import type * as THREE from 'three';
23
29
  import type { RenderDebugAdapter } from '../adapter/system-adapter';
@@ -31,8 +37,19 @@ export declare function frameCaptureContextFor(headless: boolean, rendererContex
31
37
  export interface RenderDebugAdapterDeps {
32
38
  /** The armed-on-demand frame capture over the mount's real context. */
33
39
  capture: WebGLFrameCapture;
34
- /** The live scene root traversed to attribute draws. */
35
- scene: THREE.Object3D;
40
+ /**
41
+ * The live three scene root traversed to attribute draws to the objects that
42
+ * issue them.
43
+ *
44
+ * OMITTED on a surface whose renderer publishes no per-draw annotation seam —
45
+ * the Pixi lane, where display objects have no `onBeforeRender` and the
46
+ * batcher merges many display objects into one draw, so there is no object to
47
+ * name for a given draw at all. Then every draw is recorded with
48
+ * `annotation: null` and lands in `totals.unattributed`: the honest "this
49
+ * seam cannot say who drew this", never a guess derived from the scene's
50
+ * shape.
51
+ */
52
+ scene?: THREE.Object3D;
36
53
  /** Memory snapshot supplier (renderer.info-backed). When omitted, the
37
54
  * adapter's `memorySnapshot` is absent (honest capability degradation). */
38
55
  memory?: () => RenderMemorySnapshot;
@@ -1 +1 @@
1
- {"version":3,"file":"render-debug-adapter.d.ts","sourceRoot":"","sources":["../../src/dev/render-debug-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,KAAK,EAAgC,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE7F;;;2DAG2D;AAC3D,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,OAAO,EACjB,eAAe,EAAE,OAAO,GACvB,sBAAsB,GAAG,IAAI,CAO/B;AAED,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,OAAO,EAAE,iBAAiB,CAAC;IAC3B,wDAAwD;IACxD,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC;IACtB;gFAC4E;IAC5E,MAAM,CAAC,EAAE,MAAM,oBAAoB,CAAC;IACpC;yDACqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;0BACsB;IACtB,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;IACvD,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACrC,+DAA+D;IAC/D,YAAY,IAAI,IAAI,CAAC;IACrB,6EAA6E;IAC7E,WAAW,IAAI,IAAI,CAAC;IACpB,6EAA6E;IAC7E,OAAO,IAAI,IAAI,CAAC;CACjB;AAkDD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,sBAAsB,GAAG,iBAAiB,CAgFxF"}
1
+ {"version":3,"file":"render-debug-adapter.d.ts","sourceRoot":"","sources":["../../src/dev/render-debug-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,KAAK,EAAgC,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE7F;;;2DAG2D;AAC3D,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,OAAO,EACjB,eAAe,EAAE,OAAO,GACvB,sBAAsB,GAAG,IAAI,CAO/B;AAED,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,OAAO,EAAE,iBAAiB,CAAC;IAC3B;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC;IACvB;gFAC4E;IAC5E,MAAM,CAAC,EAAE,MAAM,oBAAoB,CAAC;IACpC;yDACqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;0BACsB;IACtB,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;IACvD,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACrC,+DAA+D;IAC/D,YAAY,IAAI,IAAI,CAAC;IACrB,6EAA6E;IAC7E,WAAW,IAAI,IAAI,CAAC;IACpB,6EAA6E;IAC7E,OAAO,IAAI,IAAI,CAAC;CACjB;AAkDD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,sBAAsB,GAAG,iBAAiB,CAmFxF"}
@@ -18,6 +18,12 @@
18
18
  * `annotation: null` (counted as unattributed) — never a fabricated guess. The
19
19
  * wrappers are all restored when the capture resolves, rejects, times out, or
20
20
  * the adapter is disposed.
21
+ *
22
+ * That attribution is a THREE capability, not a property of frame capture: a
23
+ * surface whose renderer has no per-draw annotation seam omits `scene` entirely
24
+ * (the Pixi ingest lane does — `editor/src/ingest/ingest-render-debug.ts`), and
25
+ * every draw is then recorded unattributed. The capture itself is GL-level and
26
+ * unchanged either way; only the names beside the draws go away.
21
27
  */
22
28
  /** Decide whether a mount can host frame capture — a real WebGL2 context with
23
29
  * the draw entry points, never a headless/stub renderer. Exported so the
@@ -73,6 +79,10 @@ export function createRenderDebugAdapter(deps) {
73
79
  let pending = null;
74
80
  function wrapOnBeforeRender() {
75
81
  const restores = [];
82
+ // No scene ⇒ no annotation seam on this surface (see `scene` above): wrap
83
+ // nothing, restore nothing, and let every draw record `annotation: null`.
84
+ if (!scene)
85
+ return restores;
76
86
  scene.traverse((object) => {
77
87
  if (!isRenderable(object))
78
88
  return;
@@ -46,8 +46,10 @@
46
46
  * mixer; see xstate-animation-binding.ts).
47
47
  * - `_availableClips` — string[] of clip names discovered on the GLTF
48
48
  * (inspector dropdown; same names as `_animClips`' keys).
49
- * - `_xstateAnimation` — live native XState/Three binding exposed for
50
- * play-mode inspection; removed when binding disposes.
49
+ * - `_animationRuntime` format-neutral live native mixer/action inspection.
50
+ * - `_xstateBehavior` — optional live XState behavior actor inspection.
51
+ * - `_xstateAnimation` — compatibility handle for the optional XState→Three
52
+ * bridge; animation UI never discovers through it.
51
53
  *
52
54
  * Disposal contract:
53
55
  * - `__sharedGeometry` — `true` when a mesh's geometry is shared/cached and MUST
@@ -117,7 +119,9 @@ import type { ParticleSystem } from 'three.quarks';
117
119
  import type { ConstraintMark } from '../adapter/constraint';
118
120
  import type { RapierEditableBody } from '../adapter/rapier-physics-adapter';
119
121
  import type { ReflectionProbeMark } from '../adapter/reflection-probe';
122
+ import type { AnimationRuntimeInspection } from '../animation/runtime-inspection';
120
123
  import type { XStateAnimationBinding } from '../animation/xstate-animation-binding';
124
+ import type { XStateBehaviorInspection } from '../behavior/xstate-inspection';
121
125
  /** The kinds of editor helper objects tagged via `editorHelperType`. */
122
126
  export type EditorHelperType = 'lights' | 'cameras' | 'audio' | 'colliders' | 'joints' | 'lod' | 'splines' | 'particles' | 'particle-shape' | 'pivot' | 'navmesh' | 'constraints' | 'reflection-probes' | 'skeletons';
123
127
  /**
@@ -142,6 +146,8 @@ export interface UserDataSchema {
142
146
  _animMixer: THREE.AnimationMixer;
143
147
  _animClips: Map<string, THREE.AnimationClip>;
144
148
  _availableClips: string[];
149
+ _animationRuntime: AnimationRuntimeInspection;
150
+ _xstateBehavior: XStateBehaviorInspection;
145
151
  _xstateAnimation: XStateAnimationBinding;
146
152
  __sharedGeometry: boolean;
147
153
  __shadeOrig: THREE.Material | THREE.Material[];
@@ -201,6 +207,8 @@ export declare const UserDataKeys: {
201
207
  readonly _animMixer: "_animMixer";
202
208
  readonly _animClips: "_animClips";
203
209
  readonly _availableClips: "_availableClips";
210
+ readonly _animationRuntime: "_animationRuntime";
211
+ readonly _xstateBehavior: "_xstateBehavior";
204
212
  readonly _xstateAnimation: "_xstateAnimation";
205
213
  readonly __sharedGeometry: "__sharedGeometry";
206
214
  readonly __shadeOrig: "__shadeOrig";
@@ -1 +1 @@
1
- {"version":3,"file":"user-data.d.ts","sourceRoot":"","sources":["../../src/ecs/user-data.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"user-data.d.ts","sourceRoot":"","sources":["../../src/ecs/user-data.ts"],"names":[],"mappings":"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"}
@@ -46,8 +46,10 @@
46
46
  * mixer; see xstate-animation-binding.ts).
47
47
  * - `_availableClips` — string[] of clip names discovered on the GLTF
48
48
  * (inspector dropdown; same names as `_animClips`' keys).
49
- * - `_xstateAnimation` — live native XState/Three binding exposed for
50
- * play-mode inspection; removed when binding disposes.
49
+ * - `_animationRuntime` format-neutral live native mixer/action inspection.
50
+ * - `_xstateBehavior` — optional live XState behavior actor inspection.
51
+ * - `_xstateAnimation` — compatibility handle for the optional XState→Three
52
+ * bridge; animation UI never discovers through it.
51
53
  *
52
54
  * Disposal contract:
53
55
  * - `__sharedGeometry` — `true` when a mesh's geometry is shared/cached and MUST
@@ -132,6 +134,8 @@ export const UserDataKeys = {
132
134
  _animMixer: '_animMixer',
133
135
  _animClips: '_animClips',
134
136
  _availableClips: '_availableClips',
137
+ _animationRuntime: '_animationRuntime',
138
+ _xstateBehavior: '_xstateBehavior',
135
139
  _xstateAnimation: '_xstateAnimation',
136
140
  __sharedGeometry: '__sharedGeometry',
137
141
  __shadeOrig: '__shadeOrig',
@@ -0,0 +1,10 @@
1
+ import type { InputBinding } from './input-types';
2
+ /**
3
+ * Whether two bindings name the same physical input.
4
+ *
5
+ * This is the native identity rule used by both runtime rebinding and the
6
+ * editor's `.inputmap.json` document. Deadzones do not change identity, while
7
+ * opposite directions on one gamepad axis remain independent controls.
8
+ */
9
+ export declare function inputBindingsCollide(a: InputBinding, b: InputBinding): boolean;
10
+ //# sourceMappingURL=binding-identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binding-identity.d.ts","sourceRoot":"","sources":["../../src/input/binding-identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,OAAO,CA2B9E"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Whether two bindings name the same physical input.
3
+ *
4
+ * This is the native identity rule used by both runtime rebinding and the
5
+ * editor's `.inputmap.json` document. Deadzones do not change identity, while
6
+ * opposite directions on one gamepad axis remain independent controls.
7
+ */
8
+ export function inputBindingsCollide(a, b) {
9
+ if (a.type !== b.type)
10
+ return false;
11
+ switch (a.type) {
12
+ case 'key':
13
+ return a.code === b.code;
14
+ case 'mouse_button':
15
+ return a.button === b.button;
16
+ case 'mouse_move':
17
+ return true;
18
+ case 'gamepad_button':
19
+ return a.button === b.button;
20
+ case 'gamepad_axis': {
21
+ const other = b;
22
+ return a.axis === other.axis && a.direction === other.direction;
23
+ }
24
+ case 'gamepad_axis_pair': {
25
+ const other = b;
26
+ return a.xAxis === other.xAxis && a.yAxis === other.yAxis;
27
+ }
28
+ case 'touch_button':
29
+ case 'touch_stick':
30
+ case 'test_axis':
31
+ case 'test_vector2':
32
+ case 'test_pointer_delta':
33
+ case 'test_pointer_position':
34
+ return a.sourceId === b.sourceId;
35
+ }
36
+ }
@@ -27,175 +27,6 @@ export declare class InputTickError extends Error {
27
27
  };
28
28
  constructor(tick: number, currentTick: number);
29
29
  }
30
- /**
31
- * Maps raw keyboard/mouse/gamepad events → named actions.
32
- *
33
- * Usage:
34
- * const input = new InputManager();
35
- * await input.loadMap('inputmaps/default.inputmap.json');
36
- * // In game loop:
37
- * input.poll(); // call at start of frame
38
- * if (input.isPressed('jump')) { ... }
39
- * if (input.isJustPressed('attack')) { ... }
40
- * input.endFrame(); // call at end of frame
41
- *
42
- * F1 (spec §12 "Define Typed Action Values") — typed action values:
43
- *
44
- * Every action DECLARES a value shape (`InputAction.valueType`, defaulted to
45
- * `'digital'` — see `input-types.ts`'s `ActionValueType`). Each shape has its
46
- * own typed getter, none of which return `any`:
47
- *
48
- * - `'digital'` — `isPressed`/`isJustPressed`/`isJustReleased` -> `boolean`
49
- * - `'scalar'` — `getScalar` -> `number`
50
- * - `'vector2'` — `getVector2` -> `Vector2` ({x,y})
51
- * - `'pointerDelta'` — `getPointerDelta` -> `Vector2`
52
- * - `'pointerPosition'` — `getPointerPosition` -> `Vector2`
53
- *
54
- * Reading an action through the WRONG getter (e.g. `getScalar` on a
55
- * `'digital'` action) throws — that's the type-safety enforcement point,
56
- * since actions are declared in data (JSON), not TS types, so there's no
57
- * compiler backstop otherwise. `readAction(name, expectedType)` is a generic
58
- * entry point over the same getters, typed via `ActionValueOf<T>`.
59
- *
60
- * Each typed getter has a `*Source` sibling (e.g. `getScalarSource`) that
61
- * returns `ActionValueSource | null` — which binding (and, for gamepad
62
- * bindings, which connected gamepad, or for injected test bindings, which
63
- * named source) produced the current value. That's the "device/source
64
- * metadata" AC.
65
- *
66
- * Deadzone + normalization:
67
- * - scalar: below `deadzone` magnitude -> 0; at/above it, rescaled from 0
68
- * (at the deadzone edge) to ±1 (at |raw| = 1), sign preserved
69
- * (`rescaleScalar`).
70
- * - vector2: below `deadzone` magnitude -> {0,0}; at/above it, direction is
71
- * preserved and magnitude is rescaled the same way, then the result is
72
- * clamped to the unit circle — magnitude never exceeds 1 even for a raw
73
- * diagonal input like {1,1} (`rescaleVector2`).
74
- *
75
- * Simultaneous-binding combine rules (documented here, spec §12 F1
76
- * "simultaneous bindings combine predictably"):
77
- * - digital: OR — any one satisfied binding makes the action pressed
78
- * (pre-existing behavior, unchanged).
79
- * - scalar: max-magnitude across contributing bindings' (deadzone-applied)
80
- * values, sign preserved; ties keep the first-listed binding
81
- * (deterministic given binding array order).
82
- * - vector2: sum contributing (deadzone-applied) {x,y} values component-
83
- * wise, then clamp the sum to the unit circle (never renormalized UP —
84
- * only ever scaled down if the sum exceeds magnitude 1).
85
- * - pointerDelta: sum contributing deltas (matches the existing
86
- * mouseDeltaX/Y + lookStick accumulation precedent below).
87
- * - pointerPosition: last-write-wins — the contributing source most
88
- * recently updated (by injection call order) wins; position isn't
89
- * additive so summing would be meaningless.
90
- *
91
- * Synthetic input injection (test hook, also the shape of F2's "injected
92
- * test input" backend): `injectAxis`/`injectVector2`/`injectPointerDelta`/
93
- * `injectPointerPosition` push a raw value into a named source, read back by
94
- * binding an action to `{ type: 'test_axis' | 'test_vector2' |
95
- * 'test_pointer_delta' | 'test_pointer_position', sourceId }` — the exact
96
- * same aggregation path (deadzone/normalize/combine) real device bindings
97
- * use.
98
- *
99
- * F2 (spec §12 "Complete Device Backends") completes the real-device side of
100
- * that same typed-value path:
101
- *
102
- * - `mouse_move` — un-rejected (schema.ts). Feeds `getPointerDelta` (raw
103
- * accumulated `mouseDeltaX/Y`, no deadzone) and `getVector2` (the same
104
- * delta, deadzone-rescaled + unit-circle-clamped).
105
- * - `gamepad_axis_pair` — un-rejected (schema.ts). Feeds `getVector2` with
106
- * the coupled `(xAxis, yAxis)` reading, deadzone-rescaled like a real
107
- * stick (default deadzone 0.15, matching `gamepad_axis`).
108
- * - `touch_button`/`touch_stick` — new binding kinds for touch/virtual
109
- * controls. `setTouchButton(sourceId, pressed)` feeds a digital action
110
- * (edge-tracked like `mouse_button`); `setTouchStick(sourceId, value)`
111
- * feeds a vector2 action (deadzone-rescaled like a gamepad stick). These
112
- * are the injectable entry points a real on-screen touch UI's own
113
- * touchstart/touchmove/touchend handlers would call — that DOM wiring is
114
- * a thin adapter at the edge (browser-verified separately, e.g. F4/e2e);
115
- * the mapping logic here is unit-tested headlessly with no DOM.
116
- * - Focus gating — `blur`/`focus` on `window` (guarded, real DOM only) now
117
- * drop input the same way `setEnabled(false)` does (flushing held
118
- * key/mouse/touch-button state) without touching the `enabled` flag the
119
- * editor drives — see `focused`/`inputActive` below. This is what stops
120
- * a stuck key/button when the user alt-tabs away mid-press.
121
- * - Pointer lock — `pointerlockchange` on `document` (guarded) tracks
122
- * `isPointerLocked()`; losing lock flushes mouse-button state (a click
123
- * held at the moment lock exits must not stick).
124
- * - Gamepad device identity — `getGamepadInfo(index)` exposes `{index, id,
125
- * mapping, connected}`; `ActionValueSource.gamepadId` (in addition to the
126
- * pre-existing `gamepadIndex`) is populated for every
127
- * gamepad_button/gamepad_axis/gamepad_axis_pair source.
128
- * - Disconnection/reconnection needs no new tracking: `poll()` already
129
- * re-reads `navigator.getGamepads()` every frame and every read (digital
130
- * edges, scalar/vector2 contributions) already skips a `null` gamepad
131
- * entry, so a disconnected gamepad's bound actions go neutral (and a
132
- * previously-held button correctly fires `isJustReleased`) with no
133
- * special-cased code — see the state-transition tests.
134
- *
135
- * F3 (spec §12 "Add Rebinding and Prompts") completes the input system with
136
- * rebinding, structural conflict detection, and device-prompt resolution:
137
- *
138
- * - Listing/mutating: `getBindings`/`setBindings`/`addBinding`/
139
- * `removeBinding`/`replaceBinding` — the same `this.actions` map F1/F2
140
- * already read, now with a public read + mutation surface (there was
141
- * previously none — every existing call site either loaded a map once or
142
- * read through the typed getters).
143
- * - Reset-to-defaults: `registerAction`/`loadMap`/`loadMapObject` snapshot
144
- * each action's bindings into `defaultBindings` (a deep clone) at
145
- * registration/load time; `resetBindings`/`resetAllBindings` restore from
146
- * that snapshot. Later rebinding calls do NOT touch the snapshot, so
147
- * "reset" always means "back to what was authored/loaded", not "back to
148
- * the last reset".
149
- * - Persist: `toInputMapFile()` serializes the live action set back into
150
- * the exact `.inputmap.json` shape (`InputMapFile`) `loadMap` reads;
151
- * `loadMapObject(data)` is `loadMap`'s synchronous, no-`fetch` sibling —
152
- * both funnel through the same `InputMapFileSchema`-validated
153
- * `applyParsedMap`. This is the round-trip seam: serialize, write/hand to
154
- * something else, reload, and rebound actions survive. It complements —
155
- * doesn't replace — the SDK's `project.inputMap.read/validate/update`
156
- * operations (B2, `packages/vgai-sdk/src/project/input-map-operations.ts`):
157
- * those are FILE-level (a CLI/agent editing the `.inputmap.json` on disk,
158
- * no running game involved); this is RUNTIME-level (a live game rebinding
159
- * while playing). Both validate through the identical
160
- * `InputMapFileSchema`, so a file B2 wrote loads here unchanged, and a
161
- * map this class serializes is a valid document for B2 to read back.
162
- * - Conflicts: `findConflicts(proposed, excludeActionName?)` scans every
163
- * OTHER registered action's bindings for one that's structurally
164
- * equivalent to `proposed` (see the private `bindingsCollide` — same
165
- * physical input identity: same key code, same mouse button, the same
166
- * gamepad button/axis/axis-pair, the same touch `sourceId`, etc.) and
167
- * returns the (possibly empty) list as plain `BindingConflict` data —
168
- * never throws. A rebinding UI calls this BEFORE calling
169
- * `addBinding`/`replaceBinding`/`setBindings` and decides what to do with
170
- * a non-empty result (block, warn, let the user steal the binding by
171
- * removing it from the other action first).
172
- * - Prompts: `getPrompt(actionName, device?, gamepadIndex?)` resolves a
173
- * `BindingPrompt` (display label + icon name) for whichever of the
174
- * action's bindings belongs to the requested `PromptDevice` family
175
- * (keyboard/mouse/gamepad/touch — `bindingDeviceFamily` in
176
- * `prompt-labels.ts`), using `getGamepadInfo` to prefer the standard
177
- * mapping's canonical glyph names (`'A'`, `'LB'`, ...) for gamepad
178
- * buttons and falling back to a raw index label (or a "disconnected"
179
- * label) when the pad isn't in standard mapping or isn't connected.
180
- * `device` is optional (F4 below) — omit it to resolve against
181
- * `getLastActiveDevice()` instead.
182
- *
183
- * F4 (spec §12 "Schema and Examples") closes F3's one open gap — a
184
- * current-ACTIVE-device tracker, so a prompt UI can switch its displayed
185
- * label as the player switches controllers instead of the caller having to
186
- * track that itself:
187
- *
188
- * - `getLastActiveDevice()` returns the `PromptDevice` family of whichever
189
- * input arrived most recently — keyboard on `keydown`, mouse on
190
- * `mousedown`/a real `mousemove`, gamepad on a button press or a stick
191
- * pushed meaningfully off-center (checked in `poll()`), touch on
192
- * `setTouchButton(_, true)` or `setTouchStick` pushed meaningfully
193
- * off-center. `null` before any input has arrived.
194
- * - `getPrompt(actionName)` (device omitted) resolves against it directly,
195
- * falling back to `'keyboard'` before any input has arrived — a HUD can
196
- * call it every frame with no extra bookkeeping and the label switches on
197
- * its own.
198
- */
199
30
  export declare class InputManager {
200
31
  private actions;
201
32
  private actionValueTypes;
@@ -228,12 +59,24 @@ export declare class InputManager {
228
59
  private touchButtonsJustUp;
229
60
  private touchStickValues;
230
61
  private lastActiveDevice;
231
- /** Coarse "is this stick meaningfully off-center" check shared by the
232
- * gamepad and touch-stick active-device heuristics above deliberately a
233
- * higher bar than a binding's own (often much smaller) configured
234
- * deadzone, since this is "did the player just grab this control", not
235
- * "does this binding's value count as non-zero". */
236
- private static isStickActive;
62
+ /**
63
+ * "Is this control off its rest position" for the active-device tracker,
64
+ * answered from what the GAME DECLARED rather than from a threshold this
65
+ * class invented.
66
+ *
67
+ * It used to be `Math.hypot(v.x, v.y) > 0.3` — a constant nobody could see or
68
+ * change, sitting on top of a deadzone the game had already stated. A game
69
+ * that declares a 0.5 deadzone on its move stick considers everything under
70
+ * 0.5 to be rest; reporting "the player switched to gamepad" at 0.31 makes a
71
+ * HUD's prompt flip to a control the game itself is ignoring. Zero inference
72
+ * (ARCHITECTURE-CORE §The editor protocol) says the fix is to read the
73
+ * declaration, and it is already here in `this.actions`.
74
+ *
75
+ * SMALLEST wins when several bindings name one source: the first magnitude at
76
+ * which ANY of the game's own bindings treats the control as live is the
77
+ * moment the player has grabbed it.
78
+ */
79
+ private declaredDeadzone;
237
80
  private virtualDigitalHeld;
238
81
  private virtualDigitalTapQueued;
239
82
  private virtualDigitalTapActive;
@@ -693,16 +536,6 @@ export declare class InputManager {
693
536
  /** Reset every action that has a snapshot back to its registered/loaded
694
537
  * defaults. Convenience batch form of `resetBindings`. */
695
538
  resetAllBindings(): void;
696
- /**
697
- * Whether `a` and `b` are the SAME physical input (F3's structural-conflict
698
- * identity check — see `findConflicts`). Deliberately narrower than deep
699
- * equality: `deadzone` never participates (two bindings on the same key
700
- * with different deadzones are still the same physical control), and a
701
- * `gamepad_axis`'s `direction` DOES participate — opposite directions of one
702
- * physical axis (e.g. "accelerate" on positive, "brake" on negative) are a
703
- * legitimate, non-conflicting pair, not a collision.
704
- */
705
- private static bindingsCollide;
706
539
  /**
707
540
  * Every EXISTING binding, on every OTHER registered action, that is
708
541
  * structurally the same physical input as `proposed` (F3 AC "conflicts are