@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.
- package/LICENSE +202 -0
- package/NOTICE +20 -0
- package/README.md +38 -3
- package/package.json +510 -4
- package/src/account.ts +210 -0
- package/src/chrome.ts +88 -0
- package/src/client.ts +1646 -0
- package/src/commands.ts +66 -0
- package/src/contributions.ts +619 -0
- package/src/css-numeric-style.ts +97 -0
- package/src/document-probe.ts +282 -0
- package/src/editor-view.ts +225 -0
- package/src/extension.ts +40 -0
- package/src/generations.ts +178 -0
- package/src/host.ts +1157 -0
- package/src/http-transport.browser.ts +14 -0
- package/src/http-transport.node.ts +19 -0
- package/src/index.ts +131 -0
- package/src/kit/CapabilityCoverageSection.tsx +185 -0
- package/src/kit/account-client.ts +333 -0
- package/src/kit/action-registry.ts +317 -0
- package/src/kit/active-product.ts +76 -0
- package/src/kit/active-project.ts +155 -0
- package/src/kit/adapter-editor-config.ts +25 -0
- package/src/kit/adapter-module.ts +7 -0
- package/src/kit/adapter-observation.ts +49 -0
- package/src/kit/animation/animation-clock.ts +479 -0
- package/src/kit/animation/stage-transport.ts +385 -0
- package/src/kit/api/assets.ts +365 -0
- package/src/kit/api/project-open.ts +355 -0
- package/src/kit/api/project-source.ts +180 -0
- package/src/kit/api/project-state.ts +110 -0
- package/src/kit/api/relay.ts +270 -0
- package/src/kit/api/themes.ts +45 -0
- package/src/kit/api-asset-library-wire.ts +45 -0
- package/src/kit/api-base.ts +10 -0
- package/src/kit/api-build.ts +99 -0
- package/src/kit/api-git-wire.ts +56 -0
- package/src/kit/api-logs.ts +92 -0
- package/src/kit/api-project-identity.ts +74 -0
- package/src/kit/api-settings.ts +36 -0
- package/src/kit/api-worktrees.ts +205 -0
- package/src/kit/asset-capabilities.ts +344 -0
- package/src/kit/asset-compare-core.ts +171 -0
- package/src/kit/asset-editor-context.tsx +101 -0
- package/src/kit/asset-events.ts +96 -0
- package/src/kit/asset-inspector-actions.ts +87 -0
- package/src/kit/asset-selection-viewer-registry.ts +113 -0
- package/src/kit/asset-selection.ts +146 -0
- package/src/kit/asset-thumbnails.ts +25 -0
- package/src/kit/asset-viewers.ts +115 -0
- package/src/kit/asset-workflow/asset-import-jobs.ts +106 -0
- package/src/kit/asset-workflow/asset-ledger-backend.ts +126 -0
- package/src/kit/asset-workflow/asset-ledger.ts +156 -0
- package/src/kit/asset-workflow/asset-materialization-report.ts +140 -0
- package/src/kit/asset-workflow/asset-pack-manifest.ts +320 -0
- package/src/kit/asset-workflow/asset-types.ts +142 -0
- package/src/kit/asset-workflow/audio-preview-player.ts +193 -0
- package/src/kit/asset-workflow/audio-waveform.ts +22 -0
- package/src/kit/asset-workflow/cloud-asset-client.ts +263 -0
- package/src/kit/asset-workflow/hosted-asset-materialization.ts +236 -0
- package/src/kit/asset-workflow/image-view-scale.ts +31 -0
- package/src/kit/asset-workflow/import-contract.ts +124 -0
- package/src/kit/asset-workflow/ledger-write-lock.ts +244 -0
- package/src/kit/asset-workflow/pixi-spritesheet.ts +197 -0
- package/src/kit/asset-workflow/preview-resource-lifetime.ts +44 -0
- package/src/kit/asset-workflow/project-asset-commands.ts +20 -0
- package/src/kit/asset-workflow/project-content.ts +288 -0
- package/src/kit/asset-workflow/project-source-index.ts +545 -0
- package/src/kit/asset-workflow/thumbnail-system.ts +256 -0
- package/src/kit/authoring/active-adapter.ts +200 -0
- package/src/kit/authoring/active-systems.ts +422 -0
- package/src/kit/authoring/adapter-key.ts +18 -0
- package/src/kit/authoring/authoring-asset-url.ts +27 -0
- package/src/kit/authoring/bootstrap-state.ts +49 -0
- package/src/kit/authoring/boundary-authoring-adapter.ts +189 -0
- package/src/kit/authoring/canvas-scene-guides.ts +84 -0
- package/src/kit/authoring/composite-authoring-adapter.ts +2109 -0
- package/src/kit/authoring/consumer-actions.ts +531 -0
- package/src/kit/authoring/design-time-layers.ts +852 -0
- package/src/kit/authoring/design-time-mount-registry.ts +244 -0
- package/src/kit/authoring/edit-mode-authoring.ts +637 -0
- package/src/kit/authoring/empty-project-authoring.ts +22 -0
- package/src/kit/authoring/instance-source-menu.ts +135 -0
- package/src/kit/authoring/layered-pick.ts +185 -0
- package/src/kit/authoring/mounted-root-subjects.ts +146 -0
- package/src/kit/authoring/no-authoring-adapter.ts +59 -0
- package/src/kit/authoring/object3d-document-persistence.ts +122 -0
- package/src/kit/authoring/panel-authoring.ts +121 -0
- package/src/kit/authoring/project-authoring-session.ts +105 -0
- package/src/kit/authoring/provenance.ts +99 -0
- package/src/kit/authoring/react-canvas-navigation.ts +259 -0
- package/src/kit/authoring/react-design-canvas-style.ts +20 -0
- package/src/kit/authoring/react-story-board.ts +917 -0
- package/src/kit/authoring/selection-scope.ts +195 -0
- package/src/kit/authoring/shell-document-ops.ts +169 -0
- package/src/kit/authoring/story-board-chrome-fit.ts +107 -0
- package/src/kit/authoring/story-board-presentation.ts +111 -0
- package/src/kit/authoring/three-root.ts +67 -0
- package/src/kit/authoring/viewport-tool-context.ts +73 -0
- package/src/kit/authoring/viewport-tool-owner.ts +38 -0
- package/src/kit/authoring/world-session-state.ts +101 -0
- package/src/kit/authoring-seam-evidence.ts +300 -0
- package/src/kit/availability-tick.ts +66 -0
- package/src/kit/bitmap-label.ts +120 -0
- package/src/kit/boot-routing.ts +392 -0
- package/src/kit/breakpoint-state.ts +43 -0
- package/src/kit/build-identity.ts +16 -0
- package/src/kit/bytes-codec.ts +62 -0
- package/src/kit/cancellation-reason.ts +58 -0
- package/src/kit/canvas-frames.ts +88 -0
- package/src/kit/capture-camera-pose.ts +77 -0
- package/src/kit/capture-size.ts +88 -0
- package/src/kit/chrome-registry.ts +159 -0
- package/src/kit/chrome-slot-registry.ts +91 -0
- package/src/kit/collaboration-client.ts +264 -0
- package/src/kit/collaboration-presence.ts +41 -0
- package/src/kit/command-dispatch.ts +19 -0
- package/src/kit/command-listener.ts +2182 -0
- package/src/kit/command-registry.ts +71 -0
- package/src/kit/component-board-registry.ts +205 -0
- package/src/kit/component-states-registry.ts +199 -0
- package/src/kit/components/AlignToolbar.tsx +204 -0
- package/src/kit/components/ApplicationMenus.tsx +372 -0
- package/src/kit/components/AssetEditorShell.tsx +216 -0
- package/src/kit/components/AssetInspectorToolSection.tsx +124 -0
- package/src/kit/components/BoardRulers.tsx +354 -0
- package/src/kit/components/CanvasAddNodeDialogs.tsx +529 -0
- package/src/kit/components/CanvasSceneViewport.tsx +1195 -0
- package/src/kit/components/ChromeSlot.tsx +20 -0
- package/src/kit/components/CodeView.tsx +470 -0
- package/src/kit/components/CompactInspectorShell.tsx +39 -0
- package/src/kit/components/ConsolePanel.tsx +273 -0
- package/src/kit/components/GameplaySessionTimeline.tsx +295 -0
- package/src/kit/components/InspectionProjection.tsx +932 -0
- package/src/kit/components/Inspector.tsx +270 -0
- package/src/kit/components/InspectorCanvasPreview.tsx +35 -0
- package/src/kit/components/InspectorFieldsSection.tsx +290 -0
- package/src/kit/components/InspectorStoriesSection.tsx +92 -0
- package/src/kit/components/InspectorToolSection.tsx +96 -0
- package/src/kit/components/InspectorTransformSection.tsx +245 -0
- package/src/kit/components/LightExplorerPanel.tsx +433 -0
- package/src/kit/components/MediaProperties.tsx +145 -0
- package/src/kit/components/ProjectHeader.tsx +328 -0
- package/src/kit/components/ReactCanvasControls.tsx +358 -0
- package/src/kit/components/RootSelectionOverlay.tsx +3688 -0
- package/src/kit/components/RootTextEditor.tsx +79 -0
- package/src/kit/components/SaveStatus.tsx +70 -0
- package/src/kit/components/SurfaceCrashBoundary.tsx +105 -0
- package/src/kit/components/SurfaceStateOverlay.tsx +24 -0
- package/src/kit/components/ToolContributionSurfaces.tsx +49 -0
- package/src/kit/components/ToolHost.tsx +380 -0
- package/src/kit/components/Toolbar.tsx +811 -0
- package/src/kit/components/TransientHint.tsx +44 -0
- package/src/kit/components/VersionControlSection.tsx +470 -0
- package/src/kit/components/ViewportOverlaysMenu.tsx +177 -0
- package/src/kit/components/VolterLogo.tsx +18 -0
- package/src/kit/components/WorktreeSwitcher.tsx +712 -0
- package/src/kit/components/account-documents.tsx +1162 -0
- package/src/kit/components/asset-documents.tsx +794 -0
- package/src/kit/components/asset-editor-persistence.ts +216 -0
- package/src/kit/components/asset-selection-section.tsx +545 -0
- package/src/kit/components/asset-thumbnails.tsx +307 -0
- package/src/kit/components/asset-viewers/AudioViewer.tsx +201 -0
- package/src/kit/components/asset-viewers/GenericJsonViewer.tsx +102 -0
- package/src/kit/components/asset-viewers/ImageViewer.tsx +300 -0
- package/src/kit/components/asset-viewers/JsonAssetDocument.tsx +98 -0
- package/src/kit/components/asset-viewers/OnlineAssetDetail.tsx +426 -0
- package/src/kit/components/asset-viewers/SourceAssetViewer.tsx +356 -0
- package/src/kit/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
- package/src/kit/components/asset-viewers/VideoViewer.tsx +101 -0
- package/src/kit/components/asset-viewers/shader-source.ts +144 -0
- package/src/kit/components/board-guides.ts +150 -0
- package/src/kit/components/canvas-scene-hotkeys.ts +37 -0
- package/src/kit/components/canvas-temporary-pivot.ts +34 -0
- package/src/kit/components/core-utilities.tsx +94 -0
- package/src/kit/components/inspector-preview-section.tsx +223 -0
- package/src/kit/components/inspector-revert-label.ts +20 -0
- package/src/kit/components/inspector-selection.ts +42 -0
- package/src/kit/components/inspector-stories-gating.ts +171 -0
- package/src/kit/components/inspector-transform-subject.ts +11 -0
- package/src/kit/components/inspector-transform.ts +88 -0
- package/src/kit/components/kind-documents.tsx +544 -0
- package/src/kit/components/primitives/DraftColorInput.tsx +74 -0
- package/src/kit/components/project-tool-documents.tsx +402 -0
- package/src/kit/components/scene-documents.tsx +221 -0
- package/src/kit/components/status-contributions.tsx +407 -0
- package/src/kit/components/tool-documents.tsx +302 -0
- package/src/kit/components/tool-schema-form.tsx +262 -0
- package/src/kit/components/use-after-paint.ts +41 -0
- package/src/kit/components/use-project-image-assets.ts +86 -0
- package/src/kit/components/workspace-history.ts +32 -0
- package/src/kit/components/world-documents.tsx +570 -0
- package/src/kit/components/world-overlay-gestures.ts +1939 -0
- package/src/kit/composite-screenshot.ts +2238 -0
- package/src/kit/content-entry-source-registry.ts +184 -0
- package/src/kit/contribution-surfaces.ts +48 -0
- package/src/kit/coverage/canvas-reveal.ts +192 -0
- package/src/kit/coverage/design-time-surfaces.ts +101 -0
- package/src/kit/coverage/ontology-invariants.ts +466 -0
- package/src/kit/coverage/session-vitals.ts +503 -0
- package/src/kit/crash-null-boundary.ts +36 -0
- package/src/kit/creation-site-edit.ts +1491 -0
- package/src/kit/creation-site-registry.ts +160 -0
- package/src/kit/delegate-harness-registry.ts +134 -0
- package/src/kit/document-areas.ts +70 -0
- package/src/kit/document-context-registry.ts +193 -0
- package/src/kit/document-open-registry.ts +200 -0
- package/src/kit/document-play-extension.ts +221 -0
- package/src/kit/document-preview-source.ts +20 -0
- package/src/kit/document-renderer-session.ts +138 -0
- package/src/kit/document-stage-sessions.ts +26 -0
- package/src/kit/document-viewports.ts +120 -0
- package/src/kit/editor-api.ts +46 -0
- package/src/kit/editor-chrome-capture.ts +136 -0
- package/src/kit/editor-commands.ts +176 -0
- package/src/kit/editor-console.ts +580 -0
- package/src/kit/editor-current-view.ts +56 -0
- package/src/kit/editor-document-probe.ts +1166 -0
- package/src/kit/editor-git-client.ts +115 -0
- package/src/kit/editor-hotkeys.ts +728 -0
- package/src/kit/editor-lease-view.ts +39 -0
- package/src/kit/editor-lease.ts +415 -0
- package/src/kit/editor-mode.ts +19 -0
- package/src/kit/editor-notifications.ts +140 -0
- package/src/kit/editor-presence.ts +563 -0
- package/src/kit/editor-presentation-activity.ts +58 -0
- package/src/kit/editor-presentation-notice.ts +42 -0
- package/src/kit/editor-runtime.tsx +147 -0
- package/src/kit/editor-server-response.ts +86 -0
- package/src/kit/editor-session-attribution.ts +85 -0
- package/src/kit/editor-session-mode.ts +54 -0
- package/src/kit/editor-state-facets.ts +74 -0
- package/src/kit/editor-view-presentation.ts +777 -0
- package/src/kit/environment-images.ts +58 -0
- package/src/kit/eyedropper-session.ts +60 -0
- package/src/kit/files/file-provider.ts +62 -0
- package/src/kit/files/project-files.ts +270 -0
- package/src/kit/finders/index.ts +137 -0
- package/src/kit/finders/scenes-from-entrypoint-selection.ts +387 -0
- package/src/kit/frame/frame-parts.ts +30 -0
- package/src/kit/framed-document-capture.ts +34 -0
- package/src/kit/game-globals-prelude.ts +143 -0
- package/src/kit/game-surface-defaults.ts +33 -0
- package/src/kit/gameplay-dom-recording.ts +318 -0
- package/src/kit/gameplay-export-state.ts +14 -0
- package/src/kit/gameplay-replay.ts +417 -0
- package/src/kit/gameplay-session-time.ts +9 -0
- package/src/kit/gameplay-sessions.ts +204 -0
- package/src/kit/hierarchy-component-marks.ts +298 -0
- package/src/kit/hierarchy-internals.ts +197 -0
- package/src/kit/hierarchy-kind-icon.ts +217 -0
- package/src/kit/hierarchy-menu-registry.ts +67 -0
- package/src/kit/hierarchy-node-rows.ts +307 -0
- package/src/kit/hierarchy-panel-view.ts +280 -0
- package/src/kit/hierarchy-projection.ts +76 -0
- package/src/kit/hierarchy-row-media.ts +45 -0
- package/src/kit/hierarchy-row-model.ts +308 -0
- package/src/kit/hierarchy-rows.ts +11 -0
- package/src/kit/hierarchy-walk.ts +86 -0
- package/src/kit/history/editor-session.ts +25 -0
- package/src/kit/history/history-commands.ts +147 -0
- package/src/kit/history/history-delegate.ts +187 -0
- package/src/kit/history/history-limit-notices.ts +43 -0
- package/src/kit/history/history-service.ts +1189 -0
- package/src/kit/history/persistence-coordinator.ts +35 -0
- package/src/kit/history/project-file-history.ts +386 -0
- package/src/kit/history/project-root-history-backends.ts +139 -0
- package/src/kit/history/resource-registry.ts +209 -0
- package/src/kit/history/snapshot-store.ts +103 -0
- package/src/kit/history/source-history-backend.ts +546 -0
- package/src/kit/history-types.ts +124 -0
- package/src/kit/hmr-registration-group.ts +67 -0
- package/src/kit/hmr-stable-react-context.ts +23 -0
- package/src/kit/hotkeys.ts +190 -0
- package/src/kit/inference-diagnostics.ts +69 -0
- package/src/kit/initial-project.ts +80 -0
- package/src/kit/inspection/active-subject.ts +571 -0
- package/src/kit/inspection/active-surface.ts +142 -0
- package/src/kit/inspection/compose-subject.ts +1055 -0
- package/src/kit/inspection/compose.ts +7 -0
- package/src/kit/inspection/display.ts +171 -0
- package/src/kit/inspection/document-subject.ts +109 -0
- package/src/kit/inspection/game-subject.ts +85 -0
- package/src/kit/inspection/null-subject.ts +119 -0
- package/src/kit/inspection/serialize.ts +357 -0
- package/src/kit/inspection/use-active-inspection.ts +180 -0
- package/src/kit/inspection-model.ts +542 -0
- package/src/kit/inspection-node-media.ts +58 -0
- package/src/kit/inspector-presentation.ts +203 -0
- package/src/kit/inspector-property-grouping.ts +64 -0
- package/src/kit/inspector-section-registry.ts +221 -0
- package/src/kit/instance-source-actions.ts +163 -0
- package/src/kit/js-heap.ts +71 -0
- package/src/kit/key-actions.ts +91 -0
- package/src/kit/keymap-presets.ts +428 -0
- package/src/kit/layout-policy.ts +31 -0
- package/src/kit/light-explorer-model.ts +134 -0
- package/src/kit/live-canvas-frame.ts +55 -0
- package/src/kit/live-document.ts +296 -0
- package/src/kit/live-gesture-lock.ts +50 -0
- package/src/kit/live-seam-evidence.ts +11 -0
- package/src/kit/live-session-registry.ts +220 -0
- package/src/kit/live-transition.ts +391 -0
- package/src/kit/manifest-project.ts +107 -0
- package/src/kit/module-fetch-diagnosis.ts +192 -0
- package/src/kit/mount-failure-report.ts +154 -0
- package/src/kit/native-selection-style.ts +497 -0
- package/src/kit/object3d-document-write-policy.ts +137 -0
- package/src/kit/packaged-runtime.ts +108 -0
- package/src/kit/palettes/maya.palette.json +57 -0
- package/src/kit/palettes/substance.palette.json +57 -0
- package/src/kit/performance-profiler.ts +367 -0
- package/src/kit/performance-sources.ts +69 -0
- package/src/kit/photograph-notice.ts +141 -0
- package/src/kit/play-boot-phase.ts +166 -0
- package/src/kit/play-camera-flight.ts +35 -0
- package/src/kit/png-encode.worker.ts +26 -0
- package/src/kit/presentation-surface.ts +248 -0
- package/src/kit/product-command.ts +90 -0
- package/src/kit/project-adapter.ts +1140 -0
- package/src/kit/project-asset-refresh.ts +23 -0
- package/src/kit/project-asset-roots.ts +68 -0
- package/src/kit/project-local-state.ts +151 -0
- package/src/kit/project-manager.ts +243 -0
- package/src/kit/project-module-changes.ts +201 -0
- package/src/kit/project-module-split.ts +270 -0
- package/src/kit/project-play-layers.ts +25 -0
- package/src/kit/project-provenance.ts +115 -0
- package/src/kit/project-ready.ts +42 -0
- package/src/kit/project-shape.ts +68 -0
- package/src/kit/project-tools.ts +107 -0
- package/src/kit/projection-types.ts +44 -0
- package/src/kit/readiness.ts +113 -0
- package/src/kit/renderer-resource-counts.ts +27 -0
- package/src/kit/reported-play-state.ts +90 -0
- package/src/kit/resolve-contributed-command.ts +14 -0
- package/src/kit/resolve-relative-specifier.ts +33 -0
- package/src/kit/retained-document-states.ts +91 -0
- package/src/kit/scene-document-plan.ts +320 -0
- package/src/kit/scene-live-open.ts +210 -0
- package/src/kit/scoped-game-css.ts +152 -0
- package/src/kit/served-url.ts +5 -0
- package/src/kit/session-close.ts +17 -0
- package/src/kit/session-tombstone.ts +127 -0
- package/src/kit/settings/settings-provider.ts +82 -0
- package/src/kit/settings-store.ts +348 -0
- package/src/kit/shell-document-state.ts +27 -0
- package/src/kit/shell-store-door.ts +45 -0
- package/src/kit/shell-store.ts +722 -0
- package/src/kit/source-conflict.ts +122 -0
- package/src/kit/stage-context.ts +377 -0
- package/src/kit/stage-invalidation.ts +25 -0
- package/src/kit/stage-store-registry.ts +69 -0
- package/src/kit/startup-failure.ts +80 -0
- package/src/kit/state-report-deferral.ts +73 -0
- package/src/kit/storage/host-files-storage.ts +97 -0
- package/src/kit/storage/http-storage.ts +174 -0
- package/src/kit/storage/index.ts +75 -0
- package/src/kit/storage/mem-storage.ts +158 -0
- package/src/kit/storage/path-lock.ts +44 -0
- package/src/kit/storage/paths.ts +26 -0
- package/src/kit/storage-types.ts +127 -0
- package/src/kit/stories/StoryPreviewMount.tsx +306 -0
- package/src/kit/stories/compose-project-stories.ts +255 -0
- package/src/kit/stories/prefabs-finder.ts +54 -0
- package/src/kit/stories/prefabs-from-stories.ts +182 -0
- package/src/kit/stories/project-story-regions.ts +24 -0
- package/src/kit/stories/story-capture.ts +579 -0
- package/src/kit/stories/story-declared-medium.ts +126 -0
- package/src/kit/stories/story-discovery.ts +176 -0
- package/src/kit/stories/story-dom-runtime.ts +78 -0
- package/src/kit/stories/story-grouping.ts +111 -0
- package/src/kit/stories/story-mount-turn.ts +27 -0
- package/src/kit/stories/story-presentation.ts +215 -0
- package/src/kit/stories/story-preview-component.ts +7 -0
- package/src/kit/stories/story-registry.ts +530 -0
- package/src/kit/stories-scope.ts +35 -0
- package/src/kit/story-document-openers.ts +36 -0
- package/src/kit/story-thumbnails.ts +47 -0
- package/src/kit/surface-keyboard.ts +101 -0
- package/src/kit/surface-state.ts +135 -0
- package/src/kit/system-seam-evidence.ts +72 -0
- package/src/kit/tab-census.ts +202 -0
- package/src/kit/tab-lifecycle-client.ts +227 -0
- package/src/kit/theme-library.ts +897 -0
- package/src/kit/theme-preference.ts +429 -0
- package/src/kit/three-viewport-presentation.ts +23 -0
- package/src/kit/tool-contribution-play.ts +74 -0
- package/src/kit/tool-loader.ts +1918 -0
- package/src/kit/transform-mode-request.ts +66 -0
- package/src/kit/transient-hint.ts +78 -0
- package/src/kit/transport-strip.tsx +174 -0
- package/src/kit/ui-source/adapter-region-includes.ts +238 -0
- package/src/kit/ui-source/file-region-resolver.ts +302 -0
- package/src/kit/ui-source/inspect.ts +775 -0
- package/src/kit/ui-source/source-write-backend.ts +605 -0
- package/src/kit/ui-source/tier-source-write-backend.ts +279 -0
- package/src/kit/user-local-state.ts +105 -0
- package/src/kit/viewport-activation-timings.ts +840 -0
- package/src/kit/viewport-editor-controls.ts +22 -0
- package/src/kit/viewport-presentation.ts +668 -0
- package/src/kit/viewport-surface-status.tsx +55 -0
- package/src/kit/wait-until.ts +37 -0
- package/src/kit/worker-call-metrics.ts +166 -0
- package/src/kit/workspace-areas.ts +191 -0
- package/src/kit/workspace-aux-commands.ts +11 -0
- package/src/kit/workspace-available-documents.ts +142 -0
- package/src/kit/workspace-core-utilities.ts +31 -0
- package/src/kit/workspace-document-ids.ts +59 -0
- package/src/kit/workspace-document-registry.ts +624 -0
- package/src/kit/workspace-document-restore.ts +146 -0
- package/src/kit/workspace-host-commands.ts +141 -0
- package/src/kit/workspace-persistence-gate.ts +40 -0
- package/src/kit/workspace-play-utilities.ts +44 -0
- package/src/kit/workspace-presets.ts +446 -0
- package/src/kit/workspace-regions.ts +276 -0
- package/src/kit/workspace-static-panels.ts +73 -0
- package/src/kit/workspace-status-registry.ts +121 -0
- package/src/kit/workspace-storage.ts +35 -0
- package/src/kit/workspace-style.ts +226 -0
- package/src/kit/workspace-utility-commands.ts +74 -0
- package/src/kit/workspace-utility-registry.ts +263 -0
- package/src/kit/world-adoption-event.ts +23 -0
- package/src/kit/world-adoption.ts +115 -0
- package/src/kit/world-canvas-viewport-state.ts +35 -0
- package/src/kit/world-document-routing.ts +104 -0
- package/src/kit/world-pan-state.ts +198 -0
- package/src/kit/write-pipe.ts +173 -0
- package/src/layout-arrangements.ts +5 -0
- package/src/layouts.tsx +108 -0
- package/src/looks.ts +16 -0
- package/src/project/output-roots.ts +73 -0
- package/src/project/tab-census.ts +155 -0
- package/src/project-tool-catalog.ts +104 -0
- package/src/selection.tsx +107 -0
- package/src/services.ts +18 -0
- package/src/session/build-report.ts +22 -0
- package/src/session/collaboration-types.ts +262 -0
- package/src/session/command-table.ts +327 -0
- package/src/session/discovery.ts +100 -0
- package/src/session/editor-brand.ts +48 -0
- package/src/session/editor-compatibility.ts +317 -0
- package/src/session/editor-control-lifecycle.ts +68 -0
- package/src/session/editor-control-protocol.ts +5 -0
- package/src/session/entrypoint-selection-readers.ts +66 -0
- package/src/session/entrypoint-selection-source.ts +120 -0
- package/src/session/game-css-scope.ts +30 -0
- package/src/session/hosted-attachment.ts +225 -0
- package/src/session/limited-view.ts +82 -0
- package/src/session/product-create.ts +24 -0
- package/src/session/product-locator.ts +478 -0
- package/src/session/project-module-url.ts +242 -0
- package/src/session/project-serving.ts +164 -0
- package/src/session/project-upgrade.ts +403 -0
- package/src/session/registry-format.ts +210 -0
- package/src/session/relative-path-guard.ts +56 -0
- package/src/session/scoped-game-css.ts +461 -0
- package/src/session/source-glob.ts +15 -0
- package/src/session/tool-contribution-convention.ts +123 -0
- package/src/session/workbench-locator.ts +712 -0
- package/src/session.ts +41 -0
- package/src/share.ts +160 -0
- package/src/source-analysis.ts +28 -0
- package/src/source-authoring.ts +439 -0
- package/src/tools/errors.ts +91 -0
- package/src/tools/provider-execution.ts +70 -0
- package/src/tools/registry.ts +341 -0
- package/src/tools/types.ts +159 -0
- package/src/transport.ts +100 -0
- package/src/types.ts +1693 -0
- package/src/views.ts +164 -0
- package/src/widgets/design-system.ts +93 -0
- package/src/widgets/editor-appearance.ts +151 -0
- package/src/widgets/editor-material.ts +83 -0
- package/src/widgets/icon-set-registry.ts +105 -0
- package/src/widgets/index.ts +71 -0
- package/src/widgets/inspector-widgets/AlignmentGrid.tsx +182 -0
- package/src/widgets/inspector-widgets/AssetSlotPicker.tsx +123 -0
- package/src/widgets/inspector-widgets/BorderEditor.tsx +309 -0
- package/src/widgets/inspector-widgets/ColorPicker.tsx +549 -0
- package/src/widgets/inspector-widgets/CurveEditor.tsx +359 -0
- package/src/widgets/inspector-widgets/FilterEditor.tsx +108 -0
- package/src/widgets/inspector-widgets/FontPicker.tsx +191 -0
- package/src/widgets/inspector-widgets/GradientEditor.tsx +623 -0
- package/src/widgets/inspector-widgets/ScrubbableInput.tsx +180 -0
- package/src/widgets/inspector-widgets/ShadowEditor.tsx +319 -0
- package/src/widgets/inspector-widgets/color-utils.ts +201 -0
- package/src/widgets/inspector-widgets/curve-utils.ts +212 -0
- package/src/widgets/inspector-widgets/index.ts +25 -0
- package/src/widgets/inspector-widgets/shared.tsx +140 -0
- package/src/widgets/interactive-edit-scope.ts +33 -0
- package/src/widgets/patterns/Dialog.tsx +140 -0
- package/src/widgets/patterns/Fields.tsx +44 -0
- package/src/widgets/patterns/List.tsx +25 -0
- package/src/widgets/patterns/StateSurface.tsx +40 -0
- package/src/widgets/patterns/Surfaces.tsx +122 -0
- package/src/widgets/patterns/Tabs.tsx +80 -0
- package/src/widgets/patterns/Toolbar.tsx +72 -0
- package/src/widgets/patterns/Tree.tsx +72 -0
- package/src/widgets/primitives/AnchoredMenu.tsx +260 -0
- package/src/widgets/primitives/Button.tsx +62 -0
- package/src/widgets/primitives/ColorInput.tsx +78 -0
- package/src/widgets/primitives/DraftTextInput.tsx +63 -0
- package/src/widgets/primitives/EditorIcon.tsx +157 -0
- package/src/widgets/primitives/FormControls.tsx +88 -0
- package/src/widgets/primitives/HoverPreview.tsx +96 -0
- package/src/widgets/primitives/JsonInput.tsx +113 -0
- package/src/widgets/primitives/Layout.tsx +100 -0
- package/src/widgets/primitives/Menu.tsx +161 -0
- package/src/widgets/primitives/NumberInput.tsx +169 -0
- package/src/widgets/primitives/Panel.tsx +80 -0
- package/src/widgets/primitives/SectionHeader.tsx +77 -0
- package/src/widgets/primitives/Text.tsx +54 -0
- package/src/widgets/primitives/ThemeRootPortal.tsx +52 -0
- package/src/widgets/primitives/Tooltip.tsx +204 -0
- package/src/widgets/primitives/Vec3Input.tsx +70 -0
- package/src/widgets/primitives/banner-tones.ts +32 -0
- package/src/widgets/primitives/clamp-to-viewport.ts +44 -0
- package/src/widgets/primitives/editor-icons.ts +254 -0
- package/src/widgets/primitives/panel-header-styles.ts +42 -0
- package/src/widgets/theme.ts +2841 -0
- package/src/widgets/z-index.ts +25 -0
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KIND DOCUMENTS — an adapter-table document (a model, a page; ARCHITECTURE-CORE
|
|
3
|
+
* §The project model, "Documents, not scenes") opened in the editor
|
|
4
|
+
* registered for its kind (owner ruling, 2026-09-05: the tab IS the thing —
|
|
5
|
+
* `cage`, kind Model — and the editor is chosen by the document's kind; code
|
|
6
|
+
* is never a fallback, it opens only when code is opened).
|
|
7
|
+
*
|
|
8
|
+
* A `workspace.document` contribution declares `export const documentKind =
|
|
9
|
+
* 'model'` (`tool-loader.ts`, `documentContributionForKind`). Opening a table
|
|
10
|
+
* entry of that kind opens ONE document per entry — id `document:<entry id>`,
|
|
11
|
+
* title = the entry's label — whose content, header and shelf are the
|
|
12
|
+
* contribution's own components mounted through the same `ToolHost` a tool
|
|
13
|
+
* document uses, with the entry handed over as `props.document`
|
|
14
|
+
* (`ToolDocumentEntry`). Persisted and restored by the entry's id
|
|
15
|
+
* (`workspace-state-persistence.ts`); presented in view links as
|
|
16
|
+
* `{ kind: 'document', id }`. A kind with no registered editor opens nothing
|
|
17
|
+
* here and the caller falls back to the entry's source, by its own choice.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { ToolDocumentEntry } from '@volter/sdk/contributions';
|
|
21
|
+
import { themeVars } from '@volter/sdk/widgets';
|
|
22
|
+
import type { DocumentEntry } from '@volter/project/adapter/adapter-module';
|
|
23
|
+
import { type ComponentType, useSyncExternalStore } from 'react';
|
|
24
|
+
import { setSelectedAsset } from '@volter/sdk/kit/asset-selection';
|
|
25
|
+
import { assetCapabilities } from '@volter/sdk/kit/asset-capabilities';
|
|
26
|
+
import {
|
|
27
|
+
awaitAnnouncedObject3DDocumentSession,
|
|
28
|
+
waitForContributedDocumentMount,
|
|
29
|
+
} from '@volter/sdk/kit/document-context-registry';
|
|
30
|
+
import { registerDocumentOpener } from '@volter/sdk/kit/document-open-registry';
|
|
31
|
+
import type { AssetKind } from '@volter/sdk/kit/asset-selection';
|
|
32
|
+
import {
|
|
33
|
+
projectAdapterFacet,
|
|
34
|
+
type ResolvedDocumentTable,
|
|
35
|
+
subscribeProjectAdapter,
|
|
36
|
+
} from '@volter/sdk/kit/project-adapter';
|
|
37
|
+
import {
|
|
38
|
+
documentContributionForKind,
|
|
39
|
+
getGlobalToolContributions,
|
|
40
|
+
subscribeToolContributions,
|
|
41
|
+
} from '@volter/sdk/kit/tool-loader';
|
|
42
|
+
import { waitUntil } from '@volter/sdk/kit/wait-until';
|
|
43
|
+
import { getCurrentProject } from '@volter/sdk/kit/active-project';
|
|
44
|
+
import {
|
|
45
|
+
type OpenWorkspaceDocumentOptions,
|
|
46
|
+
openWorkspaceDocument,
|
|
47
|
+
openWorkspaceDocuments,
|
|
48
|
+
type WorkspaceDocumentContentProps,
|
|
49
|
+
} from '@volter/sdk/kit/workspace-document-registry';
|
|
50
|
+
import { registerWorkspaceDocumentRestorer } from '@volter/sdk/kit/workspace-document-restore';
|
|
51
|
+
import { openAssetDocument } from '@volter/sdk/kit/components/asset-documents';
|
|
52
|
+
import { ToolHost } from '@volter/sdk/kit/components/ToolHost';
|
|
53
|
+
|
|
54
|
+
const PREFIX = 'document:';
|
|
55
|
+
|
|
56
|
+
/** Stable identity for one table entry's document. */
|
|
57
|
+
export function kindDocumentId(entryId: string): string {
|
|
58
|
+
return `${PREFIX}${entryId}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** The table entry id a kind document id names, or `null` for another kind of id. */
|
|
62
|
+
export function kindDocumentEntryId(documentId: string): string | null {
|
|
63
|
+
return documentId.startsWith(PREFIX) ? documentId.slice(PREFIX.length) : null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** The entries of every open kind document, by document id — what content,
|
|
67
|
+
* header and shelf mounts read, and what persistence records. */
|
|
68
|
+
const entries = new Map<
|
|
69
|
+
string,
|
|
70
|
+
{ readonly entry: DocumentEntry; readonly props: ToolDocumentEntry }
|
|
71
|
+
>();
|
|
72
|
+
|
|
73
|
+
export function kindDocumentEntry(documentId: string): DocumentEntry | undefined {
|
|
74
|
+
return entries.get(documentId)?.entry;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function asToolDocumentEntry(entry: DocumentEntry): ToolDocumentEntry {
|
|
78
|
+
return {
|
|
79
|
+
id: entry.id,
|
|
80
|
+
kind: entry.kind,
|
|
81
|
+
label: entry.label,
|
|
82
|
+
...(entry.source
|
|
83
|
+
? {
|
|
84
|
+
source: {
|
|
85
|
+
path: entry.source.path,
|
|
86
|
+
...(entry.source.export ? { export: entry.source.export } : {}),
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
: {}),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* What a table entry of a kind NOTHING edits opens as: the asset its source
|
|
95
|
+
* already is. A module, or anything the asset routes do not know, opens as
|
|
96
|
+
* source; a kind the routes DO know (a model, an image, a video) opens in its
|
|
97
|
+
* own viewer. Before this, every unedited kind opened as source.
|
|
98
|
+
*/
|
|
99
|
+
export function uneditedKindAssetKind(entry: DocumentEntry): AssetKind {
|
|
100
|
+
const path = entry.source?.path;
|
|
101
|
+
if (!path) return 'source';
|
|
102
|
+
const kind = assetCapabilities(path).kind;
|
|
103
|
+
return kind === 'model' ||
|
|
104
|
+
kind === 'image' ||
|
|
105
|
+
kind === 'video' ||
|
|
106
|
+
kind === 'audio' ||
|
|
107
|
+
kind === 'json'
|
|
108
|
+
? kind
|
|
109
|
+
: 'source';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Is there an editor registered for documents of `kind`? */
|
|
113
|
+
export function hasKindEditor(kind: string): boolean {
|
|
114
|
+
return documentContributionForKind(kind) !== undefined;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Open (or activate) the document for one table entry in the editor
|
|
119
|
+
* registered for its kind. `false` (opens nothing) when no contribution
|
|
120
|
+
* declares that kind — the caller decides what an unedited kind opens as.
|
|
121
|
+
*/
|
|
122
|
+
export function openKindDocument(
|
|
123
|
+
entry: DocumentEntry,
|
|
124
|
+
options: OpenWorkspaceDocumentOptions = {},
|
|
125
|
+
): boolean {
|
|
126
|
+
const contribution = documentContributionForKind(entry.kind);
|
|
127
|
+
if (!contribution) return false;
|
|
128
|
+
const id = kindDocumentId(entry.id);
|
|
129
|
+
entries.set(id, { entry, props: asToolDocumentEntry(entry) });
|
|
130
|
+
openWorkspaceDocument(
|
|
131
|
+
{
|
|
132
|
+
id,
|
|
133
|
+
// The tab is the THING: the entry's own label, never the editor's name.
|
|
134
|
+
title: entry.label,
|
|
135
|
+
kind: 'document',
|
|
136
|
+
workspaceRole: 'authored-subject',
|
|
137
|
+
provenance: {
|
|
138
|
+
...(entry.source ? { sourcePath: entry.source.path } : {}),
|
|
139
|
+
origin: contribution.file,
|
|
140
|
+
},
|
|
141
|
+
Content: KindDocumentContent,
|
|
142
|
+
...(contribution.Toolbar ? { Toolbar: KindDocumentToolbar } : {}),
|
|
143
|
+
...(contribution.Shelf ? { Shelf: KindDocumentShelf } : {}),
|
|
144
|
+
presentation: () => ({ kind: 'document', id: entry.id }),
|
|
145
|
+
persist: () => ({ entryId: entry.id }),
|
|
146
|
+
onDispose: (documentId) => {
|
|
147
|
+
entries.delete(documentId);
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
options,
|
|
151
|
+
);
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* THE `document` ADDRESS (`document-open-registry.ts`) — the other half of the
|
|
157
|
+
* `presentation()` above. An entry's id is the whole address; which editor
|
|
158
|
+
* opens it, and what that document's id turns out to be, are this module's
|
|
159
|
+
* rules and the presenter no longer holds either. Registered at module load,
|
|
160
|
+
* the shape `packages/editor-game/src/three/story-documents/three-story-documents.tsx:239`
|
|
161
|
+
* uses.
|
|
162
|
+
*
|
|
163
|
+
* SETTLING is the two waits an explicit address needs, and they are separate
|
|
164
|
+
* because they fail differently. The TABLE resolves more than once — a
|
|
165
|
+
* contributed finder (the mesh capability's models finder) registers after the
|
|
166
|
+
* first resolution and brings its entries — so a missing entry is not yet an
|
|
167
|
+
* answer; and a kind's EDITOR arrives with the contribution pass, which on a
|
|
168
|
+
* cold reload is well past the default window. Each refuses in its own words:
|
|
169
|
+
* a table that lists no such document is a different defect from a kind
|
|
170
|
+
* nothing can edit, and only this module can tell them apart.
|
|
171
|
+
*/
|
|
172
|
+
registerDocumentOpener<{ readonly id: string }>({
|
|
173
|
+
id: 'document',
|
|
174
|
+
owner: 'kind-documents',
|
|
175
|
+
open: (_store, request) => {
|
|
176
|
+
const entry = tableEntry(request.id);
|
|
177
|
+
if (!entry || !hasKindEditor(entry.kind)) return null;
|
|
178
|
+
return openKindDocument(entry) ? kindDocumentId(entry.id) : null;
|
|
179
|
+
},
|
|
180
|
+
settle: async (request) => {
|
|
181
|
+
const REGISTRATION_WINDOW_MS = 20_000;
|
|
182
|
+
await waitUntil(() => tableEntry(request.id) !== undefined, REGISTRATION_WINDOW_MS);
|
|
183
|
+
const entry = tableEntry(request.id);
|
|
184
|
+
if (!entry) throw new Error(`The project's document table lists no document: ${request.id}`);
|
|
185
|
+
if (await waitUntil(() => hasKindEditor(entry.kind), REGISTRATION_WINDOW_MS)) return;
|
|
186
|
+
throw new Error(
|
|
187
|
+
`No editor is registered for documents of kind '${entry.kind}' (${request.id})`,
|
|
188
|
+
);
|
|
189
|
+
},
|
|
190
|
+
/**
|
|
191
|
+
* THE KIND'S OWN READINESS — a contributed document is ready to be driven
|
|
192
|
+
* once its React root has committed and, if that root mounted a stage, once
|
|
193
|
+
* the stage has registered its Object3D session. The presenter used to hold
|
|
194
|
+
* this rule for this address by name (`editor-view-presentation.ts`'s
|
|
195
|
+
* `kind === 'tool' || 'asset'`); it belongs here, where the contribution the
|
|
196
|
+
* host mounted is what answers.
|
|
197
|
+
*/
|
|
198
|
+
ready: async (documentId) => {
|
|
199
|
+
await waitForContributedDocumentMount(documentId);
|
|
200
|
+
await awaitAnnouncedObject3DDocumentSession(documentId);
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
function tableEntry(id: string): DocumentEntry | undefined {
|
|
205
|
+
return projectAdapterFacet()?.scenes.entries.find((candidate) => candidate.id === id);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* `openKindDocument` once the kind's editor is registered — now, or when the
|
|
210
|
+
* contribution pass that brings it completes. A restored layout and a
|
|
211
|
+
* shared view both name a document before the project's contributions have
|
|
212
|
+
* loaded (measured 2026-09-05: the entry arrived, the editor had not, and
|
|
213
|
+
* the document opened nothing). Gives up when the project changes under it.
|
|
214
|
+
*/
|
|
215
|
+
export function openKindDocumentWhenReady(
|
|
216
|
+
entry: DocumentEntry,
|
|
217
|
+
options: OpenWorkspaceDocumentOptions = {},
|
|
218
|
+
): void {
|
|
219
|
+
if (openKindDocument(entry, options)) return;
|
|
220
|
+
const stop = subscribeToolContributions(() => {
|
|
221
|
+
if (openKindDocument(entry, options)) stop();
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** Open the kind document `documentId` names once its entry and editor exist,
|
|
226
|
+
* without taking focus — a tab the workbench restored asking for its content.
|
|
227
|
+
* False when the id is not a kind document's. */
|
|
228
|
+
export function reopenKindDocument(documentId: string): boolean {
|
|
229
|
+
const entryId = kindDocumentEntryId(documentId);
|
|
230
|
+
if (entryId === null) return false;
|
|
231
|
+
// Not `whenDocumentEntry`: a restored tab asks before the page has a project,
|
|
232
|
+
// and that helper reads the project's arrival as a switch and gives up.
|
|
233
|
+
const attempt = (): boolean => {
|
|
234
|
+
const entry = projectAdapterFacet()?.scenes.entries.find((candidate) => candidate.id === entryId);
|
|
235
|
+
if (!entry) return false;
|
|
236
|
+
openKindDocumentWhenReady(entry, { activate: false });
|
|
237
|
+
return true;
|
|
238
|
+
};
|
|
239
|
+
if (!attempt()) {
|
|
240
|
+
const stop = subscribeProjectAdapter(() => {
|
|
241
|
+
if (attempt()) stop();
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/** Every open kind document takes its slots afresh when contributions
|
|
248
|
+
* change (a module re-evaluated on save may have gained or lost its
|
|
249
|
+
* `Toolbar`); `openWorkspaceDocument` on an open id refreshes the descriptor. */
|
|
250
|
+
export function installKindDocumentRefresh(): () => void {
|
|
251
|
+
return subscribeToolContributions(() => {
|
|
252
|
+
const open = new Set(openWorkspaceDocuments().map((d) => d.descriptor.id));
|
|
253
|
+
for (const [id, { entry }] of entries) {
|
|
254
|
+
if (!open.has(id)) continue;
|
|
255
|
+
if (documentContributionForKind(entry.kind))
|
|
256
|
+
openKindDocument(entry, { activate: false });
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// --- Restore, and what this kind does when a project opens ----------------
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Run `fn` with the table entry `entryId` names once the adapter's table
|
|
265
|
+
* lists it — now, or on the adapter change that brings it. A table resolves
|
|
266
|
+
* MORE THAN ONCE: a contributed finder (the mesh capability's models finder)
|
|
267
|
+
* registers after the first resolution and the table is resolved again with
|
|
268
|
+
* its entries, so "not pending" is not "complete" (measured 2026-09-05: a
|
|
269
|
+
* model document restored on the first resolution found no entry). Stops
|
|
270
|
+
* waiting when the project changes under it.
|
|
271
|
+
*/
|
|
272
|
+
function whenDocumentEntry(entryId: string, fn: (entry: DocumentEntry) => void): void {
|
|
273
|
+
const project = getCurrentProject();
|
|
274
|
+
const attempt = (): boolean => {
|
|
275
|
+
if (getCurrentProject() !== project) return true;
|
|
276
|
+
const facet = projectAdapterFacet();
|
|
277
|
+
if (!facet) return false;
|
|
278
|
+
const entry = facet.scenes.entries.find((candidate) => candidate.id === entryId);
|
|
279
|
+
if (!entry) return false;
|
|
280
|
+
fn(entry);
|
|
281
|
+
return true;
|
|
282
|
+
};
|
|
283
|
+
if (attempt()) return;
|
|
284
|
+
const stop = subscribeProjectAdapter(() => {
|
|
285
|
+
if (attempt()) stop();
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** The table entry a fresh checkout opens on: the declared default when it
|
|
290
|
+
* is a document with a source (and not a scene, which is pinned elsewhere),
|
|
291
|
+
* else the NEWEST such entry — the table lists finder sources newest first,
|
|
292
|
+
* so with several models and nothing declared the one most recently written
|
|
293
|
+
* is the one on screen (Photoshop reopens the last document; a models
|
|
294
|
+
* project with two models and no record used to open on nothing at all). */
|
|
295
|
+
function defaultTableEntry(table: ResolvedDocumentTable): DocumentEntry | null {
|
|
296
|
+
// An entry opens by its source file or by its kind's own editor: a models project with no
|
|
297
|
+
// `.blend` lists only the standing `blender:runtime` entry, which has no file and is still
|
|
298
|
+
// the thing to open.
|
|
299
|
+
const candidates = table.entries.filter(
|
|
300
|
+
(entry) =>
|
|
301
|
+
entry.kind !== 'scene' &&
|
|
302
|
+
entry.kind !== 'prefab' &&
|
|
303
|
+
(entry.source !== undefined || documentContributionForKind(entry.kind) !== undefined),
|
|
304
|
+
);
|
|
305
|
+
const declared = candidates.find((entry) => entry.id === table.default);
|
|
306
|
+
if (declared) return declared;
|
|
307
|
+
return candidates[0] ?? null;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/** Discovery can fill an empty workspace, but it must not replace a document
|
|
311
|
+
* the person already has open. Adding or generating a file advertises it in
|
|
312
|
+
* Content; activating it remains an explicit document-open operation. */
|
|
313
|
+
let stopFollowingTableDocuments: (() => void) | null = null;
|
|
314
|
+
/** The follow rule's baseline, persisted as this kind's own session state. */
|
|
315
|
+
let seenTableIds: Set<string> | null = null;
|
|
316
|
+
/** Keep the discovery baseline across reloads so a new entry can fill an
|
|
317
|
+
* otherwise empty workspace once, without reopening existing entries. */
|
|
318
|
+
function followNewTableDocuments(seen?: readonly string[]): void {
|
|
319
|
+
stopFollowingTableDocuments?.();
|
|
320
|
+
let known: Set<string> | null = seen ? new Set(seen) : null;
|
|
321
|
+
const observe = (): void => {
|
|
322
|
+
const facet = projectAdapterFacet();
|
|
323
|
+
if (!facet || facet.documentsPending) return;
|
|
324
|
+
const ids = new Set(facet.scenes.entries.map((entry) => entry.id));
|
|
325
|
+
if (known === null) {
|
|
326
|
+
known = ids;
|
|
327
|
+
seenTableIds = ids;
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const entry = [...facet.scenes.entries]
|
|
331
|
+
.reverse()
|
|
332
|
+
.find(
|
|
333
|
+
(candidate) =>
|
|
334
|
+
!known?.has(candidate.id) &&
|
|
335
|
+
candidate.kind !== 'scene' &&
|
|
336
|
+
candidate.kind !== 'prefab' &&
|
|
337
|
+
candidate.source &&
|
|
338
|
+
hasKindEditor(candidate.kind),
|
|
339
|
+
);
|
|
340
|
+
// Advance before opening: document activation can publish the table again.
|
|
341
|
+
known = ids;
|
|
342
|
+
seenTableIds = ids;
|
|
343
|
+
if (openWorkspaceDocuments().some((document) => !document.descriptor.area)) return;
|
|
344
|
+
if (entry?.source && openKindDocument(entry, { activate: true, preview: true })) {
|
|
345
|
+
setSelectedAsset({
|
|
346
|
+
path: `/${entry.source.path}`,
|
|
347
|
+
name: entry.label,
|
|
348
|
+
kind: 'source',
|
|
349
|
+
capabilities: assetCapabilities(entry.source.path),
|
|
350
|
+
origin: 'project',
|
|
351
|
+
health: 'healthy',
|
|
352
|
+
selectionCount: 1,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
observe();
|
|
357
|
+
stopFollowingTableDocuments = subscribeProjectAdapter(observe);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* A RECORD WHOSE FILES ARE ALL GONE opens the project's default, not nothing: a models project
|
|
362
|
+
* whose only `.blend` was deleted between sessions would otherwise sit on an empty workspace
|
|
363
|
+
* (on Cyclotron, the cover's 90 s refusal). Decided once, for the whole record, and only
|
|
364
|
+
* on a table that loaded cleanly for this project — a failed or partial load lists nothing and
|
|
365
|
+
* proves nothing gone.
|
|
366
|
+
*/
|
|
367
|
+
function openDefaultWhenRestoresAreGone(entryIds: readonly string[]): void {
|
|
368
|
+
const project = getCurrentProject();
|
|
369
|
+
const attempt = (): boolean => {
|
|
370
|
+
if (getCurrentProject() !== project) return true;
|
|
371
|
+
const facet = projectAdapterFacet();
|
|
372
|
+
if (!facet || facet.documentsPending || facet.error !== null) return false;
|
|
373
|
+
if (facet.scenes.entries.some((entry) => entryIds.includes(entry.id))) return true;
|
|
374
|
+
openDefaultTableDocument();
|
|
375
|
+
return true;
|
|
376
|
+
};
|
|
377
|
+
if (attempt()) return;
|
|
378
|
+
const stop = subscribeProjectAdapter(() => {
|
|
379
|
+
if (attempt()) stop();
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function openDefaultTableDocument(): void {
|
|
384
|
+
const project = getCurrentProject();
|
|
385
|
+
const attempt = (): boolean => {
|
|
386
|
+
if (getCurrentProject() !== project) return true;
|
|
387
|
+
const facet = projectAdapterFacet();
|
|
388
|
+
if (!facet || facet.documentsPending) return false;
|
|
389
|
+
// "SOMETHING IS ALREADY OPEN" MEANS A DOCUMENT A PERSON IS IN — never an
|
|
390
|
+
// AREA document. A workspace's own `areas` (the Model workspace's Timeline)
|
|
391
|
+
// open with the layout, before the adapter's table has settled, and they
|
|
392
|
+
// are never activatable (`workspace-document-registry.ts` gates activation
|
|
393
|
+
// on `!descriptor.area`). Counting one as "the session already has a
|
|
394
|
+
// document" is what left a fresh `--template models` scaffold under the
|
|
395
|
+
// Code-OSS frame with "No document open yet (0 registered)" and the cube
|
|
396
|
+
// never opened — measured 2026-09-20, walk 3 beat 2: the table held
|
|
397
|
+
// `model:src/models/cube.blend` while `open` held only the timeline.
|
|
398
|
+
if (openWorkspaceDocuments().some((document) => !document.descriptor.area)) return true;
|
|
399
|
+
const entry = defaultTableEntry(facet.scenes);
|
|
400
|
+
// A non-scene entry nothing can open YET (its kind's editor registers after the first
|
|
401
|
+
// table) is waited for: the table resolves again when the contributions land.
|
|
402
|
+
if (!entry) return !facet.scenes.entries.some((one) => one.kind !== 'scene' && one.kind !== 'prefab');
|
|
403
|
+
if (!entry.source) {
|
|
404
|
+
// No file: only its kind's editor opens it.
|
|
405
|
+
openKindDocument(entry);
|
|
406
|
+
return true;
|
|
407
|
+
}
|
|
408
|
+
{
|
|
409
|
+
const path = `/${entry.source.path}`;
|
|
410
|
+
// The kind's own editor when one is registered (a model opens as a
|
|
411
|
+
// model); the source only for a kind nothing edits.
|
|
412
|
+
if (!openKindDocument(entry)) {
|
|
413
|
+
openAssetDocument(path, uneditedKindAssetKind(entry));
|
|
414
|
+
}
|
|
415
|
+
// Opened AND selected, the way a Content click leaves it: the kind's
|
|
416
|
+
// own asset inspector (a model's Edit mesh door) is the first thing
|
|
417
|
+
// the Inspector shows.
|
|
418
|
+
setSelectedAsset({
|
|
419
|
+
path,
|
|
420
|
+
name: entry.label,
|
|
421
|
+
kind: 'source',
|
|
422
|
+
capabilities: assetCapabilities(entry.source.path),
|
|
423
|
+
origin: 'project',
|
|
424
|
+
health: 'healthy',
|
|
425
|
+
selectionCount: 1,
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
return true;
|
|
429
|
+
};
|
|
430
|
+
if (attempt()) return;
|
|
431
|
+
const stop = subscribeProjectAdapter(() => {
|
|
432
|
+
if (attempt()) stop();
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
registerWorkspaceDocumentRestorer({
|
|
437
|
+
kind: 'document',
|
|
438
|
+
owner: 'kind-documents',
|
|
439
|
+
// The table resolves asynchronously; an entry that is gone (or a kind whose
|
|
440
|
+
// editor is gone) reopens nothing, like a deleted tool. It also resolves
|
|
441
|
+
// AFTER the restore loop has ended and the stored active id has been asked
|
|
442
|
+
// for, so a kind document that was the active tab must activate ITSELF as
|
|
443
|
+
// it reopens — or the page lands on whichever sibling resolved first (a
|
|
444
|
+
// session reloaded onto the starter cube while its mushroom was the tab in
|
|
445
|
+
// use, 2026-09-06).
|
|
446
|
+
restore: ({ state, active }) => {
|
|
447
|
+
const record = state as { entryId?: unknown } | null | undefined;
|
|
448
|
+
const entryId = typeof record?.entryId === 'string' ? record.entryId : null;
|
|
449
|
+
if (!entryId) return false;
|
|
450
|
+
whenDocumentEntry(entryId, (entry) => {
|
|
451
|
+
openKindDocumentWhenReady(entry, { activate: active });
|
|
452
|
+
});
|
|
453
|
+
return true;
|
|
454
|
+
},
|
|
455
|
+
persistKindState: () => (seenTableIds ? { seen: [...seenTableIds] } : undefined),
|
|
456
|
+
beginRestore: ({ state, hasDocumentsToRestore, documentsToRestore }) => {
|
|
457
|
+
const record = state as { seen?: unknown } | null | undefined;
|
|
458
|
+
const seen = Array.isArray(record?.seen)
|
|
459
|
+
? record.seen.filter((id): id is string => typeof id === 'string')
|
|
460
|
+
: undefined;
|
|
461
|
+
// A SESSION WITH NOTHING TO RESTORE opens on the project's own DEFAULT
|
|
462
|
+
// document — what the adapter table declares (or its one non-scene
|
|
463
|
+
// entry): a models project opens its model, a website its page. Scenes
|
|
464
|
+
// have their pinned door (`CenterDocuments`) and are not this one's
|
|
465
|
+
// business.
|
|
466
|
+
//
|
|
467
|
+
// This used to read `!hasRecord`, and "a project that recorded 'nothing
|
|
468
|
+
// open' keeps nothing open" stood beside it as if it were a decision. It
|
|
469
|
+
// was a hole: closing the last document writes `open: []`, and every boot
|
|
470
|
+
// after that restored nothing and opened nothing (walk 5 beat 0 —
|
|
471
|
+
// measured on a `cyclotron create` scaffold, where the product's cover
|
|
472
|
+
// then sat out its 90 s budget and blamed Blender for a model nobody had
|
|
473
|
+
// asked it to open).
|
|
474
|
+
if (!hasDocumentsToRestore) openDefaultTableDocument();
|
|
475
|
+
else {
|
|
476
|
+
// Only when the whole record is this kind's: another kind's document may be coming back.
|
|
477
|
+
const entryIds = documentsToRestore.map((doc) =>
|
|
478
|
+
doc.kind === 'document' ? (doc.state as { entryId?: unknown } | null)?.entryId : undefined,
|
|
479
|
+
);
|
|
480
|
+
if (entryIds.every((id): id is string => typeof id === 'string')) {
|
|
481
|
+
openDefaultWhenRestoresAreGone(entryIds);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
followNewTableDocuments(seen);
|
|
485
|
+
},
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
function useContribution(documentId: string) {
|
|
489
|
+
useSyncExternalStore(subscribeToolContributions, getGlobalToolContributions);
|
|
490
|
+
const entry = entries.get(documentId)?.props;
|
|
491
|
+
return { entry, contribution: entry ? documentContributionForKind(entry.kind) : undefined };
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
export function KindDocumentToolbar({ documentId, active }: WorkspaceDocumentContentProps) {
|
|
495
|
+
const { entry, contribution } = useContribution(documentId);
|
|
496
|
+
if (!entry || !contribution?.Toolbar) return null;
|
|
497
|
+
return (
|
|
498
|
+
<ToolHost
|
|
499
|
+
key={`${contribution.id}:${contribution.version}:toolbar:${documentId}`}
|
|
500
|
+
contribution={contribution}
|
|
501
|
+
Component={contribution.Toolbar as unknown as ComponentType<Record<string, unknown>>}
|
|
502
|
+
documentId={documentId}
|
|
503
|
+
active={active}
|
|
504
|
+
document={entry}
|
|
505
|
+
/>
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
export function KindDocumentShelf({ documentId, active }: WorkspaceDocumentContentProps) {
|
|
510
|
+
const { entry, contribution } = useContribution(documentId);
|
|
511
|
+
if (!entry || !contribution?.Shelf) return null;
|
|
512
|
+
return (
|
|
513
|
+
<ToolHost
|
|
514
|
+
key={`${contribution.id}:${contribution.version}:shelf:${documentId}`}
|
|
515
|
+
contribution={contribution}
|
|
516
|
+
Component={contribution.Shelf as unknown as ComponentType<Record<string, unknown>>}
|
|
517
|
+
documentId={documentId}
|
|
518
|
+
active={active}
|
|
519
|
+
document={entry}
|
|
520
|
+
/>
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
export function KindDocumentContent({ documentId, active }: WorkspaceDocumentContentProps) {
|
|
525
|
+
const { entry, contribution } = useContribution(documentId);
|
|
526
|
+
if (!entry || !contribution) {
|
|
527
|
+
return (
|
|
528
|
+
<div
|
|
529
|
+
style={{ padding: 12, fontSize: 12, color: themeVars.content.muted, pointerEvents: 'auto' }}
|
|
530
|
+
>
|
|
531
|
+
No editor is registered for this document's kind — close this document.
|
|
532
|
+
</div>
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
return (
|
|
536
|
+
<ToolHost
|
|
537
|
+
key={`${contribution.id}:${contribution.version}:${documentId}`}
|
|
538
|
+
contribution={contribution}
|
|
539
|
+
documentId={documentId}
|
|
540
|
+
active={active}
|
|
541
|
+
document={entry}
|
|
542
|
+
/>
|
|
543
|
+
);
|
|
544
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A colour swatch whose picking is LOCAL until the pick is COMMITTED — the
|
|
3
|
+
* discipline {@link DraftTextInput} applies to every Inspector row whose
|
|
4
|
+
* `onChange` is a SOURCE WRITE, for the one control that could not use it.
|
|
5
|
+
*
|
|
6
|
+
* WHY. A native `<input type="color">` fires `input` continuously while the
|
|
7
|
+
* user drags inside the picker, and React's `onChange` maps to that event. The
|
|
8
|
+
* Inspector's colour row wrote SOURCE per event, so one colour pick queued a
|
|
9
|
+
* burst of writes and remounts: the field re-rendered from the old source
|
|
10
|
+
* value under the picker, the last write carried the pre-edit colour, and the
|
|
11
|
+
* refusal that followed marked the path dynamic — which greys the swatch until
|
|
12
|
+
* the next remount. Two human passes reported it the same way ("the colour
|
|
13
|
+
* changes just once, then I can't select colour again"; "change the colour to
|
|
14
|
+
* red — that did not work").
|
|
15
|
+
*
|
|
16
|
+
* The native `change` event is the pick's own commit (fired when the picker
|
|
17
|
+
* closes, and immediately for a programmatic set), so it is what writes. While
|
|
18
|
+
* the picker is open the swatch shows the draft; when it is not being edited
|
|
19
|
+
* the swatch tracks the live value, so an external change still shows.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { ColorSwatchInput } from '@volter/sdk/widgets';
|
|
23
|
+
import { type InputHTMLAttributes, useEffect, useRef, useState } from 'react';
|
|
24
|
+
|
|
25
|
+
export interface DraftColorInputProps
|
|
26
|
+
extends Omit<InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange'> {
|
|
27
|
+
/** The live value, shown whenever the swatch is not being picked. */
|
|
28
|
+
readonly value: string;
|
|
29
|
+
/** Fires ONCE per committed pick, with the final colour. Not called when
|
|
30
|
+
* the colour is unchanged. */
|
|
31
|
+
readonly onCommit: (next: string) => void;
|
|
32
|
+
/** Fires on EVERY value the picker streams while it is open, so the viewport
|
|
33
|
+
* follows the pointer. Live-only: the commit above is what persists. */
|
|
34
|
+
readonly onPreview?: (next: string) => void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function DraftColorInput({ value, onCommit, onPreview, ...rest }: DraftColorInputProps) {
|
|
38
|
+
const [draft, setDraft] = useState<string | null>(null);
|
|
39
|
+
const element = useRef<HTMLInputElement | null>(null);
|
|
40
|
+
// The value this pick STARTED from. A live preview makes `value` follow the
|
|
41
|
+
// draft (the object really is that colour now), so comparing the commit
|
|
42
|
+
// against `value` would find nothing changed and never persist — the commit
|
|
43
|
+
// must be measured against where the pick began.
|
|
44
|
+
const startValue = useRef<string | null>(null);
|
|
45
|
+
// The commit event is NATIVE `change`; React's onChange is the `input`
|
|
46
|
+
// stream, so this listener cannot be expressed as a prop.
|
|
47
|
+
const latest = useRef({ draft, onCommit });
|
|
48
|
+
latest.current = { draft, onCommit };
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
const node = element.current;
|
|
51
|
+
if (!node) return;
|
|
52
|
+
const commit = (): void => {
|
|
53
|
+
const { draft: picked, onCommit: commitTo } = latest.current;
|
|
54
|
+
const next = picked ?? node.value;
|
|
55
|
+
if (next && next !== startValue.current) commitTo(next);
|
|
56
|
+
startValue.current = null;
|
|
57
|
+
setDraft(null);
|
|
58
|
+
};
|
|
59
|
+
node.addEventListener('change', commit);
|
|
60
|
+
return () => node.removeEventListener('change', commit);
|
|
61
|
+
}, []);
|
|
62
|
+
return (
|
|
63
|
+
<ColorSwatchInput
|
|
64
|
+
{...rest}
|
|
65
|
+
ref={element}
|
|
66
|
+
value={draft ?? value}
|
|
67
|
+
onChange={(event) => {
|
|
68
|
+
if (startValue.current === null) startValue.current = value;
|
|
69
|
+
setDraft(event.target.value);
|
|
70
|
+
onPreview?.(event.target.value);
|
|
71
|
+
}}
|
|
72
|
+
/>
|
|
73
|
+
);
|
|
74
|
+
}
|