@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,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hierarchy context-menu contribution registry — the escape hatch for
|
|
3
|
+
* first-party-only row actions that are NOT contract-expressible through
|
|
4
|
+
* `StructureProvider`/`InspectorProvider`. `GameHierarchy` (the contract-only
|
|
5
|
+
* shell) calls {@link getHierarchyMenuItems} and appends whatever comes back
|
|
6
|
+
* to its own Rename/Duplicate/Show-Hide/Lock/Delete items — it never branches
|
|
7
|
+
* on WHICH registration fired, keeping Rule Zero intact: the shell still
|
|
8
|
+
* speaks only the `AuthoringAdapter` contract, and only a REGISTRATION module
|
|
9
|
+
* is allowed to reach into store internals.
|
|
10
|
+
*
|
|
11
|
+
* PERMANENT adapter-module contribution seam, the same status as
|
|
12
|
+
* `inspector-section-registry.ts`: first-party affordances that aren't
|
|
13
|
+
* (yet, or ever) contract-expressible register through here instead of the
|
|
14
|
+
* contract-only shell branching on adapter identity. If a given affordance later
|
|
15
|
+
* becomes contract-expressible, its OWN registration is removed at that point —
|
|
16
|
+
* the registry mechanism itself is not temporary. Nothing registers today, and
|
|
17
|
+
* an empty registry is a legitimate state.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { EditorShellStore } from './editor-shell-store';
|
|
21
|
+
|
|
22
|
+
export interface HierarchyMenuContext {
|
|
23
|
+
/** The row's node id (an `EditorNode.id` — format-neutral). */
|
|
24
|
+
readonly nodeId: string;
|
|
25
|
+
readonly store: EditorShellStore;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface HierarchyMenuItem {
|
|
29
|
+
readonly label: string;
|
|
30
|
+
readonly action: () => void;
|
|
31
|
+
readonly color?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type Matcher = (ctx: HierarchyMenuContext) => boolean;
|
|
35
|
+
type ItemsFactory = (ctx: HierarchyMenuContext) => HierarchyMenuItem[];
|
|
36
|
+
|
|
37
|
+
interface Registration {
|
|
38
|
+
readonly match: Matcher;
|
|
39
|
+
readonly items: ItemsFactory;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const registrations: Registration[] = [];
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Register a set of first-party (or other non-contract) hierarchy context-menu
|
|
46
|
+
* items. `match` decides whether this registration applies to a given row;
|
|
47
|
+
* `items` builds the actual entries when it does (called only when `match`
|
|
48
|
+
* returns true). Returns an unregister function.
|
|
49
|
+
*/
|
|
50
|
+
export function registerHierarchyMenuItems(match: Matcher, items: ItemsFactory): () => void {
|
|
51
|
+
const reg: Registration = { match, items };
|
|
52
|
+
registrations.push(reg);
|
|
53
|
+
return () => {
|
|
54
|
+
const idx = registrations.indexOf(reg);
|
|
55
|
+
if (idx >= 0) registrations.splice(idx, 1);
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Every registered item that applies to `ctx`, in registration order. */
|
|
60
|
+
export function getHierarchyMenuItems(ctx: HierarchyMenuContext): HierarchyMenuItem[] {
|
|
61
|
+
return registrations.filter((r) => r.match(ctx)).flatMap((r) => r.items(ctx));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Test-only reset for module-level menu registrations. */
|
|
65
|
+
export function __resetHierarchyMenuRegistryForTest(): void {
|
|
66
|
+
registrations.length = 0;
|
|
67
|
+
}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure row-flattening for `IngestHierarchy` (no React) — D-W4 (F14/F18),
|
|
3
|
+
* extracted the same way `hierarchy-rows.ts` extracts `SceneHierarchy`'s
|
|
4
|
+
* equivalent, so the key/collapse/cycle-guard logic is unit-testable without
|
|
5
|
+
* rendering.
|
|
6
|
+
*
|
|
7
|
+
* §0.5's ground truth: an ingested game's structural ids
|
|
8
|
+
* (`ingest:<path>:<type>:<name>`, `@volter/editor-threejs/adapter/ingest/structural-ids`'s
|
|
9
|
+
* `assignStructuralIds`) are baked ONCE at capture and are the key every
|
|
10
|
+
* editor surface addresses an object by — never touched here. But
|
|
11
|
+
* `IngestHierarchy` re-reads the LIVE `Object3D` tree every render
|
|
12
|
+
* (`adapter.hierarchy.node(id)`), and a live game can reorder or clone
|
|
13
|
+
* subtrees after capture, so the SAME baked id can legitimately show up in
|
|
14
|
+
* more than one place in a single walk — `EditorNode.id` alone is no longer
|
|
15
|
+
* a safe React key, and naively recursing `childIds` with no guard can loop
|
|
16
|
+
* forever if a stale/duplicated id ever points back at one of its own
|
|
17
|
+
* ancestors.
|
|
18
|
+
*
|
|
19
|
+
* Per-parent child cap, copied from `hierarchy-rows.ts`'s
|
|
20
|
+
* `flattenVisibleRows`/ `CHILD_CAP`/`MORE_ID_PREFIX` (same constants, no
|
|
21
|
+
* drift). Unlike first-party (which only caps in play mode), the adapter
|
|
22
|
+
* panel's tree is BY DEFINITION a live game scene graph, so `capEnabled`
|
|
23
|
+
* defaults to `false` here (matching this function's PRE-cap behavior
|
|
24
|
+
* byte-for-byte — every existing caller/test that doesn't pass the new params
|
|
25
|
+
* keeps working unchanged) and `IngestHierarchy` explicitly turns it on for
|
|
26
|
+
* the browse view. Search bypasses the cap by calling with `capEnabled=false`
|
|
27
|
+
* (D-C4) — the exact same "flatten UNCAPPED, filter flat" shape this module
|
|
28
|
+
* already used for search before the cap existed.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import type { EditorNode, HierarchyProvider } from '@volter/editor-project/adapter';
|
|
32
|
+
import { CHILD_CAP, MORE_ID_PREFIX } from './hierarchy-rows';
|
|
33
|
+
|
|
34
|
+
/** One flattened, render-ready row over an ingested game's live hierarchy. */
|
|
35
|
+
export interface HierarchyNodeRow {
|
|
36
|
+
readonly node: EditorNode;
|
|
37
|
+
readonly depth: number;
|
|
38
|
+
/**
|
|
39
|
+
* Render key material: the walk path (root index, then child index at
|
|
40
|
+
* each level) — NOT `node.id` alone. Stays unique across a render even
|
|
41
|
+
* when the id scheme collides, because it is derived from POSITION in
|
|
42
|
+
* the walk, not from the adapter's (potentially stale/duplicated) data.
|
|
43
|
+
*/
|
|
44
|
+
readonly pathKey: string;
|
|
45
|
+
readonly hasChildren: boolean;
|
|
46
|
+
/** True when an ANCESTOR's `pathKey` is in the caller's collapsed-set —
|
|
47
|
+
* i.e. this row is inside a collapsed subtree (F18). The row itself is
|
|
48
|
+
* still included in the returned array (so a search can still find it);
|
|
49
|
+
* the component filters it out when not searching. */
|
|
50
|
+
readonly hiddenByCollapse: boolean;
|
|
51
|
+
/** Present on a synthetic "… N more" row that reveals capped siblings
|
|
52
|
+
* (D-C2) — `parentPathKey` is the capped parent's `pathKey`, `hidden` is
|
|
53
|
+
* how many of its children are not shown. Never present on a real row. */
|
|
54
|
+
readonly more?: { readonly parentPathKey: string; readonly hidden: number };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Backstop against a childIds list this guard's own dedup somehow doesn't
|
|
59
|
+
* anticipate (e.g. a very deep but genuinely acyclic live tree) — ingested
|
|
60
|
+
* games are not expected to nest anywhere near this deep; this is a second,
|
|
61
|
+
* independent safety net, not the primary guard (see `visited` below).
|
|
62
|
+
*/
|
|
63
|
+
const MAX_DEPTH = 500;
|
|
64
|
+
|
|
65
|
+
/** How many of a parent's children to walk (D-C1/D-C3) — split out of `walk`
|
|
66
|
+
* below purely to keep that function's cognitive-complexity score down. */
|
|
67
|
+
function childLimit(
|
|
68
|
+
capEnabled: boolean,
|
|
69
|
+
revealed: ReadonlyMap<string, number>,
|
|
70
|
+
parentPathKey: string,
|
|
71
|
+
): number {
|
|
72
|
+
return capEnabled
|
|
73
|
+
? Math.max(CHILD_CAP, revealed.get(parentPathKey) ?? CHILD_CAP)
|
|
74
|
+
: Number.POSITIVE_INFINITY;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** The synthetic "… N more" row for a capped parent (D-C2) — a render-only
|
|
78
|
+
* stub, never fed back to the adapter. Split out of `walk` below purely to
|
|
79
|
+
* keep that function's cognitive-complexity score down. */
|
|
80
|
+
function buildMoreRow(
|
|
81
|
+
parentPathKey: string,
|
|
82
|
+
depth: number,
|
|
83
|
+
parentId: string,
|
|
84
|
+
hiddenByCollapse: boolean,
|
|
85
|
+
hidden: number,
|
|
86
|
+
): HierarchyNodeRow {
|
|
87
|
+
return {
|
|
88
|
+
node: {
|
|
89
|
+
id: `${MORE_ID_PREFIX}${parentPathKey}`,
|
|
90
|
+
label: '',
|
|
91
|
+
kind: 'object',
|
|
92
|
+
parentId,
|
|
93
|
+
childIds: [],
|
|
94
|
+
},
|
|
95
|
+
depth,
|
|
96
|
+
pathKey: `${parentPathKey}/__more__`,
|
|
97
|
+
hasChildren: false,
|
|
98
|
+
hiddenByCollapse,
|
|
99
|
+
more: { parentPathKey, hidden },
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Flatten an ingest adapter's hierarchy into display rows.
|
|
105
|
+
*
|
|
106
|
+
* F14 cycle/dup guard: `visited` tracks every `node.id` already emitted in
|
|
107
|
+
* THIS walk. A live game reordering/cloning objects can make the same baked
|
|
108
|
+
* id reachable from more than one place (a real duplicate) or, in principle,
|
|
109
|
+
* from one of its own descendants (a cycle) — either way the id is stale
|
|
110
|
+
* data describing the CURRENT live scene, not a second logical node. The
|
|
111
|
+
* chosen semantics: render the first occurrence encountered (root-first,
|
|
112
|
+
* then depth-first child order) and silently skip every later one — no
|
|
113
|
+
* second row, and a cycle can never recurse forever. `collapsedKeys` is
|
|
114
|
+
* keyed by `pathKey`, not `node.id` (F18) — a walk-path is stable for "this
|
|
115
|
+
* position in the tree shape", which is what "collapsed" means to a user
|
|
116
|
+
* looking at the panel; keying by id would let a stale/reused id apply a
|
|
117
|
+
* collapse to the WRONG node after a live reorder, or fail to distinguish
|
|
118
|
+
* two positions that happen to share a duplicated id.
|
|
119
|
+
*
|
|
120
|
+
* D-C1/D-C3 cap: when `capEnabled`, each parent's children are limited to
|
|
121
|
+
* `max(CHILD_CAP, revealed.get(parentPathKey) ?? CHILD_CAP)` and a synthetic
|
|
122
|
+
* more-row is appended when some are hidden (D-C2). D-C5: children beyond
|
|
123
|
+
* the limit are never walked, so never added to `visited` — a duplicate id
|
|
124
|
+
* whose first structural occurrence was capped away still renders at its
|
|
125
|
+
* next reachable occurrence (the dedup guard's "once, not zero times"
|
|
126
|
+
* guarantee holds). D-C6: a COLLAPSED parent (its own `pathKey` is in
|
|
127
|
+
* `collapsedKeys`) contributes no child rows and no more-row at all when
|
|
128
|
+
* capped — the walk stops at the parent itself rather than descending and
|
|
129
|
+
* relying on `hiddenByCollapse` filtering, since a more-row would otherwise
|
|
130
|
+
* still need suppressing. Uncapped calls (search, D-C4) are unaffected:
|
|
131
|
+
* collapse only ever gates recursion when `capEnabled`, so a collapsed
|
|
132
|
+
* subtree's matches stay reachable when searching, exactly as before.
|
|
133
|
+
*/
|
|
134
|
+
export function flattenHierarchyRows(
|
|
135
|
+
hierarchy: Pick<HierarchyProvider, 'roots' | 'node'>,
|
|
136
|
+
collapsedKeys: ReadonlySet<string>,
|
|
137
|
+
revealed: ReadonlyMap<string, number> = new Map(),
|
|
138
|
+
capEnabled = false,
|
|
139
|
+
): HierarchyNodeRow[] {
|
|
140
|
+
const rows: HierarchyNodeRow[] = [];
|
|
141
|
+
const visited = new Set<string>();
|
|
142
|
+
|
|
143
|
+
const walk = (node: EditorNode, depth: number, pathKey: string, parentHidden: boolean): void => {
|
|
144
|
+
if (visited.has(node.id) || depth > MAX_DEPTH) return;
|
|
145
|
+
visited.add(node.id);
|
|
146
|
+
|
|
147
|
+
const hasChildren = node.childIds.length > 0;
|
|
148
|
+
rows.push({ node, depth, pathKey, hasChildren, hiddenByCollapse: parentHidden });
|
|
149
|
+
|
|
150
|
+
const isCollapsed = collapsedKeys.has(pathKey);
|
|
151
|
+
if (capEnabled && isCollapsed) return; // D-C6: nothing of a collapsed subtree renders.
|
|
152
|
+
|
|
153
|
+
const childHidden = parentHidden || isCollapsed;
|
|
154
|
+
const shown = Math.min(node.childIds.length, childLimit(capEnabled, revealed, pathKey));
|
|
155
|
+
|
|
156
|
+
for (let i = 0; i < shown; i++) {
|
|
157
|
+
const child = hierarchy.node(node.childIds[i]!);
|
|
158
|
+
if (child) walk(child, depth + 1, `${pathKey}.${i}`, childHidden);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (capEnabled && node.childIds.length > shown) {
|
|
162
|
+
rows.push(
|
|
163
|
+
buildMoreRow(pathKey, depth + 1, node.id, childHidden, node.childIds.length - shown),
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
hierarchy.roots().forEach((root, i) => {
|
|
169
|
+
walk(root, 0, `r${i}`, false);
|
|
170
|
+
});
|
|
171
|
+
return rows;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Patch an uncapped structural snapshot after an identity-unique projection
|
|
176
|
+
* reports the parents whose direct child lists changed.
|
|
177
|
+
*
|
|
178
|
+
* Each changed parent's complete visible subtree is replaced in place. This
|
|
179
|
+
* preserves every unaffected row object and avoids asking the provider about
|
|
180
|
+
* the rest of a large world. Rebuilding the parent (not only its new child)
|
|
181
|
+
* is what preserves exact sibling order and walk-path keys after insert,
|
|
182
|
+
* remove, or reparent. `null` is the conservative answer whenever the delta
|
|
183
|
+
* cannot be related to the previous snapshot; the caller then takes the full
|
|
184
|
+
* {@link flattenHierarchyRows} path.
|
|
185
|
+
*
|
|
186
|
+
* This helper requires provider-unique ids. The live Three projector supplies
|
|
187
|
+
* that invariant when it supplies the parent delta; arbitrary hierarchy
|
|
188
|
+
* providers continue to use the full flattener and its duplicate-id guard.
|
|
189
|
+
*/
|
|
190
|
+
export function patchUniqueHierarchyRows(
|
|
191
|
+
hierarchy: Pick<HierarchyProvider, 'node'>,
|
|
192
|
+
previous: readonly HierarchyNodeRow[],
|
|
193
|
+
changedParentIds: ReadonlySet<string>,
|
|
194
|
+
): HierarchyNodeRow[] | null {
|
|
195
|
+
if (changedParentIds.size === 0) return previous as HierarchyNodeRow[];
|
|
196
|
+
|
|
197
|
+
const rowIndexById = new Map<string, number>();
|
|
198
|
+
for (let index = 0; index < previous.length; index += 1) {
|
|
199
|
+
const row = previous[index]!;
|
|
200
|
+
if (!row.more) rowIndexById.set(row.node.id, index);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
interface Replacement {
|
|
204
|
+
readonly start: number;
|
|
205
|
+
readonly end: number;
|
|
206
|
+
readonly row: HierarchyNodeRow;
|
|
207
|
+
readonly node: EditorNode;
|
|
208
|
+
}
|
|
209
|
+
const candidates: Replacement[] = [];
|
|
210
|
+
for (const id of changedParentIds) {
|
|
211
|
+
const start = rowIndexById.get(id);
|
|
212
|
+
const node = hierarchy.node(id);
|
|
213
|
+
// A removed internal parent is covered by its changed surviving ancestor.
|
|
214
|
+
// Validate that relationship below after all surviving candidates are known.
|
|
215
|
+
if (start === undefined || node === null) continue;
|
|
216
|
+
const row = previous[start]!;
|
|
217
|
+
let end = start + 1;
|
|
218
|
+
while (end < previous.length && previous[end]!.depth > row.depth) end += 1;
|
|
219
|
+
candidates.push({ start, end, row, node });
|
|
220
|
+
}
|
|
221
|
+
if (candidates.length === 0) return null;
|
|
222
|
+
|
|
223
|
+
candidates.sort((a, b) => a.start - b.start);
|
|
224
|
+
const replacements: Replacement[] = [];
|
|
225
|
+
for (const candidate of candidates) {
|
|
226
|
+
const ancestor = replacements.at(-1);
|
|
227
|
+
if (ancestor && candidate.start < ancestor.end) continue;
|
|
228
|
+
replacements.push(candidate);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Every changed parent that existed in the previous snapshot must either be
|
|
232
|
+
// rebuilt itself or lie inside a rebuilt ancestor. Otherwise the delta is
|
|
233
|
+
// incomplete for this view (for example a decorator hid the raw parent).
|
|
234
|
+
for (const id of changedParentIds) {
|
|
235
|
+
const oldIndex = rowIndexById.get(id);
|
|
236
|
+
if (oldIndex === undefined) continue;
|
|
237
|
+
if (!replacements.some(({ start, end }) => oldIndex >= start && oldIndex < end)) return null;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const flattenSubtree = (replacement: Replacement): HierarchyNodeRow[] | null => {
|
|
241
|
+
const rows: HierarchyNodeRow[] = [];
|
|
242
|
+
const visited = new Set<string>();
|
|
243
|
+
let valid = true;
|
|
244
|
+
const walk = (node: EditorNode, depth: number, pathKey: string): void => {
|
|
245
|
+
if (!valid) return;
|
|
246
|
+
if (visited.has(node.id) || depth > MAX_DEPTH) {
|
|
247
|
+
valid = false;
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
visited.add(node.id);
|
|
251
|
+
rows.push({
|
|
252
|
+
node,
|
|
253
|
+
depth,
|
|
254
|
+
pathKey,
|
|
255
|
+
hasChildren: node.childIds.length > 0,
|
|
256
|
+
hiddenByCollapse: false,
|
|
257
|
+
});
|
|
258
|
+
for (let childIndex = 0; childIndex < node.childIds.length; childIndex += 1) {
|
|
259
|
+
const child = hierarchy.node(node.childIds[childIndex]!);
|
|
260
|
+
if (child) walk(child, depth + 1, `${pathKey}.${String(childIndex)}`);
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
walk(replacement.node, replacement.row.depth, replacement.row.pathKey);
|
|
264
|
+
return valid ? rows : null;
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const next = [...previous];
|
|
268
|
+
for (let index = replacements.length - 1; index >= 0; index -= 1) {
|
|
269
|
+
const replacement = replacements[index]!;
|
|
270
|
+
const rows = flattenSubtree(replacement);
|
|
271
|
+
if (rows === null) return null;
|
|
272
|
+
next.splice(replacement.start, replacement.end - replacement.start, ...rows);
|
|
273
|
+
}
|
|
274
|
+
return next;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/** Stable React key for a row — walk path + id, so it never collides even
|
|
278
|
+
* when the underlying id scheme does (F14). */
|
|
279
|
+
export function hierarchyRowKey(row: Pick<HierarchyNodeRow, 'pathKey' | 'node'>): string {
|
|
280
|
+
return `${row.pathKey}:${row.node.id}`;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* The pure start/end row-index math for the hierarchy panel's
|
|
285
|
+
* scroll-windowed rendering. Kept here (not inlined in the component) for two
|
|
286
|
+
* reasons: it is unit-testable standalone with no React/jsdom involved, and a
|
|
287
|
+
* tamper test can `vi.mock` this ONE function to neutralize windowing (return
|
|
288
|
+
* the full range) and prove the render-bounding behavior actually depends on
|
|
289
|
+
* it, not on some other accidental cap.
|
|
290
|
+
*
|
|
291
|
+
* `overscan` extra rows are kept rendered on each side of the visible band
|
|
292
|
+
* so a fast scroll or keyboard nav doesn't flash empty space before the next
|
|
293
|
+
* paint catches up. `end` is clamped to `totalRows`; `start` is clamped to 0
|
|
294
|
+
* (never negative near the top of the list).
|
|
295
|
+
*/
|
|
296
|
+
export function hierarchyRowWindow(
|
|
297
|
+
totalRows: number,
|
|
298
|
+
scrollTop: number,
|
|
299
|
+
viewportPx: number,
|
|
300
|
+
rowH: number,
|
|
301
|
+
overscan: number,
|
|
302
|
+
): { start: number; end: number } {
|
|
303
|
+
const start = Math.max(0, Math.floor(scrollTop / rowH) - overscan);
|
|
304
|
+
const visibleCount = Math.ceil(viewportPx / rowH) + overscan * 2;
|
|
305
|
+
const end = Math.min(totalRows, start + visibleCount);
|
|
306
|
+
return { start, end };
|
|
307
|
+
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `editor.hierarchy()` — the machine door onto the hierarchy panel's ACTUAL
|
|
3
|
+
* rendered row tree.
|
|
4
|
+
*
|
|
5
|
+
* ## Why this publishes instead of re-deriving
|
|
6
|
+
*
|
|
7
|
+
* `inspection/active-subject.ts` answers "what is the inspector showing?" by
|
|
8
|
+
* calling the same composer the panel calls, with the same inputs, at the
|
|
9
|
+
* moment it is asked. That works because every one of the inspector's inputs is
|
|
10
|
+
* reachable from live state.
|
|
11
|
+
*
|
|
12
|
+
* The hierarchy panel's are not. Its final row list is a fold of the adapter's
|
|
13
|
+
* tree, the mark view, the internals reveal, the search term, the child cap,
|
|
14
|
+
* the selection scope, per-world hide flags, AND two pieces of state that live
|
|
15
|
+
* inside the component instance: the session expansion map (`useRef`) and the
|
|
16
|
+
* measured scroll window. A door that re-walked the adapter to "reconstruct"
|
|
17
|
+
* that list would be a SECOND row pipeline, free to disagree with the panel —
|
|
18
|
+
* and a door whose whole purpose is diagnosing the panel is worthless the
|
|
19
|
+
* moment it can disagree with it. That is not hypothetical: `editor.status()`'s
|
|
20
|
+
* `entities` facet (`authoring/shell-document-ops.ts`) walks the RAW adapter
|
|
21
|
+
* hierarchy with no marks, no internals folding and no document promotion, so
|
|
22
|
+
* it reports a tree the panel has never rendered — which is exactly why it
|
|
23
|
+
* could not surface a panel defect.
|
|
24
|
+
*
|
|
25
|
+
* So the panel PUBLISHES what it computed. The snapshot holds the panel's own
|
|
26
|
+
* `HierarchyNodeRow[]` and the panel's own predicates by reference — not copies, not
|
|
27
|
+
* re-derivations — and serialization happens only when the door is called, so a
|
|
28
|
+
* render that nobody reads costs one object allocation.
|
|
29
|
+
*
|
|
30
|
+
* ## What "mounted" means here
|
|
31
|
+
*
|
|
32
|
+
* The publish happens in an effect, so the snapshot describes a tree that has
|
|
33
|
+
* been COMMITTED to the DOM. With no panel mounted there is no snapshot and the
|
|
34
|
+
* door refuses by name rather than answering with an empty tree — a fabricated
|
|
35
|
+
* "the hierarchy is empty" is the anti-shim rule's failure on the one surface
|
|
36
|
+
* that exists to be believed. Because the commit is what publishes, a caller
|
|
37
|
+
* that MUTATES the panel (Expand/Collapse All) takes
|
|
38
|
+
* {@link nextHierarchyPanelSnapshot} before it acts and awaits it, so its ack
|
|
39
|
+
* means "the rows the next `hierarchy()` serializes are the rows this mutation
|
|
40
|
+
* produced" rather than "the mutation was requested".
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
import type { HierarchyNodeRow } from './hierarchy-node-rows';
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* What the panel hands over: its final rows plus the predicates it already
|
|
47
|
+
* evaluated them with. Every member is the panel's own — see this module's
|
|
48
|
+
* header for why nothing here is recomputed.
|
|
49
|
+
*/
|
|
50
|
+
export interface HierarchyPanelSnapshot {
|
|
51
|
+
/** The panel's final row list, in display order, AFTER search / cap /
|
|
52
|
+
* collapse / scope / world-hide filtering — i.e. the rows a human scrolls. */
|
|
53
|
+
readonly rows: readonly HierarchyNodeRow[];
|
|
54
|
+
/** The slice actually in the DOM right now (virtualization window). */
|
|
55
|
+
readonly window: { readonly start: number; readonly end: number };
|
|
56
|
+
/** The active search term, or `null` when browsing. */
|
|
57
|
+
readonly searchTerm: string | null;
|
|
58
|
+
/** The row the panel is scoped into (double-clicked instance), or `null`. */
|
|
59
|
+
readonly scopeId: string | null;
|
|
60
|
+
/** The panel's own expansion verdict — session state, then the persisted
|
|
61
|
+
* preference, then the shape/mark defaults. */
|
|
62
|
+
readonly isExpanded: (row: HierarchyNodeRow) => boolean;
|
|
63
|
+
/** True for a row that exists only because internals were revealed. */
|
|
64
|
+
readonly isInternal: (id: string) => boolean;
|
|
65
|
+
/** True for a row carrying `vgaiComponentRoot`. */
|
|
66
|
+
readonly isComponentRoot: (id: string) => boolean;
|
|
67
|
+
/** How many children this row's view FOLDED AWAY as implementation. */
|
|
68
|
+
readonly foldedInternalCount: (id: string) => number;
|
|
69
|
+
/** The panel's own Expand All action. Machine readers use the same mutation
|
|
70
|
+
* as the toolbar, then read a later committed snapshot; they never bypass
|
|
71
|
+
* collapse state by walking the adapter behind the panel. */
|
|
72
|
+
readonly expandAll: () => void;
|
|
73
|
+
/** The panel's own Collapse All action — the SAME toolbar button's other
|
|
74
|
+
* half. It exists because Expand All alone is a one-way door: once a
|
|
75
|
+
* machine reader expands, nothing through the product restores the tree's
|
|
76
|
+
* rest state (the fold is written to this project's persisted preference,
|
|
77
|
+
* and a chevron's own click is not drivable — `editor.document.click`
|
|
78
|
+
* refuses editor chrome by name). A rest state the product cannot return
|
|
79
|
+
* to is a rest state the product cannot certify. */
|
|
80
|
+
readonly collapseAll: () => void;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** One serialized panel row. Nested, because the shape of the tree IS the
|
|
84
|
+
* thing under diagnosis. */
|
|
85
|
+
export interface SerializedHierarchyRow {
|
|
86
|
+
id: string;
|
|
87
|
+
label: string;
|
|
88
|
+
/** The dim type suffix the row prints (`Coin1 ·Coin`). */
|
|
89
|
+
typeLabel?: string;
|
|
90
|
+
role?: string;
|
|
91
|
+
depth: number;
|
|
92
|
+
/**
|
|
93
|
+
* Children the row's own view has — what opening the caret reveals. This is
|
|
94
|
+
* the PROJECTED count: implementation children folded by the mark view are
|
|
95
|
+
* not in it (they are in {@link internalChildCount}).
|
|
96
|
+
*/
|
|
97
|
+
childCount: number;
|
|
98
|
+
/** Children folded away as implementation, reachable through "Reveal
|
|
99
|
+
* Internals". Non-zero with `childCount: 0` is a row whose whole subtree is
|
|
100
|
+
* machinery. */
|
|
101
|
+
internalChildCount: number;
|
|
102
|
+
/**
|
|
103
|
+
* Whether the panel renders a disclosure control on this row. THE
|
|
104
|
+
* load-bearing field: a row with children of any kind and
|
|
105
|
+
* `expandable: false` is a subtree the UI offers no way to reach.
|
|
106
|
+
*/
|
|
107
|
+
expandable: boolean;
|
|
108
|
+
/** Only meaningful when {@link expandable}. */
|
|
109
|
+
expanded?: boolean;
|
|
110
|
+
/** Read-only, de-emphasized revealed-internal row. */
|
|
111
|
+
internal?: true;
|
|
112
|
+
/** Marked component-instance root. */
|
|
113
|
+
componentRoot?: true;
|
|
114
|
+
/** A synthetic "… N more" cap stub rather than a real node. */
|
|
115
|
+
more?: { hidden: number };
|
|
116
|
+
children?: readonly SerializedHierarchyRow[];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** The whole panel, as data. */
|
|
120
|
+
export interface SerializedHierarchyPanel {
|
|
121
|
+
/** Total rows in the panel's list (not just the windowed slice). */
|
|
122
|
+
rowCount: number;
|
|
123
|
+
/** The slice in the DOM; `end - start < rowCount` means scrolling reveals more. */
|
|
124
|
+
window: { start: number; end: number };
|
|
125
|
+
/** Present only while a search is filtering the tree. */
|
|
126
|
+
search?: string;
|
|
127
|
+
/** Present only while the panel is scoped into a subtree. */
|
|
128
|
+
scopeId?: string;
|
|
129
|
+
/** Which surface the rows belong to — a play-mode tree and an edit-mode tree
|
|
130
|
+
* come from different adapters, and telling them apart is the first question
|
|
131
|
+
* any hierarchy diagnosis asks. */
|
|
132
|
+
playState: string;
|
|
133
|
+
activeViewportTab: string;
|
|
134
|
+
roots: readonly SerializedHierarchyRow[];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ------------------------------------------------------------ session state
|
|
138
|
+
|
|
139
|
+
let published: HierarchyPanelSnapshot | null = null;
|
|
140
|
+
|
|
141
|
+
/** Callers parked in {@link nextHierarchyPanelSnapshot}, settled by the next
|
|
142
|
+
* publish (resolve) or by the panel going away (reject). */
|
|
143
|
+
const waiters: Array<{
|
|
144
|
+
readonly resolve: (snapshot: HierarchyPanelSnapshot) => void;
|
|
145
|
+
readonly reject: (error: Error) => void;
|
|
146
|
+
}> = [];
|
|
147
|
+
|
|
148
|
+
/** Called by `GameHierarchy` after every commit. */
|
|
149
|
+
export function publishHierarchyPanelSnapshot(snapshot: HierarchyPanelSnapshot): void {
|
|
150
|
+
published = snapshot;
|
|
151
|
+
if (waiters.length === 0) return;
|
|
152
|
+
for (const waiter of waiters.splice(0, waiters.length)) waiter.resolve(snapshot);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Resolve on the panel's NEXT published snapshot — i.e. the next React commit.
|
|
157
|
+
*
|
|
158
|
+
* A mutation through the snapshot's own actions (`expandAll`/`collapseAll`)
|
|
159
|
+
* only mutates a ref and schedules a re-render; the rows the door serializes
|
|
160
|
+
* are republished from the panel's effect. Take this promise BEFORE calling the
|
|
161
|
+
* action and await it after, and the mutation's ack lands on the committed
|
|
162
|
+
* tree. No timeout: the actions force a render unconditionally
|
|
163
|
+
* (`useReducer` increment — never a bail-out, even when the expansion map is
|
|
164
|
+
* unchanged), so a publish always follows, and a caller that would otherwise
|
|
165
|
+
* hang is instead rejected by {@link clearHierarchyPanelSnapshot}.
|
|
166
|
+
*/
|
|
167
|
+
export function nextHierarchyPanelSnapshot(): Promise<HierarchyPanelSnapshot> {
|
|
168
|
+
return new Promise<HierarchyPanelSnapshot>((resolve, reject) => {
|
|
169
|
+
waiters.push({ resolve, reject });
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Called on unmount. Guarded so a remount's publish is never clobbered by the
|
|
174
|
+
* outgoing instance's cleanup (effect cleanup runs after the next mount's
|
|
175
|
+
* effect in a React remount). */
|
|
176
|
+
export function clearHierarchyPanelSnapshot(snapshot: HierarchyPanelSnapshot): void {
|
|
177
|
+
if (published !== snapshot) return;
|
|
178
|
+
published = null;
|
|
179
|
+
if (waiters.length === 0) return;
|
|
180
|
+
// This cleanup is NOT unmount-only: the panel's publish effect depends on the
|
|
181
|
+
// snapshot object, which is fresh every render, so an ordinary update runs
|
|
182
|
+
// this clear and then the new publish back-to-back inside one commit. Only a
|
|
183
|
+
// real unmount leaves `published` null once that commit has drained, so the
|
|
184
|
+
// rejection is deferred one microtask and skipped if a publish arrived.
|
|
185
|
+
queueMicrotask(() => {
|
|
186
|
+
if (published !== null || waiters.length === 0) return;
|
|
187
|
+
for (const waiter of waiters.splice(0, waiters.length)) {
|
|
188
|
+
waiter.reject(
|
|
189
|
+
new Error(
|
|
190
|
+
'the hierarchy panel (GameHierarchy) unmounted before it published the mutated row tree, so the mutation cannot be acknowledged against a rendered tree. Open the Hierarchy panel in the workspace dock and retry.',
|
|
191
|
+
),
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** `null` when no hierarchy panel is mounted. */
|
|
198
|
+
export function hierarchyPanelSnapshot(): HierarchyPanelSnapshot | null {
|
|
199
|
+
return published;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** Test-only reset for the module-level singleton. */
|
|
203
|
+
export function __resetHierarchyPanelSnapshotForTest(): void {
|
|
204
|
+
published = null;
|
|
205
|
+
waiters.length = 0;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// -------------------------------------------------------------- serialization
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Turn the panel's flat, depth-tagged rows back into the nesting a reader sees.
|
|
212
|
+
*
|
|
213
|
+
* The flattener emits rows in display order with a `depth`, so a depth stack
|
|
214
|
+
* rebuilds the parenting exactly — including a search result set, whose depths
|
|
215
|
+
* jump (an ancestor may be filtered out), which the stack handles by popping to
|
|
216
|
+
* the nearest shallower row rather than inventing a parent.
|
|
217
|
+
*/
|
|
218
|
+
export function serializeHierarchyPanel(
|
|
219
|
+
snapshot: HierarchyPanelSnapshot,
|
|
220
|
+
mode: { readonly playState: string; readonly activeViewportTab: string },
|
|
221
|
+
): SerializedHierarchyPanel {
|
|
222
|
+
const roots: SerializedHierarchyRow[] = [];
|
|
223
|
+
/** The open ancestor chain: `stack[i]` is the last row emitted at depth `i`. */
|
|
224
|
+
const stack: SerializedHierarchyRow[] = [];
|
|
225
|
+
|
|
226
|
+
for (const row of snapshot.rows) {
|
|
227
|
+
const serialized = serializeRow(row, snapshot);
|
|
228
|
+
while (stack.length > row.depth) stack.pop();
|
|
229
|
+
const parent = stack.length > 0 ? stack[stack.length - 1] : undefined;
|
|
230
|
+
if (parent === undefined) {
|
|
231
|
+
roots.push(serialized);
|
|
232
|
+
} else {
|
|
233
|
+
const children = parent.children as SerializedHierarchyRow[] | undefined;
|
|
234
|
+
if (children === undefined) parent.children = [serialized];
|
|
235
|
+
else children.push(serialized);
|
|
236
|
+
}
|
|
237
|
+
stack.push(serialized);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
rowCount: snapshot.rows.length,
|
|
242
|
+
window: { start: snapshot.window.start, end: snapshot.window.end },
|
|
243
|
+
...(snapshot.searchTerm ? { search: snapshot.searchTerm } : {}),
|
|
244
|
+
...(snapshot.scopeId ? { scopeId: snapshot.scopeId } : {}),
|
|
245
|
+
playState: mode.playState,
|
|
246
|
+
activeViewportTab: mode.activeViewportTab,
|
|
247
|
+
roots,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function serializeRow(
|
|
252
|
+
row: HierarchyNodeRow,
|
|
253
|
+
snapshot: HierarchyPanelSnapshot,
|
|
254
|
+
): SerializedHierarchyRow {
|
|
255
|
+
const { node } = row;
|
|
256
|
+
if (row.more) {
|
|
257
|
+
return {
|
|
258
|
+
id: node.id,
|
|
259
|
+
label: `… ${row.more.hidden} more`,
|
|
260
|
+
depth: row.depth,
|
|
261
|
+
childCount: 0,
|
|
262
|
+
internalChildCount: 0,
|
|
263
|
+
expandable: false,
|
|
264
|
+
more: { hidden: row.more.hidden },
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
return {
|
|
268
|
+
id: node.id,
|
|
269
|
+
label: node.label,
|
|
270
|
+
...(node.typeLabel === undefined ? {} : { typeLabel: node.typeLabel }),
|
|
271
|
+
...(node.role === undefined ? {} : { role: node.role }),
|
|
272
|
+
depth: row.depth,
|
|
273
|
+
childCount: node.childIds.length,
|
|
274
|
+
internalChildCount: snapshot.foldedInternalCount(node.id),
|
|
275
|
+
expandable: row.hasChildren,
|
|
276
|
+
...(row.hasChildren ? { expanded: snapshot.isExpanded(row) } : {}),
|
|
277
|
+
...(snapshot.isInternal(node.id) ? { internal: true as const } : {}),
|
|
278
|
+
...(snapshot.isComponentRoot(node.id) ? { componentRoot: true as const } : {}),
|
|
279
|
+
};
|
|
280
|
+
}
|