@volter/editor-game 0.5.68 → 0.5.70
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 +2 -2
- 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 +11 -11
- 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 +4 -4
- 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 +3 -3
- 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 +11 -11
- 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 +15 -15
- 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 +10 -10
- 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
package/NOTICE
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
Copyright 2026 Volter AI, Inc.
|
|
2
2
|
|
|
3
|
-
The files in this package were imported from volter-ai/
|
|
3
|
+
The files in this package were imported from volter-ai/volter-engine at commit
|
|
4
4
|
09c2749ce. LICENSE contains the AGPL-3.0-only license they retain.
|
|
5
5
|
|
|
6
|
-
packages/game/src, packages/game/contributions
|
|
6
|
+
packages/game/src, packages/game/contributions
|
|
7
7
|
-> src, contributions
|
|
8
|
-
packages/dom/src, packages/dom/contributions
|
|
8
|
+
packages/dom/src, packages/dom/contributions
|
|
9
9
|
-> src/react, contributions/react
|
|
10
10
|
packages/threejs/src except viewport/ and capture/, packages/threejs/contributions
|
|
11
|
-
|
|
12
|
-
host modules of packages/editor/src
|
|
11
|
+
-> src/three, contributions/three
|
|
12
|
+
host modules of packages/editor/src -> src/host, including
|
|
13
13
|
gameplay-export.ts and document-preview-three.ts, and the world-root stage
|
|
14
14
|
(components/world-root-stage.ts and the modules it draws with)
|
|
15
15
|
src/host/components/world-root-stage-binding.tsx is transcribed from the
|
|
@@ -18,6 +18,6 @@ The files in this package were imported from volter-ai/vgai-engine at commit
|
|
|
18
18
|
contributions/scene-document.service.ts from the Scene document half of
|
|
19
19
|
packages/editor/src/components/CenterDocuments.tsx
|
|
20
20
|
|
|
21
|
-
src/host/sdk/tools.ts was imported from
|
|
22
|
-
|
|
21
|
+
src/host/sdk/tools.ts was imported from src/tools.ts of the Apache-2.0 SDK
|
|
22
|
+
package of volter-ai/volter-engine, and retains that license. It re-exports the
|
|
23
23
|
Apache-2.0 tool contract of @volter/editor-sdk.
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* which fires at once when one is already registered) rather than for a React
|
|
13
13
|
* mount.
|
|
14
14
|
*
|
|
15
|
-
* It reports its failure to the editor console — `
|
|
15
|
+
* It reports its failure to the editor console — `volter-game-editor console` is what reads
|
|
16
16
|
* it — rather than leaving a stopped surface with no reason on it.
|
|
17
17
|
*/
|
|
18
18
|
import { onShellStore } from '@volter/editor-sdk/kit/shell-store-door';
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* as a center document: the build-role targets, the manifest fields a build
|
|
4
4
|
* reads, and the Build trigger. A document rather than a dialog because the
|
|
5
5
|
* configuration is a persistent authored surface (it writes
|
|
6
|
-
* `
|
|
6
|
+
* `volter.project.json` through the history service) someone tunes and re-runs,
|
|
7
7
|
* and because a modal would block the viewport while a build streams.
|
|
8
8
|
*
|
|
9
9
|
* It ships with `@volter/editor-game`, so a folder of models has no Build Profiles tab
|
|
@@ -23,7 +23,7 @@ export default function BuildProgressStatus() {
|
|
|
23
23
|
if (session.phase === 'building') {
|
|
24
24
|
return (
|
|
25
25
|
<span
|
|
26
|
-
className="
|
|
26
|
+
className="volter-status-copy"
|
|
27
27
|
data-testid="status-build-progress"
|
|
28
28
|
data-build-phase="building"
|
|
29
29
|
data-status-tone="accent"
|
|
@@ -34,7 +34,7 @@ export default function BuildProgressStatus() {
|
|
|
34
34
|
}
|
|
35
35
|
return (
|
|
36
36
|
<span
|
|
37
|
-
className="
|
|
37
|
+
className="volter-status-copy"
|
|
38
38
|
data-testid="status-build-progress"
|
|
39
39
|
data-build-phase={session.result?.ok ? 'complete' : 'failed'}
|
|
40
40
|
data-status-tone={session.result?.ok ? 'success' : 'danger'}
|
|
@@ -25,7 +25,7 @@ export default function BuildHeader() {
|
|
|
25
25
|
aria-label="Export project"
|
|
26
26
|
disabled={playing}
|
|
27
27
|
title={playing ? 'Stop Play mode before exporting the project' : 'Export project'}
|
|
28
|
-
className="
|
|
28
|
+
className="volter-chrome-island volter-glass-island"
|
|
29
29
|
onClick={() => {
|
|
30
30
|
openBuildProfilesDocument();
|
|
31
31
|
}}
|
|
@@ -31,7 +31,7 @@ export default function ConnectionStatus() {
|
|
|
31
31
|
type="button"
|
|
32
32
|
variant="ghost"
|
|
33
33
|
size="compact"
|
|
34
|
-
className="
|
|
34
|
+
className="volter-status-action"
|
|
35
35
|
data-testid="status-connection"
|
|
36
36
|
data-connection-state={state}
|
|
37
37
|
onClick={() => editorHost().workspace.showUtility(NETWORK_UTILITY_ID)}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* ## The two doors, both the host's own, neither of them new vocabulary
|
|
17
17
|
*
|
|
18
|
-
* - `session.reportFacet(collect, { reusableKeys })` — the four `
|
|
18
|
+
* - `session.reportFacet(collect, { reusableKeys })` — the four `volter-game-editor status`
|
|
19
19
|
* facets. The keys are declared REUSABLE because grading a root re-walks
|
|
20
20
|
* its tree (76ms–1.3s, measured), which is exactly the cost
|
|
21
21
|
* `command-listener.ts`'s `REUSABLE_DERIVED_FACETS` exists to keep off the
|
|
@@ -86,7 +86,7 @@ function coverageFacets(reuse: Record<string, unknown> | null): Record<string, u
|
|
|
86
86
|
: null,
|
|
87
87
|
// The THIRD derived family, and the one that lives outside both adapter
|
|
88
88
|
// contracts: the native verbs whose subject is the PROJECT rather than a
|
|
89
|
-
// mounted root — its committed proof route, whether `
|
|
89
|
+
// mounted root — its committed proof route, whether `volter-game-editor add` can land a
|
|
90
90
|
// capability here, and whether it can produce a standalone build at all
|
|
91
91
|
// (`@editor/coverage/project-verb-coverage`). Without it a project could
|
|
92
92
|
// be green in the other two families and silently have none of the three.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The STEP verbs of the session wire (`@volter/editor-sdk/commands`, a
|
|
3
3
|
* `workspace.command` contribution): `game-eval`, the module lane behind
|
|
4
|
-
* `
|
|
4
|
+
* `volter-game-editor eval`'s `game.run(...)`, and `page-script`, the in-page Playwright
|
|
5
5
|
* shim behind `page(...)`. Both carry a step function's own SOURCE over the
|
|
6
6
|
* wire and reconstruct it here — closures do not survive the trip — so both
|
|
7
7
|
* are gated on a live game surface (a play session or an ingest mount) and
|
|
8
8
|
* rooted at the game container, never editor chrome.
|
|
9
9
|
*
|
|
10
|
-
* The module lane's page-side door (`window.
|
|
10
|
+
* The module lane's page-side door (`window.__volterGameEval`) and the two
|
|
11
11
|
* providers it needs are installed when this module loads, which is when the
|
|
12
12
|
* verbs themselves become available: one handler, two doors, registered
|
|
13
13
|
* together.
|
|
@@ -37,7 +37,7 @@ export const point = 'workspace.command';
|
|
|
37
37
|
* source in the editor page (same wire contract as `page-script`: closures do
|
|
38
38
|
* not survive) and runs it against a scope of { page, modules, instanceId } —
|
|
39
39
|
* `modules(path)` importing the RUNNING mount's own module instances
|
|
40
|
-
* (`game-module-access.ts`). This is what makes `
|
|
40
|
+
* (`game-module-access.ts`). This is what makes `volter-game-editor eval` able to touch the
|
|
41
41
|
* game's exported modules directly, in the browser, with no registry: the
|
|
42
42
|
* step is literal JS against the game's real functions.
|
|
43
43
|
*
|
|
@@ -51,12 +51,12 @@ export const point = 'workspace.command';
|
|
|
51
51
|
*/
|
|
52
52
|
declare global {
|
|
53
53
|
interface Window {
|
|
54
|
-
|
|
54
|
+
__volterGameEval?: (src: string, instance?: string) => Promise<unknown>;
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
if (typeof window !== 'undefined') {
|
|
58
58
|
setFocusedInstanceProvider(focusedInstanceId);
|
|
59
|
-
window.
|
|
59
|
+
window.__volterGameEval = async (src: string, instance?: string) => {
|
|
60
60
|
const result = await handleGameEval({
|
|
61
61
|
type: 'game-eval',
|
|
62
62
|
src,
|
|
@@ -151,7 +151,7 @@ async function handlePageScript(cmd: EditorCommandMessage): Promise<EditorComman
|
|
|
151
151
|
// first-party `play-mode.ts` session. Keep the Playwright-style page door on
|
|
152
152
|
// the same reachability rule as bridge calls/screenshots: a real ingest
|
|
153
153
|
// container is sufficient, while the genuinely-unmounted case still
|
|
154
|
-
// refuses below. Without this, `
|
|
154
|
+
// refuses below. Without this, `volter-game-editor play` could start an ingested game and
|
|
155
155
|
// `game.commands()` would work, yet `page(...)` answered "not in play mode"
|
|
156
156
|
// against that very same visible game.
|
|
157
157
|
if (!isPlayModeActive() && !isIngestActive()) return notPlayingResult();
|
|
@@ -96,7 +96,7 @@ export const commands: CommandContribution['commands'] = {
|
|
|
96
96
|
}
|
|
97
97
|
// D15/T-D15.5 (review objection 2's fix) — resolved through the SAME
|
|
98
98
|
// per-world `DebugRegistry.getVirtualInputTarget(worldId?)` the debug
|
|
99
|
-
// bridge's `window.
|
|
99
|
+
// bridge's `window.__volter.input.*` calls, instead of the old
|
|
100
100
|
// `Game.input` (always the DEFAULT world only) — an explicit
|
|
101
101
|
// `cmd['worldId']` reaches that world specifically; omitted resolves
|
|
102
102
|
// to the same default both doors now share. Throws
|
|
@@ -217,7 +217,7 @@ export const commands: CommandContribution['commands'] = {
|
|
|
217
217
|
// session's `GameInternal.runTicks` through `getPlayRuntimeAccess()`'s
|
|
218
218
|
// `runTicks` accessor (itself backed by the SAME
|
|
219
219
|
// `DebugRegistry.getRunTicksTarget()` the bridge's
|
|
220
|
-
// `window.
|
|
220
|
+
// `window.__volter.runTicks` calls — one implementation, byte-identical
|
|
221
221
|
// behavior across doors, D17). `runTicks` itself throws a structured
|
|
222
222
|
// `DebugError` (`RUN_TICKS_PAUSED`) while paused — never a silent no-op —
|
|
223
223
|
// which `structuredErrorResult` below carries through as `data.code`.
|
|
@@ -38,7 +38,7 @@ export default function GenerationsStatus() {
|
|
|
38
38
|
type="button"
|
|
39
39
|
variant="ghost"
|
|
40
40
|
size="compact"
|
|
41
|
-
className="
|
|
41
|
+
className="volter-status-action"
|
|
42
42
|
data-testid="status-generations"
|
|
43
43
|
aria-label={`Generations, ${unseen} unseen, ${running} running`}
|
|
44
44
|
title={`${unseen} unseen generation results, ${running} running — open Generations`}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* registration, its `ingest`/`ingestCaptureWait` state facets and its
|
|
10
10
|
* `onShellStore` binding are module-load side effects of
|
|
11
11
|
* `mount-ingest-root.ts`. The static import below is therefore load-bearing
|
|
12
|
-
* — `
|
|
12
|
+
* — `volter-game-editor status` carries `ingest: null` / `ingestCaptureWait: null` before
|
|
13
13
|
* contribution pass. A product that composes no `@volter/editor-game` reports
|
|
14
14
|
* neither key, which is the honest state: no lane claims to mount
|
|
15
15
|
* unmodified games.
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* `isIngestActive()` is answered by a mount this hook already made.
|
|
25
25
|
*
|
|
26
26
|
* 3. REGISTERING THIS LANE'S ADAPTER DECLARATIONS. A repo-vendored game does
|
|
27
|
-
* not ship its own `
|
|
27
|
+
* not ship its own `volter.adapter.ts` — by the REALM rule its host-realm
|
|
28
28
|
* declaration lives in the in-tree registry (`@editor/ingest/registry`),
|
|
29
29
|
* which the host used to import directly and therefore carried in every
|
|
30
30
|
* editor boot, a `models` build that mounts no unmodified game included.
|
|
@@ -116,7 +116,7 @@ export const commands: CommandContribution['commands'] = {
|
|
|
116
116
|
// guard here: `play` on an already-playing (or still-booting) session
|
|
117
117
|
// is a RESTART, not a no-op, matching the SDK's own documented contract
|
|
118
118
|
// (`play.start`'s summary: "Start (or restart) play mode" —
|
|
119
|
-
// `packages/
|
|
119
|
+
// `packages/volter-sdk/src/play/lifecycle-operations.ts`). What used to
|
|
120
120
|
// make a restart unsafe was `enterPlayMode()` having no reentrancy
|
|
121
121
|
// guard for the async-boot window before it assigns `_session` — two
|
|
122
122
|
// overlapping calls ran their entire prologues concurrently and
|
|
@@ -127,11 +127,11 @@ export const commands: CommandContribution['commands'] = {
|
|
|
127
127
|
// SDK, a UI Play-button click racing a relayed command — gets a safe,
|
|
128
128
|
// clean restart for free without needing a guard here too.
|
|
129
129
|
try {
|
|
130
|
-
// D15/T-D15.6 (objection-4 fix) — `
|
|
130
|
+
// D15/T-D15.6 (objection-4 fix) — `volter-game-editor play --seed <n>` relays as
|
|
131
131
|
// `cmd['seed']`; `enterPlayMode`'s explicit-config seed leg (beats
|
|
132
|
-
// manifest.determinism.defaultSeed/?
|
|
132
|
+
// manifest.determinism.defaultSeed/?volter-seed=).
|
|
133
133
|
const seed = cmd['seed'];
|
|
134
|
-
// `
|
|
134
|
+
// `volter-game-editor play --name <text>` rides the same wire as `--seed`: a plain
|
|
135
135
|
// field on the relayed command, slugified server-side into this run's
|
|
136
136
|
// log filename and journal line. Absent, everything is unchanged.
|
|
137
137
|
const runName = cmd['name'];
|
|
@@ -173,11 +173,11 @@ export const commands: CommandContribution['commands'] = {
|
|
|
173
173
|
// EVERY PLAY RECORDS. There is no flag and no opt-in — see
|
|
174
174
|
// `play-recording.ts` for why the capability had to stop being one an
|
|
175
175
|
// agent must remember to switch on. `cmd['record']` only NAMES the file
|
|
176
|
-
// (`
|
|
176
|
+
// (`volter-game-editor play --record <name>`); its absence names the clip after the
|
|
177
177
|
// durable Gameplay Session.
|
|
178
178
|
//
|
|
179
179
|
// Started here rather than inside `enterPlayMode` on purpose: this
|
|
180
|
-
// handler is the RELAYED play (`
|
|
180
|
+
// handler is the RELAYED play (`volter-game-editor play`, the SDK's `play.start`),
|
|
181
181
|
// which is exactly the population the recording exists for. A human
|
|
182
182
|
// clicking the editor's own Play button is their own witness and gets
|
|
183
183
|
// play unchanged.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* ## Why this is a package and not the host's
|
|
10
10
|
*
|
|
11
|
-
* It was `
|
|
11
|
+
* It was the host's `authoring/react-inspector-section.tsx`,
|
|
12
12
|
* registered at module scope and reached by ONE line in the host's entry:
|
|
13
13
|
* `main.tsx:33`, `import './authoring/react-inspector-section';`. A bare
|
|
14
14
|
* side-effect import has no `from`, so the closure gate's walk never followed
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
* the DOM projection and the CSS inspection estate
|
|
63
63
|
* (`components/RootSelectionOverlay.tsx`); the surgical JSX writer and the
|
|
64
64
|
* structural write pipe (`authoring/r3f-source-authoring-adapter.ts`,
|
|
65
|
-
* `@
|
|
65
|
+
* `@volter/editor-game`'s `src/host/authoring/pixi-source-write-target.ts`); the breakpoint state
|
|
66
66
|
* (`components/BoardRulers.tsx`); `authoring/react-story-board.ts`, the
|
|
67
67
|
* board's geometry, which three host surfaces read
|
|
68
68
|
* (`components/RootSelectionOverlay.tsx:98`,
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@volter/editor-game",
|
|
3
3
|
"author": "Volter AI, Inc.",
|
|
4
4
|
"license": "AGPL-3.0-only",
|
|
5
|
-
"version": "0.5.
|
|
5
|
+
"version": "0.5.70",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
8
8
|
},
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"./host/stories/story-pixi-preview": "./src/host/stories/story-pixi-preview.ts",
|
|
31
31
|
"./host/stories/story-media-captures": "./src/host/stories/story-media-captures.ts"
|
|
32
32
|
},
|
|
33
|
-
"
|
|
33
|
+
"volter": {
|
|
34
34
|
"contributions": [
|
|
35
35
|
"./contributions/asset-budget-asset.menu.ts",
|
|
36
36
|
"./contributions/asset-budget.action.ts",
|
|
@@ -101,11 +101,11 @@
|
|
|
101
101
|
"serving": "./dist-node/serving.mjs"
|
|
102
102
|
},
|
|
103
103
|
"dependencies": {
|
|
104
|
-
"@volter/editor-sdk": "0.5.
|
|
105
|
-
"@volter/editor-project": "0.5.
|
|
106
|
-
"@volter/editor-threejs": "0.5.
|
|
107
|
-
"@volter/threejs-runtime": "0.5.
|
|
108
|
-
"@volter/game-runtime": "0.5.
|
|
104
|
+
"@volter/editor-sdk": "0.5.70",
|
|
105
|
+
"@volter/editor-project": "0.5.70",
|
|
106
|
+
"@volter/editor-threejs": "0.5.70",
|
|
107
|
+
"@volter/threejs-runtime": "0.5.70",
|
|
108
|
+
"@volter/game-runtime": "0.5.70",
|
|
109
109
|
"@colyseus/msgpackr": "^1.11.3",
|
|
110
110
|
"@colyseus/schema": "^4.0.14",
|
|
111
111
|
"@colyseus/sdk": "^0.17.34",
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
"xstate": "^5.32.4",
|
|
139
139
|
"zod": "^4.3.6",
|
|
140
140
|
"@fortawesome/fontawesome-svg-core": "^7.2.0",
|
|
141
|
-
"@volter/editor-react": "0.5.
|
|
141
|
+
"@volter/editor-react": "0.5.70"
|
|
142
142
|
},
|
|
143
143
|
"peerDependencies": {
|
|
144
144
|
"@sparkjsdev/spark": "^2.1.0",
|
package/serving/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `@volter/editor-game`'s server half (`package.json#
|
|
2
|
+
* `@volter/editor-game`'s server half (`package.json#volter.serving`): the one deep specifier a
|
|
3
3
|
* game's own contributions name, `@editor/game-module-access` (the template's
|
|
4
4
|
* `src/contributions/use-game-modules.ts`), resolved to this package's module. The page
|
|
5
5
|
* bundle maps the same specifier for its own copy (`src/host/served-bundle-runtime-modules.ts`);
|
|
@@ -882,7 +882,7 @@ function OptimizeActions({ entry, onApplied }: { entry: AssetBudgetEntry; onAppl
|
|
|
882
882
|
{lodCandidates.length > 0 ? (
|
|
883
883
|
<div style={{ display: 'flex', gap: spaceVar[2], marginTop: spaceVar[3] }}>
|
|
884
884
|
<Select
|
|
885
|
-
className="
|
|
885
|
+
className="volter-select"
|
|
886
886
|
aria-label="LOD base node"
|
|
887
887
|
data-testid="asset-budget-op-lod-node"
|
|
888
888
|
value={chosenLodNode}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* - the project REFERENCE GRAPH: which manifest entries, code files, or
|
|
13
13
|
* sibling assets mention each asset ("what uses this", critique P5),
|
|
14
14
|
* the unused list derived from it, and duplicate groups by sha256
|
|
15
|
-
* - provenance stamps projected from `.
|
|
15
|
+
* - provenance stamps projected from `.volter/provenance.json`
|
|
16
16
|
*
|
|
17
17
|
* Anti-shim: anything unmeasurable is reported as absent/unknown with a
|
|
18
18
|
* reason (`inspectError`, `gpuBytes: null`, `unknownTextureCount`) — never a
|
|
@@ -190,7 +190,7 @@ export interface AssetBudgetSource {
|
|
|
190
190
|
* Reference-owner documents living OUTSIDE the walked snapshot, scanned for
|
|
191
191
|
* references but never budget rows. Server mode uses this for the project
|
|
192
192
|
* manifest: `HttpStorage` is hard-rooted at `public/` (its own doc comment;
|
|
193
|
-
* the T3.3 "two-`.
|
|
193
|
+
* the T3.3 "two-`.volter`-dirs" finding), so `volter.project.json` is unreachable
|
|
194
194
|
* through the seam and is fetched over the dev server instead — without it,
|
|
195
195
|
* every manifest-referenced asset (input maps, scenes) would be reported
|
|
196
196
|
* unused, a fabricated finding.
|
|
@@ -213,7 +213,7 @@ export interface AssetBudgetSource {
|
|
|
213
213
|
readonly codeReferencesScannable?: boolean;
|
|
214
214
|
readBytes(path: string): Promise<Uint8Array>;
|
|
215
215
|
readText(path: string): Promise<string>;
|
|
216
|
-
/** Parsed `.
|
|
216
|
+
/** Parsed `.volter/provenance.json` (or null/undefined when absent). */
|
|
217
217
|
readonly provenance?: unknown;
|
|
218
218
|
}
|
|
219
219
|
|
|
@@ -282,7 +282,7 @@ export function isEngineVendoredRuntimePath(path: string): boolean {
|
|
|
282
282
|
// --- Reference scanning ------------------------------------------------------
|
|
283
283
|
|
|
284
284
|
const CODE_OWNER_PATTERN = /\.(?:tsx?|jsx?|mjs|cjs)$/i;
|
|
285
|
-
const MANIFEST_NAME = '
|
|
285
|
+
const MANIFEST_NAME = 'volter.project.json';
|
|
286
286
|
|
|
287
287
|
/**
|
|
288
288
|
* The manifest is the ONLY JSON document that owns asset references. An
|
|
@@ -450,7 +450,7 @@ const IGNORED_DIRS = new Set([
|
|
|
450
450
|
'.git',
|
|
451
451
|
'dist',
|
|
452
452
|
'build',
|
|
453
|
-
'.
|
|
453
|
+
'.volter',
|
|
454
454
|
'.ci-scaffold',
|
|
455
455
|
'coverage',
|
|
456
456
|
'test-results',
|
|
@@ -476,21 +476,21 @@ export async function collectProjectBudgetSource(
|
|
|
476
476
|
await walk('');
|
|
477
477
|
|
|
478
478
|
// Server mode: `HttpStorage` is hard-rooted at the project's `public/`
|
|
479
|
-
// folder (its doc comment; the T3.3 "two-`.
|
|
479
|
+
// folder (its doc comment; the T3.3 "two-`.volter`-dirs" finding), so BOTH
|
|
480
480
|
// project-root documents the budget needs live outside the seam. Use the
|
|
481
481
|
// dev server's own idioms for each: the raw manifest served at
|
|
482
|
-
// `/
|
|
483
|
-
// `/__editor/
|
|
482
|
+
// `/volter.project.json` (`manifest-project.ts`) and the `.volter/`-scoped
|
|
483
|
+
// `/__editor/volter-file` route (`project-provenance.ts`). Anything
|
|
484
484
|
// unavailable stays honestly absent — no fabricated owners or stamps.
|
|
485
485
|
if (isPublicRootedBackend(backend)) {
|
|
486
486
|
const ownerFiles: AssetBudgetFile[] = [];
|
|
487
487
|
const virtualTexts = new Map<string, string>();
|
|
488
488
|
try {
|
|
489
|
-
const manifestRes = await fetch('/
|
|
489
|
+
const manifestRes = await fetch('/volter.project.json');
|
|
490
490
|
if (manifestRes.ok) {
|
|
491
491
|
const text = await manifestRes.text();
|
|
492
|
-
virtualTexts.set('
|
|
493
|
-
ownerFiles.push({ path: '
|
|
492
|
+
virtualTexts.set('volter.project.json', text);
|
|
493
|
+
ownerFiles.push({ path: 'volter.project.json', size: text.length });
|
|
494
494
|
}
|
|
495
495
|
} catch {
|
|
496
496
|
// No reachable manifest → no manifest-owned references.
|
|
@@ -501,7 +501,7 @@ export async function collectProjectBudgetSource(
|
|
|
501
501
|
// answers `text/plain` raw file bytes, which that JSON-only reader would
|
|
502
502
|
// reject as a non-answer. See `optimize-apply.ts`'s `readLedgerText`.
|
|
503
503
|
const provenanceRes = await fetch(
|
|
504
|
-
`/__editor/
|
|
504
|
+
`/__editor/volter-file?${new URLSearchParams({ path: '.volter/provenance.json' })}`,
|
|
505
505
|
);
|
|
506
506
|
if (provenanceRes.ok) provenance = JSON.parse(await provenanceRes.text());
|
|
507
507
|
} catch {
|
|
@@ -525,8 +525,8 @@ export async function collectProjectBudgetSource(
|
|
|
525
525
|
|
|
526
526
|
let provenance: unknown = null;
|
|
527
527
|
try {
|
|
528
|
-
if (await backend.exists('.
|
|
529
|
-
provenance = JSON.parse(await backend.read('.
|
|
528
|
+
if (await backend.exists('.volter/provenance.json')) {
|
|
529
|
+
provenance = JSON.parse(await backend.read('.volter/provenance.json'));
|
|
530
530
|
}
|
|
531
531
|
} catch {
|
|
532
532
|
provenance = null; // unreadable provenance = no stamps, never a crash
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Storage-side APPLY flow for Asset Budget optimizations (W4a M3).
|
|
3
3
|
*
|
|
4
4
|
* One place owns "optimized bytes land in the project": write through the
|
|
5
|
-
* storage seam, stamp central provenance (`.
|
|
5
|
+
* storage seam, stamp central provenance (`.volter/provenance.json`, the SAME
|
|
6
6
|
* document/idiom the generative-assets pipeline stamps and
|
|
7
7
|
* `project-provenance.ts` projects — one operation with an `outputs` entry
|
|
8
8
|
* carrying path/bytes/sha256), invalidate the engine's URL-keyed asset cache
|
|
@@ -27,7 +27,7 @@ import { handleProjectMutationFailure } from '@volter/editor-sdk/kit/source-conf
|
|
|
27
27
|
import { isPublicRootedBackend, type StorageBackend } from '@volter/editor-sdk/kit/storage-types';
|
|
28
28
|
import { invalidateCachedAsset } from '@volter/threejs-runtime/asset-loaders';
|
|
29
29
|
|
|
30
|
-
const PROVENANCE_PATH = '.
|
|
30
|
+
const PROVENANCE_PATH = '.volter/provenance.json';
|
|
31
31
|
|
|
32
32
|
/** Serving path (`/models/x.glb`) or bare path → storage path under public/. */
|
|
33
33
|
export function assetStoragePath(path: string): string {
|
|
@@ -74,10 +74,10 @@ function ledgerAssetPath(storagePath: string): string {
|
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
76
|
* Ledger IO honoring the backend's reach: server-mode `HttpStorage` is
|
|
77
|
-
* hard-rooted at `public/`, so writing `.
|
|
78
|
-
* would land at `public/.
|
|
79
|
-
* (the exact T3.3 "two-`.
|
|
80
|
-
* `.
|
|
77
|
+
* hard-rooted at `public/`, so writing `.volter/provenance.json` through it
|
|
78
|
+
* would land at `public/.volter/provenance.json` — a divergent second ledger
|
|
79
|
+
* (the exact T3.3 "two-`.volter`-dirs" bug class). The dev server's
|
|
80
|
+
* `.volter/`-scoped `/__editor/volter-file` GET/POST route pair is the recorded
|
|
81
81
|
* fix for that class; every other
|
|
82
82
|
* backend reaches the project root directly.
|
|
83
83
|
*/
|
|
@@ -88,7 +88,7 @@ async function readLedgerText(backend: StorageBackend): Promise<string | null> {
|
|
|
88
88
|
// file bytes, and that reader's whole rule is "the editor server answers
|
|
89
89
|
// JSON" — it would reject this route's successes.
|
|
90
90
|
const res = await fetch(
|
|
91
|
-
`/__editor/
|
|
91
|
+
`/__editor/volter-file?${new URLSearchParams({ path: PROVENANCE_PATH })}`,
|
|
92
92
|
);
|
|
93
93
|
if (res.status === 404) return null;
|
|
94
94
|
if (!res.ok) throw new Error(`read ${PROVENANCE_PATH}: HTTP ${res.status}`);
|
|
@@ -101,7 +101,7 @@ async function readLedgerText(backend: StorageBackend): Promise<string | null> {
|
|
|
101
101
|
async function writeLedgerText(backend: StorageBackend, content: string): Promise<void> {
|
|
102
102
|
if (isPublicRootedBackend(backend)) {
|
|
103
103
|
const write = async () => {
|
|
104
|
-
const res = await fetch('/__editor/
|
|
104
|
+
const res = await fetch('/__editor/volter-file', {
|
|
105
105
|
method: 'POST',
|
|
106
106
|
headers: { 'Content-Type': 'application/json' },
|
|
107
107
|
body: JSON.stringify({ path: PROVENANCE_PATH, content, ...sourceMutationAttribution() }),
|
package/src/bridge/call.ts
CHANGED
|
@@ -17,7 +17,7 @@ import { dispatchBridgeMethod, hasLiveDebugPlane } from './dispatch';
|
|
|
17
17
|
* this package); everything else is `dispatchBridgeMethod`'s own structured
|
|
18
18
|
* failure, caught here and shipped back via `structuredErrorResult` so
|
|
19
19
|
* `code`/`data` survive the relay round trip byte-equivalent to the
|
|
20
|
-
* page-transport's `unwrap()` path (`packages/
|
|
20
|
+
* page-transport's `unwrap()` path (`packages/volter-live/src/game-client/client.ts`). */
|
|
21
21
|
export async function handleBridgeCall(cmd: EditorCommandMessage): Promise<EditorCommandResult> {
|
|
22
22
|
// The precondition is "no plane at all", not "not playing" — see
|
|
23
23
|
// `hasLiveDebugPlane`. The per-method preconditions inside
|
|
@@ -28,7 +28,7 @@ export async function handleBridgeCall(cmd: EditorCommandMessage): Promise<Edito
|
|
|
28
28
|
// the still edit world can be driven.
|
|
29
29
|
if (!isPlayModeActive() && !hasLiveDebugPlane()) {
|
|
30
30
|
// A LIVE INGEST that publishes no plane is a third state, and answering it
|
|
31
|
-
// with "not in play mode" sends the reader to `
|
|
31
|
+
// with "not in play mode" sends the reader to `volter-game-editor play` over a game that
|
|
32
32
|
// is already running and visible. MEASURED on the `flappy` canvas ingest:
|
|
33
33
|
// `game.waitSimTime(...)` refused with the play sentence while the mount's
|
|
34
34
|
// own play state read `playing`. The mount is what is missing a plane, so
|
|
@@ -43,7 +43,7 @@ export async function handleBridgeCall(cmd: EditorCommandMessage): Promise<Edito
|
|
|
43
43
|
'this ingest mount is live, but it publishes no debug plane — the mount installs no ' +
|
|
44
44
|
'SystemAdapters.debug, so there is nothing to enumerate, read or drive through the ' +
|
|
45
45
|
'game seam. Starting play will not change that; the game itself must declare the ' +
|
|
46
|
-
'
|
|
46
|
+
'volter game contract (or carry a contract shim beside it) for these calls to have an ' +
|
|
47
47
|
'answer.',
|
|
48
48
|
}
|
|
49
49
|
: notPlayingResult();
|
package/src/bridge/dispatch.ts
CHANGED
|
@@ -109,19 +109,19 @@ function recordContractSystemUse(member: string, value: unknown, name?: string):
|
|
|
109
109
|
|
|
110
110
|
/**
|
|
111
111
|
* #140 — the generic session-wire dispatch table: the SAME method-name
|
|
112
|
-
* surface `window.
|
|
113
|
-
* `
|
|
112
|
+
* surface `window.__volter` exposes (`@volter/editor-game/runtime/debug-bridge`'s
|
|
113
|
+
* `VolterDebugHandle` — `state`/`stateAll`/`providers`/`commands`/`events`/
|
|
114
114
|
* `snapshot`/`invoke`/`runTicks`/`input.*`), built from the SAME
|
|
115
115
|
* registry-backed accessors the sibling
|
|
116
116
|
* `gameplay.command.ts` verbs (`list-gameplay-state`/`inject-input`/`run-ticks`)
|
|
117
117
|
* already use. This is what makes the
|
|
118
118
|
* `bridge-call` relay op (below) a session-generic primitive rather than a
|
|
119
119
|
* test-specific one — any client of the live session (the `@volter/editor-live`
|
|
120
|
-
* `RelayTransport`, a future one-shot `
|
|
120
|
+
* `RelayTransport`, a future one-shot `volter game state/call/hold` REPL) can
|
|
121
121
|
* issue `{method, callArgs}` against it with no dependency on a proof run's
|
|
122
122
|
* own lifecycle/env, and get byte-identical dispatch to the page-transport's
|
|
123
123
|
* `page.evaluate(bridgeCallInPage)` (D17) — without requiring the editor tab
|
|
124
|
-
* to be loaded with `?
|
|
124
|
+
* to be loaded with `?volter-debug=1` (that gate exists for the bridge's own
|
|
125
125
|
* production exposure; this relay is already local-loopback-only — see
|
|
126
126
|
* `editor-server.ts`'s CSRF/origin guard).
|
|
127
127
|
*/
|
|
@@ -228,7 +228,7 @@ export async function dispatchBridgeMethod(
|
|
|
228
228
|
// funnels window error/unhandledrejection into the editor console as
|
|
229
229
|
// level 'error' / source 'runtime' (`installEditorConsoleCapture`'s
|
|
230
230
|
// boot-time listeners) — the SAME events and message format
|
|
231
|
-
// `window.
|
|
231
|
+
// `window.__volter`'s own handle buffers. Fenced to the current play run
|
|
232
232
|
// via `inPlayRun` so a probe never reads a previous run's stale
|
|
233
233
|
// failures, capped at 100 for parity with the bridge's ring buffer.
|
|
234
234
|
pageErrors: collectPlayRunPageErrors(),
|
|
@@ -308,10 +308,10 @@ export async function dispatchBridgeMethod(
|
|
|
308
308
|
case 'input.clearVirtualActions':
|
|
309
309
|
// bridge↔wire coverage-parity gate (`bridge-wire-parity.test.ts`)
|
|
310
310
|
// closed this trio's gap: `startRecording`/`stopRecording`/`isRecording`
|
|
311
|
-
// exist on the page bridge's `
|
|
311
|
+
// exist on the page bridge's `VolterDebugInputHandle` (`runtime/
|
|
312
312
|
// debug-bridge.ts`) but had no relay case at all — an agent driving the
|
|
313
313
|
// input-trace recorder over the session wire (RelayTransport) instead of
|
|
314
|
-
// `?
|
|
314
|
+
// `?volter-debug=1` simply had no door to it. Same single optional
|
|
315
315
|
// trailing `worldId` shape as `clearVirtualActions`.
|
|
316
316
|
case 'input.startRecording':
|
|
317
317
|
case 'input.stopRecording':
|
|
@@ -320,10 +320,10 @@ export async function dispatchBridgeMethod(
|
|
|
320
320
|
// D15/T-D15.5 (rebase composition with #140): this wire is a THIRD
|
|
321
321
|
// door to the virtual-input target — it must resolve through the SAME
|
|
322
322
|
// `DebugRegistry.getVirtualInputTarget(worldId?)` the page bridge
|
|
323
|
-
// (`window.
|
|
323
|
+
// (`window.__volter.input.*`) and the `inject-input` relay case use, so
|
|
324
324
|
// no two doors can ever disagree about which world an unqualified
|
|
325
325
|
// actuation targets. Each method takes the page bridge's own optional
|
|
326
|
-
// trailing `worldId` (byte-parity with `
|
|
326
|
+
// trailing `worldId` (byte-parity with `VolterDebugInputHandle`); an
|
|
327
327
|
// explicit, unregistered id throws the registry's structured
|
|
328
328
|
// `DEBUG_INPUT_WORLD_NOT_FOUND`, shipped back over the wire as-is.
|
|
329
329
|
const worldId = (
|
|
@@ -365,7 +365,7 @@ export async function dispatchBridgeMethod(
|
|
|
365
365
|
return inputTarget.isInputRecording();
|
|
366
366
|
}
|
|
367
367
|
case 'input.scheduleActionAtTick': {
|
|
368
|
-
// bridge↔wire coverage-parity gate: `window.
|
|
368
|
+
// bridge↔wire coverage-parity gate: `window.__volter.input.
|
|
369
369
|
// scheduleActionAtTick` (`runtime/debug-bridge.ts`, D15/T-D15.5) had NO
|
|
370
370
|
// bridge-call case — it was reachable over the relay ONLY via the
|
|
371
371
|
// separate `inject-input` command's `atTick` field (see that case,
|
|
@@ -390,7 +390,7 @@ export async function dispatchBridgeMethod(
|
|
|
390
390
|
}
|
|
391
391
|
case 'input.injectPointerDelta':
|
|
392
392
|
case 'input.injectPointerPosition': {
|
|
393
|
-
// pointer-dispatch op: `window.
|
|
393
|
+
// pointer-dispatch op: `window.__volter.input.injectPointerDelta`/
|
|
394
394
|
// `injectPointerPosition` (`runtime/debug-bridge.ts`) had no relay case
|
|
395
395
|
// — this is the HONEST gameplay-seam reading of "pointer dispatch": the
|
|
396
396
|
// engine's existing virtual pointer-injection, never a synthesized DOM
|
|
@@ -417,7 +417,7 @@ export async function dispatchBridgeMethod(
|
|
|
417
417
|
return undefined;
|
|
418
418
|
}
|
|
419
419
|
case 'holdFor': {
|
|
420
|
-
// #140/D17: byte-identical semantics to `window.
|
|
420
|
+
// #140/D17: byte-identical semantics to `window.__volter.holdFor` (door
|
|
421
421
|
// a, `runtime/debug-bridge.ts`) — same `getInputTarget(worldId?)`
|
|
422
422
|
// resolution as the `input.*` cases above, same `waitForHoldBudget`
|
|
423
423
|
// poll/stall loop (imported, not hand-copied, so the two doors can
|
package/src/bridge/screenshot.ts
CHANGED
|
@@ -51,7 +51,7 @@ import { captureLiveCanvasFrame } from './live-frames';
|
|
|
51
51
|
*
|
|
52
52
|
* BOTH legs read a canvas, and a canvas is only readable after its frame when
|
|
53
53
|
* its WebGL context was created with `preserveDrawingBuffer: true`. Every
|
|
54
|
-
* canvas the
|
|
54
|
+
* canvas the volter RUNTIME mounts sets it (`@volter/editor-game/runtime/create-runtime`,
|
|
55
55
|
* D5 §1/§4); a canvas an INGESTED game created is the game's own and usually
|
|
56
56
|
* does not, which read as a silently BLACK screenshot over a perfectly
|
|
57
57
|
* healthy running game. {@link liveCanvasFrame} is the answer for that
|
|
@@ -102,8 +102,8 @@ function screenshotResult(
|
|
|
102
102
|
* and the play log whose event timestamps convert an event into an offset.
|
|
103
103
|
*
|
|
104
104
|
* THIS USED TO BE A REFUSAL, AND THE REFUSAL WAS THE DEFECT (2026-08-29,
|
|
105
|
-
* cold fox #3). Because `
|
|
106
|
-
* `
|
|
105
|
+
* cold fox #3). Because `volter-game-editor play` always records, refusing the still made
|
|
106
|
+
* `volter-game-editor screenshot` dead for the rest of the session — and the look lane's
|
|
107
107
|
* questions ("is the ear proportion right", "is the fox sunk into the
|
|
108
108
|
* ground") are exactly the ones a still DOES answer. The refusal was
|
|
109
109
|
* discouraging a wrong question by making a right one impossible, and the
|
|
@@ -160,7 +160,7 @@ export async function handleBridgeScreenshot(
|
|
|
160
160
|
// Same reachability rule `handleBridgeCall` uses, and for the same reason:
|
|
161
161
|
// an ingested game's mount IS the running game, so it never creates a
|
|
162
162
|
// first-party play session and `isPlayModeActive()` alone made
|
|
163
|
-
// `
|
|
163
|
+
// `volter-game-editor screenshot` permanently unusable against ingest. Loosening the gate
|
|
164
164
|
// costs nothing in honesty — the ingest mount renders into the very
|
|
165
165
|
// container `getInstanceContainer()` returns (`play-mode.ts`'s
|
|
166
166
|
// `getGameContainer` is shared with the ingest mount paths), and when there is
|
|
@@ -171,10 +171,10 @@ export async function handleBridgeScreenshot(
|
|
|
171
171
|
// TRUE. `hasLiveDebugPlane()` covers an ingest that publishes a debug plane
|
|
172
172
|
// projected from a declared contract — which a canvas ingest has no way to
|
|
173
173
|
// do (`mount-canvas-ingest-root.ts` publishes `setActiveSystems({})`), so
|
|
174
|
-
// `
|
|
174
|
+
// `volter-game-editor screenshot` answered "not in play mode" over a mounted, running,
|
|
175
175
|
// self-ticking game whose play state the mount had itself set to `playing`.
|
|
176
176
|
// A lying refusal is worse than a missing feature: it sends the reader to
|
|
177
|
-
// `
|
|
177
|
+
// `volter-game-editor play`, which is not the thing that was wrong. The question this gate
|
|
178
178
|
// asks is "is a game surface live here", and a live ingest is one.
|
|
179
179
|
if (!isPlayModeActive() && !hasLiveDebugPlane() && !isIngestActive()) return notPlayingResult();
|
|
180
180
|
// Capture the ADDRESSED seat, not always the primary. `game.instance(id)`
|