@volter/editor-game 0.5.68 → 0.5.69
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/NOTICE +7 -7
- package/contributions/autoplay.service.ts +1 -1
- package/contributions/build-profiles.document.tsx +1 -1
- package/contributions/build-progress.status.tsx +2 -2
- package/contributions/build.header.tsx +1 -1
- package/contributions/connection.status.tsx +1 -1
- package/contributions/coverage.service.ts +2 -2
- package/contributions/game-eval.command.ts +6 -6
- package/contributions/gameplay.command.ts +2 -2
- package/contributions/generations.status.tsx +1 -1
- package/contributions/ingest.service.ts +2 -2
- package/contributions/play.command.ts +6 -6
- package/contributions/react/react-inspector.service.ts +1 -1
- package/package.json +8 -8
- package/serving/index.ts +1 -1
- package/src/asset-budget/AssetBudgetPanel.tsx +1 -1
- package/src/asset-budget/asset-budget-model.ts +14 -14
- package/src/asset-budget/optimize-apply.ts +8 -8
- package/src/bridge/call.ts +3 -3
- package/src/bridge/dispatch.ts +12 -12
- package/src/bridge/screenshot.ts +6 -6
- package/src/build/BuildProfilesPanel.tsx +8 -8
- package/src/canvas/canvas-board/CanvasBoardDocument.tsx +2 -2
- package/src/canvas/canvas-board/canvas-component-board.ts +1 -1
- package/src/canvas/canvas-design-mount.ts +1 -1
- package/src/coverage/live-project-verbs.ts +3 -3
- package/src/coverage/native-system-coverage.ts +3 -3
- package/src/coverage/root-coverage.ts +2 -2
- package/src/coverage/session-coverage.ts +2 -2
- package/src/design-system-stories/InspectorNarrowBodies.stories.tsx +2 -2
- package/src/game-document/DevicePresetPicker.tsx +6 -6
- package/src/game-document/GameCaptureFrameButton.tsx +1 -1
- package/src/game-document/GameDocument.tsx +2 -2
- package/src/game-document/GamePanel.tsx +9 -9
- package/src/game-document/InstanceInspectorPicker.tsx +1 -1
- package/src/game-document/device-preview.ts +4 -4
- package/src/game-document/physics-debug.ts +2 -2
- package/src/generation/GenerationActivity.tsx +22 -22
- package/src/generation/GenerationGallery.css +79 -79
- package/src/generation/generation-documents.tsx +25 -25
- package/src/generation/generation-presentation.ts +1 -1
- package/src/host/adapter-reach.ts +1 -1
- package/src/host/adapter-runtime-bindings.ts +5 -5
- package/src/host/after-paint.ts +3 -3
- package/src/host/api/configurations.ts +1 -1
- package/src/host/authoring/canvas-runtime-recognition.ts +2 -2
- package/src/host/authoring/contract-hierarchy-authoring.ts +6 -6
- package/src/host/authoring/contract-scenes-stories.ts +5 -5
- package/src/host/authoring/ingest-data-writer.ts +1 -1
- package/src/host/authoring/ingest-source-persistence.ts +2 -2
- package/src/host/authoring/mount-isolated-pixi-screen.ts +1 -1
- package/src/host/authoring/pixi-authoring-adapter.ts +60 -4
- package/src/host/authoring/pixi-creatable-kinds.ts +18 -0
- package/src/host/authoring/pixi-live-write-target.ts +6 -5
- package/src/host/authoring/pixi-source-write-target.ts +5 -2
- package/src/host/authoring/pixi-structure-history.ts +3 -3
- package/src/host/binding-resolver.ts +6 -6
- package/src/host/browser-transpile.ts +10 -10
- package/src/host/canvas-preview-frames.ts +1 -1
- package/src/host/components/CameraAuthoringOverlay.tsx +14 -14
- package/src/host/components/HeaderTelemetry.tsx +11 -11
- package/src/host/components/PixiIsolationSceneContent.tsx +2 -2
- package/src/host/components/ResolutionPicker.tsx +4 -4
- package/src/host/components/scene-document.tsx +3 -3
- package/src/host/components/world-root-stage-binding.tsx +1 -1
- package/src/host/components/world-root-stage.ts +1 -1
- package/src/host/coverage/authoring-read-probe.ts +1 -1
- package/src/host/coverage/capability-coverage.ts +22 -22
- package/src/host/coverage/game-contract-seam-evidence.ts +8 -8
- package/src/host/coverage/project-verb-coverage.ts +1 -1
- package/src/host/coverage/system-adapter-coverage.ts +19 -6
- package/src/host/game-location-guard.ts +3 -3
- package/src/host/game-module-access.ts +6 -6
- package/src/host/game-realm-page.ts +3 -3
- package/src/host/game-realm-reclaim.ts +1 -1
- package/src/host/gameplay-recording.ts +5 -5
- package/src/host/gated-globals.ts +13 -13
- package/src/host/ingest/registry.ts +14 -14
- package/src/host/play-control-hook.ts +1 -1
- package/src/host/playwright-shim.ts +2 -2
- package/src/host/projection/pixi.ts +2 -2
- package/src/host/react-mount-runtime.ts +1 -1
- package/src/host/roots/canvas-root.tsx +2 -2
- package/src/host/roots/r3f-root.tsx +1 -1
- package/src/host/scene-view-drawability.ts +1 -1
- package/src/host/sdk/tools.ts +1 -1
- package/src/host/staged-projects.ts +1 -1
- package/src/host/stories/story-pixi-preview.ts +1 -1
- package/src/host/stories/story-three-preview.ts +1 -1
- package/src/host/three-ingest-runtime.ts +1 -1
- package/src/ingest/active-ingest.ts +1 -1
- package/src/ingest/authoring/ingest-dom-surface-authoring.ts +4 -4
- package/src/ingest/authoring/ingest-root-adapter.ts +11 -11
- package/src/ingest/capture-wait-report.ts +4 -4
- package/src/ingest/discovery-public-ingest.ts +4 -4
- package/src/ingest/dom-stub-mark.ts +1 -1
- package/src/ingest/entry-load.ts +1 -1
- package/src/ingest/game-contract-realm.ts +3 -3
- package/src/ingest/game-pointer-lock.ts +1 -1
- package/src/ingest/ingest-canvas-scene-document.tsx +2 -2
- package/src/ingest/ingest-evidence-hook.ts +6 -6
- package/src/ingest/ingest-frame-snapshot.ts +2 -2
- package/src/ingest/ingest-play-commands.ts +1 -1
- package/src/ingest/ingest-play-control.ts +11 -11
- package/src/ingest/ingest-render-debug.ts +5 -5
- package/src/ingest/ingest-siblings.ts +3 -3
- package/src/ingest/module-mode.ts +2 -2
- package/src/ingest/mount-canvas-ingest-root.ts +10 -10
- package/src/ingest/mount-coverage.ts +3 -3
- package/src/ingest/mount-dom-ingest-root.ts +7 -7
- package/src/ingest/mount-ingest-root.ts +10 -10
- package/src/ingest/mount-three-ingest-root.ts +5 -5
- package/src/ingest/resolve-three.ts +2 -2
- package/src/ingest/served-bundle.ts +6 -6
- package/src/ingest/served-html-boot.ts +8 -8
- package/src/ingest/surface-dom.ts +9 -9
- package/src/ingest/surface-three.ts +1 -1
- package/src/ingest/types.ts +1 -1
- package/src/ingest/unmount-ingest-root.ts +3 -3
- package/src/network/NetworkInspectorPanel.tsx +2 -2
- package/src/play/play-boot-stall.ts +1 -1
- package/src/play/play-mode.ts +31 -30
- package/src/play/play-recording.ts +12 -12
- package/src/play-bar/PlayBar.tsx +8 -8
- package/src/play-bar/PlayerCountPicker.tsx +3 -3
- package/src/profiler/FrameDebuggerPanel.tsx +2 -2
- package/src/profiler/PerformancePanel.tsx +4 -4
- package/src/react/design-time-react-mount.ts +5 -5
- package/src/react/dom-authoring-adapter.ts +3 -3
- package/src/react/react-inspector-section.tsx +2 -2
- package/src/react/react-world-authoring-adapter.ts +20 -20
- package/src/react/story-documents/story-documents.tsx +4 -4
- package/src/react/ui-component-board.ts +1 -1
- package/src/runtime/adapter/audio-meter.ts +1 -1
- package/src/runtime/adapter/ingest/contract-debug-adapter.ts +4 -4
- package/src/runtime/adapter/ingest/contract-system-adapters.ts +9 -9
- package/src/runtime/adapter/ingest/merge-debug-adapters.ts +2 -2
- package/src/runtime/adapter/ingest/observation-debug-adapter.ts +1 -1
- package/src/runtime/adapter/native-debug-module.ts +5 -5
- package/src/runtime/audio/pose-guard.ts +1 -1
- package/src/runtime/core/game-scoped-slot.ts +1 -1
- package/src/runtime/create-runtime.ts +14 -14
- package/src/runtime/debug-bridge.ts +25 -25
- package/src/runtime/debug-registry.ts +17 -17
- package/src/runtime/dev/instruments.ts +1 -1
- package/src/runtime/dev/performance-profiler.ts +2 -2
- package/src/runtime/dev/register-render-vitals.ts +2 -2
- package/src/runtime/dev/static-batch-advisor.ts +3 -3
- package/src/runtime/dev-build.ts +3 -3
- package/src/runtime/game.ts +5 -5
- package/src/runtime/input-router.ts +1 -1
- package/src/runtime/mount-manifest.ts +9 -9
- package/src/runtime/pixi/authoring.ts +1 -1
- package/src/runtime/pixi/ingest.ts +1 -1
- package/src/runtime/presentation.ts +1 -1
- package/src/runtime/render-control.ts +21 -21
- package/src/runtime/render-seed.ts +3 -3
- package/src/runtime/run-ticks-settled.ts +1 -1
- package/src/services/game-audio.ts +3 -3
- package/src/services/game-network.ts +4 -4
- package/src/three/authoring/model-asset-inspector-section.css +15 -15
- package/src/three/authoring/model-asset-inspector-section.tsx +7 -7
- package/src/three/authoring/r3f-design-session.ts +10 -10
- package/src/three/authoring/r3f-source-authoring-adapter.ts +5 -5
- package/src/three/authoring/three-authoring-adapter.ts +5 -4
- package/src/three/authoring/typed-three-inspector.ts +1 -1
- package/src/three/story-documents/three-story-documents.tsx +3 -3
- package/src/three/three-board/board-scene.ts +9 -9
- package/src/three/three-board/three-component-board.ts +1 -1
|
@@ -148,10 +148,10 @@ function publishCanvasIngestSystems(
|
|
|
148
148
|
setActiveSystems(systems);
|
|
149
149
|
editorConsole.log(
|
|
150
150
|
contractSystems
|
|
151
|
-
? `canvas ingest: "${gameName}" declares the
|
|
151
|
+
? `canvas ingest: "${gameName}" declares the volter game contract — ` +
|
|
152
152
|
`${contractSystems.commands?.length ?? 0} commands, ` +
|
|
153
153
|
`${contractSystems.state?.length ?? 0} state providers`
|
|
154
|
-
: `canvas ingest: "${gameName}" declares no
|
|
154
|
+
: `canvas ingest: "${gameName}" declares no volter game contract — game.commands()/` +
|
|
155
155
|
'game.state() have nothing to answer and will refuse by naming that',
|
|
156
156
|
'ingest',
|
|
157
157
|
);
|
|
@@ -361,7 +361,7 @@ function publishStructuralCanvasRuntime(
|
|
|
361
361
|
'ingest',
|
|
362
362
|
);
|
|
363
363
|
|
|
364
|
-
publishIngestHook('
|
|
364
|
+
publishIngestHook('__volterIngest2D', {
|
|
365
365
|
gameId: sessionId,
|
|
366
366
|
...ingestHookEvidence(adapter),
|
|
367
367
|
runtime: recognized.runtime,
|
|
@@ -481,7 +481,7 @@ async function mountCanvasIngestRootInner(
|
|
|
481
481
|
// F26: same cold-mount announcement the three adapter makes
|
|
482
482
|
// (ingest-root-adapter.ts) — a pixi game may declare the game contract and
|
|
483
483
|
// defer its session until ▶; games that ignore the flag behave as before.
|
|
484
|
-
(window as unknown as {
|
|
484
|
+
(window as unknown as { __volterMountCold?: boolean }).__volterMountCold = true;
|
|
485
485
|
// THE namespace the game's own modules will resolve `pixi.js` to.
|
|
486
486
|
//
|
|
487
487
|
// `installSceneCapture2D` wraps `Application.prototype.render` on the
|
|
@@ -518,7 +518,7 @@ async function mountCanvasIngestRootInner(
|
|
|
518
518
|
// unfocused editor window).
|
|
519
519
|
preferStructuralRuntime: async () => {
|
|
520
520
|
const realm = ingestGameRealmWindow() as unknown as PhaserRealmLike & BabylonRealmLike;
|
|
521
|
-
await realm.
|
|
521
|
+
await realm.__volterBabylon?.ready;
|
|
522
522
|
return recognizeStructuralCanvasRuntime(store, realm) !== null;
|
|
523
523
|
},
|
|
524
524
|
});
|
|
@@ -578,8 +578,8 @@ async function mountCanvasIngestRootInner(
|
|
|
578
578
|
const stage = mount.stage as Container;
|
|
579
579
|
// The game's async setup may add display objects after its first captured frame —
|
|
580
580
|
// wait for the stage to settle. `nextPaint()` rather than a bare rAF because
|
|
581
|
-
// this mount is awaited by `
|
|
582
|
-
// `
|
|
581
|
+
// this mount is awaited by `volter-game-editor play`: in a hidden tab (every agent-worktree
|
|
582
|
+
// `volter-game-editor edit` opens one — see `after-paint.ts`) no frame ever arrives, so a
|
|
583
583
|
// bare chain hangs this bounded loop on iteration 1 and play stalls in its
|
|
584
584
|
// boot phase with nothing to report.
|
|
585
585
|
for (let i = 0; i < 90 && (stage.children?.length ?? 0) === 0; i++) {
|
|
@@ -776,7 +776,7 @@ async function mountCanvasIngestRootInner(
|
|
|
776
776
|
// PD-3: the mount stood — but `contract-ready` may only be recorded when the
|
|
777
777
|
// declared promise actually ANSWERED. The three lane's `awaitWorldReady`
|
|
778
778
|
// (`authoring/ingest-root-adapter.ts`) is the precedent: a game that declares
|
|
779
|
-
// `window.
|
|
779
|
+
// `window.volterGame.ready` is awaited exactly once, and a declared signal that
|
|
780
780
|
// REJECTS does not fail the mount (the frame is already captured) — it
|
|
781
781
|
// degrades to the measured wait, LOUDLY, and the row then reports `measured`,
|
|
782
782
|
// which is the truth about which answer stood. Recording `contract-ready`
|
|
@@ -789,7 +789,7 @@ async function mountCanvasIngestRootInner(
|
|
|
789
789
|
readinessStood = 'declared';
|
|
790
790
|
} catch (err) {
|
|
791
791
|
editorConsole.error(
|
|
792
|
-
`Ingest game "${game.id}" declared \`window.
|
|
792
|
+
`Ingest game "${game.id}" declared \`window.volterGame.ready\` and it REJECTED ` +
|
|
793
793
|
`(${String(err)}) — the frame was already captured, so the host fell back to the ` +
|
|
794
794
|
'measured settle wait. This root now reports readiness as measured.',
|
|
795
795
|
'ingest',
|
|
@@ -828,7 +828,7 @@ async function mountCanvasIngestRootInner(
|
|
|
828
828
|
'ingest',
|
|
829
829
|
);
|
|
830
830
|
|
|
831
|
-
publishIngestHook('
|
|
831
|
+
publishIngestHook('__volterIngest2D', {
|
|
832
832
|
gameId: sessionId,
|
|
833
833
|
...ingestHookEvidence(adapter),
|
|
834
834
|
drawCount: () => mount.capture.getDrawCount(),
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Everything here is a measurement or the plumbing of one — the mount-time
|
|
6
6
|
* one-shot probe (the editor capabilities reached),
|
|
7
7
|
* the live re-read of the loop verdict, the once-per-mount
|
|
8
|
-
* console door, and the report the status facet and the `
|
|
8
|
+
* console door, and the report the status facet and the `__volterIngest` hook
|
|
9
9
|
* both serve. Mount PLUMBING lives in the `mount-*-ingest-root.ts` siblings
|
|
10
10
|
* and deliberately not here: a reader asking "what did the editor actually
|
|
11
11
|
* measure about this game, and where does that number come from" should have
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
type ContractSurface,
|
|
38
38
|
projectContractSystemAdapters,
|
|
39
39
|
} from '../runtime/adapter/ingest/contract-system-adapters';
|
|
40
|
-
import type {
|
|
40
|
+
import type { VolterGameContract } from '@volter/editor-project/adapter/ingest/game-contract';
|
|
41
41
|
import type { SystemAdapters } from '@volter/editor-project/adapter/system-adapter';
|
|
42
42
|
import { activeIngest } from './active-ingest';
|
|
43
43
|
import type { IngestMount } from './authoring/ingest-root-adapter';
|
|
@@ -163,7 +163,7 @@ export const LOOP_PROBE_ABSENT =
|
|
|
163
163
|
*/
|
|
164
164
|
export function measureSystemAdapters(
|
|
165
165
|
active: SystemAdapters,
|
|
166
|
-
contract:
|
|
166
|
+
contract: VolterGameContract | null,
|
|
167
167
|
/** The mount's surface when the caller has one — see
|
|
168
168
|
* `contract-system-adapters.ts`'s header for the one slot it decides
|
|
169
169
|
* (`physics`, whose vocabulary follows the surface). */
|
|
@@ -72,7 +72,7 @@ async function mountDomIngestRootInner(store: EditorShellStore, folderId: string
|
|
|
72
72
|
const projectRoot = ingestGameDomProjectRoot(folderId);
|
|
73
73
|
if (!projectRoot) {
|
|
74
74
|
editorConsole.error(
|
|
75
|
-
`React ingest "${folderId}": no
|
|
75
|
+
`React ingest "${folderId}": no __VOLTER_ENGINE_ROOT__ available to resolve its entry`,
|
|
76
76
|
'ingest',
|
|
77
77
|
);
|
|
78
78
|
return;
|
|
@@ -95,7 +95,7 @@ async function mountDomIngestRootInner(store: EditorShellStore, folderId: string
|
|
|
95
95
|
// F26: same cold-mount announcement as the other ingest routes — the react
|
|
96
96
|
// world's entry executes in the editor realm and may declare the game
|
|
97
97
|
// contract to defer its session until ▶. Opt-in, never demanded.
|
|
98
|
-
(window as unknown as {
|
|
98
|
+
(window as unknown as { __volterMountCold?: boolean }).__volterMountCold = true;
|
|
99
99
|
const { createGameRuntime } = await import('../runtime/create-runtime');
|
|
100
100
|
const specs = await resolveAllRoots(game.manifest, projectRoot);
|
|
101
101
|
const w = gameContainer.clientWidth;
|
|
@@ -155,7 +155,7 @@ async function mountDomIngestRootInner(store: EditorShellStore, folderId: string
|
|
|
155
155
|
const coverage = domMountCoverage(adapter);
|
|
156
156
|
recordMountCoverage(coverage);
|
|
157
157
|
|
|
158
|
-
publishIngestHook('
|
|
158
|
+
publishIngestHook('__volterIngestReact', {
|
|
159
159
|
gameId: folderId,
|
|
160
160
|
worldId: game.worldId,
|
|
161
161
|
...ingestHookEvidence(adapter),
|
|
@@ -169,7 +169,7 @@ async function mountDomIngestRootInner(store: EditorShellStore, folderId: string
|
|
|
169
169
|
domEvidence: () => reactDomEvidence(root, adapter),
|
|
170
170
|
// D-L1: honest `typeof === 'function'` check on the REAL session
|
|
171
171
|
// control this route just installed above — never an independent
|
|
172
|
-
// literal `true` (mirrors `
|
|
172
|
+
// literal `true` (mirrors `__volterSiblingMounts`'s identical discipline).
|
|
173
173
|
setPausedPresent: typeof lifecycle.setPaused === 'function',
|
|
174
174
|
});
|
|
175
175
|
}
|
|
@@ -177,7 +177,7 @@ async function mountDomIngestRootInner(store: EditorShellStore, folderId: string
|
|
|
177
177
|
/**
|
|
178
178
|
* D-Y2 (slice S2) — the manifest-route sibling of {@link mountDomIngestRoot}: an
|
|
179
179
|
* EXTERNAL-FOLDER `ingest-react` world (the opened project's OWN
|
|
180
|
-
* `
|
|
180
|
+
* `volter.project.json`, not the in-tree `ingest/games/<id>` fixture registry)
|
|
181
181
|
* enters the same react ingest session. Exactly the same roots-path recipe
|
|
182
182
|
* (one-element `resolveAllRoots` + roots-path `createGameRuntime`) and the same
|
|
183
183
|
* `DomAuthoringAdapter` D-K4 wiring — only the SOURCE of
|
|
@@ -215,7 +215,7 @@ export async function mountDomIngestRootFromManifest(
|
|
|
215
215
|
|
|
216
216
|
// F26: same cold-mount announcement the vendored route makes — an
|
|
217
217
|
// external-folder game may declare the game contract too.
|
|
218
|
-
(window as unknown as {
|
|
218
|
+
(window as unknown as { __volterMountCold?: boolean }).__volterMountCold = true;
|
|
219
219
|
const { createGameRuntime } = await import('../runtime/create-runtime');
|
|
220
220
|
const specs = await resolveAllRoots({ ...manifest, roots: [world] }, projectRoot);
|
|
221
221
|
const w = gameContainer.clientWidth;
|
|
@@ -260,7 +260,7 @@ export async function mountDomIngestRootFromManifest(
|
|
|
260
260
|
const coverage = domMountCoverage(adapter);
|
|
261
261
|
recordMountCoverage(coverage);
|
|
262
262
|
|
|
263
|
-
publishIngestHook('
|
|
263
|
+
publishIngestHook('__volterIngestReact', {
|
|
264
264
|
worldId: world.id,
|
|
265
265
|
...ingestHookEvidence(adapter),
|
|
266
266
|
noAuthoring: false,
|
|
@@ -173,7 +173,7 @@ registerEditorStateFacet(() => ({
|
|
|
173
173
|
* mount is attempted (that flag is what swaps the viewport onto the live
|
|
174
174
|
* scene). When the mount then throws, that flag, plus any authoring
|
|
175
175
|
* adapter/adopted scene a partial mount installed, used to survive — so
|
|
176
|
-
* `
|
|
176
|
+
* `volter-game-editor status` reported `playing`, the hierarchy kept presenting whatever tree
|
|
177
177
|
* was underneath, and the only trace of the failure was one console line. This
|
|
178
178
|
* is the single teardown every failure path runs: drop the partial session,
|
|
179
179
|
* reset the play surface, and record + broadcast the failure so the status item
|
|
@@ -509,7 +509,7 @@ async function tryManifestIngestRoute2D(
|
|
|
509
509
|
* DOM sibling of {@link tryManifestIngestRoute}/{@link tryManifestIngestRoute2D}
|
|
510
510
|
* (D-Y2, slice S2): a manifest-backed project declaring an `ingest-react` root
|
|
511
511
|
* mounts the native-React ingest session straight from that root (external
|
|
512
|
-
* folder — `
|
|
512
|
+
* folder — `volter-game-editor edit <folder>` — not the in-tree `ingest/games/<id>` fixture
|
|
513
513
|
* registry). Same "applied or not" contract, same D-V2 composite scan/
|
|
514
514
|
* route-selection/sibling-mount shape as its three/canvas siblings above.
|
|
515
515
|
*/
|
|
@@ -689,7 +689,7 @@ async function autoLaunchIngestInner(store: EditorShellStore): Promise<void> {
|
|
|
689
689
|
// and several of that module's suites run under the Node vitest environment
|
|
690
690
|
// where a bare top-level `window` write is a load-time ReferenceError.
|
|
691
691
|
if (import.meta.env.DEV && typeof window !== 'undefined') {
|
|
692
|
-
(window as unknown as Record<string, unknown>)['
|
|
692
|
+
(window as unknown as Record<string, unknown>)['__volterIngestApi'] = {
|
|
693
693
|
enter: (gameId: string) => {
|
|
694
694
|
if (!_boundStore) throw new Error('ingest roots not bound');
|
|
695
695
|
return mountThreeIngestRootById(_boundStore, gameId);
|
|
@@ -700,7 +700,7 @@ if (import.meta.env.DEV && typeof window !== 'undefined') {
|
|
|
700
700
|
isActive: () => activeIngest()?.kind === 'three',
|
|
701
701
|
};
|
|
702
702
|
// Canvas sibling (T6.1 slice 4) — same shape, over the canvas ingest session.
|
|
703
|
-
(window as unknown as Record<string, unknown>)['
|
|
703
|
+
(window as unknown as Record<string, unknown>)['__volterIngestApi2D'] = {
|
|
704
704
|
enter: (gameId: string) => {
|
|
705
705
|
if (!_boundStore) throw new Error('ingest roots not bound');
|
|
706
706
|
return mountCanvasIngestRootById(_boundStore, gameId);
|
|
@@ -710,7 +710,7 @@ if (import.meta.env.DEV && typeof window !== 'undefined') {
|
|
|
710
710
|
};
|
|
711
711
|
// DOM sibling (Track N, N2) — same shape, over the native-React ingest
|
|
712
712
|
// session.
|
|
713
|
-
(window as unknown as Record<string, unknown>)['
|
|
713
|
+
(window as unknown as Record<string, unknown>)['__volterIngestApiReact'] = {
|
|
714
714
|
enter: (folderId: string) => {
|
|
715
715
|
if (!_boundStore) throw new Error('ingest roots not bound');
|
|
716
716
|
return mountDomIngestRoot(_boundStore, folderId);
|
|
@@ -722,19 +722,19 @@ if (import.meta.env.DEV && typeof window !== 'undefined') {
|
|
|
722
722
|
// `packages/editor/src/authoring/mount-failure-report.ts`'s multi-entry
|
|
723
723
|
// list is otherwise only ever read by the status bar's `mount-failure`
|
|
724
724
|
// contribution (a React component), invisible to `page.evaluate()`. This is
|
|
725
|
-
// a plain function returning the LIVE list —
|
|
725
|
+
// a plain function returning the LIVE list — a probe's browser
|
|
726
726
|
// phase is this surface's first consumer, but any other dev/e2e caller can
|
|
727
|
-
// poll it the same way `
|
|
728
|
-
(window as unknown as Record<string, unknown>)['
|
|
727
|
+
// poll it the same way `__volterIngestApi*` are already polled.
|
|
728
|
+
(window as unknown as Record<string, unknown>)['__volterMountFailureReports'] = () =>
|
|
729
729
|
getMountFailureReports();
|
|
730
730
|
// D-H1 (Slice B): headless-readable per-sibling signal — the live slot's
|
|
731
731
|
// `siblings` (D-V2's composite-sibling handles, `ingest-siblings.ts`'s
|
|
732
732
|
// `SiblingMount[]`) is otherwise invisible to `page.evaluate()`, same blind spot
|
|
733
|
-
// `
|
|
733
|
+
// `__volterMountFailureReports` closed for mount failures. A plain function
|
|
734
734
|
// returning a LIVE view (never a snapshot, re-reads the slot on every call) of
|
|
735
735
|
// honest per-sibling flags only — no capture/draw proof, see
|
|
736
736
|
// `DoctorSiblingEvidence`'s doc comment (`packages/editor/src/doctor/report.ts`).
|
|
737
|
-
(window as unknown as Record<string, unknown>)['
|
|
737
|
+
(window as unknown as Record<string, unknown>)['__volterSiblingMounts'] = () =>
|
|
738
738
|
(activeIngest()?.siblings ?? []).map((s) => ({
|
|
739
739
|
worldId: s.worldId,
|
|
740
740
|
setPausedPresent: typeof s.setPaused === 'function',
|
|
@@ -80,7 +80,7 @@ function captureMechanism(via: CaptureMechanism | null): string {
|
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
82
|
* Publish a captured three ingest to the whole editor: resize lifecycle,
|
|
83
|
-
* hierarchy/inspector adapter, viewport adoption and the `
|
|
83
|
+
* hierarchy/inspector adapter, viewport adoption and the `__volterIngest`
|
|
84
84
|
* proof hook.
|
|
85
85
|
*/
|
|
86
86
|
function activateCapturedThreeIngest(args: {
|
|
@@ -143,7 +143,7 @@ function activateCapturedThreeIngest(args: {
|
|
|
143
143
|
// physics/input/animation/etc.) → those are correctly N/A while ingested. Only
|
|
144
144
|
// the asset-path remap (done at mount) is a first-party asset-adapter behavior.
|
|
145
145
|
// The ONE exception is earned, never inferred: a game that DECLARES verbs and
|
|
146
|
-
// state in its contract (`window.
|
|
146
|
+
// state in its contract (`window.volterGame.systems`) gets a `debug` adapter
|
|
147
147
|
// projected from those declarations by `mountIngestGame`, so `game.commands()`
|
|
148
148
|
// /`game.state()` reach it through the ordinary bridge. A game that declares
|
|
149
149
|
// nothing still lands here with `{}` and the pre-contract floor stands.
|
|
@@ -211,7 +211,7 @@ function activateCapturedThreeIngest(args: {
|
|
|
211
211
|
...(import.meta.env.DEV ? { adapter: liveAuthoring, store } : {}),
|
|
212
212
|
};
|
|
213
213
|
defineLoopHookFields(hook, mount);
|
|
214
|
-
publishIngestHook('
|
|
214
|
+
publishIngestHook('__volterIngest', hook);
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
async function mountThreeIngestRootInner(
|
|
@@ -314,7 +314,7 @@ async function mountThreeIngestRootInner(
|
|
|
314
314
|
* {@link mountThreeIngestRootFromManifest} builds the descriptor straight from
|
|
315
315
|
* an arbitrary project's manifest instead (the CLI-on-folder route, for a game
|
|
316
316
|
* folder never registered in source) — both end up here. `sessionId` is the
|
|
317
|
-
* id this session is known by — the `
|
|
317
|
+
* id this session is known by — the `__volterIngest` dev-hook's reported
|
|
318
318
|
* `gameId` and the id every log line names; it is always the world/game id
|
|
319
319
|
* (`game.id`), passed explicitly rather than re-read off `game` so the two
|
|
320
320
|
* callers' "id" concept — a fixture's registry-era id vs. a manifest's world
|
|
@@ -350,7 +350,7 @@ export async function mountThreeIngestRootById(
|
|
|
350
350
|
/**
|
|
351
351
|
* Mount straight from a manifest's `ingest-three` world — the CLI-on-folder
|
|
352
352
|
* route (T3.3 slice 3): a game folder never registered in source, whose
|
|
353
|
-
* `
|
|
353
|
+
* `volter.project.json` declares an ingest-three world. Builds the descriptor via
|
|
354
354
|
* `resolveIngestDescriptor` (ingest/resolve-three.ts — parameterized by the
|
|
355
355
|
* manifest's ingest fields, no registry lookup) and mounts it exactly like any
|
|
356
356
|
* other {@link IngestGame}. The session is known by the world id — the same
|
|
@@ -32,8 +32,8 @@ import type { IngestGame } from './types';
|
|
|
32
32
|
*
|
|
33
33
|
* - A THREE ingest's teardown disposes the R3F root, so a remount MUST
|
|
34
34
|
* re-evaluate the entry — `remountEpochs: true` gives every `load()` its
|
|
35
|
-
* own `?
|
|
36
|
-
* it is deliberately NOT `
|
|
35
|
+
* own `?volter-ingest-remount=` buster (see `INGEST_REMOUNT_QUERY` for why
|
|
36
|
+
* it is deliberately NOT `volter-mount`, whose realm-keying and subgraph
|
|
37
37
|
* stamping the ingest readers cannot follow; an ingest's `load` IS its
|
|
38
38
|
* mount). A bare URL made stop → ▶ a NO-OP: browser module identity is
|
|
39
39
|
* per-URL, the already-evaluated entry's top-level boot did not re-run,
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
*
|
|
4
4
|
* `public/ingest/<id>/` holds games vendored as build output rather than as
|
|
5
5
|
* source (CLAUDE.md, "Repo layout"). Those folders carry their own
|
|
6
|
-
* `
|
|
6
|
+
* `volter.project.json`, so `volter-game-editor edit public/ingest/<id>` opens them like any
|
|
7
7
|
* other project — and the manifest ingest route then built the entry's import
|
|
8
8
|
* url with `fsImportPath`, i.e. `/@fs/<abs>/…`, putting a file that lives in
|
|
9
9
|
* VITE'S OWN `public/` DIRECTORY into Vite's module graph.
|
|
10
10
|
*
|
|
11
11
|
* That is the one thing Vite refuses outright. Measured on this route
|
|
12
|
-
* (2026-08-20, `
|
|
12
|
+
* (2026-08-20, `volter-game-editor edit public/ingest/tanks`, identically for `simcity`):
|
|
13
13
|
*
|
|
14
14
|
* [vite] Internal Server Error
|
|
15
15
|
* Cannot import non-asset file /ingest/tanks/three-r170.module.js which is
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* not stop being served because the door that opened it was a session rather
|
|
28
28
|
* than a `?project=` id, so the LOCAL route resolves the same way: by URL.
|
|
29
29
|
*
|
|
30
|
-
* The `
|
|
30
|
+
* The `__VOLTER_ENGINE_ROOT__` read is the exact inverse of
|
|
31
31
|
* `imported-gallery.ts`'s `importedProjectPath` (gallery card → absolute folder);
|
|
32
32
|
* this is absolute folder → served URL.
|
|
33
33
|
*/
|
|
@@ -36,7 +36,7 @@ import { importServedModule } from '../host/browser-transpile';
|
|
|
36
36
|
import { ensureServedBundleRuntimeModules } from '../host/served-bundle-runtime-modules';
|
|
37
37
|
import { bootDeclaredDocument, declaresClassicEntry, readDeclaredBoot } from './served-html-boot';
|
|
38
38
|
|
|
39
|
-
declare const
|
|
39
|
+
declare const __VOLTER_ENGINE_ROOT__: string;
|
|
40
40
|
|
|
41
41
|
function withoutTrailingSlash(path: string): string {
|
|
42
42
|
return path.endsWith('/') ? path.slice(0, -1) : path;
|
|
@@ -52,8 +52,8 @@ function withoutTrailingSlash(path: string): string {
|
|
|
52
52
|
* checkout, not about the game.
|
|
53
53
|
*/
|
|
54
54
|
export function servedProjectBaseUrl(projectRoot: string): string | undefined {
|
|
55
|
-
if (typeof
|
|
56
|
-
const publicRoot = `${withoutTrailingSlash(
|
|
55
|
+
if (typeof __VOLTER_ENGINE_ROOT__ !== 'string' || !__VOLTER_ENGINE_ROOT__) return undefined;
|
|
56
|
+
const publicRoot = `${withoutTrailingSlash(__VOLTER_ENGINE_ROOT__)}/public/`;
|
|
57
57
|
const dir = `${withoutTrailingSlash(projectRoot)}/`;
|
|
58
58
|
if (!dir.startsWith(publicRoot) || dir === publicRoot) return undefined;
|
|
59
59
|
return `/${dir.slice(publicRoot.length)}`;
|
|
@@ -166,10 +166,10 @@ export function declaresClassicEntry(boot: DeclaredBoot | null, entryUrl: string
|
|
|
166
166
|
*/
|
|
167
167
|
export async function stageDeclaredDom(boot: DeclaredBoot): Promise<void> {
|
|
168
168
|
const realmDocument = ingestGameRealmWindow().document;
|
|
169
|
-
realmDocument.querySelector('[data-
|
|
169
|
+
realmDocument.querySelector('[data-volter-declared-dom]')?.remove();
|
|
170
170
|
if (boot.bodyHtml.trim().length === 0 && boot.inlineCss.length === 0) return;
|
|
171
171
|
const holder = realmDocument.createElement('div');
|
|
172
|
-
holder.setAttribute('data-
|
|
172
|
+
holder.setAttribute('data-volter-declared-dom', '');
|
|
173
173
|
// `pointer-events:none` on the WRAPPER, restored per child: the holder is a
|
|
174
174
|
// host artifact, not part of the game's page, and it blanketed the game's
|
|
175
175
|
// canvas — a Babylon game whose whole UI is in-canvas (space-truckers' GUI
|
|
@@ -212,7 +212,7 @@ export async function stageDeclaredDom(boot: DeclaredBoot): Promise<void> {
|
|
|
212
212
|
for (const staged of holder.querySelectorAll('[id]')) {
|
|
213
213
|
if (surface.id === staged.id) surface.removeAttribute('id');
|
|
214
214
|
for (const stub of surface.querySelectorAll(
|
|
215
|
-
`[data-
|
|
215
|
+
`[data-volter-dom-stub][id="${CSS.escape(staged.id)}"]`,
|
|
216
216
|
)) {
|
|
217
217
|
if (stub !== staged) stub.remove();
|
|
218
218
|
}
|
|
@@ -278,15 +278,15 @@ export async function bootDeclaredDocument(
|
|
|
278
278
|
// violation ("trap returned falsish for property 'window'"), so the traps
|
|
279
279
|
// delegate to the captured realm window instead of proxying it.
|
|
280
280
|
const scope =
|
|
281
|
-
'var
|
|
282
|
-
'
|
|
283
|
-
'var
|
|
281
|
+
'var __volterPristine = new Set(Object.getOwnPropertyNames(globalThis));\n' +
|
|
282
|
+
'__volterPristine.add("__volterPristine"); __volterPristine.add("__volterRealmGlobals");\n' +
|
|
283
|
+
'var __volterRealmGlobals = (function (w) {\n' +
|
|
284
284
|
' return new Proxy({}, {\n' +
|
|
285
|
-
' has: function (_, k) { return typeof k === "string" && !
|
|
285
|
+
' has: function (_, k) { return typeof k === "string" && !__volterPristine.has(k) && k in w; },\n' +
|
|
286
286
|
' get: function (_, k) { return typeof k === "string" ? w[k] : undefined; },\n' +
|
|
287
287
|
' set: function (_, k, v) { w[k] = v; return true; },\n' +
|
|
288
288
|
' });\n' +
|
|
289
289
|
'})(window);\n';
|
|
290
|
-
const body = `${GAME_GLOBALS_PRELUDE}\n${scope}\nreturn (function(){ with (
|
|
290
|
+
const body = `${GAME_GLOBALS_PRELUDE}\n${scope}\nreturn (function(){ with (__volterRealmGlobals) {\n${sources.join('\n;\n')}\n} }).call(window);`;
|
|
291
291
|
gameRealmPage().withCurrentScript(entryUrl, () => new Function(body)());
|
|
292
292
|
}
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
*
|
|
16
16
|
* `projectRoot` can't come from `import.meta.glob`/`import.meta.url` alone
|
|
17
17
|
* (those resolve to HTTP URLs in the browser, not filesystem paths) — it is
|
|
18
|
-
* built from `
|
|
19
|
-
* `server/dev.ts`, mirroring the existing `
|
|
18
|
+
* built from `__VOLTER_ENGINE_ROOT__` (a dev-server-only Vite `define`,
|
|
19
|
+
* `server/dev.ts`, mirroring the existing `__VOLTER_PROJECT_PATH__` define) plus
|
|
20
20
|
* this folder's FIXED, known-at-build-time relative offset. `browser`
|
|
21
|
-
* editor-mode builds (no dev server) never define `
|
|
21
|
+
* editor-mode builds (no dev server) never define `__VOLTER_ENGINE_ROOT__` —
|
|
22
22
|
* callers must check `getEditorMode() !== 'browser'` first (mirrors every other
|
|
23
23
|
* `/@fs/`-dependent ingest route's guard, e.g. `ingest/mount-ingest-root.ts`'s
|
|
24
24
|
* `tryManifestIngestRoute`).
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
import { type IngestEntry, ingestEntriesOnSurface } from '../host/ingest/registry';
|
|
28
28
|
import type { ResolvedGameManifest } from '@volter/editor-project/manifest/load';
|
|
29
29
|
|
|
30
|
-
declare const
|
|
30
|
+
declare const __VOLTER_ENGINE_ROOT__: string;
|
|
31
31
|
|
|
32
32
|
/** A discovered `dom`-surface ingest fixture: its parsed manifest (exactly one
|
|
33
33
|
* ingest root) plus that root's id for convenience. */
|
|
@@ -72,13 +72,13 @@ export function getIngestGameDom(folderId: string): IngestGameDom | undefined {
|
|
|
72
72
|
/**
|
|
73
73
|
* The absolute on-disk `projectRoot` for a discovered dom ingest fixture's
|
|
74
74
|
* folder — what `resolveRootBinding`/`resolveAllRoots` need to resolve its
|
|
75
|
-
* `entry`. `undefined` when `
|
|
75
|
+
* `entry`. `undefined` when `__VOLTER_ENGINE_ROOT__` isn't defined (browser-mode
|
|
76
76
|
* static build — no dev server, no `/@fs/` route to resolve through anyway).
|
|
77
77
|
*/
|
|
78
78
|
export function ingestGameDomProjectRoot(folderId: string): string | undefined {
|
|
79
|
-
if (typeof
|
|
80
|
-
const root =
|
|
81
|
-
?
|
|
82
|
-
:
|
|
79
|
+
if (typeof __VOLTER_ENGINE_ROOT__ !== 'string' || !__VOLTER_ENGINE_ROOT__) return undefined;
|
|
80
|
+
const root = __VOLTER_ENGINE_ROOT__.endsWith('/')
|
|
81
|
+
? __VOLTER_ENGINE_ROOT__.slice(0, -1)
|
|
82
|
+
: __VOLTER_ENGINE_ROOT__;
|
|
83
83
|
return `${root}/packages/editor/src/ingest/games/${folderId}`;
|
|
84
84
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* `ingest/discovery.ts`, which owned its own glob of `games/*`).
|
|
4
4
|
*
|
|
5
5
|
* Discovery is no longer here: `registry.ts` does the one glob over
|
|
6
|
-
* `./games/*\/
|
|
6
|
+
* `./games/*\/volter.project.json` and hands back parsed entries. This module's only
|
|
7
7
|
* job is turning a `three`-surface entry into the `IngestGame` descriptor
|
|
8
8
|
* `ingest/mount-ingest-root.ts` mounts — which is genuinely per-surface work, and is why the
|
|
9
9
|
* builders stayed split when discovery was unified.
|
package/src/ingest/types.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* It is the common contract every discovery frontend builds:
|
|
7
7
|
* `ingest/surface-three.ts`'s glob-based discovery of the in-tree fixture games
|
|
8
|
-
* under `ingest/games/<id>/
|
|
8
|
+
* under `ingest/games/<id>/volter.project.json`, `binding-resolver.ts`'s
|
|
9
9
|
* `resolveIngestDescriptor` (an arbitrary project folder's manifest, mounted
|
|
10
10
|
* through the dev server), and `ingest/discovery-public-ingest.ts` (a game
|
|
11
11
|
* served out of the repo's public dir, by id).
|
|
@@ -131,7 +131,7 @@ function disposeThreejsSession(s: IngestSession): void {
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
reclaimGameRealm('', 'The ingested game');
|
|
134
|
-
clearIngestHook('
|
|
134
|
+
clearIngestHook('__volterIngest');
|
|
135
135
|
editorConsole.log('Ingest root unmounted', 'ingest');
|
|
136
136
|
}
|
|
137
137
|
|
|
@@ -160,7 +160,7 @@ function disposePixiSession(s: IngestSession2D): void {
|
|
|
160
160
|
/* ignore */
|
|
161
161
|
}
|
|
162
162
|
reclaimGameRealm('', 'The ingested canvas game');
|
|
163
|
-
clearIngestHook('
|
|
163
|
+
clearIngestHook('__volterIngest2D');
|
|
164
164
|
editorConsole.log('canvas ingest root unmounted', 'ingest');
|
|
165
165
|
}
|
|
166
166
|
|
|
@@ -184,7 +184,7 @@ function disposeReactSession(s: IngestSessionReact): void {
|
|
|
184
184
|
/* ignore */
|
|
185
185
|
}
|
|
186
186
|
reclaimGameRealm('', 'The ingested DOM game');
|
|
187
|
-
clearIngestHook('
|
|
187
|
+
clearIngestHook('__volterIngestReact');
|
|
188
188
|
editorConsole.log('DOM ingest root unmounted', 'ingest');
|
|
189
189
|
}
|
|
190
190
|
|
|
@@ -680,7 +680,7 @@ export function NetworkInspectorPanel() {
|
|
|
680
680
|
data-testid="network-inspector"
|
|
681
681
|
// §2.31 P2 amendment: text-dense output region reads over a local
|
|
682
682
|
// frosted layer (inert for non-frost themes).
|
|
683
|
-
className="
|
|
683
|
+
className="volter-content-frost"
|
|
684
684
|
style={{
|
|
685
685
|
flex: 1,
|
|
686
686
|
minHeight: 0,
|
|
@@ -1338,7 +1338,7 @@ function ServerView({
|
|
|
1338
1338
|
if (inspection === null) {
|
|
1339
1339
|
return (
|
|
1340
1340
|
<AbsentNote testId="net-server-absent">
|
|
1341
|
-
The room server serves no Monitor view (its `server` configuration sets
|
|
1341
|
+
The room server serves no Monitor view (its `server` configuration sets VOLTER_ROOM_MONITOR=1).
|
|
1342
1342
|
</AbsentNote>
|
|
1343
1343
|
);
|
|
1344
1344
|
}
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* `relayCommandTimeoutMs`), so the caller gets
|
|
22
22
|
* "Command timed out — editor connected but did not respond" — a message that
|
|
23
23
|
* names nothing, points at nothing, and hides the one remedy that works
|
|
24
|
-
* (foreground the tab; the very next `
|
|
24
|
+
* (foreground the tab; the very next `volter-game-editor play` then starts in seconds).
|
|
25
25
|
*
|
|
26
26
|
* ## What this does, and deliberately does not do
|
|
27
27
|
*
|