@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
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* `PlayBar` renders two different transports — the native one (title "Play
|
|
5
5
|
* (run game)") and the ingest one (label "Run ingested game") — and anything
|
|
6
6
|
* outside the component that needs to find "the play control" was matching a
|
|
7
|
-
* LABEL.
|
|
7
|
+
* LABEL. A probe polled for the native string as its editor-readiness
|
|
8
8
|
* boundary and therefore waited out its whole timeout budget on every ingest
|
|
9
9
|
* project, which renders the other one (SimCity ingest dogfood, S-6).
|
|
10
10
|
*
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* `page-script` relay op constructs one per call and hands it to a
|
|
9
9
|
* reconstructed step function; a real `@playwright/test` `Page` drives the SAME
|
|
10
10
|
* step file when the spec runs under `PageTransport`
|
|
11
|
-
* (`packages/
|
|
11
|
+
* (`packages/volter-live/src/game-client/client.ts`) in CI. That duality is why
|
|
12
12
|
* `createPageShim`'s return value is typed `as Page` — every implemented member
|
|
13
13
|
* matches Playwright's own shape closely enough that a step written against it
|
|
14
14
|
* compiles against the real type too.
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
* under both `PageTransport` (real Playwright, real closures) and
|
|
42
42
|
* `RelayTransport` (this shim, serialized) must be written as though ALWAYS
|
|
43
43
|
* serialized — inline every value the step needs; see
|
|
44
|
-
* `packages/
|
|
44
|
+
* `packages/volter-live/src/game-client/client.ts`'s `GameClient.page()` doc comment for
|
|
45
45
|
* the client-facing half of this contract.
|
|
46
46
|
*/
|
|
47
47
|
|
|
@@ -179,8 +179,8 @@ export class PixiProjector {
|
|
|
179
179
|
if (rect.width <= 0 || rect.height <= 0) return null;
|
|
180
180
|
const mapped = this.mapping?.pointFromClient?.(clientX, clientY, rect) ?? null;
|
|
181
181
|
if (this.mapping?.pointFromClient) return mapped;
|
|
182
|
-
const logicalWidth = Number(surface.dataset?.['
|
|
183
|
-
const logicalHeight = Number(surface.dataset?.['
|
|
182
|
+
const logicalWidth = Number(surface.dataset?.['volterStageWidth'] ?? rect.width);
|
|
183
|
+
const logicalHeight = Number(surface.dataset?.['volterStageHeight'] ?? rect.height);
|
|
184
184
|
if (!(logicalWidth > 0) || !(logicalHeight > 0)) return null;
|
|
185
185
|
return {
|
|
186
186
|
x: (clientX - rect.left) * (logicalWidth / rect.width),
|
|
@@ -54,7 +54,7 @@ function staticReactRootMountRuntime(): ReactRootMountRuntime {
|
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* Import + shape-check the packaged runtime's synthetic
|
|
57
|
-
* `/
|
|
57
|
+
* `/__volter-react-world-runtime` module (`vite-plugin-module-doorways.ts`,
|
|
58
58
|
* registered only by `packaged.ts`'s project-rooted Vite instance and by
|
|
59
59
|
* `vitest.config.ts` for test coverage — never by `dev.ts`/the root
|
|
60
60
|
* `vite.config.ts`). A loud, named failure if the module resolves but is
|
|
@@ -134,7 +134,7 @@ function canvasWorldAdapter(
|
|
|
134
134
|
throw new Error(
|
|
135
135
|
`canvas world "${id}": this lane has already mounted this canvas. @pixi/react keys ` +
|
|
136
136
|
'its reconciler roots off the canvas element, so re-using one would resurrect a ' +
|
|
137
|
-
'root whose Application is destroyed. Hand each mount a fresh canvas (every
|
|
137
|
+
'root whose Application is destroyed. Hand each mount a fresh canvas (every volter ' +
|
|
138
138
|
'host already does).',
|
|
139
139
|
);
|
|
140
140
|
}
|
|
@@ -308,7 +308,7 @@ function canvasWorldAdapter(
|
|
|
308
308
|
mountedApp.ticker.update(elapsedMs);
|
|
309
309
|
},
|
|
310
310
|
// Pixi's own hit test finds only interactive objects (`eventMode` static or dynamic), so a
|
|
311
|
-
//
|
|
311
|
+
// 2D layer claims its tappable objects and lets every other point fall through to the world beneath.
|
|
312
312
|
hitTest(x: number, y: number): boolean {
|
|
313
313
|
if (disposed) return false;
|
|
314
314
|
// Pixi points its boundary at the last rendered scene inside each of its own pointer
|
|
@@ -208,7 +208,7 @@ function threeWorldAdapter(id: string, component: ComponentType, runtime: R3FRun
|
|
|
208
208
|
Fragment,
|
|
209
209
|
null,
|
|
210
210
|
content,
|
|
211
|
-
createElement(MountEffectsReady, { key: '
|
|
211
|
+
createElement(MountEffectsReady, { key: 'volter-mount-effects-ready' }),
|
|
212
212
|
);
|
|
213
213
|
// A reconcile-time crash (e.g. a missing `extend` catalogue entry)
|
|
214
214
|
// surfaces as an uncaught window error and `onCreated` never fires —
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* throw, attributes it to that scene, and stops re-throwing it forever.
|
|
22
22
|
*
|
|
23
23
|
* The game is NOT lost when this fires: its own renderer keeps drawing into its
|
|
24
|
-
* own canvas, which the host adopted, so the Game tab and `
|
|
24
|
+
* own canvas, which the host adopted, so the Game tab and `volter-game-editor screenshot`
|
|
25
25
|
* show the real thing. What is lost is the editor-camera Scene view of it,
|
|
26
26
|
* which is exactly what the message says.
|
|
27
27
|
*/
|
package/src/host/sdk/tools.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* input/result schemas, structured error codes, and the metadata a caller reads
|
|
6
6
|
* before invoking (`permission`, `host`, `mutates`, `supportsDryRun`). The
|
|
7
7
|
* contract exists because a tool is called across a process boundary — CLI to
|
|
8
|
-
* editor to node host, and `
|
|
8
|
+
* editor to node host, and `volter mcp` to an external agent over stdio — where
|
|
9
9
|
* you cannot throw. `ToolRegistry.dispatch` turns every expected failure
|
|
10
10
|
* (unknown name, bad input, an `impl` throw, a bad return) into a typed outcome
|
|
11
11
|
* instead.
|
|
@@ -350,7 +350,7 @@ const FIRST_FRAME_TIMEOUT_MS = PIXI_MOUNT_TIMEOUT_MS;
|
|
|
350
350
|
* Wait until every collected `Application` has PRESENTED a frame with content
|
|
351
351
|
* in it — the readiness test a capture of a canvas story owes itself.
|
|
352
352
|
*
|
|
353
|
-
* MEASURED DEFECT (this is why the function exists): `
|
|
353
|
+
* MEASURED DEFECT (this is why the function exists): `volter-game-editor screenshot
|
|
354
354
|
* <file>.stories.tsx` photographed a `@pixi/react` story blank. The capture
|
|
355
355
|
* lane's own readiness test is "the container has committed child nodes", and
|
|
356
356
|
* `<Application>` commits its `<canvas>` on the FIRST commit — before
|
|
@@ -150,7 +150,7 @@ export interface MountedStoryObject3D {
|
|
|
150
150
|
|
|
151
151
|
/** The name of the wrapper `<group>` every story is rendered into, so its root
|
|
152
152
|
* `Object3D` can be extracted unambiguously from fiber's scene. */
|
|
153
|
-
export const PREVIEW_ROOT_NAME = '
|
|
153
|
+
export const PREVIEW_ROOT_NAME = 'volter:story-preview-root';
|
|
154
154
|
|
|
155
155
|
/** How long to wait for fiber's first commit before giving up. The LAST-RESORT
|
|
156
156
|
* ceiling only: a reconcile-time crash is now caught by
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* `canvas-entry-runtime.ts`'s `resolveCanvasPixiForEditor`.
|
|
5
5
|
*
|
|
6
6
|
* See `../vite-plugin-module-doorways.ts` for the measured failure this
|
|
7
|
-
* closes and for why the ingest lane does not borrow `/
|
|
7
|
+
* closes and for why the ingest lane does not borrow `/__volter-r3f-runtime`.
|
|
8
8
|
*
|
|
9
9
|
* A mount site resolves this ONCE and hands what it gets to everything it
|
|
10
10
|
* builds for that game. Nothing further down reaches for a static import: a
|
|
@@ -108,7 +108,7 @@ export type ActiveIngest = (
|
|
|
108
108
|
) & {
|
|
109
109
|
siblings: SiblingMount[];
|
|
110
110
|
/** The mounted world's id — the SAME id every log line and the
|
|
111
|
-
* `
|
|
111
|
+
* `__volterIngest` hook's `gameId` names. Carried on the slot (rather than
|
|
112
112
|
* re-derived) so the status facet can report WHICH world is live
|
|
113
113
|
* without a second source of truth (S-1). */
|
|
114
114
|
worldId: string;
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
walkOidTree,
|
|
21
21
|
} from '../../react/react-world-authoring-adapter';
|
|
22
22
|
import type { AuthoringAdapter } from '@volter/editor-project/adapter';
|
|
23
|
-
import type {
|
|
23
|
+
import type { VolterGameContract } from '@volter/editor-project/adapter/ingest/game-contract';
|
|
24
24
|
|
|
25
25
|
type ReadableDomRoot = OverlayElement & DomElementLike & { readonly ownerDocument?: Document };
|
|
26
26
|
|
|
@@ -50,7 +50,7 @@ function iframeDocumentRoot(hostEl: HTMLElement): ReadableDomRoot | null {
|
|
|
50
50
|
|
|
51
51
|
function resolveGameDomRoot(
|
|
52
52
|
hostEl: HTMLElement,
|
|
53
|
-
declaredRoot:
|
|
53
|
+
declaredRoot: VolterGameContract['root'] | undefined,
|
|
54
54
|
): ReadableDomRoot | null {
|
|
55
55
|
if (isReadableDomRoot(declaredRoot)) return declaredRoot;
|
|
56
56
|
return iframeDocumentRoot(hostEl) ?? (isReadableDomRoot(hostEl) ? hostEl : null);
|
|
@@ -143,7 +143,7 @@ export function withDetectedDomSurface(args: {
|
|
|
143
143
|
primary: AuthoringAdapter;
|
|
144
144
|
worldId: string;
|
|
145
145
|
hostEl: HTMLElement;
|
|
146
|
-
declaredRoot?:
|
|
146
|
+
declaredRoot?: VolterGameContract['root'];
|
|
147
147
|
store: EditorShellStore;
|
|
148
148
|
}): AuthoringAdapter {
|
|
149
149
|
const gameRoot = resolveGameDomRoot(args.hostEl, args.declaredRoot);
|
|
@@ -158,7 +158,7 @@ export function withDetectedDomSurface(args: {
|
|
|
158
158
|
// refuse every detected DOM sibling before the ingest could mount.
|
|
159
159
|
const domUiJournalId = `${args.worldId}/dom-ui`;
|
|
160
160
|
const liveUiRoot: DomElementLike & OidElementLike = {
|
|
161
|
-
tagName: '
|
|
161
|
+
tagName: 'volter-dom-surface',
|
|
162
162
|
id: '',
|
|
163
163
|
className: '',
|
|
164
164
|
get children() {
|
|
@@ -385,7 +385,7 @@ function bootWindowPageErrors(startedAt: number): string[] {
|
|
|
385
385
|
/**
|
|
386
386
|
* Wait for the game's world to be BUILT, declaration first.
|
|
387
387
|
*
|
|
388
|
-
* A game that declares `window.
|
|
388
|
+
* A game that declares `window.volterGame.ready` is awaited exactly once and the
|
|
389
389
|
* measured poll never runs — the game states when it is done, so the host has
|
|
390
390
|
* nothing to estimate. Everything else keeps {@link waitForSceneToSettle},
|
|
391
391
|
* which is the MEASURED fallback and is labelled as such wherever readiness is
|
|
@@ -408,7 +408,7 @@ async function awaitWorldReady(
|
|
|
408
408
|
return 'declared';
|
|
409
409
|
} catch (err) {
|
|
410
410
|
editorConsole.error(
|
|
411
|
-
`Ingest game "${gameId}" declared \`window.
|
|
411
|
+
`Ingest game "${gameId}" declared \`window.volterGame.ready\` and it REJECTED (${String(err)}) ` +
|
|
412
412
|
'— the world was already captured, so the host fell back to the measured settle wait. ' +
|
|
413
413
|
'This root now reports readiness as measured.',
|
|
414
414
|
'ingest',
|
|
@@ -442,8 +442,8 @@ async function waitForSceneToSettle(scene: THREE.Scene, maxMs = 5000): Promise<v
|
|
|
442
442
|
* Some games append their canvas to `document.body` — reparent it into the
|
|
443
443
|
* host. A DOM-hybrid game (React/R3F with HTML UI: HUDs, overlay panels, drei
|
|
444
444
|
* `<Html>` portals) can declare the element that OWNS its canvas via
|
|
445
|
-
* `window.
|
|
446
|
-
* `
|
|
445
|
+
* `window.volterGame.root` (the declared game→host contract, game-contract.ts;
|
|
446
|
+
* `__volterGameRoot` is the pre-contract alias). Adopting only the bare canvas
|
|
447
447
|
* would strand that UI at page level over the editor chrome, and following the
|
|
448
448
|
* canvas would require the game to know host layout internals — an arcane
|
|
449
449
|
* demand. Adopt the declared root wholesale so the game's own DOM structure
|
|
@@ -472,7 +472,7 @@ function adoptGameDomRoot(hostEl: HTMLElement, surface: HTMLElement): HTMLElemen
|
|
|
472
472
|
const realmWindow = ingestGameRealmWindow();
|
|
473
473
|
const declaredRoot =
|
|
474
474
|
readIngestGameContract()?.root ??
|
|
475
|
-
(realmWindow as unknown as {
|
|
475
|
+
(realmWindow as unknown as { __volterGameRoot?: unknown }).__volterGameRoot;
|
|
476
476
|
const declared =
|
|
477
477
|
declaredRoot instanceof HTMLElement && declaredRoot.contains(surface) ? declaredRoot : surface;
|
|
478
478
|
if (declared.contains(hostEl)) return hostEl;
|
|
@@ -516,7 +516,7 @@ export async function mountIngestGame(
|
|
|
516
516
|
// Host policy, not per-game CSS — see `game-realm-page.ts` for the four
|
|
517
517
|
// page-shaped assumptions this covers and why each one breaks an in-realm
|
|
518
518
|
// mount. Registered on the DEFAULT realm because an ingest descriptor's
|
|
519
|
-
// module urls carry no `?
|
|
519
|
+
// module urls carry no `?volter-mount=` (binding-resolver.ts's
|
|
520
520
|
// `resolveIngestDescriptor` builds bare `fsImportPath` urls).
|
|
521
521
|
const realmPage = setGameSurface(hostEl);
|
|
522
522
|
|
|
@@ -614,10 +614,10 @@ export async function mountIngestGame(
|
|
|
614
614
|
// Signal COLD MOUNT before the entry executes: editor mounts are for
|
|
615
615
|
// inspection first, so a session-driven game MAY defer its side-effects
|
|
616
616
|
// (backend connection, narrative, audio) until the editor's play control
|
|
617
|
-
// dispatches '
|
|
617
|
+
// dispatches 'volter:ingest-play' (getIngestPlayControl, ingest/mount-ingest-root.ts).
|
|
618
618
|
// Rendering must continue regardless — capture needs a frame — and games
|
|
619
619
|
// that ignore the flag behave exactly as before (opt-in, never demanded).
|
|
620
|
-
(window as unknown as {
|
|
620
|
+
(window as unknown as { __volterMountCold?: boolean }).__volterMountCold = true;
|
|
621
621
|
// THE BOOT WINDOW OPENS HERE (M29). Everything the page throws from this
|
|
622
622
|
// instant until the mount resolves belongs to this game's boot, and it is the
|
|
623
623
|
// fact that separates "crashed before ready" from "never became ready" — the
|
|
@@ -650,7 +650,7 @@ export async function mountIngestGame(
|
|
|
650
650
|
// boots in the background parks here instead of dying, with the trap still
|
|
651
651
|
// installed, so the first frame after the human foregrounds the tab is the
|
|
652
652
|
// captured one. `setCaptureWait` is what keeps that park from reading as a
|
|
653
|
-
// hung mount — `
|
|
653
|
+
// hung mount — `volter-game-editor status` names it.
|
|
654
654
|
rt = await capture.waitForCapture({
|
|
655
655
|
timeoutMs,
|
|
656
656
|
onWait: (wait) => setCaptureWait(game.id, wait),
|
|
@@ -797,10 +797,10 @@ export async function mountIngestGame(
|
|
|
797
797
|
// well after `setPaused` returned. Nothing else would notify the store, and
|
|
798
798
|
// `collectState` is push-based — the control API would keep serving a
|
|
799
799
|
// snapshot taken before the measurement existed, reporting `loop: null`
|
|
800
|
-
// forever. Broadcast so `
|
|
800
|
+
// forever. Broadcast so `volter-game-editor status` sees the verdict it just produced.
|
|
801
801
|
onVerdict: () => store.shell.notifyIngestEdit(),
|
|
802
802
|
});
|
|
803
|
-
// The game's DECLARED system surface (`window.
|
|
803
|
+
// The game's DECLARED system surface (`window.volterGame.systems`), projected
|
|
804
804
|
// onto the host's ordinary `SystemAdapters.debug`. `activateCapturedThreeIngest`
|
|
805
805
|
// hands `mounted.systems` straight to `setActiveSystems`, so a shim that
|
|
806
806
|
// declares verbs makes `game.commands()`/`game.state()` work through the same
|
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
* background — the normal human path — no longer burns its window unable to
|
|
8
8
|
* draw. What it does instead is WAIT, potentially for as long as the human
|
|
9
9
|
* takes to come back to the tab, and a wait is exactly the state every door
|
|
10
|
-
* used to report as silence: nothing mounted, nothing failed, `
|
|
10
|
+
* used to report as silence: nothing mounted, nothing failed, `volter-game-editor status`
|
|
11
11
|
* counting down a clock that was not running. So the wait is published:
|
|
12
|
-
* `collectState`'s `ingestCaptureWait` carries it, and `
|
|
12
|
+
* `collectState`'s `ingestCaptureWait` carries it, and `volter-game-editor status` prints
|
|
13
13
|
* "waiting for first visible frame — tab is hidden" instead of a countdown.
|
|
14
14
|
*
|
|
15
15
|
* A LIVE VIEW, never a snapshot — same rule as `IngestMount.realmLoopVerdict`
|
|
16
|
-
* and the `
|
|
16
|
+
* and the `__volterIngest` hook's `reflected`/`sceneChildren`: the elapsed
|
|
17
17
|
* numbers move on their own, so a frozen copy starts lying the instant it is
|
|
18
18
|
* taken. The slot holds the window itself and derives the report at read time.
|
|
19
19
|
*
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
import { notifyLiveSessionsChanged } from '@volter/editor-sdk/kit/live-session-registry';
|
|
28
28
|
import type { VisibleCaptureWindow } from '@volter/threejs-runtime/adapter/ingest/visible-capture-window';
|
|
29
29
|
|
|
30
|
-
/** The wait as `
|
|
30
|
+
/** The wait as `volter-game-editor status` reports it. */
|
|
31
31
|
export interface CaptureWaitStatus {
|
|
32
32
|
/** The world whose first frame is being waited for. */
|
|
33
33
|
readonly worldId: string;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The three sibling of `surface-canvas.ts` (the pixi lane, which is the idiom
|
|
5
5
|
* benchmark this file is modelled on): a game vendored under
|
|
6
|
-
* `public/ingest/<id>/` carries its own declarative `
|
|
6
|
+
* `public/ingest/<id>/` carries its own declarative `volter.project.json`, and
|
|
7
7
|
* its id resolves it into the SAME `IngestGame` descriptor every other three
|
|
8
8
|
* ingest route produces. Adding a fourth vendored game is a folder plus a
|
|
9
9
|
* manifest — no edit to this file, no per-game page, no branch anywhere.
|
|
@@ -81,7 +81,7 @@ function readVendoredIngestRoot(
|
|
|
81
81
|
const roots = declaredRoots(manifest);
|
|
82
82
|
if (roots.length !== 1) {
|
|
83
83
|
throw new Error(
|
|
84
|
-
`vendored ingest discovery: "${folderId}/
|
|
84
|
+
`vendored ingest discovery: "${folderId}/volter.project.json" must declare exactly one root ` +
|
|
85
85
|
`(found ${roots.length}).`,
|
|
86
86
|
);
|
|
87
87
|
}
|
|
@@ -92,7 +92,7 @@ function readVendoredIngestRoot(
|
|
|
92
92
|
root.adapter.identity !== expect.identity
|
|
93
93
|
) {
|
|
94
94
|
throw new Error(
|
|
95
|
-
`vendored ingest discovery: "${folderId}/
|
|
95
|
+
`vendored ingest discovery: "${folderId}/volter.project.json" must declare one ` +
|
|
96
96
|
`${expect.surface} { ingest } root (found surface "${root.surface}", adapter identity ` +
|
|
97
97
|
`"${root.adapter.identity}").`,
|
|
98
98
|
);
|
|
@@ -161,7 +161,7 @@ export function buildPublicCanvasIngestGame(
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
/**
|
|
164
|
-
* Resolve a vendored game id against `public/ingest/<id>/
|
|
164
|
+
* Resolve a vendored game id against `public/ingest/<id>/volter.project.json`.
|
|
165
165
|
*
|
|
166
166
|
* `null` means "no such vendored three ingest" (no manifest served at that
|
|
167
167
|
* path) — the caller falls through to its own unknown-id report. A manifest
|
package/src/ingest/entry-load.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* editor's realm, preceded by the host-added contract module the manifest names
|
|
4
4
|
* in `ingest.contractShim` when it declares one.
|
|
5
5
|
*
|
|
6
|
-
* ORDER IS THE WHOLE CONTRACT. The shim assigns `window.
|
|
6
|
+
* ORDER IS THE WHOLE CONTRACT. The shim assigns `window.volterGame` synchronously
|
|
7
7
|
* at top level (see the field's schema description), so it must be evaluated
|
|
8
8
|
* BEFORE the game's entry — a game that reads the declaration during its own
|
|
9
9
|
* module evaluation would otherwise see nothing, and a shim that lazily
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { gameRealmForMountId } from '../host/gated-globals';
|
|
2
2
|
import {
|
|
3
3
|
readGameContract,
|
|
4
|
-
type
|
|
4
|
+
type VolterGameContract,
|
|
5
5
|
} from '@volter/editor-project/adapter/ingest/game-contract';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* The browser realm used by the singleton ingest routes.
|
|
9
9
|
*
|
|
10
|
-
* Vendored ingest entry graphs deliberately carry no `?
|
|
10
|
+
* Vendored ingest entry graphs deliberately carry no `?volter-mount=` query:
|
|
11
11
|
* they share the editor's Pixi/Three packages and run in the default gated
|
|
12
12
|
* realm. Realm hardening keeps game-owned expandos on that realm's window
|
|
13
13
|
* proxy, so host code must read the contract from the same proxy rather than
|
|
@@ -28,7 +28,7 @@ export function ingestGameRealmWindow(): Window {
|
|
|
28
28
|
* reached by every `bridge-call`) degrading instead of throwing
|
|
29
29
|
* `window is not defined` at them.
|
|
30
30
|
*/
|
|
31
|
-
export function readIngestGameContract():
|
|
31
|
+
export function readIngestGameContract(): VolterGameContract | null {
|
|
32
32
|
if (typeof window === 'undefined') return null;
|
|
33
33
|
return readGameContract(ingestGameRealmWindow());
|
|
34
34
|
}
|
|
@@ -59,7 +59,7 @@ export function installGamePointerLockGate(): void {
|
|
|
59
59
|
if (entry && !entry.gate()) {
|
|
60
60
|
// A NEW native console.error site, suppressed to keep this task's diff at
|
|
61
61
|
// zero new lint warnings — and native on purpose: this fires from a game's
|
|
62
|
-
// own click handler in the page, and the page console is what `
|
|
62
|
+
// own click handler in the page, and the page console is what `volter-game-editor
|
|
63
63
|
// status` reads.
|
|
64
64
|
// biome-ignore lint/suspicious/noConsole: see comment above
|
|
65
65
|
console.error(
|
|
@@ -136,8 +136,8 @@ export function IngestCanvasSceneContent({
|
|
|
136
136
|
<div
|
|
137
137
|
ref={containerRef}
|
|
138
138
|
data-testid="world-document:ingest-canvas-scene"
|
|
139
|
-
data-
|
|
140
|
-
data-
|
|
139
|
+
data-volter-backdrop-color={active ? CANVAS_SCENE_BACKGROUND : undefined}
|
|
140
|
+
data-volter-backdrop-policy={active ? 'dark-frost' : undefined}
|
|
141
141
|
style={{
|
|
142
142
|
position: 'absolute',
|
|
143
143
|
inset: 0,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The `
|
|
2
|
+
* The `__volterIngest` / `__volterIngest2D` / `__volterIngestReact` dev hooks: the
|
|
3
3
|
* headless-readable evidence a live ingest mount publishes for automation,
|
|
4
|
-
* screenshots and
|
|
4
|
+
* screenshots and probes.
|
|
5
5
|
*
|
|
6
6
|
* Everything here is EVIDENCE, not control: names read off the live adapter,
|
|
7
7
|
* counters read off the live gate, the coverage report re-derived on demand.
|
|
@@ -18,7 +18,7 @@ import type { IngestMount } from './authoring/ingest-root-adapter';
|
|
|
18
18
|
import { ingestCoverageReport } from './mount-coverage';
|
|
19
19
|
|
|
20
20
|
/** The window key each surface's mount publishes its evidence under. */
|
|
21
|
-
export type IngestHookKey = '
|
|
21
|
+
export type IngestHookKey = '__volterIngest' | '__volterIngest2D' | '__volterIngestReact';
|
|
22
22
|
|
|
23
23
|
const AUTHORING_PROVIDER_KEYS = [
|
|
24
24
|
'hierarchy',
|
|
@@ -57,7 +57,7 @@ export function ingestHookEvidence(adapter: AuthoringAdapter): Record<string, un
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
|
-
* The loop fields the `
|
|
60
|
+
* The loop fields the `__volterIngest` dev hook publishes — the measured verdict
|
|
61
61
|
* plus the gate's own counters, so automation can drive Play/Pause/Step through
|
|
62
62
|
* exactly the seam the editor's own buttons use rather than a parallel one.
|
|
63
63
|
*/
|
|
@@ -85,10 +85,10 @@ export function defineLoopHookFields(target: Record<string, unknown>, mount: Ing
|
|
|
85
85
|
|
|
86
86
|
/**
|
|
87
87
|
* D-L1 — the LIVE value behind
|
|
88
|
-
* `
|
|
88
|
+
* `__volterIngestReact.domEvidence()`, shared by both react ingest routes.
|
|
89
89
|
* Evaluated at scrape time (a function result, never memoized),
|
|
90
90
|
* same "read the live state fresh on every call" discipline as
|
|
91
|
-
* `
|
|
91
|
+
* `__volterSiblingMounts` (D-H1).
|
|
92
92
|
*
|
|
93
93
|
* `elementCount` prefers the DOM's real `querySelectorAll('*').length` — a
|
|
94
94
|
* real browser `HTMLElement` (what `reactRoot()` actually returns in
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* SAME-FRAME PIXELS for an ingested game's canvas — the reason `
|
|
2
|
+
* SAME-FRAME PIXELS for an ingested game's canvas — the reason `volter-game-editor
|
|
3
3
|
* screenshot` no longer returns black over a running ingest.
|
|
4
4
|
*
|
|
5
5
|
* ## The failure
|
|
6
6
|
*
|
|
7
7
|
* `composite-screenshot.ts` reads a game's canvas with `drawImage`, and that
|
|
8
8
|
* only works on a WebGL canvas whose context was created with
|
|
9
|
-
* `preserveDrawingBuffer: true`. Every canvas the
|
|
9
|
+
* `preserveDrawingBuffer: true`. Every canvas the volter RUNTIME mounts sets it
|
|
10
10
|
* (`@volter/editor-game/runtime/create-runtime`), which is why the composite leg has always
|
|
11
11
|
* worked for first-party play. An INGESTED game creates its own canvas: the
|
|
12
12
|
* racing-game's `<Canvas>` passes no `gl` prop, so fiber's default
|
|
@@ -12,13 +12,13 @@ import { gameContractEpoch } from '../host/coverage/game-contract-seam-evidence'
|
|
|
12
12
|
import { recordLiveSeamEvidence } from '@volter/editor-sdk/kit/live-seam-evidence';
|
|
13
13
|
import { editorConsole } from '@volter/editor-sdk/kit/editor-console';
|
|
14
14
|
import { activateLiveDocument } from '@volter/editor-sdk/kit/live-document';
|
|
15
|
-
import type {
|
|
15
|
+
import type { VolterGameContract } from '@volter/editor-project/adapter/ingest/game-contract';
|
|
16
16
|
import { activeIngest, type IngestLifecycleControl } from './active-ingest';
|
|
17
17
|
import { readIngestGameContract } from './game-contract-realm';
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* The play-state control surface for the CURRENT ingest session (F17/F21):
|
|
21
|
-
* mounts are COLD by doctrine — the adapter sets `window.
|
|
21
|
+
* mounts are COLD by doctrine — the adapter sets `window.__volterMountCold`
|
|
22
22
|
* before the game's entry executes, and a session-driven game may defer its
|
|
23
23
|
* side-effects (backend connection, narrative, audio) until the first
|
|
24
24
|
* `play()`. Everything is contract-first (game-contract.ts): `lifecycle.start`
|
|
@@ -72,9 +72,9 @@ export function setIngestPlaying(playing: boolean): void {
|
|
|
72
72
|
*/
|
|
73
73
|
export function resetIngestPlaySurface(): void {
|
|
74
74
|
setIngestPlaying(false);
|
|
75
|
-
const w = window as unknown as {
|
|
76
|
-
delete w.
|
|
77
|
-
delete w.
|
|
75
|
+
const w = window as unknown as { __volterMountCold?: boolean; __volterIngestPlayed?: boolean };
|
|
76
|
+
delete w.__volterMountCold;
|
|
77
|
+
delete w.__volterIngestPlayed;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
/**
|
|
@@ -90,7 +90,7 @@ export interface IngestLifecycleFallback {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
function runContractLifecycleEffect(
|
|
93
|
-
contract:
|
|
93
|
+
contract: VolterGameContract,
|
|
94
94
|
member: 'start' | 'pause' | 'resume',
|
|
95
95
|
run: () => void,
|
|
96
96
|
): void {
|
|
@@ -132,7 +132,7 @@ export function bindIngestLifecycle(
|
|
|
132
132
|
runContractLifecycleEffect(contract, 'start', () => declared.start?.());
|
|
133
133
|
return;
|
|
134
134
|
}
|
|
135
|
-
window.dispatchEvent(new CustomEvent('
|
|
135
|
+
window.dispatchEvent(new CustomEvent('volter:ingest-play'));
|
|
136
136
|
};
|
|
137
137
|
|
|
138
138
|
const hasPause = typeof declared?.pause === 'function';
|
|
@@ -209,7 +209,7 @@ function fanOutSiblingPause(paused: boolean): void {
|
|
|
209
209
|
* either from its own entry, or from the host-added module the manifest names
|
|
210
210
|
* in `ingest.contractShim`, which the mount imports first.
|
|
211
211
|
*/
|
|
212
|
-
export function activeIngestContract():
|
|
212
|
+
export function activeIngestContract(): VolterGameContract | null {
|
|
213
213
|
return readIngestGameContract();
|
|
214
214
|
}
|
|
215
215
|
|
|
@@ -247,9 +247,9 @@ export function getIngestPlayControl(): IngestPlayControl | null {
|
|
|
247
247
|
// Late-constructed game clients must not re-defer: the flag records
|
|
248
248
|
// that play already happened this session — and makes ▶-after-⏸ a
|
|
249
249
|
// RESUME, so `lifecycle.start` fires at most once per mount.
|
|
250
|
-
const w = window as unknown as {
|
|
251
|
-
if (w.
|
|
252
|
-
w.
|
|
250
|
+
const w = window as unknown as { __volterIngestPlayed?: boolean };
|
|
251
|
+
if (w.__volterIngestPlayed) return release();
|
|
252
|
+
w.__volterIngestPlayed = true;
|
|
253
253
|
lifecycle.start();
|
|
254
254
|
// A mount ends HELD (see `ingestContentTimeForMode`), so the first ▶ is
|
|
255
255
|
// ALSO the release of that hold — same path every later ▶ takes.
|
|
@@ -72,7 +72,7 @@ import { collectRenderMemory } from '../runtime/dev/render-memory';
|
|
|
72
72
|
import { createWebGLFrameCapture } from '../runtime/dev/webgl-frame-capture';
|
|
73
73
|
import { pixiRenderingContext } from '../runtime/pixi/render-pass-bracket';
|
|
74
74
|
import type { ObservationDeclaration } from '@volter/editor-project/adapter/adapter-module';
|
|
75
|
-
import type {
|
|
75
|
+
import type { VolterGameSystems } from '@volter/editor-project/adapter/ingest/game-contract';
|
|
76
76
|
import type { SystemAdapters } from '@volter/editor-project/adapter/system-adapter';
|
|
77
77
|
import type { RenderPassHooks } from '@volter/threejs-runtime/adapter/ingest/scene-capture';
|
|
78
78
|
import type * as THREE from 'three';
|
|
@@ -223,7 +223,7 @@ export interface IngestSystemsWiring {
|
|
|
223
223
|
* accessor-trap for three, the renderer's runners for Pixi).
|
|
224
224
|
*/
|
|
225
225
|
export function wireIngestSystems(opts: {
|
|
226
|
-
readonly contractSystems:
|
|
226
|
+
readonly contractSystems: VolterGameSystems | undefined;
|
|
227
227
|
/**
|
|
228
228
|
* THIS MOUNT'S SURFACE, stated rather than inferred from which runtime is
|
|
229
229
|
* present — the recognized-Phaser/Babylon canvas branch captures neither
|
|
@@ -271,8 +271,8 @@ export function wireIngestSystems(opts: {
|
|
|
271
271
|
'game' in opts ? opts.game : typeof window === 'undefined' ? null : ingestGameRealmWindow(),
|
|
272
272
|
);
|
|
273
273
|
const { adapter: debug, collisions } = mergeDebugAdapters([
|
|
274
|
-
{ label: "the game's own contract (window.
|
|
275
|
-
{ label: "its adapter's observation table (
|
|
274
|
+
{ label: "the game's own contract (window.volterGame.systems)", adapter: contractDebug },
|
|
275
|
+
{ label: "its adapter's observation table (volter.adapter.ts)", adapter: observationDebug },
|
|
276
276
|
]);
|
|
277
277
|
const declared = projectContractSystemAdapters(opts.contractSystems, opts.surface);
|
|
278
278
|
const renderDebug = opts.runtime
|
|
@@ -284,7 +284,7 @@ export function wireIngestSystems(opts: {
|
|
|
284
284
|
// (last writer wins), so this is the only place that may install it, and
|
|
285
285
|
// anything needing the game's render pass multiplexes here rather than
|
|
286
286
|
// opening a second seam. The second consumer is the same-frame canvas
|
|
287
|
-
// snapshot (`ingest-frame-snapshot.ts`) that makes `
|
|
287
|
+
// snapshot (`ingest-frame-snapshot.ts`) that makes `volter-game-editor screenshot` readable
|
|
288
288
|
// over a game whose canvas has no `preserveDrawingBuffer`; it costs nothing
|
|
289
289
|
// until armed, and `deliverArmedIngestFrame` no-ops while no source is set —
|
|
290
290
|
// which is the canvas lane's state, because a Pixi ingest is already
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* the exact resolve+mount `module-mode.ts`'s `mountModuleRootRuntime`
|
|
21
21
|
* proves out, reused via `mountModuleRootRuntime`, but with NONE of that
|
|
22
22
|
* route's global side effects (no `setActiveAuthoring`/`setActiveSystems`,
|
|
23
|
-
* no viewport-tab switch, no `
|
|
23
|
+
* no viewport-tab switch, no `__volterModule` hook, no play-surface writes).
|
|
24
24
|
* Its `SiblingMount.setPaused` (D-B1) is wired straight from the scoped
|
|
25
25
|
* `GameSession.pause()`/`.resume()` `mountModuleRootRuntime` hands back —
|
|
26
26
|
* the SAME honest, already-existing capability `play-mode.ts`'s own
|
|
@@ -159,7 +159,7 @@ async function mountDefaultReactSibling(
|
|
|
159
159
|
const Entry = await resolveReactAdapterRootComponent(world, realm);
|
|
160
160
|
|
|
161
161
|
const layer = document.createElement('div');
|
|
162
|
-
layer.dataset['
|
|
162
|
+
layer.dataset['volterRootSurface'] = 'true';
|
|
163
163
|
styleSiblingLayer(layer, world, 'none');
|
|
164
164
|
gameContainer.appendChild(layer);
|
|
165
165
|
|
|
@@ -241,7 +241,7 @@ async function mountDefaultReactSibling(
|
|
|
241
241
|
* runtime `module-mode.ts`'s `mountModuleRootRuntime` provides — the exact
|
|
242
242
|
* resolve+mount the primary module route performs, reused here with none
|
|
243
243
|
* of that route's global side effects: no `setActiveAuthoring`/
|
|
244
|
-
* `setActiveSystems`, no viewport-tab switch, no `
|
|
244
|
+
* `setActiveSystems`, no viewport-tab switch, no `__volterModule` hook, no
|
|
245
245
|
* mount-failure-report clear. Mounts into its OWN layer div (never straight
|
|
246
246
|
* into the shared `gameContainer` the way the primary/single-world routes
|
|
247
247
|
* do) so its internal canvas/DOM stacking never collides with the ingest
|
|
@@ -74,7 +74,7 @@ export function exitModuleMode(): void {
|
|
|
74
74
|
} catch {
|
|
75
75
|
/* ignore */
|
|
76
76
|
}
|
|
77
|
-
delete (window as unknown as Record<string, unknown>)['
|
|
77
|
+
delete (window as unknown as Record<string, unknown>)['__volterModule'];
|
|
78
78
|
editorConsole.log('Module adapter mode stopped', 'adapter');
|
|
79
79
|
}
|
|
80
80
|
|
|
@@ -152,7 +152,7 @@ export async function enterModuleModeFromManifestRoot(
|
|
|
152
152
|
// Measured from the mounted adapter rather than declared by the route.
|
|
153
153
|
const reach = measureAdapterReach(mounted);
|
|
154
154
|
|
|
155
|
-
(window as unknown as Record<string, unknown>)['
|
|
155
|
+
(window as unknown as Record<string, unknown>)['__volterModule'] = {
|
|
156
156
|
worldId: world.id,
|
|
157
157
|
adapterId,
|
|
158
158
|
reach,
|