@vgai/engine 0.5.14 → 0.5.16
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 +228 -17
- package/dist/adapter/adapter-module.d.ts.map +1 -1
- package/dist/adapter/adapter-module.js +224 -42
- package/dist/adapter/authoring-seam-contract.d.ts +530 -0
- package/dist/adapter/authoring-seam-contract.d.ts.map +1 -0
- package/dist/adapter/authoring-seam-contract.js +162 -0
- package/dist/adapter/authoring.d.ts +237 -50
- package/dist/adapter/authoring.d.ts.map +1 -1
- package/dist/adapter/authoring.js +2 -1
- package/dist/adapter/entrypoint-selection-source.d.ts +35 -0
- package/dist/adapter/entrypoint-selection-source.d.ts.map +1 -0
- package/dist/adapter/entrypoint-selection-source.js +151 -0
- package/dist/adapter/finders/scenes-from-entrypoint-selection.d.ts +7 -1
- package/dist/adapter/finders/scenes-from-entrypoint-selection.d.ts.map +1 -1
- package/dist/adapter/finders/scenes-from-entrypoint-selection.js +142 -21
- package/dist/adapter/first-party-systems.d.ts +13 -3
- package/dist/adapter/first-party-systems.d.ts.map +1 -1
- package/dist/adapter/first-party-systems.js +10 -3
- package/dist/adapter/index.d.ts +7 -2
- package/dist/adapter/index.d.ts.map +1 -1
- package/dist/adapter/index.js +4 -0
- package/dist/adapter/ingest/contract-system-adapters.d.ts +1 -1
- package/dist/adapter/ingest/contract-system-adapters.d.ts.map +1 -1
- package/dist/adapter/ingest/contract-system-adapters.js +13 -25
- package/dist/adapter/ingest/game-contract-seams.d.ts +214 -0
- package/dist/adapter/ingest/game-contract-seams.d.ts.map +1 -0
- package/dist/adapter/ingest/game-contract-seams.js +62 -0
- package/dist/adapter/ingest/game-contract.d.ts +5 -3
- package/dist/adapter/ingest/game-contract.d.ts.map +1 -1
- package/dist/adapter/ingest/game-contract.js +4 -1
- package/dist/adapter/ingest/merge-debug-adapters.d.ts +52 -0
- package/dist/adapter/ingest/merge-debug-adapters.d.ts.map +1 -0
- package/dist/adapter/ingest/merge-debug-adapters.js +141 -0
- package/dist/adapter/ingest/observation-debug-adapter.d.ts +56 -0
- package/dist/adapter/ingest/observation-debug-adapter.d.ts.map +1 -0
- package/dist/adapter/ingest/observation-debug-adapter.js +131 -0
- package/dist/adapter/ingest/scene-capture.d.ts +38 -13
- package/dist/adapter/ingest/scene-capture.d.ts.map +1 -1
- package/dist/adapter/ingest/scene-capture.js +101 -24
- package/dist/adapter/ingest/visible-capture-window.d.ts +22 -5
- package/dist/adapter/ingest/visible-capture-window.d.ts.map +1 -1
- package/dist/adapter/ingest/visible-capture-window.js +46 -7
- package/dist/adapter/native-debug-module.d.ts +43 -0
- package/dist/adapter/native-debug-module.d.ts.map +1 -0
- package/dist/adapter/native-debug-module.js +230 -0
- package/dist/adapter/object3d-authoring-subject.d.ts +32 -0
- package/dist/adapter/object3d-authoring-subject.d.ts.map +1 -0
- package/dist/adapter/object3d-authoring-subject.js +25 -0
- package/dist/adapter/root-adapter.d.ts +21 -56
- package/dist/adapter/root-adapter.d.ts.map +1 -1
- package/dist/adapter/root-adapter.js +4 -20
- package/dist/adapter/root-seam-contract.d.ts +124 -0
- package/dist/adapter/root-seam-contract.d.ts.map +1 -0
- package/dist/adapter/root-seam-contract.js +36 -0
- package/dist/adapter/seam-evidence.d.ts +118 -0
- package/dist/adapter/seam-evidence.d.ts.map +1 -0
- package/dist/adapter/seam-evidence.js +231 -0
- package/dist/adapter/setup-three-root-adapter.d.ts +2 -3
- package/dist/adapter/setup-three-root-adapter.d.ts.map +1 -1
- package/dist/adapter/setup-three-root-adapter.js +2 -3
- package/dist/adapter/system-adapter.d.ts +6 -1
- package/dist/adapter/system-adapter.d.ts.map +1 -1
- package/dist/adapter/system-seam-contract.d.ts +354 -0
- package/dist/adapter/system-seam-contract.d.ts.map +1 -0
- package/dist/adapter/system-seam-contract.js +95 -0
- package/dist/animation/xstate-animation-binding.d.ts +6 -0
- package/dist/animation/xstate-animation-binding.d.ts.map +1 -1
- package/dist/animation/xstate-animation-binding.js +142 -4
- package/dist/asset-formats/collider.d.ts +1 -1
- package/dist/asset-formats/mesh.d.ts +2 -2
- package/dist/asset-formats/particles.d.ts +1 -1
- package/dist/canvas-react/engine-bridge.d.ts +6 -6
- package/dist/canvas-react/engine-bridge.d.ts.map +1 -1
- package/dist/canvas-react/engine-bridge.js +2 -2
- package/dist/canvas-react/index.d.ts +2 -2
- package/dist/canvas-react/index.d.ts.map +1 -1
- package/dist/canvas-react/index.js +1 -1
- package/dist/canvas-react/pixi-react-adapter.d.ts +15 -9
- package/dist/canvas-react/pixi-react-adapter.d.ts.map +1 -1
- package/dist/canvas-react/pixi-react-adapter.js +43 -29
- package/dist/canvas-react/pixi-react-root-factory.d.ts.map +1 -1
- package/dist/canvas-react/pixi-react-root-factory.js +4 -0
- package/dist/canvas-react/world-context.d.ts +22 -12
- package/dist/canvas-react/world-context.d.ts.map +1 -1
- package/dist/canvas-react/world-context.js +12 -51
- package/dist/ecs/user-data.d.ts +5 -0
- package/dist/ecs/user-data.d.ts.map +1 -1
- package/dist/ecs/user-data.js +3 -0
- package/dist/input/input-manager.d.ts +49 -0
- package/dist/input/input-manager.d.ts.map +1 -1
- package/dist/input/input-manager.js +127 -0
- package/dist/manifest/schema.d.ts +9 -9
- package/dist/manifest/schema.js +1 -1
- package/dist/pixi/authoring.d.ts.map +1 -1
- package/dist/pixi/authoring.js +220 -1
- package/dist/pixi/ingest.d.ts +2 -1
- package/dist/pixi/ingest.d.ts.map +1 -1
- package/dist/pixi/ingest.js +4 -2
- package/dist/pixi/scene-capture.d.ts +9 -1
- package/dist/pixi/scene-capture.d.ts.map +1 -1
- package/dist/pixi/scene-capture.js +9 -6
- package/dist/render/particles-factory.d.ts +13 -6
- package/dist/render/particles-factory.d.ts.map +1 -1
- package/dist/render/particles-factory.js +6 -3
- package/dist/runtime/create-runtime.d.ts +23 -46
- package/dist/runtime/create-runtime.d.ts.map +1 -1
- package/dist/runtime/create-runtime.js +22 -67
- package/dist/runtime/game.d.ts +29 -71
- package/dist/runtime/game.d.ts.map +1 -1
- package/dist/runtime/game.js +15 -54
- package/dist/runtime/mount-game.d.ts.map +1 -1
- package/dist/runtime/mount-game.js +12 -1
- package/dist/runtime/mount-manifest.d.ts.map +1 -1
- package/dist/runtime/mount-manifest.js +4 -5
- package/dist/runtime/types.d.ts +18 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/setup/setup-renderer.d.ts +3 -4
- package/dist/setup/setup-renderer.d.ts.map +1 -1
- package/dist/setup/setup-renderer.js +3 -4
- package/dist/world3d-react/engine-bridge.d.ts +1 -1
- package/dist/world3d-react/engine-bridge.js +1 -1
- package/dist/world3d-react/r3f-adapter.d.ts +7 -0
- package/dist/world3d-react/r3f-adapter.d.ts.map +1 -1
- package/dist/world3d-react/r3f-adapter.js +50 -21
- package/dist/world3d-react/r3f-root-factory.d.ts.map +1 -1
- package/dist/world3d-react/r3f-root-factory.js +4 -0
- package/dist/world3d-react/world-context.d.ts +9 -3
- package/dist/world3d-react/world-context.d.ts.map +1 -1
- package/dist/world3d-react/world-context.js +5 -18
- package/package.json +1 -1
- package/schemas/engine-capabilities.json +8 -8
- package/schemas/vgai-project.schema.json +1 -1
- package/src/adapter/adapter-module.ts +407 -50
- package/src/adapter/authoring-seam-contract.ts +211 -0
- package/src/adapter/authoring.ts +242 -50
- package/src/adapter/entrypoint-selection-source.ts +159 -0
- package/src/adapter/finders/scenes-from-entrypoint-selection.ts +159 -28
- package/src/adapter/first-party-systems.ts +17 -3
- package/src/adapter/index.ts +51 -1
- package/src/adapter/ingest/contract-system-adapters.ts +26 -30
- package/src/adapter/ingest/game-contract-seams.ts +85 -0
- package/src/adapter/ingest/game-contract.ts +9 -4
- package/src/adapter/ingest/merge-debug-adapters.ts +193 -0
- package/src/adapter/ingest/observation-debug-adapter.ts +158 -0
- package/src/adapter/ingest/scene-capture.ts +126 -23
- package/src/adapter/ingest/visible-capture-window.ts +63 -9
- package/src/adapter/native-debug-module.ts +307 -0
- package/src/adapter/object3d-authoring-subject.ts +50 -0
- package/src/adapter/root-adapter.ts +21 -56
- package/src/adapter/root-seam-contract.ts +56 -0
- package/src/adapter/seam-evidence.ts +336 -0
- package/src/adapter/setup-three-root-adapter.ts +4 -6
- package/src/adapter/system-adapter.ts +6 -1
- package/src/adapter/system-seam-contract.ts +121 -0
- package/src/animation/xstate-animation-binding.ts +151 -4
- package/src/canvas-react/engine-bridge.ts +6 -6
- package/src/canvas-react/index.ts +2 -1
- package/src/canvas-react/pixi-react-adapter.tsx +55 -34
- package/src/canvas-react/pixi-react-root-factory.tsx +4 -0
- package/src/canvas-react/world-context.ts +26 -101
- package/src/ecs/user-data.ts +5 -0
- package/src/input/input-manager.ts +122 -0
- package/src/manifest/schema.ts +1 -1
- package/src/pixi/authoring.ts +236 -1
- package/src/pixi/ingest.ts +9 -2
- package/src/pixi/scene-capture.ts +20 -5
- package/src/render/particles-factory.ts +16 -6
- package/src/runtime/create-runtime.ts +41 -106
- package/src/runtime/game.ts +41 -111
- package/src/runtime/mount-game.ts +19 -1
- package/src/runtime/mount-manifest.ts +4 -5
- package/src/runtime/types.ts +22 -0
- package/src/setup/setup-renderer.ts +3 -4
- package/src/world3d-react/engine-bridge.ts +1 -1
- package/src/world3d-react/r3f-adapter.tsx +64 -24
- package/src/world3d-react/r3f-root-factory.tsx +4 -0
- package/src/world3d-react/world-context.ts +11 -36
|
@@ -35,6 +35,13 @@ export interface CreateR3FAdapterOptions {
|
|
|
35
35
|
* actions). A missing/invalid map degrades loudly without failing the
|
|
36
36
|
* mount — see `world-context.ts`. */
|
|
37
37
|
readonly inputMapPath?: string | null | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Transitional compatibility for explicit pre-native adapters. The
|
|
40
|
+
* default-export root factory always passes `false`: ordinary R3F trees get
|
|
41
|
+
* no vgai context/provider or private scheduler. Remove this switch with
|
|
42
|
+
* the last explicit legacy adapter migration.
|
|
43
|
+
*/
|
|
44
|
+
readonly engineRuntime?: boolean | undefined;
|
|
38
45
|
/** The colour pipeline this world was AUTHORED for, applied to the host's renderer for the life
|
|
39
46
|
* of the mount and restored on dispose. Omit it (every world here does) to keep the host's own
|
|
40
47
|
* defaults; declare it when the world's colours were picked against a different engine's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"r3f-adapter.d.ts","sourceRoot":"","sources":["../../src/world3d-react/r3f-adapter.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;
|
|
1
|
+
{"version":3,"file":"r3f-adapter.d.ts","sourceRoot":"","sources":["../../src/world3d-react/r3f-adapter.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAWH,OAAO,EAA2B,KAAK,SAAS,EAAsB,MAAM,OAAO,CAAC;AACpF,OAAO,KAAK,EAAoB,WAAW,EAAoB,MAAM,YAAY,CAAC;AAgBlF,OAAO,EAA4B,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AA2CvF,sEAAsE;AACtE,MAAM,WAAW,uBAAuB;IACtC,qEAAqE;IACrE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;;uBAEmB;IACnB,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAC5B;;;;0CAIsC;IACtC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClD;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7C;;;iDAG6C;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;CACrD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,WAAW,CA2gB9E"}
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* project guarantees via its Vite `resolve.dedupe: ['three', 'react',
|
|
19
19
|
* 'react-dom']` (see `examples/r3f-first-party/vite.config.ts`).
|
|
20
20
|
*/
|
|
21
|
-
import { advance, createRoot, extend, events as pointerEvents, useFrame, } from '@react-three/fiber';
|
|
21
|
+
import { advance, createRoot, extend, flushSync, events as pointerEvents, useFrame, } from '@react-three/fiber';
|
|
22
22
|
import { createElement, Fragment, useEffect, useMemo } from 'react';
|
|
23
23
|
import { registerRenderVitals } from '../dev/register-render-vitals';
|
|
24
24
|
import { createRenderDebugAdapter, frameCaptureContextFor, } from '../dev/render-debug-adapter';
|
|
@@ -27,6 +27,7 @@ import { RENDER_SUBMIT_PHASE } from '../dev/render-vitals';
|
|
|
27
27
|
import { createWebGLFrameCapture } from '../dev/webgl-frame-capture';
|
|
28
28
|
import { WorldProvider } from '../react/world-state';
|
|
29
29
|
import { createSoftParticleDepthPass } from '../render/soft-particle-depth';
|
|
30
|
+
import { getDebugRegistry } from '../runtime/debug-registry';
|
|
30
31
|
import { devLayersEnabled } from '../runtime/dev-layers';
|
|
31
32
|
import { EngineBridge } from './engine-bridge';
|
|
32
33
|
import { applyWorldRendererConfig } from './renderer-config';
|
|
@@ -68,7 +69,7 @@ function SoftParticleDepth() {
|
|
|
68
69
|
* second `requestAnimationFrame` loop (design §1.C).
|
|
69
70
|
*/
|
|
70
71
|
export function createR3FAdapter(options) {
|
|
71
|
-
const { id, content, inputMapPath, renderer: rendererConfig } = options;
|
|
72
|
+
const { id, content, inputMapPath, engineRuntime = true, renderer: rendererConfig } = options;
|
|
72
73
|
return {
|
|
73
74
|
id,
|
|
74
75
|
async mount(host) {
|
|
@@ -122,15 +123,14 @@ export function createR3FAdapter(options) {
|
|
|
122
123
|
// for one is a compile error rather than anything that can happen at
|
|
123
124
|
// runtime. `scene`/`camera` are backfilled right after fiber's first
|
|
124
125
|
// commit resolves them, before any tick can run.
|
|
125
|
-
const runtime = createR3FRootContext(host, { id, inputMapPath });
|
|
126
|
-
const { systems } = runtime;
|
|
126
|
+
const runtime = engineRuntime ? createR3FRootContext(host, { id, inputMapPath }) : null;
|
|
127
127
|
// `ctx` rides the bridge so ordinary components can reach engine
|
|
128
128
|
// services through `useGameContext()`.
|
|
129
|
-
const bridge = { ctx: runtime.ctx };
|
|
129
|
+
const bridge = runtime ? { ctx: runtime.ctx } : null;
|
|
130
130
|
// Actions must exist before any component's init()/first frame reads
|
|
131
131
|
// them — wait for the (never-rejecting) input-map load before the first
|
|
132
132
|
// commit.
|
|
133
|
-
await runtime
|
|
133
|
+
await runtime?.inputMapReady;
|
|
134
134
|
// The world's own colour pipeline. Applied AFTER `root.configure()` below — see the comment
|
|
135
135
|
// at its call site for why "before" is the version that silently does nothing.
|
|
136
136
|
let restoreRendererConfig = () => { };
|
|
@@ -147,6 +147,19 @@ export function createR3FAdapter(options) {
|
|
|
147
147
|
const statePromise = new Promise((resolve) => {
|
|
148
148
|
resolveState = resolve;
|
|
149
149
|
});
|
|
150
|
+
let resolveEffectsReady;
|
|
151
|
+
const effectsReady = new Promise((resolve) => {
|
|
152
|
+
resolveEffectsReady = resolve;
|
|
153
|
+
});
|
|
154
|
+
// Rendered after the game's content. React runs passive effects in tree
|
|
155
|
+
// order, so when this fires every useDebugProvider/useDebugCommand in
|
|
156
|
+
// the initial tree has registered. A Play acknowledgement is a claim
|
|
157
|
+
// that the mounted game's command surface exists, not merely that Fiber
|
|
158
|
+
// allocated a scene.
|
|
159
|
+
function MountEffectsReady() {
|
|
160
|
+
useEffect(resolveEffectsReady, []);
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
150
163
|
// `root.configure()` is ASYNC in fiber v9 (`Promise<ReconcilerRoot>`)
|
|
151
164
|
// — the design doc's §1.C sketch shows it called synchronously; the
|
|
152
165
|
// real v9 API (verified against
|
|
@@ -244,11 +257,13 @@ export function createR3FAdapter(options) {
|
|
|
244
257
|
// until this landed. `host.game` is genuinely absent in bare/headless
|
|
245
258
|
// hosts, so the provider is conditional and those hooks stay the inert
|
|
246
259
|
// no-ops they already document themselves to be.
|
|
247
|
-
const game = runtime
|
|
260
|
+
const game = runtime?.ctx.game;
|
|
248
261
|
// `SoftParticleDepth` trails the world's own tree deliberately — see its
|
|
249
262
|
// docblock for why the subscription must land last.
|
|
250
|
-
const world = createElement(Fragment, null, content, createElement(SoftParticleDepth, { key: 'vgai-soft-particle-depth' }));
|
|
251
|
-
root.render(
|
|
263
|
+
const world = createElement(Fragment, null, content, runtime ? createElement(SoftParticleDepth, { key: 'vgai-soft-particle-depth' }) : null, createElement(MountEffectsReady, { key: 'vgai-mount-effects-ready' }));
|
|
264
|
+
root.render(bridge
|
|
265
|
+
? createElement(EngineBridge.Provider, { value: bridge }, game ? createElement(WorldProvider, { game }, world) : world)
|
|
266
|
+
: world);
|
|
252
267
|
// A reconcile-time crash (e.g. a missing `extend` catalogue entry)
|
|
253
268
|
// surfaces as an uncaught window error and `onCreated` never fires —
|
|
254
269
|
// without this guard, `mount()` would await `statePromise` FOREVER and
|
|
@@ -258,7 +273,7 @@ export function createR3FAdapter(options) {
|
|
|
258
273
|
const onError = (event) => {
|
|
259
274
|
cleanup();
|
|
260
275
|
root.unmount();
|
|
261
|
-
runtime
|
|
276
|
+
runtime?.dispose();
|
|
262
277
|
restoreRendererConfig();
|
|
263
278
|
reject(new Error(`r3f-adapter: fiber crashed before its first commit — ${event.message} ` +
|
|
264
279
|
'(mount() fails loudly instead of hanging on onCreated)'));
|
|
@@ -266,7 +281,7 @@ export function createR3FAdapter(options) {
|
|
|
266
281
|
const timer = setTimeout(() => {
|
|
267
282
|
cleanup();
|
|
268
283
|
root.unmount();
|
|
269
|
-
runtime
|
|
284
|
+
runtime?.dispose();
|
|
270
285
|
restoreRendererConfig();
|
|
271
286
|
reject(new Error('r3f-adapter: onCreated did not fire within 10s — the R3F tree never reached ' +
|
|
272
287
|
'its first commit (mount() fails loudly instead of hanging)'));
|
|
@@ -276,7 +291,7 @@ export function createR3FAdapter(options) {
|
|
|
276
291
|
window.removeEventListener('error', onError);
|
|
277
292
|
};
|
|
278
293
|
window.addEventListener('error', onError);
|
|
279
|
-
void statePromise.then((s) => {
|
|
294
|
+
void Promise.all([statePromise, effectsReady]).then(([s]) => {
|
|
280
295
|
cleanup();
|
|
281
296
|
resolve(s);
|
|
282
297
|
});
|
|
@@ -294,7 +309,7 @@ export function createR3FAdapter(options) {
|
|
|
294
309
|
// Backfill the component runtime's ctx with fiber's real scene/camera
|
|
295
310
|
// (W3 — see the HONESTY NOTE above). This happens before the first
|
|
296
311
|
// `update(dt)` tick, so no component ever observes them missing.
|
|
297
|
-
runtime
|
|
312
|
+
runtime?.setSceneCamera(state.scene, state.camera);
|
|
298
313
|
// THE STORE IS THE TRUTH, NOT THE `onCreated` SNAPSHOT.
|
|
299
314
|
//
|
|
300
315
|
// `state` is one immutable zustand snapshot: fiber's store is
|
|
@@ -319,6 +334,7 @@ export function createR3FAdapter(options) {
|
|
|
319
334
|
// `RootState` for precisely this reason, so reading it per frame is the
|
|
320
335
|
// supported way to see the live root. It is a plain map read.
|
|
321
336
|
const live = () => state.get();
|
|
337
|
+
const gameDebugRegistry = host.game ? getDebugRegistry(host.game) : null;
|
|
322
338
|
// --- Live render vitals (issue #1504), for an R3F world -----------------
|
|
323
339
|
// The SAME door the classic adapter seeds
|
|
324
340
|
// (`../adapter/setup-three-root-adapter.ts`), seeded here for the same
|
|
@@ -357,8 +373,11 @@ export function createR3FAdapter(options) {
|
|
|
357
373
|
// sets on play — under the dev gate this is the same cost arriving a
|
|
358
374
|
// little earlier, not a new one.
|
|
359
375
|
host.game.profiler.enabled = true;
|
|
376
|
+
if (!gameDebugRegistry) {
|
|
377
|
+
throw new Error('r3f-adapter: mounted Game has no debug registry.');
|
|
378
|
+
}
|
|
360
379
|
renderVitals = registerRenderVitals({
|
|
361
|
-
registry:
|
|
380
|
+
registry: gameDebugRegistry,
|
|
362
381
|
worldId: id,
|
|
363
382
|
profiler: host.game.profiler,
|
|
364
383
|
scene: live().scene,
|
|
@@ -382,8 +401,12 @@ export function createR3FAdapter(options) {
|
|
|
382
401
|
memory: () => collectRenderMemory(live().scene, host.renderer.info),
|
|
383
402
|
})
|
|
384
403
|
: null;
|
|
404
|
+
// The session debug registry is host instrumentation, not component
|
|
405
|
+
// context. Publishing the existing adapter here lets coverage and
|
|
406
|
+
// editor panels see the same door without wrapping the R3F tree.
|
|
407
|
+
const systemAdapters = runtime?.systemAdapters ?? (gameDebugRegistry ? { debug: gameDebugRegistry.adapter } : {});
|
|
385
408
|
if (renderDebugWiring)
|
|
386
|
-
|
|
409
|
+
systemAdapters.renderDebug = renderDebugWiring.adapter;
|
|
387
410
|
// The engine drives every `useFrame` through the mounted world's
|
|
388
411
|
// `update(dt)` hook, never off a raw host-loop callback. That is the
|
|
389
412
|
// whole pause story: `runFrameImpl` (`runtime/game.ts`) calls
|
|
@@ -411,7 +434,7 @@ export function createR3FAdapter(options) {
|
|
|
411
434
|
// resumed frame as one giant `useFrame` delta — the exact "time passed
|
|
412
435
|
// while frozen" illusion acceptance gate 2 forbids.
|
|
413
436
|
let elapsed = 0;
|
|
414
|
-
/** The
|
|
437
|
+
/** The legacy component ctx camera last backfilled by `update()`. */
|
|
415
438
|
let backfilledCamera = state.camera;
|
|
416
439
|
return {
|
|
417
440
|
kind: 'three',
|
|
@@ -444,7 +467,7 @@ export function createR3FAdapter(options) {
|
|
|
444
467
|
// WebGL2 context exists, `renderDebug` are engine-seeded. Game code
|
|
445
468
|
// adds its own capabilities via `ctx.registerSystemAdapter` exactly
|
|
446
469
|
// as in a classic world.
|
|
447
|
-
systems:
|
|
470
|
+
systems: systemAdapters,
|
|
448
471
|
update(dt) {
|
|
449
472
|
elapsed += dt;
|
|
450
473
|
const current = live();
|
|
@@ -453,14 +476,14 @@ export function createR3FAdapter(options) {
|
|
|
453
476
|
// component reading one while the frame uses the other is the
|
|
454
477
|
// silent kind of wrong. Identity-gated, so this is one comparison
|
|
455
478
|
// per frame in the overwhelmingly common no-swap case.
|
|
456
|
-
if (current.camera !== backfilledCamera) {
|
|
479
|
+
if (runtime && current.camera !== backfilledCamera) {
|
|
457
480
|
backfilledCamera = current.camera;
|
|
458
481
|
runtime.setSceneCamera(current.scene, current.camera);
|
|
459
482
|
}
|
|
460
483
|
// Engine phases FIRST (registered systems mutate transforms),
|
|
461
484
|
// then fiber's advance (useFrame callbacks + the actual render see
|
|
462
485
|
// the fresh state). Both are host-gated: neither runs while frozen.
|
|
463
|
-
systems.run(dt);
|
|
486
|
+
runtime?.systems.run(dt);
|
|
464
487
|
renderDebugWiring?.beforeRender();
|
|
465
488
|
try {
|
|
466
489
|
const profiler = host.game?.profiler;
|
|
@@ -513,7 +536,13 @@ export function createR3FAdapter(options) {
|
|
|
513
536
|
// Reject/restore a pending capture while its renderables still
|
|
514
537
|
// exist, then unmount component effects and strip runtime state.
|
|
515
538
|
renderDebugWiring?.dispose();
|
|
516
|
-
|
|
539
|
+
// The editor audits and disposes the mounted game's window/document realm immediately
|
|
540
|
+
// after `session.stop()`. Fiber's ordinary `unmount()` submits a concurrent reconciler
|
|
541
|
+
// update, so component effect cleanups could still be pending at that boundary and the
|
|
542
|
+
// audit would truthfully report/reclaim listeners the world was about to remove itself.
|
|
543
|
+
// Force the unmount COMMIT (not fiber's deliberately delayed renderer/context disposal)
|
|
544
|
+
// to finish here: a stopped root owns no live component lifecycle beyond this method.
|
|
545
|
+
flushSync(() => root.unmount());
|
|
517
546
|
// The vitals fold owns two `profiler.subscribe` registrations, and
|
|
518
547
|
// `runtime.dispose()`'s `strip(id)` removes the REGISTRATIONS only —
|
|
519
548
|
// this is the one path that ends the subscriptions, exactly as the
|
|
@@ -521,7 +550,7 @@ export function createR3FAdapter(options) {
|
|
|
521
550
|
// subscription can never outlive the door it feeds.
|
|
522
551
|
renderVitals?.dispose();
|
|
523
552
|
renderVitals = null;
|
|
524
|
-
runtime
|
|
553
|
+
runtime?.dispose();
|
|
525
554
|
restoreRendererConfig();
|
|
526
555
|
},
|
|
527
556
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"r3f-root-factory.d.ts","sourceRoot":"","sources":["../../src/world3d-react/r3f-root-factory.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAUnE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"r3f-root-factory.d.ts","sourceRoot":"","sources":["../../src/world3d-react/r3f-root-factory.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAUnE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAc/F;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,qBAQ5B,CAAC"}
|
|
@@ -59,6 +59,10 @@ export function resolveR3FEntryAdapter(entryModule, rootId) {
|
|
|
59
59
|
return createR3FAdapter({
|
|
60
60
|
id: rootId,
|
|
61
61
|
content: createElement(mod.default),
|
|
62
|
+
// A default-exported R3F component is an ordinary R3F app. The host
|
|
63
|
+
// controls Fiber's native `frameloop: 'never'` scheduler; vgai runtime
|
|
64
|
+
// context, systems and state providers never enter its React tree.
|
|
65
|
+
engineRuntime: false,
|
|
62
66
|
});
|
|
63
67
|
}
|
|
64
68
|
return null;
|
|
@@ -13,12 +13,15 @@
|
|
|
13
13
|
* `ctx.debug = registry.forRoot(id)`, so a component's
|
|
14
14
|
* effect can `ctx.debug.registerStateProvider(...)` and be visible
|
|
15
15
|
* to `vgai eval`/the editor's debug panels — previously a silent no-op.
|
|
16
|
-
* 2. **`ctx.input` is the game-owned `InputManager
|
|
16
|
+
* 2. **`ctx.input` is the game-owned `InputManager` when a Game hosts the
|
|
17
|
+
* root** (`host.game.input` —
|
|
17
18
|
* the same instance the classic adapter uses when hosted), and this
|
|
18
19
|
* module registers the SAME per-world debug-registry seams the classic
|
|
19
20
|
* adapter registers (`setVirtualInputTarget`/`setInputActionsSource`/
|
|
20
21
|
* `setInputTraceSource`), which is what makes `game.input.*` (the bot
|
|
21
22
|
* input doctrine) work instead of throwing `DEBUG_INPUT_UNAVAILABLE`.
|
|
23
|
+
* A bare/foreign mount receives `null`, visibly in the type, rather than
|
|
24
|
+
* a getter that throws later inside a frame callback.
|
|
22
25
|
* The project's input map is loaded through `Game.loadInputMap` (the
|
|
23
26
|
* game-owned, load-once path every root shares) with the SAME default
|
|
24
27
|
* path the classic adapter uses. A missing/unparseable map degrades
|
|
@@ -36,7 +39,7 @@ import type { ThreeHostContext } from '../adapter';
|
|
|
36
39
|
import type { SystemAdapters } from '../adapter/system-adapter';
|
|
37
40
|
import { createSystemRunner } from '../core/system-runner';
|
|
38
41
|
import { type DebugRegistry } from '../runtime/debug-registry';
|
|
39
|
-
import type { GameContext } from '../runtime/types';
|
|
42
|
+
import type { ComponentContextBase, GameContext } from '../runtime/types';
|
|
40
43
|
/** The classic adapter's default input-map path — the conventional location
|
|
41
44
|
* every scaffolded project ships (`public/inputmaps/default.inputmap.json`). */
|
|
42
45
|
export declare const DEFAULT_INPUT_MAP_PATH = "/inputmaps/default.inputmap.json";
|
|
@@ -75,7 +78,10 @@ export declare const DEFAULT_INPUT_MAP_PATH = "/inputmaps/default.inputmap.json"
|
|
|
75
78
|
* exporting `setup(ctx): Promise<GameCleanup>`, which `SetupThreeRootAdapter`
|
|
76
79
|
* mounts with the complete {@link GameContext}.
|
|
77
80
|
*/
|
|
78
|
-
export type R3FGameContext = Pick<GameContext, 'scene' | '
|
|
81
|
+
export type R3FGameContext = ComponentContextBase & Pick<GameContext, 'scene' | 'sceneIndex' | 'assets' | 'clock'> & {
|
|
82
|
+
/** Fiber may install either a perspective or orthographic camera. */
|
|
83
|
+
camera: THREE.Camera;
|
|
84
|
+
};
|
|
79
85
|
export interface R3FRootContextOptions {
|
|
80
86
|
/** World id — provenance for every debug-registry registration (matches the
|
|
81
87
|
* manifest root id by the same convention the classic adapter follows). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"world-context.d.ts","sourceRoot":"","sources":["../../src/world3d-react/world-context.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"world-context.d.ts","sourceRoot":"","sources":["../../src/world3d-react/world-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAmCK;AAEL,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAOhE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EAEL,KAAK,aAAa,EAEnB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,KAAK,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE1E;iFACiF;AACjF,eAAO,MAAM,sBAAsB,qCAAqC,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,MAAM,cAAc,GAAG,oBAAoB,GAC/C,IAAI,CAAC,WAAW,EAAE,OAAO,GAAG,YAAY,GAAG,QAAQ,GAAG,OAAO,CAAC,GAAG;IAC/D,qEAAqE;IACrE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;CACtB,CAAC;AAEJ,MAAM,WAAW,qBAAqB;IACpC;gFAC4E;IAC5E,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACnD;AAED;+EAC+E;AAC/E,MAAM,WAAW,cAAc;IAC7B;6EACyE;IACzE,QAAQ,CAAC,GAAG,EAAE,cAAc,CAAC;IAC7B,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;IACxD;;mFAE+E;IAC/E,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC;;;;;;yDAMqD;IACrD,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC;qEACiE;IACjE,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC;;;4DAGwD;IACxD,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;IAC/D;;gFAE4E;IAC5E,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,qBAAqB,GAC7B,cAAc,CAqJhB"}
|
|
@@ -13,12 +13,15 @@
|
|
|
13
13
|
* `ctx.debug = registry.forRoot(id)`, so a component's
|
|
14
14
|
* effect can `ctx.debug.registerStateProvider(...)` and be visible
|
|
15
15
|
* to `vgai eval`/the editor's debug panels — previously a silent no-op.
|
|
16
|
-
* 2. **`ctx.input` is the game-owned `InputManager
|
|
16
|
+
* 2. **`ctx.input` is the game-owned `InputManager` when a Game hosts the
|
|
17
|
+
* root** (`host.game.input` —
|
|
17
18
|
* the same instance the classic adapter uses when hosted), and this
|
|
18
19
|
* module registers the SAME per-world debug-registry seams the classic
|
|
19
20
|
* adapter registers (`setVirtualInputTarget`/`setInputActionsSource`/
|
|
20
21
|
* `setInputTraceSource`), which is what makes `game.input.*` (the bot
|
|
21
22
|
* input doctrine) work instead of throwing `DEBUG_INPUT_UNAVAILABLE`.
|
|
23
|
+
* A bare/foreign mount receives `null`, visibly in the type, rather than
|
|
24
|
+
* a getter that throws later inside a frame callback.
|
|
22
25
|
* The project's input map is loaded through `Game.loadInputMap` (the
|
|
23
26
|
* game-owned, load-once path every root shares) with the SAME default
|
|
24
27
|
* path the classic adapter uses. A missing/unparseable map degrades
|
|
@@ -63,6 +66,7 @@ export function createR3FRootContext(host, options) {
|
|
|
63
66
|
const ctxRaw = {
|
|
64
67
|
systems,
|
|
65
68
|
assets: host.assets,
|
|
69
|
+
input: host.game?.input ?? null,
|
|
66
70
|
registerSystemAdapter: (kind, adapter) => {
|
|
67
71
|
// biome-ignore lint/suspicious/noExplicitAny: same per-key record write the classic adapter performs; correct by construction
|
|
68
72
|
systemAdapters[kind] = adapter;
|
|
@@ -106,7 +110,6 @@ export function createR3FRootContext(host, options) {
|
|
|
106
110
|
if (host.game) {
|
|
107
111
|
const game = host.game;
|
|
108
112
|
const input = game.input;
|
|
109
|
-
ctxRaw['input'] = input;
|
|
110
113
|
debugRegistry.setInputActionsSource(id, () => input.actionNames().map((name) => ({ name, valueType: input.getActionValueType(name) })));
|
|
111
114
|
debugRegistry.setInputTraceSource(id, () => {
|
|
112
115
|
const raw = input.getInputTrace();
|
|
@@ -144,22 +147,6 @@ export function createR3FRootContext(host, options) {
|
|
|
144
147
|
});
|
|
145
148
|
}
|
|
146
149
|
}
|
|
147
|
-
else {
|
|
148
|
-
// `input` IS a field of every R3F world's ctx — it is game-owned, and this
|
|
149
|
-
// particular mount has no Game to own it (a bare harness or a foreign
|
|
150
|
-
// host). A throwing getter names that at the read, instead of handing back
|
|
151
|
-
// `undefined` that breaks deep inside a frame callback. Non-enumerable so
|
|
152
|
-
// spreads/serialization of the ctx never trip it.
|
|
153
|
-
Object.defineProperty(ctxRaw, 'input', {
|
|
154
|
-
configurable: true,
|
|
155
|
-
enumerable: false,
|
|
156
|
-
get() {
|
|
157
|
-
throw new Error(`R3F world "${id}": ctx.input is game-owned and this mount has no Game host ` +
|
|
158
|
-
'(host.game is absent — bare harness/foreign host); mount through the vgai host ' +
|
|
159
|
-
'to get the shared InputManager.');
|
|
160
|
-
},
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
150
|
return {
|
|
164
151
|
ctx,
|
|
165
152
|
systems,
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@vgai/engine",
|
|
3
3
|
"author": "Volter AI, Inc.",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
|
-
"version": "0.5.
|
|
5
|
+
"version": "0.5.16",
|
|
6
6
|
"description": "Readable TypeScript game engine and universal host for Three.js, PixiJS, and React games.",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"game-engine",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
],
|
|
16
16
|
"notes": "Grepped packages/engine/src for ccd/CCD/setCcdEnabled: zero matches. The engine constructs no rigid bodies itself — games build their own descs via ctx.RAPIER — and nothing engine-side ever enables ccd. Workaround: keep dynamic-body per-step travel small relative to the thinnest collider, or add intermediate colliders; a game may also call setCcdEnabled on its own bodies directly.",
|
|
17
17
|
"evidenceHashes": {
|
|
18
|
-
"packages/engine/src/adapter/setup-three-root-adapter.ts": "
|
|
18
|
+
"packages/engine/src/adapter/setup-three-root-adapter.ts": "98fb35199a246d99fe752ea467d48a30c71da7f4d4e6f06efa372b0c6abb5456"
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
21
|
{
|
|
@@ -35,15 +35,15 @@
|
|
|
35
35
|
"id": "input-value-model",
|
|
36
36
|
"area": "input",
|
|
37
37
|
"status": "supported-with-caveats",
|
|
38
|
-
"claim": "F1 (spec §12) added a typed action-value model (digital/scalar/vector2/pointerDelta/pointerPosition, default digital) with real deadzone/combine rules and a valueType-mismatch throw. F2 ('Complete Device Backends') un-rejects mouse_move/gamepad_axis_pair, giving both real readers (mouse_move -> pointerDelta/vector2 off the real mouse-delta accumulator; gamepad_axis_pair -> vector2 off a coupled xAxis/yAxis stick, deadzone-rescaled like gamepad_axis), and adds touch_button/touch_stick (digital/vector2) via setTouchButton/setTouchStick. Real window focus (blur/focus) and pointer-lock state are tracked and flush held REAL-device input on loss (#144: virtual/scheduled machine input gates on enabled only and survives blur); gamepad device identity (id/mapping) is exposed via getGamepadInfo/ActionValueSource.gamepadId. F4 adds getLastActiveDevice() + an optional getPrompt device param. Caveat: pointerPosition still has no real-device backend (test_pointer_position injection only); scalar isn't fed by mouse_move (no axis-select field).",
|
|
38
|
+
"claim": "F1 (spec §12) added a typed action-value model (digital/scalar/vector2/pointerDelta/pointerPosition, default digital) with real deadzone/combine rules and a valueType-mismatch throw. F2 ('Complete Device Backends') un-rejects mouse_move/gamepad_axis_pair, giving both real readers (mouse_move -> pointerDelta/vector2 off the real mouse-delta accumulator; gamepad_axis_pair -> vector2 off a coupled xAxis/yAxis stick, deadzone-rescaled like gamepad_axis), and adds touch_button/touch_stick (digital/vector2) via setTouchButton/setTouchStick. Real window focus (blur/focus) and pointer-lock state are tracked (requestPointerLock / exitPointerLock) and flush held REAL-device input on loss (#144: virtual/scheduled machine input gates on enabled only and survives blur); gamepad device identity (id/mapping) is exposed via getGamepadInfo/ActionValueSource.gamepadId. F4 adds getLastActiveDevice() + an optional getPrompt device param. Device-poll getters (isDeviceKeyPressed / isDeviceMouseButtonPressed / getDeviceMouseDelta / getDeviceMousePosition / hasDeviceGamepad / isDeviceGamepadButtonPressed / getDeviceGamepadAxis) read the same keysDown/mouseButtons/gamepads stores without inventing implicit actions, and return inert at READ time when inputActive is false. Caveat: pointerPosition still has no real-device backend (test_pointer_position injection only); scalar isn't fed by mouse_move (no axis-select field).",
|
|
39
39
|
"evidence": [
|
|
40
40
|
"packages/engine/src/input/input-types.ts:2-40 (InputBinding union incl. mouse_move/gamepad_axis_pair/touch_button/touch_stick/test_*)",
|
|
41
|
-
"packages/engine/src/input/input-manager.ts
|
|
41
|
+
"packages/engine/src/input/input-manager.ts (digital/gating/typed getters/device-poll/inject*/setTouch*/getGamepadInfo/F4 getLastActiveDevice+getPrompt/requestPointerLock/exitPointerLock)"
|
|
42
42
|
],
|
|
43
43
|
"notes": "gamepad disconnect/reconnect needs no special-cased code: poll() re-reads navigator.getGamepads() and every read skips a null slot, so a disconnected gamepad's actions go neutral with a correct isJustReleased edge for free — see input-device-backends-f2.test.ts.",
|
|
44
44
|
"evidenceHashes": {
|
|
45
45
|
"packages/engine/src/input/input-types.ts": "62d9005609a72b55a8214c869d1b27825b1a17b9389f3f3f5d0b04725331b382",
|
|
46
|
-
"packages/engine/src/input/input-manager.ts": "
|
|
46
|
+
"packages/engine/src/input/input-manager.ts": "41b1255eb18c74c022b3cc87f6e050d3fb7ee6883215e3888337ff0d94defa63"
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
49
|
{
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"notes": "This is a compatibility integration, not the canonical animation model: project-owned native controllers may drive AnimationMixer directly. When XState is deliberately used, parallel regions use distinct layer names; the binding filters native clip tracks, uses AnimationUtils.makeClipAdditive, can register with ctx.systems, and publishes format-neutral native runtime inspection until disposal.",
|
|
59
59
|
"evidenceHashes": {
|
|
60
60
|
"packages/engine/src/animation/xstate-animation-meta.ts": "80376ac74819803616c4b396244a971cb9a6b2859c33409d032363bfeb3db44f",
|
|
61
|
-
"packages/engine/src/animation/xstate-animation-binding.ts": "
|
|
61
|
+
"packages/engine/src/animation/xstate-animation-binding.ts": "8ec400c5abe1550a72adca3dfe30e57c42239fdd1eb986b8e05ec973ea3f3d7b"
|
|
62
62
|
}
|
|
63
63
|
},
|
|
64
64
|
{
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"notes": "Limits: ARCHITECTURE-CORE.md. Any editor capability a mount does not reach stands warned per capability until it works.",
|
|
74
74
|
"evidenceHashes": {
|
|
75
75
|
"vendor/games/verify-unaltered.mjs": "257a362030a10f4d72a3280815069fbd83f436e1619391635b6f8df2ddd6c339",
|
|
76
|
-
"packages/engine/src/manifest/schema.ts": "
|
|
76
|
+
"packages/engine/src/manifest/schema.ts": "65500eb1594bd2333418bf073858131d449f0a17e0b584fc4dedc15bf01970bf"
|
|
77
77
|
}
|
|
78
78
|
},
|
|
79
79
|
{
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"notes": "Scope is native-DOM React ONLY (D-N1): R3F/@pixi/react games are canvas games and ride the three.js/pixi seams instead. Generality limit: ONE proven game (react-rpg — menu-to-dungeon e2e under React 19; both game-2 candidates rejected on evidence, R-N7). Game deps must be host-installed root deps (D-N6). Open R-N6: vendored react games' raw window listeners bypass the play-mode input gate.",
|
|
89
89
|
"evidenceHashes": {
|
|
90
90
|
"vendor/games/verify-unaltered.mjs": "257a362030a10f4d72a3280815069fbd83f436e1619391635b6f8df2ddd6c339",
|
|
91
|
-
"packages/editor/src/adapter-resolver.ts": "
|
|
91
|
+
"packages/editor/src/adapter-resolver.ts": "433a2c22d274510302cd4be0163e5bd7400387bef7dc97bb7fab5eeac601127b"
|
|
92
92
|
}
|
|
93
93
|
},
|
|
94
94
|
{
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
"notes": "This file exists for negatives engine-api.json can't express (e.g. 'parses but does nothing'). For the full positive surface, read engine-api.json/.md — regenerated by `npm run generate-engine-manifest`, can't drift.",
|
|
105
105
|
"evidenceHashes": {
|
|
106
106
|
"packages/engine/schemas/engine-api.json": "cdfd395fab88575a13c74451051e6c86f8b07980152120f00caa62098ecf7917",
|
|
107
|
-
"packages/engine/src/animation/xstate-animation-binding.ts": "
|
|
107
|
+
"packages/engine/src/animation/xstate-animation-binding.ts": "8ec400c5abe1550a72adca3dfe30e57c42239fdd1eb986b8e05ec973ea3f3d7b",
|
|
108
108
|
"packages/engine/src/animation/blend-node.ts": "9e1d2018acf138bb984fd0d2c7ff1045ef00689e613abf531453af0a1ba06b2e"
|
|
109
109
|
}
|
|
110
110
|
}
|
|
@@ -460,7 +460,7 @@
|
|
|
460
460
|
"type": "string"
|
|
461
461
|
},
|
|
462
462
|
"lesson": {
|
|
463
|
-
"description": "Optional Learn-site lesson URL that teaches this project 1:1 (e.g. https://vgai-learn.pages.dev/
|
|
463
|
+
"description": "Optional Learn-site lesson URL that teaches this project 1:1 (e.g. https://vgai-learn.pages.dev/manual/physics/joints/)",
|
|
464
464
|
"type": "string"
|
|
465
465
|
}
|
|
466
466
|
},
|