@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.
Files changed (169) hide show
  1. package/NOTICE +7 -7
  2. package/contributions/autoplay.service.ts +1 -1
  3. package/contributions/build-profiles.document.tsx +1 -1
  4. package/contributions/build-progress.status.tsx +2 -2
  5. package/contributions/build.header.tsx +1 -1
  6. package/contributions/connection.status.tsx +1 -1
  7. package/contributions/coverage.service.ts +2 -2
  8. package/contributions/game-eval.command.ts +6 -6
  9. package/contributions/gameplay.command.ts +2 -2
  10. package/contributions/generations.status.tsx +1 -1
  11. package/contributions/ingest.service.ts +2 -2
  12. package/contributions/play.command.ts +6 -6
  13. package/contributions/react/react-inspector.service.ts +2 -2
  14. package/package.json +8 -8
  15. package/serving/index.ts +1 -1
  16. package/src/asset-budget/AssetBudgetPanel.tsx +1 -1
  17. package/src/asset-budget/asset-budget-model.ts +14 -14
  18. package/src/asset-budget/optimize-apply.ts +8 -8
  19. package/src/bridge/call.ts +3 -3
  20. package/src/bridge/dispatch.ts +12 -12
  21. package/src/bridge/screenshot.ts +6 -6
  22. package/src/build/BuildProfilesPanel.tsx +8 -8
  23. package/src/canvas/canvas-board/CanvasBoardDocument.tsx +2 -2
  24. package/src/canvas/canvas-board/canvas-component-board.ts +1 -1
  25. package/src/canvas/canvas-design-mount.ts +1 -1
  26. package/src/coverage/live-project-verbs.ts +3 -3
  27. package/src/coverage/native-system-coverage.ts +3 -3
  28. package/src/coverage/root-coverage.ts +2 -2
  29. package/src/coverage/session-coverage.ts +2 -2
  30. package/src/design-system-stories/InspectorNarrowBodies.stories.tsx +2 -2
  31. package/src/game-document/DevicePresetPicker.tsx +6 -6
  32. package/src/game-document/GameCaptureFrameButton.tsx +1 -1
  33. package/src/game-document/GameDocument.tsx +2 -2
  34. package/src/game-document/GamePanel.tsx +9 -9
  35. package/src/game-document/InstanceInspectorPicker.tsx +1 -1
  36. package/src/game-document/device-preview.ts +4 -4
  37. package/src/game-document/physics-debug.ts +2 -2
  38. package/src/generation/GenerationActivity.tsx +22 -22
  39. package/src/generation/GenerationGallery.css +79 -79
  40. package/src/generation/generation-documents.tsx +25 -25
  41. package/src/generation/generation-presentation.ts +1 -1
  42. package/src/host/adapter-reach.ts +1 -1
  43. package/src/host/adapter-runtime-bindings.ts +5 -5
  44. package/src/host/after-paint.ts +3 -3
  45. package/src/host/api/configurations.ts +1 -1
  46. package/src/host/authoring/canvas-runtime-recognition.ts +2 -2
  47. package/src/host/authoring/contract-hierarchy-authoring.ts +6 -6
  48. package/src/host/authoring/contract-scenes-stories.ts +5 -5
  49. package/src/host/authoring/ingest-data-writer.ts +1 -1
  50. package/src/host/authoring/ingest-source-persistence.ts +2 -2
  51. package/src/host/authoring/mount-isolated-pixi-screen.ts +1 -1
  52. package/src/host/authoring/pixi-authoring-adapter.ts +60 -4
  53. package/src/host/authoring/pixi-creatable-kinds.ts +18 -0
  54. package/src/host/authoring/pixi-live-write-target.ts +6 -5
  55. package/src/host/authoring/pixi-source-write-target.ts +5 -2
  56. package/src/host/authoring/pixi-structure-history.ts +3 -3
  57. package/src/host/binding-resolver.ts +6 -6
  58. package/src/host/browser-transpile.ts +11 -11
  59. package/src/host/canvas-preview-frames.ts +1 -1
  60. package/src/host/components/CameraAuthoringOverlay.tsx +14 -14
  61. package/src/host/components/HeaderTelemetry.tsx +11 -11
  62. package/src/host/components/PixiIsolationSceneContent.tsx +2 -2
  63. package/src/host/components/ResolutionPicker.tsx +4 -4
  64. package/src/host/components/scene-document.tsx +3 -3
  65. package/src/host/components/world-root-stage-binding.tsx +1 -1
  66. package/src/host/components/world-root-stage.ts +1 -1
  67. package/src/host/coverage/authoring-read-probe.ts +1 -1
  68. package/src/host/coverage/capability-coverage.ts +22 -22
  69. package/src/host/coverage/game-contract-seam-evidence.ts +8 -8
  70. package/src/host/coverage/project-verb-coverage.ts +1 -1
  71. package/src/host/coverage/system-adapter-coverage.ts +19 -6
  72. package/src/host/game-location-guard.ts +4 -4
  73. package/src/host/game-module-access.ts +6 -6
  74. package/src/host/game-realm-page.ts +3 -3
  75. package/src/host/game-realm-reclaim.ts +1 -1
  76. package/src/host/gameplay-recording.ts +5 -5
  77. package/src/host/gated-globals.ts +13 -13
  78. package/src/host/ingest/registry.ts +14 -14
  79. package/src/host/play-control-hook.ts +1 -1
  80. package/src/host/playwright-shim.ts +3 -3
  81. package/src/host/projection/pixi.ts +2 -2
  82. package/src/host/react-mount-runtime.ts +1 -1
  83. package/src/host/roots/canvas-root.tsx +2 -2
  84. package/src/host/roots/r3f-root.tsx +1 -1
  85. package/src/host/scene-view-drawability.ts +1 -1
  86. package/src/host/sdk/tools.ts +1 -1
  87. package/src/host/staged-projects.ts +1 -1
  88. package/src/host/stories/story-pixi-preview.ts +1 -1
  89. package/src/host/stories/story-three-preview.ts +1 -1
  90. package/src/host/three-ingest-runtime.ts +1 -1
  91. package/src/ingest/active-ingest.ts +1 -1
  92. package/src/ingest/authoring/ingest-dom-surface-authoring.ts +4 -4
  93. package/src/ingest/authoring/ingest-root-adapter.ts +11 -11
  94. package/src/ingest/capture-wait-report.ts +4 -4
  95. package/src/ingest/discovery-public-ingest.ts +4 -4
  96. package/src/ingest/dom-stub-mark.ts +1 -1
  97. package/src/ingest/entry-load.ts +1 -1
  98. package/src/ingest/game-contract-realm.ts +3 -3
  99. package/src/ingest/game-pointer-lock.ts +1 -1
  100. package/src/ingest/ingest-canvas-scene-document.tsx +2 -2
  101. package/src/ingest/ingest-evidence-hook.ts +6 -6
  102. package/src/ingest/ingest-frame-snapshot.ts +2 -2
  103. package/src/ingest/ingest-play-commands.ts +1 -1
  104. package/src/ingest/ingest-play-control.ts +11 -11
  105. package/src/ingest/ingest-render-debug.ts +5 -5
  106. package/src/ingest/ingest-siblings.ts +3 -3
  107. package/src/ingest/module-mode.ts +2 -2
  108. package/src/ingest/mount-canvas-ingest-root.ts +10 -10
  109. package/src/ingest/mount-coverage.ts +3 -3
  110. package/src/ingest/mount-dom-ingest-root.ts +7 -7
  111. package/src/ingest/mount-ingest-root.ts +11 -11
  112. package/src/ingest/mount-three-ingest-root.ts +5 -5
  113. package/src/ingest/resolve-three.ts +2 -2
  114. package/src/ingest/served-bundle.ts +6 -6
  115. package/src/ingest/served-html-boot.ts +8 -8
  116. package/src/ingest/surface-dom.ts +9 -9
  117. package/src/ingest/surface-three.ts +1 -1
  118. package/src/ingest/types.ts +1 -1
  119. package/src/ingest/unmount-ingest-root.ts +3 -3
  120. package/src/network/NetworkInspectorPanel.tsx +2 -2
  121. package/src/play/play-boot-stall.ts +1 -1
  122. package/src/play/play-mode.ts +31 -30
  123. package/src/play/play-recording.ts +12 -12
  124. package/src/play-bar/PlayBar.tsx +8 -8
  125. package/src/play-bar/PlayerCountPicker.tsx +3 -3
  126. package/src/profiler/FrameDebuggerPanel.tsx +2 -2
  127. package/src/profiler/PerformancePanel.tsx +4 -4
  128. package/src/react/design-time-react-mount.ts +5 -5
  129. package/src/react/dom-authoring-adapter.ts +3 -3
  130. package/src/react/react-inspector-section.tsx +2 -2
  131. package/src/react/react-world-authoring-adapter.ts +20 -20
  132. package/src/react/story-documents/story-documents.tsx +4 -4
  133. package/src/react/ui-component-board.ts +1 -1
  134. package/src/runtime/adapter/audio-meter.ts +1 -1
  135. package/src/runtime/adapter/ingest/contract-debug-adapter.ts +4 -4
  136. package/src/runtime/adapter/ingest/contract-system-adapters.ts +9 -9
  137. package/src/runtime/adapter/ingest/merge-debug-adapters.ts +2 -2
  138. package/src/runtime/adapter/ingest/observation-debug-adapter.ts +1 -1
  139. package/src/runtime/adapter/native-debug-module.ts +5 -5
  140. package/src/runtime/audio/pose-guard.ts +1 -1
  141. package/src/runtime/core/game-scoped-slot.ts +1 -1
  142. package/src/runtime/create-runtime.ts +15 -15
  143. package/src/runtime/debug-bridge.ts +25 -25
  144. package/src/runtime/debug-registry.ts +17 -17
  145. package/src/runtime/dev/instruments.ts +1 -1
  146. package/src/runtime/dev/performance-profiler.ts +2 -2
  147. package/src/runtime/dev/register-render-vitals.ts +2 -2
  148. package/src/runtime/dev/static-batch-advisor.ts +3 -3
  149. package/src/runtime/dev-build.ts +3 -3
  150. package/src/runtime/game.ts +5 -5
  151. package/src/runtime/input-router.ts +1 -1
  152. package/src/runtime/mount-manifest.ts +10 -10
  153. package/src/runtime/pixi/authoring.ts +1 -1
  154. package/src/runtime/pixi/ingest.ts +1 -1
  155. package/src/runtime/presentation.ts +1 -1
  156. package/src/runtime/render-control.ts +21 -21
  157. package/src/runtime/render-seed.ts +3 -3
  158. package/src/runtime/run-ticks-settled.ts +1 -1
  159. package/src/services/game-audio.ts +3 -3
  160. package/src/services/game-network.ts +4 -4
  161. package/src/three/authoring/model-asset-inspector-section.css +15 -15
  162. package/src/three/authoring/model-asset-inspector-section.tsx +7 -7
  163. package/src/three/authoring/r3f-design-session.ts +10 -10
  164. package/src/three/authoring/r3f-source-authoring-adapter.ts +5 -5
  165. package/src/three/authoring/three-authoring-adapter.ts +5 -4
  166. package/src/three/authoring/typed-three-inspector.ts +1 -1
  167. package/src/three/story-documents/three-story-documents.tsx +3 -3
  168. package/src/three/three-board/board-scene.ts +9 -9
  169. package/src/three/three-board/three-component-board.ts +1 -1
@@ -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="vgai-content-frost"
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 VGAI_ROOM_MONITOR=1).
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 `vgai play` then starts in seconds).
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
  *
@@ -113,6 +113,7 @@ import {
113
113
  nodeKeyedPhysics,
114
114
  type TransformProvider,
115
115
  } from '@volter/editor-project/adapter';
116
+ import { physicsOwnerOf } from '@volter/editor-project/adapter';
116
117
  import { assertNever } from '@volter/editor-project/adapter/adapter-surface';
117
118
  import { declaredRoots, rootById } from '@volter/editor-project/adapter/manifest-interpreter';
118
119
  import { readOidSourceAnchors } from '../three/authoring/oid-source-persistence';
@@ -151,7 +152,7 @@ export interface PlayModeContext {
151
152
  *
152
153
  * ITS IDENTITY IS THE MOUNT ID, and there is only ever one id for it.
153
154
  * `resolveAllRootEntries` opens a mount epoch; every project module of this
154
- * instance is served under it as `?vgai-mount=<id>`; browser module identity
155
+ * instance is served under it as `?volter-mount=<id>`; browser module identity
155
156
  * is per-url, so that id IS the module-graph boundary; and `gated-globals.ts`
156
157
  * resolves this instance's realm and input gate by reading the same id back
157
158
  * off the url. Registering it under any second name would be two identities
@@ -164,7 +165,7 @@ export interface PlayModeContext {
164
165
  * interleaved log streams and read, later, as a game bug.
165
166
  */
166
167
  interface PlayInstance {
167
- /** The mount id — see above. What `?vgai-mount=` carries, what the realm and
168
+ /** The mount id — see above. What `?volter-mount=` carries, what the realm and
168
169
  * input gate are keyed by, what `setActiveSystems` registers under and what
169
170
  * the session wire addresses. Empty until a composition has resolved. */
170
171
  /** The element this instance mounted into (the primary's is the live
@@ -364,8 +365,8 @@ export function markRestartRequired(reason: string): void {
364
365
  *
365
366
  * They are kept because the unresolved-console ledger names conditions BY
366
367
  * THEIR TEXT, and a remount is the event that resolves them: measured
367
- * 2026-08-29, `vgai restart` reported "↻ Restarted — session ready" while its
368
- * own named warning stayed in `vgai console` forever, because the ledger's
368
+ * 2026-08-29, `volter-game-editor restart` reported "↻ Restarted — session ready" while its
369
+ * own named warning stayed in `volter-game-editor console` forever, because the ledger's
369
370
  * automatic clearing rule is a PAGE LOAD and a remount is not one — only
370
371
  * `game.reloadPage()` could silence a warning the named verb had already
371
372
  * fixed. `clearRestartRequired` now reports them resolved (ledger clearing
@@ -427,7 +428,7 @@ let _playEpoch = 0;
427
428
  //
428
429
  // PD-1: this used to be nulled by `exitPlayMode()`, which meant the errors of
429
430
  // a run that FAILED became invisible the instant the failed run rolled back —
430
- // `vgai status` reported `pageErrors: []` for a play that had just thrown, the
431
+ // `volter-game-editor status` reported `pageErrors: []` for a play that had just thrown, the
431
432
  // exact "every diagnostic says healthy" symptom. The fence's job is to exclude
432
433
  // a PREVIOUS run's noise, and the next `enterPlayMode` re-stamping it does
433
434
  // that; dropping it on exit only ever hid the evidence of the last run.
@@ -437,7 +438,7 @@ let _playStartedAtMs: number | null = null;
437
438
  //
438
439
  // Why an end and not just a start: with an open-ended window every editor error
439
440
  // logged AFTER a run stopped still counted as "during the play run", so it fell
440
- // into the play-fenced `consoleErrors` facet — which `vgai status` renders only
441
+ // into the play-fenced `consoleErrors` facet — which `volter-game-editor status` renders only
441
442
  // while play is live. One play run, and every later editor-frame error went
442
443
  // invisible again, which is the exact defect the session-lifetime facets exist
443
444
  // to close. Stamped at the END of `exitPlayMode`, so a FAILED run's errors (all
@@ -795,14 +796,14 @@ async function installPlayRootAuthoring(
795
796
  store.shell.notifyIngestEdit();
796
797
 
797
798
  // Dev/e2e diagnostic handle — the SAME pattern `ingest/mount-ingest-root.ts`'s
798
- // `window.__vgaiIngest`/`window.__vgaiIngest2D` use:
799
+ // `window.__volterIngest`/`window.__volterIngest2D` use:
799
800
  // `store.saveNow()` (Ctrl/Cmd+S) and `_autoSave()` are both structurally
800
801
  // guarded OFF while ANY authoring override is active (`hasAuthoringOverride()`
801
802
  // / the play-state check) — the adapter's OWN `persistence.save()` is the
802
803
  // only way an override session's edits reach disk, so tests/tooling need a
803
804
  // handle to call it directly, exactly as the ingest sessions expose.
804
805
  if (import.meta.env.DEV) {
805
- (window as unknown as Record<string, unknown>)['__vgaiMultiRoot'] = {
806
+ (window as unknown as Record<string, unknown>)['__volterMultiRoot'] = {
806
807
  adapter: composite,
807
808
  worldIds: children.map((c) => c.worldId),
808
809
  store,
@@ -838,7 +839,7 @@ function exitPlayRootAuthoring(store: EditorShellStore): void {
838
839
  _instance.journalSession = '';
839
840
  }
840
841
  if (import.meta.env.DEV) {
841
- delete (window as unknown as Record<string, unknown>)['__vgaiMultiRoot'];
842
+ delete (window as unknown as Record<string, unknown>)['__volterMultiRoot'];
842
843
  }
843
844
  }
844
845
  /**
@@ -923,7 +924,7 @@ if (import.meta.hot) import.meta.hot.dispose(stopAssetReload);
923
924
 
924
925
  // --- Script HMR ---
925
926
  if (import.meta.hot) {
926
- import.meta.hot.on('vgai:restart-required', (data: { file: string }) => {
927
+ import.meta.hot.on('volter:restart-required', (data: { file: string }) => {
927
928
  if (!_instance.session) return;
928
929
  const file = data.file.split('/').pop() ?? data.file;
929
930
  markRestartRequired(`${file} changed and cannot be applied safely while the game is running.`);
@@ -937,12 +938,12 @@ if (import.meta.hot) {
937
938
  // PlayBar's Restart button lights up (variant 'primary') carrying this
938
939
  // reason, and ONE click remounts every root from fresh source and
939
940
  // re-enters play (`enterPlayMode` re-imports the entry with a
940
- // cache-busting query — see `loadProjectScripts`). `vgai status` reports
941
+ // cache-busting query — see `loadProjectScripts`). `volter-game-editor status` reports
941
942
  // the same pending-restart state via `collectState().restartRequired`, so
942
943
  // agents get the signal humans get. EDIT-mode behavior is unchanged
943
944
  // (`_instance.session` is null there; absorb-by-remount stays as landed — see
944
945
  // r3f-design-session.ts).
945
- import.meta.hot.on('vgai:r3f-entry-update', (data: { file: string }) => {
946
+ import.meta.hot.on('volter:r3f-entry-update', (data: { file: string }) => {
946
947
  if (!_instance.session) return;
947
948
  const file = data.file.split('/').pop() ?? data.file;
948
949
  markRestartRequired(
@@ -950,7 +951,7 @@ if (import.meta.hot) {
950
951
  );
951
952
  warnRestartRequired(`Restart required: ${file} changed while playing.`);
952
953
  });
953
- import.meta.hot.on('vgai:script-update', async (data: { file: string }) => {
954
+ import.meta.hot.on('volter:script-update', async (data: { file: string }) => {
954
955
  // Project-tool source belongs to editor chrome. The tool contribution
955
956
  // store re-imports and remounts it; no game root can become stale from an
956
957
  // editor-only document changing.
@@ -1010,7 +1011,7 @@ export function bindPlayMode(store: EditorShellStore): void {
1010
1011
  _ctx = { store, gameContainer: null! }; // set dynamically from the live document's container
1011
1012
  // THE BARE-KEY YIELD IS THE FRAME'S. While Play runs the game's keys are the
1012
1013
  // game's, and what decides is the workbench: our stage actions carry a
1013
- // `when` clause over `vgai.stage.focused`/`vgai.play`, so a bare key reaches
1014
+ // `when` clause over `volter.stage.focused`/`volter.play`, so a bare key reaches
1014
1015
  // the game rather than a shell binding, and a ⌘-chord stays the workbench's.
1015
1016
  // The realm gate tracks the same predicate independently (`gated-globals.ts`
1016
1017
  // and `surface-keyboard.ts`), which is what keeps a game's raw
@@ -1031,7 +1032,7 @@ export function isPlayModeActive(): boolean {
1031
1032
  * Narrow relay accessor — the live play session's virtual input targets
1032
1033
  * and the Game root's loop, for `command-listener.ts`'s
1033
1034
  * `inject-input`/`set-time-scale`/`set-seed` cases. This is exactly the
1034
- * accessor the vgai-sdk honest-gap jsdocs prescribed
1035
+ * accessor the volter-sdk honest-gap jsdocs prescribed
1035
1036
  * (`play/input-operations.ts`, `play/control-operations.ts`): `_instance.session` is
1036
1037
  * module-private, so the relay needs this one exported read. Everything else
1037
1038
  * the relay reads (state providers, debug commands) flows through
@@ -1040,7 +1041,7 @@ export function isPlayModeActive(): boolean {
1040
1041
  * `getInputTarget(worldId?)` (D15/T-D15.5 — review objection 2's fix)
1041
1042
  * is one resolution for every input door: both the SAME `getDebugRegistry(game).getVirtualInputTarget(worldId)`
1042
1043
  * — one resolution function (`debug-registry.ts`'s `resolveInputRootId`),
1043
- * so `inject-input` (this accessor) and `window.__vgai.input.*`
1044
+ * so `inject-input` (this accessor) and `window.__volter.input.*`
1044
1045
  * (`debug-bridge.ts`) can never disagree about which world an unqualified
1045
1046
  * actuation targets again. `null` when nothing is registered for the
1046
1047
  * resolved id (or no `Game` is running at all); throws the registry's own
@@ -1048,7 +1049,7 @@ export function isPlayModeActive(): boolean {
1048
1049
  *
1049
1050
  * `runTicks` (D15/T-D15.4) is added the SAME way: reached via
1050
1051
  * `getDebugRegistry(game).getRunTicksTarget()` — the identical accessor
1051
- * `runtime/debug-bridge.ts`'s `window.__vgai.runTicks` (door a) goes
1052
+ * `runtime/debug-bridge.ts`'s `window.__volter.runTicks` (door a) goes
1052
1053
  * through, so the editor relay's `run-ticks` case (door b, → `play.runTicks`)
1053
1054
  * calls byte-identical behavior (D17). `null` only when no `Game` is running
1054
1055
  * at all (`_instance.session` is `null`) — a live `Game` always wires a run-ticks
@@ -1285,7 +1286,7 @@ export function resizeGame(width: number, height: number, pixelRatio?: number):
1285
1286
 
1286
1287
  /**
1287
1288
  * Serializes every `enterPlayMode()` invocation (the ghost-runtime bug:
1288
- * `vgai play` on an already-playing/still-booting session left the
1289
+ * `volter-game-editor play` on an already-playing/still-booting session left the
1289
1290
  * PREVIOUS runtime alive, ticking and rendering alongside the new one).
1290
1291
  *
1291
1292
  * Root cause: `enterPlayModeInner`'s own `if (_instance.session) exitPlayMode()`
@@ -1305,7 +1306,7 @@ export function resizeGame(width: number, height: number, pixelRatio?: number):
1305
1306
  * size exceeded` — not a hypothetical). In the field this window is entered
1306
1307
  * whenever a caller re-issues `play` before the browser has acked the first
1307
1308
  * (a slow scene boot outliving the relay's/SDK's own `play.start` timeout is
1308
- * the documented trigger — `packages/vgai-sdk/src/play/transport.ts`'s
1309
+ * the documented trigger — `packages/editor-sdk/src/transport.ts`'s
1309
1310
  * `PLAY_START_TIMEOUT_MS`/`editor-server.ts`'s `PLAY_COMMAND_TIMEOUT_MS` —
1310
1311
  * and `play.start`'s own contract is explicitly "start (or restart)", so a
1311
1312
  * caller retrying after a timeout is using the API as documented, not
@@ -1403,16 +1404,16 @@ async function startAutoLaunchedAdapterPlay(store: EditorShellStore): Promise<bo
1403
1404
  /**
1404
1405
  * Enter play mode: create a game canvas, start game, disable editor controls.
1405
1406
  *
1406
- * `explicitSeed` (D15/T-D15.6, objection-4 fix — `vgai play --seed <n>`)
1407
+ * `explicitSeed` (D15/T-D15.6, objection-4 fix — `volter-game-editor play --seed <n>`)
1407
1408
  * — the CLI's `play` command relays it through as `cmd['seed']`
1408
1409
  * (`command-listener.ts`'s `'play'` case); it is the "explicit config"
1409
1410
  * leg of `resolveDeterminismSeed`'s precedence (highest — beats
1410
- * `manifest.determinism.defaultSeed`/`?vgai-seed=` on the editor's own
1411
+ * `manifest.determinism.defaultSeed`/`?volter-seed=` on the editor's own
1411
1412
  * page URL), threaded into whichever mount path this play resolves to
1412
1413
  * below, exactly like `mountManifestRoots`'s own `opts.seed` already is
1413
1414
  * for a standalone boot.
1414
1415
  *
1415
- * `runName` (optional — `vgai play --name <text>`) is FINDABILITY and nothing
1416
+ * `runName` (optional — `volter-game-editor play --name <text>`) is FINDABILITY and nothing
1416
1417
  * else: the server slugifies it into this run's `logs/play-*.jsonl` filename
1417
1418
  * and its session-journal line, so "the run where I tested the boss fight" is
1418
1419
  * a grep instead of timestamp archaeology. No registry, no uniqueness check —
@@ -1469,7 +1470,7 @@ async function enterPlayModeInner(
1469
1470
  // `enterPlayMode` owns the begin/end pair; this function owns the marks.
1470
1471
  // Play must never start while the boot-time project bootstrap is still in
1471
1472
  // flight. Resolves immediately when no bootstrap is pending; gating HERE
1472
- // rather than in the Play button covers every caller — UI, `vgai play` relay,
1473
+ // rather than in the Play button covers every caller — UI, `volter-game-editor play` relay,
1473
1474
  // SDK.
1474
1475
  markPlayBootPhase('waiting for the project bootstrap to settle');
1475
1476
  await projectBootstrapSettled();
@@ -1712,9 +1713,9 @@ async function enterPlayModeInner(
1712
1713
  entries,
1713
1714
  width: rw,
1714
1715
  height: rh,
1715
- // D15/T-D15.6 — `vgai play --seed`'s explicit config leg; `undefined`
1716
+ // D15/T-D15.6 — `volter-game-editor play --seed`'s explicit config leg; `undefined`
1716
1717
  // (the overwhelmingly common case) leaves `mountManifestRoots`'s own
1717
- // manifest/`?vgai-seed=` precedence untouched.
1718
+ // manifest/`?volter-seed=` precedence untouched.
1718
1719
  seed: explicitSeed,
1719
1720
  playtest,
1720
1721
  });
@@ -1733,7 +1734,7 @@ async function enterPlayModeInner(
1733
1734
  // PD-3 — close the window and report LOUDLY. A split does not stop the
1734
1735
  // game (both copies run; they just disagree), so this is an error-level
1735
1736
  // report rather than a throw: the failure mode being fixed is SILENCE,
1736
- // not a crash. `collectState` carries the same reports to `vgai status`,
1737
+ // not a crash. `collectState` carries the same reports to `volter-game-editor status`,
1737
1738
  // and `editorConsole.error` reaches the editor console panel and the
1738
1739
  // play-log sink the CLI reads back.
1739
1740
  for (const split of endProjectModuleSplitWatch(project.rootPath)) {
@@ -1744,7 +1745,7 @@ async function enterPlayModeInner(
1744
1745
  // mount, and `mountManifestRoots` resolving IS that answer — including the
1745
1746
  // roots' own async setup, which it awaits. So every one of these roots
1746
1747
  // reports `declared`, and no measured wait stands anywhere behind them
1747
- // (`readiness.ts`; published as `vgai status`'s `readiness` facet).
1748
+ // (`readiness.ts`; published as `volter-game-editor status`'s `readiness` facet).
1748
1749
  for (const rootId of _hostMountedReadyRootIds) {
1749
1750
  recordRootReadiness({ rootId, mechanism: 'host-mount', source: 'declared', state: 'ready' });
1750
1751
  }
@@ -1861,7 +1862,7 @@ async function enterPlayModeInner(
1861
1862
  store.setEcsSyncTransform((id, obj) => {
1862
1863
  // `commit` refuses an id this adapter cannot resolve rather than
1863
1864
  // returning as if the write landed — so ask before driving it.
1864
- if (!physics || physics.ownerOf(id) === 'unresolved') return;
1865
+ if (!physics || physicsOwnerOf(physics, id) === 'unresolved') return;
1865
1866
  physics.commit(id, {
1866
1867
  position: obj.position.toArray() as [number, number, number],
1867
1868
  rotation: obj.quaternion.toArray() as [number, number, number, number],
@@ -1928,7 +1929,7 @@ async function enterPlayModeInner(
1928
1929
  * cardinality half of multiplayer authoring (see the `_additional` doc).
1929
1930
  *
1930
1931
  * Valid only while the primary is playing. The returned id is the instance's
1931
- * mount id (what `?vgai-mount=` carries and what `game.instance(id)`
1932
+ * mount id (what `?volter-mount=` carries and what `game.instance(id)`
1932
1933
  * addresses). This does the INSTANCE subset of `enterPlayModeInner` and none
1933
1934
  * of its session/focus work: it resolves its own mount epoch, mounts the roots
1934
1935
  * into `container`, registers a performance source and its System adapters
@@ -2483,7 +2484,7 @@ editorHost().live.register({
2483
2484
  });
2484
2485
 
2485
2486
  // What only Play knows of the state report (`host.session.reportFacet`):
2486
- // `vgai status --json` spreads these beside the host's own fields.
2487
+ // `volter-game-editor status --json` spreads these beside the host's own fields.
2487
2488
  editorHost().session.reportFacet(() => ({
2488
2489
  // The live loop's time-scale, so `play.status` reports the real applied
2489
2490
  // value after a `set-time-scale` instead of an honest-gap null.
@@ -2,15 +2,15 @@
2
2
  * EVERY RELAYED PLAY RECORDS, AND AN IDLE RUN STOPS ITSELF.
3
3
  *
4
4
  * The defect this closes is not a missing feature — the recorder
5
- * (`gameplay-recording.ts`) already existed, behind `vgai eval
5
+ * (`gameplay-recording.ts`) already existed, behind `volter-game-editor eval
6
6
  * 'editor.recording.start()'`. The defect is that verifying a game through a
7
7
  * single screenshot answers a temporal question by luck, and a capability an
8
8
  * agent has to remember to switch on is one it does not use. So there is no
9
- * flag: `vgai play` starts a recording, full stop, and the evidence exists
9
+ * flag: `volter-game-editor play` starts a recording, full stop, and the evidence exists
10
10
  * whether or not anyone thought to ask for it.
11
11
  *
12
12
  * WHY THE RELAYED PLAY AND NOT THE PLAY BUTTON. The binding is in
13
- * `play.command.ts`'s `'play'` handler, so it covers `vgai play`, the SDK's
13
+ * `play.command.ts`'s `'play'` handler, so it covers `volter-game-editor play`, the SDK's
14
14
  * `play.start`, and nothing else. Clicking Play in the editor is a HUMAN at
15
15
  * the surface: they are the witness, the idle rule below ("no session
16
16
  * commands and no player input") is meaningless for them, and auto-stopping
@@ -21,11 +21,11 @@
21
21
  * script threw — leaves a growing file that nobody can open. The idle window
22
22
  * is what converts an abandoned run into finished evidence.
23
23
  *
24
- * WHAT RECORDING DOES *NOT* DO: gate the still (2026-08-29). `vgai screenshot`
24
+ * WHAT RECORDING DOES *NOT* DO: gate the still (2026-08-29). `volter-game-editor screenshot`
25
25
  * used to REFUSE while a recording was live, on the argument that a single
26
26
  * frame answers a temporal question by luck. The argument is right and the
27
- * refusal was still the defect: because play always records, one `vgai play`
28
- * killed `vgai screenshot` for the rest of the session — and "what does it
27
+ * refusal was still the defect: because play always records, one `volter-game-editor play`
28
+ * killed `volter-game-editor screenshot` for the rest of the session — and "what does it
29
29
  * look like" is a question a still answers exactly, and the one the whole
30
30
  * look/modeling lane asks (measured, cold fox #3: the loop is play → look).
31
31
  * Discouraging a wrong question by making a right one impossible is not a
@@ -56,7 +56,7 @@ import type { AudioRecordingHandle } from '@volter/editor-project/adapter';
56
56
  *
57
57
  * ONE constant, editor-side, and deliberately generous: the thing it must
58
58
  * never do is cut a run that someone is still working with. Two minutes is
59
- * longer than any gap between an agent's own commands (`vgai eval` round
59
+ * longer than any gap between an agent's own commands (`volter-game-editor eval` round
60
60
  * trips are seconds) and longer than a human's pause at the keyboard, while
61
61
  * still being short enough that an abandoned run becomes a readable file
62
62
  * inside the same working session rather than the next day.
@@ -100,7 +100,7 @@ let live: LivePlayRecording | null = null;
100
100
  * The recorder's own "already active" guard is released at the END of
101
101
  * `stopGameplayRecording` (it awaits the in-flight frame, the recorder's stop
102
102
  * event, and the chunk uploads). `live` is cleared at the START. So a restart —
103
- * `vgai play` over a running play, which tears down through `exitPlayMode`'s
103
+ * `volter-game-editor play` over a running play, which tears down through `exitPlayMode`'s
104
104
  * fire-and-forget teardown and then starts the next recording — would look
105
105
  * finished to this module while the recorder was still busy, and the next start
106
106
  * would refuse. This handle is what a start waits on; without it the second
@@ -169,7 +169,7 @@ export function lastPlayRecording(): GameplayRecordingCapture | null {
169
169
  * Two callers, and the pair is the whole definition of "idle": every relayed
170
170
  * session command (`host.session.onCommandDispatched`, subscribed below) and
171
171
  * every player input event (the listeners installed below). A run is idle only
172
- * when BOTH have gone quiet — an agent driving through `vgai eval` and a human
172
+ * when BOTH have gone quiet — an agent driving through `volter-game-editor eval` and a human
173
173
  * holding a movement key are each, alone, enough to keep it alive.
174
174
  */
175
175
  export function notePlayActivity(): void {
@@ -194,7 +194,7 @@ function installInputListeners(): () => void {
194
194
  *
195
195
  * Never throws: a browser that cannot record must not be a browser that cannot
196
196
  * PLAY. The failure is reported to the editor console (which is what
197
- * `vgai console` and every command's trailing console summary read) and play
197
+ * `volter-game-editor console` and every command's trailing console summary read) and play
198
198
  * continues with no clip, rather than an ack that refuses a working game
199
199
  * because its evidence path is unavailable.
200
200
  */
@@ -291,7 +291,7 @@ export async function endPlayRecording(
291
291
  return stop;
292
292
  }
293
293
 
294
- /** One sentence, used by both the auto-stop note and the `vgai screenshot`
294
+ /** One sentence, used by both the auto-stop note and the `volter-game-editor screenshot`
295
295
  * refusal, so the two doors cannot describe the same clip differently. */
296
296
  export function describeCapture(capture: GameplayRecordingCapture): string {
297
297
  const seconds = Math.round(capture.durationMs / 100) / 10;
@@ -329,7 +329,7 @@ async function autoStopIdlePlay(): Promise<void> {
329
329
 
330
330
  // HALF OF "IS THIS RUN IDLE" — the other half is player input, watched
331
331
  // above. Every relayed command counts: an agent that is still driving a game
332
- // through `vgai eval` is not idle, whatever the command was, and a stamp
332
+ // through `volter-game-editor eval` is not idle, whatever the command was, and a stamp
333
333
  // filed per verb would quietly exclude whichever verb someone forgot.
334
334
  // No-op unless a recording is live.
335
335
  editorHost().session.onCommandDispatched(() => notePlayActivity());
@@ -67,7 +67,7 @@ function SaveRegimeIndicator({ regime }: { regime: 'ephemeral' | null }) {
67
67
  <span
68
68
  role="img"
69
69
  aria-label={label}
70
- className="vgai-play-edit-regime"
70
+ className="volter-play-edit-regime"
71
71
  data-testid="play-edit-regime"
72
72
  data-regime={regime}
73
73
  title={label}
@@ -141,7 +141,7 @@ export function PlayBarView({
141
141
  <Inline
142
142
  role="toolbar"
143
143
  aria-label="Game transport"
144
- className="vgai-playbar"
144
+ className="volter-playbar"
145
145
  gap={2}
146
146
  align="center"
147
147
  >
@@ -231,7 +231,7 @@ export function PlayBar({ placement = 'launcher' }: { placement?: 'launcher' | '
231
231
  <Inline
232
232
  role="toolbar"
233
233
  aria-label="Game transport"
234
- className="vgai-playbar"
234
+ className="volter-playbar"
235
235
  gap={2}
236
236
  align="center"
237
237
  >
@@ -336,7 +336,7 @@ function PlayOptions() {
336
336
  const { settings } = editorHost();
337
337
  const keepPanelsVisible = useSyncExternalStore(
338
338
  settings.subscribe,
339
- () => settings.get('vgai.play.keepPanelsVisible') === true,
339
+ () => settings.get('volter.play.keepPanelsVisible') === true,
340
340
  );
341
341
  const [open, setOpen] = useState(false);
342
342
  const anchor = useRef<HTMLButtonElement>(null);
@@ -358,7 +358,7 @@ function PlayOptions() {
358
358
  role="menuitemcheckbox"
359
359
  aria-checked={keepPanelsVisible}
360
360
  onSelect={() => {
361
- settings.set('vgai.play.keepPanelsVisible', !keepPanelsVisible);
361
+ settings.set('volter.play.keepPanelsVisible', !keepPanelsVisible);
362
362
  setOpen(false);
363
363
  }}
364
364
  >
@@ -420,14 +420,14 @@ function RunPicker({ run, disabled }: { readonly run: RunState; readonly disable
420
420
  const selected = run.configurations.find((c) => c.id === run.selectedId);
421
421
  const label = selected?.id === PLAY_ID ? 'Play' : (selected?.id ?? 'Play');
422
422
  return (
423
- <div className="vgai-playbar-popover-anchor">
423
+ <div className="volter-playbar-popover-anchor">
424
424
  <Button
425
425
  ref={ref}
426
426
  variant="ghost"
427
427
  size="compact"
428
428
  aria-haspopup="menu"
429
429
  aria-expanded={open}
430
- aria-controls={open ? 'vgai-run-configuration-menu' : undefined}
430
+ aria-controls={open ? 'volter-run-configuration-menu' : undefined}
431
431
  data-testid="run-configuration-picker"
432
432
  disabled={disabled}
433
433
  onClick={() => setOpen((value) => !value)}
@@ -438,7 +438,7 @@ function RunPicker({ run, disabled }: { readonly run: RunState; readonly disable
438
438
  </Button>
439
439
  {open && (
440
440
  <AnchoredMenu
441
- id="vgai-run-configuration-menu"
441
+ id="volter-run-configuration-menu"
442
442
  anchorRef={ref}
443
443
  align="start"
444
444
  gap={4}
@@ -55,14 +55,14 @@ export function InstanceCountPicker() {
55
55
 
56
56
  const count = playerCountFromExtras(extra);
57
57
  return (
58
- <div className="vgai-playbar-popover-anchor">
58
+ <div className="volter-playbar-popover-anchor">
59
59
  <Button
60
60
  ref={ref}
61
61
  variant="ghost"
62
62
  size="comfortable"
63
63
  aria-haspopup="menu"
64
64
  aria-expanded={open}
65
- aria-controls={open ? 'vgai-player-count-menu' : undefined}
65
+ aria-controls={open ? 'volter-player-count-menu' : undefined}
66
66
  onClick={() => setOpen((value) => !value)}
67
67
  title={`${instanceLabel(count)} — choose how many runtimes Play mounts side by side`}
68
68
  >
@@ -73,7 +73,7 @@ export function InstanceCountPicker() {
73
73
  </Button>
74
74
  {open && (
75
75
  <AnchoredMenu
76
- id="vgai-player-count-menu"
76
+ id="volter-player-count-menu"
77
77
  anchorRef={ref}
78
78
  gap={4}
79
79
  onDismiss={() => setOpen(false)}
@@ -69,7 +69,7 @@ function DrawRow({
69
69
  data-testid="frame-draw-row"
70
70
  data-draw-index={draw.index}
71
71
  data-selected={selected || undefined}
72
- className="vgai-frame-draw-row"
72
+ className="volter-frame-draw-row"
73
73
  onClick={onSelect}
74
74
  >
75
75
  <span style={{ ...MONO, color: themeVars.content.dim, width: 34, display: 'inline-block' }}>
@@ -381,7 +381,7 @@ export function FrameDebuggerPanel() {
381
381
  data-testid="frame-debugger"
382
382
  // §2.31 P2 amendment: text-dense output region reads over a local
383
383
  // frosted layer (inert for non-frost themes).
384
- className="vgai-content-frost"
384
+ className="volter-content-frost"
385
385
  style={{ flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column', fontSize: 12 }}
386
386
  >
387
387
  {/* Header: capture control + honest scope statement + history strip */}
@@ -68,7 +68,7 @@ function downloadCapture(profiler: PerformanceProfiler): void {
68
68
  const url = URL.createObjectURL(new Blob([profiler.exportJSON()], { type: 'application/json' }));
69
69
  const anchor = document.createElement('a');
70
70
  anchor.href = url;
71
- anchor.download = `vgai-performance-${new Date().toISOString().replaceAll(':', '-')}.json`;
71
+ anchor.download = `volter-performance-${new Date().toISOString().replaceAll(':', '-')}.json`;
72
72
  anchor.click();
73
73
  URL.revokeObjectURL(url);
74
74
  }
@@ -84,7 +84,7 @@ function downloadTrace(profiler: PerformanceProfiler, processName: string): void
84
84
  const url = URL.createObjectURL(new Blob([JSON.stringify(trace)], { type: 'application/json' }));
85
85
  const anchor = document.createElement('a');
86
86
  anchor.href = url;
87
- anchor.download = `vgai-trace-${new Date().toISOString().replaceAll(':', '-')}.json`;
87
+ anchor.download = `volter-trace-${new Date().toISOString().replaceAll(':', '-')}.json`;
88
88
  anchor.click();
89
89
  URL.revokeObjectURL(url);
90
90
  }
@@ -874,7 +874,7 @@ export function PerformancePanel() {
874
874
 
875
875
  return (
876
876
  <div
877
- className="vgai-content-frost"
877
+ className="volter-content-frost"
878
878
  style={{
879
879
  height: '100%',
880
880
  overflow: 'auto',
@@ -937,7 +937,7 @@ export function PerformancePanel() {
937
937
  <Button
938
938
  size="compact"
939
939
  data-testid="profiler-export-trace"
940
- onClick={() => downloadTrace(profiler, source?.label ?? 'vgai')}
940
+ onClick={() => downloadTrace(profiler, source?.label ?? 'volter')}
941
941
  >
942
942
  Export Chrome trace
943
943
  </Button>
@@ -146,7 +146,7 @@ async function seedRootViewportFromManifest(): Promise<void> {
146
146
  const current = getRootCanvasViewport();
147
147
  if (current.width !== null || current.height !== null) return;
148
148
  try {
149
- const text = await readProjectTextFile('vgai.project.json');
149
+ const text = await readProjectTextFile('volter.project.json');
150
150
  if (!text) return;
151
151
  const manifest = JSON.parse(text) as {
152
152
  resolution?: { width?: unknown; height?: unknown };
@@ -282,7 +282,7 @@ export async function mountReactDesignLayer(
282
282
  // The join is by component NAME, not function identity, and that is
283
283
  // measured rather than assumed: a story module is imported at its own
284
284
  // `/@fs/<path>?t=<now>` url (`story-discovery.ts`) while a root entry is
285
- // imported at the mount epoch's `?vgai-mount=<n>` url
285
+ // imported at the mount epoch's `?volter-mount=<n>` url
286
286
  // (`project-module-url.ts`), and browser ES-module identity is per-url — so
287
287
  // the component object a story's meta holds is never the object the entry
288
288
  // loader returns. `pickComponentPreviewStory` (`story-registry.ts`) is the
@@ -328,7 +328,7 @@ export async function mountReactDesignLayer(
328
328
  // names an action that cannot be taken. Opening on the first story is that
329
329
  // board's documented behaviour, not a degraded one. Measured on the
330
330
  // repo-vendored `racing-game` ingest, whose manifest declares one ingest
331
- // root and no dom root: a permanent unresolvable warning on every `vgai`
331
+ // root and no dom root: a permanent unresolvable warning on every `volter`
332
332
  // command, for a board that was working exactly as designed.
333
333
  if (candidate.path && !defaultPortableStory) {
334
334
  editorConsole.warn(
@@ -512,8 +512,8 @@ export async function mountReactDesignLayer(
512
512
  designTokens: () => {
513
513
  const content = board.activeContent();
514
514
  const scopeElement =
515
- content.closest?.('[data-vgai-game-styles]') ??
516
- content.querySelector?.('[data-vgai-game-styles]') ??
515
+ content.closest?.('[data-volter-game-styles]') ??
516
+ content.querySelector?.('[data-volter-game-styles]') ??
517
517
  content;
518
518
  return getDesignTokens(
519
519
  getComputedStyle(scopeElement) as unknown as Parameters<typeof getDesignTokens>[0],
@@ -24,7 +24,7 @@
24
24
  * DIRECTLY and record the same write into an in-memory
25
25
  * {@link DomStyleEdits} document that is never saved anywhere. (Until
26
26
  * 2026-08-02 that document was flushed to a per-world JSON sidecar under
27
- * the project's `.vgai/`; the owner deleted that system outright — no
27
+ * the project's `.volter/`; the owner deleted that system outright — no
28
28
  * compat read, no replacement.) There is NO `SourceWriteBackend` import
29
29
  * anywhere in this file and NO `/__ui-source` traffic of any kind, ever —
30
30
  * this is the one hard invariant the design doc's §4 NOTs pin (AC-K7).
@@ -328,8 +328,8 @@ export class DomAuthoringAdapter implements AuthoringAdapter {
328
328
  * root: a fresh snapshot every call (same "the DOM is live and may
329
329
  * re-render, never cached" discipline as
330
330
  * `hierarchy.roots()`/`hierarchy.node()` above), not a count taken once at
331
- * construction. Backs `__vgaiIngestReact.domEvidence().hierarchyNodeCount`
332
- * — one of the four legs `vgai doctor`'s react-ingest MOUNTED bar requires
331
+ * construction. Backs `__volterIngestReact.domEvidence().hierarchyNodeCount`
332
+ * — one of the four legs the react-ingest MOUNTED bar requires
333
333
  * (`clearsReactIngestMountedBar`, `packages/editor/src/doctor/report.ts`).
334
334
  */
335
335
  nodeCount(): number {
@@ -415,7 +415,7 @@ function GradientRow({ prop, raw, disabled, testId, commit }: KindRowProps): Rea
415
415
  <Button
416
416
  type="button"
417
417
  variant="secondary"
418
- className="vgai-field-trigger"
418
+ className="volter-field-trigger"
419
419
  data-testid={testId}
420
420
  disabled={disabled}
421
421
  onClick={() => commit(prop.path, composeGradient(DEFAULT_GRADIENT))}
@@ -601,7 +601,7 @@ function CheckboxRow({ prop, raw, disabled, testId, commit }: KindRowProps): Rea
601
601
  }}
602
602
  >
603
603
  <Checkbox
604
- className="vgai-checkbox"
604
+ className="volter-checkbox"
605
605
  data-testid={testId}
606
606
  checked={raw !== false}
607
607
  disabled={disabled}