@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,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE `story` ADDRESS — one registered opener for every gesture that opens a
|
|
3
|
+
* portable story (`@editor/document-open-registry`).
|
|
4
|
+
*
|
|
5
|
+
* The host used to reach four different ways: `ProjectLayout` branched on
|
|
6
|
+
* `requested.kind === 'story'` and pre-loaded the module itself,
|
|
7
|
+
* `scene-documents` resolved a composed id against the registry,
|
|
8
|
+
* `GameHierarchy` called `openStoryDocumentByStoryId`, and
|
|
9
|
+
* `editor-view-presentation` polled the registry, derived the title and chose
|
|
10
|
+
* the medium. All four were the host knowing what CSF is. They are now ONE
|
|
11
|
+
* address, `story`, and the host asks for it exactly as it asks for
|
|
12
|
+
* `generation` (WORK.md §Stories leave the host, edges 4–7).
|
|
13
|
+
*
|
|
14
|
+
* TWO WAYS TO NAME A STORY, because the gestures genuinely differ: a module
|
|
15
|
+
* path plus an export name (a layout address, a view address, a package that
|
|
16
|
+
* just WROTE the module), or the composed Storybook id (a hierarchy row's
|
|
17
|
+
* node id, a scene-table plan). Both resolve here; neither is the host's
|
|
18
|
+
* problem.
|
|
19
|
+
*
|
|
20
|
+
* WHICH SURFACE it lands on is still the declared medium
|
|
21
|
+
* (`story-declared-medium.ts`) delegated to `story:three` / `story:isolated`,
|
|
22
|
+
* and `mode: 'docs'` to `story:docs`. Those three are `@vgai/game`'s
|
|
23
|
+
* documents: a build without that package has no opener for them and this one
|
|
24
|
+
* answers `null`, which is the same honest answer an undeclared medium gives.
|
|
25
|
+
*
|
|
26
|
+
* SETTLING. `open` is synchronous and a story address routinely arrives before
|
|
27
|
+
* discovery has published the module — on a layout restore, and immediately
|
|
28
|
+
* after a package writes a story module. `document-open-registry.ts` already
|
|
29
|
+
* has the shape for that: try once, let the kind SETTLE, try again. What each
|
|
30
|
+
* former call site did by hand is what `settle` does here, and which one it
|
|
31
|
+
* does depends on what the failed attempt NAMED — a module path settles by
|
|
32
|
+
* loading exactly that module (`ProjectLayout`'s `ensureProjectStoryModule`,
|
|
33
|
+
* whose own loop re-runs when a concurrent discovery pass supersedes it, and
|
|
34
|
+
* which is also what a package that just WROTE a story module needs), an
|
|
35
|
+
* id-only address by waiting for discovery to PUBLISH
|
|
36
|
+
* (`whenProjectStoriesReady`, never a refresh of its own — a later pass
|
|
37
|
+
* supersedes that and it returns over an emptied registry, measured in unit
|
|
38
|
+
* 4). `tierSourceWriteBackend()` comes first on both, because a restored
|
|
39
|
+
* address can arrive before the source backend the discovery scan reads
|
|
40
|
+
* exists — that is the await `ProjectLayout` held.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
import { object3DDocumentSession } from '../authoring/object3d-document-session-registry';
|
|
44
|
+
import { openRegisteredDocument, registerDocumentOpener } from '../document-open-registry';
|
|
45
|
+
import { editorConsole } from '../editor-console';
|
|
46
|
+
import { getCurrentProject } from '../project-manager';
|
|
47
|
+
import { tierSourceWriteBackend } from '../ui-source/tier-source-write-backend';
|
|
48
|
+
import { DOCUMENT_REGISTRATION_TIMEOUT_MS, waitUntil } from '../wait-until';
|
|
49
|
+
import type { WorkspaceStateStore } from '../workspace-document-restore';
|
|
50
|
+
import { getProjectStoryRegions } from './project-story-regions';
|
|
51
|
+
import { declaredStoryMedium, reportUndeclaredStoryMedium } from './story-declared-medium';
|
|
52
|
+
import {
|
|
53
|
+
ISOLATED_STORY_DOCUMENT_OPENER,
|
|
54
|
+
STORY_DOCS_DOCUMENT_OPENER,
|
|
55
|
+
THREE_STORY_DOCUMENT_OPENER,
|
|
56
|
+
} from './story-document-openers';
|
|
57
|
+
import { deriveStoryGroupPath } from './story-grouping';
|
|
58
|
+
import {
|
|
59
|
+
ensureProjectStoryModule,
|
|
60
|
+
getProjectStoryModules,
|
|
61
|
+
projectStoriesReady,
|
|
62
|
+
whenProjectStoriesReady,
|
|
63
|
+
} from './story-registry';
|
|
64
|
+
|
|
65
|
+
/** The address a story opens under. */
|
|
66
|
+
export const STORY_DOCUMENT_OPENER = 'story';
|
|
67
|
+
|
|
68
|
+
export interface StoryOpenRequest {
|
|
69
|
+
/** Project-relative CSF module path. With {@link StoryOpenRequest.storyName}
|
|
70
|
+
* this is the whole address. */
|
|
71
|
+
readonly modulePath?: string;
|
|
72
|
+
/** The story's authored export name. */
|
|
73
|
+
readonly storyName?: string;
|
|
74
|
+
/** The composed Storybook id — the other way to name the same story (a
|
|
75
|
+
* hierarchy story row's node id IS this id). */
|
|
76
|
+
readonly storyId?: string;
|
|
77
|
+
/** Tab title; derived from the story's own group path when absent. */
|
|
78
|
+
readonly title?: string;
|
|
79
|
+
/** Whether opening also FOCUSES the tab. A click-through opens and focuses;
|
|
80
|
+
* the Edit tab row offers a standing tab instead and passes `false`. */
|
|
81
|
+
readonly activate?: boolean;
|
|
82
|
+
/** `docs` opens the Storybook Docs companion instead of the preview. */
|
|
83
|
+
readonly mode?: 'preview' | 'docs';
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* What a failed attempt NAMED, waiting for `settle` — which takes no request,
|
|
88
|
+
* so this is where the pair meets. Sets rather than one slot each, because
|
|
89
|
+
* several addresses can be in flight at once (a restored layout opening three
|
|
90
|
+
* story tabs) and settling one must not drop another's.
|
|
91
|
+
*/
|
|
92
|
+
const unsettledModules = new Set<string>();
|
|
93
|
+
const unsettledIds = new Set<string>();
|
|
94
|
+
|
|
95
|
+
interface ResolvedStory {
|
|
96
|
+
readonly modulePath: string;
|
|
97
|
+
readonly storyName: string;
|
|
98
|
+
readonly title: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** The title a story gives itself: its group path's leaf, and its own label
|
|
102
|
+
* when that says something the leaf does not. */
|
|
103
|
+
function derivedTitle(story: {
|
|
104
|
+
readonly modulePath: string;
|
|
105
|
+
readonly title?: string | undefined;
|
|
106
|
+
readonly label: string;
|
|
107
|
+
}): string {
|
|
108
|
+
const subject = deriveStoryGroupPath({ modulePath: story.modulePath, title: story.title }).leaf;
|
|
109
|
+
return subject === story.label ? subject : `${subject} · ${story.label}`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Resolve an address against the live registry, or `null` when nothing
|
|
113
|
+
* composed answers to it yet. */
|
|
114
|
+
function resolve(request: StoryOpenRequest): ResolvedStory | null {
|
|
115
|
+
for (const module_ of getProjectStoryModules()) {
|
|
116
|
+
if (!module_.ok) continue;
|
|
117
|
+
for (const story of module_.stories) {
|
|
118
|
+
const matches =
|
|
119
|
+
request.storyId === undefined
|
|
120
|
+
? module_.modulePath === request.modulePath && story.name === request.storyName
|
|
121
|
+
: story.id === request.storyId;
|
|
122
|
+
if (!matches) continue;
|
|
123
|
+
return {
|
|
124
|
+
modulePath: module_.modulePath,
|
|
125
|
+
storyName: story.name,
|
|
126
|
+
title:
|
|
127
|
+
request.title ??
|
|
128
|
+
derivedTitle({ modulePath: module_.modulePath, title: story.title, label: story.label }),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function openResolved(
|
|
136
|
+
store: WorkspaceStateStore,
|
|
137
|
+
request: StoryOpenRequest,
|
|
138
|
+
story: ResolvedStory,
|
|
139
|
+
): string | null {
|
|
140
|
+
const base = {
|
|
141
|
+
modulePath: story.modulePath,
|
|
142
|
+
storyName: story.storyName,
|
|
143
|
+
title: story.title,
|
|
144
|
+
...(request.activate === undefined ? {} : { activate: request.activate }),
|
|
145
|
+
};
|
|
146
|
+
if (request.mode === 'docs') {
|
|
147
|
+
return openRegisteredDocument(STORY_DOCS_DOCUMENT_OPENER, store, base);
|
|
148
|
+
}
|
|
149
|
+
const declared = declaredStoryMedium({
|
|
150
|
+
modulePath: story.modulePath,
|
|
151
|
+
regions: getProjectStoryRegions(),
|
|
152
|
+
});
|
|
153
|
+
if (declared.medium === undefined) {
|
|
154
|
+
// An undeclared story is a NAMED gap, never a candidate for a fallback
|
|
155
|
+
// renderer — and never a reason to settle and try again, so it reports
|
|
156
|
+
// here and the address answers "opened nothing" rather than `null`'s
|
|
157
|
+
// "ask me again".
|
|
158
|
+
reportUndeclaredStoryMedium(story.modulePath, declared.reason);
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
return openRegisteredDocument(
|
|
162
|
+
declared.medium === 'three' ? THREE_STORY_DOCUMENT_OPENER : ISOLATED_STORY_DOCUMENT_OPENER,
|
|
163
|
+
store,
|
|
164
|
+
base,
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** An id no composed story carries. The caller's own refusal can only say
|
|
169
|
+
* "nothing opened it": the two ways an address fails — an unknown id, and a
|
|
170
|
+
* module with no declared medium — are both this package's to tell apart. */
|
|
171
|
+
function reportUnresolvedStoryId(storyId: string): void {
|
|
172
|
+
editorConsole.warn(
|
|
173
|
+
`No composed portable story carries the id ${JSON.stringify(storyId)}, so nothing opened it.`,
|
|
174
|
+
'editor',
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function registerStoryOpener(): () => void {
|
|
179
|
+
return registerDocumentOpener<StoryOpenRequest>({
|
|
180
|
+
id: STORY_DOCUMENT_OPENER,
|
|
181
|
+
owner: './story-opener',
|
|
182
|
+
open: (store, request) => {
|
|
183
|
+
const story = resolve(request);
|
|
184
|
+
if (story) return openResolved(store, request, story);
|
|
185
|
+
if (request.modulePath) unsettledModules.add(request.modulePath);
|
|
186
|
+
else if (request.storyId !== undefined) {
|
|
187
|
+
unsettledIds.add(request.storyId);
|
|
188
|
+
// Only once discovery has PUBLISHED is an unknown id a real answer;
|
|
189
|
+
// before that an empty registry is boot in flight, and a synchronous
|
|
190
|
+
// caller (the Edit tab row, the `open` verb) is the one that needs the
|
|
191
|
+
// name — an async caller settles and asks again first.
|
|
192
|
+
if (projectStoriesReady()) reportUnresolvedStoryId(request.storyId);
|
|
193
|
+
}
|
|
194
|
+
return null;
|
|
195
|
+
},
|
|
196
|
+
settle: async () => {
|
|
197
|
+
await tierSourceWriteBackend();
|
|
198
|
+
const modules = [...unsettledModules];
|
|
199
|
+
const ids = [...unsettledIds];
|
|
200
|
+
unsettledModules.clear();
|
|
201
|
+
unsettledIds.clear();
|
|
202
|
+
// A MODULE-named address settles by loading exactly that module, whose
|
|
203
|
+
// own loop re-runs when a concurrent discovery pass supersedes it. This
|
|
204
|
+
// is also what a package that just WROTE a story needs: the module is
|
|
205
|
+
// new, so nothing published it and the targeted load is the refresh.
|
|
206
|
+
await Promise.all(
|
|
207
|
+
modules.map((modulePath) => ensureProjectStoryModule(getCurrentProject(), modulePath)),
|
|
208
|
+
);
|
|
209
|
+
if (ids.length === 0) return;
|
|
210
|
+
// An ID-only address settles by waiting for discovery to PUBLISH — never
|
|
211
|
+
// by awaiting a refresh of its own, which a later pass supersedes and
|
|
212
|
+
// which then returns over an emptied registry (measured, unit 4).
|
|
213
|
+
await whenProjectStoriesReady();
|
|
214
|
+
for (const storyId of ids) {
|
|
215
|
+
if (!resolve({ storyId })) reportUnresolvedStoryId(storyId);
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
/**
|
|
219
|
+
* THIS ADDRESS'S OWN READINESS: a story the presenter just opened is not
|
|
220
|
+
* ready to be DRIVEN until the document it opened into has mounted its
|
|
221
|
+
* stage. The presenter used to hold this rule by spelling the three-story
|
|
222
|
+
* document's id prefix (`editor-view-presentation.ts`'s
|
|
223
|
+
* `documentId.startsWith('three-story:')`); it is this package's, because
|
|
224
|
+
* this package is what chose the medium (`openResolved` above) and
|
|
225
|
+
* therefore what knows a `three` story opens onto a turntable stage while
|
|
226
|
+
* an `isolated` one and a `docs` one do not.
|
|
227
|
+
*
|
|
228
|
+
* The MEDIUM is the declaration here, not the stage's own announcement:
|
|
229
|
+
* the story document constructs its viewport source asynchronously
|
|
230
|
+
* (`@vgai/game`'s `three-story-documents.tsx`), so at this instant nothing
|
|
231
|
+
* has rendered yet and an announcement could only read absent. A `three`
|
|
232
|
+
* medium ALWAYS mounts one, which is what makes the wait unconditional and
|
|
233
|
+
* the refusal honest.
|
|
234
|
+
*
|
|
235
|
+
* The three DIRECT callers of `story:three`
|
|
236
|
+
* (`three-board/ThreeBoardDocument.tsx:189`,
|
|
237
|
+
* `../src/component-states-source.ts`, and `openResolved` above) go
|
|
238
|
+
* through the SYNCHRONOUS door, which by the registry's own contract gets
|
|
239
|
+
* the id and waits on the kind's doors itself.
|
|
240
|
+
*/
|
|
241
|
+
ready: async (documentId, request) => {
|
|
242
|
+
if (request.mode === 'docs') return;
|
|
243
|
+
const story = resolve(request);
|
|
244
|
+
if (!story) return;
|
|
245
|
+
const declared = declaredStoryMedium({
|
|
246
|
+
modulePath: story.modulePath,
|
|
247
|
+
regions: getProjectStoryRegions(),
|
|
248
|
+
});
|
|
249
|
+
if (declared.medium !== 'three') return;
|
|
250
|
+
if (
|
|
251
|
+
await waitUntil(
|
|
252
|
+
() => object3DDocumentSession(documentId) !== null,
|
|
253
|
+
DOCUMENT_REGISTRATION_TIMEOUT_MS,
|
|
254
|
+
)
|
|
255
|
+
)
|
|
256
|
+
return;
|
|
257
|
+
throw new Error(`The requested Object3D view did not mount for document: ${documentId}`);
|
|
258
|
+
},
|
|
259
|
+
});
|
|
260
|
+
}
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Off-screen CANVAS/Pixi story preview — mount a composed CSF story that
|
|
3
|
+
* produces Pixi content and hand back the `PIXI.Container` it rendered into,
|
|
4
|
+
* plus the `Application` that owns its clock.
|
|
5
|
+
*
|
|
6
|
+
* The canvas-surface sibling of `story-three-preview.ts`, and it exists for the
|
|
7
|
+
* same reason: portable CSF is a prefab's explicit "here is how this renders",
|
|
8
|
+
* and a surface that wants to SHOW a prefab (the canvas board, and the
|
|
9
|
+
* qualification both boards key membership on) needs that render as an object,
|
|
10
|
+
* not as a picture.
|
|
11
|
+
*
|
|
12
|
+
* ## Why the mount goes through react-dom, not through a Pixi root
|
|
13
|
+
*
|
|
14
|
+
* A 2D prefab story mounts its OWN `@pixi/react` `<Application>` (see any 2D prefab's colocated
|
|
15
|
+
* story under an example project's `prefabs` directory): unlike the three lane, where the
|
|
16
|
+
* board supplies the scene and the story renders bare JSX into it, nothing
|
|
17
|
+
* supplies a canvas-surface stage, so the story carries one and renders
|
|
18
|
+
* anywhere react-dom renders. That is the story's own declaration and this
|
|
19
|
+
* module does not second-guess it — it mounts the story exactly as written, in
|
|
20
|
+
* a detached DOM host, and then ADOPTS what came out.
|
|
21
|
+
*
|
|
22
|
+
* ## What comes out, and what the caller may do with it
|
|
23
|
+
*
|
|
24
|
+
* `host` is the detached element the story rendered into and `stage` is the
|
|
25
|
+
* Application's own root container — the REAL objects, with the story's real
|
|
26
|
+
* textures on them. A caller that wants to DISPLAY the story reparents the
|
|
27
|
+
* host into its own DOM (the `2D` board does exactly this, one host per
|
|
28
|
+
* frame); nothing here rasterizes, copies, or re-creates anything, which is
|
|
29
|
+
* what keeps the composed story render the sole visual authority (the
|
|
30
|
+
* anti-shim rule) and what makes a `scaleMode: 'nearest'` sheet magnify
|
|
31
|
+
* nearest wherever it ends up — the filtering belongs to the texture's own
|
|
32
|
+
* source, and adopting the real render carries it along.
|
|
33
|
+
*
|
|
34
|
+
* The mount arrives STOPPED: `Application.init` defaults to `autoStart: true`,
|
|
35
|
+
* so the story's own `requestAnimationFrame` loop would run on wall time in a
|
|
36
|
+
* detached host nobody is looking at. {@link MountedStoryPixi.ticker} is that
|
|
37
|
+
* clock, handed to the caller so a surface that wants the cycle to PLAY drives
|
|
38
|
+
* it from its own frame instead — one clock per surface, none on wall time.
|
|
39
|
+
*
|
|
40
|
+
* ## Mounts are SERIAL, and one bad story never takes the rest down
|
|
41
|
+
*
|
|
42
|
+
* Same physics as the three lane, same queue (`story-mount-turn.ts`): a story's
|
|
43
|
+
* loaders touch process-global state (Pixi's `Assets` cache and the
|
|
44
|
+
* `@pixi/react` component catalogue are both module-global), so overlapping two
|
|
45
|
+
* mounts interleaves their setup. A story that crashes while rendering is
|
|
46
|
+
* caught by {@link CrashNullBoundary} and rejects in milliseconds with its own
|
|
47
|
+
* error rather than burning the ceiling below — the exact measurement the three
|
|
48
|
+
* lane records, and the reason a board over a project of non-canvas stories
|
|
49
|
+
* finishes at all.
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
import type { Application, Container } from 'pixi.js';
|
|
53
|
+
import { createElement } from 'react';
|
|
54
|
+
import type { Root } from 'react-dom/client';
|
|
55
|
+
import { withApplicationCollector } from '../canvas-preview-frames';
|
|
56
|
+
import { CrashNullBoundary } from '../crash-null-boundary';
|
|
57
|
+
import { mountedStoryHasPixiContent } from './pixi-story-model';
|
|
58
|
+
import { resolveStoryDomRuntime } from './story-dom-runtime';
|
|
59
|
+
import { runInStoryMountTurn } from './story-mount-turn';
|
|
60
|
+
import type { StoryPreviewComponent } from './story-three-preview';
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* How long the mount waits for the story's `Application` to finish initializing
|
|
64
|
+
* AND for its stage to hold content. Both are legitimately slow: `init()`
|
|
65
|
+
* creates a real renderer, and a prefab story commonly gates its children on
|
|
66
|
+
* its atlas (`SpritesReady`), so the content arrives when the sheet does.
|
|
67
|
+
* Matches the three lane's own first-commit ceiling.
|
|
68
|
+
*/
|
|
69
|
+
const PIXI_MOUNT_TIMEOUT_MS = 10_000;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Event-loop turns the mount waits for the story's FIRST DOM commit, and for a
|
|
73
|
+
* `<canvas>` to appear in it. This is the cheap NO: a story that renders DOM
|
|
74
|
+
* and no canvas is not a canvas story, and it must answer in a few turns rather
|
|
75
|
+
* than at the ceiling above — otherwise every board build over a UI-only
|
|
76
|
+
* project would pay ten seconds per story.
|
|
77
|
+
*/
|
|
78
|
+
const COMMIT_TURNS = 12;
|
|
79
|
+
|
|
80
|
+
/** Where the detached host sits: far off-screen, contained, inert. `contain:
|
|
81
|
+
* strict` makes the host the containing block for `position: fixed`
|
|
82
|
+
* descendants, so a story that pins itself cannot flash across the editor —
|
|
83
|
+
* the same containment `story-capture.ts` documents for its own host. */
|
|
84
|
+
const HOST_STYLE =
|
|
85
|
+
'position:fixed;left:-20000px;top:0;width:512px;height:512px;' +
|
|
86
|
+
'overflow:hidden;contain:strict;pointer-events:none;visibility:hidden;';
|
|
87
|
+
|
|
88
|
+
/** One mounted canvas story. */
|
|
89
|
+
export interface MountedStoryPixi {
|
|
90
|
+
/**
|
|
91
|
+
* The detached element the story rendered into, with its `<canvas>` inside.
|
|
92
|
+
*
|
|
93
|
+
* A DOM surface that wants to SHOW this story reparents THIS element — never
|
|
94
|
+
* the canvas alone. React owns the host's children: moving a react-rendered
|
|
95
|
+
* node out from under its own root leaves `root.unmount()` removing a child
|
|
96
|
+
* of a parent it no longer has, which throws. The host itself is ours, so it
|
|
97
|
+
* travels freely and {@link dispose} still removes it from wherever it ended
|
|
98
|
+
* up. Restyle it on adoption; {@link HOST_STYLE} only parks it off-screen.
|
|
99
|
+
*/
|
|
100
|
+
readonly host: HTMLElement;
|
|
101
|
+
/** The Application's own root container — the story's real display tree.
|
|
102
|
+
* Reparent it; never copy it. */
|
|
103
|
+
readonly stage: Container;
|
|
104
|
+
/** The story's clock, already STOPPED. A surface that wants the story's
|
|
105
|
+
* cycle to play calls `ticker.update(elapsedMs)` from its own frame. */
|
|
106
|
+
readonly ticker: Application['ticker'];
|
|
107
|
+
/**
|
|
108
|
+
* The Application the story built — its own renderer included.
|
|
109
|
+
*
|
|
110
|
+
* A displaying surface keeps that renderer (it is what draws the adopted
|
|
111
|
+
* host's canvas) and therefore keeps its WebGL context. That is the real
|
|
112
|
+
* ceiling on how many stories one surface may show at once: a browser allows
|
|
113
|
+
* on the order of sixteen contexts per page and drops the OLDEST when that
|
|
114
|
+
* runs out. `app.screen` is the mounting canvas the story's own
|
|
115
|
+
* `<Application>` declared; presentation surfaces may crop it to stage
|
|
116
|
+
* content unless the story explicitly requests a fullscreen layout.
|
|
117
|
+
*/
|
|
118
|
+
readonly app: Application;
|
|
119
|
+
/** Tear the isolated react root down and destroy the story's display tree and
|
|
120
|
+
* clock. Runs the story's own effect cleanups. Idempotent. */
|
|
121
|
+
dispose(): void;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** A mount function valid inside an already-acquired story turn — the canvas
|
|
125
|
+
* sibling of `story-three-preview.ts`'s `StoryMountInTurn`. */
|
|
126
|
+
export type PixiStoryMountInTurn = (
|
|
127
|
+
Component: StoryPreviewComponent,
|
|
128
|
+
props?: Record<string, unknown>,
|
|
129
|
+
) => Promise<MountedStoryPixi>;
|
|
130
|
+
|
|
131
|
+
/** Run one compound canvas-story operation (a whole board build) with no other
|
|
132
|
+
* story mount, of any medium, interleaving it. */
|
|
133
|
+
export function withPixiStoryMountTurn<T>(
|
|
134
|
+
task: (mount: PixiStoryMountInTurn) => Promise<T>,
|
|
135
|
+
): Promise<T> {
|
|
136
|
+
return runInStoryMountTurn(() => task(mountStoryPixiInTurn));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Mount one canvas story off-screen, taking a turn of its own. */
|
|
140
|
+
export function mountStoryPixi(
|
|
141
|
+
Component: StoryPreviewComponent,
|
|
142
|
+
props: Record<string, unknown> = {},
|
|
143
|
+
): Promise<MountedStoryPixi> {
|
|
144
|
+
return withPixiStoryMountTurn((mount) => mount(Component, props));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Dispose a standalone mount in the same shared turn domain. Compound callers
|
|
148
|
+
* already holding a turn dispose their own mounts inside it. */
|
|
149
|
+
export function disposeStoryPixi(mounted: MountedStoryPixi): Promise<void> {
|
|
150
|
+
return runInStoryMountTurn(async () => mounted.dispose());
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface PixiStoryThumbnailOptions {
|
|
154
|
+
readonly width?: number;
|
|
155
|
+
readonly height?: number;
|
|
156
|
+
readonly props?: Record<string, unknown>;
|
|
157
|
+
/** Storybook's standard layout policy. Only `fullscreen` makes the
|
|
158
|
+
* mounting Application's declared canvas part of the preview. */
|
|
159
|
+
readonly layout?: 'centered' | 'padded' | 'fullscreen';
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Photograph a canvas prefab from its portable CSF story.
|
|
164
|
+
*
|
|
165
|
+
* This is the Pixi sibling of `captureStoryComponentThumbnail`: the story is
|
|
166
|
+
* mounted through its own real `<Application>`, its paused stage is rendered
|
|
167
|
+
* once without advancing the ticker, and Pixi's extraction API reads the
|
|
168
|
+
* result back. The requested rectangle is presentation only; it never becomes
|
|
169
|
+
* a second authored size or a component-specific thumbnail asset.
|
|
170
|
+
*/
|
|
171
|
+
export async function capturePixiStoryThumbnail(
|
|
172
|
+
Component: StoryPreviewComponent,
|
|
173
|
+
options: PixiStoryThumbnailOptions = {},
|
|
174
|
+
): Promise<string> {
|
|
175
|
+
const mounted = await mountStoryPixi(Component, options.props ?? {});
|
|
176
|
+
try {
|
|
177
|
+
const width = options.width ?? 128;
|
|
178
|
+
const height = options.height ?? 96;
|
|
179
|
+
mounted.app.renderer.render({ container: mounted.stage });
|
|
180
|
+
|
|
181
|
+
const bounds = mounted.stage.getBounds();
|
|
182
|
+
const fullscreen = options.layout === 'fullscreen';
|
|
183
|
+
const padding = 8;
|
|
184
|
+
// Both frames are the STORY's own `Rectangle` — `screen.clone()` is the
|
|
185
|
+
// app's class, whatever graph the story mounted in. A story's
|
|
186
|
+
// `<Application>` comes from its own module graph (the project's under the
|
|
187
|
+
// packaged runtime), and this rectangle is handed straight back to that
|
|
188
|
+
// app's extractor; constructing the shell's class here was the one value
|
|
189
|
+
// in this path that crossed.
|
|
190
|
+
const frame = mounted.app.screen.clone();
|
|
191
|
+
if (!fullscreen) {
|
|
192
|
+
frame.x = bounds.x - padding;
|
|
193
|
+
frame.y = bounds.y - padding;
|
|
194
|
+
frame.width = Math.max(1, bounds.width + padding * 2);
|
|
195
|
+
frame.height = Math.max(1, bounds.height + padding * 2);
|
|
196
|
+
}
|
|
197
|
+
// Match the target aspect by adding transparent breathing room. Never
|
|
198
|
+
// stretch a sprite to make a rectangular thumbnail.
|
|
199
|
+
const targetAspect = width / height;
|
|
200
|
+
if (!fullscreen && frame.width / frame.height < targetAspect) {
|
|
201
|
+
const nextWidth = frame.height * targetAspect;
|
|
202
|
+
frame.x -= (nextWidth - frame.width) / 2;
|
|
203
|
+
frame.width = nextWidth;
|
|
204
|
+
} else if (!fullscreen && frame.width / frame.height > targetAspect) {
|
|
205
|
+
const nextHeight = frame.width / targetAspect;
|
|
206
|
+
frame.y -= (nextHeight - frame.height) / 2;
|
|
207
|
+
frame.height = nextHeight;
|
|
208
|
+
}
|
|
209
|
+
const background = mounted.app.renderer.background;
|
|
210
|
+
const source = (await mounted.app.renderer.extract.canvas({
|
|
211
|
+
target: mounted.stage,
|
|
212
|
+
frame,
|
|
213
|
+
...(fullscreen && background.alpha > 0 ? { clearColor: background.colorRgba } : {}),
|
|
214
|
+
})) as HTMLCanvasElement;
|
|
215
|
+
const output = document.createElement('canvas');
|
|
216
|
+
output.width = width;
|
|
217
|
+
output.height = height;
|
|
218
|
+
const context = output.getContext('2d');
|
|
219
|
+
if (!context) throw new Error('Canvas story preview could not create a 2D readback context.');
|
|
220
|
+
|
|
221
|
+
const scale = Math.min(width / source.width, height / source.height);
|
|
222
|
+
const drawWidth = source.width * scale;
|
|
223
|
+
const drawHeight = source.height * scale;
|
|
224
|
+
context.drawImage(
|
|
225
|
+
source,
|
|
226
|
+
(width - drawWidth) / 2,
|
|
227
|
+
(height - drawHeight) / 2,
|
|
228
|
+
drawWidth,
|
|
229
|
+
drawHeight,
|
|
230
|
+
);
|
|
231
|
+
return output.toDataURL('image/png');
|
|
232
|
+
} finally {
|
|
233
|
+
await disposeStoryPixi(mounted);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const nextTurn = (): Promise<void> => new Promise((resolve) => setTimeout(resolve, 0));
|
|
238
|
+
|
|
239
|
+
/** The mount body for callers that already own the story turn. */
|
|
240
|
+
async function mountStoryPixiInTurn(
|
|
241
|
+
StoryComponent: StoryPreviewComponent,
|
|
242
|
+
props: Record<string, unknown> = {},
|
|
243
|
+
): Promise<MountedStoryPixi> {
|
|
244
|
+
// Loaders first (Storybook 9's portable-story contract): a story's `loaded`
|
|
245
|
+
// data is empty until `.load()` has run, and a canvas prefab's loader is
|
|
246
|
+
// where it fetches its atlas.
|
|
247
|
+
if (typeof StoryComponent.load === 'function') await StoryComponent.load();
|
|
248
|
+
|
|
249
|
+
// In the packaged editor the CSF component and @pixi/react both belong to
|
|
250
|
+
// the project's Vite graph. Mount them with that graph's react-dom too;
|
|
251
|
+
// using the prebuilt editor bundle's createRoot crosses React dispatchers.
|
|
252
|
+
const storyRuntime = await resolveStoryDomRuntime();
|
|
253
|
+
|
|
254
|
+
const host = document.createElement('div');
|
|
255
|
+
host.setAttribute('style', HOST_STYLE);
|
|
256
|
+
document.body.appendChild(host);
|
|
257
|
+
|
|
258
|
+
let root: Root | null = null;
|
|
259
|
+
const teardown = (): void => {
|
|
260
|
+
root?.unmount();
|
|
261
|
+
root = null;
|
|
262
|
+
host.remove();
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
return await withApplicationCollector(async (created) => {
|
|
267
|
+
let renderError: unknown = null;
|
|
268
|
+
root = storyRuntime.createRoot(host);
|
|
269
|
+
root.render(
|
|
270
|
+
createElement(
|
|
271
|
+
CrashNullBoundary,
|
|
272
|
+
{
|
|
273
|
+
onCaught: (error: unknown) => {
|
|
274
|
+
renderError ??= error;
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
createElement(StoryComponent, props),
|
|
278
|
+
),
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
// The cheap NO: a committed story with no canvas in it is not a canvas
|
|
282
|
+
// story, and says so in a few turns.
|
|
283
|
+
for (let turn = 0; turn < COMMIT_TURNS; turn++) {
|
|
284
|
+
if (renderError) break;
|
|
285
|
+
if (host.querySelector('canvas')) break;
|
|
286
|
+
await nextTurn();
|
|
287
|
+
}
|
|
288
|
+
if (renderError) throw describeMountFailure(renderError);
|
|
289
|
+
if (!host.querySelector('canvas')) {
|
|
290
|
+
throw new Error('The story rendered no canvas — it does not mount Pixi content.');
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// A canvas is present, so an `Application.init()` is in flight (or has
|
|
294
|
+
// already landed). From here the ceiling is the real one: init creates a
|
|
295
|
+
// renderer, and the story's own content may be gated on its atlas.
|
|
296
|
+
const deadline = Date.now() + PIXI_MOUNT_TIMEOUT_MS;
|
|
297
|
+
let app: Application | undefined;
|
|
298
|
+
while (Date.now() < deadline) {
|
|
299
|
+
if (renderError) throw describeMountFailure(renderError);
|
|
300
|
+
app ??= created[0];
|
|
301
|
+
if (app && mountedStoryHasPixiContent(app.stage)) break;
|
|
302
|
+
await nextTurn();
|
|
303
|
+
}
|
|
304
|
+
if (!app) {
|
|
305
|
+
throw new Error(
|
|
306
|
+
'The story rendered a canvas but never initialized a Pixi Application within ' +
|
|
307
|
+
`${PIXI_MOUNT_TIMEOUT_MS / 1000}s — it is not a canvas story, or its renderer ` +
|
|
308
|
+
'could not be created here.',
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Content time does not run on wall time at design time. The story's own
|
|
313
|
+
// rAF loop stops here and the clock is handed to whoever presents it.
|
|
314
|
+
app.stop();
|
|
315
|
+
app.ticker.lastTime = 0;
|
|
316
|
+
|
|
317
|
+
let disposed = false;
|
|
318
|
+
return {
|
|
319
|
+
host,
|
|
320
|
+
stage: app.stage,
|
|
321
|
+
ticker: app.ticker,
|
|
322
|
+
app,
|
|
323
|
+
dispose(): void {
|
|
324
|
+
if (disposed) return;
|
|
325
|
+
disposed = true;
|
|
326
|
+
// React, and react ONLY. Unmounting the story's `<Application>` is
|
|
327
|
+
// what tears the Application down: `@pixi/react`'s own unmount path
|
|
328
|
+
// (`helpers/unmountRoot`) renders `null` into the stage — running
|
|
329
|
+
// every `useTick` cleanup in order — and only then destroys the app
|
|
330
|
+
// and forgets its canvas. Destroying anything here as well is a
|
|
331
|
+
// double free of a ticker its cleanups are still using.
|
|
332
|
+
teardown();
|
|
333
|
+
},
|
|
334
|
+
} satisfies MountedStoryPixi;
|
|
335
|
+
});
|
|
336
|
+
} catch (error) {
|
|
337
|
+
teardown();
|
|
338
|
+
throw error;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// ------------------------------------------------- the capture lane's frame
|
|
343
|
+
|
|
344
|
+
/** How long {@link awaitPixiStoryFrame} waits. Same ceiling, same reasons, as
|
|
345
|
+
* the mount above: a real renderer is created and a prefab's content commonly
|
|
346
|
+
* waits on its atlas. */
|
|
347
|
+
const FIRST_FRAME_TIMEOUT_MS = PIXI_MOUNT_TIMEOUT_MS;
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Wait until every collected `Application` has PRESENTED a frame with content
|
|
351
|
+
* in it — the readiness test a capture of a canvas story owes itself.
|
|
352
|
+
*
|
|
353
|
+
* MEASURED DEFECT (this is why the function exists): `vgai screenshot
|
|
354
|
+
* <file>.stories.tsx` photographed a `@pixi/react` story blank. The capture
|
|
355
|
+
* lane's own readiness test is "the container has committed child nodes", and
|
|
356
|
+
* `<Application>` commits its `<canvas>` on the FIRST commit — before
|
|
357
|
+
* `Application.init()` has even created a renderer, and long before an atlas
|
|
358
|
+
* the story gates its children on has resolved. So the sheet was rasterized
|
|
359
|
+
* from an empty canvas and looked like a perfectly plausible blank frame, which
|
|
360
|
+
* is the worst failure a look verb has.
|
|
361
|
+
*
|
|
362
|
+
* Two conditions, because either alone still lies: a renderer that has drawn an
|
|
363
|
+
* empty stage has presented a frame, and a stage with children whose renderer
|
|
364
|
+
* has not run yet has no pixels.
|
|
365
|
+
*
|
|
366
|
+
* Resolves (rather than throwing) at the ceiling: a story that genuinely never
|
|
367
|
+
* draws must still be photographed, and an honestly blank cell is the truth
|
|
368
|
+
* about it.
|
|
369
|
+
*/
|
|
370
|
+
export async function awaitPixiStoryFrame(
|
|
371
|
+
apps: readonly Application[],
|
|
372
|
+
now: () => number = Date.now,
|
|
373
|
+
): Promise<void> {
|
|
374
|
+
if (apps.length === 0) return;
|
|
375
|
+
const presented = new Set<Application>();
|
|
376
|
+
const subscriptions = apps.map((app) => {
|
|
377
|
+
const observer = {
|
|
378
|
+
postrender: () => {
|
|
379
|
+
presented.add(app);
|
|
380
|
+
},
|
|
381
|
+
};
|
|
382
|
+
app.renderer?.runners.postrender.add(observer);
|
|
383
|
+
return { app, observer };
|
|
384
|
+
});
|
|
385
|
+
try {
|
|
386
|
+
const deadline = now() + FIRST_FRAME_TIMEOUT_MS;
|
|
387
|
+
while (now() < deadline) {
|
|
388
|
+
const ready = apps.every(
|
|
389
|
+
(app) =>
|
|
390
|
+
app.stage !== undefined && mountedStoryHasPixiContent(app.stage) && presented.has(app),
|
|
391
|
+
);
|
|
392
|
+
if (ready) return;
|
|
393
|
+
await nextTurn();
|
|
394
|
+
}
|
|
395
|
+
} finally {
|
|
396
|
+
for (const { app, observer } of subscriptions) {
|
|
397
|
+
app.renderer?.runners.postrender.remove(observer);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function describeMountFailure(error: unknown): Error {
|
|
403
|
+
return new Error(
|
|
404
|
+
'mountStoryPixi: the story threw while rendering — it does not mount Pixi content, or its ' +
|
|
405
|
+
`component crashed. Original error: ${error instanceof Error ? error.message : String(error)}`,
|
|
406
|
+
{ cause: error },
|
|
407
|
+
);
|
|
408
|
+
}
|