@volter/editor-game 0.5.65 → 0.5.66

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 (141) hide show
  1. package/contributions/generation.service.ts +2 -2
  2. package/contributions/generations.status.tsx +1 -1
  3. package/contributions/godot.palette.json +99 -0
  4. package/contributions/godot.style.ts +62 -0
  5. package/contributions/godot.view.ts +69 -0
  6. package/contributions/ingest.service.ts +3 -3
  7. package/contributions/play.command.ts +1 -1
  8. package/contributions/react/react-inspector.service.ts +2 -2
  9. package/contributions/scene-document.service.ts +3 -3
  10. package/contributions/three/component-verbs.command.ts +3 -3
  11. package/contributions/unity.palette.json +102 -0
  12. package/contributions/unity.style.ts +62 -0
  13. package/contributions/unity.view.ts +76 -0
  14. package/contributions/unreal.palette.json +105 -0
  15. package/contributions/unreal.style.ts +58 -0
  16. package/contributions/unreal.view.ts +88 -0
  17. package/dist-node/serving.mjs +16 -0
  18. package/package.json +21 -14
  19. package/serving/index.ts +27 -0
  20. package/src/asset-budget/asset-budget-model.ts +3 -3
  21. package/src/asset-budget/optimize-apply.ts +7 -7
  22. package/src/bridge/dispatch.ts +2 -2
  23. package/src/bridge/screenshot.ts +3 -3
  24. package/src/coverage/live-authoring-surface.ts +1 -1
  25. package/src/coverage/live-project-verbs.ts +1 -1
  26. package/src/coverage/native-system-coverage.ts +1 -1
  27. package/src/coverage/session-coverage.ts +2 -2
  28. package/src/design-system-stories/InspectorNarrowBodies.stories.tsx +10 -50
  29. package/src/game-document/GameCaptureFrameButton.tsx +1 -1
  30. package/src/game-document/GamePanel.tsx +4 -4
  31. package/src/generation/GenerationActivity.tsx +3 -5
  32. package/src/generation/generation-documents.tsx +3 -3
  33. package/src/generation/generation-jobs.ts +1 -1
  34. package/src/generation/generation-presentation.ts +1 -1
  35. package/src/host/adapter-reach.ts +1 -1
  36. package/src/host/adapter-runtime-bindings.ts +1 -1
  37. package/src/host/api/configurations.ts +2 -2
  38. package/src/host/authoring/babylon-authoring-adapter.ts +2 -2
  39. package/src/host/authoring/contract-hierarchy-authoring.ts +1 -1
  40. package/src/host/authoring/contract-scenes-stories.ts +1 -1
  41. package/src/host/authoring/creation-site-related.ts +2 -2
  42. package/src/host/authoring/ephemeral-persistence.ts +1 -1
  43. package/src/host/authoring/gesture-persist.ts +1 -1
  44. package/src/host/authoring/ingest-source-persistence.ts +4 -4
  45. package/src/host/authoring/mount-isolated-pixi-screen.ts +1 -1
  46. package/src/host/authoring/pixi-authoring-adapter.ts +2 -2
  47. package/src/host/authoring/pixi-live-write-target.ts +3 -3
  48. package/src/host/authoring/pixi-still-presentation.ts +1 -1
  49. package/src/host/authoring/pixi-structure-history.ts +1 -1
  50. package/src/host/authoring/source-persistence-backend.ts +3 -3
  51. package/src/host/authoring/struct-write-pipe.ts +2 -2
  52. package/src/host/browser-transpile.ts +1 -1
  53. package/src/host/canvas-entry-runtime.ts +1 -1
  54. package/src/host/components/HeaderTelemetry.tsx +5 -12
  55. package/src/host/components/PixiIsolationSceneContent.tsx +8 -7
  56. package/src/host/components/ThreeIsolationSceneContent.tsx +2 -2
  57. package/src/host/components/scene-document.tsx +15 -47
  58. package/src/host/components/world-root-stage-binding.tsx +6 -15
  59. package/src/host/components/world-root-stage.ts +60 -14
  60. package/src/host/coverage/capability-coverage.ts +13 -1
  61. package/src/host/coverage/game-contract-seam-evidence.ts +1 -1
  62. package/src/host/coverage/project-verb-coverage.ts +2 -17
  63. package/src/host/coverage/system-adapter-coverage.ts +1 -1
  64. package/src/host/design-system-stories/fixtures/editor-runtime.tsx +9 -1
  65. package/src/host/document-preview-three.ts +1 -1
  66. package/src/host/game-module-access.ts +1 -1
  67. package/src/host/game-realm-page.ts +15 -7
  68. package/src/host/game-realm-reclaim.ts +1 -1
  69. package/src/host/gated-globals.ts +4 -4
  70. package/src/host/history/json-history-resource.ts +2 -2
  71. package/src/host/instance-extract-actions.ts +1 -1
  72. package/src/host/instance-fork-actions.ts +1 -1
  73. package/src/host/projection/dom.ts +2 -2
  74. package/src/host/projection/pixi.ts +1 -1
  75. package/src/host/r3f-entry-runtime.ts +1 -1
  76. package/src/host/react-mount-runtime.ts +1 -1
  77. package/src/host/realm-services.ts +1 -1
  78. package/src/host/roots/module-root.ts +1 -1
  79. package/src/host/scene-view-drawability.ts +2 -2
  80. package/src/host/server-log-bridge.ts +1 -1
  81. package/src/host/three-ingest-runtime.ts +1 -1
  82. package/src/host/use-active-performance-source.ts +1 -1
  83. package/src/ingest/active-ingest.ts +1 -1
  84. package/src/ingest/authoring/ingest-root-adapter.ts +5 -5
  85. package/src/ingest/capture-wait-report.ts +1 -1
  86. package/src/ingest/deferred-ingest-play.ts +5 -4
  87. package/src/ingest/ingest-boot-viewport.ts +4 -6
  88. package/src/ingest/ingest-canvas-scene-document.tsx +9 -8
  89. package/src/ingest/ingest-canvas-scene.ts +2 -5
  90. package/src/ingest/ingest-play-control.ts +3 -3
  91. package/src/ingest/ingest-render-debug.ts +1 -1
  92. package/src/ingest/ingest-siblings.ts +3 -3
  93. package/src/ingest/module-mode.ts +4 -5
  94. package/src/ingest/mount-canvas-ingest-root.ts +6 -6
  95. package/src/ingest/mount-coverage.ts +2 -2
  96. package/src/ingest/mount-dom-ingest-root.ts +5 -5
  97. package/src/ingest/mount-ingest-root.ts +7 -7
  98. package/src/ingest/mount-three-ingest-root.ts +4 -4
  99. package/src/ingest/unmount-ingest-root.ts +2 -2
  100. package/src/play/play-mode.ts +30 -16
  101. package/src/play/play-recording.ts +1 -1
  102. package/src/profiler/PerformancePanel.tsx +1 -1
  103. package/src/react/design-time-react-mount.ts +17 -23
  104. package/src/react/dom-authoring-adapter.ts +2 -2
  105. package/src/react/react-inspector-section.tsx +8 -8
  106. package/src/react/react-world-authoring-adapter.ts +20 -132
  107. package/src/react/story-documents/story-documents.tsx +9 -13
  108. package/src/react/ui-board-document.tsx +3 -4
  109. package/src/react/ui-component-board.ts +3 -3
  110. package/src/three/authoring/camera-runtime-inspector-section.tsx +1 -1
  111. package/src/three/authoring/constraint-inspector-section.tsx +3 -3
  112. package/src/three/authoring/model-asset-inspector-section.tsx +7 -11
  113. package/src/three/authoring/oid-source-persistence.ts +6 -6
  114. package/src/three/authoring/r3f-design-session.ts +21 -7
  115. package/src/three/authoring/r3f-source-authoring-adapter.ts +17 -17
  116. package/src/three/authoring/reflection-probe-inspector-section.tsx +3 -3
  117. package/src/three/authoring/spatial-joint-handles.ts +1 -1
  118. package/src/three/authoring/spatial-lod-handles.ts +1 -1
  119. package/src/three/authoring/spatial-particle-handles.ts +1 -1
  120. package/src/three/authoring/three-authoring-adapter.ts +4 -4
  121. package/src/three/component-verbs/extract-menu.ts +1 -1
  122. package/src/three/component-verbs/fork-menu.ts +1 -1
  123. package/src/three/component-verbs/internals-menu.ts +1 -1
  124. package/src/three/drei-asset-caches.ts +13 -0
  125. package/src/three/story-documents/three-story-documents.tsx +11 -21
  126. package/src/three/three-board/ThreeBoardDocument.tsx +12 -13
  127. package/src/three/three-board/board-scene.ts +1 -1
  128. package/src/three/three-board/three-component-board.ts +3 -3
  129. package/contributions/react/pasteboard.action.ts +0 -41
  130. package/contributions/xstate-behavior.action.ts +0 -42
  131. package/contributions/xstate-behavior.document.tsx +0 -73
  132. package/contributions/xstate-behavior.inspector.tsx +0 -28
  133. package/contributions/xstate-behavior.menu.ts +0 -23
  134. package/src/react/pasteboard-materialize.ts +0 -154
  135. package/src/xstate/XStateBehaviorSection.tsx +0 -130
  136. package/src/xstate/XStateMachineInspector.tsx +0 -566
  137. package/src/xstate/character-animation-machine.fixture.ts +0 -74
  138. package/src/xstate/live-behaviors.ts +0 -106
  139. package/src/xstate/use-live-actor-state.ts +0 -44
  140. package/src/xstate/xstate-graph.ts +0 -235
  141. package/src/xstate/xstate-layout.ts +0 -76
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * `Overlays` is the world-root half of vgai's `stage-overlay-set.tsx` — every
7
7
  * part it rendered only when `worldRoot` held (the root selection layer, the
8
- * camera-authoring pin, the controls hint while the world mounts, the scene's
8
+ * camera-authoring pin, the scene's
9
9
  * surface-state card). The rest of that overlay set is the kit's
10
10
  * `StageOverlays`, which the host renders beside this.
11
11
  */
@@ -14,26 +14,25 @@ import { activeAuthoringVersion, subscribeActiveAuthoring } from '@volter/editor
14
14
  import {
15
15
  getMountFailureReports,
16
16
  subscribeToMountFailures,
17
- } from '@volter/editor-core/authoring/mount-failure-report';
17
+ } from '@volter/editor-sdk/kit/mount-failure-report';
18
18
  import {
19
19
  object3DDocumentSessionsVersion,
20
20
  subscribeObject3DDocumentSessions,
21
21
  } from '@volter/editor-core/authoring/object3d-document-session-registry';
22
22
  import { RootSelectionOverlay } from '@volter/editor-core/components/RootSelectionOverlay';
23
23
  import { SurfaceStateOverlay } from '@volter/editor-core/components/SurfaceStateOverlay';
24
- import { ViewportControlsHint } from '@volter/editor-core/components/ViewportControlsHint';
25
24
  import type {
26
25
  WorldRootOverlayProps,
27
26
  WorldRootStageBinding,
28
27
  } from '@volter/editor-core/components/world-root-binding';
29
28
  import type { EditorShellStore } from '@volter/editor-core/editor-shell-store';
30
- import { readinessFacet, subscribeRootReadiness } from '@volter/editor-core/readiness';
31
- import { documentStageContext, threeSelectionToolsApply } from '@volter/editor-core/stage-context';
32
- import { explainSurface } from '@volter/editor-core/surface-state';
29
+ import { readinessFacet, subscribeRootReadiness } from '@volter/editor-sdk/kit/readiness';
30
+ import { documentStageContext } from '@volter/editor-core/stage-context';
31
+ import { explainSurface } from '@volter/editor-sdk/kit/surface-state';
33
32
  import {
34
33
  subscribeWorkspaceDocuments,
35
34
  workspaceDocumentRegistryVersion,
36
- } from '@volter/editor-core/workspace-document-registry';
35
+ } from '@volter/editor-sdk/kit/workspace-document-registry';
37
36
  import { useMemo, useSyncExternalStore } from 'react';
38
37
  import type * as THREE from 'three';
39
38
  import { threeSceneHasRenderableContent } from '../surface-content';
@@ -101,7 +100,6 @@ function WorldRootOverlays({
101
100
  // The world root's stage is the Scene document's: the kit's overlay props
102
101
  // carry no document id, and the Scene document is the one world-root stage.
103
102
  const ctx = documentStageContext(store, documentId, 'document');
104
- const showsSelectionTools = threeSelectionToolsApply(ctx);
105
103
  return (
106
104
  <>
107
105
  {/* Three-scene selection overlay. React/Pixi documents mount their own
@@ -114,13 +112,6 @@ function WorldRootOverlays({
114
112
  (`world-root-stage.ts`), so the pin belongs to the stage that
115
113
  installed it. */}
116
114
  {ctx.surface === 'three' ? <CameraAuthoringOverlay previewRef={cameraPreviewRef} /> : null}
117
- {/* The hint also shows WHILE the world is still mounting: a new user
118
- reads the screen during those boot seconds and looks for the camera
119
- controls exactly then. The kit's overlay set shows it on a three
120
- surface; this adds only the mounting case it does not cover. */}
121
- {!showsSelectionTools && ctx.surface !== 'three' && mountStatus === 'mounting' ? (
122
- <ViewportControlsHint />
123
- ) : null}
124
115
  <SceneViewportStateOverlay store={store} rootIds={rootIds} mountStatus={mountStatus} />
125
116
  </>
126
117
  );
@@ -21,6 +21,11 @@
21
21
  * LOAD too.
22
22
  */
23
23
 
24
+ import {
25
+ registerStartingPresentation,
26
+ registerStudioPreset,
27
+ type StudioPreset,
28
+ } from '@volter/editor-sdk/kit/viewport-presentation';
24
29
  import type { ViewportPresentation, ViewportRoot } from '@volter/editor-sdk/host';
25
30
  import { themeVars } from '@volter/editor-sdk/widgets';
26
31
  import { createPerformanceProfiler } from '@volter/game-runtime/dev/performance-profiler';
@@ -69,8 +74,8 @@ import {
69
74
  import { registerPresentedCanvasFrame } from '@volter/editor-core/canvas-preview-frames';
70
75
  import { collectState } from '@volter/editor-core/command-listener';
71
76
  import { getDownloadedAssetPath, getOnlineAssetFiles, reportEditorState } from '@volter/editor-core/editor-api';
72
- import { editorConsole } from '@volter/editor-core/editor-console';
73
- import { isEditorPresentationActive } from '@volter/editor-core/editor-presentation-activity';
77
+ import { editorConsole } from '@volter/editor-sdk/kit/editor-console';
78
+ import { isEditorPresentationActive } from '@volter/editor-sdk/kit/editor-presentation-activity';
74
79
  import type { EditorStats } from '@volter/editor-core/editor-runtime';
75
80
  import type { EditorShellStore } from '@volter/editor-core/editor-shell-store';
76
81
  import { EditorViewport, type OnlineAssetDrop } from '@volter/editor-core/editor-viewport';
@@ -79,14 +84,15 @@ import {
79
84
  nativeSelectionColors,
80
85
  nativeViewportLook,
81
86
  subscribeNativeSelectionTheme,
82
- } from '@volter/editor-core/native-selection-style';
87
+ } from '@volter/editor-sdk/kit/native-selection-style';
83
88
  import { registerPerformanceSource } from '@volter/editor-core/performance-sources';
84
89
  import { drawSceneUnlessRefused } from '../scene-view-drawability';
85
90
  import { withSceneFogNeutralized } from '@volter/editor-core/scene-view-fog';
86
91
  import { connectServerLogs } from '../server-log-bridge';
87
92
  import { focusedStageStore } from '@volter/editor-core/stage-context';
88
93
  import {
89
- createThreeSelectionOutline,
94
+ acquireThreeSelectionOutline,
95
+ releaseThreeSelectionOutline,
90
96
  setThreeSelectionOutlineColors,
91
97
  syncThreeSelectionOutline,
92
98
  } from '@volter/editor-core/three-viewport/selection-outline';
@@ -95,13 +101,36 @@ import {
95
101
  subscribeThreeViewportPresentation,
96
102
  threeViewportPresentation,
97
103
  } from '@volter/editor-core/three-viewport-presentation';
98
- import { recordViewportFirstFrame } from '@volter/editor-core/viewport-activation-timings';
104
+ import { recordViewportFirstFrame } from '@volter/editor-sdk/kit/viewport-activation-timings';
99
105
  import { savedViewportPose, saveViewportPose } from '../viewport-pose-memory';
100
106
  import { presentThreeRoots } from '../viewport-root-presentation';
101
107
  import { isEditorViewportShadingTarget } from '@volter/editor-core/viewport-shading-boundary';
102
108
  import { downloadOnlineAssetWithHistory } from '@volter/editor-core/components/asset-editor-persistence';
103
109
  import { bindStagePresenceMarkers } from '@volter/editor-core/components/stage-presence-markers';
104
110
 
111
+ /**
112
+ * THE WORLD STAGE'S STARTING PRESENTATION. Its studio is the light the world has always been
113
+ * shown by — the viewport's own ambient (0.5) and directional (1.0 from (10, 20, 10)), with no
114
+ * key and no image-based light of its own (the world's environment is the game's) — and it gives
115
+ * way to the scene's own whenever a live scene is adopted, as that rig always has.
116
+ */
117
+ const WORLD_STUDIO: StudioPreset = {
118
+ id: 'world',
119
+ title: 'World',
120
+ lights: [{ color: '#ffffff', intensity: 1, direction: [-10, -20, -10], space: 'world' }],
121
+ ambient: { color: '#ffffff', intensity: 0.5 },
122
+ environmentIntensity: 0,
123
+ };
124
+ const releaseWorldPresentation = [
125
+ registerStudioPreset(WORLD_STUDIO),
126
+ registerStartingPresentation('world', {
127
+ all: {
128
+ lighting: { source: 'studio', studioPreset: WORLD_STUDIO.id, auto: { takeover: ['light'], overridable: true } },
129
+ },
130
+ }),
131
+ ];
132
+ if (import.meta.hot) import.meta.hot.dispose(() => releaseWorldPresentation.forEach((release) => release()));
133
+
105
134
  /**
106
135
  * The world root's renderer, built to the ENGINE's own render settings —
107
136
  * opaque, high-performance, PCF soft shadows, KTX2 support taught to the
@@ -339,9 +368,20 @@ export function installWorldRootStage(options: WorldRootStageOptions): WorldRoot
339
368
  // --- Scene ---
340
369
  const scene = new THREE.Scene();
341
370
  // The palette's viewport background when it carries one; the editor's own
342
- // grey otherwise. Theme changes follow through the viewport's look
343
- // subscription (`EditorViewport`).
344
- scene.background = new THREE.Color(nativeViewportLook(canvas).background ?? 0xaaaaaa);
371
+ // grey otherwise. The viewport's look subscription (`EditorViewport`) paints
372
+ // a palette's colour over it; this one gives the grey back when the next
373
+ // palette names none, as long as the scene still wears what was painted (a
374
+ // game may set its own background).
375
+ const WORLD_BACKGROUND = 0xaaaaaa;
376
+ let paintedBackground = nativeViewportLook(canvas).background ?? WORLD_BACKGROUND;
377
+ scene.background = new THREE.Color(paintedBackground);
378
+ const unsubscribeWorldBackground = subscribeNativeSelectionTheme(canvas, () => {
379
+ const next = nativeViewportLook(canvas).background ?? WORLD_BACKGROUND;
380
+ const current = scene.background;
381
+ if (current instanceof THREE.Color && current.getHex() === paintedBackground)
382
+ scene.background = new THREE.Color(next);
383
+ paintedBackground = next;
384
+ });
345
385
 
346
386
  // --- Bind store to scene ---
347
387
  store.bindScene(scene, renderer);
@@ -354,6 +394,9 @@ export function installWorldRootStage(options: WorldRootStageOptions): WorldRoot
354
394
  onlineAssetResolver: resolveDroppedOnlineAsset,
355
395
  onProjectionChange: setThreeViewportProjection,
356
396
  });
397
+ // The world is lit and dressed by its view's presentation (`kit/viewport-presentation`), as
398
+ // a `world` stage: this module builds it, so it states how it starts (`WORLD_STUDIO` below).
399
+ const unbindPresentation = viewport.bindPresentation(documentId, 'world');
357
400
  // Bind the REAL viewport camera + orbit target so store.cameraPose (the
358
401
  // `editor.viewport.camera.get` facet, see command-listener.ts's
359
402
  // collectState) and the thumbnail-capture path read live data instead of
@@ -412,7 +455,7 @@ export function installWorldRootStage(options: WorldRootStageOptions): WorldRoot
412
455
  // declaration) would leave the previous world's colour space on the
413
456
  // editor's renderer until page reload.
414
457
  let restoreAdoptedImage: (() => void) | null = null;
415
- let selectionOutline: ReturnType<typeof createThreeSelectionOutline> | null = null;
458
+ let selectionOutline: ReturnType<typeof acquireThreeSelectionOutline> | null = null;
416
459
  let selectionOutlinePass: EffectPass | null = null;
417
460
  let selectionOutlineUnderlayPass: Pass | null = null;
418
461
  const syncSelectionTheme = (): void => {
@@ -459,10 +502,10 @@ export function installWorldRootStage(options: WorldRootStageOptions): WorldRoot
459
502
  // start from the editor's own values — see `restoreAdoptedImage`'s decl.
460
503
  restoreAdoptedImage?.();
461
504
  restoreAdoptedImage = null;
462
- // `applySceneRenderPipeline` disposes the previous pass but an
463
- // OutlineEffect's Selection owns temporary render-layer bits on the
464
- // selected objects. Clear those explicitly before dropping the effect.
465
- selectionOutline?.selection.clear();
505
+ // `applySceneRenderPipeline` disposes the previous passes; the outline
506
+ // returns to this renderer's pool first, detached from its pass and its
507
+ // selection cleared, and the rebuilt pipeline takes it back below.
508
+ if (selectionOutline) releaseThreeSelectionOutline(renderer, selectionOutline, selectionOutlinePass);
466
509
  selectionOutline = null;
467
510
  selectionOutlinePass = null;
468
511
  selectionOutlineUnderlayPass = null;
@@ -485,8 +528,9 @@ export function installWorldRootStage(options: WorldRootStageOptions): WorldRoot
485
528
  // This stage already loaded `postprocessing` for its own composer, so it
486
529
  // hands the factory its own bindings — no second module load, and the
487
530
  // outline is attached synchronously exactly as before.
488
- selectionOutline = createThreeSelectionOutline(
531
+ selectionOutline = acquireThreeSelectionOutline(
489
532
  { BlendFunction, KernelSize, OutlineEffect },
533
+ renderer,
490
534
  store.scene ?? scene,
491
535
  viewport.renderCamera,
492
536
  nativeSelectionColors(renderer.domElement),
@@ -1038,6 +1082,8 @@ export function installWorldRootStage(options: WorldRootStageOptions): WorldRoot
1038
1082
  gpuTimer.dispose();
1039
1083
  unsubscribeViewportPresentation();
1040
1084
  unsubscribeSelectionTheme();
1085
+ unsubscribeWorldBackground();
1086
+ unbindPresentation();
1041
1087
  selectionOutline?.selection.clear();
1042
1088
  softParticleDepth.dispose();
1043
1089
  composer.dispose();
@@ -44,7 +44,7 @@
44
44
  * `ingest/mount-coverage.ts` assembles the facts from the live singletons.
45
45
  */
46
46
 
47
- import { commandLine } from '@volter/editor-core/product-command';
47
+ import { commandLine } from '@volter/editor-sdk/kit/product-command';
48
48
  import type {
49
49
  AuthoringProviderKey,
50
50
  SeamEvidenceVerdict,
@@ -461,6 +461,8 @@ export interface AuthoringSurfaceFacts {
461
461
  readonly availableIsolationDocuments: number;
462
462
  readonly pieces: number;
463
463
  readonly sceneEntries: number;
464
+ /** Project story modules that did not load or compose (`editor.status().storyFailures`). */
465
+ readonly storyFailures?: number;
464
466
  }
465
467
 
466
468
  /** Required only inside the row rules. Public callers never manufacture this
@@ -1237,6 +1239,16 @@ function authoringSurfaceRows(facts: ResolvedCoverageFacts): readonly Capability
1237
1239
  'the scene table declares no scenes, so there is no surface to place prefabs on ' +
1238
1240
  '(a models or website project)',
1239
1241
  }
1242
+ : (surface.storyFailures ?? 0) > 0
1243
+ ? {
1244
+ seam: 'authoring.pieces',
1245
+ status: 'gap',
1246
+ detail:
1247
+ `${surface.storyFailures} project story module(s) failed to load, so their prefabs are missing ` +
1248
+ `from the scene table (${surface.pieces} resolved)`,
1249
+ missing: 'the prefabs those stories register are absent from Content and the component board',
1250
+ fix: 'read `editor.status().storyFailures` for each module and its error, and the console line naming the module the load failed on',
1251
+ }
1240
1252
  : surface.pieces === 0
1241
1253
  ? {
1242
1254
  seam: 'authoring.pieces',
@@ -16,7 +16,7 @@ import {
16
16
  GAME_LIFECYCLE_SHAPE,
17
17
  GAME_SYSTEMS_SHAPE,
18
18
  } from '@volter/editor-project/adapter/ingest/game-contract-seams';
19
- import { liveSeamEvidence } from '@volter/editor-core/coverage/live-seam-evidence';
19
+ import { liveSeamEvidence } from '@volter/editor-sdk/kit/live-seam-evidence';
20
20
 
21
21
  const EPOCHS = new WeakMap<object, string>();
22
22
  let nextEpoch = 1;
@@ -34,7 +34,6 @@
34
34
  * `coverage/system-adapter-coverage.ts`.
35
35
  */
36
36
 
37
- import { commandLine } from '@volter/editor-core/product-command';
38
37
  import {
39
38
  PROJECT_VERB_SLOTS,
40
39
  type ProjectVerbMeasurement,
@@ -104,30 +103,16 @@ function exportVerb(facts: ProjectVerbFacts): ProjectVerbMeasurement {
104
103
  missing:
105
104
  'this project cannot produce a standalone build, so it runs NOWHERE but the editor — the ' +
106
105
  'dev-served standalone page refuses an unexported game outright',
107
- fix: "add the scaffold's `build` script (`build: tsc && vite build`), which is what every deploy path runs",
106
+ fix: "add the scaffold's `build` script (`build: tsc && vite build`), which is what the export path runs",
108
107
  };
109
108
  }
110
- const refused = roots.filter(
111
- (root) => root.type !== 'ingest' && (root.type !== 'builtin' || root.identity !== 'three'),
112
- );
113
- const wallLeg =
114
- refused.length > 0
115
- ? `; note that the legacy ${commandLine('deploy')} verb additionally refuses ${refused
116
- .map((root) => `root "${root.id}" (${root.identity})`)
117
- .join(
118
- ', ',
119
- )} — use the project-owned deploy scripts (${commandLine('add deploy-cloudflare')}/\`deploy-vercel\`, then \`npm run deploy\`)`
120
- : '';
121
- const deployLeg = scripts.includes('deploy')
122
- ? ', and a `deploy` script to ship it'
123
- : ` (no \`deploy\` script yet — ${commandLine('add deploy-cloudflare')}/\`deploy-vercel\` adds one)`;
124
109
  const ingestLeg = ingestOnly(roots)
125
110
  ? '; this ingest project ships the standalone bundle produced by its own build unchanged'
126
111
  : '';
127
112
  return {
128
113
  slot: 'export',
129
114
  state: 'present',
130
- evidence: `this project declares a \`build\` script, which is what the export path runs to emit the \`dist/\` it stages${deployLeg}${ingestLeg}${wallLeg}`,
115
+ evidence: `this project declares a \`build\` script, which is what the export path runs to emit the \`dist/\` it stages${ingestLeg}`,
131
116
  };
132
117
  }
133
118
 
@@ -53,7 +53,7 @@ import {
53
53
  type SystemAdapterMeasurement,
54
54
  type SystemAdapterSlot,
55
55
  } from './capability-coverage';
56
- import { inspectSystemAdapterSeam } from '@volter/editor-core/coverage/system-seam-evidence';
56
+ import { inspectSystemAdapterSeam } from '@volter/editor-sdk/kit/system-seam-evidence';
57
57
 
58
58
  /** What the native derivation needs to know that the live registry cannot tell
59
59
  * it. Both facts are read off things that already exist; neither is a guess. */
@@ -11,7 +11,7 @@ import {
11
11
  setWorkspaceUtilityTabs,
12
12
  workspaceUtilityTabs,
13
13
  } from '@volter/editor-core/workspace-host-commands';
14
- import { availableWorkspaceUtilities } from '@volter/editor-core/workspace-utility-registry';
14
+ import { availableWorkspaceUtilities } from '@volter/editor-sdk/kit/workspace-utility-registry';
15
15
 
16
16
  const ZERO_STATS: EditorStats = {
17
17
  fps: 60,
@@ -22,6 +22,14 @@ const ZERO_STATS: EditorStats = {
22
22
  cameraTarget: { x: 0, y: 1, z: 0 },
23
23
  };
24
24
 
25
+ /** A story runtime's Three half, for a production component that reads the scene. */
26
+ export function storyThreeStore(runtime: EditorRuntime): EditorShellStore {
27
+ if (!(runtime.store instanceof EditorShellStore)) {
28
+ throw new Error('This runtime was not made by createStoryEditorRuntime: it has no Three store.');
29
+ }
30
+ return runtime.store;
31
+ }
32
+
25
33
  /** A real, bounded editor runtime for production component stories. */
26
34
  export function createStoryEditorRuntime(): EditorRuntime {
27
35
  const store = new EditorShellStore();
@@ -2,7 +2,7 @@ import { collectContentNodeRecords } from '@volter/editor-threejs/viewport/conte
2
2
  import { isEditorOwnedObject } from '@volter/editor-threejs/viewport/editor-layers';
3
3
  import { markHostRenderer } from '@volter/editor-threejs/viewport/renderer-ownership';
4
4
  import * as THREE from 'three';
5
- import type { DocumentPreviewCaptureRequest } from '@volter/editor-core/document-preview-source';
5
+ import type { DocumentPreviewCaptureRequest } from '@volter/editor-sdk/kit/document-preview-source';
6
6
  import { frameableContentBounds } from '@volter/editor-core/scene-framing';
7
7
 
8
8
  function authoredCameras(root: THREE.Object3D): THREE.Camera[] {
@@ -1,4 +1,4 @@
1
- import { commandLine } from '@volter/editor-core/product-command';
1
+ import { commandLine } from '@volter/editor-sdk/kit/product-command';
2
2
  /**
3
3
  * THE MODULE LANE of `vgai eval` — reach the RUNNING mount's own module
4
4
  * instances, by served path, using URLs retained by their owning realm.
@@ -42,16 +42,24 @@
42
42
  */
43
43
 
44
44
  /**
45
- * What the host stamps on an adopted surface so a game's `position:fixed`
46
- * overlay is contained to the pane.
45
+ * What the host stamps on an adopted surface so it behaves as the game's own page.
47
46
  *
48
47
  * `contain: layout` makes the element a containing block for absolutely AND
49
- * fixed positioned descendants — the one CSS primitive that does this without
50
- * the side effects of the alternatives (`transform`/`filter` also create the
51
- * containing block but force a compositing layer and, on the ADOPTED element
52
- * itself, are exactly the stamp {@link claimHostSurfaceBox} exists to clear).
48
+ * fixed positioned descendants, so a game's `position:fixed` overlay is contained to the
49
+ * pane — the one CSS primitive that does this without the side effects of the alternatives
50
+ * (`transform`/`filter` also create the containing block but force a compositing layer and,
51
+ * on the ADOPTED element itself, are exactly the stamp {@link claimHostSurfaceBox} exists to
52
+ * clear).
53
+ *
54
+ * The inherited text properties start from a page's defaults, as the game's `<body>` does
55
+ * when it ships: otherwise the editor's own typography (11px, its line height and colour)
56
+ * inherited into the game's DOM, and a game's text rendered smaller in the editor than in
57
+ * its build.
53
58
  */
54
- export const GAME_SURFACE_CONTAINMENT_CSS = 'contain: layout;';
59
+ export const GAME_SURFACE_CONTAINMENT_CSS =
60
+ 'contain: layout; font: initial; color: initial; letter-spacing: normal; word-spacing: normal;' +
61
+ ' text-align: start; text-indent: 0; text-transform: none; white-space: normal;' +
62
+ ' direction: ltr; cursor: auto; visibility: visible;';
55
63
 
56
64
  /** `EventTarget`'s own listener identity is (type, callback, capture) — read
57
65
  * the capture flag out of either options form so the page's registration
@@ -14,7 +14,7 @@
14
14
  * attached AND ungated.
15
15
  */
16
16
 
17
- import { editorConsole } from '@volter/editor-core/editor-console';
17
+ import { editorConsole } from '@volter/editor-sdk/kit/editor-console';
18
18
  import { disposeGameRealm } from './gated-globals';
19
19
 
20
20
  /**
@@ -28,8 +28,8 @@
28
28
  * callers that already reach for it alongside the proxies. */
29
29
  export { GAME_GLOBALS_PRELUDE } from '@volter/editor-core/game-globals-prelude';
30
30
 
31
- import { installCreationSiteRecorder } from '@volter/editor-core/creation-site-registry';
32
- import { setConsoleRealmAttribution } from '@volter/editor-core/editor-console';
31
+ import { installCreationSiteRecorder } from '@volter/editor-sdk/kit/creation-site-registry';
32
+ import { setConsoleRealmAttribution } from '@volter/editor-sdk/kit/editor-console';
33
33
  import { guardedGameLocation, refusedNavigationMessage } from './game-location-guard';
34
34
  import { GameRealmPage } from './game-realm-page';
35
35
  import {
@@ -44,7 +44,7 @@ import {
44
44
  type SameRealmLoopGate,
45
45
  type SameRealmLoopGateStats,
46
46
  } from './same-realm-loop-gate';
47
- import { surfaceHoldsKeyboard } from '@volter/editor-core/surface-keyboard';
47
+ import { surfaceHoldsKeyboard } from '@volter/editor-sdk/kit/surface-keyboard';
48
48
 
49
49
  /**
50
50
  * The SAME-REALM LOOP GATE (S-5) — the scheduling half of the same idea.
@@ -94,7 +94,7 @@ const INPUT_EVENT_TYPES = new Set<string>([
94
94
  * way — so a key pressed while the gate was open and released after it closed
95
95
  * (Stop with W still held) left the game's OWN input manager holding KeyW for
96
96
  * good: the editor flushes only the session's InputManager, never a
97
- * project-owned copy (`src/lib/input`). With both vertical keys stuck the hero
97
+ * project-owned one. With both vertical keys stuck the hero
98
98
  * could not move up or down while A/D worked (runhuman pass 129; Opus
99
99
  * reproduction 2026-09-03 — forcing KeyW+KeyS into `keysDown` reproduced the
100
100
  * report verbatim, a single stuck key does not). Each proxy remembers the
@@ -1,6 +1,6 @@
1
- import { sha256Hex } from '@volter/editor-core/bytes-codec';
1
+ import { sha256Hex } from '@volter/editor-sdk/kit/bytes-codec';
2
2
  import { HistoryOperationError, type HistoryService } from '@volter/editor-core/history/history-service';
3
- import type { ResourceDescriptor, ResourceDriver, ResourceKind } from '@volter/editor-core/history/types';
3
+ import type { ResourceDescriptor, ResourceDriver, ResourceKind } from '@volter/editor-sdk/kit/history-types';
4
4
 
5
5
  const encoder = new TextEncoder();
6
6
  const decoder = new TextDecoder();
@@ -20,7 +20,7 @@
20
20
  * action that writes NEW FILES — this one writes two.
21
21
  */
22
22
 
23
- import type { InstanceSourceLocator } from '@volter/editor-core/instance-source-actions';
23
+ import type { InstanceSourceLocator } from '@volter/editor-sdk/kit/instance-source-actions';
24
24
 
25
25
  export const EXTRACT_COMPONENT_LABEL = 'Extract Component…';
26
26
 
@@ -19,7 +19,7 @@
19
19
  * FILE, which no other hierarchy item does.
20
20
  */
21
21
 
22
- import type { InstanceSourceLocator } from '@volter/editor-core/instance-source-actions';
22
+ import type { InstanceSourceLocator } from '@volter/editor-sdk/kit/instance-source-actions';
23
23
 
24
24
  export const FORK_COMPONENT_LABEL = 'Fork Component…';
25
25
 
@@ -28,9 +28,9 @@
28
28
  * raycast the projector can own the way {@link ThreeProjector.pick} does.
29
29
  */
30
30
 
31
- import type { ProjectedNode, Projection } from '@volter/editor-core/projection/types';
31
+ import type { ProjectedNode, Projection } from '@volter/editor-sdk/kit/projection-types';
32
32
 
33
- export type { ProjectedNode, Projection } from '@volter/editor-core/projection/types';
33
+ export type { ProjectedNode, Projection } from '@volter/editor-sdk/kit/projection-types';
34
34
 
35
35
  /**
36
36
  * The minimum shape a live DOM walk needs. Deliberately not `Element` so a
@@ -12,7 +12,7 @@
12
12
  import type { AuthoringAdapter2D, EditorNode2D } from '@volter/game-runtime/pixi/authoring';
13
13
  import type { DOMRectLike } from '@volter/editor-project/adapter';
14
14
  import type { Container, PointData } from 'pixi.js';
15
- import type { ProjectedNode, Projection } from '@volter/editor-core/projection/types';
15
+ import type { ProjectedNode, Projection } from '@volter/editor-sdk/kit/projection-types';
16
16
 
17
17
  export type PixiNode = ProjectedNode<Container>;
18
18
 
@@ -13,7 +13,7 @@ import {
13
13
  R3F_ENTRY_RUNTIME_PATH,
14
14
  R3F_RUNTIME_PATH,
15
15
  } from '@volter/editor-sdk/host';
16
- import { isPackagedRuntime } from '@volter/editor-core/packaged-runtime';
16
+ import { isPackagedRuntime } from '@volter/editor-sdk/kit/packaged-runtime';
17
17
 
18
18
  type R3FEntryResolver = typeof resolveR3FEntryAdapter;
19
19
 
@@ -27,7 +27,7 @@ import {
27
27
  import { flushSync } from 'react-dom';
28
28
  import { createRoot } from 'react-dom/client';
29
29
  import { REACT_WORLD_RUNTIME_PATH } from '@volter/editor-sdk/host';
30
- import { isPackagedRuntime } from '@volter/editor-core/packaged-runtime';
30
+ import { isPackagedRuntime } from '@volter/editor-sdk/kit/packaged-runtime';
31
31
 
32
32
  /**
33
33
  * The pieces of "react itself" a react-world mount needs:
@@ -50,7 +50,7 @@ import {
50
50
  } from '@volter/editor-sdk/session/project-module-url';
51
51
  import type { AdapterSurface } from '@volter/editor-project/adapter/adapter-surface';
52
52
  import { resolveCanvasEntryAdapterForEditor } from './canvas-entry-runtime';
53
- import { isPackagedRuntime } from '@volter/editor-core/packaged-runtime';
53
+ import { isPackagedRuntime } from '@volter/editor-sdk/kit/packaged-runtime';
54
54
  import { type ReactRootMountRuntime, resolveReactRootMountRuntime } from './react-mount-runtime';
55
55
  import {
56
56
  resolveThreeIngestRuntimeForEditor,
@@ -131,7 +131,7 @@ function withCapabilityWarning<K extends AdapterSurface>(
131
131
  mounted.kind,
132
132
  );
133
133
  if (warning) {
134
- const { editorConsole } = await import('@volter/editor-core/editor-console');
134
+ const { editorConsole } = await import('@volter/editor-sdk/kit/editor-console');
135
135
  editorConsole.warn(warning, 'adapter');
136
136
  }
137
137
  return mounted;
@@ -26,8 +26,8 @@
26
26
  * which is exactly what the message says.
27
27
  */
28
28
 
29
- import { commandLine } from '@volter/editor-core/product-command';
30
- import { editorConsole } from '@volter/editor-core/editor-console';
29
+ import { commandLine } from '@volter/editor-sdk/kit/product-command';
30
+ import { editorConsole } from '@volter/editor-sdk/kit/editor-console';
31
31
 
32
32
  const undrawable = new WeakMap<object, string>();
33
33
 
@@ -7,7 +7,7 @@
7
7
  * session's viewport panel.
8
8
  */
9
9
  import { getServerValidationLog } from '@volter/editor-core/api/project-state';
10
- import { emitServerLogEntry } from '@volter/editor-core/editor-console';
10
+ import { emitServerLogEntry } from '@volter/editor-sdk/kit/editor-console';
11
11
  import { connectEvents } from '@volter/editor-core/editor-presence';
12
12
 
13
13
  /**
@@ -16,7 +16,7 @@ import * as shellThree from 'three';
16
16
  import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
17
17
  import { CSS3DRenderer } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
18
18
  import { THREE_INGEST_RUNTIME_PATH } from '@volter/editor-sdk/host';
19
- import { isPackagedRuntime } from '@volter/editor-core/packaged-runtime';
19
+ import { isPackagedRuntime } from '@volter/editor-sdk/kit/packaged-runtime';
20
20
 
21
21
  /**
22
22
  * THE three of the graph an ingested game's modules resolve — the project's
@@ -26,7 +26,7 @@ import {
26
26
  activeWorkspaceDocumentId,
27
27
  subscribeWorkspaceDocuments,
28
28
  workspaceDocumentRegistryVersion,
29
- } from '@volter/editor-core/workspace-document-registry';
29
+ } from '@volter/editor-sdk/kit/workspace-document-registry';
30
30
 
31
31
  export function useActivePerformanceSource(): EditorPerformanceSource | null {
32
32
  useSyncExternalStore(
@@ -192,7 +192,7 @@ export function serializeEntry<T>(run: () => Promise<T>): Promise<T> {
192
192
  return result;
193
193
  }
194
194
 
195
- import { registerLiveSession } from '@volter/editor-core/live-session-registry';
195
+ import { registerLiveSession } from '@volter/editor-sdk/kit/live-session-registry';
196
196
  // THE INGEST LANE, as the host sees it (`live-session-registry.ts`). Playing
197
197
  // is the host play-control latch, never an inferred loop
198
198
  // (`editor-session-mode.ts` records why); a deferred-ingest play counts.
@@ -19,14 +19,14 @@
19
19
 
20
20
  import { authoringOidOf } from '@volter/editor-core/authoring/component-instance-root';
21
21
  import { setIngestDataWriter } from '../../host/authoring/ingest-data-writer';
22
- import { editorConsole } from '@volter/editor-core/editor-console';
22
+ import { editorConsole } from '@volter/editor-sdk/kit/editor-console';
23
23
  import type { EditorShellStore } from '@volter/editor-core/editor-shell-store';
24
24
  import { GAME_SURFACE_CONTAINMENT_CSS } from '../../host/game-realm-page';
25
25
  import { clearGameSurface, gameLoopGate, setGameSurface } from '../../host/gated-globals';
26
26
  import { authoringJournal } from '../../host/history/json-history-resource';
27
- import { clearPresentationSurface, recordPresentationSurface } from '@volter/editor-core/presentation-surface';
27
+ import { clearPresentationSurface, recordPresentationSurface } from '@volter/editor-sdk/kit/presentation-surface';
28
28
  import { getCurrentProject } from '@volter/editor-core/project-manager';
29
- import { clearRootReadiness, recordRootReadiness } from '@volter/editor-core/readiness';
29
+ import { clearRootReadiness, recordRootReadiness } from '@volter/editor-sdk/kit/readiness';
30
30
  import {
31
31
  type SameRealmLoopGate,
32
32
  type SameRealmLoopVerdict,
@@ -34,7 +34,7 @@ import {
34
34
  } from '../../host/same-realm-loop-gate';
35
35
  import { ensureScopedGameStyles } from '@volter/editor-core/scoped-game-css';
36
36
  import { resolveThreeIngestRuntimeForEditor } from '../../host/three-ingest-runtime';
37
- import type { OidEntry } from '@volter/editor-core/ui-source/oid-transform';
37
+ import type { OidEntry } from '@volter/editor-react/source/oid-transform';
38
38
  import { createHttpSourceWriteBackend } from '@volter/editor-core/ui-source/source-write-backend';
39
39
  import { serverRecordsSourceWrites } from '@volter/editor-core/ui-source/tier-source-write-backend';
40
40
  import { clearWorldAdoption, worldAdoptionRecorder } from '@volter/editor-core/world-adoption';
@@ -295,7 +295,7 @@ export function ingestSourceRoots(
295
295
  * THE SERVE-TIME DOOR: did the OID transform stamp any of THIS root's own
296
296
  * source, according to the index the dev server built while serving it?
297
297
  *
298
- * `GET /__ui-source/index` (`vite-plugin-ui-oid.ts`) records exactly what the
298
+ * `GET /__ui-source/index` (`@volter/editor-react`'s `serving/ui-oid-plugin.ts`) records exactly what the
299
299
  * transform stamped, and it is populated at TRANSFORM time — before the module
300
300
  * is evaluated, and therefore long before any object exists to carry a stamp.
301
301
  * That is precisely the ordering the graph door cannot have: on a project's
@@ -24,7 +24,7 @@
24
24
  * path. A second mount replaces the first's entry; there is only ever one wait.
25
25
  */
26
26
 
27
- import { notifyLiveSessionsChanged } from '@volter/editor-core/live-session-registry';
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
30
  /** The wait as `vgai status` reports it. */