@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,391 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boot routing — the FTUE design's §5 precedence ladder (unit G5, decision
|
|
3
|
+
* FT-7).
|
|
4
|
+
*
|
|
5
|
+
* Which surface does launching the editor land on? The design fixes the order:
|
|
6
|
+
*
|
|
7
|
+
* 1. An EXPLICIT target always wins, and it is always the SESSION —
|
|
8
|
+
* `vgai edit <path>` / `VGAI_PROJECT` / the project browser all re-root
|
|
9
|
+
* the server, and the client asks it (rung 1b below). The hub never
|
|
10
|
+
* renders. (Already true before G5; preserved here as the first rung so
|
|
11
|
+
* the whole ladder reads in one place.)
|
|
12
|
+
* 2. REOPEN-LAST, when the user has opted in — the analog of Unreal's
|
|
13
|
+
* "Always load last project on startup" checkbox in the Project Browser
|
|
14
|
+
* corner. Default OFF: a launcher that silently swallows its own front
|
|
15
|
+
* door on first launch is worse than one extra click.
|
|
16
|
+
* 3. Otherwise the HUB — which renders recents-first for a returning user and
|
|
17
|
+
* gallery-forward when recents are empty (that split is the hub's own,
|
|
18
|
+
* keyed off the same emptiness this module reports, not a separate flag).
|
|
19
|
+
*
|
|
20
|
+
* The ESCAPE HATCH is part of the contract, not a nicety: `?hub=1` forces the
|
|
21
|
+
* hub even with reopen-last enabled, and a project that fails to open must fall
|
|
22
|
+
* back to the hub rather than trapping the user in a boot loop. Unreal behaves
|
|
23
|
+
* the same way — the browser reappears when the last project cannot load. The
|
|
24
|
+
* failure half lives at the call site (it already routes open errors to the hub
|
|
25
|
+
* via `startupFailure`); this module owns the decision that precedes it.
|
|
26
|
+
*
|
|
27
|
+
* Kept as a PURE function on purpose. Boot order is the kind of thing that is
|
|
28
|
+
* miserable to prove through a real browser and trivial to prove as data in,
|
|
29
|
+
* decision out — which also keeps it off the e2e suite, per the repo's
|
|
30
|
+
* pillars-only policy.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import { ProjectCompatibilityError } from '@volter/editor-sdk/session/editor-compatibility';
|
|
34
|
+
|
|
35
|
+
/** The minimum a recents entry must carry for routing. The real
|
|
36
|
+
* `RecentProject` (editor-api.ts) carries more; routing needs only the path,
|
|
37
|
+
* and narrowing the input keeps this module free of transport types. */
|
|
38
|
+
export interface BootRoutingRecent {
|
|
39
|
+
path: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface BootRoutingInput {
|
|
43
|
+
/** The project the launch named, already resolved by the caller: the
|
|
44
|
+
* session's own. Null when the launch named no project. */
|
|
45
|
+
explicitTarget: string | null;
|
|
46
|
+
/** `?hub=1` was present: the user explicitly asked for the front door. */
|
|
47
|
+
hubRequested: boolean;
|
|
48
|
+
/** The persisted, default-off "Reopen last project on launch" preference. */
|
|
49
|
+
reopenLastEnabled: boolean;
|
|
50
|
+
/** Recents, most-recent-first — the same order the launcher renders. */
|
|
51
|
+
recents: readonly BootRoutingRecent[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export type BootTarget =
|
|
55
|
+
| { kind: 'explicit'; path: string }
|
|
56
|
+
| { kind: 'reopen-last'; path: string }
|
|
57
|
+
| { kind: 'hub'; firstRun: boolean };
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Resolve where a launch lands. See the module docstring for the ladder.
|
|
61
|
+
*
|
|
62
|
+
* `firstRun` on the hub result is the design's new-vs-returning signal (§7):
|
|
63
|
+
* emptiness of the recents list, deliberately NOT an account, a flag, or
|
|
64
|
+
* telemetry — it degrades gracefully across machines and clean checkouts, and
|
|
65
|
+
* it is the same signal all three reference engines effectively key off.
|
|
66
|
+
*/
|
|
67
|
+
export function resolveBootTarget(input: BootRoutingInput): BootTarget {
|
|
68
|
+
if (input.explicitTarget) {
|
|
69
|
+
return { kind: 'explicit', path: input.explicitTarget };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const firstRun = input.recents.length === 0;
|
|
73
|
+
|
|
74
|
+
// `?hub=1` outranks the preference — that is the whole point of an escape
|
|
75
|
+
// hatch. Checked before reopen-last, never after.
|
|
76
|
+
if (!input.hubRequested && input.reopenLastEnabled) {
|
|
77
|
+
const mostRecent = input.recents[0];
|
|
78
|
+
// Opted in but nothing to reopen (fresh machine, or every remembered
|
|
79
|
+
// project has since been deleted — `loadRecentProjects` drops those) is
|
|
80
|
+
// not an error state: it is simply a first run.
|
|
81
|
+
if (mostRecent) return { kind: 'reopen-last', path: mostRecent.path };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return { kind: 'hub', firstRun };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Rung 1b — what the SERVER is serving.
|
|
89
|
+
*
|
|
90
|
+
* A dev server started for a project knows exactly which project that is, so a
|
|
91
|
+
* browser hitting its bare origin must land in THAT project. The launcher is
|
|
92
|
+
* legitimate for one reason only: the server answered that it has no project
|
|
93
|
+
* open. Everything else — an unreachable/failed `/__editor/project`, a
|
|
94
|
+
* malformed answer, a server that IS serving a project whose manifest it could
|
|
95
|
+
* not read — is "could not determine", and reading that as "no project" is what
|
|
96
|
+
* dropped a project-serving session's tab onto the hub while `vgai status` was
|
|
97
|
+
* still naming the project on that very port.
|
|
98
|
+
*
|
|
99
|
+
* Two failure shapes, kept apart because their remedies are:
|
|
100
|
+
* - `'unreadable'` — the server named the project it serves AND why it could
|
|
101
|
+
* not describe it (a broken `vgai.project.json`, typically). Nothing is
|
|
102
|
+
* flaky about it; retrying is a waste and the hub is a lie. Fail loudly,
|
|
103
|
+
* naming the path and the reason.
|
|
104
|
+
* - `'unknown'` — the ask itself failed (server mid-restart, a request lost
|
|
105
|
+
* under a cold Vite boot's connection pressure). Genuinely transient, so
|
|
106
|
+
* retry a bounded number of times before failing loudly.
|
|
107
|
+
*/
|
|
108
|
+
export type ServerProjectProbeStatus = 'project' | 'none' | 'unreadable' | 'unknown';
|
|
109
|
+
|
|
110
|
+
export interface ServerProjectBootInput {
|
|
111
|
+
status: ServerProjectProbeStatus;
|
|
112
|
+
/** 1-based attempt number for this boot. */
|
|
113
|
+
attempt: number;
|
|
114
|
+
/** How many probe attempts a boot may spend before giving up. */
|
|
115
|
+
maxAttempts: number;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export type ServerProjectBootAction =
|
|
119
|
+
/** The server named a project — open it. */
|
|
120
|
+
| 'open'
|
|
121
|
+
/** The server has no project: fall through to reopen-last, then the hub. */
|
|
122
|
+
| 'continue-ladder'
|
|
123
|
+
/** Transient; ask again. */
|
|
124
|
+
| 'retry'
|
|
125
|
+
/** Report loudly. NEVER the hub — the hub would claim a fact we don't have. */
|
|
126
|
+
| 'fail';
|
|
127
|
+
|
|
128
|
+
export function decideServerProjectBoot(input: ServerProjectBootInput): ServerProjectBootAction {
|
|
129
|
+
switch (input.status) {
|
|
130
|
+
case 'project':
|
|
131
|
+
return 'open';
|
|
132
|
+
case 'none':
|
|
133
|
+
return 'continue-ladder';
|
|
134
|
+
case 'unreadable':
|
|
135
|
+
return 'fail';
|
|
136
|
+
case 'unknown':
|
|
137
|
+
return input.attempt < input.maxAttempts ? 'retry' : 'fail';
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* The failure half of the same rung — what the boot surface must SAY.
|
|
143
|
+
*
|
|
144
|
+
* `decideServerProjectBoot` returns `'fail'`, and the residual measured after
|
|
145
|
+
* that fix was where the failure landed: the editor rendered the LAUNCHER with
|
|
146
|
+
* a banner over it, so a loud unreadable-manifest throw still looked like a
|
|
147
|
+
* fresh "What do you want to do?" to a human — or to an agent screenshotting
|
|
148
|
+
* the tab. Rendering is AppRoot's (`StartupErrorScreen`); this is the pure
|
|
149
|
+
* shaping of the two facts that surface must name: the project the server IS
|
|
150
|
+
* serving, and the server's own error string.
|
|
151
|
+
*/
|
|
152
|
+
export type ServerProjectFailure =
|
|
153
|
+
| { status: 'unreadable'; path: string; error: string }
|
|
154
|
+
| { status: 'unknown'; error: string };
|
|
155
|
+
|
|
156
|
+
export interface ServerProjectFailureReport {
|
|
157
|
+
/** Heading for the error surface. Never the launcher's wording. */
|
|
158
|
+
title: string;
|
|
159
|
+
/** The project the server named, or null when it could not be asked. */
|
|
160
|
+
projectPath: string | null;
|
|
161
|
+
/** The server's own error string, verbatim — never paraphrased. */
|
|
162
|
+
detail: string;
|
|
163
|
+
/** One line naming both facts; used as the thrown Error's message. */
|
|
164
|
+
summary: string;
|
|
165
|
+
/** Whether asking again could plausibly help (server mid-restart). */
|
|
166
|
+
retryable: boolean;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function describeServerProjectFailure(
|
|
170
|
+
failure: ServerProjectFailure,
|
|
171
|
+
): ServerProjectFailureReport {
|
|
172
|
+
if (failure.status === 'unreadable') {
|
|
173
|
+
return {
|
|
174
|
+
title: 'This project could not be read',
|
|
175
|
+
projectPath: failure.path,
|
|
176
|
+
detail: failure.error,
|
|
177
|
+
summary: `The editor server is serving ${failure.path}, but could not read its project: ${failure.error}`,
|
|
178
|
+
// Nothing is flaky about a broken manifest: the same ask returns the
|
|
179
|
+
// same answer until a file changes. Retry is still OFFERED (the fix is
|
|
180
|
+
// an edit away, and re-asking is how you confirm it) — this flag says
|
|
181
|
+
// the failure is not transient, not that the button is useless.
|
|
182
|
+
retryable: false,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
title: 'Could not reach the editor server',
|
|
187
|
+
projectPath: null,
|
|
188
|
+
detail: failure.error,
|
|
189
|
+
summary:
|
|
190
|
+
`Could not ask the editor server which project it is serving (${failure.error}). ` +
|
|
191
|
+
'The server may still be starting — retry in a moment.',
|
|
192
|
+
retryable: true,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* A boot failure carrying its report. `message` is the same single line the
|
|
198
|
+
* pre-report code threw, so every caller that only reads the message is
|
|
199
|
+
* unchanged; the surface that can do better reads `report`.
|
|
200
|
+
*/
|
|
201
|
+
export class ServerProjectDetectionError extends Error {
|
|
202
|
+
constructor(readonly report: ServerProjectFailureReport) {
|
|
203
|
+
super(report.summary);
|
|
204
|
+
this.name = 'ServerProjectDetectionError';
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* A detection attempt that ran out of patience rather than getting an answer.
|
|
210
|
+
*
|
|
211
|
+
* Its own class, not a message, because the recovery decision below reads the
|
|
212
|
+
* SHAPE: "we did not get an answer yet" and "the server answered, badly" have
|
|
213
|
+
* opposite remedies, and telling them apart by string is how a deadline
|
|
214
|
+
* silently becomes a verdict.
|
|
215
|
+
*/
|
|
216
|
+
export class ProjectDetectionTimeoutError extends Error {
|
|
217
|
+
constructor(readonly waitedMs: number) {
|
|
218
|
+
super(
|
|
219
|
+
`Project detection has not answered in ${Math.round(waitedMs / 1000)}s. ` +
|
|
220
|
+
'The editor server may still be starting.',
|
|
221
|
+
);
|
|
222
|
+
this.name = 'ProjectDetectionTimeoutError';
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* What to do when project detection FAILED — keep asking, or stop and say so.
|
|
228
|
+
*
|
|
229
|
+
* The measured defect (2026-08-10): the detection deadline was calibrated on
|
|
230
|
+
* the warm case (a pair of local fetches, milliseconds), and on the FIRST boot
|
|
231
|
+
* of a fresh checkout — where Vite transforms the editor graph cold — it
|
|
232
|
+
* legitimately elapsed. The elapsed deadline was then promoted to a VERDICT: a
|
|
233
|
+
* terminal error screen with no listener and no state reports, on a tab whose
|
|
234
|
+
* heartbeat, echo and socket were all perfectly healthy. A deadline decorrelates
|
|
235
|
+
* from the truth exactly on the cold case it was never measured against, so a
|
|
236
|
+
* deadline may pace a retry and must never end one.
|
|
237
|
+
*
|
|
238
|
+
* The split, therefore, is on whether the server gave a DEFINITE answer. Three
|
|
239
|
+
* patient shapes, and they are the WHOLE list — each one named against the door
|
|
240
|
+
* it actually comes through, because the first cut of this function got that
|
|
241
|
+
* wrong (see below):
|
|
242
|
+
* - `ProjectDetectionTimeoutError` — the ask ran out of patience.
|
|
243
|
+
* - `ServerProjectDetectionError` with `report.retryable` — the PROJECT probe
|
|
244
|
+
* (`GET /__editor/project`) could not be asked.
|
|
245
|
+
* - `ProjectCompatibilityError` with `recovery.kind === 'retry-editor'` — the
|
|
246
|
+
* COMPATIBILITY handshake could not be asked. `detectServerProject` runs that
|
|
247
|
+
* handshake BEFORE the probe loop, so on a refused/reset socket or a 5xx this
|
|
248
|
+
* is the shape that actually reaches this function, in milliseconds, and the
|
|
249
|
+
* probe's own retryable report never gets a chance to exist. The first cut
|
|
250
|
+
* dropped it into the default branch and shipped a comment claiming a
|
|
251
|
+
* mid-restart server was patient — it was terminal, and the unit test missed
|
|
252
|
+
* it by constructing the retryable report by hand instead of driving a failing
|
|
253
|
+
* fetch. The recovery kind is the server's own word for "I could not be
|
|
254
|
+
* reached, try again" (`editorServerUnavailableError`), which is precisely
|
|
255
|
+
* this branch's question.
|
|
256
|
+
*
|
|
257
|
+
* Everything else is a definite answer and stays terminal: an unreadable
|
|
258
|
+
* manifest, and every OTHER compatibility recovery kind — `restart-editor`,
|
|
259
|
+
* `use-compatible-editor` — each of which names an action
|
|
260
|
+
* only the user can take. The same ask returns the same answer until a file
|
|
261
|
+
* changes or a command is run, so a spinner would be a lie.
|
|
262
|
+
*
|
|
263
|
+
* TERMINAL IS THE DEFAULT: only the shapes named above are patient, so a new
|
|
264
|
+
* error type cannot quietly acquire an infinite spinner.
|
|
265
|
+
*/
|
|
266
|
+
export type ProjectDetectionRecovery =
|
|
267
|
+
| { kind: 'retry'; delayMs: number }
|
|
268
|
+
| { kind: 'terminal'; reason: 'definite-answer' };
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Backoff for the patient path. The first retry is immediate (a cold Vite boot
|
|
272
|
+
* that lost one request usually answers the next one), then it settles into a
|
|
273
|
+
* few-second poll and CAPS — the wait is unbounded in total, so the interval
|
|
274
|
+
* must not grow without bound or a server that came back at minute three would
|
|
275
|
+
* sit unnoticed for another minute.
|
|
276
|
+
*
|
|
277
|
+
* `failures` is 1-based: the delay AFTER the nth consecutive failure.
|
|
278
|
+
*/
|
|
279
|
+
export const PROJECT_DETECTION_RETRY_MAX_DELAY_MS = 15_000;
|
|
280
|
+
|
|
281
|
+
export function projectDetectionRetryDelayMs(failures: number): number {
|
|
282
|
+
if (failures <= 1) return 0;
|
|
283
|
+
return Math.min((failures - 1) * 5_000, PROJECT_DETECTION_RETRY_MAX_DELAY_MS);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export function decideProjectDetectionRecovery(
|
|
287
|
+
error: unknown,
|
|
288
|
+
failures: number,
|
|
289
|
+
): ProjectDetectionRecovery {
|
|
290
|
+
if (error instanceof ProjectDetectionTimeoutError) {
|
|
291
|
+
return { kind: 'retry', delayMs: projectDetectionRetryDelayMs(failures) };
|
|
292
|
+
}
|
|
293
|
+
// The probe's own two shapes already carry this judgement (`retryable`):
|
|
294
|
+
// 'unknown' is "could not ask", 'unreadable' is the server's definite answer.
|
|
295
|
+
if (error instanceof ServerProjectDetectionError && error.report.retryable) {
|
|
296
|
+
return { kind: 'retry', delayMs: projectDetectionRetryDelayMs(failures) };
|
|
297
|
+
}
|
|
298
|
+
// The compatibility handshake runs FIRST, so this — not the probe report
|
|
299
|
+
// above — is the shape an unreachable or restarting server produces.
|
|
300
|
+
if (error instanceof ProjectCompatibilityError && error.recovery.kind === 'retry-editor') {
|
|
301
|
+
return { kind: 'retry', delayMs: projectDetectionRetryDelayMs(failures) };
|
|
302
|
+
}
|
|
303
|
+
return { kind: 'terminal', reason: 'definite-answer' };
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/** Read the `?hub` escape hatch off a query string. Present-and-not-"0" wins,
|
|
307
|
+
* so `?hub`, `?hub=1`, and `?hub=true` all work — a user typing this into the
|
|
308
|
+
* address bar to escape a bad auto-reopen should not have to guess a spelling. */
|
|
309
|
+
export function hubRequestedFromSearch(search: string): boolean {
|
|
310
|
+
const raw = new URLSearchParams(search).get('hub');
|
|
311
|
+
if (raw === null) return false;
|
|
312
|
+
return raw !== '0' && raw.toLowerCase() !== 'false';
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// ---------------------------------------------------------------------------
|
|
316
|
+
// Removed boot params
|
|
317
|
+
// ---------------------------------------------------------------------------
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* The one boot-param gate, run before the session's project is resolved.
|
|
321
|
+
*
|
|
322
|
+
* Three removals, one guard — the `assertNoRemoved*` shape the repo uses for
|
|
323
|
+
* every retired format/param (legacy-removal doctrine, docs/ARCHITECTURE-CORE.md
|
|
324
|
+
* §Vocabulary "how content opens"). A removed boot param must never fall
|
|
325
|
+
* through silently; it errors naming the mechanism that replaced it.
|
|
326
|
+
*
|
|
327
|
+
* 1. `?project=`. Project identity lives in the SESSION: the editor server
|
|
328
|
+
* holds "which project is open" as server-side state
|
|
329
|
+
* (`GET /__editor/project`, re-rooted by `POST /__editor/open-project`),
|
|
330
|
+
* the client boots by ASKING it, and the URL is BARE. That is why a
|
|
331
|
+
* refresh — or a tab-heal navigation back to the bare origin — reopens the
|
|
332
|
+
* same project, exactly like a VS Code window. There is no surface where
|
|
333
|
+
* the URL names the project instead.
|
|
334
|
+
*
|
|
335
|
+
* 2. `?ingest=`. A vendored game is a PROJECT — every one carries its own
|
|
336
|
+
* `vgai.project.json` — so opening one is opening a project, and it opens
|
|
337
|
+
* through the session like every other (the gallery's Imported group
|
|
338
|
+
* re-roots the server at the game's manifest folder; the manifest ingest
|
|
339
|
+
* route mounts it). A param that names the MECHANISM ("ingest") rather than
|
|
340
|
+
* the thing being opened is exactly what §Vocabulary forbids.
|
|
341
|
+
*
|
|
342
|
+
* 3. `?scene=<path>`: the FLAT SCENE POOL it names is gone. There is
|
|
343
|
+
* deliberately no silent boot-time rewrite for it — a redirect is a second
|
|
344
|
+
* way to say the same thing, and a rewrite table rots into a redirect to
|
|
345
|
+
* nowhere.
|
|
346
|
+
*
|
|
347
|
+
* Pure over a search string, so it is readable without a window. Returns
|
|
348
|
+
* normally when the URL names nothing removed.
|
|
349
|
+
*/
|
|
350
|
+
export function assertNoRemovedBootParams(search: string): void {
|
|
351
|
+
const params = new URLSearchParams(search);
|
|
352
|
+
const project = params.get('project');
|
|
353
|
+
|
|
354
|
+
if (project !== null) {
|
|
355
|
+
throw new Error(
|
|
356
|
+
`Editor boot: \`?project=${project}\` — project identity does NOT live in the URL on a ` +
|
|
357
|
+
'local editor. It lives in the SESSION (the legacy-removal doctrine, ' +
|
|
358
|
+
'docs/ARCHITECTURE-CORE.md §Vocabulary "how content opens"). The local editor server ' +
|
|
359
|
+
'holds which project is open as server-side state, which is why this URL is bare and a ' +
|
|
360
|
+
'refresh reopens the same project — like a VS Code window.\n' +
|
|
361
|
+
'Fix: open the project THROUGH the session — run `volter-editor edit <path>`, or use the ' +
|
|
362
|
+
"editor's own project browser; both re-root this server via POST /__editor/open-project. " +
|
|
363
|
+
'There is no surface where the URL names the project instead.',
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const ingest = params.get('ingest');
|
|
368
|
+
if (ingest !== null) {
|
|
369
|
+
throw new Error(
|
|
370
|
+
`Editor boot: \`?ingest=${ingest}\` — REMOVED. A vendored game carries its own ` +
|
|
371
|
+
'`vgai.project.json`, so it IS a project, and there is ONE boot param for opening a ' +
|
|
372
|
+
'project. A param naming the MECHANISM rather than the thing being opened is what the ' +
|
|
373
|
+
'legacy-removal doctrine forbids (docs/ARCHITECTURE-CORE.md §Vocabulary "how content ' +
|
|
374
|
+
'opens").\n' +
|
|
375
|
+
`Fix: open the game folder through the SESSION — \`volter-editor edit <path-to-the-game-folder>\`, ` +
|
|
376
|
+
"or the New Project screen's IMPORTED group, which re-roots this server via " +
|
|
377
|
+
'POST /__editor/open-project at that folder; the manifest ingest route then mounts it.',
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const scene = params.get('scene');
|
|
382
|
+
if (scene !== null) {
|
|
383
|
+
throw new Error(
|
|
384
|
+
`Editor boot: \`?scene=${scene}\` — the flat scene pool it names was REMOVED, and so ` +
|
|
385
|
+
'was the redirect that rewrote these links (the legacy-removal ' +
|
|
386
|
+
'doctrine, docs/ARCHITECTURE-CORE.md §Vocabulary).\n' +
|
|
387
|
+
'Fix: open the project through the session (`volter-editor edit <path>`) and open the document ' +
|
|
388
|
+
'inside it.',
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { EditorServerCompatibility } from '@volter/editor-sdk/session/editor-compatibility';
|
|
2
|
+
import enginePackage from '@volter/editor-project/package.json';
|
|
3
|
+
import { GAME_MANIFEST_VERSION } from '@volter/editor-project/manifest/schema';
|
|
4
|
+
import editorPackage from '../package.json';
|
|
5
|
+
|
|
6
|
+
/** Build-time package identity shared by browser-only editor surfaces. */
|
|
7
|
+
export const BUNDLED_EDITOR_VERSION = editorPackage.version;
|
|
8
|
+
export const BUNDLED_ENGINE_VERSION = enginePackage.version;
|
|
9
|
+
export const BUNDLED_EDITOR_COMPATIBILITY: EditorServerCompatibility = {
|
|
10
|
+
apiVersion: 1,
|
|
11
|
+
engineVersion: BUNDLED_ENGINE_VERSION,
|
|
12
|
+
manifestVersion: GAME_MANIFEST_VERSION,
|
|
13
|
+
startedAt: 'browser-build',
|
|
14
|
+
source: { state: 'current' },
|
|
15
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The editor's byte codecs: content hashing, and the base64 wire encoding the
|
|
3
|
+
* dev server's save routes speak.
|
|
4
|
+
*
|
|
5
|
+
* Both functions existed as three private copies each, and both sets had
|
|
6
|
+
* already drifted — one `sha256Hex` copy hashed the wrong bytes for a
|
|
7
|
+
* subarray, one `bytesToBase64` copy blew the call stack on a large file. Each
|
|
8
|
+
* function below carries the constraint its copies disagreed about; that
|
|
9
|
+
* constraint is the reason this module exists, so keep the comment with the
|
|
10
|
+
* code.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* sha256 of `bytes`, lowercase hex — Web Crypto, available in every browser
|
|
15
|
+
* this editor supports and in Node ≥ 20's `globalThis.crypto`.
|
|
16
|
+
*
|
|
17
|
+
* `crypto.subtle.digest` hashes a whole `ArrayBuffer`, never a view's range: a
|
|
18
|
+
* `Uint8Array` with a non-zero `byteOffset` (or one shorter than its buffer)
|
|
19
|
+
* whose `.buffer` is handed over directly hashes its NEIGHBOURS too, and the
|
|
20
|
+
* digest then matches nothing. Only a view spanning its entire buffer may pass
|
|
21
|
+
* the buffer through; everything else copies its own range out first.
|
|
22
|
+
*
|
|
23
|
+
* The argument is narrowed to a real `ArrayBuffer` rather than the DOM lib's
|
|
24
|
+
* `BufferSource`, so the types here need no browser lib either — the
|
|
25
|
+
* "runs anywhere" promise is about runtime, and a DOM-only type name would
|
|
26
|
+
* quietly break it for a Node-side consumer.
|
|
27
|
+
*/
|
|
28
|
+
export async function sha256Hex(bytes: Uint8Array): Promise<string> {
|
|
29
|
+
const source =
|
|
30
|
+
bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength
|
|
31
|
+
? (bytes.buffer as ArrayBuffer)
|
|
32
|
+
: (bytes.slice().buffer as ArrayBuffer);
|
|
33
|
+
const digest = await crypto.subtle.digest('SHA-256', source);
|
|
34
|
+
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, '0')).join('');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* base64-encode `bytes` for the save routes' `encoding: 'base64'` mode, which
|
|
39
|
+
* is what the server's `Buffer.from(…, 'base64')` speaks on the other end.
|
|
40
|
+
*
|
|
41
|
+
* The walk is CHUNKED on purpose. `String.fromCharCode(...bytes)` on a 2.3 MB
|
|
42
|
+
* level file is a 2.3-million-argument spread and throws
|
|
43
|
+
* `RangeError: Maximum call stack size exceeded`; a per-byte `+=` loop avoids
|
|
44
|
+
* the spread but is quadratic on the same input. 0x8000 is the block size that
|
|
45
|
+
* stays inside every engine's argument limit.
|
|
46
|
+
*/
|
|
47
|
+
export function bytesToBase64(bytes: Uint8Array): string {
|
|
48
|
+
let binary = '';
|
|
49
|
+
const CHUNK = 0x8000;
|
|
50
|
+
for (let offset = 0; offset < bytes.byteLength; offset += CHUNK) {
|
|
51
|
+
binary += String.fromCharCode(...bytes.subarray(offset, offset + CHUNK));
|
|
52
|
+
}
|
|
53
|
+
return btoa(binary);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The inverse of {@link bytesToBase64}, via the platform's own `atob`. */
|
|
57
|
+
export function base64ToBytes(source: string): Uint8Array {
|
|
58
|
+
const binary = atob(source);
|
|
59
|
+
const bytes = new Uint8Array(binary.length);
|
|
60
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
61
|
+
return bytes;
|
|
62
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import type * as THREE from 'three';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Transient camera-authoring presentation for the Scene viewport.
|
|
5
|
+
*
|
|
6
|
+
* Cameras remain ordinary native Three.js objects owned by the active
|
|
7
|
+
* AuthoringAdapter. This module carries only viewport presentation (pin,
|
|
8
|
+
* view-through, pilot) and delegates every authored mutation to the host's
|
|
9
|
+
* canonical transform gesture path. There is no camera document or sidecar.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export type CameraViewMode = 'view' | 'pilot';
|
|
13
|
+
|
|
14
|
+
export interface CameraAuthoringSubject {
|
|
15
|
+
readonly id: string;
|
|
16
|
+
readonly name: string;
|
|
17
|
+
readonly camera: THREE.Camera;
|
|
18
|
+
readonly lens: string;
|
|
19
|
+
/** Position and rotation can both enter the adapter's normal edit gesture. */
|
|
20
|
+
readonly canAuthorPose: boolean;
|
|
21
|
+
readonly poseRefusal?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface CameraAuthoringPresentation {
|
|
25
|
+
readonly preview: CameraAuthoringSubject | null;
|
|
26
|
+
readonly previewPinned: boolean;
|
|
27
|
+
readonly view: {
|
|
28
|
+
readonly mode: CameraViewMode;
|
|
29
|
+
readonly subject: CameraAuthoringSubject;
|
|
30
|
+
} | null;
|
|
31
|
+
readonly guidesVisible: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface CameraAuthoringHost {
|
|
35
|
+
/** Camera authoring is an Edit/Scene affordance, never a Play overlay. */
|
|
36
|
+
readonly active: () => boolean;
|
|
37
|
+
readonly selected: () => CameraAuthoringSubject | null;
|
|
38
|
+
readonly resolve: (id: string) => CameraAuthoringSubject | null;
|
|
39
|
+
readonly showView: (subject: CameraAuthoringSubject, mode: CameraViewMode) => void;
|
|
40
|
+
readonly leaveView: () => void;
|
|
41
|
+
readonly alignToViewport: (subject: CameraAuthoringSubject) => void;
|
|
42
|
+
readonly subscribe: (listener: () => void) => () => void;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let host: CameraAuthoringHost | null = null;
|
|
46
|
+
let disposeHostSubscription: (() => void) | null = null;
|
|
47
|
+
let pinnedId: string | null = null;
|
|
48
|
+
let viewState: { id: string; mode: CameraViewMode; camera: THREE.Camera } | null = null;
|
|
49
|
+
let guidesVisible = true;
|
|
50
|
+
let version = 0;
|
|
51
|
+
const listeners = new Set<() => void>();
|
|
52
|
+
|
|
53
|
+
function notify(): void {
|
|
54
|
+
version++;
|
|
55
|
+
for (const listener of listeners) listener();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function syncHostState(): void {
|
|
59
|
+
if (!host) return;
|
|
60
|
+
if (!host.active()) {
|
|
61
|
+
if (viewState) host.leaveView();
|
|
62
|
+
viewState = null;
|
|
63
|
+
notify();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (pinnedId && !host.resolve(pinnedId)) pinnedId = null;
|
|
67
|
+
if (viewState) {
|
|
68
|
+
const subject = host.resolve(viewState.id);
|
|
69
|
+
if (!subject) {
|
|
70
|
+
viewState = null;
|
|
71
|
+
host.leaveView();
|
|
72
|
+
} else if (subject.camera !== viewState.camera) {
|
|
73
|
+
// HMR may replace the native camera while preserving its semantic id.
|
|
74
|
+
// Rebind the transient view to the fresh object rather than retaining a
|
|
75
|
+
// dead Three.js reference.
|
|
76
|
+
viewState = { ...viewState, camera: subject.camera };
|
|
77
|
+
host.showView(subject, viewState.mode);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
notify();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Install the one live Scene viewport host. The returned disposer is
|
|
84
|
+
* identity-guarded so a stale unmount cannot clear a newer viewport. */
|
|
85
|
+
export function installCameraAuthoringHost(next: CameraAuthoringHost): () => void {
|
|
86
|
+
disposeHostSubscription?.();
|
|
87
|
+
host?.leaveView();
|
|
88
|
+
host = next;
|
|
89
|
+
pinnedId = null;
|
|
90
|
+
viewState = null;
|
|
91
|
+
guidesVisible = true;
|
|
92
|
+
disposeHostSubscription = next.subscribe(syncHostState);
|
|
93
|
+
notify();
|
|
94
|
+
return () => {
|
|
95
|
+
if (host !== next) return;
|
|
96
|
+
disposeHostSubscription?.();
|
|
97
|
+
disposeHostSubscription = null;
|
|
98
|
+
next.leaveView();
|
|
99
|
+
host = null;
|
|
100
|
+
pinnedId = null;
|
|
101
|
+
viewState = null;
|
|
102
|
+
guidesVisible = true;
|
|
103
|
+
notify();
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function subscribeCameraAuthoring(listener: () => void): () => void {
|
|
108
|
+
listeners.add(listener);
|
|
109
|
+
return () => listeners.delete(listener);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function cameraAuthoringVersion(): number {
|
|
113
|
+
return version;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function cameraAuthoringPresentation(): CameraAuthoringPresentation {
|
|
117
|
+
if (!host?.active()) {
|
|
118
|
+
return { preview: null, previewPinned: false, view: null, guidesVisible };
|
|
119
|
+
}
|
|
120
|
+
const selected = host?.selected() ?? null;
|
|
121
|
+
const pinned = pinnedId ? (host?.resolve(pinnedId) ?? null) : null;
|
|
122
|
+
const viewSubject = viewState ? (host?.resolve(viewState.id) ?? null) : null;
|
|
123
|
+
return {
|
|
124
|
+
preview: viewSubject ? null : (pinned ?? selected),
|
|
125
|
+
previewPinned: Boolean(pinned),
|
|
126
|
+
view: viewState && viewSubject ? { mode: viewState.mode, subject: viewSubject } : null,
|
|
127
|
+
guidesVisible,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function currentCameraAuthoringSubject(): CameraAuthoringSubject | null {
|
|
132
|
+
const presentation = cameraAuthoringPresentation();
|
|
133
|
+
return presentation.view?.subject ?? presentation.preview;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function toggleCameraPreviewPin(): void {
|
|
137
|
+
const presentation = cameraAuthoringPresentation();
|
|
138
|
+
const subject = presentation.preview;
|
|
139
|
+
if (!subject) return;
|
|
140
|
+
pinnedId = presentation.previewPinned ? null : subject.id;
|
|
141
|
+
notify();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function viewThroughCamera(subject = currentCameraAuthoringSubject()): void {
|
|
145
|
+
if (!host || !subject) return;
|
|
146
|
+
if (viewState) host.leaveView();
|
|
147
|
+
viewState = { id: subject.id, mode: 'view', camera: subject.camera };
|
|
148
|
+
host.showView(subject, 'view');
|
|
149
|
+
notify();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function pilotCamera(subject = currentCameraAuthoringSubject()): void {
|
|
153
|
+
if (!host || !subject || !subject.canAuthorPose) return;
|
|
154
|
+
if (viewState) host.leaveView();
|
|
155
|
+
viewState = { id: subject.id, mode: 'pilot', camera: subject.camera };
|
|
156
|
+
host.showView(subject, 'pilot');
|
|
157
|
+
notify();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function alignCameraToViewport(subject = currentCameraAuthoringSubject()): void {
|
|
161
|
+
if (!host || !subject || !subject.canAuthorPose) return;
|
|
162
|
+
host.alignToViewport(subject);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function leaveCameraView(): void {
|
|
166
|
+
if (!host || !viewState) return;
|
|
167
|
+
viewState = null;
|
|
168
|
+
host.leaveView();
|
|
169
|
+
notify();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function toggleCameraCompositionGuides(): void {
|
|
173
|
+
guidesVisible = !guidesVisible;
|
|
174
|
+
notify();
|
|
175
|
+
}
|