@volter/sdk 0.0.0-stage → 0.5.204
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 +1168 -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 +329 -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 +669 -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,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE ONE PLACE that knows a CSS numeric style value is not the same thing as
|
|
3
|
+
* its CSS TEXT.
|
|
4
|
+
*
|
|
5
|
+
* React's own rule (`dangerousStyleValue`): a NUMBER style value is emitted
|
|
6
|
+
* verbatim when it is `0` or the property is unitless, and suffixed with `px`
|
|
7
|
+
* otherwise. So `style={{ width: 300 }}` paints 300px while
|
|
8
|
+
* `style={{ width: '300' }}` paints NOTHING — the CSSOM rejects a unitless
|
|
9
|
+
* length and keeps the previous value.
|
|
10
|
+
*
|
|
11
|
+
* That is why the inspector's numeric descriptors must reach source as
|
|
12
|
+
* NUMBERS: stringifying `300` on the way to the writer produced
|
|
13
|
+
* `width: '300'`, which React passed through verbatim, which the CSSOM
|
|
14
|
+
* rejected — a write that changed source, changed nothing on screen, and
|
|
15
|
+
* acked `persisted: true`.
|
|
16
|
+
*
|
|
17
|
+
* The two consumers are the two halves of one write: the SOURCE (a bare `300`
|
|
18
|
+
* in the JSX style object, which React px-ifies at render) and the LIVE inline
|
|
19
|
+
* patch / CSS-file declaration (which are CSS TEXT and need the unit spelled).
|
|
20
|
+
* {@link cssTextForStyleValue} is the second half.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Properties whose numeric value is unitless in CSS — the exact set the
|
|
25
|
+
* inspector's numeric widgets already print with no `px` suffix.
|
|
26
|
+
*
|
|
27
|
+
* Deliberately the SHIPPED list rather than React's full internal table: this
|
|
28
|
+
* set covers every `type: 'number'` descriptor the adapters declare
|
|
29
|
+
* (`STYLE_PROPERTIES`), and a descriptor added outside it would be wrong in
|
|
30
|
+
* the widget's suffix before it was wrong here.
|
|
31
|
+
*/
|
|
32
|
+
export const UNITLESS_NUMBER_PROPS: ReadonlySet<string> = new Set([
|
|
33
|
+
'opacity',
|
|
34
|
+
'zIndex',
|
|
35
|
+
'flexGrow',
|
|
36
|
+
'flexShrink',
|
|
37
|
+
// React's own unitless set includes these two, and px-ifying them writes
|
|
38
|
+
// INVALID CSS the browser silently drops (blind re-walk: extracting a
|
|
39
|
+
// class from an element with `fontWeight: 900` emitted
|
|
40
|
+
// `font-weight: 900px`, losing the weight). A numeric lineHeight is the
|
|
41
|
+
// unitless multiplier form — px-ifying it changes meaning, not just
|
|
42
|
+
// validity.
|
|
43
|
+
'fontWeight',
|
|
44
|
+
'lineHeight',
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* THE READ HALF of the same rule: parse a real `CSSStyleDeclaration`'s
|
|
49
|
+
* length-property VALUE (always a unit-suffixed STRING, e.g. `"16px"` — CSSOM
|
|
50
|
+
* never hands back a bare number) into the plain number a `type: 'number'`
|
|
51
|
+
* `PropertyDescriptor` needs to render/edit correctly (`Inspector.tsx`'s
|
|
52
|
+
* generic renderer does `typeof v === 'number' ? … : 0` — without this parse,
|
|
53
|
+
* EVERY numeric style field would silently display `0` against a real browser
|
|
54
|
+
* DOM, even though plain-object `style: {}` fixtures never caught it, because
|
|
55
|
+
* a hand-built fixture can hold a bare JS number directly). Strips a trailing
|
|
56
|
+
* CSS unit (`px`/`em`/`rem`/`%`/`vh`/`vw`, mirroring `ui-source/writer.ts`'s
|
|
57
|
+
* own `LITERAL_RE` unit set); a value already handed over AS a number (or
|
|
58
|
+
* `undefined`/unset) passes through unchanged.
|
|
59
|
+
*
|
|
60
|
+
* It lived in `react-world-authoring-adapter.ts` until 2026-09-18 and moved
|
|
61
|
+
* here for the reason this module's header states — this is the one place that
|
|
62
|
+
* knows CSS numeric value and CSS text are different things — and because one
|
|
63
|
+
* host module that is NOT the React surface reads it: the overlay gesture bus
|
|
64
|
+
* (`components/world-overlay-gestures.ts`) parses a computed border width to
|
|
65
|
+
* place a resize handle. That single edge dragged the whole 3,848-line React
|
|
66
|
+
* root adapter into every editor boot (phase 1 of the open-source launch).
|
|
67
|
+
*/
|
|
68
|
+
export function numericStyleValue(raw: unknown): number | undefined {
|
|
69
|
+
if (typeof raw === 'number') return raw;
|
|
70
|
+
if (typeof raw !== 'string' || raw === '') return undefined;
|
|
71
|
+
const parsed = Number.parseFloat(raw);
|
|
72
|
+
return Number.isNaN(parsed) ? undefined : parsed;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Numeric inspector edits change the magnitude of an authored CSS dimension.
|
|
76
|
+
* Keep relative units; ordinary React numbers and px values remain numbers. */
|
|
77
|
+
export function preserveNumericStyleUnit(
|
|
78
|
+
value: string | number,
|
|
79
|
+
authored: unknown,
|
|
80
|
+
): string | number {
|
|
81
|
+
if (typeof value !== 'number' || typeof authored !== 'string') return value;
|
|
82
|
+
const unit = authored.trim().match(/^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?([a-z]+|%)$/i)?.[1];
|
|
83
|
+
return unit && unit.toLowerCase() !== 'px' ? `${value}${unit}` : value;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The CSS TEXT for a style value — React's `dangerousStyleValue` rule.
|
|
88
|
+
*
|
|
89
|
+
* A string passes through untouched (it is already CSS text — `'12px'`,
|
|
90
|
+
* `'var(--brand)'`, `'50%'`). A number becomes `${n}px` unless it is `0` or
|
|
91
|
+
* the property is unitless.
|
|
92
|
+
*/
|
|
93
|
+
export function cssTextForStyleValue(prop: string, value: string | number): string {
|
|
94
|
+
if (typeof value !== 'number') return value;
|
|
95
|
+
if (value === 0 || UNITLESS_NUMBER_PROPS.has(prop)) return String(value);
|
|
96
|
+
return `${value}px`;
|
|
97
|
+
}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wire vocabulary of the EDITOR-SURFACE probe — the scoped editor-chrome
|
|
3
|
+
* door (`packages/sdk/src/kit/editor-document-probe.ts` implements it,
|
|
4
|
+
* `@volter/live`'s `editor.document` binds it, and that module's header carries
|
|
5
|
+
* the design decision and the scope contract).
|
|
6
|
+
*
|
|
7
|
+
* Deliberately NOT a page-automation vocabulary: there is no navigation, no
|
|
8
|
+
* waiting, no frame/window addressing, and no selector rooted anywhere but one
|
|
9
|
+
* of the NAMED surfaces in {@link DocumentProbeScope}. Eight actions, each one
|
|
10
|
+
* a gesture or a read an agent cannot otherwise perform through the product.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* WHICH NAMED SURFACE a step runs against — the whole addressing vocabulary of
|
|
15
|
+
* this door, and the reason it is a vocabulary rather than a free selector.
|
|
16
|
+
*
|
|
17
|
+
* Every name here resolves to ONE live element the person is looking at, found
|
|
18
|
+
* by a stamp that surface's own owner wrote (`data-volter-part` on the element
|
|
19
|
+
* the workbench handed over for a registered view; the document surface's own
|
|
20
|
+
* `data-testid`), never by walking the page for a class that looks right. A
|
|
21
|
+
* name whose surface is not on screen is REFUSED by name — an agent learns the
|
|
22
|
+
* Properties view is closed instead of reading an empty match list.
|
|
23
|
+
*
|
|
24
|
+
* - `document` — the ACTIVE centre document's whole box: its content, its
|
|
25
|
+
* header strip and its shelf rail. The default, and what this door meant
|
|
26
|
+
* before there were names.
|
|
27
|
+
* - `header` / `shelf` — the active document's toolbar strip and its tool
|
|
28
|
+
* rail, each on its own. Both are INSIDE `document`; they exist as names so
|
|
29
|
+
* a selector that also matches in the content (`button`, `[role=tab]`) can
|
|
30
|
+
* be aimed without an index.
|
|
31
|
+
* - `rail` — the Properties view (`volter.properties`): its vertical tab rail,
|
|
32
|
+
* the active tab's sections and their fields.
|
|
33
|
+
* - `outliner` — the Outliner view (`volter.outliner`): its rows, their
|
|
34
|
+
* expand/eye/camera controls, and its header.
|
|
35
|
+
* - `content` — the Content view (`volter.content`): its categories and asset
|
|
36
|
+
* rows.
|
|
37
|
+
*
|
|
38
|
+
* - `utility` — the utility view showing in the panel (a contribution's
|
|
39
|
+
* `*.utility.tsx`, the Profiler, State Watch…).
|
|
40
|
+
* - `menubar` — the application menus (Edit, View, Window…) and the menus
|
|
41
|
+
* their triggers open: the one place a person chooses Edit › Undo.
|
|
42
|
+
* - `area` — the workspace's areas beside the centre document (the Model
|
|
43
|
+
* workspace's bottom area: the Timeline, the Action Editor, the NLA editor,
|
|
44
|
+
* the Game panel), each a document of its own that the workspace opened.
|
|
45
|
+
*
|
|
46
|
+
* `rail`, `outliner`, `content`, `utility`, `menubar` and `area` are EDITOR CHROME and do not belong to the active
|
|
47
|
+
* document, so they stay reachable while the Game document is active — the
|
|
48
|
+
* Game refusal is about driving a game through synthetic gestures, and reading
|
|
49
|
+
* the panel that reports its selection is not that.
|
|
50
|
+
*/
|
|
51
|
+
export type DocumentProbeScope = 'document' | 'header' | 'shelf' | 'rail' | 'outliner' | 'content' | 'utility' | 'menubar' | 'area';
|
|
52
|
+
|
|
53
|
+
/** Keep an explicit key hold within the SDK's bounded command deadline. */
|
|
54
|
+
export const MAX_DOCUMENT_KEY_HOLD_MS = 120_000;
|
|
55
|
+
|
|
56
|
+
/** One element as the probe reports it — everything a caller needs to assert
|
|
57
|
+
* on, and nothing that requires a second round trip. */
|
|
58
|
+
export interface ProbedElement {
|
|
59
|
+
/** Position within the match list this element came from. */
|
|
60
|
+
index: number;
|
|
61
|
+
tag: string;
|
|
62
|
+
/** `innerText`, trimmed and capped. */
|
|
63
|
+
text: string;
|
|
64
|
+
attributes: Record<string, string>;
|
|
65
|
+
rect: { x: number; y: number; width: number; height: number };
|
|
66
|
+
/** Present for form controls. */
|
|
67
|
+
value?: string;
|
|
68
|
+
checked?: boolean;
|
|
69
|
+
disabled?: boolean;
|
|
70
|
+
/** Resolved style, present only for the names {@link DocumentQueryStep.styles}
|
|
71
|
+
* asked for. A standard property carries the browser's own resolved value
|
|
72
|
+
* (`backgroundColor` → `rgb(52, 52, 52)`); a custom property carries what it
|
|
73
|
+
* PAINTS when it resolves as a colour, and its declared text otherwise. */
|
|
74
|
+
styles?: Record<string, string>;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface DocumentProbeResult {
|
|
78
|
+
/** The surface the step ran against — echoed so a transcript proves WHICH
|
|
79
|
+
* one was read or driven, not merely that something was. `name` is the
|
|
80
|
+
* vocabulary word; `id`/`title` are that surface's own identity (a
|
|
81
|
+
* document's id and title, or the registered view's). */
|
|
82
|
+
scope: { name: DocumentProbeScope; id: string; title: string };
|
|
83
|
+
/** Total matches inside the scope, before any `limit`. */
|
|
84
|
+
matched: number;
|
|
85
|
+
elements: ProbedElement[];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Which named surface a step runs against; `document` when omitted. */
|
|
89
|
+
interface ScopedStep {
|
|
90
|
+
scope?: DocumentProbeScope;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Read what a surface rendered. */
|
|
94
|
+
export interface DocumentQueryStep extends ScopedStep {
|
|
95
|
+
action: 'query';
|
|
96
|
+
selector: string;
|
|
97
|
+
/** Cap on returned elements (default 25); `matched` still reports the total. */
|
|
98
|
+
limit?: number;
|
|
99
|
+
/**
|
|
100
|
+
* Style property names to resolve on each match — standard
|
|
101
|
+
* (`backgroundColor`, `borderInlineStartWidth`) or custom (`--volter-…`).
|
|
102
|
+
*
|
|
103
|
+
* Ask for the STANDARD property to learn what a surface PAINTS: a theme
|
|
104
|
+
* token is an expression (`color-mix(…)`), and the element that uses it is
|
|
105
|
+
* where the browser turns that expression into a colour. A custom property
|
|
106
|
+
* is resolved here too, through a real paint property, so a token answers
|
|
107
|
+
* with the rgb it would paint rather than its own algebra — which is the
|
|
108
|
+
* only way a `:hover` colour can be measured at all, `:hover` being a
|
|
109
|
+
* browser state no synthetic event can enter. An UNDECLARED custom
|
|
110
|
+
* property answers `""`, so "does this palette declare this group" is a
|
|
111
|
+
* question this door can be trusted with.
|
|
112
|
+
*
|
|
113
|
+
* The value is the browser's, in the browser's own spelling: a token built
|
|
114
|
+
* by `color-mix()` answers as `color(srgb …)` with float channels, a plain
|
|
115
|
+
* one as `rgb(…)`. Both are the paint; multiply a float by 255 to compare
|
|
116
|
+
* against a reference frame's 8-bit levels.
|
|
117
|
+
*/
|
|
118
|
+
styles?: string[];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** A real pointer gesture on one matched element. */
|
|
122
|
+
export interface DocumentClickStep extends ScopedStep {
|
|
123
|
+
action: 'click';
|
|
124
|
+
selector: string;
|
|
125
|
+
/** Which match (default 0). */
|
|
126
|
+
index?: number;
|
|
127
|
+
/**
|
|
128
|
+
* Clicks in the gesture (default 1). `2` is a REAL double click: the second
|
|
129
|
+
* press carries `detail: 2` and is followed by a `dblclick`, which is the
|
|
130
|
+
* only event `onDoubleClick` listens for.
|
|
131
|
+
*
|
|
132
|
+
* It is on `click` rather than a verb of its own because it is the same
|
|
133
|
+
* gesture with the same target — and it is here at all because a double
|
|
134
|
+
* click is the OUTLINER'S OWN rename gesture (`GameHierarchy.tsx`'s
|
|
135
|
+
* `onDoubleClick` → `onStartEditing`), so without it a rename could only be
|
|
136
|
+
* driven through `editor.setField`, which is not the control.
|
|
137
|
+
*/
|
|
138
|
+
clicks?: number;
|
|
139
|
+
/**
|
|
140
|
+
* Where in the element the press lands, `[x, y]` as FRACTIONS of its box from its top-left
|
|
141
|
+
* (the same convention as `drag`'s `from`/`to`); default its centre. A control whose meaning
|
|
142
|
+
* is its position — a ruler that seeks to the beat under the pointer, a lane whose
|
|
143
|
+
* double-click adds a point there — can only be driven at a chosen point with it.
|
|
144
|
+
*/
|
|
145
|
+
at?: [number, number];
|
|
146
|
+
/** Modifier keys held through the click (a Shift range pick, a Cmd/Ctrl toggle pick). */
|
|
147
|
+
altKey?: boolean;
|
|
148
|
+
ctrlKey?: boolean;
|
|
149
|
+
metaKey?: boolean;
|
|
150
|
+
shiftKey?: boolean;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* TYPE into a focused field, character by character, and commit with Enter the
|
|
155
|
+
* way a person does.
|
|
156
|
+
*
|
|
157
|
+
* `paste` cannot stand in for this: an untrusted `ClipboardEvent` performs no
|
|
158
|
+
* default action, so a plain `<input>` with no paste handler keeps its old
|
|
159
|
+
* value. And a direct `element.value = x` is invisible to React, which caches
|
|
160
|
+
* the last value it wrote on the node — the same trap `select` documents. So
|
|
161
|
+
* each character goes through the prototype's own value setter (leaving
|
|
162
|
+
* React's tracker stale, which is what makes the following `input` read as a
|
|
163
|
+
* real edit), between a real `keydown`/`keyup` for that character, so a field
|
|
164
|
+
* that commits on a KEY rather than on `input` sees the keys too.
|
|
165
|
+
*/
|
|
166
|
+
export interface DocumentTypeStep extends ScopedStep {
|
|
167
|
+
action: 'type';
|
|
168
|
+
text: string;
|
|
169
|
+
/** The field; omitted means whatever inside the scope has focus. */
|
|
170
|
+
selector?: string;
|
|
171
|
+
index?: number;
|
|
172
|
+
/** Replace what the field holds first, the way a person selects-all and
|
|
173
|
+
* types over it (default true). `false` appends at the end. */
|
|
174
|
+
replace?: boolean;
|
|
175
|
+
/** Press Enter after the text (default true) — the commit gesture for the
|
|
176
|
+
* Outliner's rename field and every numeric field in the Properties rail. */
|
|
177
|
+
enter?: boolean;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* A real pointer DRAG across one matched element: `pointerdown` at `from`,
|
|
182
|
+
* `steps` `pointermove`s along the way, `pointerup` at `to` — the sequence a
|
|
183
|
+
* mouse produces, so a canvas that begins a gesture on press and previews on
|
|
184
|
+
* move (an Asset Lab document's direct manipulation) sees the whole gesture.
|
|
185
|
+
* `from`/`to` are FRACTIONS of the element's box (`[0.5, 0.5]` is its
|
|
186
|
+
* center), so a caller reasons in the element's own space, not the screen's.
|
|
187
|
+
* A zero-length drag is a click at that fraction.
|
|
188
|
+
*/
|
|
189
|
+
export interface DocumentDragStep extends ScopedStep {
|
|
190
|
+
action: 'drag';
|
|
191
|
+
selector: string;
|
|
192
|
+
/** Which match (default 0). */
|
|
193
|
+
index?: number;
|
|
194
|
+
from: [number, number];
|
|
195
|
+
to: [number, number];
|
|
196
|
+
/** Waypoints the pointer passes through between `from` and `to`, in
|
|
197
|
+
* order — what a lasso or a knife stroke needs, since a straight drag
|
|
198
|
+
* encloses nothing. Each leg gets `steps` moves. */
|
|
199
|
+
via?: [number, number][];
|
|
200
|
+
/** Intermediate `pointermove`s between consecutive points (default 8). */
|
|
201
|
+
steps?: number;
|
|
202
|
+
/** Modifier keys held for the whole gesture (a Shift-extend, an Alt-click). */
|
|
203
|
+
altKey?: boolean;
|
|
204
|
+
ctrlKey?: boolean;
|
|
205
|
+
metaKey?: boolean;
|
|
206
|
+
shiftKey?: boolean;
|
|
207
|
+
/** The button held: 0 primary (default), 1 middle, 2 secondary. A right
|
|
208
|
+
* press is what orbits a viewport or, with Shift, places Blender's 3D cursor. */
|
|
209
|
+
button?: 0 | 1 | 2;
|
|
210
|
+
/** The pointer may leave the element after the press: `via`/`to` may lie
|
|
211
|
+
* outside 0..1 (still fractions of the element's box), the way a person
|
|
212
|
+
* drags a 10 px resize handle outward. The press stays inside, and the
|
|
213
|
+
* element keeps receiving the moves, as pointer capture delivers them. */
|
|
214
|
+
leave?: boolean;
|
|
215
|
+
/** Press and move, and KEEP THE BUTTON DOWN: the gesture stays open for readings taken in the
|
|
216
|
+
* middle of it (what another area draws while a gizmo is dragged), until a `release` step
|
|
217
|
+
* lets go at `to`. */
|
|
218
|
+
hold?: boolean;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Lets go of the drag a `hold` left pressed, where it was left. */
|
|
222
|
+
export interface DocumentReleaseStep extends ScopedStep {
|
|
223
|
+
action: 'release';
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** A real key on the explicit target, else whatever inside the document has focus. */
|
|
227
|
+
export interface DocumentKeyStep extends ScopedStep {
|
|
228
|
+
action: 'key';
|
|
229
|
+
key: string;
|
|
230
|
+
code?: string;
|
|
231
|
+
selector?: string;
|
|
232
|
+
index?: number;
|
|
233
|
+
ctrlKey?: boolean;
|
|
234
|
+
metaKey?: boolean;
|
|
235
|
+
shiftKey?: boolean;
|
|
236
|
+
altKey?: boolean;
|
|
237
|
+
/** Hold the key this long before releasing it, as a person holding W does;
|
|
238
|
+
* omitted, it is pressed and released at once. Must be finite, nonnegative
|
|
239
|
+
* and at most MAX_DOCUMENT_KEY_HOLD_MS (120 seconds). */
|
|
240
|
+
holdMs?: number;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** A real `ClipboardEvent` carrying `text/plain` — the only way to exercise a
|
|
244
|
+
* paste handler, and the gesture the Sheets build could not verify. */
|
|
245
|
+
export interface DocumentPasteStep extends ScopedStep {
|
|
246
|
+
action: 'paste';
|
|
247
|
+
text: string;
|
|
248
|
+
selector?: string;
|
|
249
|
+
index?: number;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Choose a value on a `<select>` — the gesture `click` cannot make.
|
|
254
|
+
*
|
|
255
|
+
* A native dropdown's option list is rendered by the OS, not by the DOM, so
|
|
256
|
+
* there is nothing inside the document's container for a pointer gesture to
|
|
257
|
+
* resolve against: `click` on the `<select>` opens a menu no synthetic event
|
|
258
|
+
* can reach. Assigning `element.value` is equally useless on a React
|
|
259
|
+
* controlled component — React caches the last value it wrote on the node, so
|
|
260
|
+
* a direct write is not seen as a change and the next render puts the old
|
|
261
|
+
* value straight back. The implementation goes through the prototype's own
|
|
262
|
+
* value setter and then dispatches `input`/`change`, which is the ONE spelling
|
|
263
|
+
* React's synthetic-event layer honours.
|
|
264
|
+
*/
|
|
265
|
+
export interface DocumentSelectStep extends ScopedStep {
|
|
266
|
+
action: 'select';
|
|
267
|
+
selector: string;
|
|
268
|
+
/** The option's `value` (not its label). */
|
|
269
|
+
value: string;
|
|
270
|
+
/** Which match (default 0). */
|
|
271
|
+
index?: number;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export type DocumentProbeStep =
|
|
275
|
+
| DocumentQueryStep
|
|
276
|
+
| DocumentClickStep
|
|
277
|
+
| DocumentDragStep
|
|
278
|
+
| DocumentReleaseStep
|
|
279
|
+
| DocumentKeyStep
|
|
280
|
+
| DocumentPasteStep
|
|
281
|
+
| DocumentSelectStep
|
|
282
|
+
| DocumentTypeStep;
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import type { AssetKind, EditorCameraState, EditorView, ViewPreset } from './types.js';
|
|
2
|
+
import { EDITOR_VIEW_WORKSPACE_DOCUMENT_IDS, isEditorViewUtility } from './types.js';
|
|
3
|
+
|
|
4
|
+
const PREFIX = 'view.';
|
|
5
|
+
const MAX_QUERY_LENGTH = 4096;
|
|
6
|
+
const WORKSPACE_DOCUMENT_IDS = new Set<string>(EDITOR_VIEW_WORKSPACE_DOCUMENT_IDS);
|
|
7
|
+
const ASSET_KINDS = new Set<AssetKind>([
|
|
8
|
+
'model',
|
|
9
|
+
'image',
|
|
10
|
+
'audio',
|
|
11
|
+
'animation',
|
|
12
|
+
'json',
|
|
13
|
+
'prefab',
|
|
14
|
+
'source',
|
|
15
|
+
]);
|
|
16
|
+
const CAMERAS = new Set<ViewPreset | 'isometric'>([
|
|
17
|
+
'top',
|
|
18
|
+
'front',
|
|
19
|
+
'right',
|
|
20
|
+
'perspective',
|
|
21
|
+
'isometric',
|
|
22
|
+
]);
|
|
23
|
+
type EditorViewDiagnostic = NonNullable<NonNullable<EditorView['viewport']>['diagnostic']>;
|
|
24
|
+
export const EDITOR_VIEW_DIAGNOSTICS = [
|
|
25
|
+
'solid',
|
|
26
|
+
'preview',
|
|
27
|
+
'rendered',
|
|
28
|
+
'clay',
|
|
29
|
+
'unlit',
|
|
30
|
+
'wireframe',
|
|
31
|
+
'matcap',
|
|
32
|
+
'normals',
|
|
33
|
+
'overdraw',
|
|
34
|
+
'uv',
|
|
35
|
+
'vertex-colors',
|
|
36
|
+
'bounds',
|
|
37
|
+
'skeleton',
|
|
38
|
+
] as const satisfies readonly EditorViewDiagnostic[];
|
|
39
|
+
const DIAGNOSTICS = new Set<EditorViewDiagnostic>(EDITOR_VIEW_DIAGNOSTICS);
|
|
40
|
+
function nonEmpty(value: string | null): string | null {
|
|
41
|
+
const trimmed = value?.trim();
|
|
42
|
+
return trimmed ? trimmed : null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function writeDocument(params: URLSearchParams, document: EditorView['document']): void {
|
|
46
|
+
if (!document) return;
|
|
47
|
+
params.set(`${PREFIX}docKind`, document.kind);
|
|
48
|
+
if (document.kind === 'asset' && document.entityId) {
|
|
49
|
+
params.set(`${PREFIX}doc`, document.entityId);
|
|
50
|
+
params.set(`${PREFIX}assetSource`, 'entity');
|
|
51
|
+
} else if (document.kind === 'asset') {
|
|
52
|
+
params.set(`${PREFIX}doc`, document.path!);
|
|
53
|
+
} else if (document.kind === 'scene') {
|
|
54
|
+
params.set(`${PREFIX}doc`, document.path);
|
|
55
|
+
} else if (document.kind === 'story') {
|
|
56
|
+
params.set(`${PREFIX}doc`, document.modulePath);
|
|
57
|
+
params.set(`${PREFIX}story`, document.storyName);
|
|
58
|
+
if (document.mode === 'docs') params.set(`${PREFIX}storyMode`, 'docs');
|
|
59
|
+
} else if (document.kind === 'project-tool') {
|
|
60
|
+
params.set(`${PREFIX}doc`, document.name);
|
|
61
|
+
} else {
|
|
62
|
+
params.set(`${PREFIX}doc`, document.id);
|
|
63
|
+
}
|
|
64
|
+
if (document.kind === 'asset' && document.assetKind) {
|
|
65
|
+
params.set(`${PREFIX}assetKind`, document.assetKind);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function writeViewport(params: URLSearchParams, viewport: EditorView['viewport']): void {
|
|
70
|
+
if (!viewport) return;
|
|
71
|
+
if (typeof viewport.camera === 'string') params.set(`${PREFIX}camera`, viewport.camera);
|
|
72
|
+
else if (viewport.camera) {
|
|
73
|
+
params.set(`${PREFIX}camera`, 'pose');
|
|
74
|
+
params.set(
|
|
75
|
+
`${PREFIX}cameraPosition`,
|
|
76
|
+
[viewport.camera.position.x, viewport.camera.position.y, viewport.camera.position.z].join(
|
|
77
|
+
',',
|
|
78
|
+
),
|
|
79
|
+
);
|
|
80
|
+
params.set(
|
|
81
|
+
`${PREFIX}cameraTarget`,
|
|
82
|
+
[viewport.camera.target.x, viewport.camera.target.y, viewport.camera.target.z].join(','),
|
|
83
|
+
);
|
|
84
|
+
if (viewport.camera.fov !== undefined)
|
|
85
|
+
params.set(`${PREFIX}cameraFov`, String(viewport.camera.fov));
|
|
86
|
+
}
|
|
87
|
+
if (viewport.diagnostic) params.set(`${PREFIX}diagnostic`, viewport.diagnostic);
|
|
88
|
+
if (viewport.frame) params.set(`${PREFIX}frame`, viewport.frame);
|
|
89
|
+
if (viewport.grid !== undefined) params.set(`${PREFIX}grid`, viewport.grid ? '1' : '0');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function parseVec3(value: string | null): EditorCameraState['position'] | null {
|
|
93
|
+
if (!value) return null;
|
|
94
|
+
const parts = value.split(',').map(Number);
|
|
95
|
+
if (parts.length !== 3 || parts.some((part) => !Number.isFinite(part))) return null;
|
|
96
|
+
return { x: parts[0]!, y: parts[1]!, z: parts[2]! };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function parseCamera(params: URLSearchParams): NonNullable<EditorView['viewport']>['camera'] {
|
|
100
|
+
const camera = params.get(`${PREFIX}camera`);
|
|
101
|
+
if (camera && CAMERAS.has(camera as ViewPreset | 'isometric')) {
|
|
102
|
+
return camera as ViewPreset | 'isometric';
|
|
103
|
+
}
|
|
104
|
+
if (camera !== 'pose') return undefined;
|
|
105
|
+
const position = parseVec3(params.get(`${PREFIX}cameraPosition`));
|
|
106
|
+
const target = parseVec3(params.get(`${PREFIX}cameraTarget`));
|
|
107
|
+
const fovValue = params.get(`${PREFIX}cameraFov`);
|
|
108
|
+
const fov = fovValue === null ? undefined : Number(fovValue);
|
|
109
|
+
if (!position || !target || (fov !== undefined && !Number.isFinite(fov))) return undefined;
|
|
110
|
+
return { position, target, ...(fov !== undefined ? { fov } : {}) };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function parseStoryDocument(params: URLSearchParams, modulePath: string): EditorView['document'] {
|
|
114
|
+
const storyName = nonEmpty(params.get(`${PREFIX}story`));
|
|
115
|
+
if (!storyName) return undefined;
|
|
116
|
+
return {
|
|
117
|
+
kind: 'story',
|
|
118
|
+
modulePath,
|
|
119
|
+
storyName,
|
|
120
|
+
...(params.get(`${PREFIX}storyMode`) === 'docs' ? { mode: 'docs' as const } : {}),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function parseAssetDocument(params: URLSearchParams, value: string): EditorView['document'] {
|
|
125
|
+
const assetKind = params.get(`${PREFIX}assetKind`);
|
|
126
|
+
if (params.get(`${PREFIX}assetSource`) === 'entity') {
|
|
127
|
+
return { kind: 'asset', entityId: value, assetKind: 'model' };
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
kind: 'asset',
|
|
131
|
+
path: value,
|
|
132
|
+
...(assetKind && ASSET_KINDS.has(assetKind as AssetKind)
|
|
133
|
+
? { assetKind: assetKind as AssetKind }
|
|
134
|
+
: {}),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function parseDocument(params: URLSearchParams): EditorView['document'] {
|
|
139
|
+
const kind = params.get(`${PREFIX}docKind`);
|
|
140
|
+
const value = nonEmpty(params.get(`${PREFIX}doc`));
|
|
141
|
+
if (!value) return undefined;
|
|
142
|
+
if (kind === 'scene') return { kind, path: value };
|
|
143
|
+
if (kind === 'tool') return { kind, id: value };
|
|
144
|
+
if (kind === 'document') return { kind, id: value };
|
|
145
|
+
if (kind === 'world') return { kind, id: value };
|
|
146
|
+
if (kind === 'project-tool') return { kind, name: value };
|
|
147
|
+
if (kind === 'generation') return { kind, id: value };
|
|
148
|
+
if (kind === 'story') return parseStoryDocument(params, value);
|
|
149
|
+
if (kind === 'workspace' && WORKSPACE_DOCUMENT_IDS.has(value)) {
|
|
150
|
+
return {
|
|
151
|
+
kind,
|
|
152
|
+
id: value as Extract<NonNullable<EditorView['document']>, { kind: 'workspace' }>['id'],
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
return kind === 'asset' ? parseAssetDocument(params, value) : undefined;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function parseViewport(params: URLSearchParams): EditorView['viewport'] {
|
|
159
|
+
const camera = parseCamera(params);
|
|
160
|
+
const diagnostic = params.get(`${PREFIX}diagnostic`);
|
|
161
|
+
const frame = params.get(`${PREFIX}frame`);
|
|
162
|
+
const grid = params.get(`${PREFIX}grid`);
|
|
163
|
+
const viewport = {
|
|
164
|
+
...(camera ? { camera } : {}),
|
|
165
|
+
...(diagnostic && DIAGNOSTICS.has(diagnostic as EditorViewDiagnostic)
|
|
166
|
+
? { diagnostic: diagnostic as EditorViewDiagnostic }
|
|
167
|
+
: {}),
|
|
168
|
+
...(frame === 'document' || frame === 'selection'
|
|
169
|
+
? { frame: frame as 'document' | 'selection' }
|
|
170
|
+
: {}),
|
|
171
|
+
...(grid === '0' || grid === '1' ? { grid: grid === '1' } : {}),
|
|
172
|
+
};
|
|
173
|
+
return Object.keys(viewport).length > 0 ? viewport : undefined;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** Apply only the view-owned query parameters, preserving project/scene routing params. */
|
|
177
|
+
export function editorViewUrl(view: EditorView, baseUrl: string | URL): string {
|
|
178
|
+
const url = new URL(baseUrl);
|
|
179
|
+
for (const key of [...url.searchParams.keys()]) {
|
|
180
|
+
if (key.startsWith(PREFIX)) url.searchParams.delete(key);
|
|
181
|
+
}
|
|
182
|
+
url.searchParams.set(`${PREFIX}v`, '1');
|
|
183
|
+
writeDocument(url.searchParams, view.document);
|
|
184
|
+
if (view.selection?.ids.length) {
|
|
185
|
+
for (const id of view.selection.ids) url.searchParams.append(`${PREFIX}select`, id);
|
|
186
|
+
if (view.selection.focus) url.searchParams.set(`${PREFIX}focus`, '1');
|
|
187
|
+
}
|
|
188
|
+
writeViewport(url.searchParams, view.viewport);
|
|
189
|
+
if (view.workspace) url.searchParams.set(`${PREFIX}workspace`, view.workspace);
|
|
190
|
+
if (view.panel) url.searchParams.set(`${PREFIX}panel`, view.panel);
|
|
191
|
+
if (view.utility) url.searchParams.set(`${PREFIX}utility`, view.utility);
|
|
192
|
+
if (url.search.length > MAX_QUERY_LENGTH) {
|
|
193
|
+
throw new Error(`Editor view URL exceeds the ${MAX_QUERY_LENGTH}-character share limit.`);
|
|
194
|
+
}
|
|
195
|
+
return url.toString();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Parse a shareable editor projection. Malformed projections are ignored at boot. */
|
|
199
|
+
export function editorViewFromUrl(value: string | URL): EditorView | null {
|
|
200
|
+
const url = value instanceof URL ? value : new URL(value, 'http://editor.invalid');
|
|
201
|
+
const params = url.searchParams;
|
|
202
|
+
if (params.get(`${PREFIX}v`) !== '1') return null;
|
|
203
|
+
const view: EditorView = { version: 1 };
|
|
204
|
+
const document = parseDocument(params);
|
|
205
|
+
if (document) view.document = document;
|
|
206
|
+
const ids = params
|
|
207
|
+
.getAll(`${PREFIX}select`)
|
|
208
|
+
.filter((id) => id.length > 0)
|
|
209
|
+
.slice(0, 32);
|
|
210
|
+
if (ids.length) view.selection = { ids, focus: params.get(`${PREFIX}focus`) === '1' };
|
|
211
|
+
const viewport = parseViewport(params);
|
|
212
|
+
if (viewport) view.viewport = viewport;
|
|
213
|
+
// Shape check only: a `tool:` id names a utility the OPEN PROJECT
|
|
214
|
+
// contributes, so the URL cannot know whether it exists. The editor
|
|
215
|
+
// validates it against its live registry when the view is presented.
|
|
216
|
+
const workspace = params.get(`${PREFIX}workspace`);
|
|
217
|
+
if (workspace) view.workspace = workspace;
|
|
218
|
+
// Shape check only, like `workspace` above: which panels exist is the open
|
|
219
|
+
// editor's registry, and it answers at present-time.
|
|
220
|
+
const panel = params.get(`${PREFIX}panel`);
|
|
221
|
+
if (panel) view.panel = panel;
|
|
222
|
+
const utility = params.get(`${PREFIX}utility`);
|
|
223
|
+
if (utility && isEditorViewUtility(utility)) view.utility = utility;
|
|
224
|
+
return view;
|
|
225
|
+
}
|
package/src/extension.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension contract (W3a) — the published surface a game project uses to
|
|
3
|
+
* contribute to the editor, with the degradation ladder made API.
|
|
4
|
+
*
|
|
5
|
+
* A project extends the editor through exactly three surfaces:
|
|
6
|
+
*
|
|
7
|
+
* (a) **Editor panels** — registered into the workspace as documents
|
|
8
|
+
* or utilities via a tool contribution (`package.json#volter.tools` →
|
|
9
|
+
* `contributes: [{ point: 'workspace.document' | 'workspace.utility' | 'workspace.analytics' }]`).
|
|
10
|
+
* Types: `ToolContributionProps` in `@volter/sdk/contributions`.
|
|
11
|
+
* Panels are never a parallel rail — the frame owns all layout.
|
|
12
|
+
* (b) **Inspector sections** — `point: 'selection.inspector'` /
|
|
13
|
+
* `'asset.inspector'` tool contributions with an exported `match`.
|
|
14
|
+
* Types: `ToolInspectorContributionProps` and friends, same module.
|
|
15
|
+
* (c) **System adapters** — runtime capabilities (networking, debug, …)
|
|
16
|
+
* registered from game code via `ctx.registerSystemAdapter?.(kind, impl)`
|
|
17
|
+
* (`SystemAdapters` in `@volter/project`'s
|
|
18
|
+
* `adapter/system-adapter`). Deliberately NOT re-exported here: the
|
|
19
|
+
* engine already publishes that seam and every consumer of it also
|
|
20
|
+
* imports the engine — an alias would be a dead surface.
|
|
21
|
+
*
|
|
22
|
+
* Outcomes (the anti-shim rule, as API): every contribution resolves to an
|
|
23
|
+
* {@link ExtensionContributionState} —
|
|
24
|
+
*
|
|
25
|
+
* - `'active'` — the contribution loaded and produced its surface.
|
|
26
|
+
* - `'absent'` — nothing was contributed. The editor HIDES the surface
|
|
27
|
+
* entirely; it never fabricates placeholder data for a missing
|
|
28
|
+
* contribution.
|
|
29
|
+
* - `'failed'` — the contribution exists but threw / violated the contract.
|
|
30
|
+
* The failure is contained per-contribution (the editor never crashes),
|
|
31
|
+
* the surface is hidden, and the error is reported LOUDLY (editor
|
|
32
|
+
* console) — never silently swallowed into fake output.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The terminal state of a single extension contribution (see the module doc
|
|
37
|
+
* above for the exact semantics). Not a grade and not an ordering: `absent`
|
|
38
|
+
* and `failed` both hide the surface, and `failed` is reported loudly.
|
|
39
|
+
*/
|
|
40
|
+
export type ExtensionContributionState = 'active' | 'absent' | 'failed';
|