@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,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project-authored hierarchy projection (D20).
|
|
3
|
+
*
|
|
4
|
+
* This is editor metadata, not runtime composition. `vgai.project.json.roots`
|
|
5
|
+
* declares adapter mounts; `vgai.project.json.authoring.hierarchy` only
|
|
6
|
+
* chooses how those roots are labelled and grouped in the authoring tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export interface HierarchyProjectionGroup {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly label: string;
|
|
12
|
+
readonly roots: readonly string[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface HierarchyProjection {
|
|
16
|
+
readonly rootLabels?: Readonly<Record<string, string>>;
|
|
17
|
+
readonly groups?: readonly HierarchyProjectionGroup[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function record(value: unknown): Record<string, unknown> | null {
|
|
21
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
22
|
+
? (value as Record<string, unknown>)
|
|
23
|
+
: null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Leniently read authoring metadata. Invalid entries are omitted so a typo in
|
|
28
|
+
* an optional projection can never make the game itself unopenable.
|
|
29
|
+
*/
|
|
30
|
+
export function parseHierarchyProjection(value: unknown): HierarchyProjection | undefined {
|
|
31
|
+
const source = record(value);
|
|
32
|
+
if (!source) return undefined;
|
|
33
|
+
|
|
34
|
+
const labelsSource = record(source['rootLabels']);
|
|
35
|
+
const labelEntries = labelsSource
|
|
36
|
+
? Object.entries(labelsSource).flatMap(([id, label]): Array<[string, string]> => {
|
|
37
|
+
const normalizedId = id.trim();
|
|
38
|
+
const normalizedLabel = typeof label === 'string' ? label.trim() : '';
|
|
39
|
+
return normalizedId && normalizedLabel ? [[normalizedId, normalizedLabel]] : [];
|
|
40
|
+
})
|
|
41
|
+
: [];
|
|
42
|
+
const rootLabels = labelEntries.length > 0 ? Object.fromEntries(labelEntries) : undefined;
|
|
43
|
+
|
|
44
|
+
const groupIds = new Set<string>();
|
|
45
|
+
const groupEntries = Array.isArray(source['groups'])
|
|
46
|
+
? source['groups'].flatMap((candidate): HierarchyProjectionGroup[] => {
|
|
47
|
+
const group = record(candidate);
|
|
48
|
+
const id = typeof group?.['id'] === 'string' ? group['id'].trim() : '';
|
|
49
|
+
const label = typeof group?.['label'] === 'string' ? group['label'].trim() : '';
|
|
50
|
+
const roots = Array.isArray(group?.['roots'])
|
|
51
|
+
? group['roots'].flatMap((root): string[] => {
|
|
52
|
+
const normalized = typeof root === 'string' ? root.trim() : '';
|
|
53
|
+
return normalized ? [normalized] : [];
|
|
54
|
+
})
|
|
55
|
+
: [];
|
|
56
|
+
if (!id || !label || roots.length === 0 || groupIds.has(id)) return [];
|
|
57
|
+
groupIds.add(id);
|
|
58
|
+
return [{ id, label, roots: [...new Set(roots)] }];
|
|
59
|
+
})
|
|
60
|
+
: [];
|
|
61
|
+
const groups = groupEntries.length > 0 ? groupEntries : undefined;
|
|
62
|
+
|
|
63
|
+
if (!rootLabels && !groups) return undefined;
|
|
64
|
+
return {
|
|
65
|
+
...(rootLabels ? { rootLabels } : {}),
|
|
66
|
+
...(groups ? { groups } : {}),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Read the projection from a raw `vgai.project.json` config object. */
|
|
71
|
+
export function hierarchyProjectionFromProjectConfig(
|
|
72
|
+
config: unknown,
|
|
73
|
+
): HierarchyProjection | undefined {
|
|
74
|
+
const authoring = record(record(config)?.['authoring']);
|
|
75
|
+
return parseHierarchyProjection(authoring?.['hierarchy']);
|
|
76
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the hierarchy panel is allowed to REUSE between two renders, and the
|
|
3
|
+
* row index that makes a selection change cost `O(selection × depth)` instead
|
|
4
|
+
* of `O(nodes)`.
|
|
5
|
+
*
|
|
6
|
+
* THE DEFECT THIS EXISTS FOR (scale-speed baseline, 2026-08-19, 22 of 43
|
|
7
|
+
* offender rows): `GameHierarchySurface` re-renders on every store notify — it
|
|
8
|
+
* has to, because the highlight moves — and its render body rebuilds the whole
|
|
9
|
+
* row pipeline from `adapter.hierarchy`: one uncapped flatten of every node,
|
|
10
|
+
* the per-node first-open policy, a second capped flatten, and a per-row
|
|
11
|
+
* ancestor climb. On a 20 000-node world that is 100-430ms of main-thread
|
|
12
|
+
* block AFTER a `select` whose reply already went out in 3ms, and it is paid
|
|
13
|
+
* for a change that touched nothing the walk reads.
|
|
14
|
+
*
|
|
15
|
+
* The two slots below split that pipeline where its inputs actually split:
|
|
16
|
+
*
|
|
17
|
+
* - {@link HierarchyRowCache.structural} holds everything derived from the
|
|
18
|
+
* TREE alone. Its key carries the store's `contentVersion` and the
|
|
19
|
+
* adapter's structural notification epoch. The store version stands
|
|
20
|
+
* still for a selection-only notify and moves for every other mutation
|
|
21
|
+
* (see `EditorShellStore.contentVersion`) — including the adapter's own
|
|
22
|
+
* `notifyIngestEdit` on a live structural change, which is what makes a
|
|
23
|
+
* late-arriving subtree invalidate this on the tick it lands.
|
|
24
|
+
* - {@link HierarchyRowCache.collapsed} holds the FOLD projected onto the
|
|
25
|
+
* tree — the set of row paths that are collapsed right now. Deriving it
|
|
26
|
+
* scans every structural row, so it is `O(nodes)`; its inputs are the tree
|
|
27
|
+
* and the fold, and SELECTION IS NOT ONE OF THEM. It has its own slot
|
|
28
|
+
* because the browse view below keys on the reveal a selection opens, and
|
|
29
|
+
* folding that `O(nodes)` scan into the same slot made every click pay it.
|
|
30
|
+
* - {@link HierarchyRowCache.browse} holds the capped/collapsed/searched
|
|
31
|
+
* view. It keys on the structural value BY IDENTITY plus the fold, scope,
|
|
32
|
+
* search and reveal state — so a selection that reveals nothing new reuses
|
|
33
|
+
* it, and one that does reveal something rebuilds it.
|
|
34
|
+
*
|
|
35
|
+
* Each slot holds ONE entry. The panel renders one tree at a time, and a
|
|
36
|
+
* one-entry memo cannot leak: the moment the key moves, the old value is
|
|
37
|
+
* dropped. Keys are compared element-wise with `Object.is`, so every entry
|
|
38
|
+
* must be a primitive or a stable reference — never a freshly built object
|
|
39
|
+
* (a `Set`/`Map` built per render would never compare equal and would make
|
|
40
|
+
* the cache a pure cost). Signatures are the way to put a collection in a key.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
import type { HierarchyNodeRow } from './hierarchy-node-rows';
|
|
44
|
+
|
|
45
|
+
/** Element-wise `Object.is` over two key tuples. */
|
|
46
|
+
function sameKey(a: readonly unknown[], b: readonly unknown[]): boolean {
|
|
47
|
+
if (a.length !== b.length) return false;
|
|
48
|
+
for (let i = 0; i < a.length; i += 1) if (!Object.is(a[i], b[i])) return false;
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** One memo slot: the last key it computed for, and the value it produced. */
|
|
53
|
+
class Slot<V> {
|
|
54
|
+
#key: readonly unknown[] | null = null;
|
|
55
|
+
#value: V | undefined;
|
|
56
|
+
/** How many times `compute` actually ran. Read by tests; never by product code. */
|
|
57
|
+
computeCount = 0;
|
|
58
|
+
|
|
59
|
+
get current(): V | undefined {
|
|
60
|
+
return this.#value;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
read(key: readonly unknown[], compute: (previous: V | undefined) => V): V {
|
|
64
|
+
if (this.#key !== null && sameKey(this.#key, key)) return this.#value as V;
|
|
65
|
+
const value = compute(this.#value);
|
|
66
|
+
this.#key = key;
|
|
67
|
+
this.#value = value;
|
|
68
|
+
this.computeCount += 1;
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* The panel's two memo slots. Held in a `useRef` (never module state, so it
|
|
75
|
+
* cannot leak between editor sessions — the same stance `TransformLockCache`
|
|
76
|
+
* takes).
|
|
77
|
+
*/
|
|
78
|
+
export class HierarchyRowCache<Structural, Browse, Collapsed = unknown> {
|
|
79
|
+
readonly #structural = new Slot<Structural>();
|
|
80
|
+
readonly #collapsed = new Slot<Collapsed>();
|
|
81
|
+
readonly #browse = new Slot<Browse>();
|
|
82
|
+
/**
|
|
83
|
+
* `useDeferredValue` can render 11, then speculatively render 10, then catch
|
|
84
|
+
* up to 12. A render-time one-slot memo must not let that backward key
|
|
85
|
+
* replace 11 as the predecessor for 12's exact structural delta.
|
|
86
|
+
*/
|
|
87
|
+
#structuralAdapter: unknown;
|
|
88
|
+
#structuralVersion = Number.NEGATIVE_INFINITY;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The tree-only half. `key` must name the adapter identity, the store's
|
|
92
|
+
* `contentVersion`, and any adapter-owned structural notification epoch;
|
|
93
|
+
* nothing in it may move for a selection change.
|
|
94
|
+
*/
|
|
95
|
+
structural(
|
|
96
|
+
key: readonly unknown[],
|
|
97
|
+
compute: (previous: Structural | undefined) => Structural,
|
|
98
|
+
): Structural {
|
|
99
|
+
const [adapter, version] = key;
|
|
100
|
+
if (
|
|
101
|
+
adapter === this.#structuralAdapter &&
|
|
102
|
+
typeof version === 'number' &&
|
|
103
|
+
version < this.#structuralVersion &&
|
|
104
|
+
this.#structural.current !== undefined
|
|
105
|
+
) {
|
|
106
|
+
return this.#structural.current;
|
|
107
|
+
}
|
|
108
|
+
const value = this.#structural.read(key, compute);
|
|
109
|
+
if (adapter !== this.#structuralAdapter) {
|
|
110
|
+
this.#structuralAdapter = adapter;
|
|
111
|
+
this.#structuralVersion = Number.NEGATIVE_INFINITY;
|
|
112
|
+
}
|
|
113
|
+
if (typeof version === 'number') {
|
|
114
|
+
this.#structuralVersion = Math.max(this.#structuralVersion, version);
|
|
115
|
+
}
|
|
116
|
+
return value;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* The fold-only half. `key` must START with the structural value itself and
|
|
121
|
+
* carry the fold generation/scope — and, like {@link structural}, nothing a
|
|
122
|
+
* selection moves.
|
|
123
|
+
*/
|
|
124
|
+
collapsed(
|
|
125
|
+
key: readonly unknown[],
|
|
126
|
+
compute: (previous: Collapsed | undefined) => Collapsed,
|
|
127
|
+
): Collapsed {
|
|
128
|
+
return this.#collapsed.read(key, compute);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* The capped/collapsed/searched half. `key` must START with the structural
|
|
133
|
+
* value itself, so a rebuilt tree can never be viewed through a stale
|
|
134
|
+
* browse result.
|
|
135
|
+
*/
|
|
136
|
+
browse(key: readonly unknown[], compute: (previous: Browse | undefined) => Browse): Browse {
|
|
137
|
+
return this.#browse.read(key, compute);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** How many times each slot re-derived. Test/instrumentation only. */
|
|
141
|
+
get counts(): { structural: number; collapsed: number; browse: number } {
|
|
142
|
+
return {
|
|
143
|
+
structural: this.#structural.computeCount,
|
|
144
|
+
collapsed: this.#collapsed.computeCount,
|
|
145
|
+
browse: this.#browse.computeCount,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// --------------------------------------------------------------- row index
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Where every row sits, indexed both ways.
|
|
154
|
+
*
|
|
155
|
+
* Built once per structural walk and cached with it. Both selection-driven
|
|
156
|
+
* derivations below used to SCAN every row (and `selectedAncestorNodeIds`
|
|
157
|
+
* additionally built an N-entry `Map` of its own) on every render, which is
|
|
158
|
+
* `O(nodes)` work whose answer is about a handful of selected ids.
|
|
159
|
+
*/
|
|
160
|
+
export interface RowPathIndex {
|
|
161
|
+
/** `pathKey` → node id, for every real (non-`more`) row. */
|
|
162
|
+
readonly nodeIdByPathKey: ReadonlyMap<string, string>;
|
|
163
|
+
/** node id → every `pathKey` that node is rendered at. A live tree can reach
|
|
164
|
+
* one id from more than one place; the flattener keeps the first, but the
|
|
165
|
+
* index keeps them all so nothing depends on which walk order found it. */
|
|
166
|
+
readonly pathKeysByNodeId: ReadonlyMap<string, readonly string[]>;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function indexRowPaths(rows: readonly HierarchyNodeRow[]): RowPathIndex {
|
|
170
|
+
const nodeIdByPathKey = new Map<string, string>();
|
|
171
|
+
const pathKeysByNodeId = new Map<string, string[]>();
|
|
172
|
+
for (const row of rows) {
|
|
173
|
+
if (row.more) continue;
|
|
174
|
+
nodeIdByPathKey.set(row.pathKey, row.node.id);
|
|
175
|
+
const existing = pathKeysByNodeId.get(row.node.id);
|
|
176
|
+
if (existing) existing.push(row.pathKey);
|
|
177
|
+
else pathKeysByNodeId.set(row.node.id, [row.pathKey]);
|
|
178
|
+
}
|
|
179
|
+
return { nodeIdByPathKey, pathKeysByNodeId };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** Every strict-ancestor path of `pathKey`, outermost first. */
|
|
183
|
+
export function ancestorPathKeys(pathKey: string): string[] {
|
|
184
|
+
const parts = pathKey.split('.');
|
|
185
|
+
const ancestors: string[] = [];
|
|
186
|
+
for (let i = 1; i < parts.length; i++) ancestors.push(parts.slice(0, i).join('.'));
|
|
187
|
+
return ancestors;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** The node ids of every ancestor of every selected row — the branch selection
|
|
191
|
+
* reveal opens. `O(selection × depth)`. */
|
|
192
|
+
export function selectedAncestorNodeIds(
|
|
193
|
+
index: RowPathIndex,
|
|
194
|
+
selectedIds: ReadonlySet<string>,
|
|
195
|
+
): Set<string> {
|
|
196
|
+
const ids = new Set<string>();
|
|
197
|
+
for (const selected of selectedIds) {
|
|
198
|
+
for (const pathKey of index.pathKeysByNodeId.get(selected) ?? []) {
|
|
199
|
+
for (const ancestor of ancestorPathKeys(pathKey)) {
|
|
200
|
+
const id = index.nodeIdByPathKey.get(ancestor);
|
|
201
|
+
if (id) ids.add(id);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return ids;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** How many children each ancestor of a selected row must show for that row to
|
|
209
|
+
* survive the browse-view child cap. `O(selection × depth)`. */
|
|
210
|
+
export function selectedRevealCounts(
|
|
211
|
+
index: RowPathIndex,
|
|
212
|
+
selectedIds: ReadonlySet<string>,
|
|
213
|
+
): Map<string, number> {
|
|
214
|
+
const revealed = new Map<string, number>();
|
|
215
|
+
for (const selected of selectedIds) {
|
|
216
|
+
for (const pathKey of index.pathKeysByNodeId.get(selected) ?? []) {
|
|
217
|
+
const parts = pathKey.split('.');
|
|
218
|
+
let parent = parts[0]!;
|
|
219
|
+
for (let i = 1; i < parts.length; i++) {
|
|
220
|
+
const childIndex = Number(parts[i]);
|
|
221
|
+
if (Number.isFinite(childIndex)) {
|
|
222
|
+
revealed.set(parent, Math.max(revealed.get(parent) ?? 0, childIndex + 1));
|
|
223
|
+
}
|
|
224
|
+
parent = `${parent}.${parts[i]}`;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return revealed;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* A stable, order-independent string for a reveal map, so it can sit in a memo
|
|
233
|
+
* key that is compared with `Object.is`. Reveal maps are small (one entry per
|
|
234
|
+
* ancestor of a selected/expanded row), which is what makes a signature the
|
|
235
|
+
* right shape here rather than a version counter.
|
|
236
|
+
*/
|
|
237
|
+
export function revealSignature(revealed: ReadonlyMap<string, number>): string {
|
|
238
|
+
if (revealed.size === 0) return '';
|
|
239
|
+
return [...revealed]
|
|
240
|
+
.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0))
|
|
241
|
+
.map(([pathKey, count]) => `${pathKey}=${String(count)}`)
|
|
242
|
+
.join(',');
|
|
243
|
+
}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure row-model math for the hierarchy panel.
|
|
3
|
+
*
|
|
4
|
+
* Four questions a row needs answered, all extracted here so they are unit
|
|
5
|
+
* testable without a DOM, an adapter session, or a live source tree:
|
|
6
|
+
*
|
|
7
|
+
* 1. **Is this row a component instance, and what is its type?** The
|
|
8
|
+
* adapter already computes `EditorNode.typeLabel`; the row just needs to
|
|
9
|
+
* know when to print it. Detached `#n` pockets deliberately carry no
|
|
10
|
+
* `typeLabel` — a pocket must not impersonate the `<Enemy>` that
|
|
11
|
+
* rendered it — so "has a typeLabel AND is a component row" is the whole
|
|
12
|
+
* rule and no special-casing of pockets is needed here.
|
|
13
|
+
* 2. **Is every transform channel refused, and with what sentence?**
|
|
14
|
+
* The adapter's `reason` is the ONE canonical text (doctrine rule 2): the
|
|
15
|
+
* hierarchy tooltip, the inspector field, and the gizmo-denial hint all
|
|
16
|
+
* show this exact string, never a paraphrase. So this module NEVER writes
|
|
17
|
+
* a reason of its own — it only forwards the adapter's.
|
|
18
|
+
* 3. **Does this row have authorability warnings, and what do they say?**
|
|
19
|
+
* Same rule as H2, one step stronger: the diagnostic message is written by
|
|
20
|
+
* the analyzer that found the problem and is shown VERBATIM. This module
|
|
21
|
+
* picks no wording, adds no severity of its own and truncates nothing — it
|
|
22
|
+
* counts and newline-joins.
|
|
23
|
+
* 4. **What may this row DO?** One predicate ({@link rowAffordances}) that
|
|
24
|
+
* every gate in the panel consults, instead of five copies of
|
|
25
|
+
* `!isStructural && !isInternal` drifting apart.
|
|
26
|
+
*
|
|
27
|
+
* Cost note: `R3fSourceAuthoringAdapter.editability` re-analyzes JSX
|
|
28
|
+
* attributes from cached source text on every call (string scan + parse). It
|
|
29
|
+
* is NOT free per render, which is why {@link transformLockSummary}
|
|
30
|
+
* short-circuits on the first WRITABLE channel (the overwhelmingly common
|
|
31
|
+
* case costs exactly one probe, not three) and why {@link TransformLockCache}
|
|
32
|
+
* exists at all.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import type { EditorNode, TransformChannel, TransformEditability } from '@volter/editor-project/adapter';
|
|
36
|
+
|
|
37
|
+
/** The three channels a lock glyph summarizes, in probe order. */
|
|
38
|
+
const CHANNELS: readonly TransformChannel[] = ['position', 'rotation', 'scale'];
|
|
39
|
+
|
|
40
|
+
// ------------------------------------------------------------------ H1
|
|
41
|
+
|
|
42
|
+
export interface RowIdentity {
|
|
43
|
+
/** The row's own name — unchanged, and still the ONLY thing search matches. */
|
|
44
|
+
readonly label: string;
|
|
45
|
+
/** The component type to print as a dim suffix, or null for a plain row. */
|
|
46
|
+
readonly typeSuffix: string | null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* H1 — `EnemyBravo ·Enemy`. A row earns the type suffix (and the instance
|
|
51
|
+
* accent tint that travels with it) only when it BOTH represents a component
|
|
52
|
+
* instance (`role: 'component'`) and the adapter told us its type.
|
|
53
|
+
*/
|
|
54
|
+
export function rowIdentity(node: Pick<EditorNode, 'label' | 'role' | 'typeLabel'>): RowIdentity {
|
|
55
|
+
const isInstance = node.role === 'component' && !!node.typeLabel;
|
|
56
|
+
return { label: node.label, typeSuffix: isInstance ? node.typeLabel! : null };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ------------------------------------------------------------------ H2
|
|
60
|
+
|
|
61
|
+
export interface TransformLockSummary {
|
|
62
|
+
/** True only when position, rotation AND scale are all refused. */
|
|
63
|
+
readonly locked: boolean;
|
|
64
|
+
/** The position channel's verbatim adapter reason (never rewritten here). */
|
|
65
|
+
readonly reason?: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Shared immutable "nothing to say" result — avoids per-row allocation. */
|
|
69
|
+
export const UNLOCKED: TransformLockSummary = { locked: false };
|
|
70
|
+
|
|
71
|
+
/** One channel probe. `undefined` means the adapter declares no editability
|
|
72
|
+
* opinion at all, which every consumer in this editor reads as writable
|
|
73
|
+
* (`editability?.(…)?.writable ?? true`). */
|
|
74
|
+
export type EditabilityProbe = (channel: TransformChannel) => TransformEditability | undefined;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* H2 — collapse the three channels into one row-level verdict. Short-circuits
|
|
78
|
+
* on the first writable channel, so an ordinary movable row pays for ONE
|
|
79
|
+
* `editability` call.
|
|
80
|
+
*
|
|
81
|
+
* The surfaced reason is the POSITION channel's, matching the design record:
|
|
82
|
+
* per-channel detail stays inspector-only, and the row shows one sentence.
|
|
83
|
+
*/
|
|
84
|
+
export function transformLockSummary(probe: EditabilityProbe): TransformLockSummary {
|
|
85
|
+
let positionReason: string | undefined;
|
|
86
|
+
for (const channel of CHANNELS) {
|
|
87
|
+
const verdict = probe(channel);
|
|
88
|
+
if (!verdict || verdict.writable) return UNLOCKED;
|
|
89
|
+
if (channel === 'position') positionReason = verdict.reason;
|
|
90
|
+
}
|
|
91
|
+
return positionReason === undefined ? { locked: true } : { locked: true, reason: positionReason };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** The minimal adapter surface {@link TransformLockCache} needs — structurally
|
|
95
|
+
* satisfied by `AuthoringAdapter` without importing it. */
|
|
96
|
+
export interface EditabilitySource {
|
|
97
|
+
readonly transforms?:
|
|
98
|
+
| {
|
|
99
|
+
readonly editability?:
|
|
100
|
+
| ((id: string, channel: TransformChannel) => TransformEditability)
|
|
101
|
+
| undefined;
|
|
102
|
+
}
|
|
103
|
+
| undefined;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Memoized {@link transformLockSummary} per row id.
|
|
108
|
+
*
|
|
109
|
+
* INVALIDATION KEY: `(source identity, version)`. `version` is supplied by the
|
|
110
|
+
* caller and must be a monotonically increasing counter that advances whenever
|
|
111
|
+
* anything the adapter's `editability` reads could have changed. `GameHierarchy`
|
|
112
|
+
* passes `store.getSnapshot() + adapterVersion` — the shell store's `_version`
|
|
113
|
+
* (bumped by `_notify()`, which EVERY source-write path funnels through via
|
|
114
|
+
* `notifyIngestEdit()`) plus its own adapter-subscription counter. Both are
|
|
115
|
+
* monotone, so their sum is monotone, and a stale entry therefore cannot
|
|
116
|
+
* survive a source edit: the edit bumps `_version` before the re-render that
|
|
117
|
+
* would read the cache.
|
|
118
|
+
*
|
|
119
|
+
* The cache also clears on ADAPTER SWITCH (the `source !== this.source`
|
|
120
|
+
* check), so ids minted by one adapter can never answer for another's.
|
|
121
|
+
*/
|
|
122
|
+
export class TransformLockCache {
|
|
123
|
+
private entries = new Map<string, TransformLockSummary>();
|
|
124
|
+
private source: EditabilitySource | null = null;
|
|
125
|
+
private version = Number.NaN;
|
|
126
|
+
/** Test-visible: how many times the adapter was actually probed. */
|
|
127
|
+
private computed = 0;
|
|
128
|
+
|
|
129
|
+
get computeCount(): number {
|
|
130
|
+
return this.computed;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
summaryFor(source: EditabilitySource, version: number, id: string): TransformLockSummary {
|
|
134
|
+
if (this.source !== source || this.version !== version) {
|
|
135
|
+
this.entries.clear();
|
|
136
|
+
this.source = source;
|
|
137
|
+
this.version = version;
|
|
138
|
+
}
|
|
139
|
+
const cached = this.entries.get(id);
|
|
140
|
+
if (cached) return cached;
|
|
141
|
+
this.computed++;
|
|
142
|
+
const editability = source.transforms?.editability;
|
|
143
|
+
const summary = editability
|
|
144
|
+
? transformLockSummary((channel) => editability(id, channel))
|
|
145
|
+
: UNLOCKED;
|
|
146
|
+
this.entries.set(id, summary);
|
|
147
|
+
return summary;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ------------------------------------------------------------------ H6
|
|
152
|
+
|
|
153
|
+
/** What a row is allowed to do. Every field is a REFUSAL gate, never a
|
|
154
|
+
* capability claim: `true` means "this row model does not stand in the way",
|
|
155
|
+
* and the adapter's own provider/value probes still decide whether the
|
|
156
|
+
* affordance renders at all (a `document` row has no `name` path, so it never
|
|
157
|
+
* renames regardless of what this says). */
|
|
158
|
+
export interface RowAffordances {
|
|
159
|
+
/** Reparent-by-drag. */
|
|
160
|
+
readonly draggable: boolean;
|
|
161
|
+
/** Inline rename (double-click) and the Rename menu item. */
|
|
162
|
+
readonly renamable: boolean;
|
|
163
|
+
/** ANY write: create/duplicate/delete/group, the visibility eye, the lock
|
|
164
|
+
* toggle, the entity-asset save. One flag, because H6's rule is not
|
|
165
|
+
* per-operation — a revealed internal has no writable surface at all. */
|
|
166
|
+
readonly writable: boolean;
|
|
167
|
+
/** Whether the row's label participates in hierarchy search. */
|
|
168
|
+
readonly searchable: boolean;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const ORDINARY_ROW: RowAffordances = {
|
|
172
|
+
draggable: true,
|
|
173
|
+
renamable: true,
|
|
174
|
+
writable: true,
|
|
175
|
+
searchable: true,
|
|
176
|
+
};
|
|
177
|
+
const STRUCTURAL_ROW: RowAffordances = {
|
|
178
|
+
draggable: false,
|
|
179
|
+
renamable: false,
|
|
180
|
+
writable: true,
|
|
181
|
+
searchable: true,
|
|
182
|
+
};
|
|
183
|
+
/**
|
|
184
|
+
* H6 — a revealed internal. Non-writable BY CONSTRUCTION, not by policy: it is
|
|
185
|
+
* a rendered part of a component's output with no authored source identity, so
|
|
186
|
+
* there is nothing for a rename/reparent/delete to write to. Selection stays
|
|
187
|
+
* open (the id resolves, the inspector shows what it honestly can, and H2's
|
|
188
|
+
* lock-with-reason sentence explains the refusal); search is closed, because a
|
|
189
|
+
* `mixamorig:Spine` match across four enemies buries every real row.
|
|
190
|
+
*/
|
|
191
|
+
const INTERNAL_ROW: RowAffordances = {
|
|
192
|
+
draggable: false,
|
|
193
|
+
renamable: false,
|
|
194
|
+
writable: false,
|
|
195
|
+
searchable: false,
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* The ONE gate for "may this row be written to / dragged / found by search".
|
|
200
|
+
*
|
|
201
|
+
* `structural` keeps its pre-H6 meaning exactly (world groups, organization
|
|
202
|
+
* rows, root-group members, and the `STRUCTURAL_ROLES` set): non-draggable,
|
|
203
|
+
* with its write items gated by the adapter probes the panel already runs.
|
|
204
|
+
* `internal` is the new, stronger state and it wins over everything.
|
|
205
|
+
*/
|
|
206
|
+
export function rowAffordances(row: {
|
|
207
|
+
readonly structural: boolean;
|
|
208
|
+
readonly internal: boolean;
|
|
209
|
+
}): RowAffordances {
|
|
210
|
+
if (row.internal) return INTERNAL_ROW;
|
|
211
|
+
return row.structural ? STRUCTURAL_ROW : ORDINARY_ROW;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// ------------------------------------------------------------------ H5
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* The two fields a row badge needs from one diagnostic. Structurally satisfied
|
|
218
|
+
* by `R3fAuthoringDiagnostic` — declared narrowly here so the hierarchy never
|
|
219
|
+
* imports an R3F/ui-source type (the same contract-only rule H2's
|
|
220
|
+
* {@link EditabilitySource} and H3's `InstanceSourceLocator` follow).
|
|
221
|
+
*/
|
|
222
|
+
export interface RowDiagnostic {
|
|
223
|
+
readonly code: string;
|
|
224
|
+
readonly message: string;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export interface RowWarningBadge {
|
|
228
|
+
/** How many diagnostics this row carries — always ≥ 1 when a badge exists. */
|
|
229
|
+
readonly count: number;
|
|
230
|
+
/** Every message, VERBATIM and newline-joined, in the order the adapter
|
|
231
|
+
* returned them. The badge's tooltip is this string and nothing else. */
|
|
232
|
+
readonly tooltip: string;
|
|
233
|
+
/** The codes, for the badge's `data-` attribute (a test can name the exact
|
|
234
|
+
* finding without matching on prose that is allowed to be reworded). */
|
|
235
|
+
readonly codes: readonly string[];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* H5 — collapse a row's diagnostics into its badge, or `null` for the
|
|
240
|
+
* overwhelmingly common "nothing to warn about" row.
|
|
241
|
+
*
|
|
242
|
+
* The verbatim rule is the point: doctrine rule 2 says the analyzer's sentence
|
|
243
|
+
* is the ONE canonical text, so multiple findings are STACKED (newline-joined),
|
|
244
|
+
* never summarized into "3 problems" and never truncated. A row with two
|
|
245
|
+
* warnings shows both sentences.
|
|
246
|
+
*/
|
|
247
|
+
export function rowWarningBadge(
|
|
248
|
+
diagnostics: readonly RowDiagnostic[] | undefined | null,
|
|
249
|
+
): RowWarningBadge | null {
|
|
250
|
+
if (!diagnostics || diagnostics.length === 0) return null;
|
|
251
|
+
return {
|
|
252
|
+
count: diagnostics.length,
|
|
253
|
+
tooltip: diagnostics.map((diagnostic) => diagnostic.message).join('\n'),
|
|
254
|
+
codes: diagnostics.map((diagnostic) => diagnostic.code),
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** The minimal adapter surface {@link RowWarningCache} needs — structurally
|
|
259
|
+
* satisfied by `CompositeAuthoringAdapter`/`R3fSourceAuthoringAdapter` without
|
|
260
|
+
* importing either, and honestly absent on every adapter that runs no source
|
|
261
|
+
* analyzer (which then shows no badges, rather than fabricated ones). */
|
|
262
|
+
export interface RowDiagnosticsSource {
|
|
263
|
+
readonly diagnosticsFor?: ((id: string) => readonly RowDiagnostic[] | undefined) | undefined;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Memoized {@link rowWarningBadge} per row id, with the SAME invalidation
|
|
268
|
+
* contract as {@link TransformLockCache} — `(source identity, version)`, where
|
|
269
|
+
* `GameHierarchy` passes the same `store.getSnapshot() + adapterVersion` key to
|
|
270
|
+
* both.
|
|
271
|
+
*
|
|
272
|
+
* That key is exactly right for H5 and not by coincidence: diagnostics arrive
|
|
273
|
+
* on the OID index, and the R3F adapter's `refreshSourceState()` calls
|
|
274
|
+
* `store.notifyIngestEdit()` the moment a new index lands — which bumps the
|
|
275
|
+
* store `_version` that is half this key. So a fresh index invalidates these
|
|
276
|
+
* badges by construction, on the same tick, through the path every source-write
|
|
277
|
+
* and HMR remount already funnels through.
|
|
278
|
+
*
|
|
279
|
+
* Worth caching even though the adapter's own lookup is two map reads: on a
|
|
280
|
+
* composite it is a `route(id)` ownership walk, and the badge object plus its
|
|
281
|
+
* joined tooltip string would otherwise be reallocated for every row on every
|
|
282
|
+
* render.
|
|
283
|
+
*/
|
|
284
|
+
export class RowWarningCache {
|
|
285
|
+
private entries = new Map<string, RowWarningBadge | null>();
|
|
286
|
+
private source: RowDiagnosticsSource | null = null;
|
|
287
|
+
private version = Number.NaN;
|
|
288
|
+
/** Test-visible: how many times the adapter was actually probed. */
|
|
289
|
+
private computed = 0;
|
|
290
|
+
|
|
291
|
+
get computeCount(): number {
|
|
292
|
+
return this.computed;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
badgeFor(source: RowDiagnosticsSource, version: number, id: string): RowWarningBadge | null {
|
|
296
|
+
if (this.source !== source || this.version !== version) {
|
|
297
|
+
this.entries.clear();
|
|
298
|
+
this.source = source;
|
|
299
|
+
this.version = version;
|
|
300
|
+
}
|
|
301
|
+
const cached = this.entries.get(id);
|
|
302
|
+
if (cached !== undefined) return cached;
|
|
303
|
+
this.computed++;
|
|
304
|
+
const badge = source.diagnosticsFor ? rowWarningBadge(source.diagnosticsFor(id)) : null;
|
|
305
|
+
this.entries.set(id, badge);
|
|
306
|
+
return badge;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hierarchy child-cap constants.
|
|
3
|
+
*
|
|
4
|
+
* The hierarchy panel flattens the ADAPTER's `EditorNode` tree through
|
|
5
|
+
* `hierarchy-node-rows.ts`. This module holds only the two row-cap
|
|
6
|
+
* constants, shared with that flattener so every consumer caps identically.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** Max children shown per parent before a "… N more" row (when capping is on). */
|
|
10
|
+
export const CHILD_CAP = 20;
|
|
11
|
+
export const MORE_ID_PREFIX = '__more__:';
|