@volter/sdk 0.0.0-stage → 0.5.204

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (523) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +20 -0
  3. package/README.md +38 -3
  4. package/package.json +510 -4
  5. package/src/account.ts +210 -0
  6. package/src/chrome.ts +88 -0
  7. package/src/client.ts +1646 -0
  8. package/src/commands.ts +66 -0
  9. package/src/contributions.ts +619 -0
  10. package/src/css-numeric-style.ts +97 -0
  11. package/src/document-probe.ts +282 -0
  12. package/src/editor-view.ts +225 -0
  13. package/src/extension.ts +40 -0
  14. package/src/generations.ts +178 -0
  15. package/src/host.ts +1157 -0
  16. package/src/http-transport.browser.ts +14 -0
  17. package/src/http-transport.node.ts +19 -0
  18. package/src/index.ts +131 -0
  19. package/src/kit/CapabilityCoverageSection.tsx +185 -0
  20. package/src/kit/account-client.ts +333 -0
  21. package/src/kit/action-registry.ts +317 -0
  22. package/src/kit/active-product.ts +76 -0
  23. package/src/kit/active-project.ts +155 -0
  24. package/src/kit/adapter-editor-config.ts +25 -0
  25. package/src/kit/adapter-module.ts +7 -0
  26. package/src/kit/adapter-observation.ts +49 -0
  27. package/src/kit/animation/animation-clock.ts +479 -0
  28. package/src/kit/animation/stage-transport.ts +385 -0
  29. package/src/kit/api/assets.ts +365 -0
  30. package/src/kit/api/project-open.ts +355 -0
  31. package/src/kit/api/project-source.ts +180 -0
  32. package/src/kit/api/project-state.ts +110 -0
  33. package/src/kit/api/relay.ts +270 -0
  34. package/src/kit/api/themes.ts +45 -0
  35. package/src/kit/api-asset-library-wire.ts +45 -0
  36. package/src/kit/api-base.ts +10 -0
  37. package/src/kit/api-build.ts +99 -0
  38. package/src/kit/api-git-wire.ts +56 -0
  39. package/src/kit/api-logs.ts +92 -0
  40. package/src/kit/api-project-identity.ts +74 -0
  41. package/src/kit/api-settings.ts +36 -0
  42. package/src/kit/api-worktrees.ts +205 -0
  43. package/src/kit/asset-capabilities.ts +344 -0
  44. package/src/kit/asset-compare-core.ts +171 -0
  45. package/src/kit/asset-editor-context.tsx +101 -0
  46. package/src/kit/asset-events.ts +96 -0
  47. package/src/kit/asset-inspector-actions.ts +87 -0
  48. package/src/kit/asset-selection-viewer-registry.ts +113 -0
  49. package/src/kit/asset-selection.ts +146 -0
  50. package/src/kit/asset-thumbnails.ts +25 -0
  51. package/src/kit/asset-viewers.ts +115 -0
  52. package/src/kit/asset-workflow/asset-import-jobs.ts +106 -0
  53. package/src/kit/asset-workflow/asset-ledger-backend.ts +126 -0
  54. package/src/kit/asset-workflow/asset-ledger.ts +156 -0
  55. package/src/kit/asset-workflow/asset-materialization-report.ts +140 -0
  56. package/src/kit/asset-workflow/asset-pack-manifest.ts +320 -0
  57. package/src/kit/asset-workflow/asset-types.ts +142 -0
  58. package/src/kit/asset-workflow/audio-preview-player.ts +193 -0
  59. package/src/kit/asset-workflow/audio-waveform.ts +22 -0
  60. package/src/kit/asset-workflow/cloud-asset-client.ts +263 -0
  61. package/src/kit/asset-workflow/hosted-asset-materialization.ts +236 -0
  62. package/src/kit/asset-workflow/image-view-scale.ts +31 -0
  63. package/src/kit/asset-workflow/import-contract.ts +124 -0
  64. package/src/kit/asset-workflow/ledger-write-lock.ts +244 -0
  65. package/src/kit/asset-workflow/pixi-spritesheet.ts +197 -0
  66. package/src/kit/asset-workflow/preview-resource-lifetime.ts +44 -0
  67. package/src/kit/asset-workflow/project-asset-commands.ts +20 -0
  68. package/src/kit/asset-workflow/project-content.ts +288 -0
  69. package/src/kit/asset-workflow/project-source-index.ts +545 -0
  70. package/src/kit/asset-workflow/thumbnail-system.ts +256 -0
  71. package/src/kit/authoring/active-adapter.ts +200 -0
  72. package/src/kit/authoring/active-systems.ts +422 -0
  73. package/src/kit/authoring/adapter-key.ts +18 -0
  74. package/src/kit/authoring/authoring-asset-url.ts +27 -0
  75. package/src/kit/authoring/bootstrap-state.ts +49 -0
  76. package/src/kit/authoring/boundary-authoring-adapter.ts +189 -0
  77. package/src/kit/authoring/canvas-scene-guides.ts +84 -0
  78. package/src/kit/authoring/composite-authoring-adapter.ts +2109 -0
  79. package/src/kit/authoring/consumer-actions.ts +531 -0
  80. package/src/kit/authoring/design-time-layers.ts +852 -0
  81. package/src/kit/authoring/design-time-mount-registry.ts +244 -0
  82. package/src/kit/authoring/edit-mode-authoring.ts +637 -0
  83. package/src/kit/authoring/empty-project-authoring.ts +22 -0
  84. package/src/kit/authoring/instance-source-menu.ts +135 -0
  85. package/src/kit/authoring/layered-pick.ts +185 -0
  86. package/src/kit/authoring/mounted-root-subjects.ts +146 -0
  87. package/src/kit/authoring/no-authoring-adapter.ts +59 -0
  88. package/src/kit/authoring/object3d-document-persistence.ts +122 -0
  89. package/src/kit/authoring/panel-authoring.ts +121 -0
  90. package/src/kit/authoring/project-authoring-session.ts +105 -0
  91. package/src/kit/authoring/provenance.ts +99 -0
  92. package/src/kit/authoring/react-canvas-navigation.ts +259 -0
  93. package/src/kit/authoring/react-design-canvas-style.ts +20 -0
  94. package/src/kit/authoring/react-story-board.ts +917 -0
  95. package/src/kit/authoring/selection-scope.ts +195 -0
  96. package/src/kit/authoring/shell-document-ops.ts +169 -0
  97. package/src/kit/authoring/story-board-chrome-fit.ts +107 -0
  98. package/src/kit/authoring/story-board-presentation.ts +111 -0
  99. package/src/kit/authoring/three-root.ts +67 -0
  100. package/src/kit/authoring/viewport-tool-context.ts +73 -0
  101. package/src/kit/authoring/viewport-tool-owner.ts +38 -0
  102. package/src/kit/authoring/world-session-state.ts +101 -0
  103. package/src/kit/authoring-seam-evidence.ts +300 -0
  104. package/src/kit/availability-tick.ts +66 -0
  105. package/src/kit/bitmap-label.ts +120 -0
  106. package/src/kit/boot-routing.ts +392 -0
  107. package/src/kit/breakpoint-state.ts +43 -0
  108. package/src/kit/build-identity.ts +16 -0
  109. package/src/kit/bytes-codec.ts +62 -0
  110. package/src/kit/cancellation-reason.ts +58 -0
  111. package/src/kit/canvas-frames.ts +88 -0
  112. package/src/kit/capture-camera-pose.ts +77 -0
  113. package/src/kit/capture-size.ts +88 -0
  114. package/src/kit/chrome-registry.ts +159 -0
  115. package/src/kit/chrome-slot-registry.ts +91 -0
  116. package/src/kit/collaboration-client.ts +264 -0
  117. package/src/kit/collaboration-presence.ts +41 -0
  118. package/src/kit/command-dispatch.ts +19 -0
  119. package/src/kit/command-listener.ts +2182 -0
  120. package/src/kit/command-registry.ts +71 -0
  121. package/src/kit/component-board-registry.ts +205 -0
  122. package/src/kit/component-states-registry.ts +199 -0
  123. package/src/kit/components/AlignToolbar.tsx +204 -0
  124. package/src/kit/components/ApplicationMenus.tsx +372 -0
  125. package/src/kit/components/AssetEditorShell.tsx +216 -0
  126. package/src/kit/components/AssetInspectorToolSection.tsx +124 -0
  127. package/src/kit/components/BoardRulers.tsx +354 -0
  128. package/src/kit/components/CanvasAddNodeDialogs.tsx +529 -0
  129. package/src/kit/components/CanvasSceneViewport.tsx +1195 -0
  130. package/src/kit/components/ChromeSlot.tsx +20 -0
  131. package/src/kit/components/CodeView.tsx +470 -0
  132. package/src/kit/components/CompactInspectorShell.tsx +39 -0
  133. package/src/kit/components/ConsolePanel.tsx +273 -0
  134. package/src/kit/components/GameplaySessionTimeline.tsx +295 -0
  135. package/src/kit/components/InspectionProjection.tsx +932 -0
  136. package/src/kit/components/Inspector.tsx +270 -0
  137. package/src/kit/components/InspectorCanvasPreview.tsx +35 -0
  138. package/src/kit/components/InspectorFieldsSection.tsx +290 -0
  139. package/src/kit/components/InspectorStoriesSection.tsx +92 -0
  140. package/src/kit/components/InspectorToolSection.tsx +96 -0
  141. package/src/kit/components/InspectorTransformSection.tsx +245 -0
  142. package/src/kit/components/LightExplorerPanel.tsx +433 -0
  143. package/src/kit/components/MediaProperties.tsx +145 -0
  144. package/src/kit/components/ProjectHeader.tsx +328 -0
  145. package/src/kit/components/ReactCanvasControls.tsx +358 -0
  146. package/src/kit/components/RootSelectionOverlay.tsx +3688 -0
  147. package/src/kit/components/RootTextEditor.tsx +79 -0
  148. package/src/kit/components/SaveStatus.tsx +70 -0
  149. package/src/kit/components/SurfaceCrashBoundary.tsx +105 -0
  150. package/src/kit/components/SurfaceStateOverlay.tsx +24 -0
  151. package/src/kit/components/ToolContributionSurfaces.tsx +49 -0
  152. package/src/kit/components/ToolHost.tsx +380 -0
  153. package/src/kit/components/Toolbar.tsx +811 -0
  154. package/src/kit/components/TransientHint.tsx +44 -0
  155. package/src/kit/components/VersionControlSection.tsx +470 -0
  156. package/src/kit/components/ViewportOverlaysMenu.tsx +177 -0
  157. package/src/kit/components/VolterLogo.tsx +18 -0
  158. package/src/kit/components/WorktreeSwitcher.tsx +712 -0
  159. package/src/kit/components/account-documents.tsx +1162 -0
  160. package/src/kit/components/asset-documents.tsx +794 -0
  161. package/src/kit/components/asset-editor-persistence.ts +216 -0
  162. package/src/kit/components/asset-selection-section.tsx +545 -0
  163. package/src/kit/components/asset-thumbnails.tsx +307 -0
  164. package/src/kit/components/asset-viewers/AudioViewer.tsx +201 -0
  165. package/src/kit/components/asset-viewers/GenericJsonViewer.tsx +102 -0
  166. package/src/kit/components/asset-viewers/ImageViewer.tsx +300 -0
  167. package/src/kit/components/asset-viewers/JsonAssetDocument.tsx +98 -0
  168. package/src/kit/components/asset-viewers/OnlineAssetDetail.tsx +426 -0
  169. package/src/kit/components/asset-viewers/SourceAssetViewer.tsx +356 -0
  170. package/src/kit/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
  171. package/src/kit/components/asset-viewers/VideoViewer.tsx +101 -0
  172. package/src/kit/components/asset-viewers/shader-source.ts +144 -0
  173. package/src/kit/components/board-guides.ts +150 -0
  174. package/src/kit/components/canvas-scene-hotkeys.ts +37 -0
  175. package/src/kit/components/canvas-temporary-pivot.ts +34 -0
  176. package/src/kit/components/core-utilities.tsx +94 -0
  177. package/src/kit/components/inspector-preview-section.tsx +223 -0
  178. package/src/kit/components/inspector-revert-label.ts +20 -0
  179. package/src/kit/components/inspector-selection.ts +42 -0
  180. package/src/kit/components/inspector-stories-gating.ts +171 -0
  181. package/src/kit/components/inspector-transform-subject.ts +11 -0
  182. package/src/kit/components/inspector-transform.ts +88 -0
  183. package/src/kit/components/kind-documents.tsx +544 -0
  184. package/src/kit/components/primitives/DraftColorInput.tsx +74 -0
  185. package/src/kit/components/project-tool-documents.tsx +402 -0
  186. package/src/kit/components/scene-documents.tsx +221 -0
  187. package/src/kit/components/status-contributions.tsx +407 -0
  188. package/src/kit/components/tool-documents.tsx +302 -0
  189. package/src/kit/components/tool-schema-form.tsx +262 -0
  190. package/src/kit/components/use-after-paint.ts +41 -0
  191. package/src/kit/components/use-project-image-assets.ts +86 -0
  192. package/src/kit/components/workspace-history.ts +32 -0
  193. package/src/kit/components/world-documents.tsx +570 -0
  194. package/src/kit/components/world-overlay-gestures.ts +1939 -0
  195. package/src/kit/composite-screenshot.ts +2238 -0
  196. package/src/kit/content-entry-source-registry.ts +184 -0
  197. package/src/kit/contribution-surfaces.ts +48 -0
  198. package/src/kit/coverage/canvas-reveal.ts +192 -0
  199. package/src/kit/coverage/design-time-surfaces.ts +101 -0
  200. package/src/kit/coverage/ontology-invariants.ts +466 -0
  201. package/src/kit/coverage/session-vitals.ts +503 -0
  202. package/src/kit/crash-null-boundary.ts +36 -0
  203. package/src/kit/creation-site-edit.ts +1491 -0
  204. package/src/kit/creation-site-registry.ts +160 -0
  205. package/src/kit/delegate-harness-registry.ts +134 -0
  206. package/src/kit/document-areas.ts +70 -0
  207. package/src/kit/document-context-registry.ts +193 -0
  208. package/src/kit/document-open-registry.ts +200 -0
  209. package/src/kit/document-play-extension.ts +221 -0
  210. package/src/kit/document-preview-source.ts +20 -0
  211. package/src/kit/document-renderer-session.ts +138 -0
  212. package/src/kit/document-stage-sessions.ts +26 -0
  213. package/src/kit/document-viewports.ts +120 -0
  214. package/src/kit/editor-api.ts +46 -0
  215. package/src/kit/editor-chrome-capture.ts +136 -0
  216. package/src/kit/editor-commands.ts +176 -0
  217. package/src/kit/editor-console.ts +580 -0
  218. package/src/kit/editor-current-view.ts +56 -0
  219. package/src/kit/editor-document-probe.ts +1168 -0
  220. package/src/kit/editor-git-client.ts +115 -0
  221. package/src/kit/editor-hotkeys.ts +728 -0
  222. package/src/kit/editor-lease-view.ts +39 -0
  223. package/src/kit/editor-lease.ts +415 -0
  224. package/src/kit/editor-mode.ts +19 -0
  225. package/src/kit/editor-notifications.ts +140 -0
  226. package/src/kit/editor-presence.ts +563 -0
  227. package/src/kit/editor-presentation-activity.ts +58 -0
  228. package/src/kit/editor-presentation-notice.ts +42 -0
  229. package/src/kit/editor-runtime.tsx +147 -0
  230. package/src/kit/editor-server-response.ts +86 -0
  231. package/src/kit/editor-session-attribution.ts +85 -0
  232. package/src/kit/editor-session-mode.ts +54 -0
  233. package/src/kit/editor-state-facets.ts +74 -0
  234. package/src/kit/editor-view-presentation.ts +777 -0
  235. package/src/kit/environment-images.ts +58 -0
  236. package/src/kit/eyedropper-session.ts +60 -0
  237. package/src/kit/files/file-provider.ts +62 -0
  238. package/src/kit/files/project-files.ts +270 -0
  239. package/src/kit/finders/index.ts +137 -0
  240. package/src/kit/finders/scenes-from-entrypoint-selection.ts +387 -0
  241. package/src/kit/frame/frame-parts.ts +30 -0
  242. package/src/kit/framed-document-capture.ts +34 -0
  243. package/src/kit/game-globals-prelude.ts +143 -0
  244. package/src/kit/game-surface-defaults.ts +33 -0
  245. package/src/kit/gameplay-dom-recording.ts +318 -0
  246. package/src/kit/gameplay-export-state.ts +14 -0
  247. package/src/kit/gameplay-replay.ts +417 -0
  248. package/src/kit/gameplay-session-time.ts +9 -0
  249. package/src/kit/gameplay-sessions.ts +204 -0
  250. package/src/kit/hierarchy-component-marks.ts +298 -0
  251. package/src/kit/hierarchy-internals.ts +197 -0
  252. package/src/kit/hierarchy-kind-icon.ts +217 -0
  253. package/src/kit/hierarchy-menu-registry.ts +67 -0
  254. package/src/kit/hierarchy-node-rows.ts +307 -0
  255. package/src/kit/hierarchy-panel-view.ts +280 -0
  256. package/src/kit/hierarchy-projection.ts +76 -0
  257. package/src/kit/hierarchy-row-media.ts +45 -0
  258. package/src/kit/hierarchy-row-model.ts +308 -0
  259. package/src/kit/hierarchy-rows.ts +11 -0
  260. package/src/kit/hierarchy-walk.ts +86 -0
  261. package/src/kit/history/editor-session.ts +25 -0
  262. package/src/kit/history/history-commands.ts +147 -0
  263. package/src/kit/history/history-delegate.ts +187 -0
  264. package/src/kit/history/history-limit-notices.ts +43 -0
  265. package/src/kit/history/history-service.ts +1189 -0
  266. package/src/kit/history/persistence-coordinator.ts +35 -0
  267. package/src/kit/history/project-file-history.ts +386 -0
  268. package/src/kit/history/project-root-history-backends.ts +139 -0
  269. package/src/kit/history/resource-registry.ts +209 -0
  270. package/src/kit/history/snapshot-store.ts +103 -0
  271. package/src/kit/history/source-history-backend.ts +546 -0
  272. package/src/kit/history-types.ts +124 -0
  273. package/src/kit/hmr-registration-group.ts +67 -0
  274. package/src/kit/hmr-stable-react-context.ts +23 -0
  275. package/src/kit/hotkeys.ts +190 -0
  276. package/src/kit/inference-diagnostics.ts +69 -0
  277. package/src/kit/initial-project.ts +80 -0
  278. package/src/kit/inspection/active-subject.ts +571 -0
  279. package/src/kit/inspection/active-surface.ts +142 -0
  280. package/src/kit/inspection/compose-subject.ts +1055 -0
  281. package/src/kit/inspection/compose.ts +7 -0
  282. package/src/kit/inspection/display.ts +171 -0
  283. package/src/kit/inspection/document-subject.ts +109 -0
  284. package/src/kit/inspection/game-subject.ts +85 -0
  285. package/src/kit/inspection/null-subject.ts +119 -0
  286. package/src/kit/inspection/serialize.ts +357 -0
  287. package/src/kit/inspection/use-active-inspection.ts +180 -0
  288. package/src/kit/inspection-model.ts +542 -0
  289. package/src/kit/inspection-node-media.ts +58 -0
  290. package/src/kit/inspector-presentation.ts +203 -0
  291. package/src/kit/inspector-property-grouping.ts +64 -0
  292. package/src/kit/inspector-section-registry.ts +221 -0
  293. package/src/kit/instance-source-actions.ts +163 -0
  294. package/src/kit/js-heap.ts +71 -0
  295. package/src/kit/key-actions.ts +91 -0
  296. package/src/kit/keymap-presets.ts +428 -0
  297. package/src/kit/layout-policy.ts +31 -0
  298. package/src/kit/light-explorer-model.ts +134 -0
  299. package/src/kit/live-canvas-frame.ts +55 -0
  300. package/src/kit/live-document.ts +296 -0
  301. package/src/kit/live-gesture-lock.ts +50 -0
  302. package/src/kit/live-seam-evidence.ts +11 -0
  303. package/src/kit/live-session-registry.ts +220 -0
  304. package/src/kit/live-transition.ts +391 -0
  305. package/src/kit/manifest-project.ts +107 -0
  306. package/src/kit/module-fetch-diagnosis.ts +192 -0
  307. package/src/kit/mount-failure-report.ts +154 -0
  308. package/src/kit/native-selection-style.ts +497 -0
  309. package/src/kit/object3d-document-write-policy.ts +137 -0
  310. package/src/kit/packaged-runtime.ts +108 -0
  311. package/src/kit/palettes/maya.palette.json +57 -0
  312. package/src/kit/palettes/substance.palette.json +57 -0
  313. package/src/kit/performance-profiler.ts +367 -0
  314. package/src/kit/performance-sources.ts +69 -0
  315. package/src/kit/photograph-notice.ts +141 -0
  316. package/src/kit/play-boot-phase.ts +166 -0
  317. package/src/kit/play-camera-flight.ts +35 -0
  318. package/src/kit/png-encode.worker.ts +26 -0
  319. package/src/kit/presentation-surface.ts +248 -0
  320. package/src/kit/product-command.ts +90 -0
  321. package/src/kit/project-adapter.ts +1140 -0
  322. package/src/kit/project-asset-refresh.ts +23 -0
  323. package/src/kit/project-asset-roots.ts +68 -0
  324. package/src/kit/project-local-state.ts +151 -0
  325. package/src/kit/project-manager.ts +243 -0
  326. package/src/kit/project-module-changes.ts +201 -0
  327. package/src/kit/project-module-split.ts +270 -0
  328. package/src/kit/project-play-layers.ts +25 -0
  329. package/src/kit/project-provenance.ts +115 -0
  330. package/src/kit/project-ready.ts +42 -0
  331. package/src/kit/project-shape.ts +68 -0
  332. package/src/kit/project-tools.ts +107 -0
  333. package/src/kit/projection-types.ts +44 -0
  334. package/src/kit/readiness.ts +113 -0
  335. package/src/kit/renderer-resource-counts.ts +27 -0
  336. package/src/kit/reported-play-state.ts +90 -0
  337. package/src/kit/resolve-contributed-command.ts +14 -0
  338. package/src/kit/resolve-relative-specifier.ts +33 -0
  339. package/src/kit/retained-document-states.ts +91 -0
  340. package/src/kit/scene-document-plan.ts +320 -0
  341. package/src/kit/scene-live-open.ts +210 -0
  342. package/src/kit/scoped-game-css.ts +152 -0
  343. package/src/kit/served-url.ts +5 -0
  344. package/src/kit/session-close.ts +17 -0
  345. package/src/kit/session-tombstone.ts +127 -0
  346. package/src/kit/settings/settings-provider.ts +82 -0
  347. package/src/kit/settings-store.ts +348 -0
  348. package/src/kit/shell-document-state.ts +27 -0
  349. package/src/kit/shell-store-door.ts +45 -0
  350. package/src/kit/shell-store.ts +722 -0
  351. package/src/kit/source-conflict.ts +122 -0
  352. package/src/kit/stage-context.ts +377 -0
  353. package/src/kit/stage-invalidation.ts +25 -0
  354. package/src/kit/stage-store-registry.ts +69 -0
  355. package/src/kit/startup-failure.ts +80 -0
  356. package/src/kit/state-report-deferral.ts +73 -0
  357. package/src/kit/storage/host-files-storage.ts +97 -0
  358. package/src/kit/storage/http-storage.ts +174 -0
  359. package/src/kit/storage/index.ts +75 -0
  360. package/src/kit/storage/mem-storage.ts +158 -0
  361. package/src/kit/storage/path-lock.ts +44 -0
  362. package/src/kit/storage/paths.ts +26 -0
  363. package/src/kit/storage-types.ts +127 -0
  364. package/src/kit/stories/StoryPreviewMount.tsx +306 -0
  365. package/src/kit/stories/compose-project-stories.ts +255 -0
  366. package/src/kit/stories/prefabs-finder.ts +54 -0
  367. package/src/kit/stories/prefabs-from-stories.ts +182 -0
  368. package/src/kit/stories/project-story-regions.ts +24 -0
  369. package/src/kit/stories/story-capture.ts +579 -0
  370. package/src/kit/stories/story-declared-medium.ts +126 -0
  371. package/src/kit/stories/story-discovery.ts +176 -0
  372. package/src/kit/stories/story-dom-runtime.ts +78 -0
  373. package/src/kit/stories/story-grouping.ts +111 -0
  374. package/src/kit/stories/story-mount-turn.ts +27 -0
  375. package/src/kit/stories/story-presentation.ts +215 -0
  376. package/src/kit/stories/story-preview-component.ts +7 -0
  377. package/src/kit/stories/story-registry.ts +530 -0
  378. package/src/kit/stories-scope.ts +35 -0
  379. package/src/kit/story-document-openers.ts +36 -0
  380. package/src/kit/story-thumbnails.ts +47 -0
  381. package/src/kit/surface-keyboard.ts +101 -0
  382. package/src/kit/surface-state.ts +135 -0
  383. package/src/kit/system-seam-evidence.ts +72 -0
  384. package/src/kit/tab-census.ts +202 -0
  385. package/src/kit/tab-lifecycle-client.ts +227 -0
  386. package/src/kit/theme-library.ts +897 -0
  387. package/src/kit/theme-preference.ts +429 -0
  388. package/src/kit/three-viewport-presentation.ts +23 -0
  389. package/src/kit/tool-contribution-play.ts +74 -0
  390. package/src/kit/tool-loader.ts +1918 -0
  391. package/src/kit/transform-mode-request.ts +66 -0
  392. package/src/kit/transient-hint.ts +78 -0
  393. package/src/kit/transport-strip.tsx +174 -0
  394. package/src/kit/ui-source/adapter-region-includes.ts +238 -0
  395. package/src/kit/ui-source/file-region-resolver.ts +302 -0
  396. package/src/kit/ui-source/inspect.ts +775 -0
  397. package/src/kit/ui-source/source-write-backend.ts +605 -0
  398. package/src/kit/ui-source/tier-source-write-backend.ts +279 -0
  399. package/src/kit/user-local-state.ts +105 -0
  400. package/src/kit/viewport-activation-timings.ts +840 -0
  401. package/src/kit/viewport-editor-controls.ts +22 -0
  402. package/src/kit/viewport-presentation.ts +668 -0
  403. package/src/kit/viewport-surface-status.tsx +55 -0
  404. package/src/kit/wait-until.ts +37 -0
  405. package/src/kit/worker-call-metrics.ts +166 -0
  406. package/src/kit/workspace-areas.ts +191 -0
  407. package/src/kit/workspace-aux-commands.ts +11 -0
  408. package/src/kit/workspace-available-documents.ts +142 -0
  409. package/src/kit/workspace-core-utilities.ts +31 -0
  410. package/src/kit/workspace-document-ids.ts +59 -0
  411. package/src/kit/workspace-document-registry.ts +624 -0
  412. package/src/kit/workspace-document-restore.ts +146 -0
  413. package/src/kit/workspace-host-commands.ts +141 -0
  414. package/src/kit/workspace-persistence-gate.ts +40 -0
  415. package/src/kit/workspace-play-utilities.ts +44 -0
  416. package/src/kit/workspace-presets.ts +446 -0
  417. package/src/kit/workspace-regions.ts +276 -0
  418. package/src/kit/workspace-static-panels.ts +73 -0
  419. package/src/kit/workspace-status-registry.ts +121 -0
  420. package/src/kit/workspace-storage.ts +35 -0
  421. package/src/kit/workspace-style.ts +226 -0
  422. package/src/kit/workspace-utility-commands.ts +74 -0
  423. package/src/kit/workspace-utility-registry.ts +263 -0
  424. package/src/kit/world-adoption-event.ts +23 -0
  425. package/src/kit/world-adoption.ts +115 -0
  426. package/src/kit/world-canvas-viewport-state.ts +35 -0
  427. package/src/kit/world-document-routing.ts +104 -0
  428. package/src/kit/world-pan-state.ts +198 -0
  429. package/src/kit/write-pipe.ts +173 -0
  430. package/src/layout-arrangements.ts +5 -0
  431. package/src/layouts.tsx +108 -0
  432. package/src/looks.ts +16 -0
  433. package/src/project/output-roots.ts +73 -0
  434. package/src/project/tab-census.ts +155 -0
  435. package/src/project-tool-catalog.ts +104 -0
  436. package/src/selection.tsx +107 -0
  437. package/src/services.ts +18 -0
  438. package/src/session/build-report.ts +22 -0
  439. package/src/session/collaboration-types.ts +262 -0
  440. package/src/session/command-table.ts +327 -0
  441. package/src/session/discovery.ts +100 -0
  442. package/src/session/editor-brand.ts +48 -0
  443. package/src/session/editor-compatibility.ts +329 -0
  444. package/src/session/editor-control-lifecycle.ts +68 -0
  445. package/src/session/editor-control-protocol.ts +5 -0
  446. package/src/session/entrypoint-selection-readers.ts +66 -0
  447. package/src/session/entrypoint-selection-source.ts +120 -0
  448. package/src/session/game-css-scope.ts +30 -0
  449. package/src/session/hosted-attachment.ts +225 -0
  450. package/src/session/limited-view.ts +82 -0
  451. package/src/session/product-create.ts +24 -0
  452. package/src/session/product-locator.ts +478 -0
  453. package/src/session/project-module-url.ts +242 -0
  454. package/src/session/project-serving.ts +164 -0
  455. package/src/session/project-upgrade.ts +669 -0
  456. package/src/session/registry-format.ts +210 -0
  457. package/src/session/relative-path-guard.ts +56 -0
  458. package/src/session/scoped-game-css.ts +461 -0
  459. package/src/session/source-glob.ts +15 -0
  460. package/src/session/tool-contribution-convention.ts +123 -0
  461. package/src/session/workbench-locator.ts +712 -0
  462. package/src/session.ts +41 -0
  463. package/src/share.ts +160 -0
  464. package/src/source-analysis.ts +28 -0
  465. package/src/source-authoring.ts +439 -0
  466. package/src/tools/errors.ts +91 -0
  467. package/src/tools/provider-execution.ts +70 -0
  468. package/src/tools/registry.ts +341 -0
  469. package/src/tools/types.ts +159 -0
  470. package/src/transport.ts +100 -0
  471. package/src/types.ts +1693 -0
  472. package/src/views.ts +164 -0
  473. package/src/widgets/design-system.ts +93 -0
  474. package/src/widgets/editor-appearance.ts +151 -0
  475. package/src/widgets/editor-material.ts +83 -0
  476. package/src/widgets/icon-set-registry.ts +105 -0
  477. package/src/widgets/index.ts +71 -0
  478. package/src/widgets/inspector-widgets/AlignmentGrid.tsx +182 -0
  479. package/src/widgets/inspector-widgets/AssetSlotPicker.tsx +123 -0
  480. package/src/widgets/inspector-widgets/BorderEditor.tsx +309 -0
  481. package/src/widgets/inspector-widgets/ColorPicker.tsx +549 -0
  482. package/src/widgets/inspector-widgets/CurveEditor.tsx +359 -0
  483. package/src/widgets/inspector-widgets/FilterEditor.tsx +108 -0
  484. package/src/widgets/inspector-widgets/FontPicker.tsx +191 -0
  485. package/src/widgets/inspector-widgets/GradientEditor.tsx +623 -0
  486. package/src/widgets/inspector-widgets/ScrubbableInput.tsx +180 -0
  487. package/src/widgets/inspector-widgets/ShadowEditor.tsx +319 -0
  488. package/src/widgets/inspector-widgets/color-utils.ts +201 -0
  489. package/src/widgets/inspector-widgets/curve-utils.ts +212 -0
  490. package/src/widgets/inspector-widgets/index.ts +25 -0
  491. package/src/widgets/inspector-widgets/shared.tsx +140 -0
  492. package/src/widgets/interactive-edit-scope.ts +33 -0
  493. package/src/widgets/patterns/Dialog.tsx +140 -0
  494. package/src/widgets/patterns/Fields.tsx +44 -0
  495. package/src/widgets/patterns/List.tsx +25 -0
  496. package/src/widgets/patterns/StateSurface.tsx +40 -0
  497. package/src/widgets/patterns/Surfaces.tsx +122 -0
  498. package/src/widgets/patterns/Tabs.tsx +80 -0
  499. package/src/widgets/patterns/Toolbar.tsx +72 -0
  500. package/src/widgets/patterns/Tree.tsx +72 -0
  501. package/src/widgets/primitives/AnchoredMenu.tsx +260 -0
  502. package/src/widgets/primitives/Button.tsx +62 -0
  503. package/src/widgets/primitives/ColorInput.tsx +78 -0
  504. package/src/widgets/primitives/DraftTextInput.tsx +63 -0
  505. package/src/widgets/primitives/EditorIcon.tsx +157 -0
  506. package/src/widgets/primitives/FormControls.tsx +88 -0
  507. package/src/widgets/primitives/HoverPreview.tsx +96 -0
  508. package/src/widgets/primitives/JsonInput.tsx +113 -0
  509. package/src/widgets/primitives/Layout.tsx +100 -0
  510. package/src/widgets/primitives/Menu.tsx +161 -0
  511. package/src/widgets/primitives/NumberInput.tsx +169 -0
  512. package/src/widgets/primitives/Panel.tsx +80 -0
  513. package/src/widgets/primitives/SectionHeader.tsx +77 -0
  514. package/src/widgets/primitives/Text.tsx +54 -0
  515. package/src/widgets/primitives/ThemeRootPortal.tsx +52 -0
  516. package/src/widgets/primitives/Tooltip.tsx +204 -0
  517. package/src/widgets/primitives/Vec3Input.tsx +70 -0
  518. package/src/widgets/primitives/banner-tones.ts +32 -0
  519. package/src/widgets/primitives/clamp-to-viewport.ts +44 -0
  520. package/src/widgets/primitives/editor-icons.ts +254 -0
  521. package/src/widgets/primitives/panel-header-styles.ts +42 -0
  522. package/src/widgets/theme.ts +2841 -0
  523. package/src/widgets/z-index.ts +25 -0
@@ -0,0 +1,302 @@
1
+ import { themeVars } from '@volter/sdk/widgets';
2
+ /**
3
+ * Project-tool DOCUMENTS (W3 — inventory rows B12/T2-behavior/T3): a
4
+ * `placement: 'document'` project tool (including every legacy `'dock'` tool
5
+ * — the W0 alias rule) opens as a CENTER workspace document (kind `'tool'`,
6
+ * title = the tool's own declared title per §8), hosted in the same
7
+ * error-boundaried `ToolHost` the bottom ⚙ tabs used. `placement: 'utility'`
8
+ * tools stay in the bottom area — rendered as sections of the ONE Dev
9
+ * utility (`components/DevPanel.tsx`), never as tabs of their own.
10
+ * The ⚙ dock-tab row is gone.
11
+ *
12
+ * Open gesture: one `Open Tool: <title>` command-palette action per
13
+ * discovered document tool (`buildToolActions`) — the fixed-layout menu the
14
+ * ⚙ row used to be, now a searchable command.
15
+ *
16
+ * HMR/lifecycle: the document's CONTENT reads the LIVE tool store — an HMR
17
+ * reload bumps the tool's `version`, which re-keys the mount (fresh
18
+ * component + cleared error boundary, the same physics the dock tabs had);
19
+ * a deleted tool file leaves an honest "no longer available" message in any
20
+ * open document (discovery is the folder scan, D3).
21
+ */
22
+
23
+ import { type ComponentType, useSyncExternalStore } from 'react';
24
+ import type { EditorAction } from '../action-registry';
25
+ import {
26
+ awaitAnnouncedObject3DDocumentSession,
27
+ waitForContributedDocumentMount,
28
+ } from '@volter/sdk/kit/document-context-registry';
29
+ import { registerDocumentOpener } from '@volter/sdk/kit/document-open-registry';
30
+ import {
31
+ contributionFailureHint,
32
+ getDocumentToolContributions,
33
+ getGlobalToolContributions,
34
+ refreshProjectToolContributions,
35
+ subscribeToolContributions,
36
+ } from '../tool-loader';
37
+ import {
38
+ closeWorkspaceDocument,
39
+ type OpenWorkspaceDocumentOptions,
40
+ openWorkspaceDocument,
41
+ openWorkspaceDocuments,
42
+ type WorkspaceDocumentContentProps,
43
+ } from '@volter/sdk/kit/workspace-document-registry';
44
+ import { registerWorkspaceDocumentRestorer } from '@volter/sdk/kit/workspace-document-restore';
45
+ import { ToolHost } from './ToolHost';
46
+
47
+ /** The narrow store surface tool documents need (T6.3 tab hand-off). */
48
+ /** Stable §7.1 identity for one project tool's document. */
49
+ export function toolDocumentId(toolId: string): string {
50
+ return `tool:${toolId}`;
51
+ }
52
+
53
+ /** Resolve either the canonical tool-qualified id or one unambiguous package-local id. */
54
+ export function resolveToolDocumentContributionId(id: string): string | null {
55
+ const contributions = getDocumentToolContributions();
56
+ const exact = contributions.find((item) => item.id === id);
57
+ if (exact) return exact.id;
58
+ // Ids are no longer tool-prefixed, so an exact match above is the only
59
+ // lookup left — there is no local-vs-qualified form to reconcile.
60
+ return null;
61
+ }
62
+
63
+ /**
64
+ * Open (or activate) the center document for one document-placement project
65
+ * tool. Returns `false` (opens nothing) when no discovered document tool
66
+ * carries that id — no fabricated documents for deleted/renamed tools.
67
+ */
68
+ export function openToolDocument(
69
+ toolId: string,
70
+ options: OpenWorkspaceDocumentOptions = {},
71
+ /** THE WORKSPACE AREA this document fills, when a workspace's own `areas`
72
+ * list is what opened it (`WorkspaceDocumentDescriptor.area`). Absent for
73
+ * every other opener, which is what keeps an ordinary tool document a
74
+ * centre tab. */
75
+ area?: string,
76
+ ): boolean {
77
+ const resolvedId = resolveToolDocumentContributionId(toolId);
78
+ const contribution = getDocumentToolContributions().find((item) => item.id === resolvedId);
79
+ if (!contribution) return false;
80
+ openWorkspaceDocument(
81
+ {
82
+ id: toolDocumentId(contribution.id),
83
+ ...(area === undefined ? {} : { area }),
84
+ // §8: the tool's own declared title, never a tech bucket.
85
+ title: contribution.title,
86
+ kind: 'tool-contribution',
87
+ workspaceRole: 'workspace-reference',
88
+ provenance: {
89
+ sourcePath: contribution.file,
90
+ origin: contribution.tool?.name ?? contribution.file,
91
+ },
92
+ Content: ToolDocumentContent,
93
+ // The contribution's header rides the host's own strip — the region the
94
+ // Game and Story documents already use — so a project document gets the
95
+ // same header anatomy as a built-in, drawn by the host.
96
+ ...(contribution.Toolbar ? { Toolbar: ToolDocumentToolbar } : {}),
97
+ ...(contribution.Shelf ? { Shelf: ToolDocumentShelf } : {}),
98
+ // A STANDING document is a place in the project, not an errand — pinned
99
+ // like the `3D`/`UI`/`Dev` boards. See `GlobalToolContribution.standing`.
100
+ // AN AREA DOCUMENT IS PINNED TOO, and for a stronger reason: it is not
101
+ // a tab at all, it IS the workspace's second editor group, and a close
102
+ // affordance on it would offer to empty a group nothing refills.
103
+ closeable: area === undefined && !contribution.standing,
104
+ presentation: () => ({ kind: 'tool', id: contribution.id }),
105
+ // AN AREA DOCUMENT DOES NOT PERSIST ITSELF. The WORKSPACE reopens it,
106
+ // from its own `areas` list, and it does so knowing the area id — a
107
+ // restorer running first would reopen the same contribution with NO
108
+ // area and strand it as a centre tab beside the model. `undefined` is
109
+ // the descriptor's own documented opt-out for "something else
110
+ // re-derives this at boot", which is exactly the case here.
111
+ ...(area === undefined ? { persist: () => ({ contributionId: contribution.id }) } : {}),
112
+ },
113
+ options,
114
+ );
115
+ return true;
116
+ }
117
+
118
+ /** Reopen a persisted tool document. `openToolDocument` is self-verifying —
119
+ * a deleted or renamed contribution opens nothing and answers `false`, so
120
+ * the stale panel is reconciled away. No `prepare`: the discovery pass this
121
+ * kind used to await for itself is now the restore's own first step, run for
122
+ * EVERY record because a package owns its restorer as well as its documents
123
+ * (`workspace-state-persistence.ts`, "contributions load first"). Keeping
124
+ * both ran the pass twice per boot — three reports of each unimplemented
125
+ * stub instead of one, measured on a `full` scaffold 2026-09-18. */
126
+ registerWorkspaceDocumentRestorer({
127
+ kind: 'tool-contribution',
128
+ owner: 'tool-documents',
129
+ restore: ({ state }) => {
130
+ const record = state as { contributionId?: unknown } | null | undefined;
131
+ const contributionId =
132
+ typeof record?.contributionId === 'string' ? record.contributionId : null;
133
+ return contributionId !== null && openToolDocument(contributionId);
134
+ },
135
+ });
136
+
137
+ /**
138
+ * THE `tool` ADDRESS (`document-open-registry.ts`) — the other half of the
139
+ * `presentation()` above, so the presenter reaches a contributed document
140
+ * without importing this module. Registered at module load, the shape
141
+ * `packages/editor-game/src/three/story-documents/three-story-documents.tsx:239` uses.
142
+ *
143
+ * SETTLING is the discovery pass this kind opens out of. A cold Vite graph can
144
+ * register the project catalog before its document contribution modules finish
145
+ * loading, and an explicit address is durable intent, so the owning pass is
146
+ * DRIVEN rather than raced with a timeout — what the presenter did by hand.
147
+ * "Not registered" then has two causes that need different fixes (no such
148
+ * contribution exists, or one exists and its module threw on import) and
149
+ * `contributionFailureHint` is what tells them apart; a generic refusal used to
150
+ * send the reader hunting for a missing file that was on disk all along, so
151
+ * this address refuses in its own words.
152
+ */
153
+ registerDocumentOpener<{ readonly id: string }>({
154
+ id: 'tool',
155
+ owner: 'tool-documents',
156
+ open: (_store, request) => {
157
+ // Resolve FIRST: `openToolDocument` resolves the same way and the document
158
+ // id is built from what it found, so the resolution is the answer.
159
+ const resolvedId = resolveToolDocumentContributionId(request.id);
160
+ if (resolvedId === null) return null;
161
+ return openToolDocument(resolvedId) ? toolDocumentId(resolvedId) : null;
162
+ },
163
+ settle: async (request) => {
164
+ await refreshProjectToolContributions();
165
+ if (resolveToolDocumentContributionId(request.id) !== null) return;
166
+ throw new Error(
167
+ `Tool document is not registered: ${request.id}.${contributionFailureHint(request.id)}`,
168
+ );
169
+ },
170
+ /**
171
+ * THE KIND'S OWN READINESS — a contributed document is ready to be driven
172
+ * once its React root has committed and, if that root mounted a stage, once
173
+ * the stage has registered its Object3D session. The presenter used to hold
174
+ * this rule for this address by name (`editor-view-presentation.ts`'s
175
+ * `kind === 'tool' || 'asset'`); it belongs here, where the contribution the
176
+ * host mounted is what answers.
177
+ */
178
+ ready: async (documentId) => {
179
+ await waitForContributedDocumentMount(documentId);
180
+ await awaitAnnouncedObject3DDocumentSession(documentId);
181
+ },
182
+ });
183
+
184
+ /**
185
+ * Open every STANDING document contribution, and keep that set in step with
186
+ * discovery: a capability added mid-session brings its tab with it, and a
187
+ * capability whose source is deleted takes its tab away rather than leaving a
188
+ * pinned panel nothing backs.
189
+ *
190
+ * Returns the teardown for the subscription (it does not close the documents —
191
+ * the project-open path owns that, the same way it owns the boards).
192
+ */
193
+ export function installStandingToolDocuments(): () => void {
194
+ const opened = new Set<string>();
195
+ const reconcile = () => {
196
+ const standing = getDocumentToolContributions().filter((item) => item.standing);
197
+ const live = new Set(standing.map((item) => item.id));
198
+ for (const id of opened) {
199
+ if (live.has(id)) continue;
200
+ closeWorkspaceDocument(toolDocumentId(id), { discardDirty: true });
201
+ opened.delete(id);
202
+ }
203
+ for (const item of standing) {
204
+ if (opened.has(item.id)) continue;
205
+ if (openToolDocument(item.id, { activate: false })) opened.add(item.id);
206
+ }
207
+ // EVERY open tool document takes its slots afresh on discovery change,
208
+ // standing or not: a module re-evaluated on save may have gained or lost
209
+ // its `Toolbar`, and `openWorkspaceDocument` on an open id is what
210
+ // refreshes the descriptor's mount slots (see the registry).
211
+ const open = new Set(openWorkspaceDocuments().map((d) => d.descriptor.id));
212
+ for (const item of getDocumentToolContributions()) {
213
+ if (!open.has(toolDocumentId(item.id))) continue;
214
+ openToolDocument(item.id, { activate: false });
215
+ }
216
+ };
217
+ reconcile();
218
+ return subscribeToolContributions(reconcile);
219
+ }
220
+
221
+ /** `Open Tool: <title>` palette actions — one per discovered document tool
222
+ * (the B12 discovery gesture). A standing document is always open, so its
223
+ * action ACTIVATES the tab rather than teaching a way to summon it. */
224
+ export function buildToolActions(): EditorAction[] {
225
+ return getDocumentToolContributions().map((t) => ({
226
+ id: `tool-doc:${t.id}`,
227
+ label: t.standing ? `Show ${t.title}` : `Open Tool: ${t.title}`,
228
+ category: 'action' as const,
229
+ execute: () => void openToolDocument(t.id),
230
+ }));
231
+ }
232
+
233
+ /** Content host: resolves the LIVE tool by id on every render (HMR re-key,
234
+ * honest deleted-tool state). */
235
+ /** The header strip's contents for a tool document: the contribution's own
236
+ * `Toolbar`, mounted through the same host so it reads the same props. */
237
+ export function ToolDocumentToolbar({ documentId, active }: WorkspaceDocumentContentProps) {
238
+ useSyncExternalStore(subscribeToolContributions, getGlobalToolContributions);
239
+ const toolId = documentId.startsWith('tool:') ? documentId.slice('tool:'.length) : documentId;
240
+ const contribution = getDocumentToolContributions().find((item) => item.id === toolId);
241
+ if (!contribution?.Toolbar) return null;
242
+ return (
243
+ <ToolHost
244
+ key={`${contribution.id}:${contribution.version}:toolbar`}
245
+ contribution={contribution}
246
+ Component={contribution.Toolbar as unknown as ComponentType<Record<string, unknown>>}
247
+ documentId={documentId}
248
+ active={active}
249
+ />
250
+ );
251
+ }
252
+
253
+ /** The shelf rail's contents for a tool document: the contribution's own
254
+ * `Shelf`, mounted through the same host so it reads the same props. */
255
+ export function ToolDocumentShelf({ documentId, active }: WorkspaceDocumentContentProps) {
256
+ useSyncExternalStore(subscribeToolContributions, getGlobalToolContributions);
257
+ const toolId = documentId.startsWith('tool:') ? documentId.slice('tool:'.length) : documentId;
258
+ const contribution = getDocumentToolContributions().find((item) => item.id === toolId);
259
+ if (!contribution?.Shelf) return null;
260
+ return (
261
+ <ToolHost
262
+ key={`${contribution.id}:${contribution.version}:shelf`}
263
+ contribution={contribution}
264
+ Component={contribution.Shelf as unknown as ComponentType<Record<string, unknown>>}
265
+ documentId={documentId}
266
+ active={active}
267
+ />
268
+ );
269
+ }
270
+
271
+ export function ToolDocumentContent({ documentId, active }: WorkspaceDocumentContentProps) {
272
+ useSyncExternalStore(subscribeToolContributions, getGlobalToolContributions);
273
+ const toolId = documentId.startsWith('tool:') ? documentId.slice('tool:'.length) : documentId;
274
+ const contribution = getDocumentToolContributions().find((item) => item.id === toolId);
275
+ if (!contribution) {
276
+ return (
277
+ <div
278
+ style={{ padding: 12, fontSize: 12, color: themeVars.content.muted, pointerEvents: 'auto' }}
279
+ >
280
+ This tool contribution is no longer registered — close this document.
281
+ </div>
282
+ );
283
+ }
284
+ return (
285
+ <div
286
+ key={`${contribution.id}:${contribution.version}`}
287
+ data-testid={`tool-document:${contribution.id}`}
288
+ style={{
289
+ flex: 1,
290
+ minHeight: 0,
291
+ display: 'flex',
292
+ flexDirection: 'column',
293
+ pointerEvents: 'auto',
294
+ // B-11: the editor-provided baseline breathing room every hosted
295
+ // surface's content root has by convention (carried from the dock).
296
+ padding: 12,
297
+ }}
298
+ >
299
+ <ToolHost contribution={contribution} documentId={documentId} active={active} />
300
+ </div>
301
+ );
302
+ }
@@ -0,0 +1,262 @@
1
+ import { Checkbox, Select, TextInput, text } from '@volter/sdk/widgets';
2
+ import type { CSSProperties } from 'react';
3
+
4
+ type JsonSchema = Record<string, unknown>;
5
+
6
+ function schemaRecord(value: unknown): JsonSchema {
7
+ return value && typeof value === 'object' && !Array.isArray(value) ? (value as JsonSchema) : {};
8
+ }
9
+
10
+ function schemaType(schema: JsonSchema): string | undefined {
11
+ const type = schema['type'];
12
+ if (typeof type === 'string') return type;
13
+ if (Array.isArray(type)) return type.find((item): item is string => item !== 'null');
14
+ return undefined;
15
+ }
16
+
17
+ export function defaultValueForSchema(value: unknown): unknown {
18
+ const schema = schemaRecord(value);
19
+ if ('default' in schema) return structuredClone(schema['default']);
20
+ const type = schemaType(schema);
21
+ if (type === 'object' || schema['properties']) {
22
+ const result: Record<string, unknown> = {};
23
+ for (const [key, child] of Object.entries(schemaRecord(schema['properties']))) {
24
+ const childSchema = schemaRecord(child);
25
+ if (
26
+ 'default' in childSchema ||
27
+ (Array.isArray(schema['required']) && schema['required'].includes(key))
28
+ ) {
29
+ result[key] = defaultValueForSchema(childSchema);
30
+ }
31
+ }
32
+ return result;
33
+ }
34
+ if (type === 'array') return [];
35
+ if (type === 'boolean') return false;
36
+ if (type === 'number' || type === 'integer') return Number(schema['minimum'] ?? 0);
37
+ return '';
38
+ }
39
+
40
+ function humanize(value: string): string {
41
+ return value
42
+ .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
43
+ .replace(/[-_]/g, ' ')
44
+ .replace(/^./, (letter) => letter.toUpperCase());
45
+ }
46
+
47
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: this is the deliberately small JSON-Schema widget dispatch; each primitive type remains native HTML.
48
+ function PrimitiveField({
49
+ name,
50
+ schema,
51
+ value,
52
+ required,
53
+ onChange,
54
+ }: {
55
+ name: string;
56
+ schema: JsonSchema;
57
+ value: unknown;
58
+ required: boolean;
59
+ onChange(value: unknown): void;
60
+ }) {
61
+ const type = schemaType(schema);
62
+ const description = typeof schema['description'] === 'string' ? schema['description'] : null;
63
+ const choices = Array.isArray(schema['enum']) ? schema['enum'] : null;
64
+ const id = `tool-field:${name}`;
65
+
66
+ if (type === 'boolean') {
67
+ return (
68
+ <label style={{ ...fieldStyle, gridTemplateColumns: '18px minmax(0, 1fr)' }}>
69
+ <Checkbox
70
+ id={id}
71
+ checked={value === true}
72
+ onChange={(event) => onChange(event.target.checked)}
73
+ />
74
+ <span>
75
+ <span style={fieldLabelStyle}>{humanize(name)}</span>
76
+ {description && <span style={descriptionStyle}>{description}</span>}
77
+ </span>
78
+ </label>
79
+ );
80
+ }
81
+
82
+ const label = (
83
+ <span style={fieldLabelStyle}>
84
+ {humanize(name)} {!required && <span style={optionalStyle}>optional</span>}
85
+ </span>
86
+ );
87
+
88
+ if (choices) {
89
+ return (
90
+ <label style={fieldStyle} htmlFor={id}>
91
+ {label}
92
+ <Select
93
+ id={id}
94
+ value={String(value ?? '')}
95
+ onChange={(event) => onChange(event.target.value)}
96
+ style={controlLayoutStyle}
97
+ >
98
+ {!required && <option value="">Not set</option>}
99
+ {choices.map((choice) => (
100
+ <option key={String(choice)} value={String(choice)}>
101
+ {String(choice)}
102
+ </option>
103
+ ))}
104
+ </Select>
105
+ {description && <span style={descriptionStyle}>{description}</span>}
106
+ </label>
107
+ );
108
+ }
109
+
110
+ if (type === 'number' || type === 'integer') {
111
+ return (
112
+ <label style={fieldStyle} htmlFor={id}>
113
+ {label}
114
+ <TextInput
115
+ id={id}
116
+ type="number"
117
+ value={typeof value === 'number' ? value : ''}
118
+ min={typeof schema['minimum'] === 'number' ? schema['minimum'] : undefined}
119
+ max={typeof schema['maximum'] === 'number' ? schema['maximum'] : undefined}
120
+ step={type === 'integer' ? 1 : 'any'}
121
+ onChange={(event) =>
122
+ onChange(event.target.value === '' ? undefined : Number(event.target.value))
123
+ }
124
+ style={controlLayoutStyle}
125
+ />
126
+ {description && <span style={descriptionStyle}>{description}</span>}
127
+ </label>
128
+ );
129
+ }
130
+
131
+ if (type === 'array' && schemaType(schemaRecord(schema['items'])) === 'string') {
132
+ return (
133
+ <label style={fieldStyle} htmlFor={id}>
134
+ {label}
135
+ <TextInput
136
+ id={id}
137
+ value={Array.isArray(value) ? value.join(', ') : ''}
138
+ onChange={(event) =>
139
+ onChange(
140
+ event.target.value
141
+ .split(',')
142
+ .map((item) => item.trim())
143
+ .filter(Boolean),
144
+ )
145
+ }
146
+ placeholder="Comma-separated values"
147
+ style={controlLayoutStyle}
148
+ />
149
+ {description && <span style={descriptionStyle}>{description}</span>}
150
+ </label>
151
+ );
152
+ }
153
+
154
+ return (
155
+ <label style={fieldStyle} htmlFor={id}>
156
+ {label}
157
+ <TextInput
158
+ id={id}
159
+ value={typeof value === 'string' ? value : ''}
160
+ onChange={(event) => onChange(event.target.value || (required ? '' : undefined))}
161
+ style={controlLayoutStyle}
162
+ />
163
+ {description && <span style={descriptionStyle}>{description}</span>}
164
+ </label>
165
+ );
166
+ }
167
+
168
+ function ObjectFields({
169
+ schema,
170
+ value,
171
+ onChange,
172
+ path = '',
173
+ }: {
174
+ schema: JsonSchema;
175
+ value: Record<string, unknown>;
176
+ onChange(value: Record<string, unknown>): void;
177
+ path?: string;
178
+ }) {
179
+ const properties = schemaRecord(schema['properties']);
180
+ const required = new Set(Array.isArray(schema['required']) ? schema['required'] : []);
181
+ return (
182
+ <div style={{ display: 'grid', gap: 14 }}>
183
+ {Object.entries(properties).map(([key, child]) => {
184
+ const childSchema = schemaRecord(child);
185
+ const childType = schemaType(childSchema);
186
+ const update = (next: unknown) => {
187
+ const copy = { ...value };
188
+ if (next === undefined) delete copy[key];
189
+ else copy[key] = next;
190
+ onChange(copy);
191
+ };
192
+ if (childType === 'object' || childSchema['properties']) {
193
+ return (
194
+ <fieldset key={key} style={fieldsetStyle}>
195
+ <legend style={legendStyle}>{humanize(key)}</legend>
196
+ {typeof childSchema['description'] === 'string' && (
197
+ <p style={{ ...descriptionStyle, marginTop: 0 }}>{childSchema['description']}</p>
198
+ )}
199
+ <ObjectFields
200
+ schema={childSchema}
201
+ value={schemaRecord(value[key])}
202
+ onChange={update}
203
+ path={path ? `${path}.${key}` : key}
204
+ />
205
+ </fieldset>
206
+ );
207
+ }
208
+ return (
209
+ <PrimitiveField
210
+ key={key}
211
+ name={path ? `${path}.${key}` : key}
212
+ schema={childSchema}
213
+ value={value[key]}
214
+ required={required.has(key)}
215
+ onChange={update}
216
+ />
217
+ );
218
+ })}
219
+ </div>
220
+ );
221
+ }
222
+
223
+ export function ToolSchemaForm({
224
+ schema: schemaValue,
225
+ value,
226
+ onChange,
227
+ }: {
228
+ schema: unknown;
229
+ value: Record<string, unknown>;
230
+ onChange(value: Record<string, unknown>): void;
231
+ }) {
232
+ const schema = schemaRecord(schemaValue);
233
+ if (!schema['properties']) {
234
+ return <div style={descriptionStyle}>This schema has no form-compatible fields.</div>;
235
+ }
236
+ return <ObjectFields schema={schema} value={value} onChange={onChange} />;
237
+ }
238
+
239
+ const fieldStyle: CSSProperties = { display: 'grid', gap: 5 };
240
+ const fieldLabelStyle: CSSProperties = {
241
+ color: text[1],
242
+ fontWeight: 600,
243
+ fontSize: 'var(--volter-font-sm)',
244
+ };
245
+ const optionalStyle: CSSProperties = { color: text[3], fontWeight: 400, marginLeft: 5 };
246
+ const descriptionStyle: CSSProperties = {
247
+ display: 'block',
248
+ color: text[2],
249
+ fontSize: 'var(--volter-font-sm)',
250
+ lineHeight: 1.4,
251
+ };
252
+ const controlLayoutStyle: CSSProperties = {
253
+ boxSizing: 'border-box',
254
+ width: '100%',
255
+ };
256
+ const fieldsetStyle: CSSProperties = {
257
+ margin: 0,
258
+ padding: 14,
259
+ border: '1px solid var(--volter-boundary-default)',
260
+ borderRadius: 'var(--volter-radius-md)',
261
+ };
262
+ const legendStyle: CSSProperties = { padding: '0 6px', color: text[1], fontWeight: 600 };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * "Mount this AFTER the browser has painted the commit that asked for it."
3
+ *
4
+ * The inspector's live preview is the case this exists for: its mount effect
5
+ * builds a scene snapshot and draws the first frame, and React runs that effect
6
+ * in the SAME task as the selection commit — so the card, the name and the
7
+ * preview all appeared together, whenever the preview was finally done. Gating
8
+ * the heavy child on this hook lets the commit paint first; the picture arrives
9
+ * in a later frame and nothing is waiting on it.
10
+ *
11
+ * Two frames, not one: the first `requestAnimationFrame` callback runs BEFORE
12
+ * the paint of the commit that scheduled it, so only the second is past it.
13
+ * `startTransition` is the wrong tool here — the work is not React rendering,
14
+ * it is a `useEffect` doing GL work, which a transition does not defer.
15
+ *
16
+ * `key` identifies what is being waited for (a subject id, a preview key). It
17
+ * matters because these hosts are RE-RENDERED rather than remounted as the
18
+ * selection changes: comparing against the key that became ready is what makes
19
+ * the next subject wait again instead of inheriting the last one's readiness.
20
+ *
21
+ * Callers put the gate where their PLACEHOLDER is — the mini card's preview
22
+ * shows its quiet kind glyph, the section body shows its empty box — which is
23
+ * why this is a hook and not a wrapper component with one built-in fallback.
24
+ */
25
+
26
+ import { useEffect, useState } from 'react';
27
+
28
+ export function useAfterPaint(key: string): boolean {
29
+ const [readyKey, setReadyKey] = useState<string | null>(null);
30
+ useEffect(() => {
31
+ let second = 0;
32
+ const first = requestAnimationFrame(() => {
33
+ second = requestAnimationFrame(() => setReadyKey(key));
34
+ });
35
+ return () => {
36
+ cancelAnimationFrame(first);
37
+ cancelAnimationFrame(second);
38
+ };
39
+ }, [key]);
40
+ return readyKey === key;
41
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * The project's own IMAGE assets, for the inspector's `asset` slots.
3
+ *
4
+ * This is the existing asset-workflow seam and nothing new: the same
5
+ * `listAssets` walk over `public/` that the Asset Browser's Content gallery
6
+ * runs (`collectProjectContentAssets`), narrowed with the same facet
7
+ * classifier (`projectContentAssetFacet`). A texture slot must offer the same
8
+ * files the Asset Browser shows, so it reads them from the same place rather
9
+ * than growing a second listing.
10
+ *
11
+ * ONE scan is shared by every slot on screen — a `MeshStandardMaterial`
12
+ * publishes six of them, and six independent walks of `public/` per selection
13
+ * is the kind of quiet cost a panel never recovers from. The cached scan
14
+ * expires so an asset imported mid-session shows up on the next selection
15
+ * without a reload; the Asset Browser is still the surface that IMPORTS.
16
+ */
17
+
18
+ import { useEffect, useState } from 'react';
19
+ import {
20
+ collectProjectContentAssets,
21
+ projectContentAssetFacet,
22
+ } from '@volter/sdk/kit/asset-workflow/project-content';
23
+ import { listAssets } from '@volter/sdk/kit/editor-api';
24
+
25
+ /** How long a scan is reused. Long enough to cover one selection's worth of
26
+ * slots mounting together, short enough that a just-imported texture appears
27
+ * without a reload. */
28
+ const CACHE_MS = 10_000;
29
+
30
+ export interface ProjectImageAssets {
31
+ /** Public-root-relative paths, sorted. */
32
+ readonly paths: readonly string[];
33
+ /** Directories whose listing FAILED — an empty picker over a failed scan
34
+ * would tell the author their project has no textures. */
35
+ readonly failures: readonly string[];
36
+ }
37
+
38
+ const EMPTY: ProjectImageAssets = { paths: [], failures: [] };
39
+
40
+ let cached: { at: number; scan: Promise<ProjectImageAssets> } | null = null;
41
+
42
+ async function scanProjectImageAssets(): Promise<ProjectImageAssets> {
43
+ // SHIPPED IMAGES ONLY. A material slot names a file the GAME loads at
44
+ // runtime, and reference material is never exported — offering a moodboard
45
+ // plate here would author a texture path that 404s in the built game.
46
+ const listed = await collectProjectContentAssets(listAssets, ['public']);
47
+ return {
48
+ paths: listed.assets
49
+ .filter((asset) => projectContentAssetFacet(asset.entry.name) === 'image')
50
+ .map((asset) => asset.path)
51
+ .sort((a, b) => a.localeCompare(b)),
52
+ failures: listed.failedListings,
53
+ };
54
+ }
55
+
56
+ /** The shared scan, refreshed when the cached one has expired. */
57
+ export function projectImageAssets(): Promise<ProjectImageAssets> {
58
+ const now = Date.now();
59
+ if (!cached || now - cached.at > CACHE_MS) {
60
+ cached = {
61
+ at: now,
62
+ scan: scanProjectImageAssets().catch((error: unknown) => {
63
+ cached = null;
64
+ return { paths: [], failures: [error instanceof Error ? error.message : String(error)] };
65
+ }),
66
+ };
67
+ }
68
+ return cached.scan;
69
+ }
70
+
71
+ /** Read the shared scan into a component. `enabled: false` skips it entirely,
72
+ * so a panel with no asset row never walks `public/`. */
73
+ export function useProjectImageAssets(enabled: boolean): ProjectImageAssets {
74
+ const [assets, setAssets] = useState<ProjectImageAssets>(EMPTY);
75
+ useEffect(() => {
76
+ if (!enabled) return;
77
+ let live = true;
78
+ void projectImageAssets().then((next) => {
79
+ if (live) setAssets(next);
80
+ });
81
+ return () => {
82
+ live = false;
83
+ };
84
+ }, [enabled]);
85
+ return assets;
86
+ }