@volter/sdk 0.0.0-stage → 0.5.204

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 +1168 -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 +329 -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 +669 -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,777 @@
1
+ import {
2
+ type ActiveDocumentCapture,
3
+ type CaptureDimensions,
4
+ EDITOR_VIEW_DOCUMENT_KINDS,
5
+ EDITOR_VIEW_DIAGNOSTICS,
6
+ EDITOR_VIEW_KEYS,
7
+ EDITOR_VIEW_TOOL_UTILITY_PREFIX,
8
+ type EditorView,
9
+ editorViewUrl,
10
+ isEditorViewDocumentKind,
11
+ type PresentedEditorView,
12
+ } from '@volter/sdk';
13
+ import type { StoryRef } from '@volter/project/adapter';
14
+ import { getActiveAuthoring } from '@volter/sdk/kit/authoring/active-adapter';
15
+ import { type DocumentViewport, documentViewport } from '@volter/sdk/kit/document-viewports';
16
+ import { setViewGridVisible, viewPresentationBinding } from '@volter/sdk/kit/viewport-presentation';
17
+ import { openRegisteredDocumentAsync, registeredDocumentOpenerIds } from '@volter/sdk/kit/document-open-registry';
18
+ import { currentEditorView } from './editor-current-view';
19
+ import { activeDocumentContainer } from './editor-document-probe';
20
+ import { framedCapture } from '@volter/sdk/kit/framed-document-capture';
21
+ import type { ShellStore } from '@volter/sdk/kit/shell-store';
22
+ import { activeEditorKeymap } from '@volter/sdk/kit/keymap-presets';
23
+ import { liveFrameCanvas, liveInstanceContainer } from '@volter/sdk/kit/live-session-registry';
24
+ import { projectDocumentKinds } from '@volter/sdk/kit/project-shape';
25
+ import { DOCUMENT_REGISTRATION_TIMEOUT_MS, waitUntil } from '@volter/sdk/kit/wait-until';
26
+ import { GAME_DOCUMENT_ID } from '@volter/sdk/kit/workspace-document-ids';
27
+ import {
28
+ activateWorkspaceDocument,
29
+ activeWorkspaceDocument,
30
+ activeWorkspaceDocumentId,
31
+ openWorkspaceDocuments,
32
+ workspaceDocumentSelection,
33
+ } from '@volter/sdk/kit/workspace-document-registry';
34
+ import { openAvailableWorkspaceDocument } from '@volter/sdk/kit/workspace-available-documents';
35
+ import {
36
+ activeWorkspaceStaticPanel,
37
+ showWorkspaceStaticPanel,
38
+ showWorkspaceUtility,
39
+ } from '@volter/sdk/kit/workspace-host-commands';
40
+ import {
41
+ activeEditorWorkspace,
42
+ editorWorkspaceIds,
43
+ isEditorWorkspaceId,
44
+ setEditorWorkspace,
45
+ whenEditorWorkspaceApplied,
46
+ } from '@volter/sdk/kit/workspace-presets';
47
+ import { WORKSPACE_STATIC_PANELS, type WorkspaceStaticPanelKind } from '@volter/sdk/kit/workspace-static-panels';
48
+ import { applyWorkspaceStyle, workspaceStyles } from '@volter/sdk/kit/workspace-style';
49
+ import {
50
+ availableWorkspaceUtilities,
51
+ subscribeWorkspaceUtilities,
52
+ } from '@volter/sdk/kit/workspace-utility-registry';
53
+ import {
54
+ activateRootDocument,
55
+ rootDocumentGap,
56
+ workspaceDocumentGap,
57
+ } from './world-document-routing';
58
+
59
+ async function captureLiveCanvasFrame(
60
+ canvas: HTMLCanvasElement,
61
+ ): Promise<CanvasImageSource | null> {
62
+ const { liveCanvasFrame } = await import('@volter/sdk/kit/live-canvas-frame');
63
+ return liveCanvasFrame(canvas);
64
+ }
65
+
66
+ /**
67
+ * THE TWO LAZY DOORS, and the reason they are lazy rather than plain imports:
68
+ * THIS FILE IS A DOOR EVERY PACKAGE CALLS (`packages/blender/host/
69
+ * blender-runtime-host.ts:32` imports `presentEditorView`), so whatever it
70
+ * reaches statically, a package that merely wants to present a view PAYS FOR.
71
+ * Measured 2026-09-18 (phase 1 unit 14): after the five document families left
72
+ * for the registry, these two edges were the WHOLE remainder of the game realm
73
+ * shim in this closure — `composite-screenshot` → the two game-CSS scopers,
74
+ * and `tool-loader` → `browser-project-scripts` → `browser-transpile` →
75
+ * `gated-globals` and the six realm modules behind it, plus
76
+ * `creation-site-registry` and (via `account.ts`) `editor-session-attribution`.
77
+ * Neither belongs to PRESENTING anything: one is the capture path for the Game
78
+ * document, the other is the project-tool discovery a LATE utility address
79
+ * drives. Both call sites are already async, and both modules are eagerly
80
+ * loaded by the shell itself long before either runs, so the import resolves
81
+ * from cache. `captureLiveCanvasFrame` above is the precedent this transcribes.
82
+ */
83
+ async function captureComposite(
84
+ ...args: Parameters<typeof import('@volter/sdk/kit/composite-screenshot').capturePlayComposite>
85
+ ) {
86
+ const { capturePlayComposite } = await import('@volter/sdk/kit/composite-screenshot');
87
+ return capturePlayComposite(...args);
88
+ }
89
+
90
+ async function projectToolContributions() {
91
+ return import('@volter/sdk/kit/tool-loader');
92
+ }
93
+
94
+ /**
95
+ * THE THIRD LAZY DOOR, for the same reason and by the same precedent as the
96
+ * two above — and it is the one the unit's own measurement missed. After the
97
+ * families left and those two edges went lazy, this file still reached TWO
98
+ * files of the four buckets phase 1 item 13 named, not one: the notice module
99
+ * is `collaboration and presence` by the inventory's own bucket, imported here
100
+ * statically since long before the cut. The other,
101
+ * `editor-session-attribution`, arrives `keymap-presets -> settings-store ->
102
+ * api/settings -> storage/index -> http-storage` — the storage backend's own
103
+ * edge, a 'keep' chain, and the collaboration package's question.
104
+ *
105
+ * The precondition the precedent requires holds: `AppRoot ->
106
+ * DefaultEditorLayout -> AgentPresentationNotice` loads this module at boot,
107
+ * so in a real editor the import resolves from cache, and the call site is
108
+ * already async. Notifying is not PRESENTING: a package that calls this door
109
+ * must not carry the shell's notice surface to do it.
110
+ */
111
+ async function presentationNotice() {
112
+ return import('./editor-presentation-notice');
113
+ }
114
+
115
+ /**
116
+ * Reveal the bottom-drawer utility a view names — the ONE door onto the
117
+ * drawer, routing to the same `showWorkspaceUtility` reveal a menu click uses.
118
+ *
119
+ * Every id names a utility id, and a `tool:` one names a tab a PACKAGE or the
120
+ * OPEN PROJECT contributes (`tool-loader.ts` registers each
121
+ * `workspace.utility` contribution as `tool:<contribution-id>` in the
122
+ * registry's `project` cluster). Which of those exist depends entirely on
123
+ * what is installed, so existence is checked HERE, against the live registry:
124
+ * `showWorkspaceUtility` silently ignores an id it cannot find, which is
125
+ * precisely the "the door did nothing and said nothing" failure this door
126
+ * exists to prevent.
127
+ */
128
+ function waitForWorkspaceUtility(id: string, timeoutMs = 5_000): Promise<void> {
129
+ if (availableWorkspaceUtilities().some((item) => item.id === id)) return Promise.resolve();
130
+ return new Promise((resolve) => {
131
+ let timeout = 0;
132
+ let unsubscribe = () => {};
133
+ const finish = () => {
134
+ clearTimeout(timeout);
135
+ unsubscribe();
136
+ resolve();
137
+ };
138
+ unsubscribe = subscribeWorkspaceUtilities(() => {
139
+ if (availableWorkspaceUtilities().some((item) => item.id === id)) finish();
140
+ });
141
+ if (availableWorkspaceUtilities().some((item) => item.id === id)) finish();
142
+ else timeout = window.setTimeout(finish, timeoutMs);
143
+ });
144
+ }
145
+
146
+ async function revealUtility(utility: EditorView['utility']): Promise<void> {
147
+ if (!utility) return;
148
+ if (!availableWorkspaceUtilities().some((item) => item.id === utility)) {
149
+ // A cold Vite graph can register the project catalog before its
150
+ // contribution modules finish loading — the same race the `tool` ADDRESS
151
+ // resolves in its own `settle`, by driving the owning discovery pass
152
+ // rather than racing it.
153
+ const contributed = utility.startsWith(EDITOR_VIEW_TOOL_UTILITY_PREFIX);
154
+ if (contributed) {
155
+ await (await projectToolContributions()).refreshProjectToolContributions();
156
+ // Discovery can already have started another refresh. The pass above
157
+ // then yields to that newer epoch rather than publishing stale results;
158
+ // wait for its registry publication before deciding the deep link is
159
+ // broken. This is event-driven and bounded so a genuinely absent tool
160
+ // still gets the teaching error below.
161
+ await waitForWorkspaceUtility(utility);
162
+ }
163
+ if (!availableWorkspaceUtilities().some((item) => item.id === utility)) {
164
+ const registered = availableWorkspaceUtilities().map((item) => item.id);
165
+ const hint = contributed
166
+ ? (await projectToolContributions()).contributionFailureHint(
167
+ utility.slice(EDITOR_VIEW_TOOL_UTILITY_PREFIX.length),
168
+ )
169
+ : '';
170
+ throw new Error(
171
+ `Utility is not registered: ${utility}.` +
172
+ hint +
173
+ ` Registered utilities: ${registered.length > 0 ? registered.join(', ') : '(none)'}.` +
174
+ ' A project contributes one by exporting a `workspace.utility` tool contribution;' +
175
+ ' its view id is `tool:<contribution-id>`.',
176
+ );
177
+ }
178
+ }
179
+ showWorkspaceUtility(utility);
180
+ }
181
+
182
+ /**
183
+ * Focus a static workspace panel by key — the ONE resolution behind the
184
+ * session verb (`show-panel`) and a view's `panel`, routing to the same
185
+ * `showWorkspaceStaticPanel` reveal the Window menu's own items use.
186
+ *
187
+ * The vocabulary is read from the static-panel REGISTRY at call time, never
188
+ * kept by hand here: a door with its own list is how `showPanel` came to know
189
+ * five names and none of the seven panels a human can click. An unknown key
190
+ * refuses naming the keys the registry holds; a key the registry holds but
191
+ * this layout does not show (the Inspector under its compact presentation,
192
+ * the Conversations panel with the harness collapsed) refuses saying so,
193
+ * because a silent no-op is the same failure one layer in.
194
+ */
195
+ export async function revealStaticPanel(panel: string): Promise<WorkspaceStaticPanelKind> {
196
+ const kinds = WORKSPACE_STATIC_PANELS.map((entry) => entry.kind);
197
+ const kind = kinds.find(
198
+ (candidate): candidate is WorkspaceStaticPanelKind => candidate === panel,
199
+ );
200
+ if (!kind) {
201
+ throw new Error(`"${panel}" is not a panel of this editor. Panels: ${kinds.join(', ')}.`);
202
+ }
203
+ showWorkspaceStaticPanel(kind);
204
+ if (!(await waitUntil(() => activeWorkspaceStaticPanel() === kind))) {
205
+ throw new Error(
206
+ `The ${kind} panel is not in this workspace's layout, so it could not be focused. ` +
207
+ `Panels: ${kinds.join(', ')}.`,
208
+ );
209
+ }
210
+ return kind;
211
+ }
212
+
213
+ type ViewDocument<K extends NonNullable<EditorView['document']>['kind']> = Extract<
214
+ NonNullable<EditorView['document']>,
215
+ { kind: K }
216
+ >;
217
+
218
+ /**
219
+ * Reveal the workspace scene document.
220
+ *
221
+ * `path` is purely PROVENANCE here — the active adapter's persistence
222
+ * destination, whatever its format — so restoring this view activates the
223
+ * scene surface and lets its adapter own what is on it. Nothing fetches or
224
+ * parses the path.
225
+ */
226
+ function openSceneView(_store: ShellStore, _document: ViewDocument<'scene'>) {
227
+ if (activateWorkspaceDocument('workspace:scene')) return 'workspace:scene';
228
+ // Refused rather than reported as presented: a session whose surface is another document
229
+ // (a product's Game tab) has no Scene tab to move to.
230
+ const open = openWorkspaceDocuments().map((entry) => entry.descriptor.id);
231
+ throw new Error(
232
+ 'This session has no Scene document open. Open documents: ' +
233
+ `${open.join(', ') || 'none'}; address one as { kind: "workspace", id }.`,
234
+ );
235
+ }
236
+
237
+ /**
238
+ * Reveal the edit-time document that owns a manifest root.
239
+ *
240
+ * The wait is for the BOOT RACE — a root's document is installed
241
+ * asynchronously, and an explicit view is durable intent, so a document that is
242
+ * merely late must still land. It is NOT a way to discover that a root has no
243
+ * document at all: `rootDocumentGap` is that answer, registered by whoever owns
244
+ * the decision, and it ends the wait the moment it exists.
245
+ *
246
+ * MEASURED, and the reason this branch exists: a `dom` root in a project with
247
+ * no UI board sat here for the full registration window and then threw the
248
+ * generic "not registered" — by which time the asking side (the eval relay
249
+ * gives up at ~5 s) had already reported a timeout against an unresponsive
250
+ * page. The truth was decided within the first second and nobody ever heard it.
251
+ */
252
+ async function openRootView(document: ViewDocument<'world'>) {
253
+ let activated = false;
254
+ await waitUntil(() => {
255
+ activated = activateRootDocument(document.id);
256
+ return activated || rootDocumentGap(document.id) !== null;
257
+ }, DOCUMENT_REGISTRATION_TIMEOUT_MS);
258
+ if (activated) return activeWorkspaceDocumentId();
259
+ const gap = rootDocumentGap(document.id);
260
+ if (gap) throw new Error(gap);
261
+ throw new Error(`World document is not registered: ${document.id}`);
262
+ }
263
+
264
+ /**
265
+ * The board story selector (design ledger item 4): resolve the address's
266
+ * `story` against THE BOARD'S OWN provider and apply it through the same seam
267
+ * a board click uses. Unknown or ambiguous refuses loudly WITH the candidates:
268
+ * a view that silently opened the default frame would hand back a confident
269
+ * capture of the wrong story.
270
+ *
271
+ * MEASURED, AND CHANGED, 2026-09-18 (unit 11, edge 8). This used to resolve
272
+ * against the project story REGISTRY (id / export name / label) and then check
273
+ * that the board's provider would accept the id anyway — so the provider's own
274
+ * list was always the real answer and the registry read was a detour. It is
275
+ * the only story edge in this file that is not a registry question at heart:
276
+ * `StoriesProvider` is the CONTRACT and stays host. `StoryRef` carries
277
+ * `{ id, label }`, so an address may name a story by either; the one spelling
278
+ * that no longer resolves is the CSF EXPORT name where an author gave the
279
+ * story a different display name, and the refusal now lists exactly what this
280
+ * board will accept.
281
+ */
282
+ async function applyBoardStory(documentId: string, requested: string): Promise<void> {
283
+ const matching = (stories: readonly StoryRef[]) =>
284
+ stories.filter((candidate) => candidate.id === requested || candidate.label === requested);
285
+ let known: readonly StoryRef[] = [];
286
+ const reached = await waitUntil(() => {
287
+ // The BOARD's own adapter, through its registered per-document selection
288
+ // (the same seam waitForAssetDocumentInspector reads) — the store's
289
+ // active-authoring pointer may still be the previous document's, and
290
+ // applying an unknown story id there is a measured warn-and-ignore.
291
+ const provider = workspaceDocumentSelection(documentId)?.adapter?.stories;
292
+ if (!provider) return false;
293
+ known = provider.storiesFor('');
294
+ const matches = matching(known);
295
+ if (matches.length === 1) {
296
+ provider.apply(matches[0]!.id, matches[0]!.id);
297
+ return true;
298
+ }
299
+ // A provider that has listed SOMETHING has answered; waiting longer will
300
+ // not turn an unknown name into a known one.
301
+ return known.length > 0;
302
+ }, DOCUMENT_REGISTRATION_TIMEOUT_MS);
303
+ if (!reached) {
304
+ throw new Error(
305
+ `The board mounted no stories provider within the wait window; story ` +
306
+ `${JSON.stringify(requested)} was not applied.`,
307
+ );
308
+ }
309
+ const matches = matching(known);
310
+ if (matches.length === 1) return;
311
+ throw new Error(
312
+ matches.length === 0
313
+ ? `No story matches ${JSON.stringify(requested)}. This board's stories: ` +
314
+ `${known.map((candidate) => candidate.label).join(', ') || '(none)'}.`
315
+ : `${JSON.stringify(requested)} is ambiguous (${matches.length} stories match) — ` +
316
+ `use the story id: ${matches.map((candidate) => candidate.id).join(' | ')}`,
317
+ );
318
+ }
319
+
320
+ /**
321
+ * A workspace id is the ONE address with two answers, and the order is the
322
+ * point: a module that CONSTRUCTS a workspace document under that id (the
323
+ * account document, the project-tools catalog) claims it through the registry
324
+ * first; everything else is a document some other part of the session has
325
+ * already opened, which the host activates by id out of its own registry. The
326
+ * host used to spell the two constructed ids here by hand.
327
+ */
328
+ async function openWorkspaceView(store: ShellStore, document: ViewDocument<'workspace'>) {
329
+ const claimed = await openRegisteredDocumentAsync(document.kind, store, document);
330
+ if (claimed !== null) return claimed;
331
+ // Pinned component boards are registered from asynchronous story-media
332
+ // discovery. A URL is durable intent, so wait for the same bounded project
333
+ // bootstrap window as a manifest-world route instead of treating the first
334
+ // pre-registration read as proof that the document does not exist — and end
335
+ // that wait the instant the session can SAY the document is never coming
336
+ // (`workspaceDocumentGap`, the same seam and the same reasoning as
337
+ // `openRootView` above). MEASURED before this branch existed: a workspace id
338
+ // this project has no document for burned the whole 10 s window and then
339
+ // reported the generic "not available", by which time the eval relay had
340
+ // already given up at ~5 s and filed a `play-stall` error against a tab that
341
+ // was answering fine.
342
+ let activated = false;
343
+ await waitUntil(() => {
344
+ // An available document a package registered opens on this request; an
345
+ // open one is activated.
346
+ activated =
347
+ openAvailableWorkspaceDocument(document.id) || activateWorkspaceDocument(document.id);
348
+ return activated || workspaceDocumentGap(document.id) !== null;
349
+ }, DOCUMENT_REGISTRATION_TIMEOUT_MS);
350
+ if (activated) {
351
+ if (document.story !== undefined) await applyBoardStory(document.id, document.story);
352
+ return document.id;
353
+ }
354
+ const gap = workspaceDocumentGap(document.id);
355
+ if (gap) throw new Error(gap);
356
+ throw new Error(`Workspace document is not available: ${document.id}`);
357
+ }
358
+
359
+ /**
360
+ * A VIEW ADDRESS IS AN OPENER ID. Every document kind the host does not
361
+ * construct itself is asked of `document-open-registry.ts` under its OWN kind:
362
+ * a package that can open that kind registers an opener there, and the host
363
+ * addresses the document without importing one (WORKBENCH.md §host versus
364
+ * package). A build whose package list carries no opener for the kind refuses
365
+ * by name rather than pretending — the same honest `null` an undeclared story
366
+ * medium has always given.
367
+ */
368
+ async function openDelegatedView(
369
+ store: ShellStore,
370
+ document: NonNullable<EditorView['document']>,
371
+ ): Promise<string> {
372
+ const opened = await openRegisteredDocumentAsync(document.kind, store, document);
373
+ if (opened === null) {
374
+ // The SUBJECT as the address spelled it — an id where the kind has one, the
375
+ // rest of the address where it does not (a story names a module and an
376
+ // export). The host does not know which fields a kind carries, so it prints
377
+ // what it was given rather than reaching for one field's name.
378
+ const { kind, ...subject } = document as { kind: string } & Record<string, unknown>;
379
+ const registered = registeredDocumentOpenerIds();
380
+ throw new Error(
381
+ `Nothing in this editor can open a '${kind}' document (${JSON.stringify(subject)}). ` +
382
+ `Either no package registered an opener for that view address, or the subject ` +
383
+ `does not exist. Registered view addresses: ` +
384
+ `${registered.length > 0 ? registered.join(', ') : '(none)'}.`,
385
+ );
386
+ }
387
+ return opened;
388
+ }
389
+
390
+ /**
391
+ * The second sentence of the refusal above, read from the PROJECT'S OWN
392
+ * document table rather than from a list written here — `project-shape`'s
393
+ * supplier is the resolved table's kinds, which is what makes "model" an
394
+ * answerable mistake instead of an unknown word.
395
+ */
396
+ function documentKindAdvice(kind: string): string {
397
+ const kinds = projectDocumentKinds();
398
+ if (kinds === null) return '';
399
+ if (kinds.includes(kind)) {
400
+ return (
401
+ `"${kind}" is a kind in this project's document table, not an address — a document opens ` +
402
+ `in the editor registered for its KIND, so address it as ` +
403
+ `{ kind: "document", id: "<that table entry's id>" }.`
404
+ );
405
+ }
406
+ if (kinds.length === 0) return '';
407
+ return (
408
+ `This project's document table holds ${kinds.map((one) => `"${one}"`).join(', ')}; ` +
409
+ 'each opens as { kind: "document", id: "<the table entry\'s id>" }.'
410
+ );
411
+ }
412
+
413
+ async function openRequestedDocument(
414
+ store: ShellStore,
415
+ document: EditorView['document'],
416
+ ): Promise<string | null> {
417
+ if (!document) return activeWorkspaceDocumentId();
418
+ // AN UNRECOGNIZED KIND IS A REFUSAL, exactly as an unrecognized KEY is
419
+ // (`presentEditorView`'s own note). The switch below is exhaustive over the
420
+ // published union, so TypeScript is satisfied — and at RUNTIME a kind outside
421
+ // it fell off the end, returned `undefined`, and presented `ok` having moved
422
+ // nothing, with `view.doc=undefined` in the url it handed back as
423
+ // confirmation. Measured on `{kind: 'model', path: …}`, which is the most
424
+ // likely mistake there is: `model` IS a real kind, of a row in the project's
425
+ // document table, and a table row's address is `{kind: 'document', id}`.
426
+ if (!isEditorViewDocumentKind(document.kind)) {
427
+ throw new Error(
428
+ `present-view does not know the document kind "${String(document.kind)}". ` +
429
+ `An EditorView addresses a document by one of: ${EDITOR_VIEW_DOCUMENT_KINDS.join(', ')}. ` +
430
+ documentKindAdvice(String(document.kind)),
431
+ );
432
+ }
433
+ switch (document.kind) {
434
+ // THE HOST'S OWN TWO, and they construct nothing: the scene surface is a
435
+ // fixed workspace id, and a manifest root's document is routed by
436
+ // `world-document-routing.ts`, the seam whoever owns a root registers into.
437
+ case 'scene':
438
+ return openSceneView(store, document);
439
+ case 'world':
440
+ return openRootView(document);
441
+ // EVERY OTHER KIND IS AN ADDRESS. Resolving a story's module and export,
442
+ // what an asset extension means and when its Inspector is ready, which
443
+ // editor a table entry's KIND opens in and what that document's id turns
444
+ // out to be, which contribution a tool id names — all of it is the kind's
445
+ // own job, answered through `document-open-registry.ts` by whichever
446
+ // module (host family or package) registered that address. The switch
447
+ // stays exhaustive because the ADDRESS SPACE is `@volter/sdk`'s
448
+ // `EditorView`, published and finite; the implementations are not the
449
+ // host's.
450
+ case 'asset':
451
+ case 'tool':
452
+ case 'document':
453
+ case 'story':
454
+ case 'project-tool':
455
+ case 'generation':
456
+ return openDelegatedView(store, document);
457
+ case 'workspace':
458
+ return openWorkspaceView(store, document);
459
+ }
460
+ }
461
+
462
+ function captureDataUrl(dataUrl: string): Pick<ActiveDocumentCapture, 'base64' | 'mimeType'> {
463
+ const comma = dataUrl.indexOf(',');
464
+ return { base64: comma >= 0 ? dataUrl.slice(comma + 1) : dataUrl, mimeType: 'image/png' };
465
+ }
466
+
467
+ /** The capture and the scoped probe (`editor-document-probe.ts`) must never
468
+ * disagree about which element IS the active document, so they share one
469
+ * lookup rather than two copies of the same query. */
470
+ const activeDocumentContent = activeDocumentContainer;
471
+
472
+ /**
473
+ * A BLACK FRAME IS NOT AN ANSWER — the refusal text when a document holding a
474
+ * live three ingest's own canvas photographs blank, or `null` when it did not.
475
+ *
476
+ * MEASURED (a probe of public/ingest/three-clipping-intersection): the Game
477
+ * document came back "~100% one flat surface (#000000)" and the walk filed it
478
+ * as that ingestion's play evidence until the flatness measure caught it.
479
+ *
480
+ * The mechanism is NOT that the document is empty — an ingested three game's
481
+ * own canvas IS mounted in it. It is that the canvas is the GAME'S, created
482
+ * without `preserveDrawingBuffer`, so its pixels are readable only from inside
483
+ * the game's own render pass (`ingest/ingest-frame-snapshot.ts` arms exactly
484
+ * that bracket). When the game does not draw inside the snapshot window — a
485
+ * render-on-demand world sitting idle, or a loop the Edit-tab input gate has
486
+ * frozen — the read falls back to a late `drawImage` and the browser hands
487
+ * back the discarded buffer: black, silently, in a PNG that looks like a real
488
+ * photograph.
489
+ *
490
+ * Gated on the composite's OWN degeneracy rather than on the route alone: a
491
+ * three ingest that IS drawing photographs correctly through this door and
492
+ * must keep doing so.
493
+ */
494
+ function ingestBlankFrameRefusal(
495
+ documentId: string,
496
+ content: Element,
497
+ flatness: { degenerate: boolean; warning?: string } | undefined,
498
+ ): string | null {
499
+ if (!flatness?.degenerate) return null;
500
+ const gameCanvas = liveFrameCanvas();
501
+ if (!gameCanvas || !content.contains(gameCanvas)) return null;
502
+ return (
503
+ `This door photographs the "${documentId}" document, which for a live three ingest holds the ` +
504
+ "GAME'S own canvas — created without `preserveDrawingBuffer`, so its pixels can only be read " +
505
+ "from inside the game's own render pass. This game did not draw inside that window (a " +
506
+ 'render-on-demand world sitting idle, or a loop the Edit-tab input gate has frozen), so the ' +
507
+ `frame came back BLANK (${flatness.warning ?? 'essentially one flat colour'}) — a PNG that reads ` +
508
+ "as a real image. The editor's own renderer is drawing this same world in the Scene viewport " +
509
+ '(the mount adopts the captured scene), so capture `workspace:scene` instead — or drive the ' +
510
+ 'game until it renders and ask again.'
511
+ );
512
+ }
513
+
514
+ /**
515
+ * Capture the active center subject through its native session when one
516
+ * exists, otherwise through the common mounted-document surface.
517
+ *
518
+ * `size` is a square by default and `{width, height}` when a caller wants a
519
+ * shaped frame ({@link CaptureDimensions}). The Object3D document session
520
+ * renders its buffer and camera at that aspect. Composite captures (Scene,
521
+ * Game and DOM documents) photograph the mounted panel at its own size,
522
+ * including its visible overlays, and do not use `size`.
523
+ */
524
+ export async function captureActiveEditorDocument(
525
+ store: ShellStore,
526
+ size?: CaptureDimensions,
527
+ ): Promise<ActiveDocumentCapture> {
528
+ const active = activeWorkspaceDocument();
529
+ if (!active) throw new Error('No active editor document to capture.');
530
+ const { descriptor, title } = active;
531
+ const view = currentEditorView(store);
532
+ const documentInfo = {
533
+ id: descriptor.id,
534
+ title,
535
+ kind: descriptor.kind,
536
+ ...(descriptor.provenance?.sourcePath ? { sourcePath: descriptor.provenance.sourcePath } : {}),
537
+ ...(descriptor.provenance?.rootId ? { rootId: descriptor.provenance.rootId } : {}),
538
+ };
539
+ const stage = documentViewport(descriptor.id);
540
+ if (stage?.capture) {
541
+ const dataUrl = stage.capture(size);
542
+ if (!dataUrl) throw new Error(`Object3D document could not be captured: ${descriptor.id}`);
543
+ return {
544
+ ...captureDataUrl(dataUrl),
545
+ document: documentInfo,
546
+ view,
547
+ source: 'object3d-document',
548
+ };
549
+ }
550
+ // THE GAME DOCUMENT'S SUBJECT IS THE GAME STACK, not the dock panel holding
551
+ // it — `getInstanceContainer()`, exactly what `bridge-screenshot` photographs.
552
+ //
553
+ // MEASURED (canvas ingest, `flappy`): capturing the PANEL put 64% of the
554
+ // frame at alpha 0. `composite-screenshot.ts`'s overlay leg clones the
555
+ // container's CHILDREN into a neutral wrapper, so from the panel those
556
+ // children are editor-CSS-classed layout divs whose styling a detached
557
+ // serialization drops — the game's own surface then lays out against the
558
+ // wrong containing block and contributes nothing, leaving a hole wherever
559
+ // the canvas leg did not draw. From the runtime container the game's surface
560
+ // IS the child, its inline box survives the clone, and the frame is opaque.
561
+ //
562
+ // It also removes a whole class of defect on its own: two doors onto the same
563
+ // pixels that photograph two different elements will disagree, and a reader
564
+ // has no way to tell which one is the game.
565
+ const content =
566
+ descriptor.id === GAME_DOCUMENT_ID
567
+ ? (liveInstanceContainer() ?? activeDocumentContent(descriptor.id))
568
+ : activeDocumentContent(descriptor.id);
569
+ if (!content) throw new Error(`Active document surface is not mounted: ${descriptor.id}`);
570
+ // A document whose subject runs in its own frame (the Build Player) is
571
+ // photographed inside that frame, with the frame's own same-frame pixels.
572
+ const framed = framedCapture(content);
573
+ // `liveCanvasFrame` answers only for a canvas some live surface owns — a
574
+ // registered Pixi `Application` (the `2D` board's exhibits, the first-party
575
+ // canvas root, a canvas ingest) or the three ingest mount's own canvas;
576
+ // every other canvas takes the seam's documented "read it directly" path, so
577
+ // this is inert for every document that presents neither. Without it those
578
+ // canvases photograph blank — a game's own canvas has no
579
+ // `preserveDrawingBuffer`, and this read happens well after its frame. It is
580
+ // the SAME seam `bridge-screenshot` passes, deliberately: two doors onto the
581
+ // same pixels that disagree about which lane they can see is exactly the
582
+ // defect (`live-canvas-frame.ts`).
583
+ const composite = await captureComposite(framed?.container ?? content, {
584
+ canvasFrame: framed?.canvasFrame ?? captureLiveCanvasFrame,
585
+ // The Game document's subject is the game stack and must never inherit
586
+ // editor CSS, nor may a framed game. Every other composite subject is an
587
+ // editor-owned document; its design-system classes are part of what the
588
+ // user is looking at.
589
+ includeDocumentStyles: descriptor.id !== GAME_DOCUMENT_ID && !framed,
590
+ });
591
+ // A blank frame over a live three ingest is REFUSED with its mechanism named
592
+ // rather than handed back as a photograph — see `ingestBlankFrameRefusal`.
593
+ const blank = ingestBlankFrameRefusal(descriptor.id, content, composite.flatness);
594
+ if (blank) throw new Error(blank);
595
+ return {
596
+ base64: composite.base64,
597
+ mimeType: composite.mimeType,
598
+ document: documentInfo,
599
+ view,
600
+ source:
601
+ descriptor.id === GAME_DOCUMENT_ID
602
+ ? 'game-composite'
603
+ : descriptor.id === 'workspace:scene'
604
+ ? 'scene-viewport'
605
+ : 'document-composite',
606
+ layers: composite.layers,
607
+ // The composite already MEASURES whether what it grabbed is a flat,
608
+ // contentless frame (`sampleFlatness`), and `ActiveDocumentCapture`
609
+ // declares the field — this door simply dropped it, so a blank-white
610
+ // headless play frame came back through it looking exactly like a good
611
+ // one. A probe files that frame as an ingestion's evidence, so a
612
+ // degenerate capture that cannot say so is a capture that lies.
613
+ ...(composite.flatness ? { flatness: composite.flatness } : {}),
614
+ };
615
+ }
616
+
617
+ /** The Scene document's id: the viewport a view applies to when the active
618
+ * document has none of its own (the store-level path it always took). */
619
+ const SCENE_DOCUMENT_ID = 'workspace:scene';
620
+
621
+ /**
622
+ * WHICH STAGE THIS VIEW DRIVES — a plain lookup, and deliberately nothing else.
623
+ *
624
+ * A kind declares when its document is ready to be DRIVEN in its own opener's
625
+ * `ready` (`document-open-registry.ts`), and the registry awaits it inside the
626
+ * open `openRequestedDocument` has already performed above. So by the moment
627
+ * this reads, a document that mounts a stage has registered its viewport, and a
628
+ * document that mounts none never will.
629
+ */
630
+ function resolveViewport(documentId: string | null): DocumentViewport | null {
631
+ return documentViewport(documentId) ?? documentViewport(SCENE_DOCUMENT_ID);
632
+ }
633
+
634
+ function applyPresentation(
635
+ store: ShellStore,
636
+ documentId: string | null,
637
+ view: EditorView,
638
+ warnings: string[],
639
+ ): void {
640
+ const own = documentViewport(documentId);
641
+ const stage = resolveViewport(documentId);
642
+ if (view.selection) {
643
+ if (own?.selection) own.selection.apply(view.selection.ids);
644
+ else store.selectMultiple(view.selection.ids);
645
+ }
646
+ const viewport = view.viewport;
647
+ // The grid switch is the DOCUMENT'S OWN view's (`kit/viewport-presentation`), never the
648
+ // Scene's by fallback: a view that no stage binds draws no grid to switch.
649
+ if (viewport?.grid !== undefined) {
650
+ if (documentId && viewPresentationBinding(documentId)) setViewGridVisible(documentId, viewport.grid);
651
+ else warnings.push('This document draws no grid.');
652
+ }
653
+ if (viewport?.diagnostic && !stage?.setDiagnostic(viewport.diagnostic)) {
654
+ warnings.push(`Diagnostic ${viewport.diagnostic} is unavailable for this document.`);
655
+ }
656
+ if (viewport?.camera && !stage?.setCamera(viewport.camera)) {
657
+ warnings.push(
658
+ typeof viewport.camera === 'string'
659
+ ? `${viewport.camera === 'isometric' ? 'Isometric' : viewport.camera} camera is unavailable for this document.`
660
+ : 'The camera is unavailable for this document.',
661
+ );
662
+ }
663
+ if (view.selection?.focus || viewport?.frame === 'selection') {
664
+ if (!stage?.frame('selection')) warnings.push('The requested selection could not be framed.');
665
+ } else if (viewport?.frame === 'document') {
666
+ if (!stage?.frame('document')) warnings.push('Document framing is unavailable for this document.');
667
+ }
668
+ }
669
+
670
+ /**
671
+ * The one imperative presenter behind both the agent wire command and URL
672
+ * restoration. It applies semantic intent to the current workspace layout;
673
+ * it never encodes physical coordinates.
674
+ */
675
+ export async function presentEditorView(
676
+ store: ShellStore,
677
+ view: EditorView,
678
+ options: { updateUrl?: boolean; origin?: 'agent' | 'link' | 'return' } = {},
679
+ ): Promise<PresentedEditorView> {
680
+ if (view?.version !== 1) throw new Error('present-view requires EditorView version 1.');
681
+ if (view.viewport?.diagnostic !== undefined &&
682
+ !(EDITOR_VIEW_DIAGNOSTICS as readonly string[]).includes(view.viewport.diagnostic)) {
683
+ throw new Error(`Unknown viewport diagnostic "${view.viewport.diagnostic}". ` +
684
+ `Use one of: ${EDITOR_VIEW_DIAGNOSTICS.join(', ')}. Material Preview is "preview".`);
685
+ }
686
+ // AN UNRECOGNIZED KEY IS A REFUSAL, not a silent pass-through. Every named
687
+ // field below refuses by name; an unnamed one used to be ignored AND echoed
688
+ // back in the answer, so `{version: 1, kind: 'story', …}` — the document's
689
+ // address spelled one level too high — presented `ok`, moved nothing, and
690
+ // handed the caller its own mistake as confirmation (found live, unit 17).
691
+ // The vocabulary is `@volter/sdk`'s `EDITOR_VIEW_KEYS`, published and
692
+ // finite, so the refusal can be complete.
693
+ const unknown = Object.keys(view).filter(
694
+ (key) => !(EDITOR_VIEW_KEYS as readonly string[]).includes(key),
695
+ );
696
+ if (unknown.length > 0) {
697
+ throw new Error(
698
+ `present-view does not know ${unknown.map((key) => `"${key}"`).join(', ')}. ` +
699
+ `An EditorView carries: ${EDITOR_VIEW_KEYS.join(', ')}. ` +
700
+ `A document's own address (kind, and the fields that kind reads) goes under "document".`,
701
+ );
702
+ }
703
+ const previousView = currentEditorView(store);
704
+ // The style bundle, if named: chrome appearance only, refused by name the
705
+ // way `set-style` refuses — never a silent no-op.
706
+ if (view.style !== undefined) {
707
+ const ids = workspaceStyles().map((bundle) => bundle.id);
708
+ if (!ids.includes(view.style)) {
709
+ throw new Error(
710
+ `present-view requires a style of ${ids.join(', ')}, got ${String(view.style)}.`,
711
+ );
712
+ }
713
+ applyWorkspaceStyle(view.style);
714
+ }
715
+ // The workspace first: a layout decides which documents and utilities the
716
+ // rest of the view can reach. An id the open project does not offer refuses
717
+ // by name, the same sentence as `set-workspace` — never a silent no-op.
718
+ if (view.workspace !== undefined) {
719
+ if (!isEditorWorkspaceId(view.workspace)) {
720
+ throw new Error(
721
+ `present-view requires a workspace of ${editorWorkspaceIds().join(', ')}, got ${String(view.workspace)}.`,
722
+ );
723
+ }
724
+ if (activeEditorWorkspace() !== view.workspace) {
725
+ const rebuilt = whenEditorWorkspaceApplied();
726
+ setEditorWorkspace(view.workspace);
727
+ await Promise.race([rebuilt, new Promise<void>((resolve) => setTimeout(resolve, 3000))]);
728
+ }
729
+ }
730
+ const warnings: string[] = [];
731
+ // The keymap is REPORTED, not presented (see `EditorView.keymap`): a link
732
+ // carrying one says so out loud instead of silently rewriting the bindings
733
+ // of whoever opens it.
734
+ if (view.keymap !== undefined && view.keymap !== activeEditorKeymap()) {
735
+ warnings.push(
736
+ `Keymap "${view.keymap}" was not applied — a view reports the keymap, it does not set it. ` +
737
+ `This project is on "${activeEditorKeymap()}" (its adapter's declaration, or its own settings).`,
738
+ );
739
+ }
740
+ const documentId = await openRequestedDocument(store, view.document);
741
+ await revealUtility(view.utility);
742
+ const own = documentViewport(documentId);
743
+ await own?.prepare?.();
744
+ // A shared scene/world link can arrive before the source-backed hierarchy
745
+ // mounts. Applying selection to that empty shell loses it when the world is
746
+ // adopted. Wait for the owning adapter to expose the requested identities.
747
+ if (
748
+ !own?.selection &&
749
+ view.selection?.ids.length &&
750
+ (view.document?.kind === 'scene' || view.document?.kind === 'world')
751
+ ) {
752
+ const ids = view.selection.ids;
753
+ const ready = await waitUntil(
754
+ () => ids.every((id) => getActiveAuthoring(store).hierarchy.node(id) !== null),
755
+ DOCUMENT_REGISTRATION_TIMEOUT_MS,
756
+ );
757
+ if (!ready) throw new Error(`Shared view selection is not available: ${ids.join(', ')}`);
758
+ }
759
+ // Utility layout reconciliation may restore focus to the previous center
760
+ // tab while an async Object3D document is mounting. Presentation is atomic:
761
+ // after that mount settles, the requested document must be the active one.
762
+ if (documentId && activeWorkspaceDocumentId() !== documentId) {
763
+ activateWorkspaceDocument(documentId);
764
+ }
765
+ applyPresentation(store, documentId, view, warnings);
766
+ // The panel LAST: opening a document and reconciling the utility drawer both
767
+ // take the dock's focus, so a view naming a panel must END on it.
768
+ if (view.panel !== undefined) await revealStaticPanel(view.panel);
769
+
770
+ const url = editorViewUrl(view, window.location.href);
771
+ if (options.updateUrl !== false) window.history.replaceState(window.history.state, '', url);
772
+ const presented = { view, url, warnings };
773
+ if ((options.origin ?? 'agent') === 'agent') {
774
+ (await presentationNotice()).showEditorPresentationNotice({ presented, previousView });
775
+ }
776
+ return presented;
777
+ }