@volter/editor-core 0.5.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BUNDLED_NOTICES +1527 -0
- package/LICENSE +686 -0
- package/LICENSE-APACHE +202 -0
- package/NOTICE +18 -0
- package/README.md +24 -0
- package/dist/build/chunk-JS4D4XZ3.js +175 -0
- package/dist/build/chunk-JS4D4XZ3.js.map +7 -0
- package/dist/build/vite-plugin-product-contributions.js +100 -0
- package/dist/build/vite-plugin-product-contributions.js.map +7 -0
- package/dist/build/vite-plugin-shared-react.js +25 -0
- package/dist/build/vite-plugin-shared-react.js.map +7 -0
- package/dist/build/vite-plugin-shared-three.js +86 -0
- package/dist/build/vite-plugin-shared-three.js.map +7 -0
- package/dist/server/chunk-KMJC7AGO.js +98 -0
- package/dist/server/chunk-KMJC7AGO.js.map +7 -0
- package/dist/server/chunk-PSILUMGS.js +46 -0
- package/dist/server/chunk-PSILUMGS.js.map +7 -0
- package/dist/server/frame-proxy.js +255 -0
- package/dist/server/frame-proxy.js.map +7 -0
- package/dist/server/open-browser.js +53 -0
- package/dist/server/open-browser.js.map +7 -0
- package/dist/server/process-shutdown.js +127 -0
- package/dist/server/process-shutdown.js.map +7 -0
- package/dist/server/session-registry.js +141 -0
- package/dist/server/session-registry.js.map +7 -0
- package/dist/server/spawn-opener.js +11 -0
- package/dist/server/spawn-opener.js.map +7 -0
- package/dist/server/worktree-identity.js +11 -0
- package/dist/server/worktree-identity.js.map +7 -0
- package/dist-server/packaged.mjs +88816 -0
- package/package.json +118 -0
- package/scripts/build-plugins.mjs +14 -0
- package/scripts/build-server.mjs +26 -0
- package/scripts/build-session.mjs +9 -0
- package/server/account-credentials.ts +60 -0
- package/server/account-service.ts +1434 -0
- package/server/adapter-region-includes.ts +47 -0
- package/server/asset-catalog-v2.ts +175 -0
- package/server/asset-history-snapshots.ts +196 -0
- package/server/asset-ledger-store.ts +195 -0
- package/server/asset-library-routes.ts +1595 -0
- package/server/blender-wasm-artifact.ts +430 -0
- package/server/boot-timings.ts +106 -0
- package/server/canonical-path.ts +50 -0
- package/server/checkout-workspace-preflight.ts +349 -0
- package/server/cloud-asset-catalog.ts +158 -0
- package/server/coding-inference-launch.ts +237 -0
- package/server/collaboration-account-client.ts +202 -0
- package/server/collaboration-attribution.ts +122 -0
- package/server/collaboration-session.ts +934 -0
- package/server/comfyui-bridge.ts +248 -0
- package/server/console-ledger.ts +499 -0
- package/server/creation-site-transform.ts +304 -0
- package/server/creation-site-write.ts +648 -0
- package/server/data-file-serialize.ts +158 -0
- package/server/editor-brand-html.ts +72 -0
- package/server/editor-control-socket.ts +366 -0
- package/server/editor-server-options.ts +190 -0
- package/server/editor-server.ts +1483 -0
- package/server/editor-sse.ts +352 -0
- package/server/engine-provenance.ts +169 -0
- package/server/engine-source-restart.ts +117 -0
- package/server/frame-bridge.ts +115 -0
- package/server/frame-proxy.ts +490 -0
- package/server/frame-workbench.ts +259 -0
- package/server/frontend-handoff.ts +229 -0
- package/server/game-globals-shadow.ts +113 -0
- package/server/gameplay-session-retention.ts +149 -0
- package/server/gameplay-sessions.ts +123 -0
- package/server/generation-jobs.ts +201 -0
- package/server/generation-reconciler.ts +137 -0
- package/server/generative-execution-context.ts +59 -0
- package/server/git-workflow.ts +612 -0
- package/server/harness-chat-caller.ts +36 -0
- package/server/harness-chat-service.ts +1681 -0
- package/server/idle-shutdown.ts +170 -0
- package/server/js-profiling-policy.ts +52 -0
- package/server/launcher-settings.ts +84 -0
- package/server/local-asset-catalog.ts +410 -0
- package/server/managed-account-defaults.ts +22 -0
- package/server/mock-control-plane.ts +540 -0
- package/server/model-import-conversion.ts +345 -0
- package/server/native-credential-store.ts +162 -0
- package/server/open-browser.ts +118 -0
- package/server/packaged.ts +1192 -0
- package/server/play-stall.ts +126 -0
- package/server/process-shutdown.ts +218 -0
- package/server/product-presets.ts +55 -0
- package/server/project-build-artifact.ts +95 -0
- package/server/project-components.ts +100 -0
- package/server/project-dependency-invalidation.ts +114 -0
- package/server/project-file-scan.ts +235 -0
- package/server/project-hmr-files.ts +215 -0
- package/server/project-install-roots.ts +210 -0
- package/server/project-kinds.ts +71 -0
- package/server/project-mcp-servers.ts +82 -0
- package/server/project-module-freshness.ts +109 -0
- package/server/project-module-instance.ts +375 -0
- package/server/project-optimize-deps-entries.ts +827 -0
- package/server/project-output-writer.ts +679 -0
- package/server/project-package-origin.ts +63 -0
- package/server/project-root-surface.ts +831 -0
- package/server/project-scratch-path.ts +47 -0
- package/server/project-script-hmr.ts +619 -0
- package/server/project-serving-plugins.ts +236 -0
- package/server/project-tools.ts +653 -0
- package/server/project-validation.ts +250 -0
- package/server/project-verbs.ts +127 -0
- package/server/project-view.ts +52 -0
- package/server/project-watch.ts +1134 -0
- package/server/project-work-coordinator.ts +288 -0
- package/server/provider-credentials.ts +331 -0
- package/server/recent-projects-store.ts +98 -0
- package/server/redact-secrets.ts +71 -0
- package/server/repository-presence.ts +267 -0
- package/server/routes/account.ts +357 -0
- package/server/routes/agents.ts +60 -0
- package/server/routes/assets.ts +154 -0
- package/server/routes/build.ts +13 -0
- package/server/routes/collaboration.ts +595 -0
- package/server/routes/configurations.ts +419 -0
- package/server/routes/context.ts +264 -0
- package/server/routes/control-plane.ts +1811 -0
- package/server/routes/logs.ts +272 -0
- package/server/routes/project-identity.ts +302 -0
- package/server/routes/project-open.ts +429 -0
- package/server/routes/project-source.ts +686 -0
- package/server/routes/project-state.ts +383 -0
- package/server/routes/relay.ts +1029 -0
- package/server/routes/route-helpers.ts +29 -0
- package/server/routes/served-modules.ts +138 -0
- package/server/routes/session-tabs.ts +196 -0
- package/server/routes/settings.ts +121 -0
- package/server/routes/share-control.ts +486 -0
- package/server/routes/themes.ts +116 -0
- package/server/routes/tools.ts +230 -0
- package/server/routes/worktrees.ts +595 -0
- package/server/scoped-game-css.ts +461 -0
- package/server/server-utils.ts +1194 -0
- package/server/session-product.ts +112 -0
- package/server/session-registry.ts +230 -0
- package/server/share-claims.ts +138 -0
- package/server/share-host.ts +526 -0
- package/server/share-session-gateway.ts +1362 -0
- package/server/share-tunnel.ts +123 -0
- package/server/spawn-opener.ts +74 -0
- package/server/support/play/log-format.ts +76 -0
- package/server/support/play/session-record.ts +199 -0
- package/server/support/project/build-discipline.ts +718 -0
- package/server/support/project/inspection-node.ts +119 -0
- package/server/support/project/log-naming.ts +54 -0
- package/server/support/project/provenance.ts +290 -0
- package/server/support/project/run-name.ts +18 -0
- package/server/support/project/session-journal.ts +830 -0
- package/server/support/project/shared.ts +327 -0
- package/server/tab-bootstrap.ts +62 -0
- package/server/tab-heartbeat.ts +477 -0
- package/server/tab-lifecycle.ts +550 -0
- package/server/tab-presence.ts +1508 -0
- package/server/team-agent-mirror.ts +95 -0
- package/server/twin-auth.ts +138 -0
- package/server/vendored-lock-recorder.ts +968 -0
- package/server/worktree-identity.ts +121 -0
- package/server/worktree-management.ts +398 -0
- package/server/worktree-retention.d.mts +13 -0
- package/server/worktree-retention.mjs +205 -0
- package/src/EditorContext.tsx +169 -0
- package/src/account.ts +333 -0
- package/src/action-registry.ts +532 -0
- package/src/active-product.ts +74 -0
- package/src/active-project.ts +155 -0
- package/src/adapter-editor-config.ts +25 -0
- package/src/adapter-observation.ts +49 -0
- package/src/animation/stage-transport.ts +379 -0
- package/src/animation/three-clips-subject.ts +172 -0
- package/src/api/asset-library-wire.ts +45 -0
- package/src/api/assets.ts +365 -0
- package/src/api/base.ts +10 -0
- package/src/api/build.ts +99 -0
- package/src/api/git-wire.ts +56 -0
- package/src/api/logs.ts +92 -0
- package/src/api/project-identity.ts +74 -0
- package/src/api/project-open.ts +355 -0
- package/src/api/project-source.ts +162 -0
- package/src/api/project-state.ts +107 -0
- package/src/api/relay.ts +268 -0
- package/src/api/settings.ts +36 -0
- package/src/api/themes.ts +45 -0
- package/src/api/worktrees.ts +257 -0
- package/src/asset-compare-core.ts +171 -0
- package/src/asset-compare.ts +294 -0
- package/src/asset-editor-context.tsx +100 -0
- package/src/asset-events.ts +97 -0
- package/src/asset-inspector-actions.ts +87 -0
- package/src/asset-preview-framing.ts +357 -0
- package/src/asset-preview.ts +2802 -0
- package/src/asset-selection-viewer-registry.ts +113 -0
- package/src/asset-selection.ts +133 -0
- package/src/asset-workflow/asset-capabilities.ts +344 -0
- package/src/asset-workflow/asset-import-jobs.ts +106 -0
- package/src/asset-workflow/asset-ledger-backend.ts +126 -0
- package/src/asset-workflow/asset-ledger.ts +156 -0
- package/src/asset-workflow/asset-materialization-report.ts +140 -0
- package/src/asset-workflow/asset-pack-manifest.ts +320 -0
- package/src/asset-workflow/asset-types.ts +142 -0
- package/src/asset-workflow/asset-workflow-quality.ts +61 -0
- package/src/asset-workflow/audio-preview-player.ts +193 -0
- package/src/asset-workflow/audio-waveform.ts +22 -0
- package/src/asset-workflow/cloud-asset-client.ts +263 -0
- package/src/asset-workflow/folder-preview.ts +345 -0
- package/src/asset-workflow/hosted-asset-materialization.ts +236 -0
- package/src/asset-workflow/image-view-scale.ts +32 -0
- package/src/asset-workflow/import-contract.ts +124 -0
- package/src/asset-workflow/ledger-write-lock.ts +244 -0
- package/src/asset-workflow/model-inspection.ts +818 -0
- package/src/asset-workflow/pixi-spritesheet.ts +197 -0
- package/src/asset-workflow/preview-resource-lifetime.ts +44 -0
- package/src/asset-workflow/project-asset-commands.ts +23 -0
- package/src/asset-workflow/project-asset-health.ts +139 -0
- package/src/asset-workflow/project-asset-operations.ts +154 -0
- package/src/asset-workflow/project-asset-roots.ts +68 -0
- package/src/asset-workflow/project-content.ts +288 -0
- package/src/asset-workflow/project-source-index.ts +550 -0
- package/src/asset-workflow/thumbnail-system.ts +256 -0
- package/src/authoring/active-adapter.ts +199 -0
- package/src/authoring/active-systems.ts +422 -0
- package/src/authoring/adapter-key.ts +18 -0
- package/src/authoring/authoring-asset-url.ts +27 -0
- package/src/authoring/bootstrap-state.ts +49 -0
- package/src/authoring/boundary-authoring-adapter.ts +184 -0
- package/src/authoring/breakpoint-state.ts +43 -0
- package/src/authoring/canvas-scene-guides.ts +76 -0
- package/src/authoring/component-instance-root.ts +171 -0
- package/src/authoring/composite-authoring-adapter.ts +2110 -0
- package/src/authoring/consumer-actions.ts +520 -0
- package/src/authoring/css-numeric-style.ts +97 -0
- package/src/authoring/design-time-layers.ts +849 -0
- package/src/authoring/design-time-mount-registry.ts +235 -0
- package/src/authoring/design-time-settle.ts +343 -0
- package/src/authoring/edit-mode-authoring.ts +619 -0
- package/src/authoring/eyedropper-session.ts +60 -0
- package/src/authoring/instance-source-menu-register.ts +13 -0
- package/src/authoring/instance-source-menu.ts +135 -0
- package/src/authoring/layered-pick.ts +183 -0
- package/src/authoring/live-gesture-lock.ts +50 -0
- package/src/authoring/live-object-transform.ts +62 -0
- package/src/authoring/mount-failure-report.ts +154 -0
- package/src/authoring/mounted-root-subjects.ts +144 -0
- package/src/authoring/no-authoring-adapter.ts +55 -0
- package/src/authoring/null-inspection-subjects.tsx +75 -0
- package/src/authoring/object3d-document-persistence.ts +106 -0
- package/src/authoring/object3d-document-session-registry.ts +120 -0
- package/src/authoring/object3d-document-session.ts +1326 -0
- package/src/authoring/object3d-gesture-controller.ts +113 -0
- package/src/authoring/panel-authoring.ts +121 -0
- package/src/authoring/prefab-instance-inspector-section.tsx +237 -0
- package/src/authoring/prefab-instance-section-model.ts +55 -0
- package/src/authoring/project-authoring-session.ts +105 -0
- package/src/authoring/provenance.ts +99 -0
- package/src/authoring/quarks-particle-systems.ts +19 -0
- package/src/authoring/react-canvas-navigation.ts +255 -0
- package/src/authoring/react-design-canvas-style.ts +20 -0
- package/src/authoring/react-story-board.ts +937 -0
- package/src/authoring/selection-scope.ts +195 -0
- package/src/authoring/shell-document-ops.ts +169 -0
- package/src/authoring/shell-object3d-document-write-policy.ts +108 -0
- package/src/authoring/shell-viewport-policy.ts +48 -0
- package/src/authoring/source-object3d-authoring-adapter.ts +526 -0
- package/src/authoring/stories-scope.ts +35 -0
- package/src/authoring/story-board-chrome-fit.ts +107 -0
- package/src/authoring/story-board-presentation.ts +111 -0
- package/src/authoring/three-projection-core.ts +226 -0
- package/src/authoring/viewport-pick-context.ts +40 -0
- package/src/authoring/viewport-raycast.ts +240 -0
- package/src/authoring/viewport-tool-context.ts +73 -0
- package/src/authoring/world-canvas-viewport-state.ts +35 -0
- package/src/authoring/world-hidden-viewport.ts +152 -0
- package/src/authoring/world-pan-state.ts +198 -0
- package/src/authoring/world-session-state.ts +101 -0
- package/src/authoring/write-pipe.ts +173 -0
- package/src/availability-tick.ts +66 -0
- package/src/bitmap-label.ts +120 -0
- package/src/blender-tab-metrics.ts +161 -0
- package/src/board-open-actions.ts +20 -0
- package/src/boot-routing.ts +391 -0
- package/src/build-identity.ts +15 -0
- package/src/bytes-codec.ts +62 -0
- package/src/camera-authoring.ts +175 -0
- package/src/cancellation-reason.ts +58 -0
- package/src/canvas-preview-frames.ts +482 -0
- package/src/capture-camera-pose.ts +77 -0
- package/src/chrome-registry.ts +159 -0
- package/src/chrome-slot-registry.ts +91 -0
- package/src/collaboration-client.ts +264 -0
- package/src/collaboration-presence.ts +41 -0
- package/src/command-dispatch.ts +19 -0
- package/src/command-listener.ts +2743 -0
- package/src/command-registry.ts +70 -0
- package/src/component-board-registry.ts +205 -0
- package/src/component-states-registry.ts +200 -0
- package/src/components/AgentPresentationNotice.tsx +75 -0
- package/src/components/AlignToolbar.tsx +204 -0
- package/src/components/AppRoot.tsx +394 -0
- package/src/components/ApplicationMenus.tsx +415 -0
- package/src/components/AssetBrowser.tsx +2843 -0
- package/src/components/AssetEditorShell.tsx +216 -0
- package/src/components/AssetInspectorToolSection.tsx +124 -0
- package/src/components/BoardRulers.tsx +354 -0
- package/src/components/CameraInfo.tsx +81 -0
- package/src/components/CanvasSceneViewport.tsx +556 -0
- package/src/components/CapabilityCoverageSection.tsx +185 -0
- package/src/components/CenterDocuments.tsx +22 -0
- package/src/components/ChromeSlot.tsx +20 -0
- package/src/components/CodeView.tsx +470 -0
- package/src/components/CollaborationHeaderControl.css +74 -0
- package/src/components/CompactInspectorCard.tsx +190 -0
- package/src/components/CompactInspectorShell.tsx +39 -0
- package/src/components/ConsolePanel.css +55 -0
- package/src/components/ConsolePanel.tsx +270 -0
- package/src/components/DefaultEditorLayout.tsx +106 -0
- package/src/components/DocumentHeaderStrip.tsx +96 -0
- package/src/components/DocumentShelfRail.tsx +45 -0
- package/src/components/DocumentThumbnail.tsx +345 -0
- package/src/components/EditorLeaseGuard.tsx +372 -0
- package/src/components/ErrorBanner.tsx +123 -0
- package/src/components/FolderPreviewTile.tsx +159 -0
- package/src/components/GameHierarchy.tsx +3842 -0
- package/src/components/GameplaySessionTimeline.tsx +295 -0
- package/src/components/InspectionProjection.tsx +968 -0
- package/src/components/Inspector.tsx +233 -0
- package/src/components/InspectorCanvasPreview.tsx +35 -0
- package/src/components/InspectorFieldsSection.tsx +290 -0
- package/src/components/InspectorObjectPreview.tsx +57 -0
- package/src/components/InspectorStoriesSection.tsx +92 -0
- package/src/components/InspectorToolSection.tsx +96 -0
- package/src/components/InspectorTransformSection.tsx +245 -0
- package/src/components/LightExplorerPanel.tsx +433 -0
- package/src/components/MediaProperties.tsx +145 -0
- package/src/components/NonThreeAuthoringBootstrap.tsx +19 -0
- package/src/components/Object3DDocumentToolbar.css +100 -0
- package/src/components/Object3DDocumentToolbar.tsx +454 -0
- package/src/components/Object3DDocumentViewport.tsx +58 -0
- package/src/components/ProjectHeader.css +617 -0
- package/src/components/ProjectHeader.tsx +328 -0
- package/src/components/ProjectLayout.tsx +249 -0
- package/src/components/ReactCanvasControls.tsx +284 -0
- package/src/components/RootSelectionOverlay.tsx +3162 -0
- package/src/components/RootTextEditor.tsx +79 -0
- package/src/components/SaveStatus.tsx +70 -0
- package/src/components/StageHost.tsx +1954 -0
- package/src/components/StageOverlays.tsx +21 -0
- package/src/components/StartupErrorScreen.tsx +76 -0
- package/src/components/StartupLoadingScreen.tsx +65 -0
- package/src/components/StatsOverlay.tsx +78 -0
- package/src/components/SurfaceStateOverlay.tsx +24 -0
- package/src/components/ToolContributionSurfaces.tsx +65 -0
- package/src/components/ToolHost.tsx +370 -0
- package/src/components/ToolObject3DPreview.tsx +39 -0
- package/src/components/Toolbar.tsx +595 -0
- package/src/components/TransientHint.tsx +44 -0
- package/src/components/TransportStrip.tsx +174 -0
- package/src/components/VersionControlSection.tsx +470 -0
- package/src/components/VgaiLogo.css +83 -0
- package/src/components/VgaiLogo.tsx +35 -0
- package/src/components/ViewportControlsHint.tsx +60 -0
- package/src/components/ViewportFurniture.tsx +401 -0
- package/src/components/ViewportOverlay.tsx +145 -0
- package/src/components/ViewportOverlaysMenu.tsx +153 -0
- package/src/components/ViewportShadingMenu.tsx +300 -0
- package/src/components/ViewportViewMenu.tsx +101 -0
- package/src/components/WorkspaceDocumentSurface.tsx +204 -0
- package/src/components/WorkspaceUtilitySurface.tsx +22 -0
- package/src/components/WorktreeSwitcher.css +239 -0
- package/src/components/WorktreeSwitcher.tsx +890 -0
- package/src/components/account-documents.tsx +1162 -0
- package/src/components/asset-documents.tsx +812 -0
- package/src/components/asset-editor-persistence.ts +216 -0
- package/src/components/asset-selection-section.tsx +535 -0
- package/src/components/asset-thumbnails.tsx +312 -0
- package/src/components/asset-viewers/AudioViewer.tsx +201 -0
- package/src/components/asset-viewers/EntityModelDocument.tsx +122 -0
- package/src/components/asset-viewers/EnvironmentAssetDocument.tsx +440 -0
- package/src/components/asset-viewers/GenericJsonViewer.tsx +102 -0
- package/src/components/asset-viewers/ImageViewer.tsx +300 -0
- package/src/components/asset-viewers/JsonAssetDocument.tsx +93 -0
- package/src/components/asset-viewers/LiveModuleDocument.tsx +417 -0
- package/src/components/asset-viewers/LutAssetDocument.tsx +444 -0
- package/src/components/asset-viewers/ModelAssetDocument.tsx +105 -0
- package/src/components/asset-viewers/Object3DPreview.tsx +359 -0
- package/src/components/asset-viewers/OnlineAssetDetail.tsx +421 -0
- package/src/components/asset-viewers/PasteboardModuleDocument.tsx +67 -0
- package/src/components/asset-viewers/QuarksAssetDocument.tsx +526 -0
- package/src/components/asset-viewers/ShaderAssetDocument.tsx +743 -0
- package/src/components/asset-viewers/SourceAssetViewer.tsx +281 -0
- package/src/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
- package/src/components/asset-viewers/VideoViewer.tsx +101 -0
- package/src/components/asset-viewers/shader-source.ts +144 -0
- package/src/components/asset-workflow.css +731 -0
- package/src/components/board-guides.ts +150 -0
- package/src/components/compact-inspector.css +539 -0
- package/src/components/core-utilities.tsx +90 -0
- package/src/components/editor-notifications.css +40 -0
- package/src/components/engine-workspace.css +274 -0
- package/src/components/inspector-preview-section.tsx +238 -0
- package/src/components/inspector-property-grouping.ts +64 -0
- package/src/components/inspector-revert-label.ts +20 -0
- package/src/components/inspector-selection.ts +42 -0
- package/src/components/inspector-stories-gating.ts +171 -0
- package/src/components/inspector-transform-subject.ts +11 -0
- package/src/components/inspector-transform.ts +75 -0
- package/src/components/kind-documents.tsx +500 -0
- package/src/components/palette-action-publisher.tsx +140 -0
- package/src/components/primitives/DraftColorInput.tsx +74 -0
- package/src/components/product-shell.css +1829 -0
- package/src/components/project-tool-documents.tsx +410 -0
- package/src/components/scene-documents.tsx +223 -0
- package/src/components/stage-keyboard.tsx +37 -0
- package/src/components/stage-overlay-set.tsx +107 -0
- package/src/components/stage-presence-markers.ts +478 -0
- package/src/components/standard-viewport-dressing.ts +417 -0
- package/src/components/status-contributions.tsx +403 -0
- package/src/components/tool-documents.tsx +309 -0
- package/src/components/tool-schema-form.tsx +262 -0
- package/src/components/use-after-paint.ts +41 -0
- package/src/components/use-project-image-assets.ts +86 -0
- package/src/components/viewport-header-controls.css +90 -0
- package/src/components/viewport-surface-status.tsx +55 -0
- package/src/components/workspace-history.ts +32 -0
- package/src/components/workspace-static-panel-registry.tsx +152 -0
- package/src/components/workspace-surfaces.css +621 -0
- package/src/components/world-documents.tsx +586 -0
- package/src/components/world-overlay-gestures.ts +1694 -0
- package/src/composite-screenshot.ts +1641 -0
- package/src/console-sync.ts +131 -0
- package/src/constraint-helper.ts +338 -0
- package/src/content-entry-source-registry.ts +184 -0
- package/src/coverage/authoring-seam-evidence.ts +300 -0
- package/src/coverage/canvas-reveal.ts +192 -0
- package/src/coverage/design-time-surfaces.ts +101 -0
- package/src/coverage/live-seam-evidence.ts +11 -0
- package/src/coverage/ontology-invariants.ts +466 -0
- package/src/coverage/session-vitals.ts +501 -0
- package/src/coverage/system-seam-evidence.ts +72 -0
- package/src/crash-null-boundary.ts +36 -0
- package/src/creation-site-edit.ts +1479 -0
- package/src/creation-site-registry.ts +160 -0
- package/src/delegate-harness-registry.ts +143 -0
- package/src/document-context-registry.ts +177 -0
- package/src/document-open-registry.ts +200 -0
- package/src/document-preview-source.ts +20 -0
- package/src/document-renderer-session.ts +138 -0
- package/src/editor-api.ts +46 -0
- package/src/editor-chrome-capture.ts +139 -0
- package/src/editor-commands.ts +164 -0
- package/src/editor-console.ts +563 -0
- package/src/editor-current-view.ts +82 -0
- package/src/editor-document-probe.ts +881 -0
- package/src/editor-git-client.ts +115 -0
- package/src/editor-host-door.ts +462 -0
- package/src/editor-hotkeys.ts +842 -0
- package/src/editor-lease-view.ts +39 -0
- package/src/editor-lease.ts +415 -0
- package/src/editor-mode.ts +19 -0
- package/src/editor-notifications.ts +140 -0
- package/src/editor-presence.ts +563 -0
- package/src/editor-presentation-activity.ts +50 -0
- package/src/editor-presentation-notice.ts +42 -0
- package/src/editor-runtime.tsx +145 -0
- package/src/editor-server-response.ts +86 -0
- package/src/editor-session-attribution.ts +75 -0
- package/src/editor-session-mode.ts +54 -0
- package/src/editor-shell-store.ts +1304 -0
- package/src/editor-state-facets.ts +74 -0
- package/src/editor-styles.css +33 -0
- package/src/editor-view-presentation.ts +810 -0
- package/src/editor-viewport.ts +5302 -0
- package/src/entity-lod.ts +31 -0
- package/src/entity-object.ts +91 -0
- package/src/files/file-provider.ts +62 -0
- package/src/files/project-files.ts +264 -0
- package/src/finders/index.ts +136 -0
- package/src/finders/scenes-from-entrypoint-selection.ts +387 -0
- package/src/frame/bridge.tsx +1408 -0
- package/src/frame/product.ts +77 -0
- package/src/gameplay-dom-recording.ts +319 -0
- package/src/gameplay-export-state.ts +14 -0
- package/src/gameplay-replay.ts +417 -0
- package/src/gameplay-session-time.ts +9 -0
- package/src/gameplay-sessions.ts +204 -0
- package/src/harness-chat-types.ts +253 -0
- package/src/hierarchy-component-marks.ts +298 -0
- package/src/hierarchy-drop.ts +91 -0
- package/src/hierarchy-expansion-state.ts +80 -0
- package/src/hierarchy-header-slot.ts +52 -0
- package/src/hierarchy-internals.ts +197 -0
- package/src/hierarchy-kind-icon.ts +217 -0
- package/src/hierarchy-mark-reader.ts +73 -0
- package/src/hierarchy-menu-registry.ts +67 -0
- package/src/hierarchy-node-rows.ts +307 -0
- package/src/hierarchy-panel-view.ts +280 -0
- package/src/hierarchy-projection.ts +76 -0
- package/src/hierarchy-row-cache.ts +243 -0
- package/src/hierarchy-row-model.ts +308 -0
- package/src/hierarchy-rows.ts +11 -0
- package/src/hierarchy-walk.ts +86 -0
- package/src/history/editor-session.ts +25 -0
- package/src/history/history-commands.ts +147 -0
- package/src/history/history-delegate.ts +163 -0
- package/src/history/history-limit-notices.ts +43 -0
- package/src/history/history-service.ts +1173 -0
- package/src/history/persistence-coordinator.ts +35 -0
- package/src/history/project-file-history.ts +386 -0
- package/src/history/project-root-history-backends.ts +139 -0
- package/src/history/resource-registry.ts +209 -0
- package/src/history/snapshot-store.ts +103 -0
- package/src/history/source-history-backend.ts +546 -0
- package/src/history/types.ts +124 -0
- package/src/hmr-registration-group.ts +67 -0
- package/src/hmr-stable-react-context.ts +23 -0
- package/src/hotkeys.ts +188 -0
- package/src/inference-diagnostics.ts +69 -0
- package/src/initial-project.ts +80 -0
- package/src/inspection/active-subject.ts +578 -0
- package/src/inspection/active-surface.ts +142 -0
- package/src/inspection/compose.ts +1064 -0
- package/src/inspection/display.ts +170 -0
- package/src/inspection/document-subject.ts +109 -0
- package/src/inspection/game-subject.ts +85 -0
- package/src/inspection/model.ts +542 -0
- package/src/inspection/null-subject.ts +115 -0
- package/src/inspection/serialize.ts +357 -0
- package/src/inspection/use-active-inspection.ts +180 -0
- package/src/inspector-presentation.ts +201 -0
- package/src/inspector-section-registry.ts +221 -0
- package/src/instance-source-actions.ts +163 -0
- package/src/instanced-presentation.ts +164 -0
- package/src/js-heap.ts +71 -0
- package/src/key-actions.ts +91 -0
- package/src/keymap-presets.ts +401 -0
- package/src/layout-policy.ts +31 -0
- package/src/learn-links.ts +73 -0
- package/src/light-explorer-model.ts +134 -0
- package/src/live-canvas-frame.ts +55 -0
- package/src/live-document.ts +279 -0
- package/src/live-module-source.ts +230 -0
- package/src/live-session-registry.ts +220 -0
- package/src/live-transition.ts +633 -0
- package/src/manifest-project.ts +107 -0
- package/src/model-thumbnail.ts +523 -0
- package/src/native-selection-style.ts +202 -0
- package/src/object3d-document-write-policy.ts +137 -0
- package/src/packaged-runtime.ts +108 -0
- package/src/palettes/maya.palette.json +57 -0
- package/src/palettes/substance.palette.json +57 -0
- package/src/pasteboard-module.ts +81 -0
- package/src/performance-profiler.ts +367 -0
- package/src/performance-sources.ts +69 -0
- package/src/play-boot-phase.ts +145 -0
- package/src/presentation-surface.ts +248 -0
- package/src/project-adapter.ts +1143 -0
- package/src/project-asset-refresh.ts +26 -0
- package/src/project-declaration-refresh.ts +31 -0
- package/src/project-local-state.ts +118 -0
- package/src/project-manager.ts +243 -0
- package/src/project-module-changes.ts +163 -0
- package/src/project-module-split.ts +266 -0
- package/src/project-provenance.ts +115 -0
- package/src/project-ready.ts +42 -0
- package/src/project-session-reset.ts +67 -0
- package/src/project-shape.ts +68 -0
- package/src/project-tool-discovery.ts +66 -0
- package/src/project-tools.ts +107 -0
- package/src/project-work-types.ts +149 -0
- package/src/projection/three.ts +898 -0
- package/src/projection/types.ts +44 -0
- package/src/readiness.ts +113 -0
- package/src/reflection-probe-helper.ts +142 -0
- package/src/reported-play-state.ts +90 -0
- package/src/resolve-relative-specifier.ts +33 -0
- package/src/scene-document-plan.ts +315 -0
- package/src/scene-framing.ts +315 -0
- package/src/scene-live-open.ts +210 -0
- package/src/scene-view-fog.ts +89 -0
- package/src/scoped-game-css.ts +152 -0
- package/src/session-orphan-record.ts +193 -0
- package/src/session-tombstone.ts +126 -0
- package/src/settings/settings-provider.ts +82 -0
- package/src/settings-store.ts +345 -0
- package/src/shared-view-restore.ts +42 -0
- package/src/shell-store-door.ts +45 -0
- package/src/source-conflict.ts +122 -0
- package/src/spatial-handle-visuals.ts +332 -0
- package/src/stage-context.ts +341 -0
- package/src/stage-store-registry.ts +63 -0
- package/src/stale-chunk-recovery.ts +34 -0
- package/src/state-report-deferral.ts +73 -0
- package/src/storage/host-files-storage.ts +97 -0
- package/src/storage/http-storage.ts +174 -0
- package/src/storage/index.ts +75 -0
- package/src/storage/mem-storage.ts +149 -0
- package/src/storage/path-lock.ts +44 -0
- package/src/storage/paths.ts +26 -0
- package/src/storage/types.ts +116 -0
- package/src/stories/StoryComponentThumbnail.tsx +184 -0
- package/src/stories/StoryPreviewMount.tsx +306 -0
- package/src/stories/component-content-source.tsx +106 -0
- package/src/stories/component-states-source.ts +78 -0
- package/src/stories/compose-project-stories.ts +255 -0
- package/src/stories/pixi-story-model.ts +30 -0
- package/src/stories/prefabs-finder.ts +54 -0
- package/src/stories/prefabs-from-stories.ts +182 -0
- package/src/stories/project-story-discovery.ts +78 -0
- package/src/stories/project-story-regions.ts +24 -0
- package/src/stories/story-actions.ts +54 -0
- package/src/stories/story-capture-command.ts +124 -0
- package/src/stories/story-capture.ts +584 -0
- package/src/stories/story-declared-medium.ts +126 -0
- package/src/stories/story-discovery.ts +176 -0
- package/src/stories/story-document-openers.ts +36 -0
- package/src/stories/story-dom-runtime.ts +78 -0
- package/src/stories/story-grouping.ts +111 -0
- package/src/stories/story-lane.ts +88 -0
- package/src/stories/story-mount-turn.ts +27 -0
- package/src/stories/story-opener.ts +260 -0
- package/src/stories/story-pixi-preview.ts +408 -0
- package/src/stories/story-presentation.ts +215 -0
- package/src/stories/story-registry.ts +517 -0
- package/src/stories/story-three-preview.ts +807 -0
- package/src/stories/three-story-model.ts +96 -0
- package/src/story-three-preview-runtime.ts +56 -0
- package/src/surface-keyboard.ts +112 -0
- package/src/surface-state.ts +124 -0
- package/src/tab-bootstrap.js +628 -0
- package/src/tab-census.ts +198 -0
- package/src/tab-lifecycle-client.ts +196 -0
- package/src/theme-library.ts +844 -0
- package/src/theme-preference.ts +378 -0
- package/src/theme.css +3437 -0
- package/src/three-viewport/bone-selection-highlight.ts +119 -0
- package/src/three-viewport/camera-fit.ts +41 -0
- package/src/three-viewport/interactive-renderer.ts +132 -0
- package/src/three-viewport/selection-brackets.ts +310 -0
- package/src/three-viewport/selection-outline.ts +183 -0
- package/src/three-viewport/skeleton-helper.ts +61 -0
- package/src/three-viewport/source-color.ts +167 -0
- package/src/three-viewport/studio-environment.ts +96 -0
- package/src/three-viewport-presentation.ts +23 -0
- package/src/tool-contribution-play.ts +74 -0
- package/src/tool-loader.ts +1798 -0
- package/src/transform-mode-request.ts +57 -0
- package/src/transient-hint.ts +78 -0
- package/src/trigger-volume-helper.ts +116 -0
- package/src/ui-source/adapter-region-includes.ts +241 -0
- package/src/ui-source/ensure-import.ts +132 -0
- package/src/ui-source/file-region-resolver.ts +302 -0
- package/src/ui-source/inspect.ts +775 -0
- package/src/ui-source/oid-transform.ts +1845 -0
- package/src/ui-source/plan-csf-story.ts +196 -0
- package/src/ui-source/plan-extract-component.ts +421 -0
- package/src/ui-source/plan-fork-component.ts +621 -0
- package/src/ui-source/plan-named-style.ts +95 -0
- package/src/ui-source/plan-source-edit.ts +353 -0
- package/src/ui-source/r3f-contract-resolver.ts +327 -0
- package/src/ui-source/r3f-diagnostic-index.ts +165 -0
- package/src/ui-source/r3f-environment-binding.ts +133 -0
- package/src/ui-source/r3f-joint-binding.ts +251 -0
- package/src/ui-source/r3f-lod-binding.ts +91 -0
- package/src/ui-source/r3f-particle-binding.ts +235 -0
- package/src/ui-source/r3f-physics-binding.ts +483 -0
- package/src/ui-source/r3f-project-contracts.ts +444 -0
- package/src/ui-source/relative-import-specifier.ts +34 -0
- package/src/ui-source/reparent-guard.ts +544 -0
- package/src/ui-source/source-edit-request.ts +97 -0
- package/src/ui-source/source-write-backend.ts +618 -0
- package/src/ui-source/syntactic-prop-specs.ts +296 -0
- package/src/ui-source/tier-source-write-backend.ts +279 -0
- package/src/ui-source/ts-ast.ts +171 -0
- package/src/ui-source/utility-class-support.ts +169 -0
- package/src/ui-source/write-component-default.ts +133 -0
- package/src/ui-source/writer.ts +1989 -0
- package/src/viewport-activation-timings.ts +840 -0
- package/src/viewport-authoring-policy.ts +186 -0
- package/src/viewport-controls-hint.ts +57 -0
- package/src/viewport-door.ts +237 -0
- package/src/viewport-shading-boundary.ts +12 -0
- package/src/vite-error-surface.ts +141 -0
- package/src/wait-until.ts +37 -0
- package/src/workspace-areas.ts +156 -0
- package/src/workspace-aux-commands.ts +11 -0
- package/src/workspace-available-documents.ts +127 -0
- package/src/workspace-core-utilities.ts +31 -0
- package/src/workspace-document-ids.ts +59 -0
- package/src/workspace-document-registry.ts +612 -0
- package/src/workspace-document-restore.ts +145 -0
- package/src/workspace-host-commands.ts +141 -0
- package/src/workspace-persistence-gate.ts +40 -0
- package/src/workspace-play-utilities.ts +44 -0
- package/src/workspace-presets.ts +425 -0
- package/src/workspace-regions.ts +294 -0
- package/src/workspace-state-persistence.ts +536 -0
- package/src/workspace-static-panels.ts +73 -0
- package/src/workspace-status-registry.ts +121 -0
- package/src/workspace-style.ts +239 -0
- package/src/workspace-utility-commands.ts +74 -0
- package/src/workspace-utility-registry.ts +263 -0
- package/src/workspace-viewport-rect.ts +97 -0
- package/src/world-adoption.ts +115 -0
- package/src/world-document-routing.ts +104 -0
- package/vite-plugin-creation-site-write.ts +184 -0
- package/vite-plugin-creation-site.ts +80 -0
- package/vite-plugin-game-static.ts +303 -0
- package/vite-plugin-module-doorways.ts +336 -0
- package/vite-plugin-product-contributions.ts +197 -0
- package/vite-plugin-project-game-static.ts +125 -0
- package/vite-plugin-project-jsx-js.ts +65 -0
- package/vite-plugin-project-root-absolute-assets.ts +359 -0
- package/vite-plugin-shared-react.ts +420 -0
- package/vite-plugin-shared-three.ts +203 -0
- package/vite-plugin-ui-oid.ts +2106 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The asset document shell — the frame an open asset lives in, and NOTHING
|
|
3
|
+
* about how it is inspected.
|
|
4
|
+
*
|
|
5
|
+
* "What is an asset in three.js but a hierarchical group of other three.js
|
|
6
|
+
* assets" (owner, 2026-08-07). An asset document is the three paradigm scoped
|
|
7
|
+
* to a SUBTREE — Unity's prefab-isolation mode: same viewport, same hierarchy,
|
|
8
|
+
* same inspector box, only the root changed. So the ordinary inspector rides
|
|
9
|
+
* over an asset document exactly as it rides over the scene: the same box in
|
|
10
|
+
* the same corner, draggable, minimizable, expandable to the same column, with
|
|
11
|
+
* the same per-surface preference (`inspection/display.ts` resolves it for the
|
|
12
|
+
* `asset-lab` surface like any other). This shell renders none of it.
|
|
13
|
+
*
|
|
14
|
+
* What it owns is the two things that make the document a SUBJECT PRODUCER:
|
|
15
|
+
*
|
|
16
|
+
* - it activates the asset-editor context, which is what makes the active
|
|
17
|
+
* inspection surface `asset-lab` (`inspection/active-surface.ts`);
|
|
18
|
+
* - it registers the document's SELECTION CONTEXT and publishes the
|
|
19
|
+
* document's own subject description (`inspection/document-subject.ts`).
|
|
20
|
+
*
|
|
21
|
+
* The selection context is the load-bearing half, and every asset document
|
|
22
|
+
* registers one even with nothing to select. Registering it is how a document
|
|
23
|
+
* says "I am the subject": without it the Inspector falls back to the shared
|
|
24
|
+
* entity selection, and an image viewer would show whatever was picked in the
|
|
25
|
+
* scene before it was opened. A document with live authoring of its own (the
|
|
26
|
+
* Object3D editor) passes `selection` and its picked part flows through; a
|
|
27
|
+
* document without passes nothing and gets `{adapter: null, nodeId: null}`,
|
|
28
|
+
* which resolves to its own identity floor.
|
|
29
|
+
*
|
|
30
|
+
* The identity row is where that floor lives: even a document with no sections
|
|
31
|
+
* at all says what it is, what kind it is, and where it came from — and no
|
|
32
|
+
* section of its own stands in for that row, because identity is a property of
|
|
33
|
+
* the SUBJECT (`inspection/model.ts`).
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import { type ReactNode, useEffect, useRef } from 'react';
|
|
37
|
+
import { activateAssetEditorContext } from '../asset-editor-context';
|
|
38
|
+
import { publishDocumentInspectionSubject } from '../inspection/document-subject';
|
|
39
|
+
import type { InspectionSection } from '../inspection/model';
|
|
40
|
+
import type { NullInspectionSubject } from '../inspection/null-subject';
|
|
41
|
+
import {
|
|
42
|
+
registerWorkspaceDocumentSelection,
|
|
43
|
+
type WorkspaceDocumentSelection,
|
|
44
|
+
} from '../workspace-document-registry';
|
|
45
|
+
|
|
46
|
+
/** What a document with no authoring of its own selects: itself. */
|
|
47
|
+
const DOCUMENT_IS_THE_SUBJECT: WorkspaceDocumentSelection = { adapter: null, nodeId: null };
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The part of a document subject whose change can alter the Inspector's
|
|
51
|
+
* structure. Function identities deliberately stay out of this key: render
|
|
52
|
+
* functions and field IO are read through `descriptionRef` below, so a parent
|
|
53
|
+
* render updates them without feeding the Inspector's own notification back
|
|
54
|
+
* into another publication.
|
|
55
|
+
*/
|
|
56
|
+
function subjectPublicationKey(subject: NullInspectionSubject): string {
|
|
57
|
+
return JSON.stringify({
|
|
58
|
+
id: subject.id,
|
|
59
|
+
title: subject.title,
|
|
60
|
+
hint: subject.hint,
|
|
61
|
+
kindLabel: subject.kindLabel,
|
|
62
|
+
note: subject.note,
|
|
63
|
+
sections: subject.sections.map((section) => ({
|
|
64
|
+
id: section.id,
|
|
65
|
+
title: section.title,
|
|
66
|
+
order: section.order,
|
|
67
|
+
description: section.description,
|
|
68
|
+
defaultOpen: section.defaultOpen,
|
|
69
|
+
testId: section.testId,
|
|
70
|
+
keepMounted: section.keepMounted,
|
|
71
|
+
railGroup: section.railGroup,
|
|
72
|
+
bodyKind: section.body.kind,
|
|
73
|
+
})),
|
|
74
|
+
quickActions: subject.quickActions?.map((action) => ({
|
|
75
|
+
id: action.id,
|
|
76
|
+
title: action.title,
|
|
77
|
+
label: action.label,
|
|
78
|
+
placement: action.placement,
|
|
79
|
+
pressed: action.pressed,
|
|
80
|
+
disabled: action.disabled,
|
|
81
|
+
})),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The three optional props below are spelled `?: T | undefined` rather than
|
|
87
|
+
* `?: T`, because `AssetEditorShell` PASSES ITS OWN THROUGH: under
|
|
88
|
+
* `exactOptionalPropertyTypes` an explicit `undefined` is not the same as an
|
|
89
|
+
* absent key, so `sections={sections}` on a shell whose own `sections` is
|
|
90
|
+
* optional is a type error against `?: T`. Undefined is a value this component
|
|
91
|
+
* genuinely handles (`sections ?? []`, `status &&`, `selection?.()`) — the
|
|
92
|
+
* widened type says that, where a conditional spread at the one call site would
|
|
93
|
+
* only hide it.
|
|
94
|
+
*/
|
|
95
|
+
interface AssetEditorSubjectProps {
|
|
96
|
+
documentId: string;
|
|
97
|
+
active?: boolean;
|
|
98
|
+
type: string;
|
|
99
|
+
title: string;
|
|
100
|
+
/** This document's own inspection sections, for the subject it publishes
|
|
101
|
+
* when nothing inside it is picked. Identity (name/kind/provenance) is
|
|
102
|
+
* composed from `title`/`type`/`status` — a document always has one, even
|
|
103
|
+
* with no sections at all. */
|
|
104
|
+
sections?: readonly InspectionSection[] | undefined;
|
|
105
|
+
status?: string | undefined;
|
|
106
|
+
/** What is picked INSIDE this document, for a document with authoring of
|
|
107
|
+
* its own. Read on demand (the registry calls it), so it may close over
|
|
108
|
+
* live state that changes without re-registering. */
|
|
109
|
+
selection?: (() => WorkspaceDocumentSelection | null) | undefined;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* The non-visual half of an Asset Lab document. Kept separate from the frame
|
|
114
|
+
* so project-owned contribution UIs can publish the standard subject without
|
|
115
|
+
* sending React elements across the project/editor runtime boundary.
|
|
116
|
+
*/
|
|
117
|
+
export function AssetEditorSubject({
|
|
118
|
+
documentId,
|
|
119
|
+
active = true,
|
|
120
|
+
type,
|
|
121
|
+
title,
|
|
122
|
+
sections,
|
|
123
|
+
status,
|
|
124
|
+
selection,
|
|
125
|
+
}: AssetEditorSubjectProps) {
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
if (!active) return;
|
|
128
|
+
return activateAssetEditorContext({
|
|
129
|
+
documentId,
|
|
130
|
+
title,
|
|
131
|
+
type,
|
|
132
|
+
...(status ? { status } : {}),
|
|
133
|
+
});
|
|
134
|
+
}, [active, documentId, status, title, type]);
|
|
135
|
+
|
|
136
|
+
// ONE owner for this document's selection context (the registry keys by
|
|
137
|
+
// document id, so a second registrant would silently displace the first and
|
|
138
|
+
// take the entry with it on unmount). The ref keeps the registration stable
|
|
139
|
+
// while the provider it delegates to is free to change every render.
|
|
140
|
+
const selectionRef = useRef(selection);
|
|
141
|
+
selectionRef.current = selection;
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
if (!active) return;
|
|
144
|
+
return registerWorkspaceDocumentSelection(
|
|
145
|
+
documentId,
|
|
146
|
+
() => selectionRef.current?.() ?? DOCUMENT_IS_THE_SUBJECT,
|
|
147
|
+
);
|
|
148
|
+
}, [active, documentId]);
|
|
149
|
+
|
|
150
|
+
// The document's subject DESCRIPTION — identity plus its own sections, in
|
|
151
|
+
// the same shape every surface's `describeSubject(null)` answer takes.
|
|
152
|
+
// The latest description is read on demand, so section IO closures remain
|
|
153
|
+
// live without publishing on every render. Publishing itself notifies the
|
|
154
|
+
// Inspector; doing it after every Inspector-driven parent render creates a
|
|
155
|
+
// notification -> render -> publication loop and React eventually throws
|
|
156
|
+
// "Maximum update depth exceeded" when an Object3D prefab opens.
|
|
157
|
+
const description: NullInspectionSubject = {
|
|
158
|
+
id: documentId,
|
|
159
|
+
title,
|
|
160
|
+
// `kindLabel` is what earns the composed identity ROW, and a document
|
|
161
|
+
// always names its kind: an Asset Lab document IS a thing with a name, a
|
|
162
|
+
// type and a provenance.
|
|
163
|
+
kindLabel: type,
|
|
164
|
+
...(status ? { note: { text: status, testId: 'asset-editor-status' } } : {}),
|
|
165
|
+
sections: sections ?? [],
|
|
166
|
+
};
|
|
167
|
+
const descriptionRef = useRef(description);
|
|
168
|
+
descriptionRef.current = description;
|
|
169
|
+
const publicationKey = subjectPublicationKey(description);
|
|
170
|
+
useEffect(() => {
|
|
171
|
+
if (!active) return;
|
|
172
|
+
return publishDocumentInspectionSubject(documentId, () => descriptionRef.current);
|
|
173
|
+
}, [active, documentId, publicationKey]);
|
|
174
|
+
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function AssetEditorShell({
|
|
179
|
+
documentId,
|
|
180
|
+
active = true,
|
|
181
|
+
type,
|
|
182
|
+
title,
|
|
183
|
+
sections,
|
|
184
|
+
status,
|
|
185
|
+
fill = false,
|
|
186
|
+
selection,
|
|
187
|
+
children,
|
|
188
|
+
}: AssetEditorSubjectProps & {
|
|
189
|
+
/** The child owns the whole viewport box and clips itself (a 3D canvas),
|
|
190
|
+
* rather than flowing and scrolling inside it. */
|
|
191
|
+
fill?: boolean;
|
|
192
|
+
children: ReactNode;
|
|
193
|
+
}) {
|
|
194
|
+
return (
|
|
195
|
+
<section
|
|
196
|
+
className="vgai-asset-editor"
|
|
197
|
+
data-testid={`asset-editor:${type}`}
|
|
198
|
+
aria-label={`${title} Asset Editor`}
|
|
199
|
+
>
|
|
200
|
+
<AssetEditorSubject
|
|
201
|
+
documentId={documentId}
|
|
202
|
+
active={active}
|
|
203
|
+
type={type}
|
|
204
|
+
title={title}
|
|
205
|
+
sections={sections}
|
|
206
|
+
status={status}
|
|
207
|
+
selection={selection}
|
|
208
|
+
/>
|
|
209
|
+
<main
|
|
210
|
+
className={`vgai-asset-editor__viewport${fill ? ' vgai-asset-editor__viewport--fill' : ''}`}
|
|
211
|
+
>
|
|
212
|
+
{children}
|
|
213
|
+
</main>
|
|
214
|
+
</section>
|
|
215
|
+
);
|
|
216
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ToolAssetInspectorAction,
|
|
3
|
+
ToolAssetInspectorContributionProps,
|
|
4
|
+
ToolContributionAsset,
|
|
5
|
+
} from '@volter/editor-sdk/contributions';
|
|
6
|
+
import { EditorIcon, editorIcons, groupLabelStyle } from '@volter/editor-sdk/widgets';
|
|
7
|
+
import { type ComponentType, useCallback, useEffect, useRef, useSyncExternalStore } from 'react';
|
|
8
|
+
import { accountVersion, contributionAccount, subscribeAccount } from '../account';
|
|
9
|
+
import { clearAssetInspectorActions, setAssetInspectorActions } from '../asset-inspector-actions';
|
|
10
|
+
import {
|
|
11
|
+
assetSelectionVersion,
|
|
12
|
+
getSelectedAsset,
|
|
13
|
+
subscribeAssetSelection,
|
|
14
|
+
} from '../asset-selection';
|
|
15
|
+
import { notify } from '../editor-notifications';
|
|
16
|
+
import { beginPageWork } from '../play-boot-phase';
|
|
17
|
+
import type { ProjectToolCatalogEntry } from '../project-tools';
|
|
18
|
+
import {
|
|
19
|
+
subscribeToolContributionPlay,
|
|
20
|
+
toolContributionPlay,
|
|
21
|
+
toolContributionPlayKey,
|
|
22
|
+
} from '../tool-contribution-play';
|
|
23
|
+
import { getToolContributionClient } from '../tool-loader';
|
|
24
|
+
import { toolContributionSurfaces } from './ToolContributionSurfaces';
|
|
25
|
+
import { ToolErrorBoundary } from './ToolHost';
|
|
26
|
+
|
|
27
|
+
function selectedAsset(): ToolContributionAsset | null {
|
|
28
|
+
const asset = getSelectedAsset();
|
|
29
|
+
if (!asset) return null;
|
|
30
|
+
return {
|
|
31
|
+
path: asset.path,
|
|
32
|
+
name: asset.name,
|
|
33
|
+
kind: asset.kind,
|
|
34
|
+
origin: asset.origin ?? 'project',
|
|
35
|
+
...(asset.sourcePath ? { sourcePath: asset.sourcePath } : {}),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Publish this section's verbs while it is mounted, and forget them when it
|
|
40
|
+
* goes away — a list that outlived its section would be a verb the human
|
|
41
|
+
* can no longer see (`asset-inspector-actions.ts`). */
|
|
42
|
+
function useAssetInspectorActions(
|
|
43
|
+
id: string,
|
|
44
|
+
assetPath: string | null,
|
|
45
|
+
): (actions: readonly ToolAssetInspectorAction[]) => void {
|
|
46
|
+
useEffect(() => () => clearAssetInspectorActions(id), [id]);
|
|
47
|
+
return useCallback(
|
|
48
|
+
(actions: readonly ToolAssetInspectorAction[]) => {
|
|
49
|
+
if (assetPath === null) return;
|
|
50
|
+
setAssetInspectorActions(id, assetPath, actions);
|
|
51
|
+
},
|
|
52
|
+
[id, assetPath],
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function AssetInspectorToolSection({
|
|
57
|
+
id,
|
|
58
|
+
title,
|
|
59
|
+
file,
|
|
60
|
+
tool,
|
|
61
|
+
Component,
|
|
62
|
+
}: {
|
|
63
|
+
id: string;
|
|
64
|
+
title: string;
|
|
65
|
+
file: string;
|
|
66
|
+
tool?: ProjectToolCatalogEntry | undefined;
|
|
67
|
+
Component: ComponentType<ToolAssetInspectorContributionProps>;
|
|
68
|
+
}) {
|
|
69
|
+
useSyncExternalStore(subscribeAssetSelection, assetSelectionVersion);
|
|
70
|
+
useSyncExternalStore(subscribeAccount, accountVersion, accountVersion);
|
|
71
|
+
useSyncExternalStore(
|
|
72
|
+
subscribeToolContributionPlay,
|
|
73
|
+
toolContributionPlayKey,
|
|
74
|
+
toolContributionPlayKey,
|
|
75
|
+
);
|
|
76
|
+
const asset = selectedAsset();
|
|
77
|
+
const setActions = useAssetInspectorActions(id, asset?.path ?? null);
|
|
78
|
+
// The same two host doors ToolHost hands every other contribution: a
|
|
79
|
+
// notice card keyed by title, and the main-thread work announcement. This
|
|
80
|
+
// section assembled its own props and had neither, so a model probe that
|
|
81
|
+
// spun the page for 45 s stalled every command with no phase named
|
|
82
|
+
// (2026-09-06).
|
|
83
|
+
const endWorkRef = useRef<(() => void) | null>(null);
|
|
84
|
+
const work = useCallback((label: string | null) => {
|
|
85
|
+
endWorkRef.current?.();
|
|
86
|
+
endWorkRef.current =
|
|
87
|
+
label === null ? null : beginPageWork(`building ${label.replace(/^building /, '')}`);
|
|
88
|
+
}, []);
|
|
89
|
+
useEffect(() => () => endWorkRef.current?.(), []);
|
|
90
|
+
const notifyCard = useCallback(
|
|
91
|
+
(notice: { tone: 'info' | 'warning' | 'error'; title: string; detail?: string }) =>
|
|
92
|
+
notify({
|
|
93
|
+
...notice,
|
|
94
|
+
id: `contribution:${id}:${notice.title}`,
|
|
95
|
+
...(notice.tone === 'warning' ? { fades: true } : {}),
|
|
96
|
+
}),
|
|
97
|
+
[id],
|
|
98
|
+
);
|
|
99
|
+
return (
|
|
100
|
+
<div
|
|
101
|
+
data-testid={`asset-inspector-tool-${id}`}
|
|
102
|
+
style={{ padding: 8, borderTop: '1px solid var(--vgai-structural-divider)', marginTop: 4 }}
|
|
103
|
+
>
|
|
104
|
+
<div style={{ ...groupLabelStyle, marginBottom: 4 }}>
|
|
105
|
+
<EditorIcon icon={editorIcons.tool.extension} tone="muted" style={{ marginRight: 4 }} />
|
|
106
|
+
{title}
|
|
107
|
+
</div>
|
|
108
|
+
<ToolErrorBoundary file={file}>
|
|
109
|
+
<Component
|
|
110
|
+
{...(tool ? { tool } : {})}
|
|
111
|
+
contributionId={id.slice(id.lastIndexOf(':') + 1)}
|
|
112
|
+
client={getToolContributionClient()}
|
|
113
|
+
surfaces={toolContributionSurfaces}
|
|
114
|
+
account={contributionAccount()}
|
|
115
|
+
play={toolContributionPlay()}
|
|
116
|
+
asset={asset}
|
|
117
|
+
setActions={setActions}
|
|
118
|
+
notify={notifyCard}
|
|
119
|
+
work={work}
|
|
120
|
+
/>
|
|
121
|
+
</ToolErrorBoundary>
|
|
122
|
+
</div>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RULERS + PERSISTENT GUIDES on the DOM component board (design ledger:
|
|
3
|
+
* snapping/guides). Figma's gesture grammar: drag OFF the top ruler to place
|
|
4
|
+
* a horizontal guide, off the left ruler for a vertical one; drag a guide to
|
|
5
|
+
* move it; drop it back on its ruler (or double-click it) to delete. Guides
|
|
6
|
+
* live in BOARD coordinates and persist per project+document
|
|
7
|
+
* (`board-guides.ts`); rendering maps them through the live pan/zoom.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { THEME } from '@volter/editor-sdk/widgets';
|
|
11
|
+
import { type ReactElement, useEffect, useRef, useState, useSyncExternalStore } from 'react';
|
|
12
|
+
import {
|
|
13
|
+
activeBreakpoint,
|
|
14
|
+
setActiveBreakpoint,
|
|
15
|
+
subscribeBreakpoint,
|
|
16
|
+
} from '../authoring/breakpoint-state';
|
|
17
|
+
import { getRootPan, subscribeRootPan } from '../authoring/world-pan-state';
|
|
18
|
+
import {
|
|
19
|
+
addBoardGuide,
|
|
20
|
+
type BoardGuide,
|
|
21
|
+
boardGuides,
|
|
22
|
+
moveBoardGuide,
|
|
23
|
+
registerBoardGuideTransform,
|
|
24
|
+
removeBoardGuide,
|
|
25
|
+
subscribeBoardGuides,
|
|
26
|
+
} from './board-guides';
|
|
27
|
+
|
|
28
|
+
const RULER = 16;
|
|
29
|
+
const GUIDE_COLOR = 'rgba(255, 82, 82, 0.9)';
|
|
30
|
+
const RULER_BG = 'rgba(18, 22, 26, 0.92)';
|
|
31
|
+
const TICK_COLOR = 'rgba(255, 255, 255, 0.28)';
|
|
32
|
+
|
|
33
|
+
/** A round tick step that keeps labels ~≥60px apart at the current zoom. */
|
|
34
|
+
function tickStep(zoom: number): number {
|
|
35
|
+
const steps = [10, 25, 50, 100, 250, 500, 1000, 2500, 5000];
|
|
36
|
+
return steps.find((s) => s * zoom >= 60) ?? 10000;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function formatTick(v: number): string {
|
|
40
|
+
return Math.abs(v) >= 1000 ? `${v / 1000}k` : String(v);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface DragState {
|
|
44
|
+
kind: 'place' | 'move';
|
|
45
|
+
axis: BoardGuide['axis'];
|
|
46
|
+
id: string | null;
|
|
47
|
+
/** Container-local pointer coordinate along the guide's axis. */
|
|
48
|
+
at: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function BoardRulers({
|
|
52
|
+
docId,
|
|
53
|
+
containerRef,
|
|
54
|
+
}: {
|
|
55
|
+
docId: string;
|
|
56
|
+
containerRef: React.RefObject<HTMLDivElement | null>;
|
|
57
|
+
}): ReactElement {
|
|
58
|
+
const view = useSyncExternalStore(subscribeRootPan, getRootPan);
|
|
59
|
+
const guides = useSyncExternalStore(subscribeBoardGuides, () => boardGuides(docId));
|
|
60
|
+
const [drag, setDrag] = useState<DragState | null>(null);
|
|
61
|
+
const layerRef = useRef<HTMLDivElement | null>(null);
|
|
62
|
+
|
|
63
|
+
// Register the live board transform so gesture overlays can convert guide
|
|
64
|
+
// coordinates into their own space (see board-guides.ts). Re-measured on
|
|
65
|
+
// every pan/zoom/guide change; a pure window resize between pans can leave
|
|
66
|
+
// it briefly stale, which only softens snapping — never breaks a write.
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
const el = containerRef.current;
|
|
69
|
+
if (!el) return;
|
|
70
|
+
const rect = el.getBoundingClientRect();
|
|
71
|
+
registerBoardGuideTransform(docId, {
|
|
72
|
+
originX: rect.left,
|
|
73
|
+
originY: rect.top,
|
|
74
|
+
panX: view.x,
|
|
75
|
+
panY: view.y,
|
|
76
|
+
zoom: view.zoom,
|
|
77
|
+
});
|
|
78
|
+
return () => registerBoardGuideTransform(docId, null);
|
|
79
|
+
}, [docId, containerRef, view.x, view.y, view.zoom]);
|
|
80
|
+
|
|
81
|
+
const toBoard = (local: number, axis: BoardGuide['axis']): number =>
|
|
82
|
+
Math.round((local - (axis === 'x' ? view.x : view.y)) / view.zoom);
|
|
83
|
+
const toLocal = (value: number, axis: BoardGuide['axis']): number =>
|
|
84
|
+
(axis === 'x' ? view.x : view.y) + value * view.zoom;
|
|
85
|
+
|
|
86
|
+
const localPoint = (e: { clientX: number; clientY: number }): { x: number; y: number } => {
|
|
87
|
+
const rect = containerRef.current?.getBoundingClientRect();
|
|
88
|
+
return rect ? { x: e.clientX - rect.left, y: e.clientY - rect.top } : { x: 0, y: 0 };
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const beginPlace = (axis: BoardGuide['axis']) => (e: React.PointerEvent) => {
|
|
92
|
+
e.preventDefault();
|
|
93
|
+
(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
|
|
94
|
+
const p = localPoint(e);
|
|
95
|
+
setDrag({ kind: 'place', axis, id: null, at: axis === 'x' ? p.x : p.y });
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const beginMove = (guide: BoardGuide) => (e: React.PointerEvent) => {
|
|
99
|
+
e.preventDefault();
|
|
100
|
+
e.stopPropagation();
|
|
101
|
+
(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
|
|
102
|
+
const p = localPoint(e);
|
|
103
|
+
setDrag({ kind: 'move', axis: guide.axis, id: guide.id, at: guide.axis === 'x' ? p.x : p.y });
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const onDragMove = (e: React.PointerEvent): void => {
|
|
107
|
+
if (!drag) return;
|
|
108
|
+
const p = localPoint(e);
|
|
109
|
+
const at = drag.axis === 'x' ? p.x : p.y;
|
|
110
|
+
setDrag({ ...drag, at });
|
|
111
|
+
if (drag.kind === 'move' && drag.id) moveBoardGuide(docId, drag.id, toBoard(at, drag.axis));
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const onDragEnd = (e: React.PointerEvent): void => {
|
|
115
|
+
if (!drag) return;
|
|
116
|
+
const p = localPoint(e);
|
|
117
|
+
const at = drag.axis === 'x' ? p.x : p.y;
|
|
118
|
+
const overRuler = at <= RULER;
|
|
119
|
+
if (drag.kind === 'place') {
|
|
120
|
+
if (!overRuler) addBoardGuide(docId, drag.axis, toBoard(at, drag.axis));
|
|
121
|
+
} else if (drag.id) {
|
|
122
|
+
if (overRuler) removeBoardGuide(docId, drag.id);
|
|
123
|
+
else moveBoardGuide(docId, drag.id, toBoard(at, drag.axis));
|
|
124
|
+
}
|
|
125
|
+
setDrag(null);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// Visible tick range along one axis.
|
|
129
|
+
const ticks = (axis: BoardGuide['axis']): number[] => {
|
|
130
|
+
const el = containerRef.current;
|
|
131
|
+
const extent = el ? (axis === 'x' ? el.clientWidth : el.clientHeight) : 0;
|
|
132
|
+
const step = tickStep(view.zoom);
|
|
133
|
+
const first = Math.ceil(toBoard(RULER, axis) / step) * step;
|
|
134
|
+
const last = toBoard(extent, axis);
|
|
135
|
+
const out: number[] = [];
|
|
136
|
+
for (let v = first; v <= last && out.length < 200; v += step) out.push(v);
|
|
137
|
+
return out;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const rulerStyle: React.CSSProperties = {
|
|
141
|
+
position: 'absolute',
|
|
142
|
+
background: RULER_BG,
|
|
143
|
+
zIndex: 61,
|
|
144
|
+
userSelect: 'none',
|
|
145
|
+
touchAction: 'none',
|
|
146
|
+
overflow: 'hidden',
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<div
|
|
151
|
+
ref={layerRef}
|
|
152
|
+
data-testid="board-rulers"
|
|
153
|
+
style={{ position: 'absolute', inset: 0, pointerEvents: 'none', zIndex: 60 }}
|
|
154
|
+
onPointerMove={onDragMove}
|
|
155
|
+
onPointerUp={onDragEnd}
|
|
156
|
+
>
|
|
157
|
+
{/* Placed guides. */}
|
|
158
|
+
{guides.map((guide) => {
|
|
159
|
+
const local = toLocal(guide.value, guide.axis);
|
|
160
|
+
const vertical = guide.axis === 'x';
|
|
161
|
+
return (
|
|
162
|
+
<div
|
|
163
|
+
key={guide.id}
|
|
164
|
+
data-testid={`board-guide-${guide.axis}-${guide.value}`}
|
|
165
|
+
title={`${guide.axis} = ${guide.value} — drag to move, drop on the ruler or double-click to remove`}
|
|
166
|
+
onPointerDown={beginMove(guide)}
|
|
167
|
+
onPointerMove={onDragMove}
|
|
168
|
+
onPointerUp={onDragEnd}
|
|
169
|
+
onDoubleClick={() => removeBoardGuide(docId, guide.id)}
|
|
170
|
+
style={{
|
|
171
|
+
position: 'absolute',
|
|
172
|
+
pointerEvents: 'auto',
|
|
173
|
+
cursor: vertical ? 'col-resize' : 'row-resize',
|
|
174
|
+
zIndex: 60,
|
|
175
|
+
...(vertical
|
|
176
|
+
? { left: local - 2, top: 0, bottom: 0, width: 5 }
|
|
177
|
+
: { top: local - 2, left: 0, right: 0, height: 5 }),
|
|
178
|
+
}}
|
|
179
|
+
>
|
|
180
|
+
<div
|
|
181
|
+
style={{
|
|
182
|
+
position: 'absolute',
|
|
183
|
+
background: GUIDE_COLOR,
|
|
184
|
+
...(vertical
|
|
185
|
+
? { left: 2, top: 0, bottom: 0, width: 1 }
|
|
186
|
+
: { top: 2, left: 0, right: 0, height: 1 }),
|
|
187
|
+
}}
|
|
188
|
+
/>
|
|
189
|
+
</div>
|
|
190
|
+
);
|
|
191
|
+
})}
|
|
192
|
+
{/* Placement/move preview line. */}
|
|
193
|
+
{drag && (
|
|
194
|
+
<div
|
|
195
|
+
style={{
|
|
196
|
+
position: 'absolute',
|
|
197
|
+
background: GUIDE_COLOR,
|
|
198
|
+
zIndex: 62,
|
|
199
|
+
...(drag.axis === 'x'
|
|
200
|
+
? { left: drag.at, top: 0, bottom: 0, width: 1 }
|
|
201
|
+
: { top: drag.at, left: 0, right: 0, height: 1 }),
|
|
202
|
+
}}
|
|
203
|
+
>
|
|
204
|
+
<span
|
|
205
|
+
style={{
|
|
206
|
+
position: 'absolute',
|
|
207
|
+
...(drag.axis === 'x' ? { top: RULER + 4, left: 4 } : { left: RULER + 4, top: 4 }),
|
|
208
|
+
fontSize: 9,
|
|
209
|
+
fontFamily: 'ui-monospace, monospace',
|
|
210
|
+
color: GUIDE_COLOR,
|
|
211
|
+
background: RULER_BG,
|
|
212
|
+
padding: '1px 3px',
|
|
213
|
+
borderRadius: 3,
|
|
214
|
+
whiteSpace: 'nowrap',
|
|
215
|
+
}}
|
|
216
|
+
>
|
|
217
|
+
{toBoard(drag.at, drag.axis)}
|
|
218
|
+
</span>
|
|
219
|
+
</div>
|
|
220
|
+
)}
|
|
221
|
+
{/* Top ruler — places HORIZONTAL guides? No: Figma grammar — the top
|
|
222
|
+
ruler measures X, and dragging DOWN from it places a horizontal
|
|
223
|
+
guide; the left ruler measures Y and places vertical guides. We
|
|
224
|
+
follow the measurement axis for ticks and Figma's pull direction
|
|
225
|
+
for placement. */}
|
|
226
|
+
<div
|
|
227
|
+
data-testid="board-ruler-top"
|
|
228
|
+
onPointerDown={beginPlace('y')}
|
|
229
|
+
style={{
|
|
230
|
+
...rulerStyle,
|
|
231
|
+
top: 0,
|
|
232
|
+
left: RULER,
|
|
233
|
+
right: 0,
|
|
234
|
+
height: RULER,
|
|
235
|
+
cursor: 'row-resize',
|
|
236
|
+
pointerEvents: 'auto',
|
|
237
|
+
}}
|
|
238
|
+
>
|
|
239
|
+
{ticks('x').map((v) => (
|
|
240
|
+
<span
|
|
241
|
+
key={v}
|
|
242
|
+
style={{
|
|
243
|
+
position: 'absolute',
|
|
244
|
+
left: toLocal(v, 'x'),
|
|
245
|
+
bottom: 0,
|
|
246
|
+
borderLeft: `1px solid ${TICK_COLOR}`,
|
|
247
|
+
height: 5,
|
|
248
|
+
}}
|
|
249
|
+
>
|
|
250
|
+
<span
|
|
251
|
+
style={{
|
|
252
|
+
position: 'absolute',
|
|
253
|
+
left: 2,
|
|
254
|
+
bottom: 3,
|
|
255
|
+
fontSize: 8,
|
|
256
|
+
color: TICK_COLOR,
|
|
257
|
+
fontFamily: 'ui-monospace, monospace',
|
|
258
|
+
}}
|
|
259
|
+
>
|
|
260
|
+
{formatTick(v)}
|
|
261
|
+
</span>
|
|
262
|
+
</span>
|
|
263
|
+
))}
|
|
264
|
+
</div>
|
|
265
|
+
{/* Left ruler. */}
|
|
266
|
+
<div
|
|
267
|
+
data-testid="board-ruler-left"
|
|
268
|
+
onPointerDown={beginPlace('x')}
|
|
269
|
+
style={{
|
|
270
|
+
...rulerStyle,
|
|
271
|
+
top: RULER,
|
|
272
|
+
left: 0,
|
|
273
|
+
bottom: 0,
|
|
274
|
+
width: RULER,
|
|
275
|
+
cursor: 'col-resize',
|
|
276
|
+
pointerEvents: 'auto',
|
|
277
|
+
}}
|
|
278
|
+
>
|
|
279
|
+
{ticks('y').map((v) => (
|
|
280
|
+
<span
|
|
281
|
+
key={v}
|
|
282
|
+
style={{
|
|
283
|
+
position: 'absolute',
|
|
284
|
+
top: toLocal(v, 'y'),
|
|
285
|
+
right: 0,
|
|
286
|
+
borderTop: `1px solid ${TICK_COLOR}`,
|
|
287
|
+
width: 5,
|
|
288
|
+
}}
|
|
289
|
+
>
|
|
290
|
+
<span
|
|
291
|
+
style={{
|
|
292
|
+
position: 'absolute',
|
|
293
|
+
top: 1,
|
|
294
|
+
right: 3,
|
|
295
|
+
fontSize: 8,
|
|
296
|
+
color: TICK_COLOR,
|
|
297
|
+
fontFamily: 'ui-monospace, monospace',
|
|
298
|
+
writingMode: 'vertical-rl',
|
|
299
|
+
}}
|
|
300
|
+
>
|
|
301
|
+
{formatTick(v)}
|
|
302
|
+
</span>
|
|
303
|
+
</span>
|
|
304
|
+
))}
|
|
305
|
+
</div>
|
|
306
|
+
<BreakpointArmedPill />
|
|
307
|
+
{/* Corner square. */}
|
|
308
|
+
<div
|
|
309
|
+
style={{
|
|
310
|
+
...rulerStyle,
|
|
311
|
+
top: 0,
|
|
312
|
+
left: 0,
|
|
313
|
+
width: RULER,
|
|
314
|
+
height: RULER,
|
|
315
|
+
borderRight: `1px solid ${THEME.border}`,
|
|
316
|
+
borderBottom: `1px solid ${THEME.border}`,
|
|
317
|
+
}}
|
|
318
|
+
/>
|
|
319
|
+
</div>
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/** The armed-BREAKPOINT cue on the board itself (blind-walk friction: the
|
|
324
|
+
* breakpoint select is sticky, and with the inspector scrolled elsewhere the
|
|
325
|
+
* only sign that edits were scoped — and frames were previewing narrow —
|
|
326
|
+
* was a dropdown nobody was looking at). One pill, click to disarm. */
|
|
327
|
+
function BreakpointArmedPill(): ReactElement | null {
|
|
328
|
+
const bp = useSyncExternalStore(subscribeBreakpoint, activeBreakpoint);
|
|
329
|
+
if (!bp) return null;
|
|
330
|
+
return (
|
|
331
|
+
<button
|
|
332
|
+
type="button"
|
|
333
|
+
data-testid="board-breakpoint-pill"
|
|
334
|
+
title="Style edits are scoped to this breakpoint — click to return to Base"
|
|
335
|
+
onClick={() => setActiveBreakpoint(null)}
|
|
336
|
+
style={{
|
|
337
|
+
position: 'absolute',
|
|
338
|
+
top: RULER + 8,
|
|
339
|
+
right: 12,
|
|
340
|
+
zIndex: 62,
|
|
341
|
+
pointerEvents: 'auto',
|
|
342
|
+
background: 'rgba(18, 22, 26, 0.92)',
|
|
343
|
+
color: THEME.accent,
|
|
344
|
+
border: `1px solid ${THEME.accent}`,
|
|
345
|
+
borderRadius: 999,
|
|
346
|
+
fontSize: 10,
|
|
347
|
+
padding: '3px 10px',
|
|
348
|
+
cursor: 'pointer',
|
|
349
|
+
}}
|
|
350
|
+
>
|
|
351
|
+
@ {bp} · editing this breakpoint — click to clear
|
|
352
|
+
</button>
|
|
353
|
+
);
|
|
354
|
+
}
|