@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
package/src/host.ts ADDED
@@ -0,0 +1,1157 @@
1
+ /**
2
+ * THE HOST DOOR — what a PACKAGE's contribution may read of the running
3
+ * editor (ARCHITECTURE-CORE §The workbench, "direction": a package imports
4
+ * only other packages' exports, never the host's internals).
5
+ *
6
+ * The editor registers this at boot as MODULE STATE, the same door shape as
7
+ * `registerProjectModuleLoader` in `contributions.ts`: the SDK is one
8
+ * identity in the editor's program (Vite dedupes it), so a contribution
9
+ * served from a package sees the editor's registration. The surface is
10
+ * deliberately small and grows one member per contribution that needs it;
11
+ * a member nobody reads is cut.
12
+ *
13
+ * Reading it outside a host — in a test, or a package's own tooling — throws
14
+ * by name rather than answering with an empty session: an inspector that
15
+ * silently reads "no adapter" is a measurement nobody made.
16
+ */
17
+
18
+ import type {
19
+ AudioAdapter,
20
+ NetworkingAdapter,
21
+ StoriesProvider,
22
+ SystemAdapters,
23
+ } from '@volter/project/adapter';
24
+ import type { ComponentType } from 'react';
25
+ import type { DocumentEntry } from '@volter/project/adapter/adapter-module';
26
+ import type { EditorKeyActionId, KeyChord } from '@volter/project/adapter/editor-looks';
27
+ import { useSyncExternalStore } from 'react';
28
+ import type { StageTransportHandle } from './transport';
29
+ import type { ActiveDocumentCapture, CaptureDimensions } from './types';
30
+
31
+ /**
32
+ * THE STORY RUNTIME'S DOORWAY — the URL a package dynamic-imports to reach
33
+ * Storybook's `composeStories`/`setProjectAnnotations` and React DOM's
34
+ * `createRoot`/`flushSync` FROM THE PROJECT'S OWN MODULE GRAPH, rather than
35
+ * from the shell's copy.
36
+ *
37
+ * It is here because it is the host's statement about what it serves, and a
38
+ * package may not reach into the host's build tier to read it: the address
39
+ * lived in `packages/editor-core/vite-plugin-module-doorways.ts`, which serves it,
40
+ * and the story runtime imported it back out through a specifier that stepped
41
+ * out of the editor's `src/` entirely. The plugin still OWNS the
42
+ * doorway — what it serves, and why the mount would otherwise get a second
43
+ * React (its doc comment carries the measured failure) — and now spells the
44
+ * address by importing this constant, so there is one spelling and the package
45
+ * reads it through the published door like any other host fact.
46
+ */
47
+ export const STORY_RUNTIME_PATH = '/__volter-story-runtime';
48
+ /** Project-owned React/Three namespace shared by preview consumers and the server. */
49
+ export const R3F_RUNTIME_PATH = '/__volter-r3f-runtime';
50
+ /** The project's React and react-dom for a React world mount. */
51
+ export const REACT_WORLD_RUNTIME_PATH = '/__volter-react-world-runtime';
52
+ /** The project's Pixi and canvas entry resolver for a canvas root mount. */
53
+ export const CANVAS_RUNTIME_PATH = '/__volter-canvas-runtime';
54
+ /** The project's three.js and post-processing for an ingested three root. */
55
+ export const THREE_INGEST_RUNTIME_PATH = '/__volter-three-ingest-runtime';
56
+
57
+ /** The live session's system adapters, as the editor inspects them: the
58
+ * instance under inspection when several run, the solo one otherwise. */
59
+ export interface EditorHostSystems {
60
+ /** Every adapter the inspected session registered, as one object. */
61
+ inspected(): SystemAdapters;
62
+ /** Fires when the inspected instance or its adapters change. */
63
+ subscribe(listener: () => void): () => void;
64
+ inspectedNetworking(): NetworkingAdapter | null;
65
+ /** Fires when the inspected networking adapter appears, changes or leaves. */
66
+ subscribeNetworking(listener: () => void): () => void;
67
+ inspectedAudio(): AudioAdapter | null;
68
+ /** Fires when the inspected audio adapter appears, changes or leaves. */
69
+ subscribeAudio(listener: () => void): () => void;
70
+ /** Monotonic counter behind {@link subscribeAudio}, for `useSyncExternalStore`. */
71
+ audioVersion(): number;
72
+ }
73
+
74
+ /** The editor's ONE shared availability heartbeat (250ms, refcounted): the
75
+ * signal for out-of-band changes a live session makes without notifying a
76
+ * store — an adapter's connection state, a reader appearing. */
77
+ export interface EditorHostAvailability {
78
+ subscribe(listener: () => void): () => void;
79
+ version(): number;
80
+ }
81
+
82
+ export interface EditorHostWorkspace {
83
+ /** Reveal a bottom-drawer utility by its registered id (`tool:<id>` for a
84
+ * contributed one). */
85
+ showUtility(id: string): void;
86
+ /** Open a contributed `workspace.document` by its contribution id
87
+ * (`my-tool.document`); false when no such document is registered. */
88
+ openContributedDocument(id: string): boolean;
89
+ /**
90
+ * Open a document by ADDRESS — `{ kind, …the kind's own fields }` — through
91
+ * the host's document-open registry. The SDK names NO document kind: the
92
+ * caller spells the address its own package registered (or that another
93
+ * package in the build did), the host routes it, and a kind with no
94
+ * registered opener answers `false` instead of pretending.
95
+ *
96
+ * It is the async form on purpose. A kind may need to SETTLE — re-read the
97
+ * ledger it opens documents out of — before it can answer, which is exactly
98
+ * what a package that just WROTE the subject needs (a generated story,
99
+ * addressed `{ kind: 'story', modulePath, storyName }` the moment the file
100
+ * exists).
101
+ */
102
+ open(address: { readonly kind: string } & Record<string, unknown>): Promise<boolean>;
103
+ readonly liveDocument: EditorHostLiveDocument;
104
+ }
105
+
106
+ export interface LiveDocumentContentProps {
107
+ readonly documentId: string;
108
+ /** Whether the document is the active center tab. */
109
+ readonly active: boolean;
110
+ }
111
+
112
+ /** What a lane renders inside the live document: the panel a runtime mounts
113
+ * into, and its document-local toolbar. */
114
+ export interface LiveDocumentContent {
115
+ readonly Content: ComponentType<LiveDocumentContentProps>;
116
+ readonly Toolbar?: ComponentType<LiveDocumentContentProps>;
117
+ }
118
+
119
+ /**
120
+ * THE LIVE DOCUMENT — the host's one center document for running content
121
+ * (id `workspace:game`, title `Game`). It exists exactly as long as a
122
+ * runtime does: a lane `acquire`s it before mounting (open + activate, then
123
+ * wait for the panel's container to commit) and the host closes it on the
124
+ * playing → stopped edge, handing focus back. The panel's element is the
125
+ * live CONTAINER every lane mounts into; the content that draws the panel
126
+ * is registered by the package that runs things.
127
+ */
128
+ export interface EditorHostLiveDocument {
129
+ readonly id: string;
130
+ register(content: LiveDocumentContent): () => void;
131
+ /** Resolves false when the panel did not commit in time (report it as
132
+ * the lane's own start failure — never mount into nothing). */
133
+ acquire(timeoutMs?: number): Promise<boolean>;
134
+ release(): void;
135
+ open(): boolean;
136
+ container(): HTMLElement | null;
137
+ /** The panel's attach/detach halves — detach is keyed by the element so a
138
+ * stale panel's cleanup never empties a newer panel's slot. */
139
+ setContainer(el: HTMLElement): void;
140
+ releaseContainer(el: HTMLElement): void;
141
+ }
142
+
143
+ /** The open documents, as a contribution may read them. */
144
+ export interface EditorHostDocuments {
145
+ activeId(): string | null;
146
+ /** The active document's kind (`'workspace'`, `'tool-contribution'`, …)
147
+ * and title, or null with none open. */
148
+ active(): { readonly id: string; readonly kind: string; readonly title: string } | null;
149
+ subscribe(listener: () => void): () => void;
150
+ version(): number;
151
+ /**
152
+ * THE DOCUMENT'S OWN PUBLISHED CONTEXT — the one object a document hands the
153
+ * host to be driven through (`editor.document.run(ctx => …)`, the REPL
154
+ * door), or `undefined` when that document published none.
155
+ *
156
+ * NEW (2026-09-19) because the document a package DRIVES is not always the
157
+ * document it opened: `@volter/editor-blender` presents every Blender frame into the
158
+ * Model document, which `@volter/editor-blender` contributes and publishes — so the two
159
+ * packages meet at this registry and neither may reach the host's
160
+ * `@editor/document-context-registry` to find it. The value is `unknown` on
161
+ * purpose: what a document publishes is an agreement between the package
162
+ * that renders it and the package that drives it, and the host is not a
163
+ * party to it — the caller narrows, and refuses by name when the shape is
164
+ * not the one it needs.
165
+ */
166
+ context(documentId: string): unknown;
167
+ /**
168
+ * The same read, where the caller can WAIT. Opening a document activates its
169
+ * tab before an async model import can publish a context, so a driver that
170
+ * read once would mistake a loading document for an unsupported one.
171
+ * Resolves `undefined` when the window elapses.
172
+ */
173
+ waitForContext(documentId: string, timeoutMs?: number): Promise<unknown>;
174
+ /**
175
+ * THE PUBLISHED CONTEXT HAS MOVED — said by the package that DRIVES this
176
+ * document, which is not always the package that published it.
177
+ *
178
+ * NEW (2026-09-19, WORK.md §Blender in the tab is Blender, "Inspection
179
+ * parity", I1) because a context object is a LIVE HANDLE: `@volter/editor-blender`
180
+ * reads the engine through its RNA door, and that answer decides which
181
+ * Properties tabs exist for the selected datablock — an armature has a Bone
182
+ * tab, a cube does not. Nothing in the host's own stores moves when the
183
+ * engine answers, so the inspector had no reason to re-compose and the rail
184
+ * stayed at whatever the first render could see. Calling this re-derives the
185
+ * whole inspection, matches included.
186
+ *
187
+ * It is a notification, not a publication: the context object itself is
188
+ * unchanged, and a document that published none is a no-op.
189
+ */
190
+ contextChanged(documentId: string): void;
191
+ /**
192
+ * The active center document's pixels, taken by the document's own presenter (never another
193
+ * stage's renderer and camera). A viewport whose scene another document adopted answers its
194
+ * capture through here, because the adopter is the one presenting it.
195
+ */
196
+ captureActive(size?: CaptureDimensions): Promise<ActiveDocumentCapture>;
197
+ }
198
+
199
+ /**
200
+ * The project's editor-local state document (`.volter/editor-state.json`):
201
+ * per-project preferences a contribution keeps — pins, collapsed sections —
202
+ * that are neither the game's data nor a person's global settings. One
203
+ * section per contribution, named by it.
204
+ */
205
+ export interface EditorHostProjectLocalState {
206
+ ready(): boolean;
207
+ read<T>(section: string): T | undefined;
208
+ write(section: string, value: unknown): void;
209
+ /** The open project's root path, or null on a tier with none. */
210
+ projectRootPath(): string | null;
211
+ }
212
+
213
+ /**
214
+ * A LANE that mounts something in the tab — Play, an ingested game, a module
215
+ * world — as the host sees it. A package registers its lane and the host asks
216
+ * only these questions; it never names the lane.
217
+ */
218
+ export interface LiveSession {
219
+ readonly id: string;
220
+ /** `stop` order among lanes, low first (Play before ingest). */
221
+ readonly priority?: number;
222
+ /** A real game owns a canvas right now. */
223
+ mounted(): boolean;
224
+ /** Somebody asked the host to RUN content; a held mount is not playing. */
225
+ playing(): boolean;
226
+ /** Idempotent; a no-op when the lane runs nothing. */
227
+ stop(): void;
228
+ /** The element holding a live instance (the primary when `id` is omitted). */
229
+ instanceContainer(id?: string): HTMLElement | null;
230
+ /** When this lane's most recent run began / ended (ms epoch); the host
231
+ * fences per-run diagnostics on the newest window across lanes. */
232
+ startedAt?(): number | null;
233
+ endedAt?(): number | null;
234
+ /** Why the running content is stale (a source edit the run cannot absorb),
235
+ * or null while it is fresh; `restart` is the lane's own re-entry. */
236
+ restartRequired?(): string | null;
237
+ restart?(): void;
238
+ /** Re-mount with an authored selection while running; absent when the lane
239
+ * cannot. */
240
+ remount?(args: LiveRemountArgs): Promise<{ ok: true } | { ok: false; error: string }>;
241
+ /** The canvas this lane's own render pass draws, when its pixels can only
242
+ * be read from inside that pass (no `preserveDrawingBuffer`); the host's
243
+ * frame capture asks `snapshotFrame` for it. */
244
+ frameCanvas?(): HTMLCanvasElement | null;
245
+ snapshotFrame?(): Promise<CanvasImageSource | null>;
246
+ /** Why authoring is OFF for this lane's content (an ingested native-React
247
+ * game has no scene graph to introspect), or null when it is on; the
248
+ * inspector prints it in place of its sections. */
249
+ authoringRefusal?(): string | null;
250
+ /** A relayed command this lane answers ITSELF, ahead of every handler —
251
+ * an ingested game owns its mount, so `play`/`stop`/`pause`/`resume`/
252
+ * `step` drive its own loop rather than boot a first-party session over
253
+ * it. Null declines; the host then dispatches as usual. */
254
+ command?(cmd: LiveCommand): LiveCommandResult | null;
255
+ /** The scene entries the running content navigates (a contract game's
256
+ * scene table), for `open-scene` on a running lane. */
257
+ scenes?(): LiveSceneTable | null;
258
+ /** The native surface the running content draws on, when the lane knows
259
+ * it (an ingested game's declared surface); the host's coverage grades
260
+ * a root against it. */
261
+ surface?(): 'three' | 'canvas' | 'dom' | null;
262
+ /** The lane's OWN coverage of the running content's contracts (an
263
+ * ingested game's), shown by the inspector on the live document and
264
+ * standing in for the host's native-system grading while it runs. */
265
+ coverage?(): LiveCoverageReport | null;
266
+ }
267
+
268
+ /**
269
+ * What the running content answered about a switch it ACCEPTED — read off its
270
+ * own current scene once the switch settled. `error` is the content's own
271
+ * failure (a refused asset load, a throw), reported rather than swallowed; the
272
+ * scene it is actually in is still reported beside it, because that is the
273
+ * question the caller has next.
274
+ */
275
+ export interface LiveSceneSwitchSettled {
276
+ readonly requested: string;
277
+ readonly current: string | null;
278
+ readonly error?: string;
279
+ }
280
+
281
+ /**
282
+ * A scene switch, split at the seam where the answer stops being immediate:
283
+ * MEMBERSHIP is decided synchronously against the content's own scene list,
284
+ * and only an accepted switch has a `settled` promise to await.
285
+ *
286
+ * The split is what lets the caller act on the refusal without waiting, and —
287
+ * for the host's held-mount repaint — start drawing frames the instant a
288
+ * switch is accepted rather than after it lands.
289
+ */
290
+ export type LiveSceneSwitch =
291
+ | { readonly ok: true; readonly settled: Promise<LiveSceneSwitchSettled> }
292
+ | { readonly ok: false; readonly error: string; readonly known: readonly string[] };
293
+
294
+ /**
295
+ * A running game's own scene table: its stories, plus the switch the host
296
+ * awaits to open one.
297
+ *
298
+ * `goToScene`'s RESULT is stated here rather than left `unknown` for the
299
+ * editor to narrow (as it was until 2026-09-18). The narrowing lived in a lane
300
+ * module — the ingest lane's scenes projection — so the host's `open` verb had
301
+ * to import that lane by name to know what a switch answers, which is how the
302
+ * ingest contract reached the host's live registry. A contract states its own
303
+ * result; a lane implements it.
304
+ */
305
+ export interface LiveSceneTable extends StoriesProvider {
306
+ goToScene(sceneId: string): LiveSceneSwitch;
307
+ }
308
+
309
+ /** One seam's verdict in a lane's own coverage report — the doctrine's row
310
+ * (ARCHITECTURE-CORE §Adapters never fabricate first-party data: a gap
311
+ * names the mechanism that fills it). */
312
+ export interface LiveCoverageRow {
313
+ readonly seam: string;
314
+ readonly status: 'ok' | 'gap' | 'na' | 'info';
315
+ readonly detail: string;
316
+ readonly missing?: string;
317
+ readonly fix?: string;
318
+ readonly attestedBy?: 'game' | 'host';
319
+ }
320
+
321
+ export interface LiveCoverageReport {
322
+ readonly summary: {
323
+ readonly worldId: string;
324
+ readonly rows: number;
325
+ readonly gaps: number;
326
+ readonly ok: number;
327
+ readonly na: number;
328
+ readonly info: number;
329
+ };
330
+ readonly rows: readonly LiveCoverageRow[];
331
+ }
332
+
333
+ export interface LiveCommand {
334
+ readonly type: string;
335
+ readonly [key: string]: unknown;
336
+ }
337
+
338
+ export interface LiveCommandResult {
339
+ readonly ok: boolean;
340
+ readonly error?: string;
341
+ readonly data?: Record<string, unknown>;
342
+ }
343
+
344
+ export interface LiveRunWindow {
345
+ readonly startedAt: number;
346
+ readonly endedAt: number | null;
347
+ }
348
+
349
+ export interface EditorHostLive {
350
+ register(session: LiveSession): () => void;
351
+ mounted(): boolean;
352
+ playing(): boolean;
353
+ /** The newest run across lanes, or null before any ran. */
354
+ runWindow(): LiveRunWindow | null;
355
+ restartRequired(): string | null;
356
+ /** Re-enter whichever lane reports a restart is required (or is running). */
357
+ restart(): void;
358
+ /** Fires on registration and whenever a lane says its state moved
359
+ * (`notifyChanged`). */
360
+ subscribe(listener: () => void): () => void;
361
+ version(): number;
362
+ /** A lane's own state moved (restart-required, run window). */
363
+ notifyChanged(): void;
364
+ /** The mounted lane whose render pass owns `canvas`, asked for its pixels. */
365
+ snapshotFrame(canvas: HTMLCanvasElement): Promise<CanvasImageSource | null> | null;
366
+ frameCanvas(): HTMLCanvasElement | null;
367
+ authoringRefusal(): string | null;
368
+ /** The first mounted lane's own answer to `cmd`, or null when none claims it. */
369
+ dispatch(cmd: LiveCommand): LiveCommandResult | null;
370
+ /** The running lane's scene entries, or null. */
371
+ scenes(): LiveSceneTable | null;
372
+ surface(): 'three' | 'canvas' | 'dom' | null;
373
+ coverage(): LiveCoverageReport | null;
374
+ }
375
+
376
+ /**
377
+ * The Play transition's door on the host (`host.viewport.transition`). The authored viewport's
378
+ * own door (its rig, stages, helpers and Play's adoption of live roots) is the Three
379
+ * integration's: `@volter/editor-threejs/viewport-door`.
380
+ */
381
+ export interface EditorHostViewport {
382
+ readonly transition: EditorHostLiveTransition;
383
+ }
384
+
385
+ /**
386
+ * THE LIVE TRANSITION — the host's hand-off from authoring chrome to a
387
+ * running lane: under the immersive presentation the dock dissolves, the
388
+ * authored viewport's camera flies to the authored game camera, and when the
389
+ * lane reports ready the Scene document cross-fades into the live one. The
390
+ * host decides whether the presentation is immersive and resolves the flight
391
+ * target itself; a lane only says when it starts, when it is ready, and when
392
+ * it ends. Every path out of a run must reach `end()`.
393
+ */
394
+ export interface EditorHostLiveTransition {
395
+ /** Call BEFORE flipping the session to playing: the flight target is read
396
+ * from the authored scene, which Play's own adoption then replaces. */
397
+ begin(): void;
398
+ /** The lane finished its async boot; `getLiveCamera` is the render camera
399
+ * the flight converges on so the cross-fade is pixel-continuous. The kit
400
+ * hands it to the viewport's flight unread, so it names no medium's type:
401
+ * the Three flight takes a `THREE.Object3D` and ignores anything else. */
402
+ ready(getLiveCamera?: () => unknown): void;
403
+ end(): void;
404
+ /** Once the entry settles (cross-fade done, or torn down early) — at once
405
+ * when none is in flight. One-shot; re-check session state inside. */
406
+ onSettled(fn: () => void): void;
407
+ phase(): 'idle' | 'entering' | 'holding' | 'crossfade' | 'playing';
408
+ }
409
+
410
+ /** A lane's answer to the host's "re-mount with this selection" (an authored
411
+ * scene entry opened while the lane runs). */
412
+ export interface LiveRemountArgs {
413
+ readonly selection: string;
414
+ readonly key: string;
415
+ readonly regionId: string;
416
+ }
417
+
418
+ /**
419
+ * The hierarchy's change signal. The live objects behind its node ids are the Three
420
+ * integration's (`@volter/editor-threejs/host-hierarchy-objects`).
421
+ */
422
+ export interface EditorHostHierarchy {
423
+ /** Fires on any shell-store change (membership included). */
424
+ subscribe(listener: () => void): () => void;
425
+ version(): number;
426
+ }
427
+
428
+ /** The editor's own session state a contribution may read. */
429
+ export interface EditorHostSession {
430
+ /** Announce work BEFORE entering it, on the existing heartbeat/phase channel.
431
+ * Returns an idempotent end call; use finally, including on refusal.
432
+ * Labels describe operations only, never scripts, model data or credentials.
433
+ * Diagnostics only: this neither cancels work nor changes its deadline. */
434
+ beginWork(label: string): () => void;
435
+ /**
436
+ * Contribute fields to the editor's state report (the editor's `status` command, the SDK's
437
+ * `editor.state`): the collect runs on every report and its keys are
438
+ * spread in. A lane reports what only it knows — its loop's time scale and
439
+ * liveness, its seed — where the host reports the session. Returns the
440
+ * unregister.
441
+ *
442
+ * EVERY registered collect runs on EVERY report, including the interaction
443
+ * path's reusing one — so a facet whose derivation is expensive declares its
444
+ * `reusableKeys` and reads them back off the `reuse` snapshot it is handed.
445
+ * That is what let the COVERAGE REPORT families (`rootCoverage`,
446
+ * `systemCoverage`, `projectCoverage`, `authoringCoverage`) stop being host
447
+ * fields: their 76ms-to-1.3s derivation is exactly what
448
+ * `command-listener.ts`'s `REUSABLE_DERIVED_FACETS` exists to keep off a
449
+ * store notification, and the host's own docblock says the choice is the
450
+ * CALLER's — "only the caller knows whether it is on a user's critical
451
+ * path" — so no facet-side cache could have been the same answer. The
452
+ * declared keys join that set: the host strips them from an interaction
453
+ * PATCH by name (`currentStatePatch`), and the deferred full collect that
454
+ * always follows makes them current again.
455
+ */
456
+ reportFacet(
457
+ collect: (reuse: Record<string, unknown> | null) => Record<string, unknown>,
458
+ options?: { readonly reusableKeys?: readonly string[] },
459
+ ): () => void;
460
+ /**
461
+ * THE SESSION'S PERIODIC SAMPLE — the host's own five-second vitals tick
462
+ * (`coverage/session-vitals.ts`), which a lane may hang a periodic
463
+ * derivation of its own on. Returns the unsubscribe.
464
+ *
465
+ * A lane that wants "every few seconds, look at the session and say
466
+ * something" subscribes HERE rather than starting a second interval: the
467
+ * vitals sampler already owns the cadence, already runs on every realm, and
468
+ * a package-owned timer beside it would sample the same session at a
469
+ * different instant and report two answers for one moment. Listeners run
470
+ * before the host's own reveal failsafe and invariant report, which is the
471
+ * order the coverage union held when it was a host call on this tick.
472
+ */
473
+ onSample(fn: () => void): () => void;
474
+ /** Every relayed command, by type, as it is dispatched — the signal an
475
+ * idle watchdog reads ("an agent still driving through the editor's `eval` command is
476
+ * not idle"). Returns the unsubscribe. */
477
+ onCommandDispatched(fn: (type: string) => void): () => void;
478
+ playState(): 'stopped' | 'playing' | 'paused';
479
+ /** `'ephemeral'` while Play holds edits that will not persist; null otherwise. */
480
+ playEditRegime(): 'ephemeral' | null;
481
+ /** Fires on any shell-store change; select what you read. */
482
+ subscribe(listener: () => void): () => void;
483
+ version(): number;
484
+ /**
485
+ * Whether a PROJECT SESSION is open at all — the editor has a project and the
486
+ * shell that edits it, so a document can be opened and something can be
487
+ * presented into it.
488
+ *
489
+ * NEW (2026-09-19). `@volter/editor-blender` refuses every verb but its own status
490
+ * read without one, so that a call arriving at a session-less page answers at
491
+ * once instead of booting a Blender worker (gigabytes) into a page with
492
+ * nowhere to show it. It took the same answer from the host's
493
+ * `@editor/shell-store-door`; this is the question, without the store.
494
+ */
495
+ open(): boolean;
496
+ /**
497
+ * THIS PAGE'S SESSION ENDED — the tombstone every end goes through, graceful
498
+ * (the editor's `close` command) or not (the server died, another session took the port).
499
+ * Returns the unsubscribe.
500
+ *
501
+ * NEW (2026-09-19), and it is a RELEASE hook: a page told `tab-close` keeps
502
+ * running (Chrome refuses `window.close()` for a tab a person opened), so a
503
+ * package holding something the page cannot pay for holds it forever. The
504
+ * measurement that bought it: two orphaned editor tabs held 13 GB and 7 GB of
505
+ * resident Blender worker between them and put the box into a swap storm.
506
+ * A lane that owns a worker, a socket or a device ends it here.
507
+ */
508
+ onEnded(fn: () => void): () => void;
509
+ /** Save before an explicit session close, while HTTP and the relay are live.
510
+ * Rejection cancels close; onEnded remains forced resource teardown. */
511
+ onBeforeClose(fn: () => Promise<void>): () => void;
512
+ /**
513
+ * PUBLISH (or retract, with null) THIS LANE'S OUT-OF-PROCESS WORKER METER, so
514
+ * the tab census carries it out on the heartbeat — the one channel that still
515
+ * beats through a blocked main thread, which is why `reportFacet` above
516
+ * cannot answer this: a wedged tab is exactly the tab whose state report
517
+ * never arrives.
518
+ *
519
+ * A READ rather than a snapshot: an outstanding call's age has to be computed
520
+ * at the instant it is reported, and the package is the side that has the
521
+ * clock (a blocked worker cannot report on itself, and the side that POSTED
522
+ * the call still knows when it did).
523
+ *
524
+ * The HOST owns the rest of the measurement — the main thread's own long
525
+ * tasks, and which of them overlapped the call — and starts measuring when
526
+ * the first meter arrives; the page's stalls are never a lane's to observe.
527
+ *
528
+ * `lane` is the name the census carries the meter under and the editor's `status` command
529
+ * prints (`Blender`). One meter per name: publishing again under the same
530
+ * name replaces it.
531
+ */
532
+ reportWorkerCallMeter(lane: string, read: (() => EditorHostWorkerCallMetrics) | null): void;
533
+ }
534
+
535
+ /**
536
+ * A LANE'S WORKER CALLS, as numbers — what the tab census carries so that
537
+ * the editor's `status` command can say a tab stopped answering and why.
538
+ *
539
+ * Times are milliseconds on `performance.now()`; counters are monotonic since
540
+ * the lane's runtime was constructed. MEASUREMENT ONLY: nothing here cancels,
541
+ * kills or budgets a call.
542
+ */
543
+ export interface EditorHostWorkerCallMetrics {
544
+ /** Age of the OLDEST outstanding call, or null when the worker is idle — the
545
+ * only field with a number during a wedge. */
546
+ readonly inFlightMs: number | null;
547
+ /** Duration of the newest completed call; null before the first one. */
548
+ readonly lastCallMs: number | null;
549
+ /** The longest call yet, counting an outstanding one at its current age. */
550
+ readonly maxCallMs: number | null;
551
+ /** Optional operation/boundary label supplied by the lane, without request payloads. */
552
+ readonly maxCallLabel?: string | null;
553
+ /** Current cooperative phase and count of settled wire requests; sampled, not pushed per unit. */
554
+ readonly currentPhase?: string | null;
555
+ readonly completedCalls?: number;
556
+ /** Calls past 5s, and past 30s, since the runtime was constructed. */
557
+ readonly callsOver5s: number;
558
+ readonly callsOver30s: number;
559
+ /** The newest call's window (`end` null while it is outstanding); the host
560
+ * intersects its own long tasks with it. */
561
+ readonly lastCallWindow: { readonly start: number; readonly end: number | null } | null;
562
+ /** The lane's own out-of-process memory in MB (a wasm module's linear
563
+ * memory), or null when it has none to report. */
564
+ readonly wasmMemoryMB: number | null;
565
+ }
566
+
567
+ /** The open project's declared SHAPE, as a contribution may gate on it. */
568
+ export interface EditorHostProject {
569
+ /** The declared document table after its contributed finders have settled.
570
+ * A package starting a document before its UI mounts must resolve the real
571
+ * project entries, not guess an id from an uninitialized view. */
572
+ documentTable(): Promise<{ readonly entries: readonly DocumentEntry[]; readonly default: string | null }>;
573
+ /** Whether the project declares at least one root that plays. */
574
+ mounts(): boolean;
575
+ /**
576
+ * The engine version the OPEN project is pinned to
577
+ * (`volter.project.json`'s `engine.version`), or null when no project is
578
+ * open — the same one source `ProjectHeader.tsx` renders, so a package's
579
+ * version readout can never disagree with the host's.
580
+ *
581
+ * A primitive rather than the project object on purpose: `ActiveProject`
582
+ * is a host internal, and the SDK's door grows one member per
583
+ * contribution that needs it (`@volter/editor-blender`'s `workspace.status` version
584
+ * item is the reader). Paired with {@link subscribe}, this is the whole
585
+ * "current project + change" the door owes a contribution — and it is
586
+ * stable enough for `useSyncExternalStore` without a snapshot cache.
587
+ */
588
+ engineVersion(): string | null;
589
+ subscribe(listener: () => void): () => void;
590
+ /**
591
+ * Runs once the open project's authoring surfaces are READY — its scene
592
+ * loaded and the edit-mode composite installed — the moment a lane may
593
+ * auto-launch what the manifest declares (an ingest root). Listeners run
594
+ * in registration order, each awaited; a project opened later fires it
595
+ * again. Returns the unsubscribe.
596
+ */
597
+ onReady(fn: () => void | Promise<void>): () => void;
598
+ }
599
+
600
+ export interface EditorHostNotification {
601
+ /** A stable id replaces an earlier notification with the same id. */
602
+ readonly id?: string;
603
+ readonly tone: 'info' | 'warning' | 'error';
604
+ /** One line, bold — what happened. */
605
+ readonly title: string;
606
+ /** The rest, plain — what it means, what to do. */
607
+ readonly detail?: string;
608
+ readonly actions?: readonly {
609
+ readonly label: string;
610
+ readonly run: () => void;
611
+ readonly primary?: boolean;
612
+ }[];
613
+ }
614
+
615
+ /** The editor's console — the session-held set the editor's `console` command prints. A
616
+ * contribution's diagnostics go here, never to `console.*`, so they reach
617
+ * every door whether or not anyone looks at the tab. */
618
+ export interface EditorHostConsole {
619
+ log(message: string, source: string): void;
620
+ warn(message: string, source: string): void;
621
+ error(message: string, source: string): void;
622
+ }
623
+
624
+ /**
625
+ * THE SETTINGS DOOR — one dotted `volter.*` key at a time, with the LAYER each
626
+ * value came from, and the one write that lands where it wins.
627
+ *
628
+ * ARCHITECTURE-CORE §The core is Code-OSS: *"the settings layers and settings
629
+ * UI → the configuration service (the ADAPTER layer between user and
630
+ * workspace … is the one addition)"*. The same two-owner shape as
631
+ * {@link EditorHostKeyboard}, {@link EditorHostHistory} and
632
+ * {@link EditorHostFiles}: `'host'` is standalone the editor's `edit` command, where
633
+ * `settings-store.ts`'s three layers ARE the settings; `'frame'` is the
634
+ * Code-OSS frame, where `IConfigurationService` is.
635
+ *
636
+ * ## The keys are `volter.*`, and the prefix is part of the key
637
+ *
638
+ * `volter.appearance.palette`, `volter.keymap`, `volter.devicePreview.preset` — the
639
+ * flat dotted names `@volter/project/settings/keys` derives from the settings
640
+ * schema, which is also what the fork's `contributes.configuration` is
641
+ * generated from. One spelling in this door, in `.vscode/settings.json`, in
642
+ * VS Code's Settings editor and in what the editor's `eval` command prints, because the moment
643
+ * there are two a reader has to know which side of which seam they are on to
644
+ * know which to type.
645
+ *
646
+ * ## The adapter layer, and why `inspect` names it
647
+ *
648
+ * "Project over ADAPTER over user" (§Adapters and contributions are code) is
649
+ * the one thing the configuration service does not already have, and under the
650
+ * frame it is the service's own MEMORY target — the top layer — written by the
651
+ * fork when the project's adapter loads and cleared the moment `inspect` shows
652
+ * a workspace or folder value for that key. So `inspect(key)` answers with the
653
+ * FOUR layers a person can act on, and a caller that wants to know whether a
654
+ * gesture will stick asks it rather than guessing from the effective value.
655
+ */
656
+ export interface EditorHostSettings {
657
+ /**
658
+ * Install VS Code's configuration service as the settings. The frame calls
659
+ * this once its own services exist, which is AFTER the editor mounts (a
660
+ * `ServicesAccessor` is valid only for the synchronous part of an
661
+ * invocation). Until it does, the door falls back to the editor's own layers
662
+ * rather than refusing: the editor paints in that window, and a palette read
663
+ * there is a real read with nowhere else to go.
664
+ */
665
+ setProvider(provider: EditorHostSettingsProvider): void;
666
+ /** The EFFECTIVE value — project over adapter over user over default — or
667
+ * `undefined` when no layer carries it. */
668
+ get(key: string): unknown;
669
+ /**
670
+ * Write one key.
671
+ *
672
+ * With no `target`, the write goes WHERE IT WINS: the project when this
673
+ * project's adapter or its own settings already declare the key, the user
674
+ * layer otherwise. That is the whole of `updatePreferenceSettings`'s rule,
675
+ * and it is here rather than in each caller because writing `appearance` to
676
+ * the user layer in a project whose adapter declares a style is a gesture
677
+ * that silently does nothing.
678
+ */
679
+ set(key: string, value: unknown, target?: EditorHostSettingsTarget): void;
680
+ /** Every layer's own value for this key, plus the effective one. A layer
681
+ * that is silent about the key answers `undefined` — never the value from
682
+ * the layer under it. */
683
+ inspect(key: string): EditorHostSettingsInspection;
684
+ subscribe(listener: () => void): () => void;
685
+ }
686
+
687
+ /** The two layers a person's gesture can land in. The adapter layer is the
688
+ * project's own CODE and the default layer is the build's, so neither is a
689
+ * write target. */
690
+ export type EditorHostSettingsTarget = 'user' | 'project';
691
+
692
+ export interface EditorHostSettingsInspection {
693
+ /** The built-in value, when the layer that declares the key carries one.
694
+ * The standalone layers carry none, so this is `undefined` there. */
695
+ readonly default: unknown;
696
+ /** `~/.volter/settings.json` standalone; the USER target under the frame. */
697
+ readonly user: unknown;
698
+ /** What `editor/volter.adapter.ts` DECLARES (`editor: { style, keymap }`); the
699
+ * MEMORY target under the frame. */
700
+ readonly adapter: unknown;
701
+ /** `<project>/.volter/settings.json` standalone; the WORKSPACE (and folder)
702
+ * target under the frame. */
703
+ readonly project: unknown;
704
+ /** Project over adapter over user over default. */
705
+ readonly effective: unknown;
706
+ }
707
+
708
+ /**
709
+ * THE FRAME'S HALF — what the Code-OSS bridge installs, backed by
710
+ * `IConfigurationService`. Keys are the same `volter.*` names the door takes.
711
+ *
712
+ * There is no `owner`/`setOwner` here and no optional member: unlike
713
+ * {@link EditorHostFileProvider}, a configuration service can answer every one
714
+ * of these for every key, so a member the frame "cannot answer" would be a
715
+ * defect rather than a shape.
716
+ */
717
+ export interface EditorHostSettingsProvider {
718
+ get(key: string): unknown;
719
+ inspect(key: string): EditorHostSettingsInspection;
720
+ /** Settles when the write has landed or failed — a configuration service's write is
721
+ * asynchronous, and a reader that must not see the previous value until then waits on it. */
722
+ set(key: string, value: unknown, target: EditorHostSettingsTarget): Promise<void>;
723
+ /** Fires when any `volter.*` value changes in any layer. Returns the
724
+ * unsubscribe. */
725
+ subscribe(listener: () => void): () => void;
726
+ }
727
+
728
+ /**
729
+ * THE KEYBOARD DOOR — who owns the keyboard, and the chord-independent table
730
+ * of what the editor's keyboard actions DO.
731
+ *
732
+ * ARCHITECTURE-CORE §The core is Code-OSS rule 3: *"Keyboard ownership is VS
733
+ * Code's. One keybinding system … Two listeners cannot both own the
734
+ * keyboard."* Under the Code-OSS frame the workbench's keybinding service is
735
+ * the one keyboard: the fork's contribution registers one `volter.<action id>`
736
+ * command per entry of `actions()`, gives each the chords `keymaps()` reports
737
+ * under a `when` clause over its own context keys, and dispatches through
738
+ * `invoke`. The editor installs no `keydown` listener of its own at all.
739
+ */
740
+ export interface EditorHostKeyboard {
741
+ /**
742
+ * Every action the editor has a live handler for right now, with the scope
743
+ * its chord belongs to — `'stage'` (the focused stage alone), `'panel'`
744
+ * (any of the editor's own parts) or `'global'`. The viewport set appears
745
+ * only while a three stage is mounted, so this is a live list, not a
746
+ * catalogue; `subscribe`/`version` report when it moves.
747
+ */
748
+ actions(): readonly { readonly id: string; readonly scope: 'stage' | 'panel' | 'global' }[];
749
+ /**
750
+ * Every registered keymap and the chords it assigns each action — the
751
+ * editor's own `volter` table and whatever a project's packages contribute
752
+ * (Blender's G/R/S). A keymap is a SET of keybinding rules to the frame:
753
+ * the same commands, different chords, gated on `activeKeymap()`.
754
+ */
755
+ keymaps(): readonly {
756
+ readonly id: string;
757
+ readonly title: string;
758
+ readonly chords: Readonly<
759
+ Record<
760
+ string,
761
+ readonly {
762
+ readonly key: string;
763
+ readonly code?: string;
764
+ readonly mod?: boolean;
765
+ readonly shift?: boolean;
766
+ readonly alt?: boolean;
767
+ }[]
768
+ >
769
+ >;
770
+ }[];
771
+ /** The keymap the PROJECT selected (its adapter's `editor.keymap`, its own
772
+ * settings over it). The frame publishes it as a context key and never
773
+ * keeps a second setting of its own. */
774
+ activeKeymap(): string;
775
+ /** Run one action by id. `false` when nothing handles it now, or its own
776
+ * gate refused — never silent. */
777
+ invoke(id: string): boolean;
778
+ subscribe(listener: () => void): () => void;
779
+ version(): number;
780
+ /**
781
+ * WHAT THE FOCUSED STAGE IS SHOWING, for the frame's context keys. It is
782
+ * here rather than beside `viewport` because it exists for exactly one
783
+ * reader: the `when` clauses that decide which keyboard action a chord
784
+ * reaches. `surface` is the stage's (`stage-context.ts`); `mode` is the
785
+ * document's own interaction mode when it reports one (Blender's
786
+ * object/edit/sculpt) and `null` when nothing does.
787
+ */
788
+ stage(): {
789
+ readonly surface: 'three' | 'canvas' | 'dom' | null;
790
+ readonly mode: string | null;
791
+ };
792
+ /**
793
+ * REGISTER A LANE'S KEYBOARD ACTIONS for as long as the lane lives. The lane
794
+ * writes what each action does; its chords are the ACTIVE keymap's for that
795
+ * id and move when the keymap does. A `'stage'` action answers only while a
796
+ * stage holds the editor's keyboard scope. Returns the removal.
797
+ */
798
+ bindActions(actions: readonly EditorHostKeyAction[]): () => void;
799
+ /** The active keymap's chords for one action — for a HELD gesture, which a
800
+ * keybinding rule has no way to express. */
801
+ chordsFor(id: EditorKeyActionId): readonly KeyChord[];
802
+ /** The active keymap's chord for one action as a person reads it, or null
803
+ * when the keymap gives the action none. */
804
+ shortcutFor(id: EditorKeyActionId): string | null;
805
+ }
806
+
807
+ /** One action a lane binds through {@link EditorHostKeyboard.bindActions}. */
808
+ export interface EditorHostKeyAction {
809
+ readonly id: EditorKeyActionId;
810
+ readonly scope: 'stage' | 'global';
811
+ run(event?: KeyboardEvent): void;
812
+ /** Whether the action applies right now, asked without an event. */
813
+ enabled?(): boolean;
814
+ }
815
+
816
+ /**
817
+ * ONE RECORDED EDIT, as whoever owns undo sees it — the SDK's spelling of
818
+ * `packages/sdk/src/kit/history/history-delegate.ts`'s `HistoryElement`.
819
+ *
820
+ * It is deliberately an `IResourceUndoRedoElement` (one file) or an
821
+ * `IWorkspaceUndoRedoElement` (several) without naming either: the frame does
822
+ * that translation, so no editor module imports VS Code and no file under the
823
+ * fork's `src/vs/` imports an editor module.
824
+ */
825
+ export interface EditorHostHistoryElement {
826
+ readonly id: string;
827
+ /** User-presentable, already trimmed ("Transform Selection"). This is what
828
+ * the frame's Edit menu shows after "Undo". */
829
+ readonly label: string;
830
+ /**
831
+ * The PROJECT-RELATIVE files this edit changed, in the order the
832
+ * transaction declared them — `src/prefabs/Crate.tsx`, not a URI and not an
833
+ * opaque key, because only the frame knows the workspace folder they
834
+ * resolve against, and resolving them there is what puts a gizmo drag and a
835
+ * keystroke in the same file's text editor on ONE resource's stack.
836
+ *
837
+ * EMPTY for a session-scoped edit (a live journal on a held canvas surface,
838
+ * a play run), which has no file at all. Placing such an element is the
839
+ * frame's decision, named there — never silently attached to whatever
840
+ * document happened to be open.
841
+ */
842
+ readonly resources: readonly string[];
843
+ /**
844
+ * THE WORKSPACE DOCUMENT THIS EDIT WAS MADE IN, at the moment it was
845
+ * recorded — the id, or null when nothing was active.
846
+ *
847
+ * MEASURED (2026-09-19, the game template inside the frame): a three root's
848
+ * document is NOT one file. Its adapter's own source path is the root entry
849
+ * `src/world.tsx`, while a gizmo drag on the scene's HeroBox instance writes
850
+ * `src/scenes/MainScene.tsx` — so "the document's resource" is a SET that
851
+ * grows with what the person edits, and asking the undo service about the
852
+ * entry file alone would find nothing to undo. The document id is the stable
853
+ * thing; WHICH file its next undo acts on is the newest element recorded in
854
+ * it. It is also what keeps a component view's stack apart from the main
855
+ * scene's.
856
+ */
857
+ readonly document: string | null;
858
+ /** Revert this one entry. `false` when the editor refused (a conflict, an
859
+ * expired resource, blocked history) — never a silent no-op. */
860
+ undo(): Promise<boolean>;
861
+ redo(): Promise<boolean>;
862
+ }
863
+
864
+ /**
865
+ * UNDO, for the Code-OSS frame (ARCHITECTURE-CORE §The core is Code-OSS:
866
+ * *"history-service.ts → IUndoRedoService … there is one Cmd+Z"*).
867
+ *
868
+ * The same two halves as {@link EditorHostKeyboard}, for the same reason: the
869
+ * STANDALONE the editor's `edit` command shape fills this with the editor's own
870
+ * `history-service.ts` cursor, and the FRAME takes ownership before the editor
871
+ * mounts and pushes every {@link EditorHostHistoryElement} into VS Code's
872
+ * `IUndoRedoService` instead. Nothing here caps anything by bytes — snapshot
873
+ * size stays the adapter's concern, stated where the snapshot is taken.
874
+ */
875
+ /** The frame's own undo, for every editor affordance that is not a chord. */
876
+ export interface EditorHostHistoryDelegate {
877
+ undo(): void | boolean | Promise<void | boolean>;
878
+ redo(): void | boolean | Promise<void | boolean>;
879
+ canUndo(): boolean;
880
+ canRedo(): boolean;
881
+ undoLabel?(): string | null;
882
+ redoLabel?(): string | null;
883
+ }
884
+
885
+ export interface EditorHostHistory {
886
+ /** Record a native document edit in the workbench's existing history.
887
+ * The document owns restoration; the frame owns ordering and shortcuts. */
888
+ record(element: EditorHostHistoryElement): void;
889
+ /**
890
+ * Install the frame's own undo as the one stack. Called once its service
891
+ * exists, which is AFTER the editor mounts.
892
+ *
893
+ * The delegate is the OTHER direction of this door: the editor has undo
894
+ * affordances that are not the keyboard — its Edit menu's "Undo <label>",
895
+ * the command palette, the editor's `eval` command's undo verb — and every one of them must
896
+ * reach the ONE stack. Without it the Edit menu still names the step (the
897
+ * label comes from the last recorded entry) while the click refuses, which
898
+ * is worse than no menu item at all.
899
+ */
900
+ setDelegate(delegate: EditorHostHistoryDelegate): void;
901
+ /**
902
+ * Every entry as it is recorded, once a delegate is installed. Returns the
903
+ * removal. Pair it with {@link elements}: the bridge mounts after edits are
904
+ * already possible, so it pushes what it missed first, in order.
905
+ */
906
+ onElement(listener: (element: EditorHostHistoryElement) => void): () => void;
907
+ /** Discard history for replaced/closed native documents, never ordinary edits. */
908
+ invalidate(resources: readonly string[]): void;
909
+ onInvalidated(listener: (resources: readonly string[]) => void): () => void;
910
+ /** The workbench finished moving its own stack (including keyboard commands). */
911
+ changed(): void;
912
+ /** Everything recorded so far, oldest first. */
913
+ elements(): readonly EditorHostHistoryElement[];
914
+ /**
915
+ * THE FOCUSED DOCUMENT'S OWN FILE, project-relative — the first resource a
916
+ * ⌘Z with focus on a volter stage tries, and the one a refusal names. `null`
917
+ * when nothing is open and the active adapter writes nowhere.
918
+ *
919
+ * It is deliberately NOT the whole answer, because a three root's document
920
+ * spans several files (see {@link EditorHostHistoryElement.document}); the
921
+ * frame falls back to the newest element recorded IN THAT DOCUMENT, which is
922
+ * what keeps a component view's ⌘Z off the main scene's stack — the whole
923
+ * of "Component-view Ctrl+Z acts on the MAIN scene's history" (WORK.md
924
+ * §The core is Code-OSS, U4's absorb list).
925
+ */
926
+ focusedResource(): string | null;
927
+ /** The HOST shape's undo/redo — the editor's own cursor. Under frame
928
+ * ownership these refuse by name; the frame drives elements instead. */
929
+ undo(): Promise<boolean>;
930
+ redo(): Promise<boolean>;
931
+ canUndo(): boolean;
932
+ canRedo(): boolean;
933
+ /** What the next undo/redo would be called, for a menu that shows it. */
934
+ undoLabel(): string | null;
935
+ redoLabel(): string | null;
936
+ subscribe(listener: () => void): () => void;
937
+ }
938
+
939
+ /**
940
+ * THE FILE DOOR — reading and writing the OPEN PROJECT'S OWN FILES, over
941
+ * project-relative paths, with the same two-owner shape as
942
+ * {@link EditorHostKeyboard} and {@link EditorHostHistory}.
943
+ *
944
+ * ARCHITECTURE-CORE §The core is Code-OSS: *"the storage backends → file
945
+ * system providers, the dev server as one provider"* — and the rule above it
946
+ * that governs HOW: **everything VS Code already does is USED, not rebuilt.**
947
+ *
948
+ * ## Why this is a CALL and not a file-system provider (U5, measured)
949
+ *
950
+ * Both product shapes already have a real file service over the project:
951
+ * DESKTOP opens the project folder as the workspace folder on Electron's own
952
+ * disk provider, and WEB + SERVER (the REH) serves the same folder over
953
+ * `vscode-remote://`. A `volter-session:` provider mounting the session's
954
+ * `/__editor/*` routes would be a SECOND path to bytes the workbench can
955
+ * already reach — more code, a second cache, and two notions of when a file
956
+ * changed. So under the frame this door CALLS `IFileService` (and
957
+ * `ITextFileService` for text), and the session's file routes stay exactly
958
+ * what the STANDALONE shape speaks.
959
+ *
960
+ * ## Why the frame's write is the point (U4's open, closed here)
961
+ *
962
+ * A volter element's REDO used to be lost while a text model for that file was
963
+ * open: the editor's undo wrote the file through its own transport, which is
964
+ * an EXTERNAL change to the workbench, so Monaco reloaded and
965
+ * `modelService.updateModel` pushed a fresh text element — and `pushElement`
966
+ * destroys the redo future. A write made THROUGH the workbench is the
967
+ * workbench's own: the open model is updated in place and no reload fires, so
968
+ * the future survives. That is the reason this door exists rather than a
969
+ * fourth storage backend.
970
+ *
971
+ * ## Paths
972
+ *
973
+ * PROJECT-RELATIVE, `/`-separated, no leading slash — `src/scenes/Main.tsx`,
974
+ * `public/models/hero.glb` — exactly the spelling
975
+ * {@link EditorHostHistoryElement.resources} uses, and for the same reason:
976
+ * only the frame knows the workspace folder they resolve against
977
+ * (`URI.joinPath(workspaceFolder.uri, path)`), and resolving them there is
978
+ * what lands a write on the same URI Monaco holds for that file.
979
+ *
980
+ * This is deliberately NOT `StorageBackend`'s spelling, which means two
981
+ * different things by tier — measured 2026-09-19: `HttpStorage` is rooted at
982
+ * `<project>/public/` while a project-rooted backend is rooted at the
983
+ * PROJECT ROOT, which is why the session grew four separate purpose-scoped
984
+ * project-root routes beside it (`/__editor/volter-file`,
985
+ * `/__editor/project-resource`, `/__editor/data-file`,
986
+ * `/__editor/source-files`). One spelling, here.
987
+ */
988
+ export interface EditorHostFiles {
989
+ /**
990
+ * Install the workbench's file service as the project's files. Called once
991
+ * its own services exist, which is AFTER the editor mounts — a
992
+ * `ServicesAccessor` is valid only for the synchronous part of an
993
+ * invocation, so the provider cannot be built before the mount it is handed
994
+ * to (docs/CODE-OSS.md records that trap). Until it lands the door falls
995
+ * back to the session's transports rather than refusing: a write in that
996
+ * window is a real write with nowhere else to go.
997
+ */
998
+ setProvider(provider: EditorHostFileProvider): void;
999
+ /** Read a UTF-8 text file. Rejects BY NAME if it is missing or a
1000
+ * directory. */
1001
+ read(path: string): Promise<string>;
1002
+ /** Read raw bytes. */
1003
+ readBytes(path: string): Promise<Uint8Array>;
1004
+ /**
1005
+ * Write a file, creating parent directories as needed.
1006
+ *
1007
+ * Under the frame this is the workbench's own write: when a text model is
1008
+ * open for the file it is updated IN PLACE and saved, so no external-change
1009
+ * reload fires and no text undo element lands on top of ours.
1010
+ */
1011
+ write(path: string, data: string | Uint8Array): Promise<void>;
1012
+ exists(path: string): Promise<boolean>;
1013
+ /** Shallow directory listing. */
1014
+ list(dir: string): Promise<readonly EditorHostFileEntry[]>;
1015
+ /** Change events for the project's files. Returns the unsubscribe. */
1016
+ watch(listener: (event: EditorHostFileEvent) => void): () => void;
1017
+ }
1018
+
1019
+ export interface EditorHostFileEntry {
1020
+ /** Base name, no slashes. */
1021
+ readonly name: string;
1022
+ /** Project-relative path. */
1023
+ readonly path: string;
1024
+ readonly type: 'file' | 'dir';
1025
+ }
1026
+
1027
+ export interface EditorHostFileEvent {
1028
+ readonly type: 'create' | 'update' | 'remove';
1029
+ /** Project-relative path. */
1030
+ readonly path: string;
1031
+ }
1032
+
1033
+ /**
1034
+ * THE FRAME'S HALF — what the Code-OSS bridge installs, backed by
1035
+ * `IFileService`/`ITextFileService`. Every member takes the same
1036
+ * project-relative paths the door does; the frame joins them onto the
1037
+ * workspace folder.
1038
+ *
1039
+ * A member the frame cannot answer is ABSENT rather than faked, and the door
1040
+ * falls back to the host transport for it — the anti-shim rule applied to a
1041
+ * file API, because a fabricated listing reads exactly like a real empty
1042
+ * folder.
1043
+ */
1044
+ export interface EditorHostFileProvider {
1045
+ read(path: string): Promise<string>;
1046
+ readBytes?(path: string): Promise<Uint8Array>;
1047
+ write(path: string, data: string | Uint8Array): Promise<void>;
1048
+ exists(path: string): Promise<boolean>;
1049
+ list?(dir: string): Promise<readonly EditorHostFileEntry[]>;
1050
+ watch?(listener: (event: EditorHostFileEvent) => void): () => void;
1051
+ }
1052
+
1053
+ /**
1054
+ * THE STAGE TRANSPORT DOOR — reach the transport of the stage a document runs
1055
+ * on, holding only that document's id.
1056
+ *
1057
+ * Shaped like `documents` beside it: a lookup plus a subscription, because a
1058
+ * stage mounting or unmounting changes what `for` answers and a look drawn
1059
+ * over it must re-render when it does. `null` for a document with no stage of
1060
+ * its own (a tool tab, a text document).
1061
+ */
1062
+ export interface EditorHostTransport {
1063
+ for(documentId: string): StageTransportHandle | null;
1064
+ subscribe(listener: () => void): () => void;
1065
+ }
1066
+
1067
+ /**
1068
+ * The transport vocabulary, re-exported through the host door so a skew
1069
+ * package reaches it without importing the editor's source or an engine
1070
+ * value. See `./transport.ts` for what each member means.
1071
+ */
1072
+ export type {
1073
+ StageTransportHandle,
1074
+ StageTransportSnapshot,
1075
+ TransportPlaybackState,
1076
+ TransportSubject,
1077
+ } from './transport';
1078
+
1079
+ /** Text logs and source diagnostics rendered by the native workbench. */
1080
+ export interface EditorHostOutputDiagnostic {
1081
+ readonly path: string;
1082
+ readonly line: number;
1083
+ readonly column: number;
1084
+ readonly message: string;
1085
+ readonly severity: 'error' | 'warning';
1086
+ }
1087
+
1088
+ export interface EditorHostOutput {
1089
+ /** Replace a named channel's text and its current diagnostics. Paths are project-relative. */
1090
+ write(
1091
+ id: string,
1092
+ label: string,
1093
+ text: string,
1094
+ diagnostics: readonly EditorHostOutputDiagnostic[],
1095
+ ): void;
1096
+ show(id: string): void;
1097
+ }
1098
+
1099
+ export interface EditorHost {
1100
+ readonly output: EditorHostOutput;
1101
+ readonly console: EditorHostConsole;
1102
+ readonly live: EditorHostLive;
1103
+ readonly viewport: EditorHostViewport;
1104
+ readonly hierarchy: EditorHostHierarchy;
1105
+ readonly systems: EditorHostSystems;
1106
+ readonly session: EditorHostSession;
1107
+ readonly project: EditorHostProject;
1108
+ /** Raise a notification in the editor's own tray. Returns the dismiss. */
1109
+ notify(notification: EditorHostNotification): () => void;
1110
+ readonly availability: EditorHostAvailability;
1111
+ readonly workspace: EditorHostWorkspace;
1112
+ readonly documents: EditorHostDocuments;
1113
+ readonly projectLocalState: EditorHostProjectLocalState;
1114
+ readonly keyboard: EditorHostKeyboard;
1115
+ readonly history: EditorHostHistory;
1116
+ readonly files: EditorHostFiles;
1117
+ readonly settings: EditorHostSettings;
1118
+ readonly transport: EditorHostTransport;
1119
+ }
1120
+
1121
+ /**
1122
+ * ONE registration across every copy of this module. Under the packaged
1123
+ * runtime the editor shell is a prebuilt bundle with this SDK inlined, while
1124
+ * a package's contribution is served from the project's own installed SDK —
1125
+ * two module instances, so plain module state would be an empty registry on
1126
+ * the contribution's side (measured 2026-09-17: "No editor host is
1127
+ * registered" from `@volter/editor-game`'s connection pill on a registry install).
1128
+ * The layout host (`layouts.tsx`) solved the same split with a `Symbol.for`
1129
+ * key on `globalThis`; this door does the same.
1130
+ */
1131
+ const HOST_KEY = Symbol.for('volter.editor.host');
1132
+ const hosts = globalThis as typeof globalThis & { [HOST_KEY]?: EditorHost | null };
1133
+
1134
+ /** The editor's boot registers itself; `null` unregisters (tests). */
1135
+ export function registerEditorHost(next: EditorHost | null): void {
1136
+ hosts[HOST_KEY] = next;
1137
+ }
1138
+
1139
+ export function editorHost(): EditorHost {
1140
+ const host = hosts[HOST_KEY];
1141
+ if (!host)
1142
+ throw new Error(
1143
+ 'No editor host is registered: this contribution is running outside the editor ' +
1144
+ '(`registerEditorHost` from `@volter/sdk/host` is called by the editor at boot).',
1145
+ );
1146
+ return host;
1147
+ }
1148
+
1149
+ /**
1150
+ * Re-render only when `select()`'s value changes, sampled on the host's
1151
+ * availability tick — the shape every session-state gate in the editor uses,
1152
+ * so a package's status item costs the same as a built-in one.
1153
+ */
1154
+ export function useHostAvailabilitySelector<T>(select: () => T): T {
1155
+ const { availability } = editorHost();
1156
+ return useSyncExternalStore(availability.subscribe, select, select);
1157
+ }