@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,849 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design-time layer stack (B1) — the LIFECYCLE of the design-time layers a
|
|
3
|
+
* caller-owned authoring host shows, over mounts the surface PACKAGES
|
|
4
|
+
* register (`design-time-mount-registry.ts`). Runtime still uses a z-ordered
|
|
5
|
+
* composite, but the editor supplies a distinct host per world document; only
|
|
6
|
+
* Game presents the composed result. Layers default `pointer-events:none`;
|
|
7
|
+
* the eye (`world-session-state.ts`'s `hidden`) hides a layer; `interactive`
|
|
8
|
+
* forwards real pointer events for design-time hover/press testing (a mount
|
|
9
|
+
* whose medium IS the document's subject declares `alwaysInteractive` and
|
|
10
|
+
* skips that toggle); `pickLock` is stored only (B4 consumes it in the pick
|
|
11
|
+
* walk). A layer that throws on mount degrades to its A1
|
|
12
|
+
* `BoundaryAuthoringAdapter` error node (#18) via `mount-failure-report.ts` —
|
|
13
|
+
* never a blank editor; every OTHER world (and the focused three world in
|
|
14
|
+
* particular) keeps working regardless.
|
|
15
|
+
*
|
|
16
|
+
* On a successful mount, the world's initial Boundary adapter is REPLACED in
|
|
17
|
+
* the composite by the adapter its mount minted
|
|
18
|
+
* (`CompositeAuthoringAdapter.replaceChild`, B1).
|
|
19
|
+
*
|
|
20
|
+
* `dom` and `canvas` children are candidates for these hosts. The manifest's
|
|
21
|
+
* sole three content root renders through `the world root's stage`'s own
|
|
22
|
+
* `<canvas>` instead, so this module never mounts a competing Three document.
|
|
23
|
+
*
|
|
24
|
+
* WHAT THIS MODULE NO LONGER KNOWS (2026-09-18, WORK.md §The open-source
|
|
25
|
+
* launch item 12): how either medium mounts. It dispatched them in one
|
|
26
|
+
* expression — `candidate.kind === 'canvas' ? mountCanvasLayer : mountReactLayer`
|
|
27
|
+
* — against a `LayerMountResult` contract whose own docblock said the
|
|
28
|
+
* failure/teardown/play lifecycle was "the SAME for both media", and it
|
|
29
|
+
* hard-coded each medium's staleness rule besides (canvas remounted on a
|
|
30
|
+
* storage write, dom re-projected on a story publish). The contract is the
|
|
31
|
+
* seam; `@vgai/dom` and `@vgai/canvas` register against it now, and the play
|
|
32
|
+
* handoff below tears every layer down and restores its Boundary node the
|
|
33
|
+
* instant play starts exactly as it always did — which is why the LIFECYCLE
|
|
34
|
+
* stays here rather than moving with either mount.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
import type { AuthoringAdapter, PickProvider } from '@volter/editor-project/adapter';
|
|
38
|
+
import { stackOrder } from '@volter/editor-project/adapter/root-stacking';
|
|
39
|
+
import { editorConsole } from '../editor-console';
|
|
40
|
+
import type { EditorShellStore } from '../editor-shell-store';
|
|
41
|
+
import { getCurrentProject } from '../project-manager';
|
|
42
|
+
import { subscribeToolContributions } from '../tool-loader';
|
|
43
|
+
import { BoundaryAuthoringAdapter, type BoundaryRootInfo } from './boundary-authoring-adapter';
|
|
44
|
+
import type { CompositeAuthoringAdapter } from './composite-authoring-adapter';
|
|
45
|
+
import {
|
|
46
|
+
type DesignTimeMount,
|
|
47
|
+
type DesignTimeMountContext,
|
|
48
|
+
designTimeMountFor,
|
|
49
|
+
designTimeMounts,
|
|
50
|
+
subscribeDesignTimeMounts,
|
|
51
|
+
} from './design-time-mount-registry';
|
|
52
|
+
import { queueEditModeRebuild } from './edit-mode-authoring';
|
|
53
|
+
import {
|
|
54
|
+
addMountFailureReport,
|
|
55
|
+
clearMountFailureReport,
|
|
56
|
+
formatMountFailureMessage,
|
|
57
|
+
} from './mount-failure-report';
|
|
58
|
+
import {
|
|
59
|
+
getRootCanvasViewport,
|
|
60
|
+
resetRootCanvasViewport,
|
|
61
|
+
setRootCanvasViewport,
|
|
62
|
+
subscribeRootCanvasViewport,
|
|
63
|
+
} from './world-canvas-viewport-state';
|
|
64
|
+
import {
|
|
65
|
+
getRootPan,
|
|
66
|
+
panTransformValue,
|
|
67
|
+
type RootViewController,
|
|
68
|
+
resetRootPan,
|
|
69
|
+
subscribeRootPan,
|
|
70
|
+
} from './world-pan-state';
|
|
71
|
+
import { isRootHidden, isRootInteractive } from './world-session-state';
|
|
72
|
+
|
|
73
|
+
/** D20: Play tears the design-time adapter down, so the selected CSF state
|
|
74
|
+
* must live one level above that adapter to survive Stop's rebuild. Keyed by
|
|
75
|
+
* project + root so equal root ids in different projects never bleed.
|
|
76
|
+
*
|
|
77
|
+
* IT IS STILL HERE, and it is the one lane word this module has left: the
|
|
78
|
+
* board's mount lives in `@vgai/dom` now, but `components/world-documents.tsx`
|
|
79
|
+
* reads the remembered frame for the UI board document's `presentation()`
|
|
80
|
+
* round-trip, and the host may not import a package. Closing it is the
|
|
81
|
+
* world-documents unit's, which is where the rest of that file's `dom`/
|
|
82
|
+
* `canvas` vocabulary lives too. */
|
|
83
|
+
const selectedPortableStoryByRoot = new Map<string, string>();
|
|
84
|
+
|
|
85
|
+
function portableStorySelectionKey(projectRoot: string, rootId: string): string {
|
|
86
|
+
return `${projectRoot}\0${rootId}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** The story a board ROOT last applied (undefined before any selection) —
|
|
90
|
+
* the view-address door reads this so a presented workspace document can
|
|
91
|
+
* say which frame it is on (`EditorViewDocument`'s workspace `story`). */
|
|
92
|
+
export function rememberedPortableStory(projectRoot: string, rootId: string): string | undefined {
|
|
93
|
+
return selectedPortableStoryByRoot.get(portableStorySelectionKey(projectRoot, rootId));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** The write half, for the registered mount that owns the board: it applies
|
|
97
|
+
* the story, so it is what knows which frame the root is on. */
|
|
98
|
+
export function rememberPortableStory(projectRoot: string, rootId: string, storyId: string): void {
|
|
99
|
+
selectedPortableStoryByRoot.set(portableStorySelectionKey(projectRoot, rootId), storyId);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Bottom-to-top layer z-index base — strictly below the selection overlay's
|
|
103
|
+
* z50 and `ToolStrip`+`ViewportOverlay`'s z1000, so canvas-local editing
|
|
104
|
+
* chrome is never occluded by a design-time layer. */
|
|
105
|
+
const BASE_Z_INDEX = 1;
|
|
106
|
+
|
|
107
|
+
/** One candidate world for a design-time layer — read entirely off its
|
|
108
|
+
* existing `BoundaryAuthoringAdapter` (kind/path/zOrder/pausable are already
|
|
109
|
+
* exposed there, independent of whether the composite has a writable manifest
|
|
110
|
+
* manifest surface — see that adapter's own inspector). */
|
|
111
|
+
export interface DesignTimeRootDescriptor {
|
|
112
|
+
readonly worldId: string;
|
|
113
|
+
readonly kind: 'dom' | 'canvas';
|
|
114
|
+
readonly path: string | undefined;
|
|
115
|
+
readonly zOrder: number;
|
|
116
|
+
readonly pausable: boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Mount the declared `path` entry component ALONE, skipping the project
|
|
119
|
+
* story board a dom layer otherwise becomes whenever the project has dom
|
|
120
|
+
* stories. The pasteboard document's contract (queue item 4): the FILE is
|
|
121
|
+
* the canvas and its default export the one subject — a gallery of every
|
|
122
|
+
* project story on that surface would be a different document.
|
|
123
|
+
*/
|
|
124
|
+
readonly entryOnly?: boolean;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function readCandidates(composite: CompositeAuthoringAdapter): DesignTimeRootDescriptor[] {
|
|
128
|
+
const out: DesignTimeRootDescriptor[] = [];
|
|
129
|
+
for (const { worldId, adapter } of composite.childAdapters()) {
|
|
130
|
+
if (!(adapter instanceof BoundaryAuthoringAdapter)) continue; // the focused (live) world
|
|
131
|
+
const kind = adapter.inspector.get(worldId, 'kind') as string;
|
|
132
|
+
if (kind !== 'dom' && kind !== 'canvas') continue;
|
|
133
|
+
const reason = adapter.inspector.get(worldId, 'reason');
|
|
134
|
+
if (reason !== undefined) continue; // already an error node — nothing new to attempt
|
|
135
|
+
// An `{ ingest }` root belongs to the ingest routes (`ingest/mount-ingest-root.ts`'s
|
|
136
|
+
// `tryManifestIngestRoute*`), which run the game's OWN code and capture
|
|
137
|
+
// what it renders. A design-time layer mounts a first-party document
|
|
138
|
+
// instead, so pointing it at an ingested game is a category error. A
|
|
139
|
+
// `{ module }` canvas root is the same case: its truth is the game's own
|
|
140
|
+
// imperative source, which this lane does not mount.
|
|
141
|
+
const declaredAdapter = adapter.inspector.get(worldId, 'adapter') as string | undefined;
|
|
142
|
+
if (declaredAdapter?.startsWith('ingest') || declaredAdapter?.startsWith('module')) continue;
|
|
143
|
+
out.push({
|
|
144
|
+
worldId,
|
|
145
|
+
kind,
|
|
146
|
+
path: adapter.inspector.get(worldId, 'path') as string | undefined,
|
|
147
|
+
zOrder: Number(adapter.inspector.get(worldId, 'zOrder') ?? 0),
|
|
148
|
+
pausable: adapter.inspector.get(worldId, 'pausable') !== false,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
return out;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Snapshot the non-Three roots that can own an edit-time document. Capture
|
|
155
|
+
* this before any root mounts: a successful React mount upgrades its
|
|
156
|
+
* Boundary adapter in-place, while the document still needs the manifest
|
|
157
|
+
* path and stacking metadata that Boundary disclosed. */
|
|
158
|
+
export function designTimeRootDescriptors(
|
|
159
|
+
composite: CompositeAuthoringAdapter,
|
|
160
|
+
): readonly DesignTimeRootDescriptor[] {
|
|
161
|
+
return readCandidates(composite);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* The id the project's UI board mounts under when the project has NO dom root
|
|
166
|
+
* to own it — a project whose UI components live inside an ingested game, say,
|
|
167
|
+
* whose stories are ordinary discovered CSF but whose manifest declares no
|
|
168
|
+
* `dom` root at all.
|
|
169
|
+
*
|
|
170
|
+
* Board presence keys on STORIES, not roots (owner ruling, 2026-08-15), so
|
|
171
|
+
* this case is not exotic: it is simply the board without a root underneath
|
|
172
|
+
* it. The layer mount needs SOME id — it keys pan state, the remembered story
|
|
173
|
+
* selection and the story overlay — and this is that id.
|
|
174
|
+
*
|
|
175
|
+
* No colon, deliberately. `ReactRootAuthoringAdapter` spells `worldId` into a
|
|
176
|
+
* history `displayName` that `history/resource-registry.ts` validates as a
|
|
177
|
+
* project-relative PATH, and a leading `foo:` reads as a URI scheme and throws
|
|
178
|
+
* out of the constructor (measured on the ingest dom surface, whose
|
|
179
|
+
* `<world>:dom-ui` ids hit exactly that).
|
|
180
|
+
*/
|
|
181
|
+
export const PROJECT_STORY_BOARD_ROOT_ID = 'ui-components-board';
|
|
182
|
+
|
|
183
|
+
/** Whether a descriptor names an existing child of the composite — the
|
|
184
|
+
* question `replaceChild` answers with a loud warn, asked BEFORE calling it so
|
|
185
|
+
* a rootless board (which by construction has no child) never trips it. */
|
|
186
|
+
function isCompositeChild(composite: CompositeAuthoringAdapter, worldId: string): boolean {
|
|
187
|
+
return composite.childAdapters().some((child) => child.worldId === worldId);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** The rootless UI board's descriptor — no `path`, because there is no root
|
|
191
|
+
* entry to derive a default story from; the board opens on its first story
|
|
192
|
+
* the same way it does for a root whose entry names no story. */
|
|
193
|
+
export function projectStoryBoardDescriptor(): DesignTimeRootDescriptor {
|
|
194
|
+
return {
|
|
195
|
+
worldId: PROJECT_STORY_BOARD_ROOT_ID,
|
|
196
|
+
kind: 'dom',
|
|
197
|
+
path: undefined,
|
|
198
|
+
zOrder: 0,
|
|
199
|
+
pausable: true,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Re-applies session-local layer CSS (eye + interactive) — cheap, called on
|
|
204
|
+
* every store notification, never triggers a remount. */
|
|
205
|
+
function applySessionStyle(
|
|
206
|
+
layer: HTMLElement,
|
|
207
|
+
worldId: string,
|
|
208
|
+
kind: DesignTimeRootDescriptor['kind'] = 'dom',
|
|
209
|
+
): void {
|
|
210
|
+
const display = isRootHidden(worldId) ? 'none' : 'block';
|
|
211
|
+
layer.style.display = display;
|
|
212
|
+
// A mount whose content IS the document's subject declares itself always
|
|
213
|
+
// interactive (a click on it is how you select in it). The `interactive`
|
|
214
|
+
// toggle exists for the other case, where design-time hover/press testing
|
|
215
|
+
// of real UI is opt-in because it competes with authoring gestures. Which
|
|
216
|
+
// medium is which is the mount's statement, not this module's.
|
|
217
|
+
layer.style.pointerEvents =
|
|
218
|
+
designTimeMountFor(kind)?.alwaysInteractive || isRootInteractive(worldId) ? 'auto' : 'none';
|
|
219
|
+
// React story labels live in editor chrome above the full-cover selection
|
|
220
|
+
// overlay so they remain clickable. Mirror the owning world's eye state
|
|
221
|
+
// onto that synchronized sibling.
|
|
222
|
+
for (const child of Array.from(layer.parentElement?.children ?? [])) {
|
|
223
|
+
if (child instanceof HTMLElement && child.dataset['vgaiStoryBoardChromeFor'] === worldId) {
|
|
224
|
+
child.style.display = display;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function createLayerElement(
|
|
230
|
+
container: HTMLElement,
|
|
231
|
+
candidate: DesignTimeRootDescriptor,
|
|
232
|
+
zIndex: number,
|
|
233
|
+
canvasScene: boolean,
|
|
234
|
+
): HTMLElement {
|
|
235
|
+
const { worldId } = candidate;
|
|
236
|
+
const layer = document.createElement('div');
|
|
237
|
+
layer.dataset['worldId'] = worldId;
|
|
238
|
+
layer.dataset['vgaiRootSurface'] = 'true';
|
|
239
|
+
if (canvasScene) layer.dataset['vgaiCanvasScene'] = 'true';
|
|
240
|
+
layer.style.position = 'absolute';
|
|
241
|
+
layer.style.top = '0';
|
|
242
|
+
layer.style.left = '0';
|
|
243
|
+
layer.style.width = '100%';
|
|
244
|
+
layer.style.height = '100%';
|
|
245
|
+
layer.style.zIndex = String(zIndex);
|
|
246
|
+
// Same containment as the runtime's per-world surfaces (create-runtime.ts,
|
|
247
|
+
// world-surface cssText): make this layer the containing block for
|
|
248
|
+
// `position:fixed` descendants and clip to the world's rectangle, so a
|
|
249
|
+
// game's full-screen UI (`fixed; inset:0` — the natural idiom) renders
|
|
250
|
+
// inside the viewport instead of floating over the editor chrome. Also
|
|
251
|
+
// makes behavior pan-invariant: without it, space-pan's transform (below)
|
|
252
|
+
// suddenly captured `fixed` children that were page-anchored un-panned.
|
|
253
|
+
layer.style.contain = 'layout paint';
|
|
254
|
+
applySessionStyle(layer, worldId, candidate.kind);
|
|
255
|
+
// D4 (spec27 §8 "space-pan" row) — seed this layer with whatever pan is
|
|
256
|
+
// currently in effect (normally none — `mountDesignTimeLayers` resets pan
|
|
257
|
+
// on every fresh install, see its own doc comment — but re-applying here
|
|
258
|
+
// too keeps this function correct standalone). See `world-pan-state.ts`'s
|
|
259
|
+
// doc comment for the full lockstep-translate soundness argument: THIS
|
|
260
|
+
// element is exactly `this.root`/`hostRect()` in
|
|
261
|
+
// `react-world-authoring-adapter.ts`, i.e. the host `RectProvider.rect(id)`
|
|
262
|
+
// subtracts — panning it is what keeps `rect(id)` pan-invariant.
|
|
263
|
+
applyPanTransform(layer);
|
|
264
|
+
container.appendChild(layer);
|
|
265
|
+
return layer;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** Re-applies the current shared world-pan transform to one layer element —
|
|
269
|
+
* called at creation and by `mountDesignTimeLayers`' pan subscription on
|
|
270
|
+
* every subsequent pan change (see `world-pan-state.ts`). */
|
|
271
|
+
function applyPanTransform(layer: HTMLElement): void {
|
|
272
|
+
// A native Canvas Scene renders through its own editor-camera matrix inside
|
|
273
|
+
// a viewport-sized Pixi surface. CSS-transforming that surface would turn
|
|
274
|
+
// it back into the fixed artboard the Scene document is replacing.
|
|
275
|
+
if (layer.dataset['vgaiCanvasScene'] === 'true') {
|
|
276
|
+
layer.style.transform = '';
|
|
277
|
+
layer.style.width = '100%';
|
|
278
|
+
layer.style.height = '100%';
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
layer.style.transform = panTransformValue(getRootPan()) ?? '';
|
|
282
|
+
layer.style.transformOrigin = '0 0';
|
|
283
|
+
// A React story board owns a canvas larger than the visible document and
|
|
284
|
+
// sizes the layer to its complete grid. Responsive viewport changes resize
|
|
285
|
+
// each frame through `react-story-board.ts`; do not collapse that board back
|
|
286
|
+
// to the single-runtime-surface dimensions used by React/Pixi roots.
|
|
287
|
+
if (layer.dataset['vgaiReactStoryBoard'] === 'true') return;
|
|
288
|
+
const viewport = getRootCanvasViewport();
|
|
289
|
+
layer.style.width = viewport.width === null ? '100%' : `${viewport.width}px`;
|
|
290
|
+
layer.style.height = viewport.height === null ? '100%' : `${viewport.height}px`;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* THE CONTRACT every design-time mount answers, whatever its medium — the
|
|
295
|
+
* one this module's own docblock already called "the SAME for both media",
|
|
296
|
+
* exported since the mounts moved into their surface packages
|
|
297
|
+
* (`design-time-mount-registry.ts`).
|
|
298
|
+
*/
|
|
299
|
+
export interface LayerMountResult {
|
|
300
|
+
readonly adapter?: AuthoringAdapter;
|
|
301
|
+
/**
|
|
302
|
+
* D12 (B4) — a stage hit-test over opaque mounted content, in client pixels.
|
|
303
|
+
* Source-backed React/Pixi mounts carry picking on their full adapter;
|
|
304
|
+
* foreign Pixi mounts can return this narrower capability instead.
|
|
305
|
+
*/
|
|
306
|
+
readonly pick?: PickProvider['pick'];
|
|
307
|
+
dispose(): void;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Mount design-time React worlds declared by `composite` into a caller's
|
|
312
|
+
* authoring `container`. `descriptors` narrows the mount to one world for the
|
|
313
|
+
* per-world document model; omission preserves the original multi-layer
|
|
314
|
+
* primitive for bounded callers and integration tests. Returns a disposer
|
|
315
|
+
* that must run before the owning composite is released.
|
|
316
|
+
*
|
|
317
|
+
* A no-op (returns a no-op disposer) when there are no layer candidates or no
|
|
318
|
+
* resolvable current project.
|
|
319
|
+
*
|
|
320
|
+
* Play-mode handoff: the editor's Scene and Game tabs are BOTH always
|
|
321
|
+
* mounted (only one is `display`-visible at a time — the Game tab hosts
|
|
322
|
+
* `play-mode.ts`'s OWN, entirely separate composite/mount over a REAL,
|
|
323
|
+
* ticking `Game`). The instant play starts, this module tears its
|
|
324
|
+
* design-time layers down for the rest of THIS edit session: two
|
|
325
|
+
* independent DOM trees for the SAME react world (this inert stand-in,
|
|
326
|
+
* play-mode's live one) would otherwise carry the SAME `data-testid`s
|
|
327
|
+
* (whatever the entry's own JSX declares, e.g. tri-world's `hud-count`)
|
|
328
|
+
* simultaneously in one document — not just visually confusing, but a
|
|
329
|
+
* genuine test/automation hazard (two elements answering to one testid).
|
|
330
|
+
* Stop symmetrically rebuilds edit-mode authoring and restores the selected
|
|
331
|
+
* portable CSF preview. Play and edit roots never coexist, but neither does
|
|
332
|
+
* Play permanently destroy the authoring surface.
|
|
333
|
+
*/
|
|
334
|
+
export function mountDesignTimeLayers(
|
|
335
|
+
container: HTMLElement,
|
|
336
|
+
composite: CompositeAuthoringAdapter,
|
|
337
|
+
store: EditorShellStore,
|
|
338
|
+
descriptors?: readonly DesignTimeRootDescriptor[],
|
|
339
|
+
/**
|
|
340
|
+
* Reports the adapter a descriptor's layer minted, or `null` when its layer
|
|
341
|
+
* goes away. Only a descriptor that names an EXISTING composite child is
|
|
342
|
+
* published INTO the composite (`replaceChild` is an in-place swap; it
|
|
343
|
+
* cannot grow the array, by design) — so a rootless UI board or the Dev
|
|
344
|
+
* component board has no child to upgrade, and this is how its document
|
|
345
|
+
* reaches its adapter for Hierarchy/Inspector routing.
|
|
346
|
+
*/
|
|
347
|
+
onAdapter?: (worldId: string, adapter: AuthoringAdapter | null) => void,
|
|
348
|
+
presentation?: {
|
|
349
|
+
/** Native Canvas Scene: independent editor camera and viewport renderer,
|
|
350
|
+
* not the DOM/story-board artboard presentation. */
|
|
351
|
+
readonly canvasSceneView: RootViewController;
|
|
352
|
+
},
|
|
353
|
+
/** When set, first-mount work writes named segments onto this document's
|
|
354
|
+
* activation clock (`viewport-activation-timings`). */
|
|
355
|
+
activationDocumentId?: string,
|
|
356
|
+
): () => void {
|
|
357
|
+
// D4 (spec27 §8 "space-pan" row) — a fresh layer stack starts un-panned:
|
|
358
|
+
// every call here is a "world switch" (initial edit-mode install, or an
|
|
359
|
+
// acknowledged edit-mode re-install — see `world-root-stage.ts`'s
|
|
360
|
+
// `installAll`), so a stale pan offset from a PREVIOUS layer stack must
|
|
361
|
+
// never carry over onto a different one.
|
|
362
|
+
if (presentation) presentation.canvasSceneView.reset();
|
|
363
|
+
else resetRootPan();
|
|
364
|
+
resetRootCanvasViewport();
|
|
365
|
+
// A declared project resolution seeds DOM component preview frames from the
|
|
366
|
+
// same logical screen Play/standalone use. It deliberately does NOT size a
|
|
367
|
+
// native Canvas Scene: that document is an unbounded world view and receives
|
|
368
|
+
// the separate presentation branch above. A responsive preset may still
|
|
369
|
+
// override DOM previews live through ReactCanvasControls.
|
|
370
|
+
const activeProject = getCurrentProject();
|
|
371
|
+
if (!presentation && activeProject?.config.resolution) {
|
|
372
|
+
setRootCanvasViewport(
|
|
373
|
+
activeProject.config.resolution.width,
|
|
374
|
+
activeProject.config.resolution.height,
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
// ONE-WAY PLAY HANDOFF, ENTRY HALF. The exit half — the `store.subscribe`
|
|
378
|
+
// listener at the bottom of this function, which flips `playTeardownDone`
|
|
379
|
+
// and calls `suspendForPlay()` when play STARTS — covers "layers were
|
|
380
|
+
// already mounted, then the user hit Play". But it is a TRANSITION
|
|
381
|
+
// listener, so it does nothing at all when play is ALREADY running by the
|
|
382
|
+
// time this function is first called.
|
|
383
|
+
//
|
|
384
|
+
// That ordering is reachable. `the world root's stage`'s `installAll()` (the only
|
|
385
|
+
// caller) runs at the tail of an async chain that fetches
|
|
386
|
+
// `vgai.project.json` on the way here, so a Play issued the moment the
|
|
387
|
+
// editor shell is interactive wins the race on a slow or contended host and
|
|
388
|
+
// `store.playState` is already `'playing'` on arrival. Without this guard we
|
|
389
|
+
// mount a design-time react layer anyway — rendering the project's REAL
|
|
390
|
+
// entry component against `createDesignTimeGame()`'s INERT `Game`, whose
|
|
391
|
+
// `roots` array is `[]` forever and whose loop never ticks (see that
|
|
392
|
+
// function's doc comment). A HUD listing worlds therefore renders an empty
|
|
393
|
+
// list from a Game that never registers one — and, because no further
|
|
394
|
+
// playState TRANSITION ever arrives, `suspendForPlay()` never fires and the
|
|
395
|
+
// layer is never torn down. It also carries the duplicate-`data-testid`
|
|
396
|
+
// hazard this module's own doc comment calls out for the transition case.
|
|
397
|
+
//
|
|
398
|
+
// Play mode owns the react world outright while it runs (it mounts its own
|
|
399
|
+
// live tree over a REAL, ticking Game). So the correct behavior when play
|
|
400
|
+
// is already up is the same one `suspendForPlay()` produces: mount NOTHING.
|
|
401
|
+
// Stop requests a clean edit-mode rebuild below; this entry guard therefore
|
|
402
|
+
// needs to listen for Stop even though it mounted no layers itself.
|
|
403
|
+
if (store.playState !== 'stopped') {
|
|
404
|
+
let disposed = false;
|
|
405
|
+
let rebuildRequested = false;
|
|
406
|
+
const unsubscribe = store.subscribe(() => {
|
|
407
|
+
if (disposed || rebuildRequested || store.playState !== 'stopped') return;
|
|
408
|
+
rebuildRequested = true;
|
|
409
|
+
if (!disposed) queueEditModeRebuild();
|
|
410
|
+
});
|
|
411
|
+
return () => {
|
|
412
|
+
disposed = true;
|
|
413
|
+
unsubscribe();
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
const projectRoot = activeProject?.rootPath;
|
|
417
|
+
const candidates = descriptors ? [...descriptors] : readCandidates(composite);
|
|
418
|
+
// C3 — the scene-UI child (at most one, the Three world's): already a
|
|
419
|
+
// LIVE `UIAuthoringAdapter` at composite-install time (`edit-mode-
|
|
420
|
+
// authoring.ts` — no Boundary-to-live upgrade dance needed here, unlike
|
|
421
|
+
// react/pixi), so it's a mount candidate in its own right rather than one
|
|
422
|
+
// of `readCandidates`'s Boundary-only entries.
|
|
423
|
+
if (candidates.length === 0 || !projectRoot) {
|
|
424
|
+
return () => {};
|
|
425
|
+
}
|
|
426
|
+
// Narrowed once: `mountCandidate` below is a function declaration, where
|
|
427
|
+
// the guard's control-flow narrowing does not reach.
|
|
428
|
+
const projectRootPath: string = projectRoot;
|
|
429
|
+
|
|
430
|
+
// Bottom-to-top paint order — mirrors `create-runtime.ts`'s own stacking
|
|
431
|
+
// pass, over exactly the roots this module lays out (react/pixi
|
|
432
|
+
// candidates only; the Three world keeps its untouched canvas
|
|
433
|
+
// slot below all of these — see the module doc comment).
|
|
434
|
+
const sorted = stackOrder(candidates.map((c) => ({ id: c.worldId, zOrder: c.zOrder })));
|
|
435
|
+
const orderedCandidates = sorted.map((s) => candidates.find((c) => c.worldId === s.id)!);
|
|
436
|
+
|
|
437
|
+
const candidateByRoot = new Map(orderedCandidates.map((c) => [c.worldId, c]));
|
|
438
|
+
const layers = new Map<string, HTMLElement>();
|
|
439
|
+
const disposersByWorld = new Map<string, () => void>();
|
|
440
|
+
/** Per-world mount generation — a remount supersedes any in-flight mount. */
|
|
441
|
+
const mountEpochs = new Map<string, number>();
|
|
442
|
+
// Worlds whose Boundary child we upgraded to a LIVE design-time adapter
|
|
443
|
+
// (successful react mounts). Tracked so the one-way play handoff can put an
|
|
444
|
+
// HONEST disclosure node back in the composite instead of leaving a live
|
|
445
|
+
// adapter over torn-down DOM (which renders silently empty — a #18 violation).
|
|
446
|
+
const upgraded = new Set<string>();
|
|
447
|
+
/** Worlds whose medium has no registered mount YET — see `mountCandidate`. */
|
|
448
|
+
const awaitingMount = new Set<string>();
|
|
449
|
+
/** Worlds already told, in their Boundary node, that no package registered
|
|
450
|
+
* a mount for their medium. Said once per stack, never twice. */
|
|
451
|
+
const refusedMount = new Set<string>();
|
|
452
|
+
let torndown = false; // the whole-module disposer (the world root's stage unmount) ran
|
|
453
|
+
let playTeardownDone = false; // the one-way play-mode handoff (see doc comment) ran
|
|
454
|
+
let rebuildRequested = false;
|
|
455
|
+
|
|
456
|
+
function disposeEverything(): void {
|
|
457
|
+
for (const dispose of disposersByWorld.values()) {
|
|
458
|
+
try {
|
|
459
|
+
dispose();
|
|
460
|
+
} catch (err) {
|
|
461
|
+
editorConsole.error(`[design-time-layers] dispose failed: ${err}`, 'authoring');
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
disposersByWorld.clear();
|
|
465
|
+
for (const layer of layers.values()) layer.remove();
|
|
466
|
+
layers.clear();
|
|
467
|
+
// A reported adapter now points at torn-down DOM. Retract it in the same
|
|
468
|
+
// gesture that freed it — the composite half of this (`suspendForPlay`'s
|
|
469
|
+
// Boundary swap) exists for exactly the same reason.
|
|
470
|
+
for (const candidate of orderedCandidates) onAdapter?.(candidate.worldId, null);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Play handoff: dispose the design-time layers AND revert every
|
|
475
|
+
* upgraded world back to a `BoundaryAuthoringAdapter` disclosure node
|
|
476
|
+
* (#18 — never silently empty). Not called on the whole-module disposer
|
|
477
|
+
* (`torndown`, the world root's stage unmount), where the composite is going away
|
|
478
|
+
* anyway. Stop dispatches one edit-mode rebuild after the live runtime has
|
|
479
|
+
* torn down, restoring the CSF-backed design surface. The scene-UI layer's DOM is
|
|
480
|
+
* torn down the same way (play mode renders scene-UI through the real
|
|
481
|
+
* engine's HUD mount instead — two live DOM trees for the same testids
|
|
482
|
+
* would be the same hazard `design-time-layers.ts`'s own doc comment
|
|
483
|
+
* already calls out for react roots); its adapter is left alone (still
|
|
484
|
+
* live, just without a mounted layer) since there is no Boundary form of it.
|
|
485
|
+
*/
|
|
486
|
+
function suspendForPlay(): void {
|
|
487
|
+
disposeEverything();
|
|
488
|
+
for (const worldId of upgraded) {
|
|
489
|
+
const c = candidateByRoot.get(worldId);
|
|
490
|
+
if (!c) continue;
|
|
491
|
+
const info: BoundaryRootInfo = {
|
|
492
|
+
id: c.worldId,
|
|
493
|
+
kind: c.kind,
|
|
494
|
+
entryOrScenePath: c.path,
|
|
495
|
+
zOrder: c.zOrder,
|
|
496
|
+
pausable: c.pausable,
|
|
497
|
+
};
|
|
498
|
+
composite.replaceChild(
|
|
499
|
+
worldId,
|
|
500
|
+
new BoundaryAuthoringAdapter(
|
|
501
|
+
store,
|
|
502
|
+
info,
|
|
503
|
+
'Design-time layer suspended by play mode — Stop restores it.',
|
|
504
|
+
),
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
upgraded.clear();
|
|
508
|
+
store.notifyIngestEdit();
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
function mountCandidate(
|
|
512
|
+
candidate: DesignTimeRootDescriptor,
|
|
513
|
+
i: number,
|
|
514
|
+
/** Runs once this mount has settled (mounted or failed) — the hook a
|
|
515
|
+
* re-projection uses to take the PREVIOUS layer down only then. */
|
|
516
|
+
onSettled?: () => void,
|
|
517
|
+
): void {
|
|
518
|
+
const registered = designTimeMountFor(candidate.kind);
|
|
519
|
+
// NO REGISTERED MOUNT IS NOT A FAILURE, and specifically not YET a
|
|
520
|
+
// failure: contributions load asynchronously (the inventory pass waits
|
|
521
|
+
// for the first viewport frame), so a layer stack installed at project
|
|
522
|
+
// open routinely runs before the package that owns this medium has
|
|
523
|
+
// registered. Wait, silently, with no layer and no console line — the
|
|
524
|
+
// world's own Boundary node is already standing in the composite, which
|
|
525
|
+
// is the disclosure. `awaitingMount` is what the registration
|
|
526
|
+
// subscription below mounts once the package arrives, and what the
|
|
527
|
+
// contribution pass turns into a NAMED refusal if it never does.
|
|
528
|
+
if (!registered) {
|
|
529
|
+
awaitingMount.add(candidate.worldId);
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
awaitingMount.delete(candidate.worldId);
|
|
533
|
+
const epoch = (mountEpochs.get(candidate.worldId) ?? 0) + 1;
|
|
534
|
+
mountEpochs.set(candidate.worldId, epoch);
|
|
535
|
+
const layer = createLayerElement(container, candidate, BASE_Z_INDEX + i, !!presentation);
|
|
536
|
+
layers.set(candidate.worldId, layer);
|
|
537
|
+
|
|
538
|
+
const context: DesignTimeMountContext = {
|
|
539
|
+
projectRootPath,
|
|
540
|
+
store,
|
|
541
|
+
...(presentation ? { view: presentation.canvasSceneView } : {}),
|
|
542
|
+
...(activationDocumentId ? { activationDocumentId } : {}),
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
// Wrapped so a mount that throws SYNCHRONOUSLY (an implementation that
|
|
546
|
+
// is not itself `async`) still lands in the boundary path below rather
|
|
547
|
+
// than escaping this call.
|
|
548
|
+
const mountPromise: Promise<LayerMountResult> = (async () =>
|
|
549
|
+
registered.mount(candidate, layer, context))();
|
|
550
|
+
|
|
551
|
+
mountPromise
|
|
552
|
+
.then((result) => {
|
|
553
|
+
if (torndown || playTeardownDone || mountEpochs.get(candidate.worldId) !== epoch) {
|
|
554
|
+
result.dispose();
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
if (result.adapter) {
|
|
558
|
+
// A descriptor with no composite child of its own (rootless UI or
|
|
559
|
+
// the Dev component board) is reported below and nowhere else:
|
|
560
|
+
// `replaceChild` would only warn and ignore, which is the right
|
|
561
|
+
// refusal for a real mis-routing and pure noise for a board that
|
|
562
|
+
// never had a child. For a real child, replace FIRST: publishing the
|
|
563
|
+
// mounted adapter into React before the composite owns its ids gives
|
|
564
|
+
// one render where selection belongs to neither surface. Besides a
|
|
565
|
+
// false unowned-id refusal, logging that refusal during render makes
|
|
566
|
+
// the console tray update while RootSelectionOverlay is rendering.
|
|
567
|
+
if (isCompositeChild(composite, candidate.worldId)) {
|
|
568
|
+
composite.replaceChild(candidate.worldId, result.adapter);
|
|
569
|
+
upgraded.add(candidate.worldId);
|
|
570
|
+
}
|
|
571
|
+
onAdapter?.(candidate.worldId, result.adapter);
|
|
572
|
+
} else if (result.pick) {
|
|
573
|
+
// Opaque/foreign Pixi roots can expose a stage pick without a
|
|
574
|
+
// source-authoring adapter. Re-wrap their Boundary with the pick and
|
|
575
|
+
// track it in `upgraded`: `suspendForPlay` must remove a pick that
|
|
576
|
+
// closes over a disposed Pixi stage.
|
|
577
|
+
const info: BoundaryRootInfo = {
|
|
578
|
+
id: candidate.worldId,
|
|
579
|
+
kind: candidate.kind,
|
|
580
|
+
entryOrScenePath: candidate.path,
|
|
581
|
+
zOrder: candidate.zOrder,
|
|
582
|
+
pausable: candidate.pausable,
|
|
583
|
+
};
|
|
584
|
+
composite.replaceChild(
|
|
585
|
+
candidate.worldId,
|
|
586
|
+
new BoundaryAuthoringAdapter(store, info, undefined, result.pick),
|
|
587
|
+
);
|
|
588
|
+
upgraded.add(candidate.worldId);
|
|
589
|
+
}
|
|
590
|
+
disposersByWorld.set(candidate.worldId, result.dispose);
|
|
591
|
+
// PD-1: this root is mounted — retract any failure recorded for it by
|
|
592
|
+
// an earlier attempt (per-world, never the whole list: a sibling root
|
|
593
|
+
// that is still down keeps its own report).
|
|
594
|
+
clearMountFailureReport(candidate.worldId);
|
|
595
|
+
store.notifyIngestEdit();
|
|
596
|
+
onSettled?.();
|
|
597
|
+
})
|
|
598
|
+
.catch((err: unknown) => {
|
|
599
|
+
if (mountEpochs.get(candidate.worldId) !== epoch) return;
|
|
600
|
+
onSettled?.();
|
|
601
|
+
layer.remove();
|
|
602
|
+
if (layers.get(candidate.worldId) === layer) layers.delete(candidate.worldId);
|
|
603
|
+
if (torndown || playTeardownDone) return;
|
|
604
|
+
const message = formatMountFailureMessage(err);
|
|
605
|
+
editorConsole.error(
|
|
606
|
+
`[design-time-layers] world "${candidate.worldId}" (${candidate.kind}) failed to ` +
|
|
607
|
+
`mount: ${message}`,
|
|
608
|
+
'authoring',
|
|
609
|
+
);
|
|
610
|
+
const info: BoundaryRootInfo = {
|
|
611
|
+
id: candidate.worldId,
|
|
612
|
+
kind: candidate.kind,
|
|
613
|
+
entryOrScenePath: candidate.path,
|
|
614
|
+
zOrder: candidate.zOrder,
|
|
615
|
+
pausable: candidate.pausable,
|
|
616
|
+
};
|
|
617
|
+
onAdapter?.(candidate.worldId, null);
|
|
618
|
+
if (isCompositeChild(composite, candidate.worldId)) {
|
|
619
|
+
composite.replaceChild(
|
|
620
|
+
candidate.worldId,
|
|
621
|
+
new BoundaryAuthoringAdapter(store, info, message),
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
addMountFailureReport({
|
|
625
|
+
worldId: candidate.worldId,
|
|
626
|
+
kind: candidate.kind,
|
|
627
|
+
identity: registered.identity,
|
|
628
|
+
message,
|
|
629
|
+
});
|
|
630
|
+
store.notifyIngestEdit();
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
orderedCandidates.forEach((candidate, i) => {
|
|
634
|
+
mountCandidate(candidate, i);
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Dispose one world's mount and mount it again from CURRENT source —
|
|
639
|
+
* the canvas lane's absorb-by-remount unit (storage watch below).
|
|
640
|
+
*/
|
|
641
|
+
/**
|
|
642
|
+
* A remount that keeps the OLD layer on screen until the new one has
|
|
643
|
+
* settled. `remountCandidate` tears the layer down first, so every
|
|
644
|
+
* re-projection was a visible flash — "it flickers like a reload, then the
|
|
645
|
+
* change is applied" (runhuman pass 144). The new layer is created on top;
|
|
646
|
+
* when its mount settles the previous one is disposed and removed.
|
|
647
|
+
*/
|
|
648
|
+
function reprojectCandidate(candidate: DesignTimeRootDescriptor, i: number): void {
|
|
649
|
+
const prevDispose = disposersByWorld.get(candidate.worldId);
|
|
650
|
+
disposersByWorld.delete(candidate.worldId);
|
|
651
|
+
const prevLayer = layers.get(candidate.worldId);
|
|
652
|
+
layers.delete(candidate.worldId);
|
|
653
|
+
mountCandidate(candidate, i, () => {
|
|
654
|
+
// The new layer mounted hidden — its frames fill in over a second and
|
|
655
|
+
// an empty board on top of the old one IS the flash (runhuman pass
|
|
656
|
+
// 146 still saw it with the old layer kept). Show it only now.
|
|
657
|
+
const next = layers.get(candidate.worldId);
|
|
658
|
+
if (next) next.style.visibility = '';
|
|
659
|
+
if (prevDispose) {
|
|
660
|
+
try {
|
|
661
|
+
prevDispose();
|
|
662
|
+
} catch (err) {
|
|
663
|
+
editorConsole.error(
|
|
664
|
+
`[design-time-layers] re-projection dispose failed: ${err}`,
|
|
665
|
+
'authoring',
|
|
666
|
+
);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
prevLayer?.remove();
|
|
670
|
+
});
|
|
671
|
+
const next = layers.get(candidate.worldId);
|
|
672
|
+
if (next && next !== prevLayer) next.style.visibility = 'hidden';
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
function remountCandidate(candidate: DesignTimeRootDescriptor, i: number): void {
|
|
676
|
+
const prev = disposersByWorld.get(candidate.worldId);
|
|
677
|
+
disposersByWorld.delete(candidate.worldId);
|
|
678
|
+
if (prev) {
|
|
679
|
+
try {
|
|
680
|
+
prev();
|
|
681
|
+
} catch (err) {
|
|
682
|
+
editorConsole.error(`[design-time-layers] remount dispose failed: ${err}`, 'authoring');
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
const oldLayer = layers.get(candidate.worldId);
|
|
686
|
+
if (oldLayer) {
|
|
687
|
+
oldLayer.remove();
|
|
688
|
+
layers.delete(candidate.worldId);
|
|
689
|
+
}
|
|
690
|
+
mountCandidate(candidate, i);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
// WHEN A MOUNTED LAYER GOES STALE IS THE MOUNT'S STATEMENT, NOT THIS
|
|
694
|
+
// MODULE'S. Two rules used to be hard-coded here, each bought with a
|
|
695
|
+
// measured screen. A canvas layer REMOUNTS when a write lands with no HMR
|
|
696
|
+
// channel to re-execute it: without that a structural write landed in
|
|
697
|
+
// source while the live board kept showing the old world until F5 (runhuman
|
|
698
|
+
// pass 61: "when I duplicated, nothing happened... when you refresh, now it
|
|
699
|
+
// shows"). A dom board RE-PROJECTS when its story registry publishes: same absence of
|
|
700
|
+
// HMR, and a dragged crosshair stayed where the live preview left it while
|
|
701
|
+
// an UNDO changed nothing on screen until F5 — "Ctrl+Z just blinked" for
|
|
702
|
+
// every Windows tester and, measured on the instrument, for macOS too
|
|
703
|
+
// (runhuman passes 135–142; screen read 2026-09-03). Both are facts about a
|
|
704
|
+
// MEDIUM, so both travel with the mount now.
|
|
705
|
+
//
|
|
706
|
+
// WHAT STAYS HERE is the pair of ACTIONS and the one question this module
|
|
707
|
+
// can answer — whether a stale layer may be replaced right now (not while
|
|
708
|
+
// play is running, not after teardown). REMOUNT tears the old layer down
|
|
709
|
+
// first; RE-PROJECT mounts the new one on top and disposes the previous
|
|
710
|
+
// only once it has settled, because an empty board over the old one IS the
|
|
711
|
+
// flash (runhuman pass 146). A mount asks for the one its medium affords.
|
|
712
|
+
// The three world is neither: it runs its own design session with its own
|
|
713
|
+
// absorb protocol (`r3f-design-session.ts`).
|
|
714
|
+
const invalidationStops = new Map<DesignTimeMount, () => void>();
|
|
715
|
+
function bindInvalidations(): void {
|
|
716
|
+
for (const [mount, stop] of invalidationStops) {
|
|
717
|
+
if (designTimeMountFor(mount.kind) === mount) continue;
|
|
718
|
+
// Replaced (an HMR re-evaluation) or removed: its hooks are stale.
|
|
719
|
+
stop();
|
|
720
|
+
invalidationStops.delete(mount);
|
|
721
|
+
}
|
|
722
|
+
for (const mount of designTimeMounts()) {
|
|
723
|
+
if (invalidationStops.has(mount)) continue;
|
|
724
|
+
if (designTimeMountFor(mount.kind) !== mount) continue;
|
|
725
|
+
if (!orderedCandidates.some((c) => c.kind === mount.kind)) continue;
|
|
726
|
+
const stops: Array<() => void> = [];
|
|
727
|
+
const invalidate =
|
|
728
|
+
(apply: (candidate: DesignTimeRootDescriptor, index: number) => void) => (): void => {
|
|
729
|
+
if (torndown || playTeardownDone || store.playState !== 'stopped') return;
|
|
730
|
+
orderedCandidates.forEach((candidate, index) => {
|
|
731
|
+
if (candidate.kind === mount.kind) apply(candidate, index);
|
|
732
|
+
});
|
|
733
|
+
};
|
|
734
|
+
if (mount.remountWhen) stops.push(mount.remountWhen(invalidate(remountCandidate)));
|
|
735
|
+
if (mount.reprojectWhen) stops.push(mount.reprojectWhen(invalidate(reprojectCandidate)));
|
|
736
|
+
invalidationStops.set(mount, () => {
|
|
737
|
+
for (const stop of stops) stop();
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
bindInvalidations();
|
|
742
|
+
|
|
743
|
+
// A PACKAGE THAT ARRIVES LATE STILL GETS ITS LAYER. The contribution pass
|
|
744
|
+
// that loads the surface packages is deferred behind the first viewport
|
|
745
|
+
// frame (`project-tool-discovery.ts`), so on a cold open this stack is
|
|
746
|
+
// routinely installed before any of them has registered. Every candidate it
|
|
747
|
+
// could not mount is waiting in `awaitingMount`; a registration is the
|
|
748
|
+
// moment to mount it, and the moment to bind that medium's staleness hooks.
|
|
749
|
+
const unsubMounts = subscribeDesignTimeMounts(() => {
|
|
750
|
+
if (torndown || playTeardownDone || store.playState !== 'stopped') return;
|
|
751
|
+
orderedCandidates.forEach((candidate, index) => {
|
|
752
|
+
if (!awaitingMount.has(candidate.worldId)) return;
|
|
753
|
+
if (!designTimeMountFor(candidate.kind)) return;
|
|
754
|
+
refusedMount.delete(candidate.worldId);
|
|
755
|
+
clearMountFailureReport(candidate.worldId);
|
|
756
|
+
mountCandidate(candidate, index);
|
|
757
|
+
});
|
|
758
|
+
bindInvalidations();
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
// ...AND A MEDIUM NO PACKAGE OWNS SAYS SO. Once a contribution pass has
|
|
762
|
+
// installed, "nothing registered" has stopped being "not yet" and become
|
|
763
|
+
// the answer — the honest emptiness a build whose package list carries no
|
|
764
|
+
// mount for this medium gives. It is a Boundary disclosure, deliberately
|
|
765
|
+
// NOT an `editorConsole.error` and not a mount-failure report: a build
|
|
766
|
+
// shipping no such package is a configuration fact, not a failure, and a
|
|
767
|
+
// later registration above still upgrades it.
|
|
768
|
+
const unsubContributions = subscribeToolContributions(() => {
|
|
769
|
+
if (torndown || playTeardownDone) return;
|
|
770
|
+
let refused = false;
|
|
771
|
+
for (const candidate of orderedCandidates) {
|
|
772
|
+
if (!awaitingMount.has(candidate.worldId)) continue;
|
|
773
|
+
if (refusedMount.has(candidate.worldId)) continue;
|
|
774
|
+
if (designTimeMountFor(candidate.kind)) continue;
|
|
775
|
+
refusedMount.add(candidate.worldId);
|
|
776
|
+
if (!isCompositeChild(composite, candidate.worldId)) continue;
|
|
777
|
+
const info: BoundaryRootInfo = {
|
|
778
|
+
id: candidate.worldId,
|
|
779
|
+
kind: candidate.kind,
|
|
780
|
+
entryOrScenePath: candidate.path,
|
|
781
|
+
zOrder: candidate.zOrder,
|
|
782
|
+
pausable: candidate.pausable,
|
|
783
|
+
};
|
|
784
|
+
composite.replaceChild(
|
|
785
|
+
candidate.worldId,
|
|
786
|
+
new BoundaryAuthoringAdapter(
|
|
787
|
+
store,
|
|
788
|
+
info,
|
|
789
|
+
`No package in this editor registered a design-time mount for a "${candidate.kind}" ` +
|
|
790
|
+
'world, so there is nothing here to author it with. A build ships the packages its ' +
|
|
791
|
+
'own entry in `builds/` lists.',
|
|
792
|
+
),
|
|
793
|
+
);
|
|
794
|
+
refused = true;
|
|
795
|
+
}
|
|
796
|
+
if (refused) store.notifyIngestEdit();
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
// D4 (spec27 §8 "space-pan" row) — the lockstep half of the pan feature:
|
|
800
|
+
// re-apply the current shared transform to every currently-mounted layer
|
|
801
|
+
// the instant it changes (`RootSelectionOverlay`'s own outer wrapper binds
|
|
802
|
+
// the SAME `subscribeRootPan`/`panTransformValue` pair independently — see
|
|
803
|
+
// `world-pan-state.ts`'s doc comment for why applying the identical value
|
|
804
|
+
// at both mount points is what keeps `rect(id)` pan-invariant). A cheap
|
|
805
|
+
// style write, never a remount.
|
|
806
|
+
const unsubPan = subscribeRootPan(() => {
|
|
807
|
+
for (const layer of layers.values()) applyPanTransform(layer);
|
|
808
|
+
});
|
|
809
|
+
const unsubViewport = subscribeRootCanvasViewport(() => {
|
|
810
|
+
for (const layer of layers.values()) applyPanTransform(layer);
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
const unsubStore = store.subscribe(() => {
|
|
814
|
+
if (!playTeardownDone && store.playState !== 'stopped') {
|
|
815
|
+
playTeardownDone = true;
|
|
816
|
+
suspendForPlay();
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
if (playTeardownDone && !rebuildRequested && store.playState === 'stopped' && !torndown) {
|
|
820
|
+
rebuildRequested = true;
|
|
821
|
+
// Reuse the world root's stage's one authoritative reinstall path. The event
|
|
822
|
+
// causes this mount's disposer to run before the replacement composite
|
|
823
|
+
// and layers are installed, so no React root or adapter survives across
|
|
824
|
+
// the Play -> Stop boundary.
|
|
825
|
+
if (!torndown) queueEditModeRebuild();
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
// Session toggles (eye/interactive) change via `store.notifyIngestEdit()`
|
|
829
|
+
// (`GameHierarchy.tsx`'s row affordances) — this is a cheap style
|
|
830
|
+
// re-apply, never a remount.
|
|
831
|
+
if (!playTeardownDone) {
|
|
832
|
+
for (const [worldId, layer] of layers) {
|
|
833
|
+
applySessionStyle(layer, worldId, candidateByRoot.get(worldId)?.kind ?? 'dom');
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
return () => {
|
|
839
|
+
torndown = true;
|
|
840
|
+
for (const stop of invalidationStops.values()) stop();
|
|
841
|
+
invalidationStops.clear();
|
|
842
|
+
unsubMounts();
|
|
843
|
+
unsubContributions();
|
|
844
|
+
unsubStore();
|
|
845
|
+
unsubPan();
|
|
846
|
+
unsubViewport();
|
|
847
|
+
disposeEverything();
|
|
848
|
+
};
|
|
849
|
+
}
|