@volter/editor-core 0.5.57
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/BUNDLED_NOTICES +1527 -0
- package/LICENSE +686 -0
- package/LICENSE-APACHE +202 -0
- package/NOTICE +18 -0
- package/README.md +24 -0
- package/dist/build/chunk-JS4D4XZ3.js +175 -0
- package/dist/build/chunk-JS4D4XZ3.js.map +7 -0
- package/dist/build/vite-plugin-product-contributions.js +100 -0
- package/dist/build/vite-plugin-product-contributions.js.map +7 -0
- package/dist/build/vite-plugin-shared-react.js +25 -0
- package/dist/build/vite-plugin-shared-react.js.map +7 -0
- package/dist/build/vite-plugin-shared-three.js +86 -0
- package/dist/build/vite-plugin-shared-three.js.map +7 -0
- package/dist/server/chunk-KMJC7AGO.js +98 -0
- package/dist/server/chunk-KMJC7AGO.js.map +7 -0
- package/dist/server/chunk-PSILUMGS.js +46 -0
- package/dist/server/chunk-PSILUMGS.js.map +7 -0
- package/dist/server/frame-proxy.js +255 -0
- package/dist/server/frame-proxy.js.map +7 -0
- package/dist/server/open-browser.js +53 -0
- package/dist/server/open-browser.js.map +7 -0
- package/dist/server/process-shutdown.js +127 -0
- package/dist/server/process-shutdown.js.map +7 -0
- package/dist/server/session-registry.js +141 -0
- package/dist/server/session-registry.js.map +7 -0
- package/dist/server/spawn-opener.js +11 -0
- package/dist/server/spawn-opener.js.map +7 -0
- package/dist/server/worktree-identity.js +11 -0
- package/dist/server/worktree-identity.js.map +7 -0
- package/dist-server/packaged.mjs +88816 -0
- package/package.json +118 -0
- package/scripts/build-plugins.mjs +14 -0
- package/scripts/build-server.mjs +26 -0
- package/scripts/build-session.mjs +9 -0
- package/server/account-credentials.ts +60 -0
- package/server/account-service.ts +1434 -0
- package/server/adapter-region-includes.ts +47 -0
- package/server/asset-catalog-v2.ts +175 -0
- package/server/asset-history-snapshots.ts +196 -0
- package/server/asset-ledger-store.ts +195 -0
- package/server/asset-library-routes.ts +1595 -0
- package/server/blender-wasm-artifact.ts +430 -0
- package/server/boot-timings.ts +106 -0
- package/server/canonical-path.ts +50 -0
- package/server/checkout-workspace-preflight.ts +349 -0
- package/server/cloud-asset-catalog.ts +158 -0
- package/server/coding-inference-launch.ts +237 -0
- package/server/collaboration-account-client.ts +202 -0
- package/server/collaboration-attribution.ts +122 -0
- package/server/collaboration-session.ts +934 -0
- package/server/comfyui-bridge.ts +248 -0
- package/server/console-ledger.ts +499 -0
- package/server/creation-site-transform.ts +304 -0
- package/server/creation-site-write.ts +648 -0
- package/server/data-file-serialize.ts +158 -0
- package/server/editor-brand-html.ts +72 -0
- package/server/editor-control-socket.ts +366 -0
- package/server/editor-server-options.ts +190 -0
- package/server/editor-server.ts +1483 -0
- package/server/editor-sse.ts +352 -0
- package/server/engine-provenance.ts +169 -0
- package/server/engine-source-restart.ts +117 -0
- package/server/frame-bridge.ts +115 -0
- package/server/frame-proxy.ts +490 -0
- package/server/frame-workbench.ts +259 -0
- package/server/frontend-handoff.ts +229 -0
- package/server/game-globals-shadow.ts +113 -0
- package/server/gameplay-session-retention.ts +149 -0
- package/server/gameplay-sessions.ts +123 -0
- package/server/generation-jobs.ts +201 -0
- package/server/generation-reconciler.ts +137 -0
- package/server/generative-execution-context.ts +59 -0
- package/server/git-workflow.ts +612 -0
- package/server/harness-chat-caller.ts +36 -0
- package/server/harness-chat-service.ts +1681 -0
- package/server/idle-shutdown.ts +170 -0
- package/server/js-profiling-policy.ts +52 -0
- package/server/launcher-settings.ts +84 -0
- package/server/local-asset-catalog.ts +410 -0
- package/server/managed-account-defaults.ts +22 -0
- package/server/mock-control-plane.ts +540 -0
- package/server/model-import-conversion.ts +345 -0
- package/server/native-credential-store.ts +162 -0
- package/server/open-browser.ts +118 -0
- package/server/packaged.ts +1192 -0
- package/server/play-stall.ts +126 -0
- package/server/process-shutdown.ts +218 -0
- package/server/product-presets.ts +55 -0
- package/server/project-build-artifact.ts +95 -0
- package/server/project-components.ts +100 -0
- package/server/project-dependency-invalidation.ts +114 -0
- package/server/project-file-scan.ts +235 -0
- package/server/project-hmr-files.ts +215 -0
- package/server/project-install-roots.ts +210 -0
- package/server/project-kinds.ts +71 -0
- package/server/project-mcp-servers.ts +82 -0
- package/server/project-module-freshness.ts +109 -0
- package/server/project-module-instance.ts +375 -0
- package/server/project-optimize-deps-entries.ts +827 -0
- package/server/project-output-writer.ts +679 -0
- package/server/project-package-origin.ts +63 -0
- package/server/project-root-surface.ts +831 -0
- package/server/project-scratch-path.ts +47 -0
- package/server/project-script-hmr.ts +619 -0
- package/server/project-serving-plugins.ts +236 -0
- package/server/project-tools.ts +653 -0
- package/server/project-validation.ts +250 -0
- package/server/project-verbs.ts +127 -0
- package/server/project-view.ts +52 -0
- package/server/project-watch.ts +1134 -0
- package/server/project-work-coordinator.ts +288 -0
- package/server/provider-credentials.ts +331 -0
- package/server/recent-projects-store.ts +98 -0
- package/server/redact-secrets.ts +71 -0
- package/server/repository-presence.ts +267 -0
- package/server/routes/account.ts +357 -0
- package/server/routes/agents.ts +60 -0
- package/server/routes/assets.ts +154 -0
- package/server/routes/build.ts +13 -0
- package/server/routes/collaboration.ts +595 -0
- package/server/routes/configurations.ts +419 -0
- package/server/routes/context.ts +264 -0
- package/server/routes/control-plane.ts +1811 -0
- package/server/routes/logs.ts +272 -0
- package/server/routes/project-identity.ts +302 -0
- package/server/routes/project-open.ts +429 -0
- package/server/routes/project-source.ts +686 -0
- package/server/routes/project-state.ts +383 -0
- package/server/routes/relay.ts +1029 -0
- package/server/routes/route-helpers.ts +29 -0
- package/server/routes/served-modules.ts +138 -0
- package/server/routes/session-tabs.ts +196 -0
- package/server/routes/settings.ts +121 -0
- package/server/routes/share-control.ts +486 -0
- package/server/routes/themes.ts +116 -0
- package/server/routes/tools.ts +230 -0
- package/server/routes/worktrees.ts +595 -0
- package/server/scoped-game-css.ts +461 -0
- package/server/server-utils.ts +1194 -0
- package/server/session-product.ts +112 -0
- package/server/session-registry.ts +230 -0
- package/server/share-claims.ts +138 -0
- package/server/share-host.ts +526 -0
- package/server/share-session-gateway.ts +1362 -0
- package/server/share-tunnel.ts +123 -0
- package/server/spawn-opener.ts +74 -0
- package/server/support/play/log-format.ts +76 -0
- package/server/support/play/session-record.ts +199 -0
- package/server/support/project/build-discipline.ts +718 -0
- package/server/support/project/inspection-node.ts +119 -0
- package/server/support/project/log-naming.ts +54 -0
- package/server/support/project/provenance.ts +290 -0
- package/server/support/project/run-name.ts +18 -0
- package/server/support/project/session-journal.ts +830 -0
- package/server/support/project/shared.ts +327 -0
- package/server/tab-bootstrap.ts +62 -0
- package/server/tab-heartbeat.ts +477 -0
- package/server/tab-lifecycle.ts +550 -0
- package/server/tab-presence.ts +1508 -0
- package/server/team-agent-mirror.ts +95 -0
- package/server/twin-auth.ts +138 -0
- package/server/vendored-lock-recorder.ts +968 -0
- package/server/worktree-identity.ts +121 -0
- package/server/worktree-management.ts +398 -0
- package/server/worktree-retention.d.mts +13 -0
- package/server/worktree-retention.mjs +205 -0
- package/src/EditorContext.tsx +169 -0
- package/src/account.ts +333 -0
- package/src/action-registry.ts +532 -0
- package/src/active-product.ts +74 -0
- package/src/active-project.ts +155 -0
- package/src/adapter-editor-config.ts +25 -0
- package/src/adapter-observation.ts +49 -0
- package/src/animation/stage-transport.ts +379 -0
- package/src/animation/three-clips-subject.ts +172 -0
- package/src/api/asset-library-wire.ts +45 -0
- package/src/api/assets.ts +365 -0
- package/src/api/base.ts +10 -0
- package/src/api/build.ts +99 -0
- package/src/api/git-wire.ts +56 -0
- package/src/api/logs.ts +92 -0
- package/src/api/project-identity.ts +74 -0
- package/src/api/project-open.ts +355 -0
- package/src/api/project-source.ts +162 -0
- package/src/api/project-state.ts +107 -0
- package/src/api/relay.ts +268 -0
- package/src/api/settings.ts +36 -0
- package/src/api/themes.ts +45 -0
- package/src/api/worktrees.ts +257 -0
- package/src/asset-compare-core.ts +171 -0
- package/src/asset-compare.ts +294 -0
- package/src/asset-editor-context.tsx +100 -0
- package/src/asset-events.ts +97 -0
- package/src/asset-inspector-actions.ts +87 -0
- package/src/asset-preview-framing.ts +357 -0
- package/src/asset-preview.ts +2802 -0
- package/src/asset-selection-viewer-registry.ts +113 -0
- package/src/asset-selection.ts +133 -0
- package/src/asset-workflow/asset-capabilities.ts +344 -0
- package/src/asset-workflow/asset-import-jobs.ts +106 -0
- package/src/asset-workflow/asset-ledger-backend.ts +126 -0
- package/src/asset-workflow/asset-ledger.ts +156 -0
- package/src/asset-workflow/asset-materialization-report.ts +140 -0
- package/src/asset-workflow/asset-pack-manifest.ts +320 -0
- package/src/asset-workflow/asset-types.ts +142 -0
- package/src/asset-workflow/asset-workflow-quality.ts +61 -0
- package/src/asset-workflow/audio-preview-player.ts +193 -0
- package/src/asset-workflow/audio-waveform.ts +22 -0
- package/src/asset-workflow/cloud-asset-client.ts +263 -0
- package/src/asset-workflow/folder-preview.ts +345 -0
- package/src/asset-workflow/hosted-asset-materialization.ts +236 -0
- package/src/asset-workflow/image-view-scale.ts +32 -0
- package/src/asset-workflow/import-contract.ts +124 -0
- package/src/asset-workflow/ledger-write-lock.ts +244 -0
- package/src/asset-workflow/model-inspection.ts +818 -0
- package/src/asset-workflow/pixi-spritesheet.ts +197 -0
- package/src/asset-workflow/preview-resource-lifetime.ts +44 -0
- package/src/asset-workflow/project-asset-commands.ts +23 -0
- package/src/asset-workflow/project-asset-health.ts +139 -0
- package/src/asset-workflow/project-asset-operations.ts +154 -0
- package/src/asset-workflow/project-asset-roots.ts +68 -0
- package/src/asset-workflow/project-content.ts +288 -0
- package/src/asset-workflow/project-source-index.ts +550 -0
- package/src/asset-workflow/thumbnail-system.ts +256 -0
- package/src/authoring/active-adapter.ts +199 -0
- package/src/authoring/active-systems.ts +422 -0
- package/src/authoring/adapter-key.ts +18 -0
- package/src/authoring/authoring-asset-url.ts +27 -0
- package/src/authoring/bootstrap-state.ts +49 -0
- package/src/authoring/boundary-authoring-adapter.ts +184 -0
- package/src/authoring/breakpoint-state.ts +43 -0
- package/src/authoring/canvas-scene-guides.ts +76 -0
- package/src/authoring/component-instance-root.ts +171 -0
- package/src/authoring/composite-authoring-adapter.ts +2110 -0
- package/src/authoring/consumer-actions.ts +520 -0
- package/src/authoring/css-numeric-style.ts +97 -0
- package/src/authoring/design-time-layers.ts +849 -0
- package/src/authoring/design-time-mount-registry.ts +235 -0
- package/src/authoring/design-time-settle.ts +343 -0
- package/src/authoring/edit-mode-authoring.ts +619 -0
- package/src/authoring/eyedropper-session.ts +60 -0
- package/src/authoring/instance-source-menu-register.ts +13 -0
- package/src/authoring/instance-source-menu.ts +135 -0
- package/src/authoring/layered-pick.ts +183 -0
- package/src/authoring/live-gesture-lock.ts +50 -0
- package/src/authoring/live-object-transform.ts +62 -0
- package/src/authoring/mount-failure-report.ts +154 -0
- package/src/authoring/mounted-root-subjects.ts +144 -0
- package/src/authoring/no-authoring-adapter.ts +55 -0
- package/src/authoring/null-inspection-subjects.tsx +75 -0
- package/src/authoring/object3d-document-persistence.ts +106 -0
- package/src/authoring/object3d-document-session-registry.ts +120 -0
- package/src/authoring/object3d-document-session.ts +1326 -0
- package/src/authoring/object3d-gesture-controller.ts +113 -0
- package/src/authoring/panel-authoring.ts +121 -0
- package/src/authoring/prefab-instance-inspector-section.tsx +237 -0
- package/src/authoring/prefab-instance-section-model.ts +55 -0
- package/src/authoring/project-authoring-session.ts +105 -0
- package/src/authoring/provenance.ts +99 -0
- package/src/authoring/quarks-particle-systems.ts +19 -0
- package/src/authoring/react-canvas-navigation.ts +255 -0
- package/src/authoring/react-design-canvas-style.ts +20 -0
- package/src/authoring/react-story-board.ts +937 -0
- package/src/authoring/selection-scope.ts +195 -0
- package/src/authoring/shell-document-ops.ts +169 -0
- package/src/authoring/shell-object3d-document-write-policy.ts +108 -0
- package/src/authoring/shell-viewport-policy.ts +48 -0
- package/src/authoring/source-object3d-authoring-adapter.ts +526 -0
- package/src/authoring/stories-scope.ts +35 -0
- package/src/authoring/story-board-chrome-fit.ts +107 -0
- package/src/authoring/story-board-presentation.ts +111 -0
- package/src/authoring/three-projection-core.ts +226 -0
- package/src/authoring/viewport-pick-context.ts +40 -0
- package/src/authoring/viewport-raycast.ts +240 -0
- package/src/authoring/viewport-tool-context.ts +73 -0
- package/src/authoring/world-canvas-viewport-state.ts +35 -0
- package/src/authoring/world-hidden-viewport.ts +152 -0
- package/src/authoring/world-pan-state.ts +198 -0
- package/src/authoring/world-session-state.ts +101 -0
- package/src/authoring/write-pipe.ts +173 -0
- package/src/availability-tick.ts +66 -0
- package/src/bitmap-label.ts +120 -0
- package/src/blender-tab-metrics.ts +161 -0
- package/src/board-open-actions.ts +20 -0
- package/src/boot-routing.ts +391 -0
- package/src/build-identity.ts +15 -0
- package/src/bytes-codec.ts +62 -0
- package/src/camera-authoring.ts +175 -0
- package/src/cancellation-reason.ts +58 -0
- package/src/canvas-preview-frames.ts +482 -0
- package/src/capture-camera-pose.ts +77 -0
- package/src/chrome-registry.ts +159 -0
- package/src/chrome-slot-registry.ts +91 -0
- package/src/collaboration-client.ts +264 -0
- package/src/collaboration-presence.ts +41 -0
- package/src/command-dispatch.ts +19 -0
- package/src/command-listener.ts +2743 -0
- package/src/command-registry.ts +70 -0
- package/src/component-board-registry.ts +205 -0
- package/src/component-states-registry.ts +200 -0
- package/src/components/AgentPresentationNotice.tsx +75 -0
- package/src/components/AlignToolbar.tsx +204 -0
- package/src/components/AppRoot.tsx +394 -0
- package/src/components/ApplicationMenus.tsx +415 -0
- package/src/components/AssetBrowser.tsx +2843 -0
- package/src/components/AssetEditorShell.tsx +216 -0
- package/src/components/AssetInspectorToolSection.tsx +124 -0
- package/src/components/BoardRulers.tsx +354 -0
- package/src/components/CameraInfo.tsx +81 -0
- package/src/components/CanvasSceneViewport.tsx +556 -0
- package/src/components/CapabilityCoverageSection.tsx +185 -0
- package/src/components/CenterDocuments.tsx +22 -0
- package/src/components/ChromeSlot.tsx +20 -0
- package/src/components/CodeView.tsx +470 -0
- package/src/components/CollaborationHeaderControl.css +74 -0
- package/src/components/CompactInspectorCard.tsx +190 -0
- package/src/components/CompactInspectorShell.tsx +39 -0
- package/src/components/ConsolePanel.css +55 -0
- package/src/components/ConsolePanel.tsx +270 -0
- package/src/components/DefaultEditorLayout.tsx +106 -0
- package/src/components/DocumentHeaderStrip.tsx +96 -0
- package/src/components/DocumentShelfRail.tsx +45 -0
- package/src/components/DocumentThumbnail.tsx +345 -0
- package/src/components/EditorLeaseGuard.tsx +372 -0
- package/src/components/ErrorBanner.tsx +123 -0
- package/src/components/FolderPreviewTile.tsx +159 -0
- package/src/components/GameHierarchy.tsx +3842 -0
- package/src/components/GameplaySessionTimeline.tsx +295 -0
- package/src/components/InspectionProjection.tsx +968 -0
- package/src/components/Inspector.tsx +233 -0
- package/src/components/InspectorCanvasPreview.tsx +35 -0
- package/src/components/InspectorFieldsSection.tsx +290 -0
- package/src/components/InspectorObjectPreview.tsx +57 -0
- package/src/components/InspectorStoriesSection.tsx +92 -0
- package/src/components/InspectorToolSection.tsx +96 -0
- package/src/components/InspectorTransformSection.tsx +245 -0
- package/src/components/LightExplorerPanel.tsx +433 -0
- package/src/components/MediaProperties.tsx +145 -0
- package/src/components/NonThreeAuthoringBootstrap.tsx +19 -0
- package/src/components/Object3DDocumentToolbar.css +100 -0
- package/src/components/Object3DDocumentToolbar.tsx +454 -0
- package/src/components/Object3DDocumentViewport.tsx +58 -0
- package/src/components/ProjectHeader.css +617 -0
- package/src/components/ProjectHeader.tsx +328 -0
- package/src/components/ProjectLayout.tsx +249 -0
- package/src/components/ReactCanvasControls.tsx +284 -0
- package/src/components/RootSelectionOverlay.tsx +3162 -0
- package/src/components/RootTextEditor.tsx +79 -0
- package/src/components/SaveStatus.tsx +70 -0
- package/src/components/StageHost.tsx +1954 -0
- package/src/components/StageOverlays.tsx +21 -0
- package/src/components/StartupErrorScreen.tsx +76 -0
- package/src/components/StartupLoadingScreen.tsx +65 -0
- package/src/components/StatsOverlay.tsx +78 -0
- package/src/components/SurfaceStateOverlay.tsx +24 -0
- package/src/components/ToolContributionSurfaces.tsx +65 -0
- package/src/components/ToolHost.tsx +370 -0
- package/src/components/ToolObject3DPreview.tsx +39 -0
- package/src/components/Toolbar.tsx +595 -0
- package/src/components/TransientHint.tsx +44 -0
- package/src/components/TransportStrip.tsx +174 -0
- package/src/components/VersionControlSection.tsx +470 -0
- package/src/components/VgaiLogo.css +83 -0
- package/src/components/VgaiLogo.tsx +35 -0
- package/src/components/ViewportControlsHint.tsx +60 -0
- package/src/components/ViewportFurniture.tsx +401 -0
- package/src/components/ViewportOverlay.tsx +145 -0
- package/src/components/ViewportOverlaysMenu.tsx +153 -0
- package/src/components/ViewportShadingMenu.tsx +300 -0
- package/src/components/ViewportViewMenu.tsx +101 -0
- package/src/components/WorkspaceDocumentSurface.tsx +204 -0
- package/src/components/WorkspaceUtilitySurface.tsx +22 -0
- package/src/components/WorktreeSwitcher.css +239 -0
- package/src/components/WorktreeSwitcher.tsx +890 -0
- package/src/components/account-documents.tsx +1162 -0
- package/src/components/asset-documents.tsx +812 -0
- package/src/components/asset-editor-persistence.ts +216 -0
- package/src/components/asset-selection-section.tsx +535 -0
- package/src/components/asset-thumbnails.tsx +312 -0
- package/src/components/asset-viewers/AudioViewer.tsx +201 -0
- package/src/components/asset-viewers/EntityModelDocument.tsx +122 -0
- package/src/components/asset-viewers/EnvironmentAssetDocument.tsx +440 -0
- package/src/components/asset-viewers/GenericJsonViewer.tsx +102 -0
- package/src/components/asset-viewers/ImageViewer.tsx +300 -0
- package/src/components/asset-viewers/JsonAssetDocument.tsx +93 -0
- package/src/components/asset-viewers/LiveModuleDocument.tsx +417 -0
- package/src/components/asset-viewers/LutAssetDocument.tsx +444 -0
- package/src/components/asset-viewers/ModelAssetDocument.tsx +105 -0
- package/src/components/asset-viewers/Object3DPreview.tsx +359 -0
- package/src/components/asset-viewers/OnlineAssetDetail.tsx +421 -0
- package/src/components/asset-viewers/PasteboardModuleDocument.tsx +67 -0
- package/src/components/asset-viewers/QuarksAssetDocument.tsx +526 -0
- package/src/components/asset-viewers/ShaderAssetDocument.tsx +743 -0
- package/src/components/asset-viewers/SourceAssetViewer.tsx +281 -0
- package/src/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
- package/src/components/asset-viewers/VideoViewer.tsx +101 -0
- package/src/components/asset-viewers/shader-source.ts +144 -0
- package/src/components/asset-workflow.css +731 -0
- package/src/components/board-guides.ts +150 -0
- package/src/components/compact-inspector.css +539 -0
- package/src/components/core-utilities.tsx +90 -0
- package/src/components/editor-notifications.css +40 -0
- package/src/components/engine-workspace.css +274 -0
- package/src/components/inspector-preview-section.tsx +238 -0
- package/src/components/inspector-property-grouping.ts +64 -0
- package/src/components/inspector-revert-label.ts +20 -0
- package/src/components/inspector-selection.ts +42 -0
- package/src/components/inspector-stories-gating.ts +171 -0
- package/src/components/inspector-transform-subject.ts +11 -0
- package/src/components/inspector-transform.ts +75 -0
- package/src/components/kind-documents.tsx +500 -0
- package/src/components/palette-action-publisher.tsx +140 -0
- package/src/components/primitives/DraftColorInput.tsx +74 -0
- package/src/components/product-shell.css +1829 -0
- package/src/components/project-tool-documents.tsx +410 -0
- package/src/components/scene-documents.tsx +223 -0
- package/src/components/stage-keyboard.tsx +37 -0
- package/src/components/stage-overlay-set.tsx +107 -0
- package/src/components/stage-presence-markers.ts +478 -0
- package/src/components/standard-viewport-dressing.ts +417 -0
- package/src/components/status-contributions.tsx +403 -0
- package/src/components/tool-documents.tsx +309 -0
- package/src/components/tool-schema-form.tsx +262 -0
- package/src/components/use-after-paint.ts +41 -0
- package/src/components/use-project-image-assets.ts +86 -0
- package/src/components/viewport-header-controls.css +90 -0
- package/src/components/viewport-surface-status.tsx +55 -0
- package/src/components/workspace-history.ts +32 -0
- package/src/components/workspace-static-panel-registry.tsx +152 -0
- package/src/components/workspace-surfaces.css +621 -0
- package/src/components/world-documents.tsx +586 -0
- package/src/components/world-overlay-gestures.ts +1694 -0
- package/src/composite-screenshot.ts +1641 -0
- package/src/console-sync.ts +131 -0
- package/src/constraint-helper.ts +338 -0
- package/src/content-entry-source-registry.ts +184 -0
- package/src/coverage/authoring-seam-evidence.ts +300 -0
- package/src/coverage/canvas-reveal.ts +192 -0
- package/src/coverage/design-time-surfaces.ts +101 -0
- package/src/coverage/live-seam-evidence.ts +11 -0
- package/src/coverage/ontology-invariants.ts +466 -0
- package/src/coverage/session-vitals.ts +501 -0
- package/src/coverage/system-seam-evidence.ts +72 -0
- package/src/crash-null-boundary.ts +36 -0
- package/src/creation-site-edit.ts +1479 -0
- package/src/creation-site-registry.ts +160 -0
- package/src/delegate-harness-registry.ts +143 -0
- package/src/document-context-registry.ts +177 -0
- package/src/document-open-registry.ts +200 -0
- package/src/document-preview-source.ts +20 -0
- package/src/document-renderer-session.ts +138 -0
- package/src/editor-api.ts +46 -0
- package/src/editor-chrome-capture.ts +139 -0
- package/src/editor-commands.ts +164 -0
- package/src/editor-console.ts +563 -0
- package/src/editor-current-view.ts +82 -0
- package/src/editor-document-probe.ts +881 -0
- package/src/editor-git-client.ts +115 -0
- package/src/editor-host-door.ts +462 -0
- package/src/editor-hotkeys.ts +842 -0
- package/src/editor-lease-view.ts +39 -0
- package/src/editor-lease.ts +415 -0
- package/src/editor-mode.ts +19 -0
- package/src/editor-notifications.ts +140 -0
- package/src/editor-presence.ts +563 -0
- package/src/editor-presentation-activity.ts +50 -0
- package/src/editor-presentation-notice.ts +42 -0
- package/src/editor-runtime.tsx +145 -0
- package/src/editor-server-response.ts +86 -0
- package/src/editor-session-attribution.ts +75 -0
- package/src/editor-session-mode.ts +54 -0
- package/src/editor-shell-store.ts +1304 -0
- package/src/editor-state-facets.ts +74 -0
- package/src/editor-styles.css +33 -0
- package/src/editor-view-presentation.ts +810 -0
- package/src/editor-viewport.ts +5302 -0
- package/src/entity-lod.ts +31 -0
- package/src/entity-object.ts +91 -0
- package/src/files/file-provider.ts +62 -0
- package/src/files/project-files.ts +264 -0
- package/src/finders/index.ts +136 -0
- package/src/finders/scenes-from-entrypoint-selection.ts +387 -0
- package/src/frame/bridge.tsx +1408 -0
- package/src/frame/product.ts +77 -0
- package/src/gameplay-dom-recording.ts +319 -0
- package/src/gameplay-export-state.ts +14 -0
- package/src/gameplay-replay.ts +417 -0
- package/src/gameplay-session-time.ts +9 -0
- package/src/gameplay-sessions.ts +204 -0
- package/src/harness-chat-types.ts +253 -0
- package/src/hierarchy-component-marks.ts +298 -0
- package/src/hierarchy-drop.ts +91 -0
- package/src/hierarchy-expansion-state.ts +80 -0
- package/src/hierarchy-header-slot.ts +52 -0
- package/src/hierarchy-internals.ts +197 -0
- package/src/hierarchy-kind-icon.ts +217 -0
- package/src/hierarchy-mark-reader.ts +73 -0
- package/src/hierarchy-menu-registry.ts +67 -0
- package/src/hierarchy-node-rows.ts +307 -0
- package/src/hierarchy-panel-view.ts +280 -0
- package/src/hierarchy-projection.ts +76 -0
- package/src/hierarchy-row-cache.ts +243 -0
- package/src/hierarchy-row-model.ts +308 -0
- package/src/hierarchy-rows.ts +11 -0
- package/src/hierarchy-walk.ts +86 -0
- package/src/history/editor-session.ts +25 -0
- package/src/history/history-commands.ts +147 -0
- package/src/history/history-delegate.ts +163 -0
- package/src/history/history-limit-notices.ts +43 -0
- package/src/history/history-service.ts +1173 -0
- package/src/history/persistence-coordinator.ts +35 -0
- package/src/history/project-file-history.ts +386 -0
- package/src/history/project-root-history-backends.ts +139 -0
- package/src/history/resource-registry.ts +209 -0
- package/src/history/snapshot-store.ts +103 -0
- package/src/history/source-history-backend.ts +546 -0
- package/src/history/types.ts +124 -0
- package/src/hmr-registration-group.ts +67 -0
- package/src/hmr-stable-react-context.ts +23 -0
- package/src/hotkeys.ts +188 -0
- package/src/inference-diagnostics.ts +69 -0
- package/src/initial-project.ts +80 -0
- package/src/inspection/active-subject.ts +578 -0
- package/src/inspection/active-surface.ts +142 -0
- package/src/inspection/compose.ts +1064 -0
- package/src/inspection/display.ts +170 -0
- package/src/inspection/document-subject.ts +109 -0
- package/src/inspection/game-subject.ts +85 -0
- package/src/inspection/model.ts +542 -0
- package/src/inspection/null-subject.ts +115 -0
- package/src/inspection/serialize.ts +357 -0
- package/src/inspection/use-active-inspection.ts +180 -0
- package/src/inspector-presentation.ts +201 -0
- package/src/inspector-section-registry.ts +221 -0
- package/src/instance-source-actions.ts +163 -0
- package/src/instanced-presentation.ts +164 -0
- package/src/js-heap.ts +71 -0
- package/src/key-actions.ts +91 -0
- package/src/keymap-presets.ts +401 -0
- package/src/layout-policy.ts +31 -0
- package/src/learn-links.ts +73 -0
- package/src/light-explorer-model.ts +134 -0
- package/src/live-canvas-frame.ts +55 -0
- package/src/live-document.ts +279 -0
- package/src/live-module-source.ts +230 -0
- package/src/live-session-registry.ts +220 -0
- package/src/live-transition.ts +633 -0
- package/src/manifest-project.ts +107 -0
- package/src/model-thumbnail.ts +523 -0
- package/src/native-selection-style.ts +202 -0
- package/src/object3d-document-write-policy.ts +137 -0
- package/src/packaged-runtime.ts +108 -0
- package/src/palettes/maya.palette.json +57 -0
- package/src/palettes/substance.palette.json +57 -0
- package/src/pasteboard-module.ts +81 -0
- package/src/performance-profiler.ts +367 -0
- package/src/performance-sources.ts +69 -0
- package/src/play-boot-phase.ts +145 -0
- package/src/presentation-surface.ts +248 -0
- package/src/project-adapter.ts +1143 -0
- package/src/project-asset-refresh.ts +26 -0
- package/src/project-declaration-refresh.ts +31 -0
- package/src/project-local-state.ts +118 -0
- package/src/project-manager.ts +243 -0
- package/src/project-module-changes.ts +163 -0
- package/src/project-module-split.ts +266 -0
- package/src/project-provenance.ts +115 -0
- package/src/project-ready.ts +42 -0
- package/src/project-session-reset.ts +67 -0
- package/src/project-shape.ts +68 -0
- package/src/project-tool-discovery.ts +66 -0
- package/src/project-tools.ts +107 -0
- package/src/project-work-types.ts +149 -0
- package/src/projection/three.ts +898 -0
- package/src/projection/types.ts +44 -0
- package/src/readiness.ts +113 -0
- package/src/reflection-probe-helper.ts +142 -0
- package/src/reported-play-state.ts +90 -0
- package/src/resolve-relative-specifier.ts +33 -0
- package/src/scene-document-plan.ts +315 -0
- package/src/scene-framing.ts +315 -0
- package/src/scene-live-open.ts +210 -0
- package/src/scene-view-fog.ts +89 -0
- package/src/scoped-game-css.ts +152 -0
- package/src/session-orphan-record.ts +193 -0
- package/src/session-tombstone.ts +126 -0
- package/src/settings/settings-provider.ts +82 -0
- package/src/settings-store.ts +345 -0
- package/src/shared-view-restore.ts +42 -0
- package/src/shell-store-door.ts +45 -0
- package/src/source-conflict.ts +122 -0
- package/src/spatial-handle-visuals.ts +332 -0
- package/src/stage-context.ts +341 -0
- package/src/stage-store-registry.ts +63 -0
- package/src/stale-chunk-recovery.ts +34 -0
- package/src/state-report-deferral.ts +73 -0
- package/src/storage/host-files-storage.ts +97 -0
- package/src/storage/http-storage.ts +174 -0
- package/src/storage/index.ts +75 -0
- package/src/storage/mem-storage.ts +149 -0
- package/src/storage/path-lock.ts +44 -0
- package/src/storage/paths.ts +26 -0
- package/src/storage/types.ts +116 -0
- package/src/stories/StoryComponentThumbnail.tsx +184 -0
- package/src/stories/StoryPreviewMount.tsx +306 -0
- package/src/stories/component-content-source.tsx +106 -0
- package/src/stories/component-states-source.ts +78 -0
- package/src/stories/compose-project-stories.ts +255 -0
- package/src/stories/pixi-story-model.ts +30 -0
- package/src/stories/prefabs-finder.ts +54 -0
- package/src/stories/prefabs-from-stories.ts +182 -0
- package/src/stories/project-story-discovery.ts +78 -0
- package/src/stories/project-story-regions.ts +24 -0
- package/src/stories/story-actions.ts +54 -0
- package/src/stories/story-capture-command.ts +124 -0
- package/src/stories/story-capture.ts +584 -0
- package/src/stories/story-declared-medium.ts +126 -0
- package/src/stories/story-discovery.ts +176 -0
- package/src/stories/story-document-openers.ts +36 -0
- package/src/stories/story-dom-runtime.ts +78 -0
- package/src/stories/story-grouping.ts +111 -0
- package/src/stories/story-lane.ts +88 -0
- package/src/stories/story-mount-turn.ts +27 -0
- package/src/stories/story-opener.ts +260 -0
- package/src/stories/story-pixi-preview.ts +408 -0
- package/src/stories/story-presentation.ts +215 -0
- package/src/stories/story-registry.ts +517 -0
- package/src/stories/story-three-preview.ts +807 -0
- package/src/stories/three-story-model.ts +96 -0
- package/src/story-three-preview-runtime.ts +56 -0
- package/src/surface-keyboard.ts +112 -0
- package/src/surface-state.ts +124 -0
- package/src/tab-bootstrap.js +628 -0
- package/src/tab-census.ts +198 -0
- package/src/tab-lifecycle-client.ts +196 -0
- package/src/theme-library.ts +844 -0
- package/src/theme-preference.ts +378 -0
- package/src/theme.css +3437 -0
- package/src/three-viewport/bone-selection-highlight.ts +119 -0
- package/src/three-viewport/camera-fit.ts +41 -0
- package/src/three-viewport/interactive-renderer.ts +132 -0
- package/src/three-viewport/selection-brackets.ts +310 -0
- package/src/three-viewport/selection-outline.ts +183 -0
- package/src/three-viewport/skeleton-helper.ts +61 -0
- package/src/three-viewport/source-color.ts +167 -0
- package/src/three-viewport/studio-environment.ts +96 -0
- package/src/three-viewport-presentation.ts +23 -0
- package/src/tool-contribution-play.ts +74 -0
- package/src/tool-loader.ts +1798 -0
- package/src/transform-mode-request.ts +57 -0
- package/src/transient-hint.ts +78 -0
- package/src/trigger-volume-helper.ts +116 -0
- package/src/ui-source/adapter-region-includes.ts +241 -0
- package/src/ui-source/ensure-import.ts +132 -0
- package/src/ui-source/file-region-resolver.ts +302 -0
- package/src/ui-source/inspect.ts +775 -0
- package/src/ui-source/oid-transform.ts +1845 -0
- package/src/ui-source/plan-csf-story.ts +196 -0
- package/src/ui-source/plan-extract-component.ts +421 -0
- package/src/ui-source/plan-fork-component.ts +621 -0
- package/src/ui-source/plan-named-style.ts +95 -0
- package/src/ui-source/plan-source-edit.ts +353 -0
- package/src/ui-source/r3f-contract-resolver.ts +327 -0
- package/src/ui-source/r3f-diagnostic-index.ts +165 -0
- package/src/ui-source/r3f-environment-binding.ts +133 -0
- package/src/ui-source/r3f-joint-binding.ts +251 -0
- package/src/ui-source/r3f-lod-binding.ts +91 -0
- package/src/ui-source/r3f-particle-binding.ts +235 -0
- package/src/ui-source/r3f-physics-binding.ts +483 -0
- package/src/ui-source/r3f-project-contracts.ts +444 -0
- package/src/ui-source/relative-import-specifier.ts +34 -0
- package/src/ui-source/reparent-guard.ts +544 -0
- package/src/ui-source/source-edit-request.ts +97 -0
- package/src/ui-source/source-write-backend.ts +618 -0
- package/src/ui-source/syntactic-prop-specs.ts +296 -0
- package/src/ui-source/tier-source-write-backend.ts +279 -0
- package/src/ui-source/ts-ast.ts +171 -0
- package/src/ui-source/utility-class-support.ts +169 -0
- package/src/ui-source/write-component-default.ts +133 -0
- package/src/ui-source/writer.ts +1989 -0
- package/src/viewport-activation-timings.ts +840 -0
- package/src/viewport-authoring-policy.ts +186 -0
- package/src/viewport-controls-hint.ts +57 -0
- package/src/viewport-door.ts +237 -0
- package/src/viewport-shading-boundary.ts +12 -0
- package/src/vite-error-surface.ts +141 -0
- package/src/wait-until.ts +37 -0
- package/src/workspace-areas.ts +156 -0
- package/src/workspace-aux-commands.ts +11 -0
- package/src/workspace-available-documents.ts +127 -0
- package/src/workspace-core-utilities.ts +31 -0
- package/src/workspace-document-ids.ts +59 -0
- package/src/workspace-document-registry.ts +612 -0
- package/src/workspace-document-restore.ts +145 -0
- package/src/workspace-host-commands.ts +141 -0
- package/src/workspace-persistence-gate.ts +40 -0
- package/src/workspace-play-utilities.ts +44 -0
- package/src/workspace-presets.ts +425 -0
- package/src/workspace-regions.ts +294 -0
- package/src/workspace-state-persistence.ts +536 -0
- package/src/workspace-static-panels.ts +73 -0
- package/src/workspace-status-registry.ts +121 -0
- package/src/workspace-style.ts +239 -0
- package/src/workspace-utility-commands.ts +74 -0
- package/src/workspace-utility-registry.ts +263 -0
- package/src/workspace-viewport-rect.ts +97 -0
- package/src/world-adoption.ts +115 -0
- package/src/world-document-routing.ts +104 -0
- package/vite-plugin-creation-site-write.ts +184 -0
- package/vite-plugin-creation-site.ts +80 -0
- package/vite-plugin-game-static.ts +303 -0
- package/vite-plugin-module-doorways.ts +336 -0
- package/vite-plugin-product-contributions.ts +197 -0
- package/vite-plugin-project-game-static.ts +125 -0
- package/vite-plugin-project-jsx-js.ts +65 -0
- package/vite-plugin-project-root-absolute-assets.ts +359 -0
- package/vite-plugin-shared-react.ts +420 -0
- package/vite-plugin-shared-three.ts +203 -0
- package/vite-plugin-ui-oid.ts +2106 -0
|
@@ -0,0 +1,812 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asset DOCUMENTS (W2 — inventory rows R2–R7):
|
|
3
|
+
* model/image/audio/input-map/JSON viewers open as CENTER workspace documents
|
|
4
|
+
* through `workspace-document-registry.ts`, replacing the former `RightPanel`
|
|
5
|
+
* asset-tab mechanism (`editor-store.ts`'s `AssetTab` list, deleted in this
|
|
6
|
+
* wave). The Inspector is never displaced by a viewer again (§10 acceptance
|
|
7
|
+
* #3).
|
|
8
|
+
*
|
|
9
|
+
* Identity (§7.1 stable ids): document ids keep the exact key vocabulary the
|
|
10
|
+
* old store tabs used, so the control-API surface (`open-asset-tab` /
|
|
11
|
+
* `close-asset-tab` / `active-tab` in `command-listener.ts`, `vgai
|
|
12
|
+
* open-asset`) keeps its meaning unchanged:
|
|
13
|
+
*
|
|
14
|
+
* - project asset → the serving path itself (`/textures/crate.png`)
|
|
15
|
+
* - Asset Editor → `asset-editor:entity:<entityId>`
|
|
16
|
+
* - online asset → `online:<source>:<id>`
|
|
17
|
+
*
|
|
18
|
+
* Titles are source-owned file names as authored (§8 — `crate.png`, never a
|
|
19
|
+
* technology bucket); the online document keeps the catalog's own asset name.
|
|
20
|
+
*
|
|
21
|
+
* Per-document RUNTIME state (an online asset resolving to a local path after
|
|
22
|
+
* download) lives in an HMR-stable module spec map in the house
|
|
23
|
+
* `useSyncExternalStore` shape — the registry's descriptors stay immutable,
|
|
24
|
+
* and `AssetDocumentContent` re-renders from the spec map. Specs are dropped
|
|
25
|
+
* on document dispose (close / project teardown via
|
|
26
|
+
* `closeAllWorkspaceDocuments`), so nothing leaks across sessions.
|
|
27
|
+
*
|
|
28
|
+
* T6.3 interplay: activating an asset document means neither the scene
|
|
29
|
+
* viewport nor the Game preview is the active center surface, so the
|
|
30
|
+
* descriptor's `onActivate` writes the store's `'scene'` tab — the play input
|
|
31
|
+
* gate (`playState === 'playing' && activeViewportTab === 'play'`) drops
|
|
32
|
+
* without stopping play, exactly like clicking the scene tab.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import { faCloudArrowDown, faFileLines } from '@fortawesome/free-solid-svg-icons';
|
|
36
|
+
import { bg, danger, text } from '@volter/editor-sdk/widgets';
|
|
37
|
+
import type { AuthoringAssetSubject } from '@volter/editor-project/adapter';
|
|
38
|
+
import { lazy, type ReactNode, Suspense, useEffect, useSyncExternalStore } from 'react';
|
|
39
|
+
import type * as THREE from 'three';
|
|
40
|
+
import { clearSelectedAsset } from '../asset-selection';
|
|
41
|
+
import { assetCapabilities } from '../asset-workflow/asset-capabilities';
|
|
42
|
+
import {
|
|
43
|
+
splitSpritesheetAssetPath,
|
|
44
|
+
spritesheetFrameTitle,
|
|
45
|
+
} from '../asset-workflow/pixi-spritesheet';
|
|
46
|
+
import { authoringAssetDataUrl } from '../authoring/authoring-asset-url';
|
|
47
|
+
import { awaitAnnouncedObject3DDocumentSession } from '../document-context-registry';
|
|
48
|
+
import { registerDocumentOpener } from '../document-open-registry';
|
|
49
|
+
import { projectFileExists } from '../editor-api';
|
|
50
|
+
import type { AssetKind, OnlineAssetInfo, ViewportTab } from '../editor-shell-store';
|
|
51
|
+
import { type InspectionSection, PROPERTIES_SECTION_ORDER } from '../inspection/model';
|
|
52
|
+
import { shellStoreForHost } from '../shell-store-door';
|
|
53
|
+
import { DOCUMENT_REGISTRATION_TIMEOUT_MS, waitUntil } from '../wait-until';
|
|
54
|
+
import {
|
|
55
|
+
activeWorkspaceDocumentId,
|
|
56
|
+
openWorkspaceDocument,
|
|
57
|
+
setWorkspaceDocumentTitle,
|
|
58
|
+
type WorkspaceDocumentContentProps,
|
|
59
|
+
type WorkspaceDocumentDescriptor,
|
|
60
|
+
workspaceDocumentSelection,
|
|
61
|
+
} from '../workspace-document-registry';
|
|
62
|
+
import { registerWorkspaceDocumentRestorer } from '../workspace-document-restore';
|
|
63
|
+
|
|
64
|
+
import { MediaProperties } from './MediaProperties';
|
|
65
|
+
|
|
66
|
+
const AssetEditorShell = lazy(async () => {
|
|
67
|
+
const module = await import('./AssetEditorShell');
|
|
68
|
+
return { default: module.AssetEditorShell };
|
|
69
|
+
});
|
|
70
|
+
const AudioViewer = lazy(async () => {
|
|
71
|
+
const module = await import('./asset-viewers/AudioViewer');
|
|
72
|
+
return { default: module.AudioViewer };
|
|
73
|
+
});
|
|
74
|
+
const EntityModelDocument = lazy(async () => {
|
|
75
|
+
const module = await import('./asset-viewers/EntityModelDocument');
|
|
76
|
+
return { default: module.EntityModelDocument };
|
|
77
|
+
});
|
|
78
|
+
const EnvironmentAssetDocument = lazy(async () => {
|
|
79
|
+
const module = await import('./asset-viewers/EnvironmentAssetDocument');
|
|
80
|
+
return { default: module.EnvironmentAssetDocument };
|
|
81
|
+
});
|
|
82
|
+
const ImageViewer = lazy(async () => {
|
|
83
|
+
const module = await import('./asset-viewers/ImageViewer');
|
|
84
|
+
return { default: module.ImageViewer };
|
|
85
|
+
});
|
|
86
|
+
const VideoViewer = lazy(async () => {
|
|
87
|
+
const module = await import('./asset-viewers/VideoViewer');
|
|
88
|
+
return { default: module.VideoViewer };
|
|
89
|
+
});
|
|
90
|
+
const JsonAssetDocument = lazy(async () => {
|
|
91
|
+
const module = await import('./asset-viewers/JsonAssetDocument');
|
|
92
|
+
return { default: module.JsonAssetDocument };
|
|
93
|
+
});
|
|
94
|
+
const ModelAssetDocument = lazy(async () => {
|
|
95
|
+
const module = await import('./asset-viewers/ModelAssetDocument');
|
|
96
|
+
return { default: module.ModelAssetDocument };
|
|
97
|
+
});
|
|
98
|
+
const OnlineAssetDetail = lazy(async () => {
|
|
99
|
+
const module = await import('./asset-viewers/OnlineAssetDetail');
|
|
100
|
+
return { default: module.OnlineAssetDetail };
|
|
101
|
+
});
|
|
102
|
+
const SourceAssetViewer = lazy(async () => {
|
|
103
|
+
const module = await import('./asset-viewers/SourceAssetViewer');
|
|
104
|
+
return { default: module.SourceAssetViewer };
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
/** What one open asset document is showing — the former `AssetTab` shape,
|
|
108
|
+
* now keyed by workspace-document id. */
|
|
109
|
+
export interface AssetDocumentSpec {
|
|
110
|
+
readonly assetPath: string;
|
|
111
|
+
readonly kind: AssetKind;
|
|
112
|
+
/** Entity source for a session-only Asset Editor document. Never serialized. */
|
|
113
|
+
readonly entityId?: string;
|
|
114
|
+
/** Present while this document shows an online (not-yet-downloaded) asset. */
|
|
115
|
+
readonly online?: OnlineAssetInfo;
|
|
116
|
+
readonly unavailableReason?: string;
|
|
117
|
+
/** Incremented when the file bytes change at the same path. */
|
|
118
|
+
readonly revision?: number;
|
|
119
|
+
/** Display metadata for an adapter-provided in-memory asset (for example inline SVG). */
|
|
120
|
+
readonly displayName?: string;
|
|
121
|
+
readonly sourcePath?: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface AssetDocumentMutation {
|
|
125
|
+
type: 'move' | 'delete' | 'change';
|
|
126
|
+
oldPath?: string;
|
|
127
|
+
newPath?: string;
|
|
128
|
+
paths?: readonly string[];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const hotData = import.meta.hot?.data;
|
|
132
|
+
const _specs =
|
|
133
|
+
(hotData?.['vgai:asset-document-specs'] as Map<string, AssetDocumentSpec> | undefined) ??
|
|
134
|
+
new Map<string, AssetDocumentSpec>();
|
|
135
|
+
const _pathAliases =
|
|
136
|
+
(hotData?.['vgai:asset-document-path-aliases'] as Map<string, string> | undefined) ??
|
|
137
|
+
new Map<string, string>();
|
|
138
|
+
const _focusReturnTargets = new Map<string, HTMLElement>();
|
|
139
|
+
if (hotData) {
|
|
140
|
+
// Workspace descriptors intentionally survive compatible Fast Refreshes.
|
|
141
|
+
// Their specs must survive with them or the next persistence snapshot drops
|
|
142
|
+
// the open document and leaves a titled-but-empty tab on reload.
|
|
143
|
+
hotData['vgai:asset-document-specs'] = _specs;
|
|
144
|
+
hotData['vgai:asset-document-path-aliases'] = _pathAliases;
|
|
145
|
+
}
|
|
146
|
+
let _version = 0;
|
|
147
|
+
const _listeners = new Set<() => void>();
|
|
148
|
+
|
|
149
|
+
function notifyChanged(): void {
|
|
150
|
+
_version++;
|
|
151
|
+
for (const fn of _listeners) fn();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Subscribe to spec changes (online-asset resolution). Returns unsubscribe. */
|
|
155
|
+
export function subscribeAssetDocuments(fn: () => void): () => void {
|
|
156
|
+
_listeners.add(fn);
|
|
157
|
+
return () => {
|
|
158
|
+
_listeners.delete(fn);
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** Monotonic change counter — the `getSnapshot` for `useSyncExternalStore`. */
|
|
163
|
+
export function assetDocumentsVersion(): number {
|
|
164
|
+
return _version;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** The spec behind an open asset document id, or `undefined`. */
|
|
168
|
+
export function assetDocumentSpec(id: string): AssetDocumentSpec | undefined {
|
|
169
|
+
return _specs.get(id);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** Whether `id` is one of this module's asset documents (used by
|
|
173
|
+
* `command-listener.ts` to report the legacy `activeTabKey` facet). */
|
|
174
|
+
export function isAssetDocumentId(id: string): boolean {
|
|
175
|
+
return _specs.has(id);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** The narrow store surface asset documents need (T6.3 gate hand-off). */
|
|
179
|
+
export interface AssetDocumentStore {
|
|
180
|
+
setActiveViewportTab(tab: ViewportTab): void;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** The Asset Editor additionally needs the live object map for its §8 title. */
|
|
184
|
+
export interface EntityAssetDocumentStore extends AssetDocumentStore {
|
|
185
|
+
readonly objectMap: Map<string, THREE.Object3D>;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** Shallow equality over the union of both specs' keys — the specs are flat
|
|
189
|
+
* records of primitives plus two small objects, and the only question asked
|
|
190
|
+
* of them is "did the request ask for something different". */
|
|
191
|
+
function sameSpec(a: AssetDocumentSpec, b: AssetDocumentSpec): boolean {
|
|
192
|
+
const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
193
|
+
for (const key of keys) {
|
|
194
|
+
const left = (a as unknown as Record<string, unknown>)[key];
|
|
195
|
+
const right = (b as unknown as Record<string, unknown>)[key];
|
|
196
|
+
if (left === right) continue;
|
|
197
|
+
if (JSON.stringify(left) !== JSON.stringify(right)) return false;
|
|
198
|
+
}
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function openSpecDocument(
|
|
203
|
+
store: AssetDocumentStore,
|
|
204
|
+
id: string,
|
|
205
|
+
title: string,
|
|
206
|
+
spec: AssetDocumentSpec,
|
|
207
|
+
provenance?: WorkspaceDocumentDescriptor['provenance'],
|
|
208
|
+
options: { activate?: boolean } = {},
|
|
209
|
+
): string {
|
|
210
|
+
if (typeof document !== 'undefined' && document.activeElement instanceof HTMLElement) {
|
|
211
|
+
_focusReturnTargets.set(id, document.activeElement);
|
|
212
|
+
}
|
|
213
|
+
const existing = _specs.get(id);
|
|
214
|
+
if (!existing) {
|
|
215
|
+
_specs.set(id, spec);
|
|
216
|
+
notifyChanged();
|
|
217
|
+
} else {
|
|
218
|
+
// FIRST SPEC NO LONGER WINS. Re-opening the same path with a DIFFERENT
|
|
219
|
+
// kind used to be a silent no-op: the id IS the path, the spec was written
|
|
220
|
+
// once, and every later request was dropped on the floor while the call
|
|
221
|
+
// still acked. `editor.openAsset('/x.json', 'source')` therefore handed
|
|
222
|
+
// back the JSON viewer and reported success.
|
|
223
|
+
//
|
|
224
|
+
// The honest resolution is UPDATE, not refuse, because of what the two
|
|
225
|
+
// halves of this identity are: the PATH is the document's identity (the id
|
|
226
|
+
// is literally the path) and the KIND is a VIEW of that file. A second
|
|
227
|
+
// view of the same file is an ordinary request, not a collision — refusing
|
|
228
|
+
// it would mean a file already open can only be re-viewed by closing it
|
|
229
|
+
// first, a modal rule the workspace has nowhere to show. Layout
|
|
230
|
+
// persistence agrees: it serializes whatever the spec CURRENTLY says
|
|
231
|
+
// (`{path, assetKind}`) and restores by calling this function against an
|
|
232
|
+
// empty registry, so an updated spec round-trips exactly and refusal would
|
|
233
|
+
// never fire on that path anyway.
|
|
234
|
+
//
|
|
235
|
+
// The request wins key-by-key; fields the request does not speak for
|
|
236
|
+
// (`revision`, `unavailableReason` — facts about the FILE at that path,
|
|
237
|
+
// maintained by `applyAssetDocumentMutation`) survive.
|
|
238
|
+
const merged = { ...existing, ...spec };
|
|
239
|
+
if (!sameSpec(existing, merged)) {
|
|
240
|
+
_specs.set(id, merged);
|
|
241
|
+
notifyChanged();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
const descriptor: WorkspaceDocumentDescriptor = {
|
|
245
|
+
id,
|
|
246
|
+
title,
|
|
247
|
+
kind: 'asset',
|
|
248
|
+
workspaceRole: 'authored-subject',
|
|
249
|
+
...(provenance ? { provenance } : {}),
|
|
250
|
+
Content: AssetDocumentContent,
|
|
251
|
+
closeable: true,
|
|
252
|
+
presentation: () => {
|
|
253
|
+
const current = _specs.get(id);
|
|
254
|
+
if (!current) return null;
|
|
255
|
+
if (current.entityId)
|
|
256
|
+
return { kind: 'asset', entityId: current.entityId, assetKind: 'model' };
|
|
257
|
+
if (!current.assetPath || current.online) return null;
|
|
258
|
+
return {
|
|
259
|
+
kind: 'asset',
|
|
260
|
+
path: current.assetPath,
|
|
261
|
+
assetKind: current.kind,
|
|
262
|
+
};
|
|
263
|
+
},
|
|
264
|
+
// Only a real FILE-BACKED view restores: a live-entity Asset Editor
|
|
265
|
+
// session and an unresolved online asset are not truthfully re-resolvable
|
|
266
|
+
// from a cold boot, so they return nothing and the host stores nothing.
|
|
267
|
+
persist: () => {
|
|
268
|
+
const current = _specs.get(id);
|
|
269
|
+
if (!current?.assetPath || current.online || current.entityId !== undefined) return undefined;
|
|
270
|
+
return { path: current.assetPath, assetKind: current.kind };
|
|
271
|
+
},
|
|
272
|
+
onActivate: () => {
|
|
273
|
+
store.setActiveViewportTab('edit');
|
|
274
|
+
if (spec.kind === 'image' || spec.kind === 'video' || spec.kind === 'audio')
|
|
275
|
+
clearSelectedAsset();
|
|
276
|
+
},
|
|
277
|
+
onDispose: (documentId) => {
|
|
278
|
+
if (_specs.delete(documentId)) notifyChanged();
|
|
279
|
+
const focusTarget = _focusReturnTargets.get(documentId);
|
|
280
|
+
_focusReturnTargets.delete(documentId);
|
|
281
|
+
if (focusTarget?.isConnected) setTimeout(() => focusTarget.focus(), 0);
|
|
282
|
+
},
|
|
283
|
+
};
|
|
284
|
+
return openWorkspaceDocument(descriptor, options);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Open a project asset as a center document (double-click/Enter in the asset
|
|
289
|
+
* browser, `open-asset-tab` control command). Re-opening an already-open
|
|
290
|
+
* path activates the existing document (registry dedupe) — and re-opening it
|
|
291
|
+
* with a DIFFERENT kind re-points that document's spec at the requested view
|
|
292
|
+
* rather than silently keeping the first one (see `openSpecDocument`).
|
|
293
|
+
*/
|
|
294
|
+
export function openAssetDocument(
|
|
295
|
+
store: AssetDocumentStore,
|
|
296
|
+
assetPath: string,
|
|
297
|
+
kind: AssetKind,
|
|
298
|
+
options: { activate?: boolean } = {},
|
|
299
|
+
): string {
|
|
300
|
+
const title = spritesheetFrameTitle(assetPath);
|
|
301
|
+
const { frameName } = splitSpritesheetAssetPath(assetPath);
|
|
302
|
+
const id = _pathAliases.get(normalizeAssetPath(assetPath)) ?? assetPath;
|
|
303
|
+
return openSpecDocument(
|
|
304
|
+
store,
|
|
305
|
+
id,
|
|
306
|
+
title,
|
|
307
|
+
frameName ? { assetPath, kind, displayName: title } : { assetPath, kind },
|
|
308
|
+
{ sourcePath: assetPath },
|
|
309
|
+
options,
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Reopen a persisted asset document. Verified with an EXISTENCE-ONLY probe
|
|
315
|
+
* (`projectFileExists` — a backend stat in browser-hosted projects, an HTTP
|
|
316
|
+
* HEAD on the local server): a deleted asset resolves false and the document
|
|
317
|
+
* is dropped. Deliberately not `readProjectTextFile`, which downloads the
|
|
318
|
+
* whole asset body just to throw it away here.
|
|
319
|
+
*/
|
|
320
|
+
registerWorkspaceDocumentRestorer({
|
|
321
|
+
kind: 'asset',
|
|
322
|
+
owner: 'asset-documents',
|
|
323
|
+
restore: async ({ state, store }) => {
|
|
324
|
+
const record = state as { path?: unknown; assetKind?: unknown } | null | undefined;
|
|
325
|
+
const path = typeof record?.path === 'string' ? record.path : null;
|
|
326
|
+
const assetKind = typeof record?.assetKind === 'string' ? record.assetKind : null;
|
|
327
|
+
if (!path || !assetKind) return false;
|
|
328
|
+
if (!(await projectFileExists(path))) return false;
|
|
329
|
+
openAssetDocument(store, path, assetKind as AssetKind);
|
|
330
|
+
return true;
|
|
331
|
+
},
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* THE `asset` ADDRESS (`document-open-registry.ts`) — an asset at a path, or
|
|
336
|
+
* the Asset Editor over a live scene entity. Registered at module load, the
|
|
337
|
+
* shape `packages/game/src/story-documents/three-story-documents.tsx:239`
|
|
338
|
+
* uses; what an extension means, and what `@volter/editor-sdk`'s published view
|
|
339
|
+
* kinds map onto internally, are this module's rules and the presenter no
|
|
340
|
+
* longer holds either.
|
|
341
|
+
*
|
|
342
|
+
* `ready` (the post-open half of `settle`) is why the address exists as more
|
|
343
|
+
* than a call: an asset document answers its id the moment its tab is
|
|
344
|
+
* registered, while `present` must not return until the Inspector has mounted
|
|
345
|
+
* — and for a MODEL, until its live Object3D adapter has replaced the identity
|
|
346
|
+
* floor, or an immediate inspect/setField sees a mounted tab whose graph is
|
|
347
|
+
* not ready. That rule is the asset family's; the host used to await it by
|
|
348
|
+
* hand because it knew the rule.
|
|
349
|
+
*/
|
|
350
|
+
/**
|
|
351
|
+
* THE ASSET DOCUMENT'S READINESS — this family's rule, and a DOOR two callers
|
|
352
|
+
* outside the view protocol hold besides the `ready` below
|
|
353
|
+
* (`command-listener.ts`'s `open-asset-tab` and `@vgai/game`'s ragdoll
|
|
354
|
+
* command). It lived in `editor-view-presentation.ts` while the presenter did
|
|
355
|
+
* the waiting by hand; the presenter holds no kind's rule any more, so the
|
|
356
|
+
* rule lives beside the documents it describes.
|
|
357
|
+
*/
|
|
358
|
+
export async function waitForAssetDocumentInspector(
|
|
359
|
+
documentId: string,
|
|
360
|
+
kind: AssetKind,
|
|
361
|
+
): Promise<boolean> {
|
|
362
|
+
return waitUntil(() => {
|
|
363
|
+
if (activeWorkspaceDocumentId() !== documentId) return false;
|
|
364
|
+
const selection = workspaceDocumentSelection(documentId);
|
|
365
|
+
if (!selection) return false;
|
|
366
|
+
// Every asset shell publishes its own identity once mounted. A model has
|
|
367
|
+
// a stronger readiness bar: its live Object3D adapter must have replaced
|
|
368
|
+
// that identity floor, otherwise an immediate inspect/setField would see
|
|
369
|
+
// a mounted tab whose graph and project authoring contribution are not
|
|
370
|
+
// ready yet.
|
|
371
|
+
return kind !== 'model' || selection.adapter !== null;
|
|
372
|
+
}, DOCUMENT_REGISTRATION_TIMEOUT_MS);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
registerDocumentOpener<{
|
|
376
|
+
readonly path?: string;
|
|
377
|
+
readonly assetKind?: string;
|
|
378
|
+
readonly entityId?: string;
|
|
379
|
+
}>({
|
|
380
|
+
id: 'asset',
|
|
381
|
+
owner: 'asset-documents',
|
|
382
|
+
open: (store, request) => {
|
|
383
|
+
if (request.entityId) {
|
|
384
|
+
// The Asset Editor's §8 title comes from the LIVE object map, which the
|
|
385
|
+
// address seam's narrow store (`WorkspaceStateStore`) does not carry and
|
|
386
|
+
// should not: `shell-store-door.ts` is how a lane reaches the one shell
|
|
387
|
+
// store without the seam widening for a single family.
|
|
388
|
+
const shell = shellStoreForHost();
|
|
389
|
+
if (!shell) return null;
|
|
390
|
+
const id = openEntityAssetDocument(shell, request.entityId);
|
|
391
|
+
if (!id) throw new Error(`Scene entity is not available: ${request.entityId}`);
|
|
392
|
+
return id;
|
|
393
|
+
}
|
|
394
|
+
const path = request.path;
|
|
395
|
+
if (path === undefined) return null;
|
|
396
|
+
return openAssetDocument(store, path, requestedAssetKind(request.assetKind, path));
|
|
397
|
+
},
|
|
398
|
+
ready: async (documentId, request) => {
|
|
399
|
+
const kind: AssetKind = request.entityId
|
|
400
|
+
? 'model'
|
|
401
|
+
: requestedAssetKind(request.assetKind, request.path ?? '');
|
|
402
|
+
if (!(await waitForAssetDocumentInspector(documentId, kind)))
|
|
403
|
+
throw new Error(`Asset document did not finish mounting its Inspector: ${documentId}`);
|
|
404
|
+
// AND ITS STAGE, where it mounted one. The KIND does not decide that and
|
|
405
|
+
// this module must not pretend it does: a `model` always mounts one, a
|
|
406
|
+
// `source` asset only when its module is a model builder
|
|
407
|
+
// (`asset-viewers/SourceAssetViewer.tsx:256`) and a `json` only when its
|
|
408
|
+
// content is a three.quarks system (`asset-viewers/JsonAssetDocument.tsx:64`),
|
|
409
|
+
// so the stage's own announcement is what answers. The Inspector wait above
|
|
410
|
+
// is what makes an absent announcement mean "no stage" rather than "not
|
|
411
|
+
// yet": the shell that would have rendered one has already mounted.
|
|
412
|
+
await awaitAnnouncedObject3DDocumentSession(documentId);
|
|
413
|
+
},
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* The internal view kind an address asks for. `@volter/editor-sdk`'s public
|
|
418
|
+
* view-link contract still carries 'animation' and 'prefab' kinds that have no
|
|
419
|
+
* internal counterpart; exactly those remap to their closest surviving
|
|
420
|
+
* internal kinds. Unnamed falls back to what the extension says.
|
|
421
|
+
*/
|
|
422
|
+
function requestedAssetKind(requested: string | undefined, path: string): AssetKind {
|
|
423
|
+
if (requested === 'animation') return 'source';
|
|
424
|
+
if (requested === 'prefab') return 'json';
|
|
425
|
+
return (requested as AssetKind | undefined) ?? inferAssetKind(path);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/** What an extension means. The asset browser's own vocabulary, which is why
|
|
429
|
+
* it lives beside the documents it opens rather than in the presenter. */
|
|
430
|
+
function inferAssetKind(path: string): AssetKind {
|
|
431
|
+
const ext = path.slice(path.lastIndexOf('.') + 1).toLowerCase();
|
|
432
|
+
if (ext === 'glb' || ext === 'gltf') return 'model';
|
|
433
|
+
if (['png', 'jpg', 'jpeg', 'webp', 'gif', 'svg'].includes(ext)) return 'image';
|
|
434
|
+
if (['mp3', 'ogg', 'wav', 'flac'].includes(ext)) return 'audio';
|
|
435
|
+
if (['glsl', 'vert', 'frag', 'ts', 'tsx', 'js', 'jsx', 'css', 'html', 'md', 'txt'].includes(ext))
|
|
436
|
+
return 'source';
|
|
437
|
+
return 'json';
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/** Open the Asset Editor document for a live entity. */
|
|
441
|
+
export function openEntityAssetDocument(
|
|
442
|
+
store: EntityAssetDocumentStore,
|
|
443
|
+
entityId: string,
|
|
444
|
+
): string | null {
|
|
445
|
+
const object = store.objectMap.get(entityId);
|
|
446
|
+
if (!object) return null;
|
|
447
|
+
// The live `Object3D.name` is the only name there is.
|
|
448
|
+
const title = object.name || entityId;
|
|
449
|
+
return openSpecDocument(
|
|
450
|
+
store,
|
|
451
|
+
`asset-editor:entity:${entityId}`,
|
|
452
|
+
title,
|
|
453
|
+
{ assetPath: '', kind: 'model', entityId },
|
|
454
|
+
{ origin: `entity:${entityId}` },
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/** Open an adapter-owned atomic asset that is embedded in a source document. */
|
|
459
|
+
export function openAuthoringAssetDocument(
|
|
460
|
+
store: AssetDocumentStore,
|
|
461
|
+
entityId: string,
|
|
462
|
+
subject: AuthoringAssetSubject,
|
|
463
|
+
): string {
|
|
464
|
+
const assetPath = authoringAssetDataUrl(subject);
|
|
465
|
+
return openSpecDocument(
|
|
466
|
+
store,
|
|
467
|
+
`asset-editor:subject:${entityId}`,
|
|
468
|
+
subject.name,
|
|
469
|
+
{
|
|
470
|
+
assetPath,
|
|
471
|
+
kind: subject.kind,
|
|
472
|
+
displayName: subject.name,
|
|
473
|
+
...(subject.sourcePath ? { sourcePath: subject.sourcePath } : {}),
|
|
474
|
+
},
|
|
475
|
+
subject.sourcePath ? { sourcePath: subject.sourcePath } : { origin: `entity:${entityId}` },
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/** Open an online-library asset's detail/download document. */
|
|
480
|
+
export function openOnlineAssetDocument(store: AssetDocumentStore, online: OnlineAssetInfo): void {
|
|
481
|
+
const kind: AssetKind =
|
|
482
|
+
online.type === 'model'
|
|
483
|
+
? 'model'
|
|
484
|
+
: online.type === 'animation' || online.type === 'source'
|
|
485
|
+
? 'source'
|
|
486
|
+
: 'image';
|
|
487
|
+
openSpecDocument(
|
|
488
|
+
store,
|
|
489
|
+
`online:${online.source}:${online.id}`,
|
|
490
|
+
online.name,
|
|
491
|
+
{ assetPath: '', kind, online },
|
|
492
|
+
{ origin: `online:${online.source}:${online.id}` },
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/** Point an online asset document at its downloaded local file — the local
|
|
497
|
+
* viewer takes over in place (same document id/title). */
|
|
498
|
+
export function resolveOnlineAssetDocument(id: string, localPath: string): void {
|
|
499
|
+
const spec = _specs.get(id);
|
|
500
|
+
if (!spec) return;
|
|
501
|
+
const { online: _dropped, ...rest } = spec;
|
|
502
|
+
_specs.set(id, { ...rest, assetPath: localPath });
|
|
503
|
+
notifyChanged();
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/** Test-only reset — drops all specs without touching the document registry
|
|
507
|
+
* (pair it with `__resetWorkspaceDocumentRegistryForTest`). */
|
|
508
|
+
export function __resetAssetDocumentsForTest(): void {
|
|
509
|
+
_specs.clear();
|
|
510
|
+
_pathAliases.clear();
|
|
511
|
+
_focusReturnTargets.clear();
|
|
512
|
+
notifyChanged();
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/** Keep a live editor bound to asset identity while its source path changes. */
|
|
516
|
+
export function applyAssetDocumentMutation(
|
|
517
|
+
documentId: string,
|
|
518
|
+
detail: AssetDocumentMutation,
|
|
519
|
+
): void {
|
|
520
|
+
const spec = _specs.get(documentId);
|
|
521
|
+
if (!spec?.assetPath) return;
|
|
522
|
+
const current = normalizeAssetPath(spec.assetPath);
|
|
523
|
+
if (
|
|
524
|
+
detail.type === 'move' &&
|
|
525
|
+
detail.oldPath &&
|
|
526
|
+
detail.newPath &&
|
|
527
|
+
current === normalizeAssetPath(detail.oldPath)
|
|
528
|
+
) {
|
|
529
|
+
const newPath = `/${normalizeAssetPath(detail.newPath)}`;
|
|
530
|
+
_specs.set(documentId, { ...spec, assetPath: newPath });
|
|
531
|
+
_pathAliases.set(normalizeAssetPath(newPath), documentId);
|
|
532
|
+
setWorkspaceDocumentTitle(documentId, newPath.split('/').pop() ?? newPath);
|
|
533
|
+
notifyChanged();
|
|
534
|
+
} else if (
|
|
535
|
+
detail.type === 'delete' &&
|
|
536
|
+
detail.paths?.some((path) => normalizeAssetPath(path) === current)
|
|
537
|
+
) {
|
|
538
|
+
_specs.set(documentId, {
|
|
539
|
+
...spec,
|
|
540
|
+
unavailableReason: `The source ${spec.assetPath} was deleted. Undo the deletion or close this editor.`,
|
|
541
|
+
});
|
|
542
|
+
notifyChanged();
|
|
543
|
+
} else if (
|
|
544
|
+
detail.type === 'change' &&
|
|
545
|
+
detail.paths?.some((path) => normalizeAssetPath(path) === current)
|
|
546
|
+
) {
|
|
547
|
+
_specs.set(documentId, { ...spec, revision: (spec.revision ?? 0) + 1 });
|
|
548
|
+
notifyChanged();
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
export type AssetDocumentViewerRoute =
|
|
553
|
+
| 'online'
|
|
554
|
+
| 'model'
|
|
555
|
+
| 'environment'
|
|
556
|
+
| 'image'
|
|
557
|
+
| 'video'
|
|
558
|
+
| 'audio'
|
|
559
|
+
| 'source'
|
|
560
|
+
| 'json'
|
|
561
|
+
| 'unsupported';
|
|
562
|
+
|
|
563
|
+
/** Pure routing decision, exported so every recognized asset kind is test-pinned. */
|
|
564
|
+
export function assetDocumentViewerRoute(spec: AssetDocumentSpec): AssetDocumentViewerRoute {
|
|
565
|
+
if (spec.online) return 'online';
|
|
566
|
+
if (assetCapabilities(spec.assetPath).editor === 'environment') return 'environment';
|
|
567
|
+
if (spec.kind === 'json')
|
|
568
|
+
return 'json';
|
|
569
|
+
if (['model', 'image', 'video', 'audio', 'source'].includes(spec.kind))
|
|
570
|
+
return spec.kind as AssetDocumentViewerRoute;
|
|
571
|
+
return 'unsupported';
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/** Where this asset CAME FROM — the document's own provenance block, one of
|
|
575
|
+
* the sections it publishes as its subject
|
|
576
|
+
* (`components/AssetEditorShell.tsx`). */
|
|
577
|
+
function sourceSection(spec: AssetDocumentSpec): InspectionSection {
|
|
578
|
+
return {
|
|
579
|
+
id: 'source',
|
|
580
|
+
title: 'Source',
|
|
581
|
+
icon: faFileLines,
|
|
582
|
+
order: PROPERTIES_SECTION_ORDER,
|
|
583
|
+
body: {
|
|
584
|
+
kind: 'custom',
|
|
585
|
+
render: () => <div style={{ padding: 4 }}>{spec.sourcePath ?? spec.assetPath}</div>,
|
|
586
|
+
},
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/** Routes a spec to its center viewer/editor. */
|
|
591
|
+
function AssetViewerBody({
|
|
592
|
+
id,
|
|
593
|
+
spec,
|
|
594
|
+
active,
|
|
595
|
+
}: {
|
|
596
|
+
id: string;
|
|
597
|
+
spec: AssetDocumentSpec;
|
|
598
|
+
active: boolean;
|
|
599
|
+
}) {
|
|
600
|
+
if (spec.unavailableReason) {
|
|
601
|
+
return (
|
|
602
|
+
<AssetEditorShell
|
|
603
|
+
documentId={id}
|
|
604
|
+
active={active}
|
|
605
|
+
type={spec.kind}
|
|
606
|
+
title={spec.assetPath.split('/').pop() || 'Deleted asset'}
|
|
607
|
+
status="Source unavailable"
|
|
608
|
+
>
|
|
609
|
+
<div style={{ padding: 20, color: danger }}>{spec.unavailableReason}</div>
|
|
610
|
+
</AssetEditorShell>
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
const route = assetDocumentViewerRoute(spec);
|
|
614
|
+
if (route === 'online' && spec.online) {
|
|
615
|
+
const online = spec.online;
|
|
616
|
+
return (
|
|
617
|
+
<AssetEditorShell
|
|
618
|
+
documentId={id}
|
|
619
|
+
active={active}
|
|
620
|
+
type="online"
|
|
621
|
+
title={online.name}
|
|
622
|
+
sections={[
|
|
623
|
+
{
|
|
624
|
+
id: 'online-asset',
|
|
625
|
+
title: 'Asset',
|
|
626
|
+
icon: faCloudArrowDown,
|
|
627
|
+
order: PROPERTIES_SECTION_ORDER,
|
|
628
|
+
body: {
|
|
629
|
+
kind: 'custom',
|
|
630
|
+
render: () => (
|
|
631
|
+
<OnlineAssetDetail
|
|
632
|
+
online={online}
|
|
633
|
+
mode="inspector"
|
|
634
|
+
onResolved={(localPath) => resolveOnlineAssetDocument(id, localPath)}
|
|
635
|
+
/>
|
|
636
|
+
),
|
|
637
|
+
},
|
|
638
|
+
},
|
|
639
|
+
]}
|
|
640
|
+
status={`${online.type} · ${online.source}`}
|
|
641
|
+
>
|
|
642
|
+
<OnlineAssetDetail online={online} mode="preview" />
|
|
643
|
+
</AssetEditorShell>
|
|
644
|
+
);
|
|
645
|
+
}
|
|
646
|
+
const title = (spec.displayName ?? spec.assetPath.split('/').pop()) || spec.entityId || 'Asset';
|
|
647
|
+
const viewerKey = `${id}:${spec.revision ?? 0}`;
|
|
648
|
+
if (route === 'model')
|
|
649
|
+
if (spec.assetPath)
|
|
650
|
+
return (
|
|
651
|
+
<ModelAssetDocument
|
|
652
|
+
documentId={id}
|
|
653
|
+
key={viewerKey}
|
|
654
|
+
assetPath={spec.assetPath}
|
|
655
|
+
displayName={title}
|
|
656
|
+
active={active}
|
|
657
|
+
/>
|
|
658
|
+
);
|
|
659
|
+
else if (spec.entityId)
|
|
660
|
+
return (
|
|
661
|
+
<EntityModelDocument
|
|
662
|
+
documentId={id}
|
|
663
|
+
key={viewerKey}
|
|
664
|
+
entityId={spec.entityId}
|
|
665
|
+
displayName={title}
|
|
666
|
+
active={active}
|
|
667
|
+
/>
|
|
668
|
+
);
|
|
669
|
+
else return <div style={{ padding: 20, color: danger }}>Model source is unavailable.</div>;
|
|
670
|
+
if (route === 'environment')
|
|
671
|
+
return (
|
|
672
|
+
<EnvironmentAssetDocument
|
|
673
|
+
key={viewerKey}
|
|
674
|
+
documentId={id}
|
|
675
|
+
assetPath={spec.assetPath}
|
|
676
|
+
active={active}
|
|
677
|
+
/>
|
|
678
|
+
);
|
|
679
|
+
if (route === 'source')
|
|
680
|
+
return (
|
|
681
|
+
<SourceAssetViewer
|
|
682
|
+
key={viewerKey}
|
|
683
|
+
documentId={id}
|
|
684
|
+
assetPath={spec.assetPath}
|
|
685
|
+
active={active}
|
|
686
|
+
/>
|
|
687
|
+
);
|
|
688
|
+
// A .json is content-routed: three.quarks names no extension of its own, so
|
|
689
|
+
// only the file's own structure can say whether this is a particle document
|
|
690
|
+
// or ordinary JSON. `JsonAssetDocument` owns the shell for both answers.
|
|
691
|
+
if (route === 'json')
|
|
692
|
+
return (
|
|
693
|
+
<JsonAssetDocument
|
|
694
|
+
key={viewerKey}
|
|
695
|
+
documentId={id}
|
|
696
|
+
assetPath={spec.assetPath}
|
|
697
|
+
displayName={title}
|
|
698
|
+
active={active}
|
|
699
|
+
sections={[sourceSection(spec)]}
|
|
700
|
+
status={`json · ${spec.sourcePath ?? spec.displayName ?? spec.assetPath}`}
|
|
701
|
+
/>
|
|
702
|
+
);
|
|
703
|
+
let viewer: ReactNode;
|
|
704
|
+
switch (route) {
|
|
705
|
+
case 'image':
|
|
706
|
+
viewer = (
|
|
707
|
+
<ImageViewer
|
|
708
|
+
key={viewerKey}
|
|
709
|
+
assetPath={spec.assetPath}
|
|
710
|
+
{...(spec.displayName ? { displayName: spec.displayName } : {})}
|
|
711
|
+
/>
|
|
712
|
+
);
|
|
713
|
+
break;
|
|
714
|
+
case 'video':
|
|
715
|
+
viewer = <VideoViewer key={viewerKey} assetPath={spec.assetPath} />;
|
|
716
|
+
break;
|
|
717
|
+
case 'audio':
|
|
718
|
+
viewer = <AudioViewer key={viewerKey} assetPath={spec.assetPath} />;
|
|
719
|
+
break;
|
|
720
|
+
default:
|
|
721
|
+
viewer = (
|
|
722
|
+
<div style={{ padding: 16, color: text[2], fontSize: 12 }}>
|
|
723
|
+
No viewer available for this asset type.
|
|
724
|
+
</div>
|
|
725
|
+
);
|
|
726
|
+
}
|
|
727
|
+
return (
|
|
728
|
+
<AssetEditorShell
|
|
729
|
+
documentId={id}
|
|
730
|
+
active={active}
|
|
731
|
+
type={route}
|
|
732
|
+
title={title}
|
|
733
|
+
fill={route === 'image' || route === 'video'}
|
|
734
|
+
sections={
|
|
735
|
+
(route === 'image' && !spec.assetPath.includes('#')) ||
|
|
736
|
+
route === 'video' ||
|
|
737
|
+
route === 'audio'
|
|
738
|
+
? [
|
|
739
|
+
{
|
|
740
|
+
id: 'media-properties',
|
|
741
|
+
title: 'Properties',
|
|
742
|
+
icon: faFileLines,
|
|
743
|
+
order: PROPERTIES_SECTION_ORDER,
|
|
744
|
+
body: {
|
|
745
|
+
kind: 'custom',
|
|
746
|
+
render: () => (
|
|
747
|
+
<MediaProperties
|
|
748
|
+
key={viewerKey}
|
|
749
|
+
assetPath={spec.assetPath}
|
|
750
|
+
kind={route as 'image' | 'video' | 'audio'}
|
|
751
|
+
/>
|
|
752
|
+
),
|
|
753
|
+
},
|
|
754
|
+
},
|
|
755
|
+
...(spec.sourcePath ? [sourceSection(spec)] : []),
|
|
756
|
+
]
|
|
757
|
+
: [sourceSection(spec)]
|
|
758
|
+
}
|
|
759
|
+
status={`${route} · ${spec.sourcePath ?? spec.displayName ?? spec.assetPath}`}
|
|
760
|
+
>
|
|
761
|
+
{viewer}
|
|
762
|
+
</AssetEditorShell>
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* Full-size type-specific Asset Editor document host.
|
|
768
|
+
*/
|
|
769
|
+
export function AssetDocumentContent({ documentId, active }: WorkspaceDocumentContentProps) {
|
|
770
|
+
useSyncExternalStore(subscribeAssetDocuments, assetDocumentsVersion);
|
|
771
|
+
useEffect(() => {
|
|
772
|
+
const handleMutation = (rawEvent: Event) => {
|
|
773
|
+
applyAssetDocumentMutation(
|
|
774
|
+
documentId,
|
|
775
|
+
(rawEvent as CustomEvent<AssetDocumentMutation>).detail,
|
|
776
|
+
);
|
|
777
|
+
};
|
|
778
|
+
window.addEventListener('editor:asset-mutation', handleMutation);
|
|
779
|
+
return () => window.removeEventListener('editor:asset-mutation', handleMutation);
|
|
780
|
+
}, [documentId]);
|
|
781
|
+
const spec = _specs.get(documentId);
|
|
782
|
+
return (
|
|
783
|
+
<div
|
|
784
|
+
data-testid={`asset-document:${documentId}`}
|
|
785
|
+
style={{
|
|
786
|
+
flex: 1,
|
|
787
|
+
minHeight: 0,
|
|
788
|
+
overflow: 'hidden',
|
|
789
|
+
pointerEvents: 'auto',
|
|
790
|
+
background: bg[1],
|
|
791
|
+
}}
|
|
792
|
+
>
|
|
793
|
+
{spec ? (
|
|
794
|
+
<Suspense
|
|
795
|
+
fallback={
|
|
796
|
+
<div style={{ padding: 16, color: text[2], fontSize: 12 }}>Loading asset viewer…</div>
|
|
797
|
+
}
|
|
798
|
+
>
|
|
799
|
+
<AssetViewerBody id={documentId} spec={spec} active={active} />
|
|
800
|
+
</Suspense>
|
|
801
|
+
) : (
|
|
802
|
+
<div style={{ padding: 16, color: text[2], fontSize: 12 }}>
|
|
803
|
+
This asset document is no longer available.
|
|
804
|
+
</div>
|
|
805
|
+
)}
|
|
806
|
+
</div>
|
|
807
|
+
);
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
function normalizeAssetPath(path: string): string {
|
|
811
|
+
return path.split(/[?#]/, 1)[0]!.replace(/^\/+/, '');
|
|
812
|
+
}
|