@volter/sdk 0.0.0-stage → 0.5.203

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 (523) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +20 -0
  3. package/README.md +38 -3
  4. package/package.json +510 -4
  5. package/src/account.ts +210 -0
  6. package/src/chrome.ts +88 -0
  7. package/src/client.ts +1646 -0
  8. package/src/commands.ts +66 -0
  9. package/src/contributions.ts +619 -0
  10. package/src/css-numeric-style.ts +97 -0
  11. package/src/document-probe.ts +282 -0
  12. package/src/editor-view.ts +225 -0
  13. package/src/extension.ts +40 -0
  14. package/src/generations.ts +178 -0
  15. package/src/host.ts +1157 -0
  16. package/src/http-transport.browser.ts +14 -0
  17. package/src/http-transport.node.ts +19 -0
  18. package/src/index.ts +131 -0
  19. package/src/kit/CapabilityCoverageSection.tsx +185 -0
  20. package/src/kit/account-client.ts +333 -0
  21. package/src/kit/action-registry.ts +317 -0
  22. package/src/kit/active-product.ts +76 -0
  23. package/src/kit/active-project.ts +155 -0
  24. package/src/kit/adapter-editor-config.ts +25 -0
  25. package/src/kit/adapter-module.ts +7 -0
  26. package/src/kit/adapter-observation.ts +49 -0
  27. package/src/kit/animation/animation-clock.ts +479 -0
  28. package/src/kit/animation/stage-transport.ts +385 -0
  29. package/src/kit/api/assets.ts +365 -0
  30. package/src/kit/api/project-open.ts +355 -0
  31. package/src/kit/api/project-source.ts +180 -0
  32. package/src/kit/api/project-state.ts +110 -0
  33. package/src/kit/api/relay.ts +270 -0
  34. package/src/kit/api/themes.ts +45 -0
  35. package/src/kit/api-asset-library-wire.ts +45 -0
  36. package/src/kit/api-base.ts +10 -0
  37. package/src/kit/api-build.ts +99 -0
  38. package/src/kit/api-git-wire.ts +56 -0
  39. package/src/kit/api-logs.ts +92 -0
  40. package/src/kit/api-project-identity.ts +74 -0
  41. package/src/kit/api-settings.ts +36 -0
  42. package/src/kit/api-worktrees.ts +205 -0
  43. package/src/kit/asset-capabilities.ts +344 -0
  44. package/src/kit/asset-compare-core.ts +171 -0
  45. package/src/kit/asset-editor-context.tsx +101 -0
  46. package/src/kit/asset-events.ts +96 -0
  47. package/src/kit/asset-inspector-actions.ts +87 -0
  48. package/src/kit/asset-selection-viewer-registry.ts +113 -0
  49. package/src/kit/asset-selection.ts +146 -0
  50. package/src/kit/asset-thumbnails.ts +25 -0
  51. package/src/kit/asset-viewers.ts +115 -0
  52. package/src/kit/asset-workflow/asset-import-jobs.ts +106 -0
  53. package/src/kit/asset-workflow/asset-ledger-backend.ts +126 -0
  54. package/src/kit/asset-workflow/asset-ledger.ts +156 -0
  55. package/src/kit/asset-workflow/asset-materialization-report.ts +140 -0
  56. package/src/kit/asset-workflow/asset-pack-manifest.ts +320 -0
  57. package/src/kit/asset-workflow/asset-types.ts +142 -0
  58. package/src/kit/asset-workflow/audio-preview-player.ts +193 -0
  59. package/src/kit/asset-workflow/audio-waveform.ts +22 -0
  60. package/src/kit/asset-workflow/cloud-asset-client.ts +263 -0
  61. package/src/kit/asset-workflow/hosted-asset-materialization.ts +236 -0
  62. package/src/kit/asset-workflow/image-view-scale.ts +31 -0
  63. package/src/kit/asset-workflow/import-contract.ts +124 -0
  64. package/src/kit/asset-workflow/ledger-write-lock.ts +244 -0
  65. package/src/kit/asset-workflow/pixi-spritesheet.ts +197 -0
  66. package/src/kit/asset-workflow/preview-resource-lifetime.ts +44 -0
  67. package/src/kit/asset-workflow/project-asset-commands.ts +20 -0
  68. package/src/kit/asset-workflow/project-content.ts +288 -0
  69. package/src/kit/asset-workflow/project-source-index.ts +545 -0
  70. package/src/kit/asset-workflow/thumbnail-system.ts +256 -0
  71. package/src/kit/authoring/active-adapter.ts +200 -0
  72. package/src/kit/authoring/active-systems.ts +422 -0
  73. package/src/kit/authoring/adapter-key.ts +18 -0
  74. package/src/kit/authoring/authoring-asset-url.ts +27 -0
  75. package/src/kit/authoring/bootstrap-state.ts +49 -0
  76. package/src/kit/authoring/boundary-authoring-adapter.ts +189 -0
  77. package/src/kit/authoring/canvas-scene-guides.ts +84 -0
  78. package/src/kit/authoring/composite-authoring-adapter.ts +2109 -0
  79. package/src/kit/authoring/consumer-actions.ts +531 -0
  80. package/src/kit/authoring/design-time-layers.ts +852 -0
  81. package/src/kit/authoring/design-time-mount-registry.ts +244 -0
  82. package/src/kit/authoring/edit-mode-authoring.ts +637 -0
  83. package/src/kit/authoring/empty-project-authoring.ts +22 -0
  84. package/src/kit/authoring/instance-source-menu.ts +135 -0
  85. package/src/kit/authoring/layered-pick.ts +185 -0
  86. package/src/kit/authoring/mounted-root-subjects.ts +146 -0
  87. package/src/kit/authoring/no-authoring-adapter.ts +59 -0
  88. package/src/kit/authoring/object3d-document-persistence.ts +122 -0
  89. package/src/kit/authoring/panel-authoring.ts +121 -0
  90. package/src/kit/authoring/project-authoring-session.ts +105 -0
  91. package/src/kit/authoring/provenance.ts +99 -0
  92. package/src/kit/authoring/react-canvas-navigation.ts +259 -0
  93. package/src/kit/authoring/react-design-canvas-style.ts +20 -0
  94. package/src/kit/authoring/react-story-board.ts +917 -0
  95. package/src/kit/authoring/selection-scope.ts +195 -0
  96. package/src/kit/authoring/shell-document-ops.ts +169 -0
  97. package/src/kit/authoring/story-board-chrome-fit.ts +107 -0
  98. package/src/kit/authoring/story-board-presentation.ts +111 -0
  99. package/src/kit/authoring/three-root.ts +67 -0
  100. package/src/kit/authoring/viewport-tool-context.ts +73 -0
  101. package/src/kit/authoring/viewport-tool-owner.ts +38 -0
  102. package/src/kit/authoring/world-session-state.ts +101 -0
  103. package/src/kit/authoring-seam-evidence.ts +300 -0
  104. package/src/kit/availability-tick.ts +66 -0
  105. package/src/kit/bitmap-label.ts +120 -0
  106. package/src/kit/boot-routing.ts +392 -0
  107. package/src/kit/breakpoint-state.ts +43 -0
  108. package/src/kit/build-identity.ts +16 -0
  109. package/src/kit/bytes-codec.ts +62 -0
  110. package/src/kit/cancellation-reason.ts +58 -0
  111. package/src/kit/canvas-frames.ts +88 -0
  112. package/src/kit/capture-camera-pose.ts +77 -0
  113. package/src/kit/capture-size.ts +88 -0
  114. package/src/kit/chrome-registry.ts +159 -0
  115. package/src/kit/chrome-slot-registry.ts +91 -0
  116. package/src/kit/collaboration-client.ts +264 -0
  117. package/src/kit/collaboration-presence.ts +41 -0
  118. package/src/kit/command-dispatch.ts +19 -0
  119. package/src/kit/command-listener.ts +2182 -0
  120. package/src/kit/command-registry.ts +71 -0
  121. package/src/kit/component-board-registry.ts +205 -0
  122. package/src/kit/component-states-registry.ts +199 -0
  123. package/src/kit/components/AlignToolbar.tsx +204 -0
  124. package/src/kit/components/ApplicationMenus.tsx +372 -0
  125. package/src/kit/components/AssetEditorShell.tsx +216 -0
  126. package/src/kit/components/AssetInspectorToolSection.tsx +124 -0
  127. package/src/kit/components/BoardRulers.tsx +354 -0
  128. package/src/kit/components/CanvasAddNodeDialogs.tsx +529 -0
  129. package/src/kit/components/CanvasSceneViewport.tsx +1195 -0
  130. package/src/kit/components/ChromeSlot.tsx +20 -0
  131. package/src/kit/components/CodeView.tsx +470 -0
  132. package/src/kit/components/CompactInspectorShell.tsx +39 -0
  133. package/src/kit/components/ConsolePanel.tsx +273 -0
  134. package/src/kit/components/GameplaySessionTimeline.tsx +295 -0
  135. package/src/kit/components/InspectionProjection.tsx +932 -0
  136. package/src/kit/components/Inspector.tsx +270 -0
  137. package/src/kit/components/InspectorCanvasPreview.tsx +35 -0
  138. package/src/kit/components/InspectorFieldsSection.tsx +290 -0
  139. package/src/kit/components/InspectorStoriesSection.tsx +92 -0
  140. package/src/kit/components/InspectorToolSection.tsx +96 -0
  141. package/src/kit/components/InspectorTransformSection.tsx +245 -0
  142. package/src/kit/components/LightExplorerPanel.tsx +433 -0
  143. package/src/kit/components/MediaProperties.tsx +145 -0
  144. package/src/kit/components/ProjectHeader.tsx +328 -0
  145. package/src/kit/components/ReactCanvasControls.tsx +358 -0
  146. package/src/kit/components/RootSelectionOverlay.tsx +3688 -0
  147. package/src/kit/components/RootTextEditor.tsx +79 -0
  148. package/src/kit/components/SaveStatus.tsx +70 -0
  149. package/src/kit/components/SurfaceCrashBoundary.tsx +105 -0
  150. package/src/kit/components/SurfaceStateOverlay.tsx +24 -0
  151. package/src/kit/components/ToolContributionSurfaces.tsx +49 -0
  152. package/src/kit/components/ToolHost.tsx +380 -0
  153. package/src/kit/components/Toolbar.tsx +811 -0
  154. package/src/kit/components/TransientHint.tsx +44 -0
  155. package/src/kit/components/VersionControlSection.tsx +470 -0
  156. package/src/kit/components/ViewportOverlaysMenu.tsx +177 -0
  157. package/src/kit/components/VolterLogo.tsx +18 -0
  158. package/src/kit/components/WorktreeSwitcher.tsx +712 -0
  159. package/src/kit/components/account-documents.tsx +1162 -0
  160. package/src/kit/components/asset-documents.tsx +794 -0
  161. package/src/kit/components/asset-editor-persistence.ts +216 -0
  162. package/src/kit/components/asset-selection-section.tsx +545 -0
  163. package/src/kit/components/asset-thumbnails.tsx +307 -0
  164. package/src/kit/components/asset-viewers/AudioViewer.tsx +201 -0
  165. package/src/kit/components/asset-viewers/GenericJsonViewer.tsx +102 -0
  166. package/src/kit/components/asset-viewers/ImageViewer.tsx +300 -0
  167. package/src/kit/components/asset-viewers/JsonAssetDocument.tsx +98 -0
  168. package/src/kit/components/asset-viewers/OnlineAssetDetail.tsx +426 -0
  169. package/src/kit/components/asset-viewers/SourceAssetViewer.tsx +356 -0
  170. package/src/kit/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
  171. package/src/kit/components/asset-viewers/VideoViewer.tsx +101 -0
  172. package/src/kit/components/asset-viewers/shader-source.ts +144 -0
  173. package/src/kit/components/board-guides.ts +150 -0
  174. package/src/kit/components/canvas-scene-hotkeys.ts +37 -0
  175. package/src/kit/components/canvas-temporary-pivot.ts +34 -0
  176. package/src/kit/components/core-utilities.tsx +94 -0
  177. package/src/kit/components/inspector-preview-section.tsx +223 -0
  178. package/src/kit/components/inspector-revert-label.ts +20 -0
  179. package/src/kit/components/inspector-selection.ts +42 -0
  180. package/src/kit/components/inspector-stories-gating.ts +171 -0
  181. package/src/kit/components/inspector-transform-subject.ts +11 -0
  182. package/src/kit/components/inspector-transform.ts +88 -0
  183. package/src/kit/components/kind-documents.tsx +544 -0
  184. package/src/kit/components/primitives/DraftColorInput.tsx +74 -0
  185. package/src/kit/components/project-tool-documents.tsx +402 -0
  186. package/src/kit/components/scene-documents.tsx +221 -0
  187. package/src/kit/components/status-contributions.tsx +407 -0
  188. package/src/kit/components/tool-documents.tsx +302 -0
  189. package/src/kit/components/tool-schema-form.tsx +262 -0
  190. package/src/kit/components/use-after-paint.ts +41 -0
  191. package/src/kit/components/use-project-image-assets.ts +86 -0
  192. package/src/kit/components/workspace-history.ts +32 -0
  193. package/src/kit/components/world-documents.tsx +570 -0
  194. package/src/kit/components/world-overlay-gestures.ts +1939 -0
  195. package/src/kit/composite-screenshot.ts +2238 -0
  196. package/src/kit/content-entry-source-registry.ts +184 -0
  197. package/src/kit/contribution-surfaces.ts +48 -0
  198. package/src/kit/coverage/canvas-reveal.ts +192 -0
  199. package/src/kit/coverage/design-time-surfaces.ts +101 -0
  200. package/src/kit/coverage/ontology-invariants.ts +466 -0
  201. package/src/kit/coverage/session-vitals.ts +503 -0
  202. package/src/kit/crash-null-boundary.ts +36 -0
  203. package/src/kit/creation-site-edit.ts +1491 -0
  204. package/src/kit/creation-site-registry.ts +160 -0
  205. package/src/kit/delegate-harness-registry.ts +134 -0
  206. package/src/kit/document-areas.ts +70 -0
  207. package/src/kit/document-context-registry.ts +193 -0
  208. package/src/kit/document-open-registry.ts +200 -0
  209. package/src/kit/document-play-extension.ts +221 -0
  210. package/src/kit/document-preview-source.ts +20 -0
  211. package/src/kit/document-renderer-session.ts +138 -0
  212. package/src/kit/document-stage-sessions.ts +26 -0
  213. package/src/kit/document-viewports.ts +120 -0
  214. package/src/kit/editor-api.ts +46 -0
  215. package/src/kit/editor-chrome-capture.ts +136 -0
  216. package/src/kit/editor-commands.ts +176 -0
  217. package/src/kit/editor-console.ts +580 -0
  218. package/src/kit/editor-current-view.ts +56 -0
  219. package/src/kit/editor-document-probe.ts +1166 -0
  220. package/src/kit/editor-git-client.ts +115 -0
  221. package/src/kit/editor-hotkeys.ts +728 -0
  222. package/src/kit/editor-lease-view.ts +39 -0
  223. package/src/kit/editor-lease.ts +415 -0
  224. package/src/kit/editor-mode.ts +19 -0
  225. package/src/kit/editor-notifications.ts +140 -0
  226. package/src/kit/editor-presence.ts +563 -0
  227. package/src/kit/editor-presentation-activity.ts +58 -0
  228. package/src/kit/editor-presentation-notice.ts +42 -0
  229. package/src/kit/editor-runtime.tsx +147 -0
  230. package/src/kit/editor-server-response.ts +86 -0
  231. package/src/kit/editor-session-attribution.ts +85 -0
  232. package/src/kit/editor-session-mode.ts +54 -0
  233. package/src/kit/editor-state-facets.ts +74 -0
  234. package/src/kit/editor-view-presentation.ts +777 -0
  235. package/src/kit/environment-images.ts +58 -0
  236. package/src/kit/eyedropper-session.ts +60 -0
  237. package/src/kit/files/file-provider.ts +62 -0
  238. package/src/kit/files/project-files.ts +270 -0
  239. package/src/kit/finders/index.ts +137 -0
  240. package/src/kit/finders/scenes-from-entrypoint-selection.ts +387 -0
  241. package/src/kit/frame/frame-parts.ts +30 -0
  242. package/src/kit/framed-document-capture.ts +34 -0
  243. package/src/kit/game-globals-prelude.ts +143 -0
  244. package/src/kit/game-surface-defaults.ts +33 -0
  245. package/src/kit/gameplay-dom-recording.ts +318 -0
  246. package/src/kit/gameplay-export-state.ts +14 -0
  247. package/src/kit/gameplay-replay.ts +417 -0
  248. package/src/kit/gameplay-session-time.ts +9 -0
  249. package/src/kit/gameplay-sessions.ts +204 -0
  250. package/src/kit/hierarchy-component-marks.ts +298 -0
  251. package/src/kit/hierarchy-internals.ts +197 -0
  252. package/src/kit/hierarchy-kind-icon.ts +217 -0
  253. package/src/kit/hierarchy-menu-registry.ts +67 -0
  254. package/src/kit/hierarchy-node-rows.ts +307 -0
  255. package/src/kit/hierarchy-panel-view.ts +280 -0
  256. package/src/kit/hierarchy-projection.ts +76 -0
  257. package/src/kit/hierarchy-row-media.ts +45 -0
  258. package/src/kit/hierarchy-row-model.ts +308 -0
  259. package/src/kit/hierarchy-rows.ts +11 -0
  260. package/src/kit/hierarchy-walk.ts +86 -0
  261. package/src/kit/history/editor-session.ts +25 -0
  262. package/src/kit/history/history-commands.ts +147 -0
  263. package/src/kit/history/history-delegate.ts +187 -0
  264. package/src/kit/history/history-limit-notices.ts +43 -0
  265. package/src/kit/history/history-service.ts +1189 -0
  266. package/src/kit/history/persistence-coordinator.ts +35 -0
  267. package/src/kit/history/project-file-history.ts +386 -0
  268. package/src/kit/history/project-root-history-backends.ts +139 -0
  269. package/src/kit/history/resource-registry.ts +209 -0
  270. package/src/kit/history/snapshot-store.ts +103 -0
  271. package/src/kit/history/source-history-backend.ts +546 -0
  272. package/src/kit/history-types.ts +124 -0
  273. package/src/kit/hmr-registration-group.ts +67 -0
  274. package/src/kit/hmr-stable-react-context.ts +23 -0
  275. package/src/kit/hotkeys.ts +190 -0
  276. package/src/kit/inference-diagnostics.ts +69 -0
  277. package/src/kit/initial-project.ts +80 -0
  278. package/src/kit/inspection/active-subject.ts +571 -0
  279. package/src/kit/inspection/active-surface.ts +142 -0
  280. package/src/kit/inspection/compose-subject.ts +1055 -0
  281. package/src/kit/inspection/compose.ts +7 -0
  282. package/src/kit/inspection/display.ts +171 -0
  283. package/src/kit/inspection/document-subject.ts +109 -0
  284. package/src/kit/inspection/game-subject.ts +85 -0
  285. package/src/kit/inspection/null-subject.ts +119 -0
  286. package/src/kit/inspection/serialize.ts +357 -0
  287. package/src/kit/inspection/use-active-inspection.ts +180 -0
  288. package/src/kit/inspection-model.ts +542 -0
  289. package/src/kit/inspection-node-media.ts +58 -0
  290. package/src/kit/inspector-presentation.ts +203 -0
  291. package/src/kit/inspector-property-grouping.ts +64 -0
  292. package/src/kit/inspector-section-registry.ts +221 -0
  293. package/src/kit/instance-source-actions.ts +163 -0
  294. package/src/kit/js-heap.ts +71 -0
  295. package/src/kit/key-actions.ts +91 -0
  296. package/src/kit/keymap-presets.ts +428 -0
  297. package/src/kit/layout-policy.ts +31 -0
  298. package/src/kit/light-explorer-model.ts +134 -0
  299. package/src/kit/live-canvas-frame.ts +55 -0
  300. package/src/kit/live-document.ts +296 -0
  301. package/src/kit/live-gesture-lock.ts +50 -0
  302. package/src/kit/live-seam-evidence.ts +11 -0
  303. package/src/kit/live-session-registry.ts +220 -0
  304. package/src/kit/live-transition.ts +391 -0
  305. package/src/kit/manifest-project.ts +107 -0
  306. package/src/kit/module-fetch-diagnosis.ts +192 -0
  307. package/src/kit/mount-failure-report.ts +154 -0
  308. package/src/kit/native-selection-style.ts +497 -0
  309. package/src/kit/object3d-document-write-policy.ts +137 -0
  310. package/src/kit/packaged-runtime.ts +108 -0
  311. package/src/kit/palettes/maya.palette.json +57 -0
  312. package/src/kit/palettes/substance.palette.json +57 -0
  313. package/src/kit/performance-profiler.ts +367 -0
  314. package/src/kit/performance-sources.ts +69 -0
  315. package/src/kit/photograph-notice.ts +141 -0
  316. package/src/kit/play-boot-phase.ts +166 -0
  317. package/src/kit/play-camera-flight.ts +35 -0
  318. package/src/kit/png-encode.worker.ts +26 -0
  319. package/src/kit/presentation-surface.ts +248 -0
  320. package/src/kit/product-command.ts +90 -0
  321. package/src/kit/project-adapter.ts +1140 -0
  322. package/src/kit/project-asset-refresh.ts +23 -0
  323. package/src/kit/project-asset-roots.ts +68 -0
  324. package/src/kit/project-local-state.ts +151 -0
  325. package/src/kit/project-manager.ts +243 -0
  326. package/src/kit/project-module-changes.ts +201 -0
  327. package/src/kit/project-module-split.ts +270 -0
  328. package/src/kit/project-play-layers.ts +25 -0
  329. package/src/kit/project-provenance.ts +115 -0
  330. package/src/kit/project-ready.ts +42 -0
  331. package/src/kit/project-shape.ts +68 -0
  332. package/src/kit/project-tools.ts +107 -0
  333. package/src/kit/projection-types.ts +44 -0
  334. package/src/kit/readiness.ts +113 -0
  335. package/src/kit/renderer-resource-counts.ts +27 -0
  336. package/src/kit/reported-play-state.ts +90 -0
  337. package/src/kit/resolve-contributed-command.ts +14 -0
  338. package/src/kit/resolve-relative-specifier.ts +33 -0
  339. package/src/kit/retained-document-states.ts +91 -0
  340. package/src/kit/scene-document-plan.ts +320 -0
  341. package/src/kit/scene-live-open.ts +210 -0
  342. package/src/kit/scoped-game-css.ts +152 -0
  343. package/src/kit/served-url.ts +5 -0
  344. package/src/kit/session-close.ts +17 -0
  345. package/src/kit/session-tombstone.ts +127 -0
  346. package/src/kit/settings/settings-provider.ts +82 -0
  347. package/src/kit/settings-store.ts +348 -0
  348. package/src/kit/shell-document-state.ts +27 -0
  349. package/src/kit/shell-store-door.ts +45 -0
  350. package/src/kit/shell-store.ts +722 -0
  351. package/src/kit/source-conflict.ts +122 -0
  352. package/src/kit/stage-context.ts +377 -0
  353. package/src/kit/stage-invalidation.ts +25 -0
  354. package/src/kit/stage-store-registry.ts +69 -0
  355. package/src/kit/startup-failure.ts +80 -0
  356. package/src/kit/state-report-deferral.ts +73 -0
  357. package/src/kit/storage/host-files-storage.ts +97 -0
  358. package/src/kit/storage/http-storage.ts +174 -0
  359. package/src/kit/storage/index.ts +75 -0
  360. package/src/kit/storage/mem-storage.ts +158 -0
  361. package/src/kit/storage/path-lock.ts +44 -0
  362. package/src/kit/storage/paths.ts +26 -0
  363. package/src/kit/storage-types.ts +127 -0
  364. package/src/kit/stories/StoryPreviewMount.tsx +306 -0
  365. package/src/kit/stories/compose-project-stories.ts +255 -0
  366. package/src/kit/stories/prefabs-finder.ts +54 -0
  367. package/src/kit/stories/prefabs-from-stories.ts +182 -0
  368. package/src/kit/stories/project-story-regions.ts +24 -0
  369. package/src/kit/stories/story-capture.ts +579 -0
  370. package/src/kit/stories/story-declared-medium.ts +126 -0
  371. package/src/kit/stories/story-discovery.ts +176 -0
  372. package/src/kit/stories/story-dom-runtime.ts +78 -0
  373. package/src/kit/stories/story-grouping.ts +111 -0
  374. package/src/kit/stories/story-mount-turn.ts +27 -0
  375. package/src/kit/stories/story-presentation.ts +215 -0
  376. package/src/kit/stories/story-preview-component.ts +7 -0
  377. package/src/kit/stories/story-registry.ts +530 -0
  378. package/src/kit/stories-scope.ts +35 -0
  379. package/src/kit/story-document-openers.ts +36 -0
  380. package/src/kit/story-thumbnails.ts +47 -0
  381. package/src/kit/surface-keyboard.ts +101 -0
  382. package/src/kit/surface-state.ts +135 -0
  383. package/src/kit/system-seam-evidence.ts +72 -0
  384. package/src/kit/tab-census.ts +202 -0
  385. package/src/kit/tab-lifecycle-client.ts +227 -0
  386. package/src/kit/theme-library.ts +897 -0
  387. package/src/kit/theme-preference.ts +429 -0
  388. package/src/kit/three-viewport-presentation.ts +23 -0
  389. package/src/kit/tool-contribution-play.ts +74 -0
  390. package/src/kit/tool-loader.ts +1918 -0
  391. package/src/kit/transform-mode-request.ts +66 -0
  392. package/src/kit/transient-hint.ts +78 -0
  393. package/src/kit/transport-strip.tsx +174 -0
  394. package/src/kit/ui-source/adapter-region-includes.ts +238 -0
  395. package/src/kit/ui-source/file-region-resolver.ts +302 -0
  396. package/src/kit/ui-source/inspect.ts +775 -0
  397. package/src/kit/ui-source/source-write-backend.ts +605 -0
  398. package/src/kit/ui-source/tier-source-write-backend.ts +279 -0
  399. package/src/kit/user-local-state.ts +105 -0
  400. package/src/kit/viewport-activation-timings.ts +840 -0
  401. package/src/kit/viewport-editor-controls.ts +22 -0
  402. package/src/kit/viewport-presentation.ts +668 -0
  403. package/src/kit/viewport-surface-status.tsx +55 -0
  404. package/src/kit/wait-until.ts +37 -0
  405. package/src/kit/worker-call-metrics.ts +166 -0
  406. package/src/kit/workspace-areas.ts +191 -0
  407. package/src/kit/workspace-aux-commands.ts +11 -0
  408. package/src/kit/workspace-available-documents.ts +142 -0
  409. package/src/kit/workspace-core-utilities.ts +31 -0
  410. package/src/kit/workspace-document-ids.ts +59 -0
  411. package/src/kit/workspace-document-registry.ts +624 -0
  412. package/src/kit/workspace-document-restore.ts +146 -0
  413. package/src/kit/workspace-host-commands.ts +141 -0
  414. package/src/kit/workspace-persistence-gate.ts +40 -0
  415. package/src/kit/workspace-play-utilities.ts +44 -0
  416. package/src/kit/workspace-presets.ts +446 -0
  417. package/src/kit/workspace-regions.ts +276 -0
  418. package/src/kit/workspace-static-panels.ts +73 -0
  419. package/src/kit/workspace-status-registry.ts +121 -0
  420. package/src/kit/workspace-storage.ts +35 -0
  421. package/src/kit/workspace-style.ts +226 -0
  422. package/src/kit/workspace-utility-commands.ts +74 -0
  423. package/src/kit/workspace-utility-registry.ts +263 -0
  424. package/src/kit/world-adoption-event.ts +23 -0
  425. package/src/kit/world-adoption.ts +115 -0
  426. package/src/kit/world-canvas-viewport-state.ts +35 -0
  427. package/src/kit/world-document-routing.ts +104 -0
  428. package/src/kit/world-pan-state.ts +198 -0
  429. package/src/kit/write-pipe.ts +173 -0
  430. package/src/layout-arrangements.ts +5 -0
  431. package/src/layouts.tsx +108 -0
  432. package/src/looks.ts +16 -0
  433. package/src/project/output-roots.ts +73 -0
  434. package/src/project/tab-census.ts +155 -0
  435. package/src/project-tool-catalog.ts +104 -0
  436. package/src/selection.tsx +107 -0
  437. package/src/services.ts +18 -0
  438. package/src/session/build-report.ts +22 -0
  439. package/src/session/collaboration-types.ts +262 -0
  440. package/src/session/command-table.ts +327 -0
  441. package/src/session/discovery.ts +100 -0
  442. package/src/session/editor-brand.ts +48 -0
  443. package/src/session/editor-compatibility.ts +317 -0
  444. package/src/session/editor-control-lifecycle.ts +68 -0
  445. package/src/session/editor-control-protocol.ts +5 -0
  446. package/src/session/entrypoint-selection-readers.ts +66 -0
  447. package/src/session/entrypoint-selection-source.ts +120 -0
  448. package/src/session/game-css-scope.ts +30 -0
  449. package/src/session/hosted-attachment.ts +225 -0
  450. package/src/session/limited-view.ts +82 -0
  451. package/src/session/product-create.ts +24 -0
  452. package/src/session/product-locator.ts +478 -0
  453. package/src/session/project-module-url.ts +242 -0
  454. package/src/session/project-serving.ts +164 -0
  455. package/src/session/project-upgrade.ts +403 -0
  456. package/src/session/registry-format.ts +210 -0
  457. package/src/session/relative-path-guard.ts +56 -0
  458. package/src/session/scoped-game-css.ts +461 -0
  459. package/src/session/source-glob.ts +15 -0
  460. package/src/session/tool-contribution-convention.ts +123 -0
  461. package/src/session/workbench-locator.ts +712 -0
  462. package/src/session.ts +41 -0
  463. package/src/share.ts +160 -0
  464. package/src/source-analysis.ts +28 -0
  465. package/src/source-authoring.ts +439 -0
  466. package/src/tools/errors.ts +91 -0
  467. package/src/tools/provider-execution.ts +70 -0
  468. package/src/tools/registry.ts +341 -0
  469. package/src/tools/types.ts +159 -0
  470. package/src/transport.ts +100 -0
  471. package/src/types.ts +1693 -0
  472. package/src/views.ts +164 -0
  473. package/src/widgets/design-system.ts +93 -0
  474. package/src/widgets/editor-appearance.ts +151 -0
  475. package/src/widgets/editor-material.ts +83 -0
  476. package/src/widgets/icon-set-registry.ts +105 -0
  477. package/src/widgets/index.ts +71 -0
  478. package/src/widgets/inspector-widgets/AlignmentGrid.tsx +182 -0
  479. package/src/widgets/inspector-widgets/AssetSlotPicker.tsx +123 -0
  480. package/src/widgets/inspector-widgets/BorderEditor.tsx +309 -0
  481. package/src/widgets/inspector-widgets/ColorPicker.tsx +549 -0
  482. package/src/widgets/inspector-widgets/CurveEditor.tsx +359 -0
  483. package/src/widgets/inspector-widgets/FilterEditor.tsx +108 -0
  484. package/src/widgets/inspector-widgets/FontPicker.tsx +191 -0
  485. package/src/widgets/inspector-widgets/GradientEditor.tsx +623 -0
  486. package/src/widgets/inspector-widgets/ScrubbableInput.tsx +180 -0
  487. package/src/widgets/inspector-widgets/ShadowEditor.tsx +319 -0
  488. package/src/widgets/inspector-widgets/color-utils.ts +201 -0
  489. package/src/widgets/inspector-widgets/curve-utils.ts +212 -0
  490. package/src/widgets/inspector-widgets/index.ts +25 -0
  491. package/src/widgets/inspector-widgets/shared.tsx +140 -0
  492. package/src/widgets/interactive-edit-scope.ts +33 -0
  493. package/src/widgets/patterns/Dialog.tsx +140 -0
  494. package/src/widgets/patterns/Fields.tsx +44 -0
  495. package/src/widgets/patterns/List.tsx +25 -0
  496. package/src/widgets/patterns/StateSurface.tsx +40 -0
  497. package/src/widgets/patterns/Surfaces.tsx +122 -0
  498. package/src/widgets/patterns/Tabs.tsx +80 -0
  499. package/src/widgets/patterns/Toolbar.tsx +72 -0
  500. package/src/widgets/patterns/Tree.tsx +72 -0
  501. package/src/widgets/primitives/AnchoredMenu.tsx +260 -0
  502. package/src/widgets/primitives/Button.tsx +62 -0
  503. package/src/widgets/primitives/ColorInput.tsx +78 -0
  504. package/src/widgets/primitives/DraftTextInput.tsx +63 -0
  505. package/src/widgets/primitives/EditorIcon.tsx +157 -0
  506. package/src/widgets/primitives/FormControls.tsx +88 -0
  507. package/src/widgets/primitives/HoverPreview.tsx +96 -0
  508. package/src/widgets/primitives/JsonInput.tsx +113 -0
  509. package/src/widgets/primitives/Layout.tsx +100 -0
  510. package/src/widgets/primitives/Menu.tsx +161 -0
  511. package/src/widgets/primitives/NumberInput.tsx +169 -0
  512. package/src/widgets/primitives/Panel.tsx +80 -0
  513. package/src/widgets/primitives/SectionHeader.tsx +77 -0
  514. package/src/widgets/primitives/Text.tsx +54 -0
  515. package/src/widgets/primitives/ThemeRootPortal.tsx +52 -0
  516. package/src/widgets/primitives/Tooltip.tsx +204 -0
  517. package/src/widgets/primitives/Vec3Input.tsx +70 -0
  518. package/src/widgets/primitives/banner-tones.ts +32 -0
  519. package/src/widgets/primitives/clamp-to-viewport.ts +44 -0
  520. package/src/widgets/primitives/editor-icons.ts +254 -0
  521. package/src/widgets/primitives/panel-header-styles.ts +42 -0
  522. package/src/widgets/theme.ts +2841 -0
  523. package/src/widgets/z-index.ts +25 -0
@@ -0,0 +1,320 @@
1
+ /**
2
+ * THE EDIT TAB ROW, as pure logic — what the adapter's scene table means for
3
+ * the workspace's open documents.
4
+ *
5
+ * ARCHITECTURE-CORE §Editor: "the scene table (entries, default, authorable
6
+ * flags, reach) is ONE adapter declaration with two clients — the Edit tab row
7
+ * projects it as isolation documents through the substrate family's piece
8
+ * mounts, and Play's `open()` walks it as live navigation." This module is the
9
+ * decision half of the FIRST client; `components/scene-documents.tsx` is the
10
+ * half that talks to the workspace registry, and `command-listener.ts`'s
11
+ * `open` verb resolves ONE entry through the very same table below — so the
12
+ * tab row and the verb can never disagree about what an entry is.
13
+ *
14
+ * ZERO INFERENCE. Every answer here is read off a DECLARED field of the
15
+ * entry — `authorable`, `reach`, `source`, `region`. Nothing is derived from a
16
+ * folder, a filename, a root, or the shape of the project: an entry the
17
+ * adapter did not declare simply is not here, and an entry it declared
18
+ * unreachable stays unreachable with the game's own reason attached.
19
+ */
20
+
21
+ import { getProjectStoryModules } from '@volter/sdk/kit/stories/story-registry';
22
+ import type { DocumentEntry, SceneSource } from '@volter/project/adapter/adapter-module';
23
+ import type { ResolvedDocumentTable } from './project-adapter';
24
+
25
+ /** Document-id namespace for a per-scene isolation document. Distinct from
26
+ * `three-story:` ids (the story turntable, `@volter/editor-game`'s): a scene is
27
+ * reached through the entrypoint's own selection table, not through a story,
28
+ * and the two can legitimately name the same composition. */
29
+ export const SCENE_DOCUMENT_PREFIX = 'scene:';
30
+
31
+ /** The workspace document id for one entrypoint-selection scene entry. */
32
+ export function sceneDocumentId(entryId: string): string {
33
+ return `${SCENE_DOCUMENT_PREFIX}${entryId}`;
34
+ }
35
+
36
+ /** A standing isolation tab — `scene:TitleScreen`, not `workspace:scene`. */
37
+ export function isIsolationSceneDocumentId(id: string): boolean {
38
+ return id.startsWith(SCENE_DOCUMENT_PREFIX);
39
+ }
40
+
41
+ /**
42
+ * What the Edit workspace does with ONE scene-table entry.
43
+ *
44
+ * `no-document` is not a failure — a traversal entry and a declared-unreachable
45
+ * one are both honest table rows that simply own no Edit document. Its `reason`
46
+ * is the game's OWN sentence whenever the game supplied one (a `none` reach
47
+ * carries its `reason` verbatim), so a refusal quotes the adapter rather than
48
+ * paraphrasing it.
49
+ */
50
+ export type SceneDocumentPlan =
51
+ /** Mounting the region IS opening this scene — it is the root's own standing
52
+ * document, which this entry merely NAMES. No second document. */
53
+ | { readonly kind: 'root-document'; readonly regionId: string; readonly title: string }
54
+ /** A viewport document of its own, mounting `source` in isolation. */
55
+ | {
56
+ readonly kind: 'isolation-document';
57
+ readonly documentId: string;
58
+ readonly title: string;
59
+ /** Owning root, carried into the document so its declared region — not
60
+ * its filename or export shape — decides the mounting surface. */
61
+ readonly regionId: string | null;
62
+ readonly source: SceneSource;
63
+ readonly isolationSetup?: SceneSource;
64
+ /** Present when this piece is also a running-game screen. Play's `open`
65
+ * still navigates live; Edit mounts the source in isolation and never
66
+ * holds the live host. */
67
+ readonly contractSceneId?: string;
68
+ }
69
+ /** A portable story mounts it — the existing story-document opener owns it. */
70
+ | { readonly kind: 'story-document'; readonly title: string; readonly storyId: string }
71
+ /**
72
+ * No Edit document, with the reason stated.
73
+ *
74
+ * `liveReach` separates "no document, and nothing else either" from "no
75
+ * document BECAUSE this scene is REACHED live" — the Edit workspace treats
76
+ * both the same (neither is a tab), while the `open` verb must route the
77
+ * second to the running game instead of refusing it, and must tell a caller
78
+ * with no game running to start one rather than that the scene is a dead end.
79
+ *
80
+ * Present means the live half REACHES this entry — it opens it and answers
81
+ * ok. Absent means it does not, which is two different things and
82
+ * deliberately one field: the live half may have no business with the entry
83
+ * at all (it answers `null` for `story`/`none`). A session that cannot
84
+ * remount still refuses `entrypoint-selection` coded; that is a session
85
+ * fact, not a reach fact — the intended path is remount-at-key and ends
86
+ * `ok: true`. {@link liveReachOf} is where that line is drawn.
87
+ *
88
+ * It is derived from REACH ALONE ({@link liveReachOf}), never from
89
+ * `authorable`, because the live half is the authority on this half of the
90
+ * question and it reads reach only (`scene-live-open.ts` switches on
91
+ * `entry.reach.kind`). A planner that also asked `authorable` here would call
92
+ * a screen the running game navigates to a dead end — the exact collapse this
93
+ * field exists to prevent.
94
+ */
95
+ | {
96
+ readonly kind: 'no-document';
97
+ readonly reason: string;
98
+ readonly liveReach?: 'game-contract' | 'root-mount' | 'entrypoint-selection';
99
+ };
100
+
101
+ /**
102
+ * THE ONE DERIVATION of `liveReach`, from the entry's DECLARED reach and
103
+ * nothing else — never from `authorable`, so the two clients cannot disagree.
104
+ *
105
+ * It answers for exactly the reaches `openLiveSceneEntry` REACHES: it
106
+ * navigates a `game-contract` scene through the game's own contract, it
107
+ * shows the document a `root-mount` scene draws into, and it remounts play
108
+ * at an `entrypoint-selection` key. All three end `ok: true` when the
109
+ * session can honour them, so for all three the honest Edit-half refusal
110
+ * with nothing running is `SCENE_NAVIGATION_NOT_RUNNING` — start the game
111
+ * and ask again.
112
+ *
113
+ * A session that cannot remount still refuses `entrypoint-selection` with
114
+ * `SCENE_NOT_OPENABLE_LIVE` — that is the same shape as a `game-contract`
115
+ * scene whose running game publishes no contract (`SCENE_CONTRACT_UNAVAILABLE`).
116
+ * The field names the intended live path, not every session's ability to
117
+ * walk it.
118
+ *
119
+ * A spread rather than a value so `exactOptionalPropertyTypes` gets an ABSENT
120
+ * key for "no live reach", never an explicit `undefined`. Every `no-document`
121
+ * return below spreads it unconditionally — the two where it is currently
122
+ * provably empty included — so this function stays the SOLE decider and a
123
+ * later widening cannot leave a branch silently behind.
124
+ */
125
+ function liveReachOf(entry: DocumentEntry): {
126
+ readonly liveReach?: 'game-contract' | 'root-mount' | 'entrypoint-selection';
127
+ } {
128
+ const { kind } = entry.reach;
129
+ return kind === 'game-contract' || kind === 'root-mount' || kind === 'entrypoint-selection'
130
+ ? { liveReach: kind }
131
+ : {};
132
+ }
133
+
134
+ /**
135
+ * Plan ONE entry.
136
+ *
137
+ * Order matters: `authorable` is asked FIRST because a traversal entry
138
+ * (boot/loading choreography) earns no column whatever its reach — the flag is
139
+ * about what the entry IS, while reach is about how the running game gets
140
+ * there.
141
+ *
142
+ * That order decides the DOCUMENT, and only the document. `liveReach` is
143
+ * carried through it untouched: whether a running game can be sent to a screen
144
+ * is the game's contract's business, not the host's opinion of whether the
145
+ * screen is worth authoring, and the live half honours that by reading reach
146
+ * alone.
147
+ */
148
+ export function planSceneDocument(entry: DocumentEntry): SceneDocumentPlan {
149
+ if (!entry.authorable) {
150
+ return {
151
+ kind: 'no-document',
152
+ ...liveReachOf(entry),
153
+ reason:
154
+ `"${entry.id}" is declared TRAVERSAL (boot/loading choreography), not an authorable ` +
155
+ 'composition, so it has no Edit document.',
156
+ };
157
+ }
158
+ switch (entry.reach.kind) {
159
+ case 'none':
160
+ // VERBATIM. The adapter wrote this sentence about its own game; a host
161
+ // paraphrase would be the host claiming to know why.
162
+ return { kind: 'no-document', ...liveReachOf(entry), reason: entry.reach.reason };
163
+ case 'root-mount':
164
+ return entry.region === null
165
+ ? {
166
+ // Still LIVE-REACHED: `openLiveSceneEntry` shows the document the
167
+ // running game draws into and never looks at `region`, so the
168
+ // missing region costs this entry its Edit document and nothing
169
+ // else.
170
+ kind: 'no-document',
171
+ ...liveReachOf(entry),
172
+ reason:
173
+ `"${entry.id}" is reached by mounting a region, but the entry names no region, ` +
174
+ 'so there is no standing document it could be.',
175
+ }
176
+ : { kind: 'root-document', regionId: entry.region, title: entry.label };
177
+ case 'entrypoint-selection':
178
+ // ACTIVE means the entrypoint indexes its selection table with THIS key,
179
+ // so the region's standing document already mounts this composition —
180
+ // opening a second document for it would show the same thing twice under
181
+ // two titles. The entry names the standing document instead, exactly as
182
+ // `root-mount` does. A region-less entry keeps the isolation document:
183
+ // there is no honest mapping from "active" to a document without one, and
184
+ // inventing a region is what zero-inference forbids.
185
+ if (entry.reach.active === true && entry.region !== null) {
186
+ return { kind: 'root-document', regionId: entry.region, title: entry.label };
187
+ }
188
+ return entry.source
189
+ ? {
190
+ kind: 'isolation-document',
191
+ documentId: sceneDocumentId(entry.id),
192
+ title: entry.label,
193
+ regionId: entry.region,
194
+ source: entry.source,
195
+ ...(entry.isolationSetup ? { isolationSetup: entry.isolationSetup } : {}),
196
+ }
197
+ : {
198
+ kind: 'no-document',
199
+ ...liveReachOf(entry),
200
+ reason:
201
+ `"${entry.id}" is selected at the entrypoint's \`${entry.reach.selection}\` slot, ` +
202
+ 'but the finder could not resolve the module it names, so there is nothing to ' +
203
+ 'mount in isolation.',
204
+ };
205
+ case 'game-contract':
206
+ // Authorable + a source module is an Edit piece: every authorable scene
207
+ // gets a tab (ARCHITECTURE-CORE §Editor). Play still navigates live
208
+ // through `liveReach`. Without a source there is nothing to isolate, so
209
+ // Edit stays silent and `open` asks the running game.
210
+ return entry.source
211
+ ? {
212
+ kind: 'isolation-document',
213
+ documentId: sceneDocumentId(entry.id),
214
+ title: entry.label,
215
+ regionId: entry.region,
216
+ source: entry.source,
217
+ ...(entry.isolationSetup ? { isolationSetup: entry.isolationSetup } : {}),
218
+ contractSceneId: entry.reach.sceneId,
219
+ }
220
+ : {
221
+ kind: 'no-document',
222
+ ...liveReachOf(entry),
223
+ reason:
224
+ `"${entry.id}" is reached only through the running game's own navigation ` +
225
+ `(its scenes contract calls it "${entry.reach.sceneId}"), and the entry names no ` +
226
+ 'source module, so there is no Edit document — open it while the game is running.',
227
+ };
228
+ case 'story':
229
+ return { kind: 'story-document', title: entry.label, storyId: entry.reach.storyId };
230
+ }
231
+ }
232
+
233
+ /** One row of the Edit tab row. */
234
+ export interface SceneTabRow {
235
+ readonly entry: DocumentEntry;
236
+ /** Never `no-document` — a row that owns no document is not a tab. */
237
+ readonly plan: Exclude<SceneDocumentPlan, { kind: 'no-document' }>;
238
+ /** The table's declared default entry. At most one row carries it. */
239
+ readonly isDefault: boolean;
240
+ }
241
+
242
+ /**
243
+ * The whole Edit tab row: every AUTHORABLE SCENE the table declares that owns
244
+ * a document, in the table's own order.
245
+ *
246
+ * Prefabs are excluded deliberately, and they are not second-class for it: a
247
+ * prefab already surfaces through the boards and Content, and it opens as a
248
+ * sibling document on demand through the same verb (`open`). What a standing
249
+ * TAB means is "this is one of the game's scenes", which is exactly the
250
+ * `kind: 'scene'` declaration.
251
+ */
252
+ export function sceneTabRow(table: ResolvedDocumentTable): readonly SceneTabRow[] {
253
+ const rows: SceneTabRow[] = [];
254
+ for (const entry of table.entries) {
255
+ if (entry.kind !== 'scene') continue;
256
+ const plan = planSceneDocument(entry);
257
+ if (plan.kind === 'no-document') continue;
258
+ rows.push({ entry, plan, isDefault: table.default === entry.id });
259
+ }
260
+ return rows;
261
+ }
262
+
263
+ /** What Edit and Content actually present from one resolved scene table. */
264
+ export function authoringSurfaceFromTable(
265
+ table: ResolvedDocumentTable,
266
+ openDocumentIds: readonly string[],
267
+ availableDocumentIds: readonly string[],
268
+ ): {
269
+ readonly sceneDocuments: number;
270
+ readonly isolationDocuments: number;
271
+ readonly openIsolationDocuments: number;
272
+ readonly availableIsolationDocuments: number;
273
+ readonly pieces: number;
274
+ /** Entries of kind `scene` — the surface prefabs are placed on; a table
275
+ * with none (a models or website project) has no prefabs by design. */
276
+ readonly sceneEntries: number;
277
+ /** Project story modules that did not load or compose: each one's prefab is missing from
278
+ * the table with no entry of its own to say so. */
279
+ readonly storyFailures: number;
280
+ } {
281
+ const tabs = sceneTabRow(table);
282
+ const isolationIds = tabs.flatMap((row) =>
283
+ row.plan.kind === 'isolation-document' ? [row.plan.documentId] : [],
284
+ );
285
+ const open = new Set(openDocumentIds);
286
+ const available = new Set(availableDocumentIds);
287
+ // A finder's OWN document kind (a `model` from `@volter/editor-blender`'s finder, a
288
+ // `page`, a `shot`) opens through that kind's document, never through the
289
+ // scene plan above — which answers `no-document` for it because it names
290
+ // no region. Those are documents Edit presents all the same; measured
291
+ // 2026-09-17, a models project reported "no authorable scene with a
292
+ // document to open" beside its open model document.
293
+ const kindDocuments = table.entries.filter(
294
+ (entry) => entry.authorable && entry.kind !== 'scene' && entry.kind !== 'prefab',
295
+ ).length;
296
+ return {
297
+ sceneDocuments: tabs.length + kindDocuments,
298
+ isolationDocuments: isolationIds.length,
299
+ openIsolationDocuments: isolationIds.filter((id) => open.has(id)).length,
300
+ availableIsolationDocuments: isolationIds.filter((id) => available.has(id)).length,
301
+ pieces: table.entries.filter((entry) => entry.kind === 'prefab').length,
302
+ sceneEntries: table.entries.filter((entry) => entry.kind === 'scene').length,
303
+ storyFailures: getProjectStoryModules().filter((module_) => !module_.ok).length,
304
+ };
305
+ }
306
+
307
+ /**
308
+ * Isolation tabs ARE the Edit scene row. A generic Scene tab
309
+ * (`workspace:scene` / `workspace:canvas-scene`) would be a second surface
310
+ * for the same game — the live host, or an empty world — and only belongs
311
+ * when this table has no isolation documents (or also names a root document
312
+ * that Scene already is).
313
+ */
314
+ export function isolationTabsReplaceGenericScene(table: ResolvedDocumentTable): boolean {
315
+ const rows = sceneTabRow(table);
316
+ return (
317
+ rows.some((row) => row.plan.kind === 'isolation-document') &&
318
+ !rows.some((row) => row.plan.kind === 'root-document')
319
+ );
320
+ }
@@ -0,0 +1,210 @@
1
+ /**
2
+ * THE SCENE TABLE'S SECOND CLIENT — `open()` against the RUNNING game.
3
+ *
4
+ * ARCHITECTURE-CORE §Editor: "the scene table … is ONE adapter declaration with
5
+ * two clients — the Edit tab row projects it as isolation documents … and
6
+ * Play's `open()` walks it as live navigation." `scene-document-plan.ts` +
7
+ * `components/scene-documents.tsx` are the first client; this module is the
8
+ * second, and both are reached through the ONE `open` verb in
9
+ * `command-listener.ts`, which asks this one first whenever a game is live.
10
+ *
11
+ * ZERO INFERENCE, twice over:
12
+ *
13
+ * 1. WHICH contract id an entry is, is the adapter's own declaration
14
+ * (`reach: { kind: 'game-contract', sceneId }`). Nothing here matches
15
+ * entry ids against contract ids, or assumes the two vocabularies coincide.
16
+ * 2. WHETHER that id is navigable is the GAME's answer, at the moment of use:
17
+ * the switch goes through the bound scenes projection's own
18
+ * `goToScene` (`authoring/contract-scenes-stories.ts`), which validates
19
+ * membership against the game's own `list()` and carries the mount's
20
+ * held-repaint seam. Calling the contract's `goTo` directly would route
21
+ * around both.
22
+ *
23
+ * Every seam is injected ({@link LiveSceneSession}) so the whole matrix is
24
+ * decidable headlessly — no mounted game, no workspace, no browser.
25
+ */
26
+
27
+ import type { LiveSceneTable } from '@volter/sdk/host';
28
+ import type { DocumentEntry } from '@volter/project/adapter/adapter-module';
29
+
30
+ /** What a live game session offers this verb. */
31
+ export interface LiveSceneSession {
32
+ /**
33
+ * The running game's BOUND scenes projection, or `null` when the game
34
+ * publishes none.
35
+ *
36
+ * "Bound" is load-bearing: this is the object the mount installed on the
37
+ * game's own authoring adapter — the same one the inspector's scene picker
38
+ * drives — so a switch made here is the same switch a click makes, held
39
+ * repaint and all.
40
+ */
41
+ readonly scenes: () => LiveSceneTable | null;
42
+ /**
43
+ * Activate the document the running game is presented in; `false` when the
44
+ * session has none open. An ingested game's mount IS the running game, and
45
+ * it draws into the Game document — there is no second document a
46
+ * `root-mount` scene could name.
47
+ */
48
+ readonly activateGameDocument: () => boolean;
49
+ /** The Game document's id, for the answer. */
50
+ readonly gameDocumentId: string;
51
+ /**
52
+ * Host remount of a native swap-slot scene: stop this play run and start a
53
+ * new one with the entrypoint's selection const rewritten to `key`. Absent
54
+ * when this session has no serve-time rewrite (an ingest root), which is
55
+ * when `entrypoint-selection` still refuses `SCENE_NOT_OPENABLE_LIVE`.
56
+ */
57
+ readonly remountSelection?: (args: {
58
+ readonly selection: string;
59
+ readonly key: string;
60
+ readonly regionId: string;
61
+ }) => Promise<{ readonly ok: true } | { readonly ok: false; readonly error: string }>;
62
+ }
63
+
64
+ /** A coded refusal from the live half — the SDK matches `code`, never prose. */
65
+ export interface LiveSceneOpenRefusal {
66
+ readonly ok: false;
67
+ readonly code:
68
+ | 'SCENE_CONTRACT_UNAVAILABLE'
69
+ | 'SCENE_NOT_IN_CONTRACT'
70
+ | 'SCENE_SWITCH_FAILED'
71
+ | 'SCENE_NOT_OPENABLE_LIVE'
72
+ | 'SCENE_DOCUMENT_NOT_MOUNTED';
73
+ readonly error: string;
74
+ /** The ids the game itself published, when the refusal is about membership. */
75
+ readonly known?: readonly string[];
76
+ }
77
+
78
+ export type LiveSceneOpenResult =
79
+ | {
80
+ readonly ok: true;
81
+ readonly documentId: string;
82
+ readonly title: string;
83
+ /** The game's own answer: what was asked for, and where it ended up. */
84
+ readonly scene?: { readonly requested: string; readonly current: string | null };
85
+ /**
86
+ * Present when this open restarted play rather than navigating a live
87
+ * contract — the swap slot is a module-level const, so the honest
88
+ * live path is remount-at-key.
89
+ */
90
+ readonly restart?: true;
91
+ }
92
+ | LiveSceneOpenRefusal;
93
+
94
+ /**
95
+ * Open ONE scene-table entry against the running game, or answer `null` when
96
+ * this entry is not the live half's business — a `story` reach has a portable
97
+ * mount, and a `none` reach is the adapter's own declared dead end. Both are
98
+ * the Edit half's, unchanged, and answering `null` is how this module says so
99
+ * rather than duplicating those refusals.
100
+ */
101
+ export async function openLiveSceneEntry(
102
+ entry: DocumentEntry,
103
+ session: LiveSceneSession,
104
+ ): Promise<LiveSceneOpenResult | null> {
105
+ switch (entry.reach.kind) {
106
+ case 'game-contract': {
107
+ const scenes = session.scenes();
108
+ if (!scenes) {
109
+ return {
110
+ ok: false,
111
+ code: 'SCENE_CONTRACT_UNAVAILABLE',
112
+ error:
113
+ `open: "${entry.id}" is reached through the running game's own scenes contract, ` +
114
+ 'and the game running in this session publishes none (`window.volterGame.scenes`).',
115
+ };
116
+ }
117
+ const switched = scenes.goToScene(entry.reach.sceneId);
118
+ if (!switched.ok) {
119
+ // The projection's own membership refusal, passed through: the game's
120
+ // `list()` is the authority on what it can be sent to, and a host
121
+ // paraphrase would be the host claiming to know the game's screens.
122
+ return {
123
+ ok: false,
124
+ code: 'SCENE_NOT_IN_CONTRACT',
125
+ error: `open: "${entry.id}" — ${switched.error}`,
126
+ known: switched.known,
127
+ };
128
+ }
129
+ const settled = await switched.settled;
130
+ if (settled.error !== undefined) {
131
+ return {
132
+ ok: false,
133
+ code: 'SCENE_SWITCH_FAILED',
134
+ error: `open: "${entry.id}" — the game's own navigation failed: ${settled.error}`,
135
+ };
136
+ }
137
+ // Activation is best-effort AFTER the switch: the navigation is the
138
+ // gesture, and a session with no Game document open (headless control,
139
+ // a workspace the user rearranged) still navigated the game.
140
+ session.activateGameDocument();
141
+ return {
142
+ ok: true,
143
+ documentId: session.gameDocumentId,
144
+ title: entry.label,
145
+ scene: { requested: settled.requested, current: settled.current },
146
+ };
147
+ }
148
+ case 'root-mount': {
149
+ // The running game IS this scene — mounting the region opened it — so the
150
+ // whole gesture is showing the document it draws into. REACHED, so the
151
+ // planner carries it as `liveReach: 'root-mount'` and the Edit half
152
+ // grades a no-game session `SCENE_NAVIGATION_NOT_RUNNING`: start the
153
+ // game and this returns ok. babylon-space-truckers' `splashScreen` is
154
+ // the shipped instance (`authorable: false`, so it owns no Edit
155
+ // document — pressing ▶ is the whole answer, not a defect in its
156
+ // declaration).
157
+ if (!session.activateGameDocument()) {
158
+ return {
159
+ ok: false,
160
+ code: 'SCENE_DOCUMENT_NOT_MOUNTED',
161
+ error: `open: "${entry.id}" is the running game itself, and no game document is open in this session.`,
162
+ };
163
+ }
164
+ return { ok: true, documentId: session.gameDocumentId, title: entry.label };
165
+ }
166
+ case 'entrypoint-selection': {
167
+ // The slot is a module-level CONST — the running module cannot change
168
+ // scenes. The honest live path is a host remount: stop this play run and
169
+ // start a new one with the entrypoint served at `key`. That is REAL
170
+ // navigation (the next mount executes that key), stated as a restart.
171
+ // A session with no remount seam (hosted bundle, ingest) still refuses
172
+ // coded — never an in-place fake.
173
+ const remount = session.remountSelection;
174
+ const regionId = entry.region;
175
+ if (!remount || regionId === null) {
176
+ return {
177
+ ok: false,
178
+ code: 'SCENE_NOT_OPENABLE_LIVE',
179
+ error:
180
+ `open: "${entry.id}" sits at the entrypoint's \`${entry.reach.selection}\` swap slot, ` +
181
+ 'and this session has no live remount for a native swap-slot scene — a running game ' +
182
+ 'cannot be sent there in place. Stop the game and open it as a document instead.',
183
+ };
184
+ }
185
+ const remounted = await remount({
186
+ selection: entry.reach.selection,
187
+ key: entry.reach.key,
188
+ regionId,
189
+ });
190
+ if (!remounted.ok) {
191
+ return {
192
+ ok: false,
193
+ code: 'SCENE_SWITCH_FAILED',
194
+ error: `open: "${entry.id}" — remount at \`${entry.reach.selection}["${entry.reach.key}"]\` failed: ${remounted.error}`,
195
+ };
196
+ }
197
+ session.activateGameDocument();
198
+ return {
199
+ ok: true,
200
+ documentId: session.gameDocumentId,
201
+ title: entry.label,
202
+ scene: { requested: entry.reach.key, current: entry.reach.key },
203
+ restart: true,
204
+ };
205
+ }
206
+ case 'story':
207
+ case 'none':
208
+ return null;
209
+ }
210
+ }
@@ -0,0 +1,152 @@
1
+ /**
2
+ * The client half of SCOPED GAME CSS — fetch the open project's page-level
3
+ * stylesheet (already rewritten into `@scope ([data-volter-game-styles])` by
4
+ * `@volter/sdk/session/scoped-game-css`), install it ONCE, and report honestly when
5
+ * there is nothing to install.
6
+ *
7
+ * ONE `<style>` element per project, never one per surface. Every container
8
+ * that owns game DOM — each UI-board story card's content, each story
9
+ * document's preview, the ingest surface the game mounts into — becomes a
10
+ * scope root by wearing the attribute (`markGameCssScope`, `game-css-scope.ts`),
11
+ * and the single scoped sheet paints all of them. Duplicating the sheet per
12
+ * card would multiply a foreign game's whole stylesheet by the size of the
13
+ * board for no behavioural difference at all.
14
+ *
15
+ * ## The refusal path is the point
16
+ *
17
+ * A surface that shows a game's DOM with no page CSS looks BROKEN, not empty —
18
+ * the owner hit exactly that three times before this existed and read it as
19
+ * wreckage, because nothing on screen said what was missing. So this module's
20
+ * state is a value the surfaces read (`note`), not a silent side effect: a
21
+ * board card whose project declares no stylesheet, or whose stylesheet could
22
+ * not be read, or a browser with no `@scope`, says so on the card.
23
+ *
24
+ * `@scope` is the feature detection and it is deliberately a REFUSAL, not a
25
+ * fallback: without it the served sheet's `:scope` rules would not be
26
+ * contained, and installing it anyway would restyle the editor — the precise
27
+ * failure the whole feature exists to prevent.
28
+ */
29
+
30
+ import { editorConsole } from '@volter/sdk/kit/editor-console';
31
+ import { editorServerJson } from '@volter/sdk/kit/editor-server-response';
32
+
33
+ /** What the open project's game CSS turned out to be. */
34
+ export interface ScopedGameStylesState {
35
+ /** True once the project's scoped stylesheet is attached to the document. */
36
+ readonly installed: boolean;
37
+ /** The declared stylesheet paths that were served, in emission order. */
38
+ readonly sources: readonly string[];
39
+ /**
40
+ * Surface-facing sentence naming what is missing, or `null` when the host
41
+ * has no evidence of a gap. Rendered ON a story card rather than logged,
42
+ * because the card is where the missing styling is SEEN.
43
+ */
44
+ readonly note: string | null;
45
+ }
46
+
47
+ const NOTHING_DECLARED: ScopedGameStylesState = { installed: false, sources: [], note: null };
48
+
49
+ /** `data-*` marker on the one installed element, so a re-install can find it. */
50
+ const STYLE_ELEMENT_MARKER = 'data-volter-scoped-game-css';
51
+
52
+ /** Per-project memo: the fetch+install runs once per open project, not per card. */
53
+ let pending: { projectRoot: string; state: Promise<ScopedGameStylesState> } | null = null;
54
+
55
+ /** Latest resolved state, for the synchronous readers (a board painting notes). */
56
+ let resolved: ScopedGameStylesState = NOTHING_DECLARED;
57
+
58
+ /** The installed sheet's own text — see {@link scopedGameStylesCssText}. */
59
+ let installedCss: string | null = null;
60
+
61
+ /**
62
+ * The installed stylesheet's text, or null when none is installed.
63
+ *
64
+ * Exists for ONE reader: the DOM capture leg (`composite-screenshot.ts`),
65
+ * which rasterizes a DETACHED clone of the surface through an SVG
66
+ * `foreignObject`. A detached fragment carries no document stylesheet, so
67
+ * without re-inlining this the look verb would photograph a correctly styled
68
+ * screen as unstyled — an instrument disagreeing with the product it is
69
+ * pointed at, which is worse than no instrument. (The same leg already
70
+ * re-inlines its motion freeze for the same structural reason.)
71
+ */
72
+ export function scopedGameStylesCssText(): string | null {
73
+ return installedCss;
74
+ }
75
+
76
+ /**
77
+ * True when this browser implements CSS `@scope`. Without it the served sheet
78
+ * cannot be contained, so nothing is installed at all.
79
+ */
80
+ function supportsCssScope(): boolean {
81
+ return typeof (globalThis as { CSSScopeRule?: unknown }).CSSScopeRule === 'function';
82
+ }
83
+
84
+ /**
85
+ * Fetch and install the open project's scoped game stylesheet, at most once per
86
+ * project. Safe to call from every surface that mounts game DOM — later calls
87
+ * await the same promise.
88
+ */
89
+ export async function ensureScopedGameStyles(projectRoot: string): Promise<ScopedGameStylesState> {
90
+ if (pending?.projectRoot === projectRoot) return pending.state;
91
+ const state = loadScopedGameStyles(projectRoot);
92
+ pending = { projectRoot, state };
93
+ return state;
94
+ }
95
+
96
+ /**
97
+ * The most recent resolved state. Surfaces that paint a note read this
98
+ * synchronously AFTER awaiting {@link ensureScopedGameStyles} — it exists so a
99
+ * board does not have to thread the promise through its own layout pass.
100
+ */
101
+ export function scopedGameStylesState(): ScopedGameStylesState {
102
+ return resolved;
103
+ }
104
+
105
+ async function loadScopedGameStyles(projectRoot: string): Promise<ScopedGameStylesState> {
106
+ const next = await fetchScopedGameStyles(projectRoot);
107
+ resolved = next;
108
+ return next;
109
+ }
110
+
111
+ async function fetchScopedGameStyles(projectRoot: string): Promise<ScopedGameStylesState> {
112
+ let payload: { css?: unknown; sources?: unknown; note?: unknown };
113
+ try {
114
+ const response = await fetch('/__editor/scoped-game-css');
115
+ // A page fallback in front of the route fails the reader below and lands
116
+ // in the same graceful no-op story discovery takes. Nothing is claimed
117
+ // about the project's styling.
118
+ payload = await editorServerJson<typeof payload>(
119
+ response,
120
+ 'Could not read the project scoped game CSS',
121
+ );
122
+ } catch {
123
+ return NOTHING_DECLARED;
124
+ }
125
+
126
+ const css = typeof payload.css === 'string' ? payload.css : '';
127
+ const sources = Array.isArray(payload.sources) ? (payload.sources as string[]) : [];
128
+ const note = typeof payload.note === 'string' ? payload.note : null;
129
+
130
+ if (css.length === 0) return { installed: false, sources, note };
131
+
132
+ if (!supportsCssScope()) {
133
+ const refusal =
134
+ 'unstyled — this browser has no CSS `@scope`, so the game stylesheet cannot be contained ' +
135
+ 'to the game. Loading it anyway would restyle the editor.';
136
+ editorConsole.warn(`[scoped-game-css] ${refusal}`, 'authoring');
137
+ return { installed: false, sources, note: refusal };
138
+ }
139
+
140
+ installStyleElement(projectRoot, css);
141
+ return { installed: true, sources, note };
142
+ }
143
+
144
+ /** Attach (or replace) the ONE style element carrying the project's game CSS. */
145
+ function installStyleElement(projectRoot: string, css: string): void {
146
+ const existing = document.head.querySelector(`style[${STYLE_ELEMENT_MARKER}]`);
147
+ const element = existing instanceof HTMLStyleElement ? existing : document.createElement('style');
148
+ element.setAttribute(STYLE_ELEMENT_MARKER, projectRoot);
149
+ element.textContent = css;
150
+ if (!element.isConnected) document.head.appendChild(element);
151
+ installedCss = css;
152
+ }