@volter/sdk 0.0.0-stage → 0.5.203
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/LICENSE +202 -0
- package/NOTICE +20 -0
- package/README.md +38 -3
- package/package.json +510 -4
- package/src/account.ts +210 -0
- package/src/chrome.ts +88 -0
- package/src/client.ts +1646 -0
- package/src/commands.ts +66 -0
- package/src/contributions.ts +619 -0
- package/src/css-numeric-style.ts +97 -0
- package/src/document-probe.ts +282 -0
- package/src/editor-view.ts +225 -0
- package/src/extension.ts +40 -0
- package/src/generations.ts +178 -0
- package/src/host.ts +1157 -0
- package/src/http-transport.browser.ts +14 -0
- package/src/http-transport.node.ts +19 -0
- package/src/index.ts +131 -0
- package/src/kit/CapabilityCoverageSection.tsx +185 -0
- package/src/kit/account-client.ts +333 -0
- package/src/kit/action-registry.ts +317 -0
- package/src/kit/active-product.ts +76 -0
- package/src/kit/active-project.ts +155 -0
- package/src/kit/adapter-editor-config.ts +25 -0
- package/src/kit/adapter-module.ts +7 -0
- package/src/kit/adapter-observation.ts +49 -0
- package/src/kit/animation/animation-clock.ts +479 -0
- package/src/kit/animation/stage-transport.ts +385 -0
- package/src/kit/api/assets.ts +365 -0
- package/src/kit/api/project-open.ts +355 -0
- package/src/kit/api/project-source.ts +180 -0
- package/src/kit/api/project-state.ts +110 -0
- package/src/kit/api/relay.ts +270 -0
- package/src/kit/api/themes.ts +45 -0
- package/src/kit/api-asset-library-wire.ts +45 -0
- package/src/kit/api-base.ts +10 -0
- package/src/kit/api-build.ts +99 -0
- package/src/kit/api-git-wire.ts +56 -0
- package/src/kit/api-logs.ts +92 -0
- package/src/kit/api-project-identity.ts +74 -0
- package/src/kit/api-settings.ts +36 -0
- package/src/kit/api-worktrees.ts +205 -0
- package/src/kit/asset-capabilities.ts +344 -0
- package/src/kit/asset-compare-core.ts +171 -0
- package/src/kit/asset-editor-context.tsx +101 -0
- package/src/kit/asset-events.ts +96 -0
- package/src/kit/asset-inspector-actions.ts +87 -0
- package/src/kit/asset-selection-viewer-registry.ts +113 -0
- package/src/kit/asset-selection.ts +146 -0
- package/src/kit/asset-thumbnails.ts +25 -0
- package/src/kit/asset-viewers.ts +115 -0
- package/src/kit/asset-workflow/asset-import-jobs.ts +106 -0
- package/src/kit/asset-workflow/asset-ledger-backend.ts +126 -0
- package/src/kit/asset-workflow/asset-ledger.ts +156 -0
- package/src/kit/asset-workflow/asset-materialization-report.ts +140 -0
- package/src/kit/asset-workflow/asset-pack-manifest.ts +320 -0
- package/src/kit/asset-workflow/asset-types.ts +142 -0
- package/src/kit/asset-workflow/audio-preview-player.ts +193 -0
- package/src/kit/asset-workflow/audio-waveform.ts +22 -0
- package/src/kit/asset-workflow/cloud-asset-client.ts +263 -0
- package/src/kit/asset-workflow/hosted-asset-materialization.ts +236 -0
- package/src/kit/asset-workflow/image-view-scale.ts +31 -0
- package/src/kit/asset-workflow/import-contract.ts +124 -0
- package/src/kit/asset-workflow/ledger-write-lock.ts +244 -0
- package/src/kit/asset-workflow/pixi-spritesheet.ts +197 -0
- package/src/kit/asset-workflow/preview-resource-lifetime.ts +44 -0
- package/src/kit/asset-workflow/project-asset-commands.ts +20 -0
- package/src/kit/asset-workflow/project-content.ts +288 -0
- package/src/kit/asset-workflow/project-source-index.ts +545 -0
- package/src/kit/asset-workflow/thumbnail-system.ts +256 -0
- package/src/kit/authoring/active-adapter.ts +200 -0
- package/src/kit/authoring/active-systems.ts +422 -0
- package/src/kit/authoring/adapter-key.ts +18 -0
- package/src/kit/authoring/authoring-asset-url.ts +27 -0
- package/src/kit/authoring/bootstrap-state.ts +49 -0
- package/src/kit/authoring/boundary-authoring-adapter.ts +189 -0
- package/src/kit/authoring/canvas-scene-guides.ts +84 -0
- package/src/kit/authoring/composite-authoring-adapter.ts +2109 -0
- package/src/kit/authoring/consumer-actions.ts +531 -0
- package/src/kit/authoring/design-time-layers.ts +852 -0
- package/src/kit/authoring/design-time-mount-registry.ts +244 -0
- package/src/kit/authoring/edit-mode-authoring.ts +637 -0
- package/src/kit/authoring/empty-project-authoring.ts +22 -0
- package/src/kit/authoring/instance-source-menu.ts +135 -0
- package/src/kit/authoring/layered-pick.ts +185 -0
- package/src/kit/authoring/mounted-root-subjects.ts +146 -0
- package/src/kit/authoring/no-authoring-adapter.ts +59 -0
- package/src/kit/authoring/object3d-document-persistence.ts +122 -0
- package/src/kit/authoring/panel-authoring.ts +121 -0
- package/src/kit/authoring/project-authoring-session.ts +105 -0
- package/src/kit/authoring/provenance.ts +99 -0
- package/src/kit/authoring/react-canvas-navigation.ts +259 -0
- package/src/kit/authoring/react-design-canvas-style.ts +20 -0
- package/src/kit/authoring/react-story-board.ts +917 -0
- package/src/kit/authoring/selection-scope.ts +195 -0
- package/src/kit/authoring/shell-document-ops.ts +169 -0
- package/src/kit/authoring/story-board-chrome-fit.ts +107 -0
- package/src/kit/authoring/story-board-presentation.ts +111 -0
- package/src/kit/authoring/three-root.ts +67 -0
- package/src/kit/authoring/viewport-tool-context.ts +73 -0
- package/src/kit/authoring/viewport-tool-owner.ts +38 -0
- package/src/kit/authoring/world-session-state.ts +101 -0
- package/src/kit/authoring-seam-evidence.ts +300 -0
- package/src/kit/availability-tick.ts +66 -0
- package/src/kit/bitmap-label.ts +120 -0
- package/src/kit/boot-routing.ts +392 -0
- package/src/kit/breakpoint-state.ts +43 -0
- package/src/kit/build-identity.ts +16 -0
- package/src/kit/bytes-codec.ts +62 -0
- package/src/kit/cancellation-reason.ts +58 -0
- package/src/kit/canvas-frames.ts +88 -0
- package/src/kit/capture-camera-pose.ts +77 -0
- package/src/kit/capture-size.ts +88 -0
- package/src/kit/chrome-registry.ts +159 -0
- package/src/kit/chrome-slot-registry.ts +91 -0
- package/src/kit/collaboration-client.ts +264 -0
- package/src/kit/collaboration-presence.ts +41 -0
- package/src/kit/command-dispatch.ts +19 -0
- package/src/kit/command-listener.ts +2182 -0
- package/src/kit/command-registry.ts +71 -0
- package/src/kit/component-board-registry.ts +205 -0
- package/src/kit/component-states-registry.ts +199 -0
- package/src/kit/components/AlignToolbar.tsx +204 -0
- package/src/kit/components/ApplicationMenus.tsx +372 -0
- package/src/kit/components/AssetEditorShell.tsx +216 -0
- package/src/kit/components/AssetInspectorToolSection.tsx +124 -0
- package/src/kit/components/BoardRulers.tsx +354 -0
- package/src/kit/components/CanvasAddNodeDialogs.tsx +529 -0
- package/src/kit/components/CanvasSceneViewport.tsx +1195 -0
- package/src/kit/components/ChromeSlot.tsx +20 -0
- package/src/kit/components/CodeView.tsx +470 -0
- package/src/kit/components/CompactInspectorShell.tsx +39 -0
- package/src/kit/components/ConsolePanel.tsx +273 -0
- package/src/kit/components/GameplaySessionTimeline.tsx +295 -0
- package/src/kit/components/InspectionProjection.tsx +932 -0
- package/src/kit/components/Inspector.tsx +270 -0
- package/src/kit/components/InspectorCanvasPreview.tsx +35 -0
- package/src/kit/components/InspectorFieldsSection.tsx +290 -0
- package/src/kit/components/InspectorStoriesSection.tsx +92 -0
- package/src/kit/components/InspectorToolSection.tsx +96 -0
- package/src/kit/components/InspectorTransformSection.tsx +245 -0
- package/src/kit/components/LightExplorerPanel.tsx +433 -0
- package/src/kit/components/MediaProperties.tsx +145 -0
- package/src/kit/components/ProjectHeader.tsx +328 -0
- package/src/kit/components/ReactCanvasControls.tsx +358 -0
- package/src/kit/components/RootSelectionOverlay.tsx +3688 -0
- package/src/kit/components/RootTextEditor.tsx +79 -0
- package/src/kit/components/SaveStatus.tsx +70 -0
- package/src/kit/components/SurfaceCrashBoundary.tsx +105 -0
- package/src/kit/components/SurfaceStateOverlay.tsx +24 -0
- package/src/kit/components/ToolContributionSurfaces.tsx +49 -0
- package/src/kit/components/ToolHost.tsx +380 -0
- package/src/kit/components/Toolbar.tsx +811 -0
- package/src/kit/components/TransientHint.tsx +44 -0
- package/src/kit/components/VersionControlSection.tsx +470 -0
- package/src/kit/components/ViewportOverlaysMenu.tsx +177 -0
- package/src/kit/components/VolterLogo.tsx +18 -0
- package/src/kit/components/WorktreeSwitcher.tsx +712 -0
- package/src/kit/components/account-documents.tsx +1162 -0
- package/src/kit/components/asset-documents.tsx +794 -0
- package/src/kit/components/asset-editor-persistence.ts +216 -0
- package/src/kit/components/asset-selection-section.tsx +545 -0
- package/src/kit/components/asset-thumbnails.tsx +307 -0
- package/src/kit/components/asset-viewers/AudioViewer.tsx +201 -0
- package/src/kit/components/asset-viewers/GenericJsonViewer.tsx +102 -0
- package/src/kit/components/asset-viewers/ImageViewer.tsx +300 -0
- package/src/kit/components/asset-viewers/JsonAssetDocument.tsx +98 -0
- package/src/kit/components/asset-viewers/OnlineAssetDetail.tsx +426 -0
- package/src/kit/components/asset-viewers/SourceAssetViewer.tsx +356 -0
- package/src/kit/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
- package/src/kit/components/asset-viewers/VideoViewer.tsx +101 -0
- package/src/kit/components/asset-viewers/shader-source.ts +144 -0
- package/src/kit/components/board-guides.ts +150 -0
- package/src/kit/components/canvas-scene-hotkeys.ts +37 -0
- package/src/kit/components/canvas-temporary-pivot.ts +34 -0
- package/src/kit/components/core-utilities.tsx +94 -0
- package/src/kit/components/inspector-preview-section.tsx +223 -0
- package/src/kit/components/inspector-revert-label.ts +20 -0
- package/src/kit/components/inspector-selection.ts +42 -0
- package/src/kit/components/inspector-stories-gating.ts +171 -0
- package/src/kit/components/inspector-transform-subject.ts +11 -0
- package/src/kit/components/inspector-transform.ts +88 -0
- package/src/kit/components/kind-documents.tsx +544 -0
- package/src/kit/components/primitives/DraftColorInput.tsx +74 -0
- package/src/kit/components/project-tool-documents.tsx +402 -0
- package/src/kit/components/scene-documents.tsx +221 -0
- package/src/kit/components/status-contributions.tsx +407 -0
- package/src/kit/components/tool-documents.tsx +302 -0
- package/src/kit/components/tool-schema-form.tsx +262 -0
- package/src/kit/components/use-after-paint.ts +41 -0
- package/src/kit/components/use-project-image-assets.ts +86 -0
- package/src/kit/components/workspace-history.ts +32 -0
- package/src/kit/components/world-documents.tsx +570 -0
- package/src/kit/components/world-overlay-gestures.ts +1939 -0
- package/src/kit/composite-screenshot.ts +2238 -0
- package/src/kit/content-entry-source-registry.ts +184 -0
- package/src/kit/contribution-surfaces.ts +48 -0
- package/src/kit/coverage/canvas-reveal.ts +192 -0
- package/src/kit/coverage/design-time-surfaces.ts +101 -0
- package/src/kit/coverage/ontology-invariants.ts +466 -0
- package/src/kit/coverage/session-vitals.ts +503 -0
- package/src/kit/crash-null-boundary.ts +36 -0
- package/src/kit/creation-site-edit.ts +1491 -0
- package/src/kit/creation-site-registry.ts +160 -0
- package/src/kit/delegate-harness-registry.ts +134 -0
- package/src/kit/document-areas.ts +70 -0
- package/src/kit/document-context-registry.ts +193 -0
- package/src/kit/document-open-registry.ts +200 -0
- package/src/kit/document-play-extension.ts +221 -0
- package/src/kit/document-preview-source.ts +20 -0
- package/src/kit/document-renderer-session.ts +138 -0
- package/src/kit/document-stage-sessions.ts +26 -0
- package/src/kit/document-viewports.ts +120 -0
- package/src/kit/editor-api.ts +46 -0
- package/src/kit/editor-chrome-capture.ts +136 -0
- package/src/kit/editor-commands.ts +176 -0
- package/src/kit/editor-console.ts +580 -0
- package/src/kit/editor-current-view.ts +56 -0
- package/src/kit/editor-document-probe.ts +1166 -0
- package/src/kit/editor-git-client.ts +115 -0
- package/src/kit/editor-hotkeys.ts +728 -0
- package/src/kit/editor-lease-view.ts +39 -0
- package/src/kit/editor-lease.ts +415 -0
- package/src/kit/editor-mode.ts +19 -0
- package/src/kit/editor-notifications.ts +140 -0
- package/src/kit/editor-presence.ts +563 -0
- package/src/kit/editor-presentation-activity.ts +58 -0
- package/src/kit/editor-presentation-notice.ts +42 -0
- package/src/kit/editor-runtime.tsx +147 -0
- package/src/kit/editor-server-response.ts +86 -0
- package/src/kit/editor-session-attribution.ts +85 -0
- package/src/kit/editor-session-mode.ts +54 -0
- package/src/kit/editor-state-facets.ts +74 -0
- package/src/kit/editor-view-presentation.ts +777 -0
- package/src/kit/environment-images.ts +58 -0
- package/src/kit/eyedropper-session.ts +60 -0
- package/src/kit/files/file-provider.ts +62 -0
- package/src/kit/files/project-files.ts +270 -0
- package/src/kit/finders/index.ts +137 -0
- package/src/kit/finders/scenes-from-entrypoint-selection.ts +387 -0
- package/src/kit/frame/frame-parts.ts +30 -0
- package/src/kit/framed-document-capture.ts +34 -0
- package/src/kit/game-globals-prelude.ts +143 -0
- package/src/kit/game-surface-defaults.ts +33 -0
- package/src/kit/gameplay-dom-recording.ts +318 -0
- package/src/kit/gameplay-export-state.ts +14 -0
- package/src/kit/gameplay-replay.ts +417 -0
- package/src/kit/gameplay-session-time.ts +9 -0
- package/src/kit/gameplay-sessions.ts +204 -0
- package/src/kit/hierarchy-component-marks.ts +298 -0
- package/src/kit/hierarchy-internals.ts +197 -0
- package/src/kit/hierarchy-kind-icon.ts +217 -0
- package/src/kit/hierarchy-menu-registry.ts +67 -0
- package/src/kit/hierarchy-node-rows.ts +307 -0
- package/src/kit/hierarchy-panel-view.ts +280 -0
- package/src/kit/hierarchy-projection.ts +76 -0
- package/src/kit/hierarchy-row-media.ts +45 -0
- package/src/kit/hierarchy-row-model.ts +308 -0
- package/src/kit/hierarchy-rows.ts +11 -0
- package/src/kit/hierarchy-walk.ts +86 -0
- package/src/kit/history/editor-session.ts +25 -0
- package/src/kit/history/history-commands.ts +147 -0
- package/src/kit/history/history-delegate.ts +187 -0
- package/src/kit/history/history-limit-notices.ts +43 -0
- package/src/kit/history/history-service.ts +1189 -0
- package/src/kit/history/persistence-coordinator.ts +35 -0
- package/src/kit/history/project-file-history.ts +386 -0
- package/src/kit/history/project-root-history-backends.ts +139 -0
- package/src/kit/history/resource-registry.ts +209 -0
- package/src/kit/history/snapshot-store.ts +103 -0
- package/src/kit/history/source-history-backend.ts +546 -0
- package/src/kit/history-types.ts +124 -0
- package/src/kit/hmr-registration-group.ts +67 -0
- package/src/kit/hmr-stable-react-context.ts +23 -0
- package/src/kit/hotkeys.ts +190 -0
- package/src/kit/inference-diagnostics.ts +69 -0
- package/src/kit/initial-project.ts +80 -0
- package/src/kit/inspection/active-subject.ts +571 -0
- package/src/kit/inspection/active-surface.ts +142 -0
- package/src/kit/inspection/compose-subject.ts +1055 -0
- package/src/kit/inspection/compose.ts +7 -0
- package/src/kit/inspection/display.ts +171 -0
- package/src/kit/inspection/document-subject.ts +109 -0
- package/src/kit/inspection/game-subject.ts +85 -0
- package/src/kit/inspection/null-subject.ts +119 -0
- package/src/kit/inspection/serialize.ts +357 -0
- package/src/kit/inspection/use-active-inspection.ts +180 -0
- package/src/kit/inspection-model.ts +542 -0
- package/src/kit/inspection-node-media.ts +58 -0
- package/src/kit/inspector-presentation.ts +203 -0
- package/src/kit/inspector-property-grouping.ts +64 -0
- package/src/kit/inspector-section-registry.ts +221 -0
- package/src/kit/instance-source-actions.ts +163 -0
- package/src/kit/js-heap.ts +71 -0
- package/src/kit/key-actions.ts +91 -0
- package/src/kit/keymap-presets.ts +428 -0
- package/src/kit/layout-policy.ts +31 -0
- package/src/kit/light-explorer-model.ts +134 -0
- package/src/kit/live-canvas-frame.ts +55 -0
- package/src/kit/live-document.ts +296 -0
- package/src/kit/live-gesture-lock.ts +50 -0
- package/src/kit/live-seam-evidence.ts +11 -0
- package/src/kit/live-session-registry.ts +220 -0
- package/src/kit/live-transition.ts +391 -0
- package/src/kit/manifest-project.ts +107 -0
- package/src/kit/module-fetch-diagnosis.ts +192 -0
- package/src/kit/mount-failure-report.ts +154 -0
- package/src/kit/native-selection-style.ts +497 -0
- package/src/kit/object3d-document-write-policy.ts +137 -0
- package/src/kit/packaged-runtime.ts +108 -0
- package/src/kit/palettes/maya.palette.json +57 -0
- package/src/kit/palettes/substance.palette.json +57 -0
- package/src/kit/performance-profiler.ts +367 -0
- package/src/kit/performance-sources.ts +69 -0
- package/src/kit/photograph-notice.ts +141 -0
- package/src/kit/play-boot-phase.ts +166 -0
- package/src/kit/play-camera-flight.ts +35 -0
- package/src/kit/png-encode.worker.ts +26 -0
- package/src/kit/presentation-surface.ts +248 -0
- package/src/kit/product-command.ts +90 -0
- package/src/kit/project-adapter.ts +1140 -0
- package/src/kit/project-asset-refresh.ts +23 -0
- package/src/kit/project-asset-roots.ts +68 -0
- package/src/kit/project-local-state.ts +151 -0
- package/src/kit/project-manager.ts +243 -0
- package/src/kit/project-module-changes.ts +201 -0
- package/src/kit/project-module-split.ts +270 -0
- package/src/kit/project-play-layers.ts +25 -0
- package/src/kit/project-provenance.ts +115 -0
- package/src/kit/project-ready.ts +42 -0
- package/src/kit/project-shape.ts +68 -0
- package/src/kit/project-tools.ts +107 -0
- package/src/kit/projection-types.ts +44 -0
- package/src/kit/readiness.ts +113 -0
- package/src/kit/renderer-resource-counts.ts +27 -0
- package/src/kit/reported-play-state.ts +90 -0
- package/src/kit/resolve-contributed-command.ts +14 -0
- package/src/kit/resolve-relative-specifier.ts +33 -0
- package/src/kit/retained-document-states.ts +91 -0
- package/src/kit/scene-document-plan.ts +320 -0
- package/src/kit/scene-live-open.ts +210 -0
- package/src/kit/scoped-game-css.ts +152 -0
- package/src/kit/served-url.ts +5 -0
- package/src/kit/session-close.ts +17 -0
- package/src/kit/session-tombstone.ts +127 -0
- package/src/kit/settings/settings-provider.ts +82 -0
- package/src/kit/settings-store.ts +348 -0
- package/src/kit/shell-document-state.ts +27 -0
- package/src/kit/shell-store-door.ts +45 -0
- package/src/kit/shell-store.ts +722 -0
- package/src/kit/source-conflict.ts +122 -0
- package/src/kit/stage-context.ts +377 -0
- package/src/kit/stage-invalidation.ts +25 -0
- package/src/kit/stage-store-registry.ts +69 -0
- package/src/kit/startup-failure.ts +80 -0
- package/src/kit/state-report-deferral.ts +73 -0
- package/src/kit/storage/host-files-storage.ts +97 -0
- package/src/kit/storage/http-storage.ts +174 -0
- package/src/kit/storage/index.ts +75 -0
- package/src/kit/storage/mem-storage.ts +158 -0
- package/src/kit/storage/path-lock.ts +44 -0
- package/src/kit/storage/paths.ts +26 -0
- package/src/kit/storage-types.ts +127 -0
- package/src/kit/stories/StoryPreviewMount.tsx +306 -0
- package/src/kit/stories/compose-project-stories.ts +255 -0
- package/src/kit/stories/prefabs-finder.ts +54 -0
- package/src/kit/stories/prefabs-from-stories.ts +182 -0
- package/src/kit/stories/project-story-regions.ts +24 -0
- package/src/kit/stories/story-capture.ts +579 -0
- package/src/kit/stories/story-declared-medium.ts +126 -0
- package/src/kit/stories/story-discovery.ts +176 -0
- package/src/kit/stories/story-dom-runtime.ts +78 -0
- package/src/kit/stories/story-grouping.ts +111 -0
- package/src/kit/stories/story-mount-turn.ts +27 -0
- package/src/kit/stories/story-presentation.ts +215 -0
- package/src/kit/stories/story-preview-component.ts +7 -0
- package/src/kit/stories/story-registry.ts +530 -0
- package/src/kit/stories-scope.ts +35 -0
- package/src/kit/story-document-openers.ts +36 -0
- package/src/kit/story-thumbnails.ts +47 -0
- package/src/kit/surface-keyboard.ts +101 -0
- package/src/kit/surface-state.ts +135 -0
- package/src/kit/system-seam-evidence.ts +72 -0
- package/src/kit/tab-census.ts +202 -0
- package/src/kit/tab-lifecycle-client.ts +227 -0
- package/src/kit/theme-library.ts +897 -0
- package/src/kit/theme-preference.ts +429 -0
- package/src/kit/three-viewport-presentation.ts +23 -0
- package/src/kit/tool-contribution-play.ts +74 -0
- package/src/kit/tool-loader.ts +1918 -0
- package/src/kit/transform-mode-request.ts +66 -0
- package/src/kit/transient-hint.ts +78 -0
- package/src/kit/transport-strip.tsx +174 -0
- package/src/kit/ui-source/adapter-region-includes.ts +238 -0
- package/src/kit/ui-source/file-region-resolver.ts +302 -0
- package/src/kit/ui-source/inspect.ts +775 -0
- package/src/kit/ui-source/source-write-backend.ts +605 -0
- package/src/kit/ui-source/tier-source-write-backend.ts +279 -0
- package/src/kit/user-local-state.ts +105 -0
- package/src/kit/viewport-activation-timings.ts +840 -0
- package/src/kit/viewport-editor-controls.ts +22 -0
- package/src/kit/viewport-presentation.ts +668 -0
- package/src/kit/viewport-surface-status.tsx +55 -0
- package/src/kit/wait-until.ts +37 -0
- package/src/kit/worker-call-metrics.ts +166 -0
- package/src/kit/workspace-areas.ts +191 -0
- package/src/kit/workspace-aux-commands.ts +11 -0
- package/src/kit/workspace-available-documents.ts +142 -0
- package/src/kit/workspace-core-utilities.ts +31 -0
- package/src/kit/workspace-document-ids.ts +59 -0
- package/src/kit/workspace-document-registry.ts +624 -0
- package/src/kit/workspace-document-restore.ts +146 -0
- package/src/kit/workspace-host-commands.ts +141 -0
- package/src/kit/workspace-persistence-gate.ts +40 -0
- package/src/kit/workspace-play-utilities.ts +44 -0
- package/src/kit/workspace-presets.ts +446 -0
- package/src/kit/workspace-regions.ts +276 -0
- package/src/kit/workspace-static-panels.ts +73 -0
- package/src/kit/workspace-status-registry.ts +121 -0
- package/src/kit/workspace-storage.ts +35 -0
- package/src/kit/workspace-style.ts +226 -0
- package/src/kit/workspace-utility-commands.ts +74 -0
- package/src/kit/workspace-utility-registry.ts +263 -0
- package/src/kit/world-adoption-event.ts +23 -0
- package/src/kit/world-adoption.ts +115 -0
- package/src/kit/world-canvas-viewport-state.ts +35 -0
- package/src/kit/world-document-routing.ts +104 -0
- package/src/kit/world-pan-state.ts +198 -0
- package/src/kit/write-pipe.ts +173 -0
- package/src/layout-arrangements.ts +5 -0
- package/src/layouts.tsx +108 -0
- package/src/looks.ts +16 -0
- package/src/project/output-roots.ts +73 -0
- package/src/project/tab-census.ts +155 -0
- package/src/project-tool-catalog.ts +104 -0
- package/src/selection.tsx +107 -0
- package/src/services.ts +18 -0
- package/src/session/build-report.ts +22 -0
- package/src/session/collaboration-types.ts +262 -0
- package/src/session/command-table.ts +327 -0
- package/src/session/discovery.ts +100 -0
- package/src/session/editor-brand.ts +48 -0
- package/src/session/editor-compatibility.ts +317 -0
- package/src/session/editor-control-lifecycle.ts +68 -0
- package/src/session/editor-control-protocol.ts +5 -0
- package/src/session/entrypoint-selection-readers.ts +66 -0
- package/src/session/entrypoint-selection-source.ts +120 -0
- package/src/session/game-css-scope.ts +30 -0
- package/src/session/hosted-attachment.ts +225 -0
- package/src/session/limited-view.ts +82 -0
- package/src/session/product-create.ts +24 -0
- package/src/session/product-locator.ts +478 -0
- package/src/session/project-module-url.ts +242 -0
- package/src/session/project-serving.ts +164 -0
- package/src/session/project-upgrade.ts +403 -0
- package/src/session/registry-format.ts +210 -0
- package/src/session/relative-path-guard.ts +56 -0
- package/src/session/scoped-game-css.ts +461 -0
- package/src/session/source-glob.ts +15 -0
- package/src/session/tool-contribution-convention.ts +123 -0
- package/src/session/workbench-locator.ts +712 -0
- package/src/session.ts +41 -0
- package/src/share.ts +160 -0
- package/src/source-analysis.ts +28 -0
- package/src/source-authoring.ts +439 -0
- package/src/tools/errors.ts +91 -0
- package/src/tools/provider-execution.ts +70 -0
- package/src/tools/registry.ts +341 -0
- package/src/tools/types.ts +159 -0
- package/src/transport.ts +100 -0
- package/src/types.ts +1693 -0
- package/src/views.ts +164 -0
- package/src/widgets/design-system.ts +93 -0
- package/src/widgets/editor-appearance.ts +151 -0
- package/src/widgets/editor-material.ts +83 -0
- package/src/widgets/icon-set-registry.ts +105 -0
- package/src/widgets/index.ts +71 -0
- package/src/widgets/inspector-widgets/AlignmentGrid.tsx +182 -0
- package/src/widgets/inspector-widgets/AssetSlotPicker.tsx +123 -0
- package/src/widgets/inspector-widgets/BorderEditor.tsx +309 -0
- package/src/widgets/inspector-widgets/ColorPicker.tsx +549 -0
- package/src/widgets/inspector-widgets/CurveEditor.tsx +359 -0
- package/src/widgets/inspector-widgets/FilterEditor.tsx +108 -0
- package/src/widgets/inspector-widgets/FontPicker.tsx +191 -0
- package/src/widgets/inspector-widgets/GradientEditor.tsx +623 -0
- package/src/widgets/inspector-widgets/ScrubbableInput.tsx +180 -0
- package/src/widgets/inspector-widgets/ShadowEditor.tsx +319 -0
- package/src/widgets/inspector-widgets/color-utils.ts +201 -0
- package/src/widgets/inspector-widgets/curve-utils.ts +212 -0
- package/src/widgets/inspector-widgets/index.ts +25 -0
- package/src/widgets/inspector-widgets/shared.tsx +140 -0
- package/src/widgets/interactive-edit-scope.ts +33 -0
- package/src/widgets/patterns/Dialog.tsx +140 -0
- package/src/widgets/patterns/Fields.tsx +44 -0
- package/src/widgets/patterns/List.tsx +25 -0
- package/src/widgets/patterns/StateSurface.tsx +40 -0
- package/src/widgets/patterns/Surfaces.tsx +122 -0
- package/src/widgets/patterns/Tabs.tsx +80 -0
- package/src/widgets/patterns/Toolbar.tsx +72 -0
- package/src/widgets/patterns/Tree.tsx +72 -0
- package/src/widgets/primitives/AnchoredMenu.tsx +260 -0
- package/src/widgets/primitives/Button.tsx +62 -0
- package/src/widgets/primitives/ColorInput.tsx +78 -0
- package/src/widgets/primitives/DraftTextInput.tsx +63 -0
- package/src/widgets/primitives/EditorIcon.tsx +157 -0
- package/src/widgets/primitives/FormControls.tsx +88 -0
- package/src/widgets/primitives/HoverPreview.tsx +96 -0
- package/src/widgets/primitives/JsonInput.tsx +113 -0
- package/src/widgets/primitives/Layout.tsx +100 -0
- package/src/widgets/primitives/Menu.tsx +161 -0
- package/src/widgets/primitives/NumberInput.tsx +169 -0
- package/src/widgets/primitives/Panel.tsx +80 -0
- package/src/widgets/primitives/SectionHeader.tsx +77 -0
- package/src/widgets/primitives/Text.tsx +54 -0
- package/src/widgets/primitives/ThemeRootPortal.tsx +52 -0
- package/src/widgets/primitives/Tooltip.tsx +204 -0
- package/src/widgets/primitives/Vec3Input.tsx +70 -0
- package/src/widgets/primitives/banner-tones.ts +32 -0
- package/src/widgets/primitives/clamp-to-viewport.ts +44 -0
- package/src/widgets/primitives/editor-icons.ts +254 -0
- package/src/widgets/primitives/panel-header-styles.ts +42 -0
- package/src/widgets/theme.ts +2841 -0
- package/src/widgets/z-index.ts +25 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A DOCUMENT KIND OWNS HOW IT OPENS — the forward half of the seam whose
|
|
3
|
+
* backward half is `workspace-document-restore.ts` (docs/WORKBENCH.md §host
|
|
4
|
+
* versus package).
|
|
5
|
+
*
|
|
6
|
+
* THE RULE. The host ADDRESSES a document (a story on a module, an asset at a
|
|
7
|
+
* path); it does not construct one. A module that can open a kind registers an
|
|
8
|
+
* opener under a named id, and every host call site — the palette, the
|
|
9
|
+
* hierarchy's double-click, the Edit tab row, the layout restore, the view
|
|
10
|
+
* protocol, the SDK's `host.workspace` door — asks for that id instead of
|
|
11
|
+
* importing the document module. When nothing has registered the id (a build
|
|
12
|
+
* whose package list does not carry that kind, a contribution that has not
|
|
13
|
+
* loaded yet) the answer is `null`, and the caller does what it already did
|
|
14
|
+
* for a document it could not open.
|
|
15
|
+
*
|
|
16
|
+
* WHY IT EXISTS. `workspace-document-restore.ts` fixed the PERSISTENCE half:
|
|
17
|
+
* the host no longer names a document module to reopen one. The opening half
|
|
18
|
+
* was still `import { openThreeStoryDocument } from './components/…'` in ten
|
|
19
|
+
* host files, which is the same serialization defect one rung earlier — a
|
|
20
|
+
* document cannot leave for a package while the shell calls its constructor by
|
|
21
|
+
* name. Measured 2026-09-18 (WORK.md §The open-source launch, phase 1 unit 4).
|
|
22
|
+
*
|
|
23
|
+
* WHAT AN ID IS. A string in the host's own vocabulary, declared beside the
|
|
24
|
+
* kind's other host-side contracts (`stories/story-document-openers.ts` is the
|
|
25
|
+
* first), with a request type declared in the SAME place so both sides of the
|
|
26
|
+
* seam are typed against one declaration rather than against each other.
|
|
27
|
+
* Several modules may register one id; they are tried in registration order
|
|
28
|
+
* until one returns a document id.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import type { WorkspaceStateStore } from './workspace-document-restore';
|
|
32
|
+
|
|
33
|
+
export interface DocumentOpener<Request> {
|
|
34
|
+
/** The opener id — the address vocabulary, not a module name. */
|
|
35
|
+
readonly id: string;
|
|
36
|
+
/** Which module registered it. Re-registering the same owner+id REPLACES,
|
|
37
|
+
* so an HMR re-evaluation leaves one opener, not two. */
|
|
38
|
+
readonly owner: string;
|
|
39
|
+
/**
|
|
40
|
+
* Open (or activate) the document this request addresses, and answer its
|
|
41
|
+
* document id. `null` = this opener cannot serve THIS request (an
|
|
42
|
+
* undeclared medium, a story that is no longer exported); the next
|
|
43
|
+
* registered opener is tried.
|
|
44
|
+
*
|
|
45
|
+
* THROWING is the third answer, and it is different from `null`: "this
|
|
46
|
+
* address is MINE and it is broken" — a table that lists no such entry, a
|
|
47
|
+
* contribution whose module threw on import. The throw reaches the caller
|
|
48
|
+
* with the kind's own sentence instead of the host's generic "nothing can
|
|
49
|
+
* open this", which is the only way a reader learns which of the two
|
|
50
|
+
* happened. Only an opener that OWNS the id may throw; one of several
|
|
51
|
+
* openers sharing an id answers `null` so its siblings still get their turn.
|
|
52
|
+
*/
|
|
53
|
+
readonly open: (store: WorkspaceStateStore, request: Request) => string | null;
|
|
54
|
+
/**
|
|
55
|
+
* The kind's own async settling step, awaited by
|
|
56
|
+
* {@link openRegisteredDocumentAsync} ONLY after a first synchronous attempt
|
|
57
|
+
* answered `null` — refresh the ledger this kind opens documents out of, then
|
|
58
|
+
* the attempt is made once more.
|
|
59
|
+
*
|
|
60
|
+
* It mirrors `WorkspaceDocumentRestorer.prepare` deliberately: a kind is the
|
|
61
|
+
* only thing that knows what "I might be able to open this once I have looked
|
|
62
|
+
* again" means, and the host must not hold that knowledge to address a
|
|
63
|
+
* document. Absent means one attempt is the whole answer.
|
|
64
|
+
*
|
|
65
|
+
* IT RECEIVES THE REQUEST, because settling is per-address: waiting for THIS
|
|
66
|
+
* table entry, loading THIS module, refreshing the contribution that would
|
|
67
|
+
* carry THIS id. `stories/story-opener.ts:92` is the evidence —
|
|
68
|
+
* it keeps two module-level `unsettled*` sets whose only job is to carry the
|
|
69
|
+
* failed request across to a settle that could not see it. (Existing openers
|
|
70
|
+
* that ignore the argument are unaffected; the dedupe below is by function
|
|
71
|
+
* identity, so one settle still runs once per attempt.) Like `open`, it may
|
|
72
|
+
* THROW to refuse the address with the kind's own sentence.
|
|
73
|
+
*/
|
|
74
|
+
readonly settle?: (request: Request) => Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* The kind's own POST-open readiness — `settle`'s mirror on the other side of
|
|
77
|
+
* the answer, awaited by {@link openRegisteredDocumentAsync} once an opener
|
|
78
|
+
* has produced a document id, before the caller is told the view is present.
|
|
79
|
+
*
|
|
80
|
+
* It exists because "opened" and "ready to be driven" are different instants
|
|
81
|
+
* for some kinds and the host cannot know which: an asset document answers
|
|
82
|
+
* its id the moment the tab is registered, while an immediate
|
|
83
|
+
* inspect/setField against it needs the Inspector mounted and (for a model)
|
|
84
|
+
* its live adapter installed — `waitForAssetDocumentInspector`, which the
|
|
85
|
+
* presenter used to await by hand because it knew the asset family's rule.
|
|
86
|
+
* Absent means the id IS the whole answer. May THROW to refuse.
|
|
87
|
+
*
|
|
88
|
+
* A synchronous caller ({@link openRegisteredDocument}) cannot await it, the
|
|
89
|
+
* same way it cannot settle — it gets the id and the kind's own doors are
|
|
90
|
+
* what it waits on.
|
|
91
|
+
*/
|
|
92
|
+
readonly ready?: (documentId: string, request: Request) => Promise<void>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// The registry is heterogeneous by construction — one id, one request type,
|
|
96
|
+
// checked at both ends by the shared declaration the id comes from.
|
|
97
|
+
// biome-ignore lint/suspicious/noExplicitAny: the map is keyed by id, not by type.
|
|
98
|
+
const _openers = new Map<string, DocumentOpener<any>[]>();
|
|
99
|
+
|
|
100
|
+
/** Install an opener. Returns the teardown. */
|
|
101
|
+
export function registerDocumentOpener<Request>(opener: DocumentOpener<Request>): () => void {
|
|
102
|
+
const existing = _openers.get(opener.id) ?? [];
|
|
103
|
+
const next = existing.filter((item) => item.owner !== opener.owner);
|
|
104
|
+
next.push(opener);
|
|
105
|
+
_openers.set(opener.id, next);
|
|
106
|
+
return () => {
|
|
107
|
+
const current = _openers.get(opener.id);
|
|
108
|
+
if (!current) return;
|
|
109
|
+
const remaining = current.filter((item) => item !== opener);
|
|
110
|
+
if (remaining.length === 0) _openers.delete(opener.id);
|
|
111
|
+
else _openers.set(opener.id, remaining);
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Whether anything can open this id in THIS session — what a palette asks
|
|
116
|
+
* before offering an action that would otherwise do nothing. */
|
|
117
|
+
export function hasDocumentOpener(id: string): boolean {
|
|
118
|
+
return (_openers.get(id)?.length ?? 0) > 0;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Every address this session can open, sorted. The generic answer to "what
|
|
123
|
+
* DOES this editor open?", which is what a refusal owes its reader: a build
|
|
124
|
+
* whose package list carries no opener for the kind is a configuration fact,
|
|
125
|
+
* and naming the addresses that ARE registered is the difference between
|
|
126
|
+
* "this is broken" and "this editor is not that editor".
|
|
127
|
+
*/
|
|
128
|
+
export function registeredDocumentOpenerIds(): readonly string[] {
|
|
129
|
+
return [..._openers.keys()].sort();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Open the document this request addresses, through whichever registered
|
|
134
|
+
* opener claims it. `null` = nothing here can open it, which is the same
|
|
135
|
+
* answer the host already gives for a story with no declared medium.
|
|
136
|
+
*/
|
|
137
|
+
export function openRegisteredDocument<Request>(
|
|
138
|
+
id: string,
|
|
139
|
+
store: WorkspaceStateStore,
|
|
140
|
+
request: Request,
|
|
141
|
+
): string | null {
|
|
142
|
+
for (const opener of _openers.get(id) ?? []) {
|
|
143
|
+
const opened = opener.open(store, request);
|
|
144
|
+
if (opened !== null) return opened;
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* The same question, asked where the caller can wait: try the registered
|
|
151
|
+
* openers once; if none claimed the request, let each kind SETTLE (refresh the
|
|
152
|
+
* ledger it opens out of) and try once more. Used by the VIEW PROTOCOL, which
|
|
153
|
+
* is already async and is the one caller that addresses a document by a name a
|
|
154
|
+
* person or an agent typed — the subject may simply not have been fetched yet.
|
|
155
|
+
*/
|
|
156
|
+
export async function openRegisteredDocumentAsync<Request>(
|
|
157
|
+
id: string,
|
|
158
|
+
store: WorkspaceStateStore,
|
|
159
|
+
request: Request,
|
|
160
|
+
): Promise<string | null> {
|
|
161
|
+
const openers = _openers.get(id) ?? [];
|
|
162
|
+
const direct = claim(openers, store, request);
|
|
163
|
+
if (direct) return settleReady(direct, request);
|
|
164
|
+
if (openers.length === 0) return null;
|
|
165
|
+
const settled = new Set<(request: Request) => Promise<void>>();
|
|
166
|
+
for (const opener of openers) if (opener.settle) settled.add(opener.settle);
|
|
167
|
+
for (const settle of settled) await settle(request);
|
|
168
|
+
if (settled.size === 0) return null;
|
|
169
|
+
const retried = claim(openers, store, request);
|
|
170
|
+
return retried === null ? null : settleReady(retried, request);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** The first opener that answers a document id, and WHICH one — the async door
|
|
174
|
+
* needs the identity because `ready` belongs to the opener that claimed, not
|
|
175
|
+
* to every opener sharing the address. */
|
|
176
|
+
function claim<Request>(
|
|
177
|
+
// biome-ignore lint/suspicious/noExplicitAny: the map is keyed by id, not by type.
|
|
178
|
+
openers: readonly DocumentOpener<any>[],
|
|
179
|
+
store: WorkspaceStateStore,
|
|
180
|
+
request: Request,
|
|
181
|
+
): { opener: DocumentOpener<Request>; documentId: string } | null {
|
|
182
|
+
for (const opener of openers) {
|
|
183
|
+
const documentId = opener.open(store, request);
|
|
184
|
+
if (documentId !== null) return { opener, documentId };
|
|
185
|
+
}
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async function settleReady<Request>(
|
|
190
|
+
claimed: { opener: DocumentOpener<Request>; documentId: string },
|
|
191
|
+
request: Request,
|
|
192
|
+
): Promise<string> {
|
|
193
|
+
await claimed.opener.ready?.(claimed.documentId, request);
|
|
194
|
+
return claimed.documentId;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Test-only reset (mirrors the restore registry's own). */
|
|
198
|
+
export function __resetDocumentOpenersForTest(): void {
|
|
199
|
+
_openers.clear();
|
|
200
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/** Optional document capability. A tool owns its controls, state and runner;
|
|
2
|
+
* a document kind owns the detached stage it lends that runner. Products name
|
|
3
|
+
* neither side. The page-wide registry joins packaged and served contributions. */
|
|
4
|
+
import type { ComponentType } from 'react';
|
|
5
|
+
import type { ModelPlayLogEntry } from '../types';
|
|
6
|
+
|
|
7
|
+
export interface DocumentPlayControlProps {
|
|
8
|
+
readonly documentId: string | undefined;
|
|
9
|
+
readonly onClose: () => void;
|
|
10
|
+
}
|
|
11
|
+
export interface DocumentPlayStage {
|
|
12
|
+
readonly documentId: string;
|
|
13
|
+
readonly sourcePath: string;
|
|
14
|
+
readonly root: unknown;
|
|
15
|
+
readonly camera: () => unknown;
|
|
16
|
+
/** The editing area's current draw camera, before handing its view to Play. */
|
|
17
|
+
readonly editingCamera: () => unknown;
|
|
18
|
+
readonly onFrame: (fn: (seconds: number) => void) => () => void;
|
|
19
|
+
readonly report: (title: string, detail: string) => void;
|
|
20
|
+
readonly container: HTMLElement;
|
|
21
|
+
/** The runner has updated its first drawable frame. */
|
|
22
|
+
readonly ready: () => void;
|
|
23
|
+
/** The return camera is approaching the editing pose; fade authoring chrome back in. */
|
|
24
|
+
readonly returning: () => void;
|
|
25
|
+
/** A copy of one of `root`'s materials that one object can wear alone and a runner can
|
|
26
|
+
* recolour, keeping the document's own draw hooks; null for a material that is not the
|
|
27
|
+
* document's. Absent, a runner clones. */
|
|
28
|
+
readonly ownMaterial?: (material: unknown) => unknown;
|
|
29
|
+
/** The copy's characters' clips, bound to `root` (the document's skins and actions), which the
|
|
30
|
+
* runner advances on the game's clock. Absent, the document lends no animation and rigged
|
|
31
|
+
* objects stand in their exported pose. */
|
|
32
|
+
readonly animation?: DocumentPlayAnimation;
|
|
33
|
+
}
|
|
34
|
+
export type DocumentPlayAnswer = { ok: true; armature: string } | { ok: false; why: string };
|
|
35
|
+
|
|
36
|
+
export interface DocumentPlayActionOptions {
|
|
37
|
+
readonly fade?: number;
|
|
38
|
+
readonly loop?: boolean;
|
|
39
|
+
readonly speed?: number;
|
|
40
|
+
readonly restart?: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface DocumentPlayTrackOptions extends DocumentPlayActionOptions {
|
|
44
|
+
readonly action?: string;
|
|
45
|
+
readonly influence?: number;
|
|
46
|
+
readonly mute?: boolean;
|
|
47
|
+
}
|
|
48
|
+
/** A document's animation, lent to a runner. Objects are the runner's own (`root`'s descendants). */
|
|
49
|
+
export interface DocumentPlayAnimation {
|
|
50
|
+
clips(object: unknown): readonly string[];
|
|
51
|
+
/** The active action (`animation_data.action`), crossfaded from the last. */
|
|
52
|
+
play(object: unknown, action: string, options?: DocumentPlayActionOptions): DocumentPlayAnswer;
|
|
53
|
+
stop(object: unknown, fade?: number): void;
|
|
54
|
+
playing(object: unknown): string | null;
|
|
55
|
+
/** An NLA track by name: an action for it, its influence, its mute; `null` gives it back. */
|
|
56
|
+
track(object: unknown, name: string, options: DocumentPlayTrackOptions | null): DocumentPlayAnswer;
|
|
57
|
+
/** A bone constraint's influence, or the object it aims at. */
|
|
58
|
+
constraint(object: unknown, bone: string, name: string, options: { influence?: number; target?: unknown }): DocumentPlayAnswer;
|
|
59
|
+
update(dt: number): void;
|
|
60
|
+
readonly warnings: readonly string[];
|
|
61
|
+
dispose(): void;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A RUNNING GAME'S CLOCK, as the Play tool keeps it. The numbers are the ones the runner handed
|
|
65
|
+
* the game, not the page's: `time` is the sum of every `dt` the script's `update` was given, so it
|
|
66
|
+
* stands still while paused and runs at `speed` times the page's own clock otherwise.
|
|
67
|
+
*/
|
|
68
|
+
export interface DocumentPlayClock {
|
|
69
|
+
/** Simulation seconds since this run began (the sum of the `dt`s the game was handed). */
|
|
70
|
+
readonly time: number;
|
|
71
|
+
/** Updates the game has run since this run began. */
|
|
72
|
+
readonly tick: number;
|
|
73
|
+
readonly paused: boolean;
|
|
74
|
+
/** Simulation seconds per real second; one of the transport's `speeds`. */
|
|
75
|
+
readonly speed: number;
|
|
76
|
+
/** While playing with no game running because the script failed to start or threw: why. The
|
|
77
|
+
* run stays playing (a save of the script retries it); a running game clears it. */
|
|
78
|
+
readonly failure?: string | null;
|
|
79
|
+
/** A game has started in this run and is running (its first update ran). False while the run
|
|
80
|
+
* is still preparing, and while it plays with a `failure`. Absent from a tool that predates
|
|
81
|
+
* it, which cannot say. A reader that must know whether Play WORKED (the CLI's `play`) waits
|
|
82
|
+
* for this or for `failure`, never for "playing" alone. */
|
|
83
|
+
readonly running?: boolean;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* THE GAME'S TRANSPORT — what a Play tool offers beyond Play and Stop, for a layout that draws a
|
|
87
|
+
* game panel (Cyclotron's Game mode, `@volter/editor-blender`). Optional: a tool without
|
|
88
|
+
* one still plays and stops, and a layout draws only the controls a tool answers.
|
|
89
|
+
*/
|
|
90
|
+
export interface DocumentPlayTransport {
|
|
91
|
+
/** The speeds `setSpeed` accepts, slowest first. */
|
|
92
|
+
readonly speeds: readonly number[];
|
|
93
|
+
clock(documentId: string): DocumentPlayClock;
|
|
94
|
+
/** The clock moves every played frame, so it has a subscription of its own: `subscribe` would
|
|
95
|
+
* re-render everything that only asks whether a document plays. */
|
|
96
|
+
subscribeClock(listener: () => void): () => void;
|
|
97
|
+
/** Hold or release the game's updates; the stage keeps drawing the frozen copy. */
|
|
98
|
+
setPaused(documentId: string, paused: boolean): void;
|
|
99
|
+
/** One update while paused, with one nominal frame's `dt`. */
|
|
100
|
+
step(documentId: string): void;
|
|
101
|
+
setSpeed(documentId: string, speed: number): void;
|
|
102
|
+
/** Begin the run again on a FRESH detached copy, the clock at zero. */
|
|
103
|
+
restart(documentId: string): void;
|
|
104
|
+
/**
|
|
105
|
+
* THE DOCUMENT COULD NOT LEND A STAGE (its rendered draw failed to prepare), so no runner
|
|
106
|
+
* ever started. The run stays playing with `failure` on the clock and a `script-error` entry
|
|
107
|
+
* (phase `stage`) in the play log, so the Game panel and `play-log` say why; Stop ends it and
|
|
108
|
+
* Restart tries again. Absent, the document stops the play and reports by notification.
|
|
109
|
+
*/
|
|
110
|
+
fail?(documentId: string, sourcePath: string, failure: string): void;
|
|
111
|
+
/** Changes on every restart. The document that lends the stage keys its detached copy on it,
|
|
112
|
+
* so a new generation is a new copy; the change is announced through `subscribe`. */
|
|
113
|
+
generation(documentId: string): number;
|
|
114
|
+
/** Whether the running game's own bot drives, and whether it offers one; a change is
|
|
115
|
+
* announced through `subscribeClock`. Absent, the tool has no autoplay. */
|
|
116
|
+
autoplay?(documentId: string): DocumentPlayAutoplay;
|
|
117
|
+
/** Switch the bot on (it must be offered, and the game playing) or off. On drives one of the
|
|
118
|
+
* bot's behaviours (`behavior`, required when it offers several) for at most `limit`
|
|
119
|
+
* simulation seconds (the tool's default when absent). */
|
|
120
|
+
setAutoplay?(documentId: string, on: boolean, by: 'panel' | 'cli', request?: DocumentPlayAutoplayRequest): void;
|
|
121
|
+
/** While stopped, ask the next start to switch the bot on as soon as its script offers one
|
|
122
|
+
* (`armed`); dropped if it offers none, or not the behaviour asked for. Absent, autoplay can
|
|
123
|
+
* only be switched while running. */
|
|
124
|
+
armAutoplay?(documentId: string, armed: boolean, request?: DocumentPlayAutoplayRequest): void;
|
|
125
|
+
}
|
|
126
|
+
export interface DocumentPlayAutoplayRequest {
|
|
127
|
+
readonly behavior?: string | null;
|
|
128
|
+
readonly limit?: number | null;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* AUTOPLAY, AS THE EDITOR OWNS IT: a game offers a bot, the editor decides whether it drives.
|
|
132
|
+
* Off whenever a run begins; a person's input in the game turns it off (`takeover`), and so does
|
|
133
|
+
* the run's limit (`limit`).
|
|
134
|
+
*/
|
|
135
|
+
export interface DocumentPlayAutoplay {
|
|
136
|
+
readonly on: boolean;
|
|
137
|
+
/** The running game registered a bot. */
|
|
138
|
+
readonly available: boolean;
|
|
139
|
+
/** Who made the last change: `script` is the game no longer offering a bot, `limit` the run's
|
|
140
|
+
* simulation seconds spent. */
|
|
141
|
+
readonly by: 'panel' | 'cli' | 'takeover' | 'script' | 'limit' | null;
|
|
142
|
+
/** Armed while stopped (`armAutoplay`): the next start turns it on once a bot is offered. */
|
|
143
|
+
readonly armed?: boolean;
|
|
144
|
+
/** The behaviours the bot offers, and the one driving (or armed). Absent from older tools. */
|
|
145
|
+
readonly behaviors?: readonly string[];
|
|
146
|
+
readonly behavior?: string | null;
|
|
147
|
+
/** This run's limit and the simulation time it began at, in simulation seconds. */
|
|
148
|
+
readonly limit?: number | null;
|
|
149
|
+
readonly since?: number | null;
|
|
150
|
+
/** A person's key or pointer reached the game in this run: with autoplay off, they drive. */
|
|
151
|
+
readonly person?: boolean;
|
|
152
|
+
/** What the bot last said it is doing. */
|
|
153
|
+
readonly state?: string | null;
|
|
154
|
+
/** Why the last arm was not taken when the game started; null otherwise. */
|
|
155
|
+
readonly refused?: string | null;
|
|
156
|
+
}
|
|
157
|
+
/** The newest entries of one document's play log, for a panel that draws it live. */
|
|
158
|
+
export interface DocumentPlayLog {
|
|
159
|
+
tail(documentId: string, last: number, kind?: string): {
|
|
160
|
+
readonly total: number;
|
|
161
|
+
readonly kinds: readonly string[];
|
|
162
|
+
readonly entries: readonly ModelPlayLogEntry[];
|
|
163
|
+
};
|
|
164
|
+
/** Every write to any document's log; several land in one frame, so coalesce. */
|
|
165
|
+
subscribe(listener: () => void): () => void;
|
|
166
|
+
}
|
|
167
|
+
export interface DocumentPlayExtension {
|
|
168
|
+
readonly Control: ComponentType<DocumentPlayControlProps>;
|
|
169
|
+
readonly Menu: ComponentType<DocumentPlayControlProps>;
|
|
170
|
+
playing(documentId: string): boolean;
|
|
171
|
+
/** Intended live frame shape; absent/null lets the document fill its area. */
|
|
172
|
+
aspectRatio?(documentId: string): number | null;
|
|
173
|
+
setPlaying(documentId: string, value: boolean): void;
|
|
174
|
+
escape?(documentId: string): void;
|
|
175
|
+
subscribe(listener: () => void): () => void;
|
|
176
|
+
run(stage: DocumentPlayStage): () => void;
|
|
177
|
+
/** Pause, step, speed, restart and the clock, when the tool keeps them. */
|
|
178
|
+
readonly transport?: DocumentPlayTransport;
|
|
179
|
+
/** The run's play log, when the tool keeps one. */
|
|
180
|
+
readonly log?: DocumentPlayLog;
|
|
181
|
+
/** The project path of the script this tool would run for a document's source file. */
|
|
182
|
+
scriptPath?(sourcePath: string): string;
|
|
183
|
+
/** Whether that script exists: `null` while the tool has not looked yet. A change is announced
|
|
184
|
+
* through `subscribe`. A layout uses it to open a document as a game or as a model. */
|
|
185
|
+
hasScript?(sourcePath: string): boolean | null;
|
|
186
|
+
}
|
|
187
|
+
const key = Symbol.for('volter.document-play-extensions');
|
|
188
|
+
interface Registry {
|
|
189
|
+
extensions: Map<string, DocumentPlayExtension>;
|
|
190
|
+
listeners: Set<() => void>;
|
|
191
|
+
}
|
|
192
|
+
const page = globalThis as typeof globalThis & { [key]?: Registry };
|
|
193
|
+
const registry = page[key] ??= { extensions: new Map(), listeners: new Set() };
|
|
194
|
+
function publish(): void { for (const listener of registry.listeners) listener(); }
|
|
195
|
+
export function documentPlayExtension(kind: string): DocumentPlayExtension | null {
|
|
196
|
+
return registry.extensions.get(kind) ?? null;
|
|
197
|
+
}
|
|
198
|
+
/** Host shells wrap adapter entries as generic documents. Ask the capability
|
|
199
|
+
* owners about this document's identity rather than treating that wrapper's
|
|
200
|
+
* semantic kind as the adapter's registered Play kind. */
|
|
201
|
+
export function documentPlaying(documentId: string): boolean {
|
|
202
|
+
for (const extension of registry.extensions.values()) {
|
|
203
|
+
if (extension.playing(documentId)) return true;
|
|
204
|
+
}
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
export function subscribeDocumentPlayExtensions(listener: () => void): () => void {
|
|
208
|
+
registry.listeners.add(listener);
|
|
209
|
+
return () => { registry.listeners.delete(listener); };
|
|
210
|
+
}
|
|
211
|
+
export function registerDocumentPlayExtension(kind: string, extension: DocumentPlayExtension): () => void {
|
|
212
|
+
if (registry.extensions.has(kind)) throw new Error(`A Play tool already owns ${kind} documents.`);
|
|
213
|
+
registry.extensions.set(kind, extension);
|
|
214
|
+
const stop = extension.subscribe(publish);
|
|
215
|
+
publish();
|
|
216
|
+
return () => {
|
|
217
|
+
stop();
|
|
218
|
+
if (registry.extensions.get(kind) === extension) registry.extensions.delete(kind);
|
|
219
|
+
publish();
|
|
220
|
+
};
|
|
221
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { EditorCameraState } from '../index';
|
|
2
|
+
|
|
3
|
+
export const DOCUMENT_PREVIEW_WIDTH = 320;
|
|
4
|
+
export const DOCUMENT_PREVIEW_HEIGHT = 180;
|
|
5
|
+
export const DOCUMENT_PREVIEW_RECIPE = 'document-preview-v4';
|
|
6
|
+
|
|
7
|
+
export interface DocumentPreviewCaptureRequest {
|
|
8
|
+
readonly width: number;
|
|
9
|
+
readonly height: number;
|
|
10
|
+
readonly camera?: EditorCameraState | undefined;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** The document owner supplies pixels and dependency identity; the host owns
|
|
14
|
+
* scheduling, disk cache, visibility priority, and tile state. */
|
|
15
|
+
export interface DocumentPreviewSource {
|
|
16
|
+
/** Stable identity for source and imported-dependency state. */
|
|
17
|
+
revision(): string;
|
|
18
|
+
subscribe(listener: () => void): () => void;
|
|
19
|
+
capture(request: DocumentPreviewCaptureRequest): Promise<string>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isEditorPresentationActive,
|
|
3
|
+
subscribeEditorPresentationActivity,
|
|
4
|
+
} from '@volter/sdk/kit/editor-presentation-activity';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The frame-loop + renderer lifetime for one Object3D document viewport.
|
|
8
|
+
*
|
|
9
|
+
* Deactivate ≠ dispose.
|
|
10
|
+
*
|
|
11
|
+
* The layout host keeps every open document mounted. A tab
|
|
12
|
+
* flip only flips `active`. Destroying the `WebGLRenderer` on deactivate is
|
|
13
|
+
* a full context teardown + recreate on the next flip — measured live on
|
|
14
|
+
* `examples/third-person` at 4296 ms for the first 3D-board activation and
|
|
15
|
+
* 4015 ms for the second (doctor `--timings-only`). Pause the RAF loop
|
|
16
|
+
* instead; the canvas keeps its last frame and the program cache / IBL bake
|
|
17
|
+
* survive. Real document CLOSE unmounts the host, and {@link dispose} is the
|
|
18
|
+
* one path that frees the context.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
export class DocumentRendererSession {
|
|
22
|
+
private rafId = 0;
|
|
23
|
+
private running = false;
|
|
24
|
+
private disposed = false;
|
|
25
|
+
private active = false;
|
|
26
|
+
private readonly unsubscribeActivity: () => void;
|
|
27
|
+
|
|
28
|
+
constructor(
|
|
29
|
+
private readonly frame: (time: number, resumed: boolean) => void,
|
|
30
|
+
private readonly releaseRenderer: () => void,
|
|
31
|
+
) {
|
|
32
|
+
this.unsubscribeActivity = subscribeEditorPresentationActivity(() => this.syncActivity());
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
get isDisposed(): boolean {
|
|
36
|
+
return this.disposed;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get isRunning(): boolean {
|
|
40
|
+
return this.running;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Tab flip. `false` pauses the loop and keeps the GPU surface. `true`
|
|
45
|
+
* resumes it. Neither constructs nor disposes a renderer.
|
|
46
|
+
*/
|
|
47
|
+
setActive(active: boolean): void {
|
|
48
|
+
if (this.disposed) return;
|
|
49
|
+
this.active = active;
|
|
50
|
+
this.syncActivity();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private syncActivity(): void {
|
|
54
|
+
if (this.active && isEditorPresentationActive()) this.start();
|
|
55
|
+
else this.stop();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Resizing clears the drawing buffer. Repaint immediately while visible;
|
|
59
|
+
* a suspended document redraws as soon as its presentation resumes. */
|
|
60
|
+
redraw(): void {
|
|
61
|
+
if (this.running && !this.disposed && isEditorPresentationActive()) {
|
|
62
|
+
this.guardedFrame(performance.now());
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** The one teardown path — document CLOSE / host unmount. */
|
|
67
|
+
dispose(): void {
|
|
68
|
+
this.stop();
|
|
69
|
+
if (this.disposed) return;
|
|
70
|
+
this.disposed = true;
|
|
71
|
+
this.unsubscribeActivity();
|
|
72
|
+
this.releaseRenderer();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private start(): void {
|
|
76
|
+
if (this.disposed || this.running) return;
|
|
77
|
+
this.running = true;
|
|
78
|
+
// A tab activation is a direct request to present this document. Draw one
|
|
79
|
+
// frame in the activation turn, then join the browser's animation clock.
|
|
80
|
+
// Waiting for the first rAF made a visible tab inherit Chromium's former
|
|
81
|
+
// background cadence (the 1 Hz signature) even when the page itself was
|
|
82
|
+
// visible; users saw the old canvas for that whole interval. Subsequent
|
|
83
|
+
// presentation remains ordinary rAF-driven work.
|
|
84
|
+
// Let content reset its delta baseline without advancing by the hidden interval.
|
|
85
|
+
this.guardedFrame(performance.now(), true);
|
|
86
|
+
if (!this.running || this.disposed) return;
|
|
87
|
+
this.rafId = requestAnimationFrame(this.tick);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** The last frame's failure text, so a persistent fault narrates ONCE
|
|
91
|
+
* rather than sixty times a second, and a recovered loop resets. */
|
|
92
|
+
private lastFrameFailure: string | null = null;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* One frame, and the loop survives it. A throw out of a rAF callback used
|
|
96
|
+
* to be the end of this document's presentation: the exception left
|
|
97
|
+
* `tick` before it rescheduled, so the stage froze on whatever it last
|
|
98
|
+
* drew and nothing said why. Measured (2026-09-04, the mesh document's
|
|
99
|
+
* session swap): three's "Cannot read properties of null (reading
|
|
100
|
+
* 'precision')" from one frame drawn between a disposed overlay and the
|
|
101
|
+
* scene swap killed the stage for the rest of the session. The frame's
|
|
102
|
+
* failure goes to the console WITH its stack — that is what reaches the
|
|
103
|
+
* doors — and the next frame is drawn, because a transient race recovers
|
|
104
|
+
* on its own and a persistent fault is still better shown than frozen.
|
|
105
|
+
*/
|
|
106
|
+
private guardedFrame(time: number, resumed = false): void {
|
|
107
|
+
try {
|
|
108
|
+
this.frame(time, resumed);
|
|
109
|
+
this.lastFrameFailure = null;
|
|
110
|
+
} catch (caught) {
|
|
111
|
+
const text = caught instanceof Error ? caught.message : String(caught);
|
|
112
|
+
if (text !== this.lastFrameFailure) {
|
|
113
|
+
this.lastFrameFailure = text;
|
|
114
|
+
// biome-ignore lint/suspicious/noConsole: a document frame that threw must narrate itself
|
|
115
|
+
console.error('[document renderer] a frame threw; the loop continues:', caught);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private stop(): void {
|
|
121
|
+
this.running = false;
|
|
122
|
+
if (this.rafId !== 0) {
|
|
123
|
+
cancelAnimationFrame(this.rafId);
|
|
124
|
+
this.rafId = 0;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private readonly tick = (time: number): void => {
|
|
129
|
+
if (!this.running || this.disposed) return;
|
|
130
|
+
if (!isEditorPresentationActive()) {
|
|
131
|
+
this.stop();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
this.guardedFrame(time);
|
|
135
|
+
if (!this.running || this.disposed) return;
|
|
136
|
+
this.rafId = requestAnimationFrame(this.tick);
|
|
137
|
+
};
|
|
138
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which open documents run a stage session of their own, and what that session has selected —
|
|
3
|
+
* the part of a media integration's document session the kit's stage context reads. The Three
|
|
4
|
+
* integration registers each Object3D document session here as it registers it for itself; the
|
|
5
|
+
* kit names no viewport.
|
|
6
|
+
*/
|
|
7
|
+
export interface DocumentStageSession {
|
|
8
|
+
readonly documentId: string;
|
|
9
|
+
/** The session's own selection, read straight off its authoring adapter. */
|
|
10
|
+
selection(): readonly string[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const sessions = new Map<string, DocumentStageSession>();
|
|
14
|
+
|
|
15
|
+
/** Register a document's stage session. Returns the teardown. */
|
|
16
|
+
export function registerDocumentStageSession(session: DocumentStageSession): () => void {
|
|
17
|
+
sessions.set(session.documentId, session);
|
|
18
|
+
return () => {
|
|
19
|
+
if (sessions.get(session.documentId) === session) sessions.delete(session.documentId);
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** The document's stage session, or null when it runs none (a table, a report, the world). */
|
|
24
|
+
export function documentStageSession(documentId: string): DocumentStageSession | null {
|
|
25
|
+
return sessions.get(documentId) ?? null;
|
|
26
|
+
}
|