@volter/sdk 0.0.0-stage → 0.5.203

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (523) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +20 -0
  3. package/README.md +38 -3
  4. package/package.json +510 -4
  5. package/src/account.ts +210 -0
  6. package/src/chrome.ts +88 -0
  7. package/src/client.ts +1646 -0
  8. package/src/commands.ts +66 -0
  9. package/src/contributions.ts +619 -0
  10. package/src/css-numeric-style.ts +97 -0
  11. package/src/document-probe.ts +282 -0
  12. package/src/editor-view.ts +225 -0
  13. package/src/extension.ts +40 -0
  14. package/src/generations.ts +178 -0
  15. package/src/host.ts +1157 -0
  16. package/src/http-transport.browser.ts +14 -0
  17. package/src/http-transport.node.ts +19 -0
  18. package/src/index.ts +131 -0
  19. package/src/kit/CapabilityCoverageSection.tsx +185 -0
  20. package/src/kit/account-client.ts +333 -0
  21. package/src/kit/action-registry.ts +317 -0
  22. package/src/kit/active-product.ts +76 -0
  23. package/src/kit/active-project.ts +155 -0
  24. package/src/kit/adapter-editor-config.ts +25 -0
  25. package/src/kit/adapter-module.ts +7 -0
  26. package/src/kit/adapter-observation.ts +49 -0
  27. package/src/kit/animation/animation-clock.ts +479 -0
  28. package/src/kit/animation/stage-transport.ts +385 -0
  29. package/src/kit/api/assets.ts +365 -0
  30. package/src/kit/api/project-open.ts +355 -0
  31. package/src/kit/api/project-source.ts +180 -0
  32. package/src/kit/api/project-state.ts +110 -0
  33. package/src/kit/api/relay.ts +270 -0
  34. package/src/kit/api/themes.ts +45 -0
  35. package/src/kit/api-asset-library-wire.ts +45 -0
  36. package/src/kit/api-base.ts +10 -0
  37. package/src/kit/api-build.ts +99 -0
  38. package/src/kit/api-git-wire.ts +56 -0
  39. package/src/kit/api-logs.ts +92 -0
  40. package/src/kit/api-project-identity.ts +74 -0
  41. package/src/kit/api-settings.ts +36 -0
  42. package/src/kit/api-worktrees.ts +205 -0
  43. package/src/kit/asset-capabilities.ts +344 -0
  44. package/src/kit/asset-compare-core.ts +171 -0
  45. package/src/kit/asset-editor-context.tsx +101 -0
  46. package/src/kit/asset-events.ts +96 -0
  47. package/src/kit/asset-inspector-actions.ts +87 -0
  48. package/src/kit/asset-selection-viewer-registry.ts +113 -0
  49. package/src/kit/asset-selection.ts +146 -0
  50. package/src/kit/asset-thumbnails.ts +25 -0
  51. package/src/kit/asset-viewers.ts +115 -0
  52. package/src/kit/asset-workflow/asset-import-jobs.ts +106 -0
  53. package/src/kit/asset-workflow/asset-ledger-backend.ts +126 -0
  54. package/src/kit/asset-workflow/asset-ledger.ts +156 -0
  55. package/src/kit/asset-workflow/asset-materialization-report.ts +140 -0
  56. package/src/kit/asset-workflow/asset-pack-manifest.ts +320 -0
  57. package/src/kit/asset-workflow/asset-types.ts +142 -0
  58. package/src/kit/asset-workflow/audio-preview-player.ts +193 -0
  59. package/src/kit/asset-workflow/audio-waveform.ts +22 -0
  60. package/src/kit/asset-workflow/cloud-asset-client.ts +263 -0
  61. package/src/kit/asset-workflow/hosted-asset-materialization.ts +236 -0
  62. package/src/kit/asset-workflow/image-view-scale.ts +31 -0
  63. package/src/kit/asset-workflow/import-contract.ts +124 -0
  64. package/src/kit/asset-workflow/ledger-write-lock.ts +244 -0
  65. package/src/kit/asset-workflow/pixi-spritesheet.ts +197 -0
  66. package/src/kit/asset-workflow/preview-resource-lifetime.ts +44 -0
  67. package/src/kit/asset-workflow/project-asset-commands.ts +20 -0
  68. package/src/kit/asset-workflow/project-content.ts +288 -0
  69. package/src/kit/asset-workflow/project-source-index.ts +545 -0
  70. package/src/kit/asset-workflow/thumbnail-system.ts +256 -0
  71. package/src/kit/authoring/active-adapter.ts +200 -0
  72. package/src/kit/authoring/active-systems.ts +422 -0
  73. package/src/kit/authoring/adapter-key.ts +18 -0
  74. package/src/kit/authoring/authoring-asset-url.ts +27 -0
  75. package/src/kit/authoring/bootstrap-state.ts +49 -0
  76. package/src/kit/authoring/boundary-authoring-adapter.ts +189 -0
  77. package/src/kit/authoring/canvas-scene-guides.ts +84 -0
  78. package/src/kit/authoring/composite-authoring-adapter.ts +2109 -0
  79. package/src/kit/authoring/consumer-actions.ts +531 -0
  80. package/src/kit/authoring/design-time-layers.ts +852 -0
  81. package/src/kit/authoring/design-time-mount-registry.ts +244 -0
  82. package/src/kit/authoring/edit-mode-authoring.ts +637 -0
  83. package/src/kit/authoring/empty-project-authoring.ts +22 -0
  84. package/src/kit/authoring/instance-source-menu.ts +135 -0
  85. package/src/kit/authoring/layered-pick.ts +185 -0
  86. package/src/kit/authoring/mounted-root-subjects.ts +146 -0
  87. package/src/kit/authoring/no-authoring-adapter.ts +59 -0
  88. package/src/kit/authoring/object3d-document-persistence.ts +122 -0
  89. package/src/kit/authoring/panel-authoring.ts +121 -0
  90. package/src/kit/authoring/project-authoring-session.ts +105 -0
  91. package/src/kit/authoring/provenance.ts +99 -0
  92. package/src/kit/authoring/react-canvas-navigation.ts +259 -0
  93. package/src/kit/authoring/react-design-canvas-style.ts +20 -0
  94. package/src/kit/authoring/react-story-board.ts +917 -0
  95. package/src/kit/authoring/selection-scope.ts +195 -0
  96. package/src/kit/authoring/shell-document-ops.ts +169 -0
  97. package/src/kit/authoring/story-board-chrome-fit.ts +107 -0
  98. package/src/kit/authoring/story-board-presentation.ts +111 -0
  99. package/src/kit/authoring/three-root.ts +67 -0
  100. package/src/kit/authoring/viewport-tool-context.ts +73 -0
  101. package/src/kit/authoring/viewport-tool-owner.ts +38 -0
  102. package/src/kit/authoring/world-session-state.ts +101 -0
  103. package/src/kit/authoring-seam-evidence.ts +300 -0
  104. package/src/kit/availability-tick.ts +66 -0
  105. package/src/kit/bitmap-label.ts +120 -0
  106. package/src/kit/boot-routing.ts +392 -0
  107. package/src/kit/breakpoint-state.ts +43 -0
  108. package/src/kit/build-identity.ts +16 -0
  109. package/src/kit/bytes-codec.ts +62 -0
  110. package/src/kit/cancellation-reason.ts +58 -0
  111. package/src/kit/canvas-frames.ts +88 -0
  112. package/src/kit/capture-camera-pose.ts +77 -0
  113. package/src/kit/capture-size.ts +88 -0
  114. package/src/kit/chrome-registry.ts +159 -0
  115. package/src/kit/chrome-slot-registry.ts +91 -0
  116. package/src/kit/collaboration-client.ts +264 -0
  117. package/src/kit/collaboration-presence.ts +41 -0
  118. package/src/kit/command-dispatch.ts +19 -0
  119. package/src/kit/command-listener.ts +2182 -0
  120. package/src/kit/command-registry.ts +71 -0
  121. package/src/kit/component-board-registry.ts +205 -0
  122. package/src/kit/component-states-registry.ts +199 -0
  123. package/src/kit/components/AlignToolbar.tsx +204 -0
  124. package/src/kit/components/ApplicationMenus.tsx +372 -0
  125. package/src/kit/components/AssetEditorShell.tsx +216 -0
  126. package/src/kit/components/AssetInspectorToolSection.tsx +124 -0
  127. package/src/kit/components/BoardRulers.tsx +354 -0
  128. package/src/kit/components/CanvasAddNodeDialogs.tsx +529 -0
  129. package/src/kit/components/CanvasSceneViewport.tsx +1195 -0
  130. package/src/kit/components/ChromeSlot.tsx +20 -0
  131. package/src/kit/components/CodeView.tsx +470 -0
  132. package/src/kit/components/CompactInspectorShell.tsx +39 -0
  133. package/src/kit/components/ConsolePanel.tsx +273 -0
  134. package/src/kit/components/GameplaySessionTimeline.tsx +295 -0
  135. package/src/kit/components/InspectionProjection.tsx +932 -0
  136. package/src/kit/components/Inspector.tsx +270 -0
  137. package/src/kit/components/InspectorCanvasPreview.tsx +35 -0
  138. package/src/kit/components/InspectorFieldsSection.tsx +290 -0
  139. package/src/kit/components/InspectorStoriesSection.tsx +92 -0
  140. package/src/kit/components/InspectorToolSection.tsx +96 -0
  141. package/src/kit/components/InspectorTransformSection.tsx +245 -0
  142. package/src/kit/components/LightExplorerPanel.tsx +433 -0
  143. package/src/kit/components/MediaProperties.tsx +145 -0
  144. package/src/kit/components/ProjectHeader.tsx +328 -0
  145. package/src/kit/components/ReactCanvasControls.tsx +358 -0
  146. package/src/kit/components/RootSelectionOverlay.tsx +3688 -0
  147. package/src/kit/components/RootTextEditor.tsx +79 -0
  148. package/src/kit/components/SaveStatus.tsx +70 -0
  149. package/src/kit/components/SurfaceCrashBoundary.tsx +105 -0
  150. package/src/kit/components/SurfaceStateOverlay.tsx +24 -0
  151. package/src/kit/components/ToolContributionSurfaces.tsx +49 -0
  152. package/src/kit/components/ToolHost.tsx +380 -0
  153. package/src/kit/components/Toolbar.tsx +811 -0
  154. package/src/kit/components/TransientHint.tsx +44 -0
  155. package/src/kit/components/VersionControlSection.tsx +470 -0
  156. package/src/kit/components/ViewportOverlaysMenu.tsx +177 -0
  157. package/src/kit/components/VolterLogo.tsx +18 -0
  158. package/src/kit/components/WorktreeSwitcher.tsx +712 -0
  159. package/src/kit/components/account-documents.tsx +1162 -0
  160. package/src/kit/components/asset-documents.tsx +794 -0
  161. package/src/kit/components/asset-editor-persistence.ts +216 -0
  162. package/src/kit/components/asset-selection-section.tsx +545 -0
  163. package/src/kit/components/asset-thumbnails.tsx +307 -0
  164. package/src/kit/components/asset-viewers/AudioViewer.tsx +201 -0
  165. package/src/kit/components/asset-viewers/GenericJsonViewer.tsx +102 -0
  166. package/src/kit/components/asset-viewers/ImageViewer.tsx +300 -0
  167. package/src/kit/components/asset-viewers/JsonAssetDocument.tsx +98 -0
  168. package/src/kit/components/asset-viewers/OnlineAssetDetail.tsx +426 -0
  169. package/src/kit/components/asset-viewers/SourceAssetViewer.tsx +356 -0
  170. package/src/kit/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
  171. package/src/kit/components/asset-viewers/VideoViewer.tsx +101 -0
  172. package/src/kit/components/asset-viewers/shader-source.ts +144 -0
  173. package/src/kit/components/board-guides.ts +150 -0
  174. package/src/kit/components/canvas-scene-hotkeys.ts +37 -0
  175. package/src/kit/components/canvas-temporary-pivot.ts +34 -0
  176. package/src/kit/components/core-utilities.tsx +94 -0
  177. package/src/kit/components/inspector-preview-section.tsx +223 -0
  178. package/src/kit/components/inspector-revert-label.ts +20 -0
  179. package/src/kit/components/inspector-selection.ts +42 -0
  180. package/src/kit/components/inspector-stories-gating.ts +171 -0
  181. package/src/kit/components/inspector-transform-subject.ts +11 -0
  182. package/src/kit/components/inspector-transform.ts +88 -0
  183. package/src/kit/components/kind-documents.tsx +544 -0
  184. package/src/kit/components/primitives/DraftColorInput.tsx +74 -0
  185. package/src/kit/components/project-tool-documents.tsx +402 -0
  186. package/src/kit/components/scene-documents.tsx +221 -0
  187. package/src/kit/components/status-contributions.tsx +407 -0
  188. package/src/kit/components/tool-documents.tsx +302 -0
  189. package/src/kit/components/tool-schema-form.tsx +262 -0
  190. package/src/kit/components/use-after-paint.ts +41 -0
  191. package/src/kit/components/use-project-image-assets.ts +86 -0
  192. package/src/kit/components/workspace-history.ts +32 -0
  193. package/src/kit/components/world-documents.tsx +570 -0
  194. package/src/kit/components/world-overlay-gestures.ts +1939 -0
  195. package/src/kit/composite-screenshot.ts +2238 -0
  196. package/src/kit/content-entry-source-registry.ts +184 -0
  197. package/src/kit/contribution-surfaces.ts +48 -0
  198. package/src/kit/coverage/canvas-reveal.ts +192 -0
  199. package/src/kit/coverage/design-time-surfaces.ts +101 -0
  200. package/src/kit/coverage/ontology-invariants.ts +466 -0
  201. package/src/kit/coverage/session-vitals.ts +503 -0
  202. package/src/kit/crash-null-boundary.ts +36 -0
  203. package/src/kit/creation-site-edit.ts +1491 -0
  204. package/src/kit/creation-site-registry.ts +160 -0
  205. package/src/kit/delegate-harness-registry.ts +134 -0
  206. package/src/kit/document-areas.ts +70 -0
  207. package/src/kit/document-context-registry.ts +193 -0
  208. package/src/kit/document-open-registry.ts +200 -0
  209. package/src/kit/document-play-extension.ts +221 -0
  210. package/src/kit/document-preview-source.ts +20 -0
  211. package/src/kit/document-renderer-session.ts +138 -0
  212. package/src/kit/document-stage-sessions.ts +26 -0
  213. package/src/kit/document-viewports.ts +120 -0
  214. package/src/kit/editor-api.ts +46 -0
  215. package/src/kit/editor-chrome-capture.ts +136 -0
  216. package/src/kit/editor-commands.ts +176 -0
  217. package/src/kit/editor-console.ts +580 -0
  218. package/src/kit/editor-current-view.ts +56 -0
  219. package/src/kit/editor-document-probe.ts +1166 -0
  220. package/src/kit/editor-git-client.ts +115 -0
  221. package/src/kit/editor-hotkeys.ts +728 -0
  222. package/src/kit/editor-lease-view.ts +39 -0
  223. package/src/kit/editor-lease.ts +415 -0
  224. package/src/kit/editor-mode.ts +19 -0
  225. package/src/kit/editor-notifications.ts +140 -0
  226. package/src/kit/editor-presence.ts +563 -0
  227. package/src/kit/editor-presentation-activity.ts +58 -0
  228. package/src/kit/editor-presentation-notice.ts +42 -0
  229. package/src/kit/editor-runtime.tsx +147 -0
  230. package/src/kit/editor-server-response.ts +86 -0
  231. package/src/kit/editor-session-attribution.ts +85 -0
  232. package/src/kit/editor-session-mode.ts +54 -0
  233. package/src/kit/editor-state-facets.ts +74 -0
  234. package/src/kit/editor-view-presentation.ts +777 -0
  235. package/src/kit/environment-images.ts +58 -0
  236. package/src/kit/eyedropper-session.ts +60 -0
  237. package/src/kit/files/file-provider.ts +62 -0
  238. package/src/kit/files/project-files.ts +270 -0
  239. package/src/kit/finders/index.ts +137 -0
  240. package/src/kit/finders/scenes-from-entrypoint-selection.ts +387 -0
  241. package/src/kit/frame/frame-parts.ts +30 -0
  242. package/src/kit/framed-document-capture.ts +34 -0
  243. package/src/kit/game-globals-prelude.ts +143 -0
  244. package/src/kit/game-surface-defaults.ts +33 -0
  245. package/src/kit/gameplay-dom-recording.ts +318 -0
  246. package/src/kit/gameplay-export-state.ts +14 -0
  247. package/src/kit/gameplay-replay.ts +417 -0
  248. package/src/kit/gameplay-session-time.ts +9 -0
  249. package/src/kit/gameplay-sessions.ts +204 -0
  250. package/src/kit/hierarchy-component-marks.ts +298 -0
  251. package/src/kit/hierarchy-internals.ts +197 -0
  252. package/src/kit/hierarchy-kind-icon.ts +217 -0
  253. package/src/kit/hierarchy-menu-registry.ts +67 -0
  254. package/src/kit/hierarchy-node-rows.ts +307 -0
  255. package/src/kit/hierarchy-panel-view.ts +280 -0
  256. package/src/kit/hierarchy-projection.ts +76 -0
  257. package/src/kit/hierarchy-row-media.ts +45 -0
  258. package/src/kit/hierarchy-row-model.ts +308 -0
  259. package/src/kit/hierarchy-rows.ts +11 -0
  260. package/src/kit/hierarchy-walk.ts +86 -0
  261. package/src/kit/history/editor-session.ts +25 -0
  262. package/src/kit/history/history-commands.ts +147 -0
  263. package/src/kit/history/history-delegate.ts +187 -0
  264. package/src/kit/history/history-limit-notices.ts +43 -0
  265. package/src/kit/history/history-service.ts +1189 -0
  266. package/src/kit/history/persistence-coordinator.ts +35 -0
  267. package/src/kit/history/project-file-history.ts +386 -0
  268. package/src/kit/history/project-root-history-backends.ts +139 -0
  269. package/src/kit/history/resource-registry.ts +209 -0
  270. package/src/kit/history/snapshot-store.ts +103 -0
  271. package/src/kit/history/source-history-backend.ts +546 -0
  272. package/src/kit/history-types.ts +124 -0
  273. package/src/kit/hmr-registration-group.ts +67 -0
  274. package/src/kit/hmr-stable-react-context.ts +23 -0
  275. package/src/kit/hotkeys.ts +190 -0
  276. package/src/kit/inference-diagnostics.ts +69 -0
  277. package/src/kit/initial-project.ts +80 -0
  278. package/src/kit/inspection/active-subject.ts +571 -0
  279. package/src/kit/inspection/active-surface.ts +142 -0
  280. package/src/kit/inspection/compose-subject.ts +1055 -0
  281. package/src/kit/inspection/compose.ts +7 -0
  282. package/src/kit/inspection/display.ts +171 -0
  283. package/src/kit/inspection/document-subject.ts +109 -0
  284. package/src/kit/inspection/game-subject.ts +85 -0
  285. package/src/kit/inspection/null-subject.ts +119 -0
  286. package/src/kit/inspection/serialize.ts +357 -0
  287. package/src/kit/inspection/use-active-inspection.ts +180 -0
  288. package/src/kit/inspection-model.ts +542 -0
  289. package/src/kit/inspection-node-media.ts +58 -0
  290. package/src/kit/inspector-presentation.ts +203 -0
  291. package/src/kit/inspector-property-grouping.ts +64 -0
  292. package/src/kit/inspector-section-registry.ts +221 -0
  293. package/src/kit/instance-source-actions.ts +163 -0
  294. package/src/kit/js-heap.ts +71 -0
  295. package/src/kit/key-actions.ts +91 -0
  296. package/src/kit/keymap-presets.ts +428 -0
  297. package/src/kit/layout-policy.ts +31 -0
  298. package/src/kit/light-explorer-model.ts +134 -0
  299. package/src/kit/live-canvas-frame.ts +55 -0
  300. package/src/kit/live-document.ts +296 -0
  301. package/src/kit/live-gesture-lock.ts +50 -0
  302. package/src/kit/live-seam-evidence.ts +11 -0
  303. package/src/kit/live-session-registry.ts +220 -0
  304. package/src/kit/live-transition.ts +391 -0
  305. package/src/kit/manifest-project.ts +107 -0
  306. package/src/kit/module-fetch-diagnosis.ts +192 -0
  307. package/src/kit/mount-failure-report.ts +154 -0
  308. package/src/kit/native-selection-style.ts +497 -0
  309. package/src/kit/object3d-document-write-policy.ts +137 -0
  310. package/src/kit/packaged-runtime.ts +108 -0
  311. package/src/kit/palettes/maya.palette.json +57 -0
  312. package/src/kit/palettes/substance.palette.json +57 -0
  313. package/src/kit/performance-profiler.ts +367 -0
  314. package/src/kit/performance-sources.ts +69 -0
  315. package/src/kit/photograph-notice.ts +141 -0
  316. package/src/kit/play-boot-phase.ts +166 -0
  317. package/src/kit/play-camera-flight.ts +35 -0
  318. package/src/kit/png-encode.worker.ts +26 -0
  319. package/src/kit/presentation-surface.ts +248 -0
  320. package/src/kit/product-command.ts +90 -0
  321. package/src/kit/project-adapter.ts +1140 -0
  322. package/src/kit/project-asset-refresh.ts +23 -0
  323. package/src/kit/project-asset-roots.ts +68 -0
  324. package/src/kit/project-local-state.ts +151 -0
  325. package/src/kit/project-manager.ts +243 -0
  326. package/src/kit/project-module-changes.ts +201 -0
  327. package/src/kit/project-module-split.ts +270 -0
  328. package/src/kit/project-play-layers.ts +25 -0
  329. package/src/kit/project-provenance.ts +115 -0
  330. package/src/kit/project-ready.ts +42 -0
  331. package/src/kit/project-shape.ts +68 -0
  332. package/src/kit/project-tools.ts +107 -0
  333. package/src/kit/projection-types.ts +44 -0
  334. package/src/kit/readiness.ts +113 -0
  335. package/src/kit/renderer-resource-counts.ts +27 -0
  336. package/src/kit/reported-play-state.ts +90 -0
  337. package/src/kit/resolve-contributed-command.ts +14 -0
  338. package/src/kit/resolve-relative-specifier.ts +33 -0
  339. package/src/kit/retained-document-states.ts +91 -0
  340. package/src/kit/scene-document-plan.ts +320 -0
  341. package/src/kit/scene-live-open.ts +210 -0
  342. package/src/kit/scoped-game-css.ts +152 -0
  343. package/src/kit/served-url.ts +5 -0
  344. package/src/kit/session-close.ts +17 -0
  345. package/src/kit/session-tombstone.ts +127 -0
  346. package/src/kit/settings/settings-provider.ts +82 -0
  347. package/src/kit/settings-store.ts +348 -0
  348. package/src/kit/shell-document-state.ts +27 -0
  349. package/src/kit/shell-store-door.ts +45 -0
  350. package/src/kit/shell-store.ts +722 -0
  351. package/src/kit/source-conflict.ts +122 -0
  352. package/src/kit/stage-context.ts +377 -0
  353. package/src/kit/stage-invalidation.ts +25 -0
  354. package/src/kit/stage-store-registry.ts +69 -0
  355. package/src/kit/startup-failure.ts +80 -0
  356. package/src/kit/state-report-deferral.ts +73 -0
  357. package/src/kit/storage/host-files-storage.ts +97 -0
  358. package/src/kit/storage/http-storage.ts +174 -0
  359. package/src/kit/storage/index.ts +75 -0
  360. package/src/kit/storage/mem-storage.ts +158 -0
  361. package/src/kit/storage/path-lock.ts +44 -0
  362. package/src/kit/storage/paths.ts +26 -0
  363. package/src/kit/storage-types.ts +127 -0
  364. package/src/kit/stories/StoryPreviewMount.tsx +306 -0
  365. package/src/kit/stories/compose-project-stories.ts +255 -0
  366. package/src/kit/stories/prefabs-finder.ts +54 -0
  367. package/src/kit/stories/prefabs-from-stories.ts +182 -0
  368. package/src/kit/stories/project-story-regions.ts +24 -0
  369. package/src/kit/stories/story-capture.ts +579 -0
  370. package/src/kit/stories/story-declared-medium.ts +126 -0
  371. package/src/kit/stories/story-discovery.ts +176 -0
  372. package/src/kit/stories/story-dom-runtime.ts +78 -0
  373. package/src/kit/stories/story-grouping.ts +111 -0
  374. package/src/kit/stories/story-mount-turn.ts +27 -0
  375. package/src/kit/stories/story-presentation.ts +215 -0
  376. package/src/kit/stories/story-preview-component.ts +7 -0
  377. package/src/kit/stories/story-registry.ts +530 -0
  378. package/src/kit/stories-scope.ts +35 -0
  379. package/src/kit/story-document-openers.ts +36 -0
  380. package/src/kit/story-thumbnails.ts +47 -0
  381. package/src/kit/surface-keyboard.ts +101 -0
  382. package/src/kit/surface-state.ts +135 -0
  383. package/src/kit/system-seam-evidence.ts +72 -0
  384. package/src/kit/tab-census.ts +202 -0
  385. package/src/kit/tab-lifecycle-client.ts +227 -0
  386. package/src/kit/theme-library.ts +897 -0
  387. package/src/kit/theme-preference.ts +429 -0
  388. package/src/kit/three-viewport-presentation.ts +23 -0
  389. package/src/kit/tool-contribution-play.ts +74 -0
  390. package/src/kit/tool-loader.ts +1918 -0
  391. package/src/kit/transform-mode-request.ts +66 -0
  392. package/src/kit/transient-hint.ts +78 -0
  393. package/src/kit/transport-strip.tsx +174 -0
  394. package/src/kit/ui-source/adapter-region-includes.ts +238 -0
  395. package/src/kit/ui-source/file-region-resolver.ts +302 -0
  396. package/src/kit/ui-source/inspect.ts +775 -0
  397. package/src/kit/ui-source/source-write-backend.ts +605 -0
  398. package/src/kit/ui-source/tier-source-write-backend.ts +279 -0
  399. package/src/kit/user-local-state.ts +105 -0
  400. package/src/kit/viewport-activation-timings.ts +840 -0
  401. package/src/kit/viewport-editor-controls.ts +22 -0
  402. package/src/kit/viewport-presentation.ts +668 -0
  403. package/src/kit/viewport-surface-status.tsx +55 -0
  404. package/src/kit/wait-until.ts +37 -0
  405. package/src/kit/worker-call-metrics.ts +166 -0
  406. package/src/kit/workspace-areas.ts +191 -0
  407. package/src/kit/workspace-aux-commands.ts +11 -0
  408. package/src/kit/workspace-available-documents.ts +142 -0
  409. package/src/kit/workspace-core-utilities.ts +31 -0
  410. package/src/kit/workspace-document-ids.ts +59 -0
  411. package/src/kit/workspace-document-registry.ts +624 -0
  412. package/src/kit/workspace-document-restore.ts +146 -0
  413. package/src/kit/workspace-host-commands.ts +141 -0
  414. package/src/kit/workspace-persistence-gate.ts +40 -0
  415. package/src/kit/workspace-play-utilities.ts +44 -0
  416. package/src/kit/workspace-presets.ts +446 -0
  417. package/src/kit/workspace-regions.ts +276 -0
  418. package/src/kit/workspace-static-panels.ts +73 -0
  419. package/src/kit/workspace-status-registry.ts +121 -0
  420. package/src/kit/workspace-storage.ts +35 -0
  421. package/src/kit/workspace-style.ts +226 -0
  422. package/src/kit/workspace-utility-commands.ts +74 -0
  423. package/src/kit/workspace-utility-registry.ts +263 -0
  424. package/src/kit/world-adoption-event.ts +23 -0
  425. package/src/kit/world-adoption.ts +115 -0
  426. package/src/kit/world-canvas-viewport-state.ts +35 -0
  427. package/src/kit/world-document-routing.ts +104 -0
  428. package/src/kit/world-pan-state.ts +198 -0
  429. package/src/kit/write-pipe.ts +173 -0
  430. package/src/layout-arrangements.ts +5 -0
  431. package/src/layouts.tsx +108 -0
  432. package/src/looks.ts +16 -0
  433. package/src/project/output-roots.ts +73 -0
  434. package/src/project/tab-census.ts +155 -0
  435. package/src/project-tool-catalog.ts +104 -0
  436. package/src/selection.tsx +107 -0
  437. package/src/services.ts +18 -0
  438. package/src/session/build-report.ts +22 -0
  439. package/src/session/collaboration-types.ts +262 -0
  440. package/src/session/command-table.ts +327 -0
  441. package/src/session/discovery.ts +100 -0
  442. package/src/session/editor-brand.ts +48 -0
  443. package/src/session/editor-compatibility.ts +317 -0
  444. package/src/session/editor-control-lifecycle.ts +68 -0
  445. package/src/session/editor-control-protocol.ts +5 -0
  446. package/src/session/entrypoint-selection-readers.ts +66 -0
  447. package/src/session/entrypoint-selection-source.ts +120 -0
  448. package/src/session/game-css-scope.ts +30 -0
  449. package/src/session/hosted-attachment.ts +225 -0
  450. package/src/session/limited-view.ts +82 -0
  451. package/src/session/product-create.ts +24 -0
  452. package/src/session/product-locator.ts +478 -0
  453. package/src/session/project-module-url.ts +242 -0
  454. package/src/session/project-serving.ts +164 -0
  455. package/src/session/project-upgrade.ts +403 -0
  456. package/src/session/registry-format.ts +210 -0
  457. package/src/session/relative-path-guard.ts +56 -0
  458. package/src/session/scoped-game-css.ts +461 -0
  459. package/src/session/source-glob.ts +15 -0
  460. package/src/session/tool-contribution-convention.ts +123 -0
  461. package/src/session/workbench-locator.ts +712 -0
  462. package/src/session.ts +41 -0
  463. package/src/share.ts +160 -0
  464. package/src/source-analysis.ts +28 -0
  465. package/src/source-authoring.ts +439 -0
  466. package/src/tools/errors.ts +91 -0
  467. package/src/tools/provider-execution.ts +70 -0
  468. package/src/tools/registry.ts +341 -0
  469. package/src/tools/types.ts +159 -0
  470. package/src/transport.ts +100 -0
  471. package/src/types.ts +1693 -0
  472. package/src/views.ts +164 -0
  473. package/src/widgets/design-system.ts +93 -0
  474. package/src/widgets/editor-appearance.ts +151 -0
  475. package/src/widgets/editor-material.ts +83 -0
  476. package/src/widgets/icon-set-registry.ts +105 -0
  477. package/src/widgets/index.ts +71 -0
  478. package/src/widgets/inspector-widgets/AlignmentGrid.tsx +182 -0
  479. package/src/widgets/inspector-widgets/AssetSlotPicker.tsx +123 -0
  480. package/src/widgets/inspector-widgets/BorderEditor.tsx +309 -0
  481. package/src/widgets/inspector-widgets/ColorPicker.tsx +549 -0
  482. package/src/widgets/inspector-widgets/CurveEditor.tsx +359 -0
  483. package/src/widgets/inspector-widgets/FilterEditor.tsx +108 -0
  484. package/src/widgets/inspector-widgets/FontPicker.tsx +191 -0
  485. package/src/widgets/inspector-widgets/GradientEditor.tsx +623 -0
  486. package/src/widgets/inspector-widgets/ScrubbableInput.tsx +180 -0
  487. package/src/widgets/inspector-widgets/ShadowEditor.tsx +319 -0
  488. package/src/widgets/inspector-widgets/color-utils.ts +201 -0
  489. package/src/widgets/inspector-widgets/curve-utils.ts +212 -0
  490. package/src/widgets/inspector-widgets/index.ts +25 -0
  491. package/src/widgets/inspector-widgets/shared.tsx +140 -0
  492. package/src/widgets/interactive-edit-scope.ts +33 -0
  493. package/src/widgets/patterns/Dialog.tsx +140 -0
  494. package/src/widgets/patterns/Fields.tsx +44 -0
  495. package/src/widgets/patterns/List.tsx +25 -0
  496. package/src/widgets/patterns/StateSurface.tsx +40 -0
  497. package/src/widgets/patterns/Surfaces.tsx +122 -0
  498. package/src/widgets/patterns/Tabs.tsx +80 -0
  499. package/src/widgets/patterns/Toolbar.tsx +72 -0
  500. package/src/widgets/patterns/Tree.tsx +72 -0
  501. package/src/widgets/primitives/AnchoredMenu.tsx +260 -0
  502. package/src/widgets/primitives/Button.tsx +62 -0
  503. package/src/widgets/primitives/ColorInput.tsx +78 -0
  504. package/src/widgets/primitives/DraftTextInput.tsx +63 -0
  505. package/src/widgets/primitives/EditorIcon.tsx +157 -0
  506. package/src/widgets/primitives/FormControls.tsx +88 -0
  507. package/src/widgets/primitives/HoverPreview.tsx +96 -0
  508. package/src/widgets/primitives/JsonInput.tsx +113 -0
  509. package/src/widgets/primitives/Layout.tsx +100 -0
  510. package/src/widgets/primitives/Menu.tsx +161 -0
  511. package/src/widgets/primitives/NumberInput.tsx +169 -0
  512. package/src/widgets/primitives/Panel.tsx +80 -0
  513. package/src/widgets/primitives/SectionHeader.tsx +77 -0
  514. package/src/widgets/primitives/Text.tsx +54 -0
  515. package/src/widgets/primitives/ThemeRootPortal.tsx +52 -0
  516. package/src/widgets/primitives/Tooltip.tsx +204 -0
  517. package/src/widgets/primitives/Vec3Input.tsx +70 -0
  518. package/src/widgets/primitives/banner-tones.ts +32 -0
  519. package/src/widgets/primitives/clamp-to-viewport.ts +44 -0
  520. package/src/widgets/primitives/editor-icons.ts +254 -0
  521. package/src/widgets/primitives/panel-header-styles.ts +42 -0
  522. package/src/widgets/theme.ts +2841 -0
  523. package/src/widgets/z-index.ts +25 -0
@@ -0,0 +1,372 @@
1
+ import {
2
+ AnchoredMenu,
3
+ EditorIcon,
4
+ editorIcons,
5
+ MenuItem,
6
+ MenuTrigger,
7
+ MenuSeparator as Separator,
8
+ } from '@volter/sdk/widgets';
9
+ import { type RefObject, useRef, useState, useSyncExternalStore } from 'react';
10
+ import { getActiveAuthoring } from '@volter/sdk/kit/authoring/active-adapter';
11
+ import { selectAllAuthoringNodes } from '@volter/sdk/kit/authoring/shell-document-ops';
12
+ import { useAvailabilitySelector } from '@volter/sdk/kit/availability-tick';
13
+ import {
14
+ contributedChromeVersion,
15
+ contributedDisabledFingerprint,
16
+ contributedMenuItems,
17
+ subscribeContributedChrome,
18
+ } from '@volter/sdk/kit/chrome-registry';
19
+ import { openCommandPalette } from '@volter/sdk/kit/editor-commands';
20
+ import { editorConsole } from '@volter/sdk/kit/editor-console';
21
+ import { currentEditorViewUrl } from '../editor-current-view';
22
+ import {
23
+ copySelection,
24
+ cutSelection,
25
+ deleteSelection,
26
+ duplicateSelection,
27
+ pasteSelection,
28
+ } from '@volter/sdk/kit/editor-hotkeys';
29
+ import { useEditorStore, useHistoryCommandSnapshot, useHistoryCommands } from '@volter/sdk/kit/editor-runtime';
30
+ import { editorKeymapsVersion, subscribeEditorKeymap } from '@volter/sdk/kit/keymap-presets';
31
+ import { getProjectTools, subscribeProjectTools } from '@volter/sdk/kit/project-tools';
32
+ import { getSurfaceToolContributions, subscribeToolContributions } from '@volter/sdk/kit/tool-loader';
33
+ import { openUndoHistory } from '@volter/sdk/kit/workspace-aux-commands';
34
+ import { CORE_WORKSPACE_UTILITIES } from '@volter/sdk/kit/workspace-core-utilities';
35
+ import {
36
+ showWorkspaceStaticPanel,
37
+ showWorkspaceUtility,
38
+ toggleWorkspaceFocus,
39
+ } from '@volter/sdk/kit/workspace-host-commands';
40
+ import {
41
+ activeEditorWorkspace,
42
+ editorWorkspaces,
43
+ editorWorkspacesVersion,
44
+ setEditorWorkspace,
45
+ subscribeEditorWorkspace,
46
+ subscribeEditorWorkspaces,
47
+ workspaceApplies,
48
+ } from '@volter/sdk/kit/workspace-presets';
49
+ import { subscribeWorkspaceStyles, workspaceStylesVersion } from '@volter/sdk/kit/workspace-style';
50
+ import { toggleConsoleUtility } from '@volter/sdk/kit/workspace-utility-commands';
51
+ import { openProjectToolsDocument } from '@volter/sdk/kit/components/project-tool-documents';
52
+ import { openToolDocument } from '@volter/sdk/kit/components/tool-documents';
53
+
54
+ type MenuId = 'edit' | 'view' | 'window' | 'debug' | 'tools' | 'help';
55
+
56
+ export function ApplicationMenus() {
57
+ const store = useEditorStore();
58
+ const activeAuthoring = getActiveAuthoring(store);
59
+ const structure = activeAuthoring.structure;
60
+ const clipboardIds = [...store.selectedEntityIds];
61
+ const selectedId = clipboardIds[0];
62
+ const pasteParentId = selectedId
63
+ ? (activeAuthoring.hierarchy.node(selectedId)?.parentId ?? null)
64
+ : null;
65
+ const history = useHistoryCommands();
66
+ const historySnapshot = useHistoryCommandSnapshot();
67
+ // DOCUMENTS AND UTILITIES BOTH: this menu is the only door onto a project's
68
+ // `workspace.utility` drawer tab, which registers hidden by default.
69
+ const tools = useSyncExternalStore(
70
+ subscribeToolContributions,
71
+ getSurfaceToolContributions,
72
+ getSurfaceToolContributions,
73
+ );
74
+ // The three look registries: a package's workspace, keymap or style that
75
+ // registers after this menu mounted still lists (WORKBENCH.md §Contribution points).
76
+ useSyncExternalStore(subscribeEditorWorkspaces, editorWorkspacesVersion, editorWorkspacesVersion);
77
+ useSyncExternalStore(subscribeEditorKeymap, editorKeymapsVersion, editorKeymapsVersion);
78
+ useSyncExternalStore(subscribeWorkspaceStyles, workspaceStylesVersion, workspaceStylesVersion);
79
+ useSyncExternalStore(
80
+ subscribeContributedChrome,
81
+ contributedChromeVersion,
82
+ contributedChromeVersion,
83
+ );
84
+ /** A package's items at the end of a menu (`@volter/sdk/chrome`). */
85
+ const contributed = (menu: 'view' | 'window' | 'debug' | 'tools' | 'help') => {
86
+ const items = contributedMenuItems(menu);
87
+ if (items.length === 0) return null;
88
+ return (
89
+ <>
90
+ <Separator />
91
+ {items.map((item) => (
92
+ <MenuItem
93
+ key={item.id}
94
+ {...(item.testId ? { 'data-testid': item.testId } : {})}
95
+ disabled={item.disabled?.({}) ?? false}
96
+ onSelect={choose(() => item.execute({}))}
97
+ >
98
+ {typeof item.label === 'function' ? item.label() : item.label}
99
+ </MenuItem>
100
+ ))}
101
+ </>
102
+ );
103
+ };
104
+ const commands = useSyncExternalStore(subscribeProjectTools, getProjectTools, getProjectTools);
105
+ const workspace = useSyncExternalStore(
106
+ subscribeEditorWorkspace,
107
+ activeEditorWorkspace,
108
+ activeEditorWorkspace,
109
+ );
110
+ const [open, setOpen] = useState<MenuId | null>(null);
111
+ // A contributed item's `disabled` (and dynamic label) is asked at render,
112
+ // and the point promises it may follow session state — which needs
113
+ // SOMETHING to re-render the bar when that state moves. Sample the answers
114
+ // on the shared availability tick, but only while a menu is open: closed,
115
+ // this costs nothing; open, an item can go live or dead under the cursor.
116
+ useAvailabilitySelector(() => (open ? contributedDisabledFingerprint() : ''));
117
+ const rootRef = useRef<HTMLDivElement>(null);
118
+ // ONE STABLE REF PER MENU WORD, minted on first ask. `AnchoredMenu` measures
119
+ // this element every layout pass, so a fresh object per render would rebuild
120
+ // its placement callback on every one.
121
+ const anchorRefs = useRef<Record<string, RefObject<HTMLDivElement | null>>>({});
122
+ const anchorRef = (id: MenuId): RefObject<HTMLDivElement | null> =>
123
+ (anchorRefs.current[id] ??= { current: null });
124
+
125
+ // NO OUTSIDE-POINTER LISTENER OF ITS OWN. `AnchoredMenu` dismisses on a press outside the open
126
+ // menu and its trigger (`onDismiss` below), and the menu is PORTALED out of this bar: a listener
127
+ // asking whether the press was inside the bar answered no for the menu's own rows and closed it
128
+ // on `pointerdown`, before the row's `click`. Every Edit, View and Window item then did nothing
129
+ // for a person (measured 2026-09-28 with a real click on the browser-substrate page).
130
+
131
+ // A command that FAILS says so in the console, as the same verb over the wire does: a click
132
+ // that changed nothing and said nothing reads as a dead menu.
133
+ const choose = (action: () => unknown | Promise<unknown>) => () => {
134
+ setOpen(null);
135
+ Promise.resolve()
136
+ .then(action)
137
+ .catch((error: unknown) =>
138
+ editorConsole.error(
139
+ `The menu command failed: ${error instanceof Error ? error.message : String(error)}`,
140
+ 'editor',
141
+ ),
142
+ );
143
+ };
144
+ const panels: Record<MenuId, React.ReactNode> = {
145
+ edit: (
146
+ <>
147
+ <MenuItem
148
+ disabled={historySnapshot.busy || !historySnapshot.canUndo}
149
+ onSelect={choose(() => history.undo())}
150
+ >
151
+ {historySnapshot.undoLabel ? `Undo ${historySnapshot.undoLabel}` : 'Undo'}
152
+ </MenuItem>
153
+ <MenuItem
154
+ disabled={historySnapshot.busy || !historySnapshot.canRedo}
155
+ onSelect={choose(() => history.redo())}
156
+ >
157
+ {historySnapshot.redoLabel ? `Redo ${historySnapshot.redoLabel}` : 'Redo'}
158
+ </MenuItem>
159
+ <Separator />
160
+ <MenuItem onSelect={choose(openUndoHistory)}>Undo History…</MenuItem>
161
+ <Separator />
162
+ <MenuItem
163
+ disabled={
164
+ clipboardIds.length === 0 ||
165
+ !structure?.cut ||
166
+ !(structure.canCopy?.(clipboardIds) ?? true)
167
+ }
168
+ onSelect={choose(() => cutSelection(store))}
169
+ >
170
+ Cut
171
+ </MenuItem>
172
+ <MenuItem
173
+ disabled={
174
+ clipboardIds.length === 0 ||
175
+ !structure?.copy ||
176
+ !(structure.canCopy?.(clipboardIds) ?? true)
177
+ }
178
+ onSelect={choose(() => copySelection(store))}
179
+ >
180
+ Copy
181
+ </MenuItem>
182
+ <MenuItem
183
+ disabled={!structure?.paste || !(structure.canPaste?.(pasteParentId) ?? true)}
184
+ onSelect={choose(() => pasteSelection(store))}
185
+ >
186
+ Paste
187
+ </MenuItem>
188
+ <Separator />
189
+ <MenuItem
190
+ disabled={store.selectedEntityIds.size === 0}
191
+ onSelect={choose(() => void duplicateSelection(store))}
192
+ >
193
+ Duplicate
194
+ </MenuItem>
195
+ <MenuItem
196
+ disabled={store.selectedEntityIds.size === 0}
197
+ onSelect={choose(() => void deleteSelection(store))}
198
+ >
199
+ Delete
200
+ </MenuItem>
201
+ <Separator />
202
+ <MenuItem onSelect={choose(() => selectAllAuthoringNodes(store))}>Select All</MenuItem>
203
+ <MenuItem
204
+ disabled={store.selectedEntityIds.size === 0}
205
+ onSelect={choose(() => store.select(null))}
206
+ >
207
+ Deselect All
208
+ </MenuItem>
209
+ </>
210
+ ),
211
+ view: (
212
+ <>
213
+ <MenuItem onSelect={choose(() => openCommandPalette())}>Command Palette…</MenuItem>
214
+ <MenuItem
215
+ onSelect={choose(async () => {
216
+ const url = currentEditorViewUrl(store);
217
+ try {
218
+ await navigator.clipboard.writeText(url);
219
+ editorConsole.log('Copied a link to the current editor view.', 'editor');
220
+ } catch (error) {
221
+ editorConsole.error(
222
+ `Could not copy the editor view link: ${error instanceof Error ? error.message : String(error)}`,
223
+ 'editor',
224
+ );
225
+ }
226
+ })}
227
+ >
228
+ Copy View Link
229
+ </MenuItem>
230
+ <Separator />
231
+ <MenuItem onSelect={choose(toggleWorkspaceFocus)}>Toggle Focus Mode</MenuItem>
232
+ {contributed('view')}
233
+ </>
234
+ ),
235
+ window: (
236
+ <>
237
+ {/* NAMED WORKSPACES (ARCHITECTURE-CORE §Editor chrome). This run IS
238
+ `Window → Workspace` — the ruling's switching door, with the active
239
+ one checked. There is deliberately no persistent picker strip, and
240
+ nothing else in the editor calls `setEditorWorkspace`: switching
241
+ happens here, through the registered actions, or through
242
+ `editor.workspace(id)`. */}
243
+ {editorWorkspaces()
244
+ .filter((choice) => workspaceApplies(choice.id))
245
+ .map((choice) => (
246
+ <MenuItem
247
+ key={choice.id}
248
+ role="menuitemradio"
249
+ aria-checked={workspace === choice.id}
250
+ data-testid={`workspace-${choice.id}`}
251
+ title={choice.description}
252
+ onSelect={choose(() => setEditorWorkspace(choice.id))}
253
+ >
254
+ <EditorIcon
255
+ icon={editorIcons.status.success}
256
+ style={{ opacity: workspace === choice.id ? 1 : 0 }}
257
+ />
258
+ Workspace: {choice.title}
259
+ </MenuItem>
260
+ ))}
261
+ <Separator />
262
+ <MenuItem onSelect={choose(toggleConsoleUtility)}>Console</MenuItem>
263
+ <MenuItem
264
+ onSelect={choose(() => showWorkspaceUtility(CORE_WORKSPACE_UTILITIES.lightExplorer.id))}
265
+ >
266
+ Light Explorer
267
+ </MenuItem>
268
+ <MenuItem onSelect={choose(() => showWorkspaceStaticPanel('asset-library'))}>
269
+ Asset Library
270
+ </MenuItem>
271
+ <MenuItem onSelect={choose(() => showWorkspaceUtility('generations'))}>
272
+ Generations
273
+ </MenuItem>
274
+ {contributed('window')}
275
+ </>
276
+ ),
277
+ debug: <>{contributed('debug')}</>,
278
+ tools: (
279
+ <>
280
+ <MenuItem onSelect={choose(() => openProjectToolsDocument())}>
281
+ Project Tools…
282
+ {commands.tools.length > 0 ? ` (${commands.tools.length})` : ''}
283
+ </MenuItem>
284
+ <Separator />
285
+ {tools.length ? (
286
+ tools.map((tool) => {
287
+ return (
288
+ <MenuItem
289
+ key={tool.id}
290
+ onSelect={choose(() => {
291
+ if (tool.point === 'workspace.document') openToolDocument(tool.id);
292
+ else showWorkspaceUtility(`tool:${tool.id}`);
293
+ })}
294
+ >
295
+ {tool.title}
296
+ </MenuItem>
297
+ );
298
+ })
299
+ ) : (
300
+ <MenuItem disabled>No custom project tools</MenuItem>
301
+ )}
302
+ {contributed('tools')}
303
+ </>
304
+ ),
305
+ // Help holds what packages contribute to it; with nothing contributed the
306
+ // bar shows no Help menu rather than an empty one.
307
+ help: contributedMenuItems('help').length > 0 ? contributed('help') : null,
308
+ };
309
+
310
+ return (
311
+ <div
312
+ ref={rootRef}
313
+ data-testid="app-menubar"
314
+ style={{ display: 'flex', alignItems: 'stretch', marginLeft: 'var(--volter-space-2)' }}
315
+ >
316
+ {(['edit', 'view', 'window', 'debug', 'tools', 'help'] as const)
317
+ .filter((id) => panels[id] !== null)
318
+ .map((id) => (
319
+ <div key={id} ref={anchorRef(id)} style={{ position: 'relative' }}>
320
+ <MenuTrigger
321
+ data-testid={`app-menu-${id}`}
322
+ aria-haspopup="menu"
323
+ aria-expanded={open === id}
324
+ onClick={() => setOpen((current) => (current === id ? null : id))}
325
+ onKeyDown={(event) => {
326
+ if (event.key !== 'ArrowDown') return;
327
+ event.preventDefault();
328
+ setOpen(id);
329
+ }}
330
+ onPointerEnter={() => {
331
+ if (open) setOpen(id);
332
+ }}
333
+ style={{ textTransform: 'capitalize' }}
334
+ >
335
+ {id}
336
+ </MenuTrigger>
337
+ {open === id && (
338
+ /* PORTALED, NOT `position: absolute`. These words live in the app's
339
+ title bar, and under the Code-OSS frame that bar is the workbench's
340
+ own `.part.titlebar` — 26 px tall with `overflow: hidden`, as are
341
+ `.titlebar-container` and our host slot inside it. An absolutely
342
+ positioned popup was laid out correctly (190x279, every item with a
343
+ box) and PAINTED one row: measured 2026-09-20 on U8's walk 3, where
344
+ the Window menu showed `Workspace: Model` and hid eleven items.
345
+ `AnchoredMenu` is the same primitive the toolbar, the telemetry
346
+ cluster and the Object3D toolbar already use for exactly this — it
347
+ measures the trigger, places the menu in viewport coordinates and
348
+ portals it to the theme root, which is outside every clip. */
349
+ <AnchoredMenu
350
+ anchorRef={anchorRef(id)}
351
+ dismissBoundaryRef={anchorRef(id)}
352
+ align="start"
353
+ gap={0}
354
+ clamp
355
+ autoFocusFirst
356
+ onDismiss={() => {
357
+ const trigger = rootRef.current?.querySelector<HTMLButtonElement>(
358
+ `[data-testid="app-menu-${id}"]`,
359
+ );
360
+ setOpen(null);
361
+ requestAnimationFrame(() => trigger?.focus());
362
+ }}
363
+ style={{ minWidth: 190 }}
364
+ >
365
+ {panels[id]}
366
+ </AnchoredMenu>
367
+ )}
368
+ </div>
369
+ ))}
370
+ </div>
371
+ );
372
+ }
@@ -0,0 +1,216 @@
1
+ /**
2
+ * The asset document shell — the frame an open asset lives in, and NOTHING
3
+ * about how it is inspected.
4
+ *
5
+ * "What is an asset in three.js but a hierarchical group of other three.js
6
+ * assets" (owner, 2026-08-07). An asset document is the three paradigm scoped
7
+ * to a SUBTREE — Unity's prefab-isolation mode: same viewport, same hierarchy,
8
+ * same inspector box, only the root changed. So the ordinary inspector rides
9
+ * over an asset document exactly as it rides over the scene: the same box in
10
+ * the same corner, draggable, minimizable, expandable to the same column, with
11
+ * the same per-surface preference (`inspection/display.ts` resolves it for the
12
+ * `asset-lab` surface like any other). This shell renders none of it.
13
+ *
14
+ * What it owns is the two things that make the document a SUBJECT PRODUCER:
15
+ *
16
+ * - it activates the asset-editor context, which is what makes the active
17
+ * inspection surface `asset-lab` (`inspection/active-surface.ts`);
18
+ * - it registers the document's SELECTION CONTEXT and publishes the
19
+ * document's own subject description (`inspection/document-subject.ts`).
20
+ *
21
+ * The selection context is the load-bearing half, and every asset document
22
+ * registers one even with nothing to select. Registering it is how a document
23
+ * says "I am the subject": without it the Inspector falls back to the shared
24
+ * entity selection, and an image viewer would show whatever was picked in the
25
+ * scene before it was opened. A document with live authoring of its own (the
26
+ * Object3D editor) passes `selection` and its picked part flows through; a
27
+ * document without passes nothing and gets `{adapter: null, nodeId: null}`,
28
+ * which resolves to its own identity floor.
29
+ *
30
+ * The identity row is where that floor lives: even a document with no sections
31
+ * at all says what it is, what kind it is, and where it came from — and no
32
+ * section of its own stands in for that row, because identity is a property of
33
+ * the SUBJECT (`inspection/model.ts`).
34
+ */
35
+
36
+ import { type ReactNode, useEffect, useRef } from 'react';
37
+ import { activateAssetEditorContext } from '../asset-editor-context';
38
+ import { publishDocumentInspectionSubject } from '../inspection/document-subject';
39
+ import type { InspectionSection } from '@volter/sdk/kit/inspection-model';
40
+ import type { NullInspectionSubject } from '../inspection/null-subject';
41
+ import {
42
+ registerWorkspaceDocumentSelection,
43
+ type WorkspaceDocumentSelection,
44
+ } from '@volter/sdk/kit/workspace-document-registry';
45
+
46
+ /** What a document with no authoring of its own selects: itself. */
47
+ const DOCUMENT_IS_THE_SUBJECT: WorkspaceDocumentSelection = { adapter: null, nodeId: null };
48
+
49
+ /**
50
+ * The part of a document subject whose change can alter the Inspector's
51
+ * structure. Function identities deliberately stay out of this key: render
52
+ * functions and field IO are read through `descriptionRef` below, so a parent
53
+ * render updates them without feeding the Inspector's own notification back
54
+ * into another publication.
55
+ */
56
+ function subjectPublicationKey(subject: NullInspectionSubject): string {
57
+ return JSON.stringify({
58
+ id: subject.id,
59
+ title: subject.title,
60
+ hint: subject.hint,
61
+ kindLabel: subject.kindLabel,
62
+ note: subject.note,
63
+ sections: subject.sections.map((section) => ({
64
+ id: section.id,
65
+ title: section.title,
66
+ order: section.order,
67
+ description: section.description,
68
+ defaultOpen: section.defaultOpen,
69
+ testId: section.testId,
70
+ keepMounted: section.keepMounted,
71
+ railGroup: section.railGroup,
72
+ bodyKind: section.body.kind,
73
+ })),
74
+ quickActions: subject.quickActions?.map((action) => ({
75
+ id: action.id,
76
+ title: action.title,
77
+ label: action.label,
78
+ placement: action.placement,
79
+ pressed: action.pressed,
80
+ disabled: action.disabled,
81
+ })),
82
+ });
83
+ }
84
+
85
+ /**
86
+ * The three optional props below are spelled `?: T | undefined` rather than
87
+ * `?: T`, because `AssetEditorShell` PASSES ITS OWN THROUGH: under
88
+ * `exactOptionalPropertyTypes` an explicit `undefined` is not the same as an
89
+ * absent key, so `sections={sections}` on a shell whose own `sections` is
90
+ * optional is a type error against `?: T`. Undefined is a value this component
91
+ * genuinely handles (`sections ?? []`, `status &&`, `selection?.()`) — the
92
+ * widened type says that, where a conditional spread at the one call site would
93
+ * only hide it.
94
+ */
95
+ interface AssetEditorSubjectProps {
96
+ documentId: string;
97
+ active?: boolean;
98
+ type: string;
99
+ title: string;
100
+ /** This document's own inspection sections, for the subject it publishes
101
+ * when nothing inside it is picked. Identity (name/kind/provenance) is
102
+ * composed from `title`/`type`/`status` — a document always has one, even
103
+ * with no sections at all. */
104
+ sections?: readonly InspectionSection[] | undefined;
105
+ status?: string | undefined;
106
+ /** What is picked INSIDE this document, for a document with authoring of
107
+ * its own. Read on demand (the registry calls it), so it may close over
108
+ * live state that changes without re-registering. */
109
+ selection?: (() => WorkspaceDocumentSelection | null) | undefined;
110
+ }
111
+
112
+ /**
113
+ * The non-visual half of an Asset Lab document. Kept separate from the frame
114
+ * so project-owned contribution UIs can publish the standard subject without
115
+ * sending React elements across the project/editor runtime boundary.
116
+ */
117
+ export function AssetEditorSubject({
118
+ documentId,
119
+ active = true,
120
+ type,
121
+ title,
122
+ sections,
123
+ status,
124
+ selection,
125
+ }: AssetEditorSubjectProps) {
126
+ useEffect(() => {
127
+ if (!active) return;
128
+ return activateAssetEditorContext({
129
+ documentId,
130
+ title,
131
+ type,
132
+ ...(status ? { status } : {}),
133
+ });
134
+ }, [active, documentId, status, title, type]);
135
+
136
+ // ONE owner for this document's selection context (the registry keys by
137
+ // document id, so a second registrant would silently displace the first and
138
+ // take the entry with it on unmount). The ref keeps the registration stable
139
+ // while the provider it delegates to is free to change every render.
140
+ const selectionRef = useRef(selection);
141
+ selectionRef.current = selection;
142
+ useEffect(() => {
143
+ if (!active) return;
144
+ return registerWorkspaceDocumentSelection(
145
+ documentId,
146
+ () => selectionRef.current?.() ?? DOCUMENT_IS_THE_SUBJECT,
147
+ );
148
+ }, [active, documentId]);
149
+
150
+ // The document's subject DESCRIPTION — identity plus its own sections, in
151
+ // the same shape every surface's `describeSubject(null)` answer takes.
152
+ // The latest description is read on demand, so section IO closures remain
153
+ // live without publishing on every render. Publishing itself notifies the
154
+ // Inspector; doing it after every Inspector-driven parent render creates a
155
+ // notification -> render -> publication loop and React eventually throws
156
+ // "Maximum update depth exceeded" when an Object3D prefab opens.
157
+ const description: NullInspectionSubject = {
158
+ id: documentId,
159
+ title,
160
+ // `kindLabel` is what earns the composed identity ROW, and a document
161
+ // always names its kind: an Asset Lab document IS a thing with a name, a
162
+ // type and a provenance.
163
+ kindLabel: type,
164
+ ...(status ? { note: { text: status, testId: 'asset-editor-status' } } : {}),
165
+ sections: sections ?? [],
166
+ };
167
+ const descriptionRef = useRef(description);
168
+ descriptionRef.current = description;
169
+ const publicationKey = subjectPublicationKey(description);
170
+ useEffect(() => {
171
+ if (!active) return;
172
+ return publishDocumentInspectionSubject(documentId, () => descriptionRef.current);
173
+ }, [active, documentId, publicationKey]);
174
+
175
+ return null;
176
+ }
177
+
178
+ export function AssetEditorShell({
179
+ documentId,
180
+ active = true,
181
+ type,
182
+ title,
183
+ sections,
184
+ status,
185
+ fill = false,
186
+ selection,
187
+ children,
188
+ }: AssetEditorSubjectProps & {
189
+ /** The child owns the whole viewport box and clips itself (a 3D canvas),
190
+ * rather than flowing and scrolling inside it. */
191
+ fill?: boolean;
192
+ children: ReactNode;
193
+ }) {
194
+ return (
195
+ <section
196
+ className="volter-asset-editor"
197
+ data-testid={`asset-editor:${type}`}
198
+ aria-label={`${title} Asset Editor`}
199
+ >
200
+ <AssetEditorSubject
201
+ documentId={documentId}
202
+ active={active}
203
+ type={type}
204
+ title={title}
205
+ sections={sections}
206
+ status={status}
207
+ selection={selection}
208
+ />
209
+ <main
210
+ className={`volter-asset-editor__viewport${fill ? ' volter-asset-editor__viewport--fill' : ''}`}
211
+ >
212
+ {children}
213
+ </main>
214
+ </section>
215
+ );
216
+ }