@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.
- package/dist/adapter/adapter-module.d.ts +447 -0
- package/dist/adapter/adapter-module.d.ts.map +1 -0
- package/dist/adapter/adapter-module.js +308 -0
- package/dist/adapter/authoring.d.ts +357 -10
- package/dist/adapter/authoring.d.ts.map +1 -1
- package/dist/adapter/authoring.js +87 -1
- package/dist/adapter/constraint.d.ts +9 -3
- package/dist/adapter/constraint.d.ts.map +1 -1
- package/dist/adapter/finders/finder-result.d.ts +28 -0
- package/dist/adapter/finders/finder-result.d.ts.map +1 -0
- package/dist/adapter/finders/finder-result.js +10 -0
- package/dist/adapter/finders/index.d.ts +38 -0
- package/dist/adapter/finders/index.d.ts.map +1 -0
- package/dist/adapter/finders/index.js +41 -0
- package/dist/adapter/finders/prefabs-from-stories.d.ts +64 -0
- package/dist/adapter/finders/prefabs-from-stories.d.ts.map +1 -0
- package/dist/adapter/finders/prefabs-from-stories.js +92 -0
- package/dist/adapter/finders/scenes-from-entrypoint-selection.d.ts +67 -0
- package/dist/adapter/finders/scenes-from-entrypoint-selection.d.ts.map +1 -0
- package/dist/adapter/finders/scenes-from-entrypoint-selection.js +226 -0
- package/dist/adapter/first-party-systems.d.ts.map +1 -1
- package/dist/adapter/first-party-systems.js +29 -0
- package/dist/adapter/index.d.ts +7 -3
- package/dist/adapter/index.d.ts.map +1 -1
- package/dist/adapter/index.js +5 -2
- package/dist/adapter/ingest/contract-system-adapters.d.ts +24 -1
- package/dist/adapter/ingest/contract-system-adapters.d.ts.map +1 -1
- package/dist/adapter/ingest/contract-system-adapters.js +100 -34
- package/dist/adapter/ingest/game-contract.d.ts +188 -2
- package/dist/adapter/ingest/game-contract.d.ts.map +1 -1
- package/dist/adapter/ingest/game-contract.js +107 -0
- package/dist/adapter/ingest/mount-readiness.d.ts +84 -0
- package/dist/adapter/ingest/mount-readiness.d.ts.map +1 -0
- package/dist/adapter/ingest/mount-readiness.js +81 -0
- package/dist/adapter/ingest/scene-capture.d.ts +91 -2
- package/dist/adapter/ingest/scene-capture.d.ts.map +1 -1
- package/dist/adapter/ingest/scene-capture.js +110 -18
- package/dist/adapter/ingest/structural-ids.d.ts +11 -5
- package/dist/adapter/ingest/structural-ids.d.ts.map +1 -1
- package/dist/adapter/ingest/structural-ids.js +18 -9
- package/dist/adapter/ingest/upstream-pin.d.ts +4 -2
- package/dist/adapter/ingest/upstream-pin.d.ts.map +1 -1
- package/dist/adapter/ingest/upstream-pin.js +4 -2
- package/dist/adapter/ingest/visible-capture-window.d.ts +116 -0
- package/dist/adapter/ingest/visible-capture-window.d.ts.map +1 -0
- package/dist/adapter/ingest/visible-capture-window.js +141 -0
- package/dist/adapter/loop-gate-report.d.ts +3 -4
- package/dist/adapter/loop-gate-report.d.ts.map +1 -1
- package/dist/adapter/loop-gate-report.js +3 -4
- package/dist/adapter/root-adapter.d.ts +22 -2
- package/dist/adapter/root-adapter.d.ts.map +1 -1
- package/dist/adapter/setup-three-root-adapter.d.ts.map +1 -1
- package/dist/adapter/setup-three-root-adapter.js +15 -0
- package/dist/adapter/system-adapter.d.ts +161 -2
- package/dist/adapter/system-adapter.d.ts.map +1 -1
- package/dist/adapter/system-adapter.js +18 -1
- package/dist/animation/camera-ownership.d.ts +4 -2
- package/dist/animation/camera-ownership.d.ts.map +1 -1
- package/dist/animation/camera-ownership.js +58 -1
- package/dist/animation/runtime-inspection.d.ts +70 -0
- package/dist/animation/runtime-inspection.d.ts.map +1 -0
- package/dist/animation/runtime-inspection.js +25 -0
- package/dist/animation/xstate-animation-binding.d.ts +9 -1
- package/dist/animation/xstate-animation-binding.d.ts.map +1 -1
- package/dist/animation/xstate-animation-binding.js +48 -1
- package/dist/asset-formats/material.d.ts +1 -1
- package/dist/asset-formats/mesh.d.ts +1 -1
- package/dist/asset-formats/particles.d.ts +13 -0
- package/dist/asset-formats/particles.d.ts.map +1 -1
- package/dist/asset-formats/particles.js +28 -0
- package/dist/behavior/xstate-inspection.d.ts +24 -0
- package/dist/behavior/xstate-inspection.d.ts.map +1 -0
- package/dist/behavior/xstate-inspection.js +25 -0
- package/dist/core/game-loop.d.ts +7 -5
- package/dist/core/game-loop.d.ts.map +1 -1
- package/dist/core/game-loop.js +39 -18
- package/dist/core/types.d.ts +11 -12
- package/dist/core/types.d.ts.map +1 -1
- package/dist/data/data-asset.js +1 -1
- package/dist/dev/instruments.d.ts.map +1 -1
- package/dist/dev/instruments.js +5 -1
- package/dist/dev/render-debug-adapter.d.ts +19 -2
- package/dist/dev/render-debug-adapter.d.ts.map +1 -1
- package/dist/dev/render-debug-adapter.js +10 -0
- package/dist/ecs/user-data.d.ts +10 -2
- package/dist/ecs/user-data.d.ts.map +1 -1
- package/dist/ecs/user-data.js +6 -2
- package/dist/input/binding-identity.d.ts +10 -0
- package/dist/input/binding-identity.d.ts.map +1 -0
- package/dist/input/binding-identity.js +36 -0
- package/dist/input/input-manager.d.ts +18 -185
- package/dist/input/input-manager.d.ts.map +1 -1
- package/dist/input/input-manager.js +78 -68
- package/dist/manifest/load.d.ts +14 -0
- package/dist/manifest/load.d.ts.map +1 -1
- package/dist/manifest/load.js +6 -1
- package/dist/manifest/schema.d.ts +18 -0
- package/dist/manifest/schema.d.ts.map +1 -1
- package/dist/manifest/schema.js +64 -7
- package/dist/pixi/authoring.d.ts +27 -0
- package/dist/pixi/authoring.d.ts.map +1 -1
- package/dist/pixi/authoring.js +10 -3
- package/dist/pixi/index.d.ts +1 -1
- package/dist/pixi/index.d.ts.map +1 -1
- package/dist/pixi/index.js +1 -1
- package/dist/pixi/ingest.d.ts +8 -0
- package/dist/pixi/ingest.d.ts.map +1 -1
- package/dist/pixi/ingest.js +10 -1
- package/dist/pixi/render-pass-bracket.d.ts +56 -0
- package/dist/pixi/render-pass-bracket.d.ts.map +1 -0
- package/dist/pixi/render-pass-bracket.js +98 -0
- package/dist/pixi/scene-capture.d.ts +32 -1
- package/dist/pixi/scene-capture.d.ts.map +1 -1
- package/dist/pixi/scene-capture.js +21 -9
- package/dist/pixi/system-adapters.d.ts +29 -0
- package/dist/pixi/system-adapters.d.ts.map +1 -1
- package/dist/pixi/system-adapters.js +27 -0
- package/dist/render/particles-factory.d.ts +16 -2
- package/dist/render/particles-factory.d.ts.map +1 -1
- package/dist/render/particles-factory.js +88 -5
- package/dist/render/soft-particle-depth.d.ts +149 -0
- package/dist/render/soft-particle-depth.d.ts.map +1 -0
- package/dist/render/soft-particle-depth.js +305 -0
- package/dist/render/voxel-surface.d.ts +117 -0
- package/dist/render/voxel-surface.d.ts.map +1 -0
- package/dist/render/voxel-surface.js +263 -0
- package/dist/runtime/create-runtime.js +7 -0
- package/dist/runtime/debug-bridge.d.ts +15 -15
- package/dist/runtime/debug-bridge.d.ts.map +1 -1
- package/dist/runtime/debug-bridge.js +27 -26
- package/dist/runtime/game.d.ts.map +1 -1
- package/dist/runtime/game.js +1 -2
- package/dist/setup/setup-particles.d.ts.map +1 -1
- package/dist/setup/setup-particles.js +9 -0
- package/dist/world3d-react/r3f-adapter.d.ts.map +1 -1
- package/dist/world3d-react/r3f-adapter.js +42 -3
- package/dist/world3d-react/rapier-physics-bridge.d.ts.map +1 -1
- package/dist/world3d-react/rapier-physics-bridge.js +201 -11
- package/dist-config/config.js.map +1 -1
- package/package.json +4 -2
- package/schemas/engine-capabilities.json +12 -12
- package/schemas/vgai-project.schema.json +41 -2
- package/src/adapter/adapter-module.ts +607 -0
- package/src/adapter/authoring.ts +440 -10
- package/src/adapter/constraint.ts +10 -3
- package/src/adapter/finders/finder-result.ts +29 -0
- package/src/adapter/finders/index.ts +62 -0
- package/src/adapter/finders/prefabs-from-stories.ts +142 -0
- package/src/adapter/finders/scenes-from-entrypoint-selection.ts +304 -0
- package/src/adapter/first-party-systems.ts +30 -0
- package/src/adapter/index.ts +32 -1
- package/src/adapter/ingest/contract-system-adapters.ts +116 -32
- package/src/adapter/ingest/game-contract.ts +265 -2
- package/src/adapter/ingest/mount-readiness.ts +140 -0
- package/src/adapter/ingest/scene-capture.ts +199 -22
- package/src/adapter/ingest/structural-ids.ts +21 -9
- package/src/adapter/ingest/upstream-pin.ts +4 -2
- package/src/adapter/ingest/visible-capture-window.ts +213 -0
- package/src/adapter/loop-gate-report.ts +3 -4
- package/src/adapter/root-adapter.ts +22 -2
- package/src/adapter/setup-three-root-adapter.ts +16 -0
- package/src/adapter/system-adapter.ts +188 -2
- package/src/animation/camera-ownership.ts +68 -3
- package/src/animation/runtime-inspection.ts +104 -0
- package/src/animation/xstate-animation-binding.ts +53 -1
- package/src/asset-formats/particles.ts +31 -0
- package/src/behavior/xstate-inspection.ts +51 -0
- package/src/core/game-loop.ts +39 -17
- package/src/core/types.ts +11 -12
- package/src/data/data-asset.ts +1 -1
- package/src/dev/instruments.ts +5 -1
- package/src/dev/render-debug-adapter.ts +22 -2
- package/src/ecs/user-data.ts +10 -2
- package/src/input/binding-identity.ts +37 -0
- package/src/input/input-manager.ts +93 -68
- package/src/manifest/load.ts +23 -2
- package/src/manifest/schema.ts +76 -7
- package/src/pixi/authoring.ts +37 -5
- package/src/pixi/index.ts +2 -0
- package/src/pixi/ingest.ts +15 -2
- package/src/pixi/render-pass-bracket.ts +117 -0
- package/src/pixi/scene-capture.ts +63 -13
- package/src/pixi/system-adapters.ts +41 -0
- package/src/render/particles-factory.ts +89 -6
- package/src/render/soft-particle-depth.ts +336 -0
- package/src/render/voxel-surface.ts +358 -0
- package/src/runtime/create-runtime.ts +7 -0
- package/src/runtime/debug-bridge.ts +32 -31
- package/src/runtime/game.ts +1 -2
- package/src/setup/setup-particles.ts +9 -0
- package/src/world3d-react/r3f-adapter.tsx +48 -2
- package/src/world3d-react/rapier-physics-bridge.tsx +249 -11
package/dist/core/game-loop.js
CHANGED
|
@@ -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
|
|
60
|
+
let visibilityPaused = false;
|
|
56
61
|
let visibilityListenerAttached = false;
|
|
57
|
-
|
|
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
|
-
|
|
75
|
+
visibilityPaused = true;
|
|
65
76
|
}
|
|
66
77
|
}
|
|
67
|
-
else if (
|
|
68
|
-
|
|
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-
|
|
105
|
-
// (`
|
|
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
|
-
// `
|
|
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
|
-
|
|
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
|
-
|
|
147
|
+
visibilityPaused = true;
|
|
134
148
|
return;
|
|
135
149
|
}
|
|
136
150
|
rafId = requestAnimationFrame(frame);
|
|
137
151
|
},
|
|
138
152
|
stop() {
|
|
139
153
|
running = false;
|
|
140
|
-
|
|
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
|
|
154
|
-
* `
|
|
155
|
-
*
|
|
156
|
-
* so
|
|
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 `
|
|
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
|
-
|
|
163
|
-
|
|
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) {
|
package/dist/core/types.d.ts
CHANGED
|
@@ -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'` —
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
* - `'
|
|
100
|
-
*
|
|
101
|
-
*
|
|
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`
|
|
105
|
-
* `
|
|
106
|
-
*
|
|
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' | '
|
|
109
|
+
export type GameLoopLiveness = 'running' | 'loop-starved' | 'stopped';
|
|
111
110
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/core/types.d.ts.map
CHANGED
|
@@ -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
|
|
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"}
|
package/dist/data/data-asset.js
CHANGED
|
@@ -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
|
|
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;
|
|
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"}
|
package/dist/dev/instruments.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
/**
|
|
35
|
-
|
|
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
|
|
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;
|
package/dist/ecs/user-data.d.ts
CHANGED
|
@@ -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
|
-
* - `
|
|
50
|
-
*
|
|
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":"AAAA
|
|
1
|
+
{"version":3,"file":"user-data.d.ts","sourceRoot":"","sources":["../../src/ecs/user-data.ts"],"names":[],"mappings":"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"}
|
package/dist/ecs/user-data.js
CHANGED
|
@@ -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
|
-
* - `
|
|
50
|
-
*
|
|
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
|
-
/**
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
|
|
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
|