@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,526 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only authoring projection for a native Three.js document graph.
|
|
3
|
+
*
|
|
4
|
+
* The native Object3D tree is truth. The shared three projector
|
|
5
|
+
* (`../projection/three.ts`) walks it under the document-path identity and owns
|
|
6
|
+
* the index; the shared collapse view (`three-projection-core.ts`) turns that
|
|
7
|
+
* index into rows. This CONFIGURATION supplies the two axes — document-path
|
|
8
|
+
* identity, no write target — plus what only a document has: its own document
|
|
9
|
+
* row, the model classification on it, and the read-only inspector. It never
|
|
10
|
+
* fabricates descriptors or a JSON mirror. Source parameters rebuild the graph
|
|
11
|
+
* outside this adapter.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type {
|
|
15
|
+
AuthoringAdapter,
|
|
16
|
+
AuthoringCapabilities,
|
|
17
|
+
AuthoringProvenance,
|
|
18
|
+
HierarchyProvider,
|
|
19
|
+
InspectorProvider,
|
|
20
|
+
PropertyDescriptor,
|
|
21
|
+
SelectionProvider,
|
|
22
|
+
Transform,
|
|
23
|
+
TransformProvider,
|
|
24
|
+
} from '@volter/editor-project/adapter';
|
|
25
|
+
import { isEditorOwnedObject } from '@volter/editor-threejs/viewport/editor-layers';
|
|
26
|
+
import { object3DAuthoringSubjectOf } from '@volter/editor-threejs/adapter/object3d-authoring-subject';
|
|
27
|
+
import { getUserData } from '@volter/editor-threejs/ecs/user-data';
|
|
28
|
+
import type * as THREE from 'three';
|
|
29
|
+
import {
|
|
30
|
+
classifyModelStructure,
|
|
31
|
+
inspectModel,
|
|
32
|
+
inspectModelRig,
|
|
33
|
+
} from '../asset-workflow/model-inspection';
|
|
34
|
+
import type { EditorShellStore } from '../editor-shell-store';
|
|
35
|
+
import { documentPathIdentity, ThreeProjector } from '../projection/three';
|
|
36
|
+
import {
|
|
37
|
+
CollapsedHierarchyView,
|
|
38
|
+
readLocalTransform,
|
|
39
|
+
StoreSelectionAdoption,
|
|
40
|
+
} from './three-projection-core';
|
|
41
|
+
|
|
42
|
+
export interface SourceObject3DAuthoringOptions {
|
|
43
|
+
readonly documentId: string;
|
|
44
|
+
readonly title: string;
|
|
45
|
+
readonly sourcePath: string;
|
|
46
|
+
readonly documentKind?: 'source' | 'asset';
|
|
47
|
+
/** The Asset Lab's import audit on this document's inspector — see
|
|
48
|
+
* `ToolObject3DAuthoringProps.audit`. Default on. */
|
|
49
|
+
readonly audit?: boolean;
|
|
50
|
+
/** Authored content roots when the scene also contains a document-owned
|
|
51
|
+
* presentation container. Omitted preserves the native projection roots. */
|
|
52
|
+
readonly hierarchyRoots?: readonly THREE.Object3D[];
|
|
53
|
+
readonly provenance?: AuthoringProvenance;
|
|
54
|
+
readonly modelSource?:
|
|
55
|
+
| { readonly kind: 'project-file'; readonly path: string }
|
|
56
|
+
| { readonly kind: 'entity'; readonly entityId: string };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** `node()` runs on every hierarchy render; classifying a whole graph there
|
|
60
|
+
* would walk it each time. Keyed by the root object, so a rebuilt graph is a
|
|
61
|
+
* fresh entry and a disposed one is collected with it. */
|
|
62
|
+
const documentTypeLabelByRoot = new WeakMap<THREE.Object3D, string>();
|
|
63
|
+
|
|
64
|
+
function classifyDocumentRoot(root: THREE.Object3D): string {
|
|
65
|
+
let splat = false;
|
|
66
|
+
root.traverse((object) => {
|
|
67
|
+
if (getUserData(object, 'gaussianSplat')) splat = true;
|
|
68
|
+
});
|
|
69
|
+
if (splat) return 'Gaussian splat';
|
|
70
|
+
const inspection = inspectModel(root);
|
|
71
|
+
const rig = inspectModelRig(root);
|
|
72
|
+
return {
|
|
73
|
+
static: 'Static model',
|
|
74
|
+
animated: 'Animated model',
|
|
75
|
+
rigged: 'Rigged model',
|
|
76
|
+
skinned: 'Skinned model',
|
|
77
|
+
}[classifyModelStructure(inspection, rig)];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function materialOf(object: THREE.Object3D): THREE.Material | null {
|
|
81
|
+
const material = (object as THREE.Mesh).material;
|
|
82
|
+
if (Array.isArray(material)) return material[0] ?? null;
|
|
83
|
+
return material ?? null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function colorOf(material: THREE.Material | null): THREE.Color | null {
|
|
87
|
+
const candidate = material as (THREE.Material & { color?: THREE.Color }) | null;
|
|
88
|
+
return candidate?.color ?? null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export class SourceObject3DAuthoringAdapter implements AuthoringAdapter {
|
|
92
|
+
private readonly documentNodeId: string;
|
|
93
|
+
/** The shared three projector over this document's graph. */
|
|
94
|
+
private readonly projector: ThreeProjector;
|
|
95
|
+
private readonly hierarchyRootIds: readonly string[];
|
|
96
|
+
/** The shared collapse view over {@link projector} — see
|
|
97
|
+
* `three-projection-core.ts`. */
|
|
98
|
+
private readonly view: CollapsedHierarchyView;
|
|
99
|
+
/** Selection, shared with the store the viewport writes to — see
|
|
100
|
+
* `three-projection-core.ts`. */
|
|
101
|
+
private readonly selectionState: StoreSelectionAdoption;
|
|
102
|
+
private markedSelection = new Set<THREE.Object3D>();
|
|
103
|
+
|
|
104
|
+
readonly capabilities: AuthoringCapabilities = {
|
|
105
|
+
transform: false,
|
|
106
|
+
inspectorFields: true,
|
|
107
|
+
persist: false,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
readonly provenance: AuthoringProvenance;
|
|
111
|
+
|
|
112
|
+
constructor(
|
|
113
|
+
private readonly store: EditorShellStore,
|
|
114
|
+
private readonly scene: THREE.Scene,
|
|
115
|
+
readonly options: SourceObject3DAuthoringOptions,
|
|
116
|
+
) {
|
|
117
|
+
this.provenance =
|
|
118
|
+
options.provenance ??
|
|
119
|
+
(options.documentKind === 'asset'
|
|
120
|
+
? {
|
|
121
|
+
source: 'document',
|
|
122
|
+
label: 'derived asset',
|
|
123
|
+
detail: 'Loaded from an ordinary project asset. Edit its source or import recipe.',
|
|
124
|
+
}
|
|
125
|
+
: {
|
|
126
|
+
source: 'source-code',
|
|
127
|
+
label: 'source',
|
|
128
|
+
detail:
|
|
129
|
+
'Instantiated from project TypeScript. Edit source or exposed parameters, then rebuild.',
|
|
130
|
+
});
|
|
131
|
+
this.documentNodeId = `object3d-document:${options.documentId}`;
|
|
132
|
+
// The projector stamps `userData.entityId` as it walks, so EditorViewport
|
|
133
|
+
// and its gizmo/pick code consume the same native id.
|
|
134
|
+
this.projector = new ThreeProjector(documentPathIdentity(options.documentId));
|
|
135
|
+
this.indexGraph();
|
|
136
|
+
if (
|
|
137
|
+
options.hierarchyRoots &&
|
|
138
|
+
new Set(options.hierarchyRoots).size !== options.hierarchyRoots.length
|
|
139
|
+
) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
`Object3D document "${options.title}" declared the same hierarchy root twice.`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
const declaredRootSet = new Set(options.hierarchyRoots ?? []);
|
|
145
|
+
for (const root of declaredRootSet) {
|
|
146
|
+
let parent = root.parent;
|
|
147
|
+
while (parent && parent !== scene) {
|
|
148
|
+
if (declaredRootSet.has(parent)) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`Object3D document "${options.title}" declared nested hierarchy roots; roots must be non-overlapping.`,
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
parent = parent.parent;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
this.hierarchyRootIds = options.hierarchyRoots
|
|
157
|
+
? options.hierarchyRoots.map((object) => {
|
|
158
|
+
const id = this.idByObject.get(object);
|
|
159
|
+
if (!id) {
|
|
160
|
+
throw new Error(
|
|
161
|
+
`Object3D document "${options.title}" declared a hierarchy root outside its native graph.`,
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
return id;
|
|
165
|
+
})
|
|
166
|
+
: [...this.projector.rootIds];
|
|
167
|
+
this.view = new CollapsedHierarchyView({
|
|
168
|
+
projector: this.projector,
|
|
169
|
+
scene,
|
|
170
|
+
documentNodeId: this.documentNodeId,
|
|
171
|
+
rootIds: this.hierarchyRootIds,
|
|
172
|
+
});
|
|
173
|
+
this.selectionState = new StoreSelectionAdoption({
|
|
174
|
+
store,
|
|
175
|
+
owns: (id) => this.byId.has(id),
|
|
176
|
+
initial: [this.documentNodeId],
|
|
177
|
+
onChange: (ids) => this.syncMarkedSelection(ids),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// ------------------------------------------------ graph mutated after mount
|
|
182
|
+
//
|
|
183
|
+
// The constructor's walk is a snapshot of the graph AT MOUNT, and one class
|
|
184
|
+
// of document mutates its graph afterwards: the live module document
|
|
185
|
+
// (`components/asset-viewers/LiveModuleDocument.tsx`) keeps a stable
|
|
186
|
+
// container root and SWAPS ITS CHILD on every save, precisely so the
|
|
187
|
+
// viewport's camera survives a rebuild. Measured 2026-08-29: the viewport
|
|
188
|
+
// showed the rebuilt model while the hierarchy kept the mount-time walk, so
|
|
189
|
+
// the document row lost its child and the picker addressed a disposed
|
|
190
|
+
// object.
|
|
191
|
+
//
|
|
192
|
+
// The fix is `r3f-source-authoring-adapter.ts`'s, transcribed: re-index on
|
|
193
|
+
// the GRAPH'S OWN structural events. `parent.add(child)` dispatches
|
|
194
|
+
// `childadded` on the parent, so watching the scene plus every indexed
|
|
195
|
+
// object covers every path a subtree can enter through, and no document has
|
|
196
|
+
// to remember to tell this adapter anything. Editor furniture (gizmo and
|
|
197
|
+
// helper attachments) is filtered so selection churn does not re-index.
|
|
198
|
+
|
|
199
|
+
private disposed = false;
|
|
200
|
+
dispose(): void {
|
|
201
|
+
if (this.disposed) return;
|
|
202
|
+
this.disposed = true;
|
|
203
|
+
for (const object of this.watchedForStructure) {
|
|
204
|
+
object.removeEventListener('childadded', this.onStructureChanged);
|
|
205
|
+
object.removeEventListener('childremoved', this.onStructureChanged);
|
|
206
|
+
}
|
|
207
|
+
this.watchedForStructure = [];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private watchedForStructure: THREE.Object3D[] = [];
|
|
211
|
+
private structureReindexQueued = false;
|
|
212
|
+
|
|
213
|
+
private readonly onStructureChanged = (event: { child: THREE.Object3D }): void => {
|
|
214
|
+
if (isEditorOwnedObject(event.child)) return;
|
|
215
|
+
this.scheduleStructureReindex();
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
private indexGraph(): void {
|
|
219
|
+
this.projector.project(this.scene);
|
|
220
|
+
this.watchStructure();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** (Re)attach `childadded`/`childremoved` across the indexed graph, so a
|
|
224
|
+
* freshly-swapped subtree is watched from the re-index that found it. */
|
|
225
|
+
private watchStructure(): void {
|
|
226
|
+
const structural = (object: THREE.Object3D) =>
|
|
227
|
+
object as unknown as {
|
|
228
|
+
addEventListener(
|
|
229
|
+
type: 'childadded' | 'childremoved',
|
|
230
|
+
listener: (event: { child: THREE.Object3D }) => void,
|
|
231
|
+
): void;
|
|
232
|
+
removeEventListener(
|
|
233
|
+
type: 'childadded' | 'childremoved',
|
|
234
|
+
listener: (event: { child: THREE.Object3D }) => void,
|
|
235
|
+
): void;
|
|
236
|
+
};
|
|
237
|
+
for (const object of this.watchedForStructure) {
|
|
238
|
+
structural(object).removeEventListener('childadded', this.onStructureChanged);
|
|
239
|
+
structural(object).removeEventListener('childremoved', this.onStructureChanged);
|
|
240
|
+
}
|
|
241
|
+
this.watchedForStructure = [];
|
|
242
|
+
const watch = (object: THREE.Object3D): void => {
|
|
243
|
+
structural(object).addEventListener('childadded', this.onStructureChanged);
|
|
244
|
+
structural(object).addEventListener('childremoved', this.onStructureChanged);
|
|
245
|
+
this.watchedForStructure.push(object);
|
|
246
|
+
};
|
|
247
|
+
watch(this.scene);
|
|
248
|
+
for (const [, object] of this.byId) watch(object);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** One re-index per mutation burst: a swap is remove-then-add, and a
|
|
252
|
+
* microtask runs after the whole subtree is in the graph. */
|
|
253
|
+
private scheduleStructureReindex(): void {
|
|
254
|
+
if (this.disposed || this.structureReindexQueued) return;
|
|
255
|
+
this.structureReindexQueued = true;
|
|
256
|
+
queueMicrotask(() => {
|
|
257
|
+
this.structureReindexQueued = false;
|
|
258
|
+
if (this.disposed) return;
|
|
259
|
+
this.indexGraph();
|
|
260
|
+
if (this.store.scene !== this.scene) return;
|
|
261
|
+
const map = this.store.objectMap;
|
|
262
|
+
map.clear();
|
|
263
|
+
for (const [id, object] of this.byId) map.set(id, object);
|
|
264
|
+
// Selection can name an object the swap removed; keep it inside the
|
|
265
|
+
// index the hierarchy, picker and gizmo now consume.
|
|
266
|
+
const retained = [...this.store.selectedEntityIds].filter(
|
|
267
|
+
(id) => id === this.documentNodeId || this.byId.has(id),
|
|
268
|
+
);
|
|
269
|
+
if (retained.length !== this.store.selectedEntityIds.size) {
|
|
270
|
+
this.store.selectMultiple(retained);
|
|
271
|
+
}
|
|
272
|
+
// `subscribe` on this adapter IS the store's subscribe, so notifying the
|
|
273
|
+
// store is this adapter's own change signal.
|
|
274
|
+
this.store.notifyIngestObjectMapEdit();
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private get byId(): ReadonlyMap<string, THREE.Object3D> {
|
|
279
|
+
return this.projector.objects;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
private get idByObject(): ReadonlyMap<THREE.Object3D, string> {
|
|
283
|
+
return this.projector.idsByObject;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** The document root's structural type, cached per root graph. `undefined`
|
|
287
|
+
* for a SOURCE document, whose root is whatever the project built and not
|
|
288
|
+
* a model with a structure to classify. */
|
|
289
|
+
private documentTypeLabel(): string | undefined {
|
|
290
|
+
if (this.options.documentKind !== 'asset') return undefined;
|
|
291
|
+
// NOT `documentRootObject` — that reads the document node's `childIds`,
|
|
292
|
+
// and this is called while building that node.
|
|
293
|
+
const root = this.scene.children.find((child) => this.idByObject.has(child)) ?? null;
|
|
294
|
+
if (!root) return undefined;
|
|
295
|
+
const cached = documentTypeLabelByRoot.get(root);
|
|
296
|
+
if (cached !== undefined) return cached;
|
|
297
|
+
const label = classifyDocumentRoot(root);
|
|
298
|
+
documentTypeLabelByRoot.set(root, label);
|
|
299
|
+
return label;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
readonly hierarchy: HierarchyProvider = {
|
|
303
|
+
roots: () => [this.hierarchy.node(this.documentNodeId)!],
|
|
304
|
+
node: (id) => {
|
|
305
|
+
if (id === this.documentNodeId) {
|
|
306
|
+
const typeLabel = this.documentTypeLabel();
|
|
307
|
+
return {
|
|
308
|
+
id,
|
|
309
|
+
label: this.options.title,
|
|
310
|
+
secondaryLabel: this.options.sourcePath,
|
|
311
|
+
role: 'document',
|
|
312
|
+
kind: this.options.documentKind === 'asset' ? 'model-asset' : 'three-source',
|
|
313
|
+
// What to CALL this document's root, on the inspector's identity
|
|
314
|
+
// row — "Rigged model", "Gaussian splat". It is the structure of
|
|
315
|
+
// the graph this adapter is projecting, so the adapter is the only
|
|
316
|
+
// thing that can answer it; the classification is cached per root
|
|
317
|
+
// because `node()` is called on every hierarchy render.
|
|
318
|
+
...(typeLabel ? { typeLabel } : {}),
|
|
319
|
+
parentId: null,
|
|
320
|
+
childIds: this.view.rootIds(),
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
const object = this.byId.get(id);
|
|
324
|
+
return object ? this.view.node(object) : null;
|
|
325
|
+
},
|
|
326
|
+
object3D: (id) => this.byId.get(id) ?? null,
|
|
327
|
+
idForObject3D: (object) => this.idByObject.get(object) ?? null,
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
readonly selection: SelectionProvider = {
|
|
331
|
+
get: () => this.selectionState.current(),
|
|
332
|
+
// The document row is selectable and is NOT one of this projection's
|
|
333
|
+
// objects, which is why it survives this filter and never reaches the store.
|
|
334
|
+
set: (ids) =>
|
|
335
|
+
this.selectionState.publish(
|
|
336
|
+
ids.filter((id) => id === this.documentNodeId || this.byId.has(id)),
|
|
337
|
+
),
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* THE REASON THIS PROJECTION REFUSES, spelled once because it is PRINTED:
|
|
342
|
+
* it lands in the tooltip of every generic shell control that asks this
|
|
343
|
+
* adapter whether it may write.
|
|
344
|
+
*/
|
|
345
|
+
private static readonly READ_ONLY_REASON =
|
|
346
|
+
'This document shows what the module builds; its properties are read-only here. Edit the module.';
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* READ-ONLY, AND IT SAYS SO NOW. Every write door on this adapter is a
|
|
350
|
+
* no-op and always was — `transforms.beginEdit`/`apply`/`endEdit` below and
|
|
351
|
+
* `inspector.set` further down all return `undefined` — but it declared no
|
|
352
|
+
* `editability`, which is the seam the shell asks BEFORE drawing a control
|
|
353
|
+
* (`InspectorProvider.editability`'s own contract names "hierarchy eye/lock
|
|
354
|
+
* controls"). Its default is `{ writable: true }`, so the shell believed
|
|
355
|
+
* this projection and drew a live control over a surface that discards it.
|
|
356
|
+
*
|
|
357
|
+
* MEASURED 2026-09-19 in a cold models scaffold, which is what bought this:
|
|
358
|
+
* the Outliner's EYE on a Model document lit, kept its `Hide` tooltip and
|
|
359
|
+
* its `aria-pressed="false"`, and left the frame hash byte-identical —
|
|
360
|
+
* `GameHierarchy.tsx` gates it on `visibleKnown && (editability?.writable ??
|
|
361
|
+
* true)`, and `visible` is knowable here (it reads `object.visible`) even
|
|
362
|
+
* though it is `readonly: true` in the very descriptor list below.
|
|
363
|
+
*
|
|
364
|
+
* `transforms` DELIBERATELY DOES NOT GET ONE, and that is a measurement
|
|
365
|
+
* rather than an oversight. Its write doors are no-ops too, so the honest
|
|
366
|
+
* answer is the same — but declaring it bought nothing and cost a mark:
|
|
367
|
+
* `transform-mode-request.ts`, the one place that would have NAMED the
|
|
368
|
+
* refusal, reads `store.selectedEntityIds` off the SHELL store while a
|
|
369
|
+
* document stage keeps its selection in its own, so it returns before it
|
|
370
|
+
* can speak and the host's Move/Rotate/Scale stayed silent either way —
|
|
371
|
+
* while `GameHierarchy`'s `hierarchy-transform-lock` span immediately
|
|
372
|
+
* appeared on every row, a glyph Blender's Outliner does not draw. Answer
|
|
373
|
+
* it when something acts on the answer.
|
|
374
|
+
*/
|
|
375
|
+
private readonly readOnly = (): { writable: boolean; reason: string } => ({
|
|
376
|
+
writable: false,
|
|
377
|
+
reason: SourceObject3DAuthoringAdapter.READ_ONLY_REASON,
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
readonly transforms: TransformProvider = {
|
|
381
|
+
get: (id): Transform => readLocalTransform(this.byId.get(id) ?? null),
|
|
382
|
+
beginEdit: () => undefined,
|
|
383
|
+
apply: () => undefined,
|
|
384
|
+
endEdit: () => undefined,
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
readonly inspector: InspectorProvider = {
|
|
388
|
+
properties: (id): PropertyDescriptor[] => {
|
|
389
|
+
if (id === this.documentNodeId) {
|
|
390
|
+
// A document that declined the import audit carries its own sections;
|
|
391
|
+
// the name is the identity row's and the path is the hierarchy
|
|
392
|
+
// header's, so the loose "Properties" grid would only repeat them.
|
|
393
|
+
if (this.options.audit === false) return [];
|
|
394
|
+
return [
|
|
395
|
+
{ path: 'name', label: 'Name', type: 'string', readonly: true },
|
|
396
|
+
{ path: 'source.path', label: 'Source', type: 'string', readonly: true },
|
|
397
|
+
];
|
|
398
|
+
}
|
|
399
|
+
const object = this.byId.get(id);
|
|
400
|
+
if (!object) return [];
|
|
401
|
+
const subject = object3DAuthoringSubjectOf(object);
|
|
402
|
+
if (subject?.fields) {
|
|
403
|
+
return subject.fields().map(({ value: _value, ...descriptor }) => descriptor);
|
|
404
|
+
}
|
|
405
|
+
const properties: PropertyDescriptor[] = [
|
|
406
|
+
{ path: 'name', label: 'Name', type: 'string', readonly: true },
|
|
407
|
+
{ path: 'visible', label: 'Visible', type: 'boolean', readonly: true },
|
|
408
|
+
{ path: 'object.type', label: 'Native type', type: 'string', readonly: true },
|
|
409
|
+
];
|
|
410
|
+
const mesh = object as THREE.Mesh;
|
|
411
|
+
if (mesh.isMesh && mesh.geometry) {
|
|
412
|
+
const position = mesh.geometry.getAttribute('position');
|
|
413
|
+
properties.push({
|
|
414
|
+
path: 'mesh.vertices',
|
|
415
|
+
label: 'Vertices',
|
|
416
|
+
type: 'number',
|
|
417
|
+
readonly: true,
|
|
418
|
+
group: 'Mesh',
|
|
419
|
+
});
|
|
420
|
+
if (position) {
|
|
421
|
+
properties.push({
|
|
422
|
+
path: 'mesh.triangles',
|
|
423
|
+
label: 'Triangles',
|
|
424
|
+
type: 'number',
|
|
425
|
+
readonly: true,
|
|
426
|
+
group: 'Mesh',
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
const material = materialOf(object);
|
|
431
|
+
if (material) {
|
|
432
|
+
properties.push({
|
|
433
|
+
path: 'material.type',
|
|
434
|
+
label: 'Material',
|
|
435
|
+
type: 'string',
|
|
436
|
+
readonly: true,
|
|
437
|
+
group: 'Material',
|
|
438
|
+
});
|
|
439
|
+
if (colorOf(material)) {
|
|
440
|
+
properties.push({
|
|
441
|
+
path: 'material.color',
|
|
442
|
+
label: 'Color',
|
|
443
|
+
type: 'color',
|
|
444
|
+
readonly: true,
|
|
445
|
+
group: 'Material',
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
const skinned = object as THREE.SkinnedMesh;
|
|
450
|
+
if (skinned.isSkinnedMesh && skinned.skeleton) {
|
|
451
|
+
properties.push({
|
|
452
|
+
path: 'skin.bones',
|
|
453
|
+
label: 'Bones',
|
|
454
|
+
type: 'number',
|
|
455
|
+
readonly: true,
|
|
456
|
+
group: 'Skin',
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
return properties;
|
|
460
|
+
},
|
|
461
|
+
get: (id, path) => {
|
|
462
|
+
if (id === this.documentNodeId) {
|
|
463
|
+
if (path === 'name') return this.options.title;
|
|
464
|
+
if (path === 'source.path') return this.options.sourcePath;
|
|
465
|
+
return undefined;
|
|
466
|
+
}
|
|
467
|
+
const object = this.byId.get(id);
|
|
468
|
+
if (!object) return undefined;
|
|
469
|
+
const subject = object3DAuthoringSubjectOf(object);
|
|
470
|
+
const subjectField = subject?.fields?.().find((field) => field.path === path);
|
|
471
|
+
if (subjectField) return subjectField.value();
|
|
472
|
+
if (path === 'name') return object.name || object.type;
|
|
473
|
+
if (path === 'visible') return object.visible;
|
|
474
|
+
if (path === 'object.type') return object.type;
|
|
475
|
+
const mesh = object as THREE.Mesh;
|
|
476
|
+
if (path === 'mesh.vertices') return mesh.geometry?.getAttribute('position')?.count ?? 0;
|
|
477
|
+
if (path === 'mesh.triangles') {
|
|
478
|
+
const geometry = mesh.geometry;
|
|
479
|
+
return (geometry?.index?.count ?? geometry?.getAttribute('position')?.count ?? 0) / 3;
|
|
480
|
+
}
|
|
481
|
+
const material = materialOf(object);
|
|
482
|
+
if (path === 'material.type') return material?.type;
|
|
483
|
+
if (path === 'material.color') {
|
|
484
|
+
const color = colorOf(material);
|
|
485
|
+
return color ? `#${color.getHexString()}` : undefined;
|
|
486
|
+
}
|
|
487
|
+
if (path === 'skin.bones') return (object as THREE.SkinnedMesh).skeleton?.bones.length ?? 0;
|
|
488
|
+
return undefined;
|
|
489
|
+
},
|
|
490
|
+
set: () => undefined,
|
|
491
|
+
// See {@link readOnly}: `set` above writes nothing, so no generic surface
|
|
492
|
+
// may draw a live control over one of these values.
|
|
493
|
+
editability: () => this.readOnly(),
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
subscribe(listener: () => void): () => void {
|
|
497
|
+
return this.store.subscribe(listener);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
get documentId(): string {
|
|
501
|
+
return this.documentNodeId;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
get documentRootObject(): THREE.Object3D | null {
|
|
505
|
+
const rootId = this.hierarchy.node(this.documentNodeId)?.childIds[0];
|
|
506
|
+
return rootId ? (this.byId.get(rootId) ?? null) : null;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
private syncMarkedSelection(ids: readonly string[]): void {
|
|
510
|
+
const next = new Set(
|
|
511
|
+
ids
|
|
512
|
+
.map((id) => this.byId.get(id) ?? null)
|
|
513
|
+
.filter((object): object is THREE.Object3D => object !== null)
|
|
514
|
+
.filter((object) => object3DAuthoringSubjectOf(object)?.selectionChanged !== undefined),
|
|
515
|
+
);
|
|
516
|
+
for (const object of this.markedSelection) {
|
|
517
|
+
if (!next.has(object)) object3DAuthoringSubjectOf(object)?.selectionChanged?.(false);
|
|
518
|
+
}
|
|
519
|
+
for (const object of next) {
|
|
520
|
+
if (!this.markedSelection.has(object)) {
|
|
521
|
+
object3DAuthoringSubjectOf(object)?.selectionChanged?.(true);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
this.markedSelection = next;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `StoriesProvider` node-id protocol's one reserved value.
|
|
3
|
+
*
|
|
4
|
+
* `storiesFor`/`active`/`apply` all take a node id. The EMPTY id is not a node:
|
|
5
|
+
* it is the WORLD-LEVEL question — "list YOUR stories", asked with no node in
|
|
6
|
+
* hand. A world-level provider (contract scenes, a react root's portable CSF)
|
|
7
|
+
* ignores the node id and answers its whole list; a node-scoped provider (the
|
|
8
|
+
* binding `component-states-registry.ts` hands an adapter) has no node here
|
|
9
|
+
* and answers nothing. That
|
|
10
|
+
* difference is the ONE derivation of "which scope is this provider?" in the
|
|
11
|
+
* editor — `components/inspector-stories-gating.ts`'s
|
|
12
|
+
* `resolveWorldStoriesInput`/`resolveNodeScopedStories` are its two readings
|
|
13
|
+
* and must not grow a third.
|
|
14
|
+
*
|
|
15
|
+
* Because it is a PROBE, the answer to it must be a property of the provider,
|
|
16
|
+
* never of session state: an implementer whose empty-id answer depends on what
|
|
17
|
+
* the user last clicked makes its own scope flip under the shell mid-session.
|
|
18
|
+
* Implementers that special-case the empty id import this constant rather than
|
|
19
|
+
* spelling `''`, so the protocol has one definition and the probe and the
|
|
20
|
+
* answer can never drift apart.
|
|
21
|
+
*
|
|
22
|
+
* It lives here (a leaf module importing nothing) rather than beside the gating
|
|
23
|
+
* probe because the providers in this directory answer it, and
|
|
24
|
+
* `components/inspector-stories-gating.ts` value-imports two of them
|
|
25
|
+
* (`ReactRootAuthoringAdapter`, `CompositeAuthoringAdapter`) — so a back-import
|
|
26
|
+
* from an adapter would be a runtime cycle.
|
|
27
|
+
*
|
|
28
|
+
* Nor does it belong in the engine beside `StoriesProvider`. `@volter/editor-project/adapter`,
|
|
29
|
+
* the barrel every consumer imports that type through, is deliberately
|
|
30
|
+
* TYPE-ONLY (P-6) and may not re-export a value; and reaching past it to
|
|
31
|
+
* `@volter/editor-project/adapter/authoring` (which does carry values) would publish an
|
|
32
|
+
* EDITOR-only protocol constant as a public engine entry point, since the
|
|
33
|
+
* engine's export map is the wildcard `"./*"`.
|
|
34
|
+
*/
|
|
35
|
+
export const WORLD_SCOPE_NODE_ID = '';
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Board chrome — frame names and group names — is CONSTANT-SIZE client-space
|
|
3
|
+
* furniture floating over a board that zooms underneath it (the deliberate
|
|
4
|
+
* Figma-style choice: names stay readable at any scale). The authored gaps
|
|
5
|
+
* that chrome lives in DO shrink with zoom, so below some zoom a constant
|
|
6
|
+
* 26px frame-name stack no longer fits a 64-authored-px row gap and paints
|
|
7
|
+
* over the frames of the row above.
|
|
8
|
+
*
|
|
9
|
+
* This module owns the one rule that prevents that: **chrome degrades, frames
|
|
10
|
+
* never move**. Given the client-space room above a row of frames, it returns
|
|
11
|
+
* the scale/opacity/offset the chrome must adopt so its painted box always
|
|
12
|
+
* ends at or below whatever sits above it. Layout stays zoom-independent.
|
|
13
|
+
*
|
|
14
|
+
* Priority: a group name is the navigation anchor at overview zoom, so it is
|
|
15
|
+
* served FIRST out of the available room and therefore degrades LAST; the
|
|
16
|
+
* frame name gets whatever is left over.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
export const FRAME_LABEL_HEIGHT = 20;
|
|
20
|
+
export const FRAME_LABEL_GAP = 6;
|
|
21
|
+
export const GROUP_LABEL_HEIGHT = 22;
|
|
22
|
+
export const GROUP_LABEL_GAP = 10;
|
|
23
|
+
|
|
24
|
+
/** Client px a frame name claims above its frame's top edge at scale 1. */
|
|
25
|
+
export const FRAME_LABEL_STACK = FRAME_LABEL_HEIGHT + FRAME_LABEL_GAP;
|
|
26
|
+
/** Client px a group name claims above the frame-name stack at scale 1. */
|
|
27
|
+
export const GROUP_LABEL_STACK = GROUP_LABEL_HEIGHT + GROUP_LABEL_GAP;
|
|
28
|
+
|
|
29
|
+
/** Below this scale a name starts fading; below the hide scale it is dropped
|
|
30
|
+
* entirely, because an unreadable sliver of text is noise, not information. */
|
|
31
|
+
const FRAME_FADE_FROM = 0.6;
|
|
32
|
+
const FRAME_HIDE_BELOW = 0.4;
|
|
33
|
+
const GROUP_FADE_FROM = 0.7;
|
|
34
|
+
const GROUP_HIDE_BELOW = 0.45;
|
|
35
|
+
|
|
36
|
+
export interface ChromePlacement {
|
|
37
|
+
/** Uniform scale, applied with `transform-origin` at the element's bottom-left. */
|
|
38
|
+
readonly scale: number;
|
|
39
|
+
/** 0..1; 0 only when `visible` is false. */
|
|
40
|
+
readonly opacity: number;
|
|
41
|
+
/** false → do not paint (and do not accept pointer events) at all. */
|
|
42
|
+
readonly visible: boolean;
|
|
43
|
+
/** Client px to subtract from the row's top edge to get the element's `top`.
|
|
44
|
+
* Accounts for the element's own unscaled height, since the scale pivots on
|
|
45
|
+
* its bottom edge. */
|
|
46
|
+
readonly offset: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface StoryChromePlacement {
|
|
50
|
+
readonly frame: ChromePlacement;
|
|
51
|
+
/** null when the row carries no group name. */
|
|
52
|
+
readonly group: ChromePlacement | null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function fade(scale: number, fadeFrom: number, hideBelow: number): [number, boolean] {
|
|
56
|
+
if (scale >= fadeFrom) return [1, true];
|
|
57
|
+
if (scale <= hideBelow) return [0, false];
|
|
58
|
+
return [(scale - hideBelow) / (fadeFrom - hideBelow), true];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Fit one frame row's chrome into the client-space `room` above it — the
|
|
63
|
+
* distance from the row's top edge to the bottom edge of the nearest frames
|
|
64
|
+
* above it (`Infinity` for the first row of the board, which has nothing
|
|
65
|
+
* above it to collide with).
|
|
66
|
+
*
|
|
67
|
+
* Invariant: the painted top of every returned placement is at or below
|
|
68
|
+
* `rowTop - room`, so chrome never paints over a frame that is not its own.
|
|
69
|
+
*/
|
|
70
|
+
export function placeStoryChrome(room: number, withGroupLabel: boolean): StoryChromePlacement {
|
|
71
|
+
const usable = Math.max(0, room);
|
|
72
|
+
const groupScale = withGroupLabel ? Math.min(1, usable / GROUP_LABEL_STACK) : 0;
|
|
73
|
+
const [groupOpacity, groupVisible] = fade(groupScale, GROUP_FADE_FROM, GROUP_HIDE_BELOW);
|
|
74
|
+
|
|
75
|
+
const frameRoom = Math.max(0, usable - GROUP_LABEL_STACK * groupScale);
|
|
76
|
+
const frameScale = Math.min(1, frameRoom / FRAME_LABEL_STACK);
|
|
77
|
+
const [frameOpacity, frameVisible] = fade(frameScale, FRAME_FADE_FROM, FRAME_HIDE_BELOW);
|
|
78
|
+
|
|
79
|
+
// A dropped frame name reserves nothing, which lets the group name settle
|
|
80
|
+
// closer to the frames instead of floating over an empty band.
|
|
81
|
+
const frameConsumed = frameVisible ? FRAME_LABEL_STACK * frameScale : 0;
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
frame: {
|
|
85
|
+
scale: frameScale,
|
|
86
|
+
opacity: frameOpacity,
|
|
87
|
+
visible: frameVisible,
|
|
88
|
+
offset: FRAME_LABEL_GAP * frameScale + FRAME_LABEL_HEIGHT,
|
|
89
|
+
},
|
|
90
|
+
group: withGroupLabel
|
|
91
|
+
? {
|
|
92
|
+
scale: groupScale,
|
|
93
|
+
opacity: groupOpacity,
|
|
94
|
+
visible: groupVisible,
|
|
95
|
+
offset: frameConsumed + GROUP_LABEL_GAP * groupScale + GROUP_LABEL_HEIGHT,
|
|
96
|
+
}
|
|
97
|
+
: null,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Paint one chrome element at the placement this module computed. */
|
|
102
|
+
export function applyStoryChrome(element: HTMLElement, placement: ChromePlacement): void {
|
|
103
|
+
element.style.transformOrigin = '0 100%';
|
|
104
|
+
element.style.transform = placement.scale >= 1 ? '' : `scale(${placement.scale})`;
|
|
105
|
+
element.style.opacity = placement.visible ? String(placement.opacity) : '0';
|
|
106
|
+
element.style.display = placement.visible ? '' : 'none';
|
|
107
|
+
}
|