@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,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE EDIT TAB ROW, as pure logic — what the adapter's scene table means for
|
|
3
|
+
* the workspace's open documents.
|
|
4
|
+
*
|
|
5
|
+
* ARCHITECTURE-CORE §Editor: "the scene table (entries, default, authorable
|
|
6
|
+
* flags, reach) is ONE adapter declaration with two clients — the Edit tab row
|
|
7
|
+
* projects it as isolation documents through the substrate family's piece
|
|
8
|
+
* mounts, and Play's `open()` walks it as live navigation." This module is the
|
|
9
|
+
* decision half of the FIRST client; `components/scene-documents.tsx` is the
|
|
10
|
+
* half that talks to the workspace registry, and `command-listener.ts`'s
|
|
11
|
+
* `open` verb resolves ONE entry through the very same table below — so the
|
|
12
|
+
* tab row and the verb can never disagree about what an entry is.
|
|
13
|
+
*
|
|
14
|
+
* ZERO INFERENCE. Every answer here is read off a DECLARED field of the
|
|
15
|
+
* entry — `authorable`, `reach`, `source`, `region`. Nothing is derived from a
|
|
16
|
+
* folder, a filename, a root, or the shape of the project: an entry the
|
|
17
|
+
* adapter did not declare simply is not here, and an entry it declared
|
|
18
|
+
* unreachable stays unreachable with the game's own reason attached.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import type { DocumentEntry, SceneSource } from '@volter/editor-project/adapter/adapter-module';
|
|
22
|
+
import type { ResolvedDocumentTable } from './project-adapter';
|
|
23
|
+
|
|
24
|
+
/** Document-id namespace for a per-scene isolation document. Distinct from
|
|
25
|
+
* `three-story:` ids (the story turntable, `@vgai/game`'s): a scene is
|
|
26
|
+
* reached through the entrypoint's own selection table, not through a story,
|
|
27
|
+
* and the two can legitimately name the same composition. */
|
|
28
|
+
export const SCENE_DOCUMENT_PREFIX = 'scene:';
|
|
29
|
+
|
|
30
|
+
/** The workspace document id for one entrypoint-selection scene entry. */
|
|
31
|
+
export function sceneDocumentId(entryId: string): string {
|
|
32
|
+
return `${SCENE_DOCUMENT_PREFIX}${entryId}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** A standing isolation tab — `scene:TitleScreen`, not `workspace:scene`. */
|
|
36
|
+
export function isIsolationSceneDocumentId(id: string): boolean {
|
|
37
|
+
return id.startsWith(SCENE_DOCUMENT_PREFIX);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* What the Edit workspace does with ONE scene-table entry.
|
|
42
|
+
*
|
|
43
|
+
* `no-document` is not a failure — a traversal entry and a declared-unreachable
|
|
44
|
+
* one are both honest table rows that simply own no Edit document. Its `reason`
|
|
45
|
+
* is the game's OWN sentence whenever the game supplied one (a `none` reach
|
|
46
|
+
* carries its `reason` verbatim), so a refusal quotes the adapter rather than
|
|
47
|
+
* paraphrasing it.
|
|
48
|
+
*/
|
|
49
|
+
export type SceneDocumentPlan =
|
|
50
|
+
/** Mounting the region IS opening this scene — it is the root's own standing
|
|
51
|
+
* document, which this entry merely NAMES. No second document. */
|
|
52
|
+
| { readonly kind: 'root-document'; readonly regionId: string; readonly title: string }
|
|
53
|
+
/** A viewport document of its own, mounting `source` in isolation. */
|
|
54
|
+
| {
|
|
55
|
+
readonly kind: 'isolation-document';
|
|
56
|
+
readonly documentId: string;
|
|
57
|
+
readonly title: string;
|
|
58
|
+
/** Owning root, carried into the document so its declared region — not
|
|
59
|
+
* its filename or export shape — decides the mounting surface. */
|
|
60
|
+
readonly regionId: string | null;
|
|
61
|
+
readonly source: SceneSource;
|
|
62
|
+
readonly isolationSetup?: SceneSource;
|
|
63
|
+
/** Present when this piece is also a running-game screen. Play's `open`
|
|
64
|
+
* still navigates live; Edit mounts the source in isolation and never
|
|
65
|
+
* holds the live host. */
|
|
66
|
+
readonly contractSceneId?: string;
|
|
67
|
+
}
|
|
68
|
+
/** A portable story mounts it — the existing story-document opener owns it. */
|
|
69
|
+
| { readonly kind: 'story-document'; readonly title: string; readonly storyId: string }
|
|
70
|
+
/**
|
|
71
|
+
* No Edit document, with the reason stated.
|
|
72
|
+
*
|
|
73
|
+
* `liveReach` separates "no document, and nothing else either" from "no
|
|
74
|
+
* document BECAUSE this scene is REACHED live" — the Edit workspace treats
|
|
75
|
+
* both the same (neither is a tab), while the `open` verb must route the
|
|
76
|
+
* second to the running game instead of refusing it, and must tell a caller
|
|
77
|
+
* with no game running to start one rather than that the scene is a dead end.
|
|
78
|
+
*
|
|
79
|
+
* Present means the live half REACHES this entry — it opens it and answers
|
|
80
|
+
* ok. Absent means it does not, which is two different things and
|
|
81
|
+
* deliberately one field: the live half may have no business with the entry
|
|
82
|
+
* at all (it answers `null` for `story`/`none`). A session that cannot
|
|
83
|
+
* remount still refuses `entrypoint-selection` coded; that is a session
|
|
84
|
+
* fact, not a reach fact — the intended path is remount-at-key and ends
|
|
85
|
+
* `ok: true`. {@link liveReachOf} is where that line is drawn.
|
|
86
|
+
*
|
|
87
|
+
* It is derived from REACH ALONE ({@link liveReachOf}), never from
|
|
88
|
+
* `authorable`, because the live half is the authority on this half of the
|
|
89
|
+
* question and it reads reach only (`scene-live-open.ts` switches on
|
|
90
|
+
* `entry.reach.kind`). A planner that also asked `authorable` here would call
|
|
91
|
+
* a screen the running game navigates to a dead end — the exact collapse this
|
|
92
|
+
* field exists to prevent.
|
|
93
|
+
*/
|
|
94
|
+
| {
|
|
95
|
+
readonly kind: 'no-document';
|
|
96
|
+
readonly reason: string;
|
|
97
|
+
readonly liveReach?: 'game-contract' | 'root-mount' | 'entrypoint-selection';
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* THE ONE DERIVATION of `liveReach`, from the entry's DECLARED reach and
|
|
102
|
+
* nothing else — never from `authorable`, so the two clients cannot disagree.
|
|
103
|
+
*
|
|
104
|
+
* It answers for exactly the reaches `openLiveSceneEntry` REACHES: it
|
|
105
|
+
* navigates a `game-contract` scene through the game's own contract, it
|
|
106
|
+
* shows the document a `root-mount` scene draws into, and it remounts play
|
|
107
|
+
* at an `entrypoint-selection` key. All three end `ok: true` when the
|
|
108
|
+
* session can honour them, so for all three the honest Edit-half refusal
|
|
109
|
+
* with nothing running is `SCENE_NAVIGATION_NOT_RUNNING` — start the game
|
|
110
|
+
* and ask again.
|
|
111
|
+
*
|
|
112
|
+
* A session that cannot remount still refuses `entrypoint-selection` with
|
|
113
|
+
* `SCENE_NOT_OPENABLE_LIVE` — that is the same shape as a `game-contract`
|
|
114
|
+
* scene whose running game publishes no contract (`SCENE_CONTRACT_UNAVAILABLE`).
|
|
115
|
+
* The field names the intended live path, not every session's ability to
|
|
116
|
+
* walk it.
|
|
117
|
+
*
|
|
118
|
+
* A spread rather than a value so `exactOptionalPropertyTypes` gets an ABSENT
|
|
119
|
+
* key for "no live reach", never an explicit `undefined`. Every `no-document`
|
|
120
|
+
* return below spreads it unconditionally — the two where it is currently
|
|
121
|
+
* provably empty included — so this function stays the SOLE decider and a
|
|
122
|
+
* later widening cannot leave a branch silently behind.
|
|
123
|
+
*/
|
|
124
|
+
function liveReachOf(entry: DocumentEntry): {
|
|
125
|
+
readonly liveReach?: 'game-contract' | 'root-mount' | 'entrypoint-selection';
|
|
126
|
+
} {
|
|
127
|
+
const { kind } = entry.reach;
|
|
128
|
+
return kind === 'game-contract' || kind === 'root-mount' || kind === 'entrypoint-selection'
|
|
129
|
+
? { liveReach: kind }
|
|
130
|
+
: {};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Plan ONE entry.
|
|
135
|
+
*
|
|
136
|
+
* Order matters: `authorable` is asked FIRST because a traversal entry
|
|
137
|
+
* (boot/loading choreography) earns no column whatever its reach — the flag is
|
|
138
|
+
* about what the entry IS, while reach is about how the running game gets
|
|
139
|
+
* there.
|
|
140
|
+
*
|
|
141
|
+
* That order decides the DOCUMENT, and only the document. `liveReach` is
|
|
142
|
+
* carried through it untouched: whether a running game can be sent to a screen
|
|
143
|
+
* is the game's contract's business, not the host's opinion of whether the
|
|
144
|
+
* screen is worth authoring, and the live half honours that by reading reach
|
|
145
|
+
* alone.
|
|
146
|
+
*/
|
|
147
|
+
export function planSceneDocument(entry: DocumentEntry): SceneDocumentPlan {
|
|
148
|
+
if (!entry.authorable) {
|
|
149
|
+
return {
|
|
150
|
+
kind: 'no-document',
|
|
151
|
+
...liveReachOf(entry),
|
|
152
|
+
reason:
|
|
153
|
+
`"${entry.id}" is declared TRAVERSAL (boot/loading choreography), not an authorable ` +
|
|
154
|
+
'composition, so it has no Edit document.',
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
switch (entry.reach.kind) {
|
|
158
|
+
case 'none':
|
|
159
|
+
// VERBATIM. The adapter wrote this sentence about its own game; a host
|
|
160
|
+
// paraphrase would be the host claiming to know why.
|
|
161
|
+
return { kind: 'no-document', ...liveReachOf(entry), reason: entry.reach.reason };
|
|
162
|
+
case 'root-mount':
|
|
163
|
+
return entry.region === null
|
|
164
|
+
? {
|
|
165
|
+
// Still LIVE-REACHED: `openLiveSceneEntry` shows the document the
|
|
166
|
+
// running game draws into and never looks at `region`, so the
|
|
167
|
+
// missing region costs this entry its Edit document and nothing
|
|
168
|
+
// else.
|
|
169
|
+
kind: 'no-document',
|
|
170
|
+
...liveReachOf(entry),
|
|
171
|
+
reason:
|
|
172
|
+
`"${entry.id}" is reached by mounting a region, but the entry names no region, ` +
|
|
173
|
+
'so there is no standing document it could be.',
|
|
174
|
+
}
|
|
175
|
+
: { kind: 'root-document', regionId: entry.region, title: entry.label };
|
|
176
|
+
case 'entrypoint-selection':
|
|
177
|
+
// ACTIVE means the entrypoint indexes its selection table with THIS key,
|
|
178
|
+
// so the region's standing document already mounts this composition —
|
|
179
|
+
// opening a second document for it would show the same thing twice under
|
|
180
|
+
// two titles. The entry names the standing document instead, exactly as
|
|
181
|
+
// `root-mount` does. A region-less entry keeps the isolation document:
|
|
182
|
+
// there is no honest mapping from "active" to a document without one, and
|
|
183
|
+
// inventing a region is what zero-inference forbids.
|
|
184
|
+
if (entry.reach.active === true && entry.region !== null) {
|
|
185
|
+
return { kind: 'root-document', regionId: entry.region, title: entry.label };
|
|
186
|
+
}
|
|
187
|
+
return entry.source
|
|
188
|
+
? {
|
|
189
|
+
kind: 'isolation-document',
|
|
190
|
+
documentId: sceneDocumentId(entry.id),
|
|
191
|
+
title: entry.label,
|
|
192
|
+
regionId: entry.region,
|
|
193
|
+
source: entry.source,
|
|
194
|
+
...(entry.isolationSetup ? { isolationSetup: entry.isolationSetup } : {}),
|
|
195
|
+
}
|
|
196
|
+
: {
|
|
197
|
+
kind: 'no-document',
|
|
198
|
+
...liveReachOf(entry),
|
|
199
|
+
reason:
|
|
200
|
+
`"${entry.id}" is selected at the entrypoint's \`${entry.reach.selection}\` slot, ` +
|
|
201
|
+
'but the finder could not resolve the module it names, so there is nothing to ' +
|
|
202
|
+
'mount in isolation.',
|
|
203
|
+
};
|
|
204
|
+
case 'game-contract':
|
|
205
|
+
// Authorable + a source module is an Edit piece: every authorable scene
|
|
206
|
+
// gets a tab (ARCHITECTURE-CORE §Editor). Play still navigates live
|
|
207
|
+
// through `liveReach`. Without a source there is nothing to isolate, so
|
|
208
|
+
// Edit stays silent and `open` asks the running game.
|
|
209
|
+
return entry.source
|
|
210
|
+
? {
|
|
211
|
+
kind: 'isolation-document',
|
|
212
|
+
documentId: sceneDocumentId(entry.id),
|
|
213
|
+
title: entry.label,
|
|
214
|
+
regionId: entry.region,
|
|
215
|
+
source: entry.source,
|
|
216
|
+
...(entry.isolationSetup ? { isolationSetup: entry.isolationSetup } : {}),
|
|
217
|
+
contractSceneId: entry.reach.sceneId,
|
|
218
|
+
}
|
|
219
|
+
: {
|
|
220
|
+
kind: 'no-document',
|
|
221
|
+
...liveReachOf(entry),
|
|
222
|
+
reason:
|
|
223
|
+
`"${entry.id}" is reached only through the running game's own navigation ` +
|
|
224
|
+
`(its scenes contract calls it "${entry.reach.sceneId}"), and the entry names no ` +
|
|
225
|
+
'source module, so there is no Edit document — open it while the game is running.',
|
|
226
|
+
};
|
|
227
|
+
case 'story':
|
|
228
|
+
return { kind: 'story-document', title: entry.label, storyId: entry.reach.storyId };
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** One row of the Edit tab row. */
|
|
233
|
+
export interface SceneTabRow {
|
|
234
|
+
readonly entry: DocumentEntry;
|
|
235
|
+
/** Never `no-document` — a row that owns no document is not a tab. */
|
|
236
|
+
readonly plan: Exclude<SceneDocumentPlan, { kind: 'no-document' }>;
|
|
237
|
+
/** The table's declared default entry. At most one row carries it. */
|
|
238
|
+
readonly isDefault: boolean;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* The whole Edit tab row: every AUTHORABLE SCENE the table declares that owns
|
|
243
|
+
* a document, in the table's own order.
|
|
244
|
+
*
|
|
245
|
+
* Prefabs are excluded deliberately, and they are not second-class for it: a
|
|
246
|
+
* prefab already surfaces through the boards and Content, and it opens as a
|
|
247
|
+
* sibling document on demand through the same verb (`open`). What a standing
|
|
248
|
+
* TAB means is "this is one of the game's scenes", which is exactly the
|
|
249
|
+
* `kind: 'scene'` declaration.
|
|
250
|
+
*/
|
|
251
|
+
export function sceneTabRow(table: ResolvedDocumentTable): readonly SceneTabRow[] {
|
|
252
|
+
const rows: SceneTabRow[] = [];
|
|
253
|
+
for (const entry of table.entries) {
|
|
254
|
+
if (entry.kind !== 'scene') continue;
|
|
255
|
+
const plan = planSceneDocument(entry);
|
|
256
|
+
if (plan.kind === 'no-document') continue;
|
|
257
|
+
rows.push({ entry, plan, isDefault: table.default === entry.id });
|
|
258
|
+
}
|
|
259
|
+
return rows;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** What Edit and Content actually present from one resolved scene table. */
|
|
263
|
+
export function authoringSurfaceFromTable(
|
|
264
|
+
table: ResolvedDocumentTable,
|
|
265
|
+
openDocumentIds: readonly string[],
|
|
266
|
+
availableDocumentIds: readonly string[],
|
|
267
|
+
): {
|
|
268
|
+
readonly sceneDocuments: number;
|
|
269
|
+
readonly isolationDocuments: number;
|
|
270
|
+
readonly openIsolationDocuments: number;
|
|
271
|
+
readonly availableIsolationDocuments: number;
|
|
272
|
+
readonly pieces: number;
|
|
273
|
+
/** Entries of kind `scene` — the surface prefabs are placed on; a table
|
|
274
|
+
* with none (a models or website project) has no prefabs by design. */
|
|
275
|
+
readonly sceneEntries: number;
|
|
276
|
+
} {
|
|
277
|
+
const tabs = sceneTabRow(table);
|
|
278
|
+
const isolationIds = tabs.flatMap((row) =>
|
|
279
|
+
row.plan.kind === 'isolation-document' ? [row.plan.documentId] : [],
|
|
280
|
+
);
|
|
281
|
+
const open = new Set(openDocumentIds);
|
|
282
|
+
const available = new Set(availableDocumentIds);
|
|
283
|
+
// A finder's OWN document kind (a `model` from `@volter/editor-blender`'s finder, a
|
|
284
|
+
// `page`, a `shot`) opens through that kind's document, never through the
|
|
285
|
+
// scene plan above — which answers `no-document` for it because it names
|
|
286
|
+
// no region. Those are documents Edit presents all the same; measured
|
|
287
|
+
// 2026-09-17, a models project reported "no authorable scene with a
|
|
288
|
+
// document to open" beside its open model document.
|
|
289
|
+
const kindDocuments = table.entries.filter(
|
|
290
|
+
(entry) => entry.authorable && entry.kind !== 'scene' && entry.kind !== 'prefab',
|
|
291
|
+
).length;
|
|
292
|
+
return {
|
|
293
|
+
sceneDocuments: tabs.length + kindDocuments,
|
|
294
|
+
isolationDocuments: isolationIds.length,
|
|
295
|
+
openIsolationDocuments: isolationIds.filter((id) => open.has(id)).length,
|
|
296
|
+
availableIsolationDocuments: isolationIds.filter((id) => available.has(id)).length,
|
|
297
|
+
pieces: table.entries.filter((entry) => entry.kind === 'prefab').length,
|
|
298
|
+
sceneEntries: table.entries.filter((entry) => entry.kind === 'scene').length,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Isolation tabs ARE the Edit scene row. A generic Scene tab
|
|
304
|
+
* (`workspace:scene` / `workspace:canvas-scene`) would be a second surface
|
|
305
|
+
* for the same game — the live host, or an empty world — and only belongs
|
|
306
|
+
* when this table has no isolation documents (or also names a root document
|
|
307
|
+
* that Scene already is).
|
|
308
|
+
*/
|
|
309
|
+
export function isolationTabsReplaceGenericScene(table: ResolvedDocumentTable): boolean {
|
|
310
|
+
const rows = sceneTabRow(table);
|
|
311
|
+
return (
|
|
312
|
+
rows.some((row) => row.plan.kind === 'isolation-document') &&
|
|
313
|
+
!rows.some((row) => row.plan.kind === 'root-document')
|
|
314
|
+
);
|
|
315
|
+
}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the editor camera should look at when it adopts a world nobody authored
|
|
3
|
+
* here — the two answers behind `EditorViewport.focusOnScene`.
|
|
4
|
+
*
|
|
5
|
+
* ## The measured defect
|
|
6
|
+
*
|
|
7
|
+
* Auto-frame framed the game's ENTIRE content AABB. Measured on a Cuberun
|
|
8
|
+
* mount: a 2,000-radius BackSide skybox sphere, a sun mesh at `z = -2000` and a
|
|
9
|
+
* hyperspace prop at `z ≈ -5365` stretched that AABB to ~8,400 units deep, so
|
|
10
|
+
* the fit distance landed the camera 12,870 units away from a ~1,000-unit
|
|
11
|
+
* gameplay corridor. 93% of the Scene viewport was black, and the one visible
|
|
12
|
+
* thing was the OUTSIDE of the skybox. The same world framed at working
|
|
13
|
+
* distance is vivid and correct. (Descent measured the same looseness at a
|
|
14
|
+
* smaller scale: a camera at ~2,580 for an ~800-unit world.)
|
|
15
|
+
*
|
|
16
|
+
* The union is the wrong instrument because a backdrop is not content the
|
|
17
|
+
* reader is looking FOR — it is content that exists to be far away. One prop
|
|
18
|
+
* 5,000 units out costs the whole framing, and no amount of care in the fit
|
|
19
|
+
* math can recover it.
|
|
20
|
+
*
|
|
21
|
+
* ## The two answers, in order
|
|
22
|
+
*
|
|
23
|
+
* 1. {@link viewFromGameCamera} — a game's author already decided the
|
|
24
|
+
* interesting view, so seeding the orbit camera from the world matrix of a
|
|
25
|
+
* camera the game itself placed opens the Scene tab where the game looks.
|
|
26
|
+
* {@link pickGameCamera} decides which camera that is.
|
|
27
|
+
* 2. {@link frameableContentBounds} — the fallback for a game whose camera we
|
|
28
|
+
* cannot name. It trims outliers off the union before framing.
|
|
29
|
+
*
|
|
30
|
+
* ## Why gap-trimming and not a percentile
|
|
31
|
+
*
|
|
32
|
+
* A blanket percentile (frame the inner 90% of content) would tighten the
|
|
33
|
+
* framing of EVERY world, including the uniform ones that are framed correctly
|
|
34
|
+
* today. This trims only across a spatial GAP: a face of the bounding box moves
|
|
35
|
+
* inward only when a small share of boxes sits beyond a void spanning a large
|
|
36
|
+
* fraction of the current diagonal. A uniformly-filled world has no such gap,
|
|
37
|
+
* so it comes back byte-identical to the plain union — that identity is the
|
|
38
|
+
* first property the tests pin.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
import { isEditorOwnedObject } from '@volter/editor-threejs/viewport/editor-layers';
|
|
42
|
+
import * as THREE from 'three';
|
|
43
|
+
|
|
44
|
+
/** Tuning for {@link frameableContentBounds}. Defaults are the shipped values. */
|
|
45
|
+
export interface FrameableBoundsOptions {
|
|
46
|
+
/** Largest share of the boxes all trimming together may discard. */
|
|
47
|
+
maxOutlierFraction?: number;
|
|
48
|
+
/** A gap must span this share of the current content diagonal to be a gap. */
|
|
49
|
+
minGapFraction?: number;
|
|
50
|
+
/** Below this many boxes there is no distribution to judge; nothing trims. */
|
|
51
|
+
minSampleSize?: number;
|
|
52
|
+
/** Cap on trim passes, so cost stays bounded on a huge world. */
|
|
53
|
+
maxPasses?: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const DEFAULTS: Required<FrameableBoundsOptions> = {
|
|
57
|
+
maxOutlierFraction: 0.1,
|
|
58
|
+
minGapFraction: 0.2,
|
|
59
|
+
minSampleSize: 8,
|
|
60
|
+
maxPasses: 8,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/** Orbit pivot distance when there is no content to measure one from. */
|
|
64
|
+
const EMPTY_CONTENT_PIVOT_DISTANCE = 10;
|
|
65
|
+
|
|
66
|
+
/** How far down the view axis the content must start for the pivot to mean
|
|
67
|
+
* anything — as a share of the content's own radius. */
|
|
68
|
+
const MIN_PIVOT_RADIUS_FRACTION = 0.01;
|
|
69
|
+
|
|
70
|
+
type Axis = 'x' | 'y' | 'z';
|
|
71
|
+
const AXES: readonly Axis[] = ['x', 'y', 'z'];
|
|
72
|
+
|
|
73
|
+
function unionOf(boxes: readonly THREE.Box3[], indices: Iterable<number>): THREE.Box3 {
|
|
74
|
+
const out = new THREE.Box3();
|
|
75
|
+
for (const i of indices) out.union(boxes[i] as THREE.Box3);
|
|
76
|
+
return out;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** One candidate trim: the boxes beyond the widest gap on one box face. */
|
|
80
|
+
interface GapCut {
|
|
81
|
+
gap: number;
|
|
82
|
+
discard: number[];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The widest gap found scanning inward from any of the six faces, across at
|
|
87
|
+
* most `budget` boxes.
|
|
88
|
+
*
|
|
89
|
+
* Scanning from a FACE (rather than clustering centers) is what catches a
|
|
90
|
+
* skybox: its centre sits with the content, and only its extent is an outlier.
|
|
91
|
+
*/
|
|
92
|
+
function widestOuterGap(
|
|
93
|
+
boxes: readonly THREE.Box3[],
|
|
94
|
+
kept: ReadonlySet<number>,
|
|
95
|
+
budget: number,
|
|
96
|
+
): GapCut | null {
|
|
97
|
+
let best: GapCut | null = null;
|
|
98
|
+
for (const axis of AXES) {
|
|
99
|
+
for (const side of ['min', 'max'] as const) {
|
|
100
|
+
const values: Array<{ i: number; v: number }> = [];
|
|
101
|
+
for (const i of kept) values.push({ i, v: (boxes[i] as THREE.Box3)[side][axis] });
|
|
102
|
+
// Outliers are the smallest values on a min face and the largest on a max
|
|
103
|
+
// face; sort so index 0 is always the outermost.
|
|
104
|
+
values.sort((a, b) => (side === 'min' ? a.v - b.v : b.v - a.v));
|
|
105
|
+
const reach = Math.min(budget, values.length - 1);
|
|
106
|
+
for (let k = 0; k < reach; k++) {
|
|
107
|
+
const gap = Math.abs((values[k + 1] as { v: number }).v - (values[k] as { v: number }).v);
|
|
108
|
+
if (best && gap <= best.gap) continue;
|
|
109
|
+
best = { gap, discard: values.slice(0, k + 1).map((e) => e.i) };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return best;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The box worth FRAMING, given one world-space box per content node.
|
|
118
|
+
*
|
|
119
|
+
* Returns the plain union whenever there is nothing defensible to trim: too few
|
|
120
|
+
* boxes to judge, no gap wide enough, or a budget of zero. Never returns an
|
|
121
|
+
* empty box for non-empty input.
|
|
122
|
+
*/
|
|
123
|
+
export function frameableContentBounds(
|
|
124
|
+
boxes: readonly THREE.Box3[],
|
|
125
|
+
options: FrameableBoundsOptions = {},
|
|
126
|
+
): THREE.Box3 {
|
|
127
|
+
const opts = { ...DEFAULTS, ...options };
|
|
128
|
+
const content = boxes.filter((b) => !b.isEmpty());
|
|
129
|
+
const all = content.map((_, i) => i);
|
|
130
|
+
const full = unionOf(content, all);
|
|
131
|
+
if (content.length < opts.minSampleSize) return full;
|
|
132
|
+
|
|
133
|
+
let budget = Math.floor(content.length * opts.maxOutlierFraction);
|
|
134
|
+
if (budget < 1) return full;
|
|
135
|
+
|
|
136
|
+
const kept = new Set(all);
|
|
137
|
+
let bounds = full;
|
|
138
|
+
const size = new THREE.Vector3();
|
|
139
|
+
for (let pass = 0; pass < opts.maxPasses && budget > 0; pass++) {
|
|
140
|
+
const diagonal = bounds.getSize(size).length();
|
|
141
|
+
if (!(diagonal > 0)) break;
|
|
142
|
+
const cut = widestOuterGap(content, kept, budget);
|
|
143
|
+
if (!cut || cut.gap <= opts.minGapFraction * diagonal) break;
|
|
144
|
+
for (const i of cut.discard) kept.delete(i);
|
|
145
|
+
budget -= cut.discard.length;
|
|
146
|
+
bounds = unionOf(content, kept);
|
|
147
|
+
}
|
|
148
|
+
return bounds.isEmpty() ? full : bounds;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** An orbit-camera pose: where the eye sits and what it orbits around. */
|
|
152
|
+
export interface SeededView {
|
|
153
|
+
position: THREE.Vector3;
|
|
154
|
+
target: THREE.Vector3;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* The editor orbit pose that reproduces `camera`'s own view.
|
|
159
|
+
*
|
|
160
|
+
* The eye is the game camera's world position and the view direction is its
|
|
161
|
+
* own; the only thing invented is the orbit PIVOT, which is placed at the depth
|
|
162
|
+
* of the content along that view direction — the point the reader is already
|
|
163
|
+
* looking at, so the first orbit drag turns around the world rather than
|
|
164
|
+
* around a point behind their head.
|
|
165
|
+
*
|
|
166
|
+
* Returns `null` when that pivot cannot be placed: the world sits BEHIND the
|
|
167
|
+
* camera (a view showing none of the game is not worth adopting), or it sits
|
|
168
|
+
* ON it, which leaves an orbit pivot at the eye — measured as a target
|
|
169
|
+
* 4.6e-14 units out, an orbit control that can only spin in place. Both fall
|
|
170
|
+
* back to {@link frameableContentBounds}.
|
|
171
|
+
*/
|
|
172
|
+
export function viewFromGameCamera(camera: THREE.Camera, content: THREE.Box3): SeededView | null {
|
|
173
|
+
const forward = camera.getWorldDirection(new THREE.Vector3());
|
|
174
|
+
const position = new THREE.Vector3().setFromMatrixPosition(camera.matrixWorld);
|
|
175
|
+
if (!Number.isFinite(position.lengthSq()) || forward.lengthSq() === 0) return null;
|
|
176
|
+
if (content.isEmpty()) {
|
|
177
|
+
return {
|
|
178
|
+
position,
|
|
179
|
+
target: position.clone().addScaledVector(forward, EMPTY_CONTENT_PIVOT_DISTANCE),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
const sphere = content.getBoundingSphere(new THREE.Sphere());
|
|
183
|
+
const along = sphere.center.clone().sub(position).dot(forward);
|
|
184
|
+
if (!(along > sphere.radius * MIN_PIVOT_RADIUS_FRACTION)) return null;
|
|
185
|
+
return { position, target: position.clone().addScaledVector(forward, along) };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* The NDC points a seeded view is sampled at: the centre plus a ring at 60% of
|
|
190
|
+
* the way to each edge/corner. Nine rays — enough that a view whose middle is
|
|
191
|
+
* blocked by one prop still reads as open, cheap enough to run on every seed
|
|
192
|
+
* attempt over a whole game graph.
|
|
193
|
+
*/
|
|
194
|
+
const OCCLUSION_SAMPLES: ReadonlyArray<readonly [number, number]> = [
|
|
195
|
+
[0, 0],
|
|
196
|
+
[-0.6, 0.6],
|
|
197
|
+
[0.6, 0.6],
|
|
198
|
+
[-0.6, -0.6],
|
|
199
|
+
[0.6, -0.6],
|
|
200
|
+
[0, 0.6],
|
|
201
|
+
[0, -0.6],
|
|
202
|
+
[-0.6, 0],
|
|
203
|
+
[0.6, 0],
|
|
204
|
+
];
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* How near a hit has to be, as a share of the view's own pivot distance, to
|
|
208
|
+
* count as "pressed against the lens" rather than "part of the world". At 2%,
|
|
209
|
+
* a camera looking 100 units into a world is blocked only by something inside
|
|
210
|
+
* 2 units of it.
|
|
211
|
+
*/
|
|
212
|
+
const NEAR_FIELD_FRACTION = 0.02;
|
|
213
|
+
|
|
214
|
+
const _raycaster = new THREE.Raycaster();
|
|
215
|
+
const _ndc = new THREE.Vector2();
|
|
216
|
+
|
|
217
|
+
/** Three's raycast reports hits on invisible objects; a hidden collider proxy
|
|
218
|
+
* in front of the lens blocks nothing a reader would see. */
|
|
219
|
+
function isVisibleInWorld(object: THREE.Object3D): boolean {
|
|
220
|
+
for (let node: THREE.Object3D | null = object; node; node = node.parent) {
|
|
221
|
+
if (!node.visible) return false;
|
|
222
|
+
}
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Does a view posed HERE show the world, or a surface pressed against the lens?
|
|
228
|
+
*
|
|
229
|
+
* The measured defect: a game's own camera is placed for the game's own moment
|
|
230
|
+
* — inside a cockpit, behind a wall it is about to drive through, under
|
|
231
|
+
* terrain that has not settled — and adopting it as the editor's opening view
|
|
232
|
+
* can hand the reader a full-bleed rectangle of rock. The view is a perfectly
|
|
233
|
+
* good gameplay camera and a useless first look, and nothing in the pose
|
|
234
|
+
* itself says which.
|
|
235
|
+
*
|
|
236
|
+
* The instrument is geometric, not pixels: nine rays through the frustum, and
|
|
237
|
+
* a view SHOWS THE WORLD when at least one of them either escapes (sky,
|
|
238
|
+
* backdrop, open space) or reaches something farther than
|
|
239
|
+
* {@link NEAR_FIELD_FRACTION} of what this view claims to be looking at. The
|
|
240
|
+
* threshold is relative to the view's own pivot distance, so it needs no
|
|
241
|
+
* world-scale constant and reads the same on a 10-unit room and a 10,000-unit
|
|
242
|
+
* canyon.
|
|
243
|
+
*
|
|
244
|
+
* Deliberately conservative: EVERY sample must be blocked in the near field
|
|
245
|
+
* before the view is refused, so an ordinary view with a prop in the middle or
|
|
246
|
+
* ground filling its lower half still passes. A refusal here costs the reader
|
|
247
|
+
* only the game's own camera — the caller falls back to
|
|
248
|
+
* {@link frameableContentBounds}, which always shows something.
|
|
249
|
+
*
|
|
250
|
+
* Three's raycast honours `material.side` exactly as the renderer does, and
|
|
251
|
+
* that alignment is the reason this instrument is honest rather than merely
|
|
252
|
+
* cheap: a camera sealed inside a front-faced solid is invisible to BOTH — the
|
|
253
|
+
* reader sees through the shell, the rays escape through it, and the view is
|
|
254
|
+
* correctly not called blocked. The failure this catches is the one that is
|
|
255
|
+
* actually on screen: front faces, filling the frame, right at the lens.
|
|
256
|
+
*
|
|
257
|
+
* (The screenshot lane measures the same failure from the other side, on
|
|
258
|
+
* PIXELS, in `composite-screenshot.ts`. That instrument needs a drawn frame
|
|
259
|
+
* and a GPU readback, and it cannot tell a legitimately flat picture from a
|
|
260
|
+
* blocked one — which is why the decision to adopt a pose is made here, before
|
|
261
|
+
* anything is drawn.)
|
|
262
|
+
*/
|
|
263
|
+
export function seededViewShowsWorld(
|
|
264
|
+
camera: THREE.Camera,
|
|
265
|
+
content: readonly THREE.Object3D[],
|
|
266
|
+
pivotDistance: number,
|
|
267
|
+
): boolean {
|
|
268
|
+
if (!(pivotDistance > 0) || content.length === 0) return true;
|
|
269
|
+
const nearField = pivotDistance * NEAR_FIELD_FRACTION;
|
|
270
|
+
for (const [x, y] of OCCLUSION_SAMPLES) {
|
|
271
|
+
_ndc.set(x, y);
|
|
272
|
+
_raycaster.setFromCamera(_ndc, camera);
|
|
273
|
+
const hits = _raycaster.intersectObjects(content as THREE.Object3D[], true);
|
|
274
|
+
const blocker = hits.find((hit) => isVisibleInWorld(hit.object));
|
|
275
|
+
if (!blocker || blocker.distance > nearField) return true;
|
|
276
|
+
}
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/** Every camera in the game's own scene, in scene order, editor furniture and
|
|
281
|
+
* its subtrees excluded. */
|
|
282
|
+
function gameCameras(node: THREE.Object3D, out: THREE.Camera[] = []): THREE.Camera[] {
|
|
283
|
+
if (isEditorOwnedObject(node)) return out;
|
|
284
|
+
if ((node as THREE.Camera).isCamera) out.push(node as THREE.Camera);
|
|
285
|
+
for (const child of node.children) gameCameras(child, out);
|
|
286
|
+
return out;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* The camera whose view an ingest mount should adopt — one the game itself
|
|
291
|
+
* CREATED AND PLACED, which means one that is in the game's own scene graph.
|
|
292
|
+
*
|
|
293
|
+
* The capture's own camera (the one the first `render(scene, camera)` used) is
|
|
294
|
+
* preferred WHEN it is one of those, and is otherwise ignored, because on the
|
|
295
|
+
* first rendered frame it can be a reconciler's placeholder rather than the
|
|
296
|
+
* author's camera. Measured on Cuberun: the captured camera came back with an
|
|
297
|
+
* identity world matrix at the origin while the game's own
|
|
298
|
+
* `<PerspectiveCamera position={[0, 10, -10]}>` was sitting in the scene at
|
|
299
|
+
* (0, 8, 3.5) looking down the corridor — seeding from the capture opened on a
|
|
300
|
+
* flat wall of ground plane, seeding from the scene's camera opened on the
|
|
301
|
+
* game.
|
|
302
|
+
*
|
|
303
|
+
* Editor furniture is never adopted: the capture trap sits on the shared
|
|
304
|
+
* `WebGLRenderer.prototype`, so the editor's own cameras are the one thing
|
|
305
|
+
* that must never come back from here.
|
|
306
|
+
*/
|
|
307
|
+
export function pickGameCamera(
|
|
308
|
+
captured: THREE.Camera | null | undefined,
|
|
309
|
+
scene: THREE.Object3D,
|
|
310
|
+
): THREE.Camera | null {
|
|
311
|
+
const cameras = gameCameras(scene);
|
|
312
|
+
if (cameras.length === 0) return null;
|
|
313
|
+
if (captured && cameras.includes(captured)) return captured;
|
|
314
|
+
return cameras[0] as THREE.Camera;
|
|
315
|
+
}
|