@dailies-studio/shot-editor 0.1.0 → 0.2.0
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/dist/.vite/manifest.json +382 -0
- package/dist/assets/AgentPanel-CQejLbiX.js +2 -0
- package/dist/assets/AgentPanel-DJEphah0.css +1 -0
- package/dist/assets/AgentQuestionDialog-BqkD0kXF.js +1 -0
- package/dist/assets/CodeStudio-Dv4ihHpz.js +23 -0
- package/dist/assets/CommentsPanel-B4yhhT1T.js +1 -0
- package/dist/assets/ComponentLibraryRail-Ch_dsAru.js +1 -0
- package/dist/assets/ComponentStage-BRhRotyH.js +1 -0
- package/dist/assets/CurvePane-BjFVabKX.css +1 -0
- package/dist/assets/CurvePane-R22WzllJ.js +1 -0
- package/dist/assets/ExportDialog-CWLQWTmG.js +2 -0
- package/dist/assets/FontPicker-DWKaYL7F.js +1 -0
- package/dist/assets/FontPicker-v0IOIArM.css +1 -0
- package/dist/assets/GenerateDrawer-Bh3SqDKt.js +2 -0
- package/dist/assets/InsertDrawer-Ce1fod1L.js +1 -0
- package/dist/assets/LibraryBrowser-D9sEGz5w.js +2 -0
- package/dist/assets/MakeItYoursSection-CMO4319_.js +2 -0
- package/dist/assets/MaterialGraphCanvas-BFzl4wWR.js +23 -0
- package/dist/assets/MaterialGraphCanvas-BIUD59ik.css +1 -0
- package/dist/assets/MaterialWorkspace-CqTWqaRA.js +14 -0
- package/dist/assets/PreferencesDialog-CBf9_OoD.js +1 -0
- package/dist/assets/PresetsSection-CUEaoCVU.js +1 -0
- package/dist/assets/SoundHistory-BeS8EW1h.js +1 -0
- package/dist/assets/SoundMode-BmcZru3i.js +3 -0
- package/dist/assets/StockSounds-DdAUGRYK.js +1 -0
- package/dist/assets/TemplateFieldSection-CaeXpLFo.js +1 -0
- package/dist/assets/VersionHistoryPanel-CxG6XhNP.js +1 -0
- package/dist/assets/board-B88EPuLO.css +1 -0
- package/dist/assets/board-CL-he7SL.js +3 -0
- package/dist/assets/components-0oOSPN0l.js +1 -0
- package/dist/assets/googleFontRanges-gp32wJMo.js +1 -0
- package/dist/assets/googleFonts-BNon6M7X.js +1 -0
- package/dist/assets/iconsAndAliases-DL7gXP5j.js +1863 -0
- package/dist/assets/index-4F5NQmI8.css +1 -0
- package/dist/assets/index-BGHQGV5z.js +117 -0
- package/dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/dist/assets/libraryModel-CpIwfFha.js +1 -0
- package/dist/assets/lucide-6iK64tTB.js +9319 -0
- package/dist/assets/motionStamp-CH-Hew4E.js +1 -0
- package/dist/assets/takeMeasure-Tdg0TxEi.js +1 -0
- package/dist/assets/webmcp-BsB9gxWC.js +2 -0
- package/dist/index.html +34 -3
- package/package.json +12 -9
- package/src/addFamilies.ts +66 -0
- package/src/api.ts +1631 -55
- package/src/app/App.tsx +977 -198
- package/src/app/lazyPanel.tsx +137 -0
- package/src/app/lazySurfaces.tsx +203 -0
- package/src/audio/index.tsx +41 -10
- package/src/audio/meter.ts +485 -0
- package/src/audio/meterMath.ts +273 -0
- package/src/audio/meterStore.ts +155 -0
- package/src/audio/offlineMix.ts +289 -0
- package/src/audio/preview.ts +928 -118
- package/src/bridge.ts +15 -5
- package/src/bridgeTypes.ts +1611 -36
- package/src/channels.ts +17 -32
- package/src/fonts/googleFonts.ts +4 -0
- package/src/hostApi.ts +174 -0
- package/src/icons.tsx +770 -0
- package/src/layerWords.ts +61 -0
- package/src/main.tsx +56 -4
- package/src/panels/ResizeHandle.tsx +33 -43
- package/src/panels/agent/AgentDots.tsx +36 -0
- package/src/panels/agent/AgentPanel.tsx +119 -43
- package/src/panels/agent/AgentQuestionDialog.tsx +202 -0
- package/src/panels/agent/agent.css +113 -97
- package/src/panels/agent/agentGate.ts +35 -0
- package/src/panels/code/CodeDefaultsPanel.tsx +345 -0
- package/src/panels/code/CodeStudio.tsx +373 -0
- package/src/panels/code/FileTree.tsx +265 -0
- package/src/panels/code/codeBufferGuard.ts +52 -0
- package/src/panels/code/codeParts.tsx +321 -0
- package/src/panels/comments/CommentComposer.tsx +239 -0
- package/src/panels/comments/CommentThread.tsx +346 -0
- package/src/panels/comments/CommentsPanel.tsx +336 -0
- package/src/panels/comments/InboxButton.tsx +131 -0
- package/src/panels/comments/MentionMenu.tsx +98 -0
- package/src/panels/comments/parts.tsx +171 -0
- package/src/panels/export/ExportDialog.tsx +919 -96
- package/src/panels/export/ExportScrim.tsx +57 -0
- package/src/panels/files/AssetsTab.tsx +656 -0
- package/src/panels/files/FilePanel.tsx +1466 -216
- package/src/panels/files/LayerMarks.tsx +40 -0
- package/src/panels/files/LeftColumn.tsx +37 -0
- package/src/panels/files/McpSection.tsx +690 -47
- package/src/panels/files/MissingAssetsNotice.tsx +60 -0
- package/src/panels/files/assetDrag.ts +79 -0
- package/src/panels/files/resourceParts.tsx +255 -0
- package/src/panels/fonts/FontPicker.tsx +762 -0
- package/src/panels/fonts/faceCache.ts +207 -0
- package/src/panels/fonts/fontPicker.css +271 -0
- package/src/panels/fonts/pickerModel.ts +265 -0
- package/src/panels/fonts/pickerRequest.ts +46 -0
- package/src/panels/header/AccountAvatar.tsx +76 -0
- package/src/panels/header/AgentChip.tsx +77 -0
- package/src/panels/header/AppMenu.tsx +213 -0
- package/src/panels/header/Header.tsx +564 -84
- package/src/panels/header/HistoryControls.tsx +31 -5
- package/src/panels/header/PresenceStack.tsx +329 -0
- package/src/panels/header/ProjectTitle.tsx +232 -0
- package/src/panels/header/ShareButton.tsx +59 -0
- package/src/panels/header/StatusBadges.tsx +358 -27
- package/src/panels/header/SyncDeletedDialog.tsx +88 -0
- package/src/panels/header/ZoomControls.tsx +46 -15
- package/src/panels/header/agentHandoff.ts +52 -0
- package/src/panels/header/leave.ts +26 -0
- package/src/panels/help/HelpSection.tsx +189 -163
- package/src/panels/insert/InsertDrawer.tsx +723 -0
- package/src/panels/insert/iconSet.ts +109 -0
- package/src/panels/inspector/ExposeDot.tsx +117 -0
- package/src/panels/inspector/FramingRows.tsx +314 -44
- package/src/panels/inspector/InspectorFooter.tsx +91 -0
- package/src/panels/inspector/InspectorHead.tsx +425 -0
- package/src/panels/inspector/InspectorPanel.tsx +408 -124
- package/src/panels/inspector/KeyframeDot.tsx +373 -0
- package/src/panels/inspector/KeyframeSection.tsx +257 -0
- package/src/panels/inspector/MarkerSection.tsx +55 -11
- package/src/panels/inspector/ParamRow.tsx +84 -53
- package/src/panels/inspector/RightColumn.tsx +152 -0
- package/src/panels/inspector/TimeSection.tsx +866 -0
- package/src/panels/inspector/animate/EaseControl.tsx +244 -0
- package/src/panels/inspector/animate/PresetsSection.tsx +135 -0
- package/src/panels/inspector/animate/ShotSection.tsx +562 -48
- package/src/panels/inspector/design/AlignRow.tsx +95 -31
- package/src/panels/inspector/design/AppearanceSection.tsx +118 -9
- package/src/panels/inspector/design/ClonerSection.tsx +323 -62
- package/src/panels/inspector/design/ComponentSection.tsx +50 -43
- package/src/panels/inspector/design/CornerSection.tsx +45 -14
- package/src/panels/inspector/design/DefinitionProps.tsx +315 -0
- package/src/panels/inspector/design/DefinitionSection.tsx +136 -0
- package/src/panels/inspector/design/DeviceSection.tsx +210 -0
- package/src/panels/inspector/design/FillSection.tsx +83 -51
- package/src/panels/inspector/design/FontField.tsx +196 -0
- package/src/panels/inspector/design/HtmlSection.tsx +23 -12
- package/src/panels/inspector/design/InstanceSection.tsx +373 -154
- package/src/panels/inspector/design/MaskSection.tsx +84 -0
- package/src/panels/inspector/design/MaterialSection.tsx +177 -0
- package/src/panels/inspector/design/MediaSection.tsx +273 -120
- package/src/panels/inspector/design/MeshSection.tsx +910 -82
- package/src/panels/inspector/design/PaintRows.tsx +550 -0
- package/src/panels/inspector/design/PlateStyleSection.tsx +177 -0
- package/src/panels/inspector/design/ShadowSection.tsx +221 -48
- package/src/panels/inspector/design/SplineFollowSection.tsx +235 -0
- package/src/panels/inspector/design/StrokeSection.tsx +228 -43
- package/src/panels/inspector/design/TemplateFieldSection.tsx +57 -0
- package/src/panels/inspector/design/TransformSection.tsx +244 -50
- package/src/panels/inspector/design/TypographySection.tsx +679 -110
- package/src/panels/inspector/layout.ts +295 -0
- package/src/panels/inspector/propValue.ts +199 -0
- package/src/panels/inspector/scene/CameraSection.tsx +232 -22
- package/src/panels/inspector/scene/EffectsSection.tsx +722 -71
- package/src/panels/inspector/scene/MakeItYoursSection.tsx +180 -0
- package/src/panels/inspector/scene/SceneDocSection.tsx +191 -0
- package/src/panels/inspector/scene/SceneSection.tsx +219 -44
- package/src/panels/inspector/scene/TransitionSection.tsx +523 -72
- package/src/panels/inspector/storyboard/StoryboardReferenceSection.tsx +593 -0
- package/src/panels/inspector/storyboard/VideoStill.tsx +120 -0
- package/src/panels/inspector/timeModel.ts +190 -0
- package/src/panels/inspector/useDocWrite.ts +438 -146
- package/src/panels/library/LibraryBrowser.tsx +435 -0
- package/src/panels/library/LibraryGrid.tsx +190 -0
- package/src/panels/library/LibraryPreviewPanel.tsx +349 -0
- package/src/panels/library/LibraryRail.tsx +84 -0
- package/src/panels/library/LibrarySoundPanel.tsx +293 -0
- package/src/panels/library/SoundHistory.tsx +245 -0
- package/src/panels/library/StockSounds.tsx +390 -0
- package/src/panels/library/libraryModel.ts +147 -0
- package/src/panels/library/stockSearch.ts +77 -0
- package/src/panels/maskMarks.tsx +117 -0
- package/src/panels/material/MaterialCommentNode.tsx +54 -0
- package/src/panels/material/MaterialGraphCanvas.tsx +861 -0
- package/src/panels/material/MaterialGraphMenu.tsx +45 -0
- package/src/panels/material/MaterialGroupNode.tsx +56 -0
- package/src/panels/material/MaterialLibrary.tsx +253 -0
- package/src/panels/material/MaterialNode.tsx +453 -0
- package/src/panels/material/MaterialNodePalette.tsx +349 -0
- package/src/panels/material/MaterialParameterControls.tsx +525 -0
- package/src/panels/material/MaterialRerouteNode.tsx +42 -0
- package/src/panels/material/MaterialWorkspace.tsx +501 -0
- package/src/panels/material/NodePreview.tsx +70 -0
- package/src/panels/material/flowModel.ts +441 -0
- package/src/panels/material/parameterValues.ts +231 -0
- package/src/panels/material/previewScheduler.ts +235 -0
- package/src/panels/material/reactFlow.css +6 -0
- package/src/panels/material/socketGlyph.ts +85 -0
- package/src/panels/material/viewportMemory.ts +58 -0
- package/src/panels/preferences/PreferencesDialog.tsx +215 -0
- package/src/panels/share/ShareComponentDialog.tsx +247 -0
- package/src/panels/stage/StageMenu.tsx +35 -5
- package/src/panels/stage/StagePanel.tsx +338 -23
- package/src/panels/stage/cellSlots.tsx +70 -0
- package/src/panels/storyboard/BoardCanvas.tsx +739 -0
- package/src/panels/storyboard/BoardCursors.tsx +158 -0
- package/src/panels/storyboard/BoardDropDialog.tsx +161 -0
- package/src/panels/storyboard/BoardPlan.tsx +42 -0
- package/src/panels/storyboard/ComponentSheet.tsx +187 -0
- package/src/panels/storyboard/ComponentStage.tsx +235 -0
- package/src/panels/storyboard/MiniSketch.tsx +173 -0
- package/src/panels/storyboard/PartPicker.tsx +64 -0
- package/src/panels/storyboard/PlanPanel.tsx +617 -0
- package/src/panels/storyboard/ReferencePreview.tsx +217 -0
- package/src/panels/storyboard/ShotBrief.tsx +360 -0
- package/src/panels/storyboard/ShotCard.tsx +251 -0
- package/src/panels/storyboard/StagePreview.tsx +348 -0
- package/src/panels/storyboard/StillThumbs.tsx +162 -0
- package/src/panels/storyboard/StoryboardView.tsx +79 -0
- package/src/panels/storyboard/board.css +1065 -0
- package/src/panels/storyboard/board.ts +12 -0
- package/src/panels/storyboard/boardClipboard.ts +111 -0
- package/src/panels/storyboard/boardOrder.ts +68 -0
- package/src/panels/storyboard/boardRows.tsx +425 -0
- package/src/panels/storyboard/liveCap.ts +90 -0
- package/src/panels/storyboard/plan.css +295 -0
- package/src/panels/storyboard/posterCache.ts +133 -0
- package/src/panels/storyboard/shotboard/ComponentPicker.tsx +373 -0
- package/src/panels/storyboard/shotboard/ImagePicker.tsx +145 -0
- package/src/panels/storyboard/shotboard/ShotBoard.tsx +292 -0
- package/src/panels/storyboard/shotboard/SketchCanvas.tsx +443 -0
- package/src/panels/storyboard/shotboard/SketchInspector.tsx +471 -0
- package/src/panels/storyboard/shotboard/SketchItem.tsx +240 -0
- package/src/panels/storyboard/shotboard/SketchLayers.tsx +130 -0
- package/src/panels/storyboard/shotboard/SketchPlay.tsx +108 -0
- package/src/panels/storyboard/shotboard/SketchStrip.tsx +178 -0
- package/src/panels/storyboard/shotboard/SketchToolFooter.tsx +99 -0
- package/src/panels/storyboard/shotboard/sketch.css +1392 -0
- package/src/panels/storyboard/shotboard/sketchModel.ts +219 -0
- package/src/panels/storyboard/storyboardDrop.ts +164 -0
- package/src/panels/studio/ComponentLibraryRail.tsx +346 -0
- package/src/panels/studio/ComponentSidePanel.tsx +355 -0
- package/src/panels/studio/ComponentStudio.tsx +243 -0
- package/src/panels/studio/ComponentsHome.tsx +318 -0
- package/src/panels/studio/ComponentsPreview.tsx +179 -0
- package/src/panels/studio/EveryUse.tsx +244 -0
- package/src/panels/studio/ThisUsePanel.tsx +679 -0
- package/src/panels/studio/componentParts.tsx +341 -0
- package/src/panels/studio/components.ts +6 -0
- package/src/panels/studio/newCodeComponent.ts +66 -0
- package/src/panels/timeline/AudioFxButton.tsx +290 -0
- package/src/panels/timeline/AudioLane.tsx +674 -85
- package/src/panels/timeline/BlockRow.tsx +154 -85
- package/src/panels/timeline/ChannelRow.tsx +378 -129
- package/src/panels/timeline/CurvePane.tsx +508 -0
- package/src/panels/timeline/Filmstrip.tsx +361 -0
- package/src/panels/timeline/GenerateDrawer.tsx +407 -0
- package/src/panels/timeline/KeyStretch.tsx +115 -0
- package/src/panels/timeline/LifespanRow.tsx +730 -47
- package/src/panels/timeline/MarkerLane.tsx +46 -8
- package/src/panels/timeline/PlayButton.tsx +91 -0
- package/src/panels/timeline/PropertyPicker.tsx +254 -0
- package/src/panels/timeline/ShotRow.tsx +400 -0
- package/src/panels/timeline/SoundMode.tsx +1406 -0
- package/src/panels/timeline/TimelineDock.tsx +2338 -272
- package/src/panels/timeline/TransportVolume.tsx +163 -0
- package/src/panels/timeline/beatRuler.ts +74 -0
- package/src/panels/timeline/curveModel.ts +500 -0
- package/src/panels/timeline/duckUnderVoice.ts +68 -0
- package/src/panels/timeline/keyframeMenu.ts +138 -0
- package/src/panels/timeline/labelWidth.ts +49 -0
- package/src/panels/timeline/marquee.ts +155 -0
- package/src/panels/timeline/model.ts +1860 -199
- package/src/panels/timeline/snap.ts +125 -43
- package/src/panels/timeline/staggerPreview.tsx +92 -0
- package/src/panels/timeline/takeMeasure.ts +72 -0
- package/src/panels/timeline/useLive.ts +48 -0
- package/src/panels/timeline/viewport.ts +234 -0
- package/src/panels/toolbar/BackChip.tsx +116 -0
- package/src/panels/toolbar/CameraViewBar.tsx +118 -49
- package/src/panels/toolbar/CanvasBar.tsx +117 -0
- package/src/panels/toolbar/InsertButton.tsx +38 -0
- package/src/panels/toolbar/IsolationTrail.tsx +156 -0
- package/src/panels/toolbar/PanelToggles.tsx +86 -0
- package/src/panels/toolbar/ShadingBar.tsx +119 -26
- package/src/panels/toolbar/ToolDockBar.tsx +329 -80
- package/src/panels/toolbar/ToolFooter.tsx +102 -0
- package/src/panels/toolbar/ViewModeBar.tsx +247 -38
- package/src/panels/toolbar/WorkPlaneBar.tsx +94 -0
- package/src/panels/toolbar/useAddRows.tsx +326 -0
- package/src/panels/toolbar/useDismiss.ts +122 -0
- package/src/panels/versions/VersionHistoryPanel.tsx +274 -0
- package/src/panels/versions/versionModel.ts +103 -0
- package/src/panels/virtualWindow.ts +271 -0
- package/src/shotTokens.css +151 -60
- package/src/stage/FrustumGizmo.tsx +504 -84
- package/src/stage/GridPlane.tsx +225 -16
- package/src/stage/NodePreviews.tsx +628 -0
- package/src/stage/PerfHud.tsx +437 -47
- package/src/stage/SplitRenderer.tsx +816 -169
- package/src/stage/StageApp.tsx +4274 -486
- package/src/stage/StageRootBoundary.tsx +114 -0
- package/src/stage/StageTools.tsx +651 -151
- package/src/stage/TransformGizmo.tsx +696 -0
- package/src/stage/adaptivePresentation.ts +145 -0
- package/src/stage/bridgeClient.ts +2522 -41
- package/src/stage/exportWorker.ts +9 -0
- package/src/stage/feed.ts +305 -14
- package/src/stage/fontPreview.ts +176 -0
- package/src/stage/frustumGeometry.ts +319 -1
- package/src/stage/furnitureTokens.ts +33 -0
- package/src/stage/gizmoMath.ts +508 -16
- package/src/stage/gpuTimer.ts +276 -0
- package/src/stage/instanceModules.ts +194 -33
- package/src/stage/interactions/move.ts +24 -5
- package/src/stage/isolation.ts +291 -33
- package/src/stage/jsSelfProfiler.ts +325 -0
- package/src/stage/main.tsx +116 -16
- package/src/stage/modalState.ts +222 -23
- package/src/stage/moduleEpoch.ts +60 -0
- package/src/stage/motionPathStage.ts +279 -0
- package/src/stage/motionPreview.ts +74 -0
- package/src/stage/overlays/Overlays.tsx +1112 -159
- package/src/stage/overlays/Rulers.tsx +495 -0
- package/src/stage/panes.ts +159 -10
- package/src/stage/project.ts +68 -3
- package/src/stage/renderScaleController.ts +730 -0
- package/src/stage/rulers.ts +129 -0
- package/src/stage/sceneExtent.ts +75 -0
- package/src/stage/shading.ts +20 -0
- package/src/stage/splineStage.ts +632 -0
- package/src/stage/stagePerformanceTelemetry.ts +717 -0
- package/src/stage/stageTheme.ts +36 -0
- package/src/stage/stageWarmup.ts +11 -0
- package/src/stage/textAutoSize.ts +124 -0
- package/src/stage/tier1Export.ts +641 -0
- package/src/stage/tokenColor.ts +14 -9
- package/src/stage/view.ts +56 -9
- package/src/stage/workingView.ts +277 -33
- package/src/state/accountPrefs.ts +261 -0
- package/src/state/agentActions.ts +173 -15
- package/src/state/agentActivity.ts +198 -0
- package/src/state/agentQuestion.ts +239 -0
- package/src/state/bootOpen.ts +42 -0
- package/src/state/cameraVerbs.ts +139 -0
- package/src/state/clientId.ts +6 -1
- package/src/state/comments.ts +1099 -0
- package/src/state/context.tsx +19 -1
- package/src/state/editorPrefs.ts +220 -0
- package/src/state/errorReports.ts +121 -0
- package/src/state/fieldWrite.ts +161 -0
- package/src/state/fontRecents.ts +70 -0
- package/src/state/fonts.ts +656 -0
- package/src/state/graphClipboard.ts +414 -0
- package/src/state/imageThumbs.ts +216 -0
- package/src/state/insert.ts +444 -67
- package/src/state/isolationTrail.ts +92 -0
- package/src/state/keyMoves.ts +134 -0
- package/src/state/keyframeClipboard.ts +177 -0
- package/src/state/keymap.ts +1153 -117
- package/src/state/layoutPrefs.ts +272 -0
- package/src/state/layouts.ts +205 -0
- package/src/state/measureMedia.ts +167 -0
- package/src/state/menu.ts +2341 -28
- package/src/state/motionStamp.ts +7 -0
- package/src/state/panelSize.ts +375 -5
- package/src/state/pendingChanges.ts +119 -0
- package/src/state/playHold.ts +78 -0
- package/src/state/playbackPreparation.ts +562 -0
- package/src/state/posterCapture.ts +242 -0
- package/src/state/presence.ts +254 -0
- package/src/state/projectComponents.ts +160 -0
- package/src/state/renderEvents.ts +298 -18
- package/src/state/runtimeErrors.ts +46 -0
- package/src/state/selection.ts +12 -0
- package/src/state/shortcuts.ts +1606 -0
- package/src/state/sketchGuide.ts +51 -0
- package/src/state/splineRefs.ts +87 -0
- package/src/state/stageHealth.ts +259 -0
- package/src/state/stageWatchdog.ts +47 -0
- package/src/state/stillStage.ts +330 -0
- package/src/state/stillThumbs.ts +474 -0
- package/src/state/store.ts +23591 -2982
- package/src/state/storyboardModel.ts +528 -0
- package/src/state/sync.ts +1257 -0
- package/src/state/syncCache.ts +159 -0
- package/src/state/triangles.ts +13 -0
- package/src/state/types.ts +1698 -55
- package/src/state/unsavedGuard.ts +49 -0
- package/src/state/viewMode.ts +200 -0
- package/src/state/webmcp.ts +1128 -0
- package/src/state/workspace.ts +1147 -0
- package/src/styles/assets-tab.css +304 -0
- package/src/styles/canvas.css +545 -0
- package/src/styles/comments.css +1435 -0
- package/src/styles/controls.css +162 -0
- package/src/styles/dialogs.css +390 -0
- package/src/styles/insert-drawer.css +586 -0
- package/src/styles/inspector-board.css +207 -0
- package/src/styles/inspector-object.css +486 -0
- package/src/styles/inspector-shot.css +252 -0
- package/src/styles/inspector.css +360 -0
- package/src/styles/left-column.css +1628 -0
- package/src/styles/library-preview.css +575 -0
- package/src/styles/library.css +512 -0
- package/src/styles/modes/code.css +569 -0
- package/src/styles/modes/component.css +1561 -0
- package/src/styles/modes/material.css +1201 -0
- package/src/styles/modes/storyboard.css +518 -0
- package/src/styles/share-component.css +49 -0
- package/src/styles/shell.css +653 -0
- package/src/styles/shot-brief.css +360 -0
- package/src/styles/states.css +76 -0
- package/src/styles/sync.css +380 -0
- package/src/styles/timeline-graph.css +384 -0
- package/src/styles/timeline-meters.css +89 -0
- package/src/styles/timeline-rows.css +1959 -0
- package/src/styles/timeline-sound.css +1003 -0
- package/src/styles/timeline.css +754 -0
- package/src/styles/tool-footer.css +525 -0
- package/src/styles/topbar.css +886 -0
- package/src/styles/versions.css +262 -0
- package/src/styles.css +72 -2921
- package/src/tools.ts +108 -23
- package/dist/assets/index-B7notge7.css +0 -1
- package/dist/assets/index-BBE6Ta9L.js +0 -52
- package/src/panels/files/icons.tsx +0 -118
- package/src/panels/header/DocSwitcher.tsx +0 -85
- package/src/panels/header/TransportBar.tsx +0 -86
- package/src/panels/inspector/animate/BlockTiming.tsx +0 -341
- package/src/panels/inspector/animate/DuringBlocks.tsx +0 -85
- package/src/panels/inspector/animate/InOutPresets.tsx +0 -57
- package/src/panels/inspector/animate/ResolvedChannels.tsx +0 -150
- package/src/panels/inspector/animate/useBlocks.ts +0 -43
- package/src/panels/material/MaterialPicker.tsx +0 -172
- package/src/panels/timeline/SceneStrip.tsx +0 -145
- package/src/panels/toolbar/AddMenu.tsx +0 -230
- package/src/stage/MoveGizmo.tsx +0 -411
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// "GUIDE: SKETCH N" (the Brief, schema v44): one storyboard sketch as the
|
|
2
|
+
// plain shapes bridge v47 carries, so the stage draws it as dashed outlines
|
|
3
|
+
// over the camera frame without any storyboard code of its own. Pure.
|
|
4
|
+
import { findSketch, sketchCardOf } from "@dailies-studio/shot/doc";
|
|
5
|
+
import type { Doc3D } from "@dailies-studio/shot/doc";
|
|
6
|
+
import { framesToSeconds } from "@dailies-studio/engine";
|
|
7
|
+
import type { ShotSketchGuide, ShotSketchGuideRect } from "../bridgeTypes.js";
|
|
8
|
+
import { formatDuration } from "../panels/timeline/model.js";
|
|
9
|
+
|
|
10
|
+
/** A box's corner on the stage, the sketch's own `radius` (sketch.ts). */
|
|
11
|
+
const BOX_RADIUS = 8;
|
|
12
|
+
/** A text item's chip says its words, cut to fit a chip. */
|
|
13
|
+
const TEXT_CHIP_MAX = 24;
|
|
14
|
+
|
|
15
|
+
function clip(text: string): string {
|
|
16
|
+
const one = text.replace(/\s+/g, " ").trim();
|
|
17
|
+
return one.length <= TEXT_CHIP_MAX ? one : `${one.slice(0, TEXT_CHIP_MAX - 1)}…`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The guide for one sketch, or null when the part does not hold it. Every
|
|
22
|
+
* image, component, text and box item is an outline with its label (a box's
|
|
23
|
+
* label, a card's label, a text's words); an arrow stays an arrow. The first
|
|
24
|
+
* label carries the sketch's time, "pile · 1.60s", the one moment it shows.
|
|
25
|
+
*/
|
|
26
|
+
export function sketchGuideOf(doc: Doc3D, partId: string, sketchId: string): ShotSketchGuide | null {
|
|
27
|
+
const found = findSketch(doc, sketchId);
|
|
28
|
+
if (found === null || found.part.id !== partId) return null;
|
|
29
|
+
const rects: ShotSketchGuideRect[] = [];
|
|
30
|
+
const arrows: ShotSketchGuide["arrows"][number][] = [];
|
|
31
|
+
for (const item of found.sketch.items) {
|
|
32
|
+
if (item.kind === "arrow") {
|
|
33
|
+
arrows.push({ from: item.from, to: item.to, ...(item.label === undefined ? {} : { label: item.label }) });
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const label =
|
|
37
|
+
item.kind === "box" ? item.label : item.kind === "text" ? clip(item.text) : (sketchCardOf(doc, item)?.label ?? "Missing");
|
|
38
|
+
rects.push({
|
|
39
|
+
at: item.position,
|
|
40
|
+
size: item.size,
|
|
41
|
+
...(item.kind === "box" ? { radius: BOX_RADIUS } : {}),
|
|
42
|
+
...(label === undefined || label.trim() === "" ? {} : { label: label.trim() }),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
const frame = found.sketch.frame;
|
|
46
|
+
const first = rects.find((rect) => rect.label !== undefined);
|
|
47
|
+
if (frame !== undefined && first !== undefined) {
|
|
48
|
+
first.label = `${first.label} · ${formatDuration(framesToSeconds(frame, doc.fps))}`;
|
|
49
|
+
}
|
|
50
|
+
return { rects, arrows };
|
|
51
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MAX_FRAMING_ZOOM,
|
|
3
|
+
MIN_FRAMING_ZOOM,
|
|
4
|
+
layerChildren,
|
|
5
|
+
meshPrimitiveOf,
|
|
6
|
+
planeDistance,
|
|
7
|
+
splineFrameScale,
|
|
8
|
+
splineProjectedRange,
|
|
9
|
+
splineReferenceProblems,
|
|
10
|
+
worldBaseTransform,
|
|
11
|
+
} from "@dailies-studio/shot/doc";
|
|
12
|
+
import type { Layer3D, Scene3D } from "@dailies-studio/shot/doc";
|
|
13
|
+
|
|
14
|
+
/** Check the graph the inspector would commit before offering a spline source. */
|
|
15
|
+
export function splineSourceIsSafe(
|
|
16
|
+
layersById: Readonly<Record<string, Layer3D>>,
|
|
17
|
+
consumerIds: readonly string[],
|
|
18
|
+
source: string,
|
|
19
|
+
site: "follow" | "cloner",
|
|
20
|
+
): boolean {
|
|
21
|
+
const consumers = new Set(consumerIds);
|
|
22
|
+
const proposed: Record<string, Layer3D> = { ...layersById };
|
|
23
|
+
for (const id of consumerIds) {
|
|
24
|
+
const layer = proposed[id];
|
|
25
|
+
if (layer === undefined) continue;
|
|
26
|
+
if (site === "follow") {
|
|
27
|
+
proposed[id] = {
|
|
28
|
+
...layer,
|
|
29
|
+
splineFollow: { ...layer.splineFollow, spline: source },
|
|
30
|
+
} as Layer3D;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (layer.kind === "cloner") {
|
|
34
|
+
proposed[id] = {
|
|
35
|
+
...layer,
|
|
36
|
+
cloner: { ...layer.cloner, mode: { kind: "spline", spline: source } },
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return !splineReferenceProblems(proposed).some((problem) =>
|
|
41
|
+
consumers.has(problem.consumer) || problem.cycle?.some((id) => consumers.has(id)) === true,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Camera rails have a stricter source contract than layer followers.
|
|
46
|
+
*
|
|
47
|
+
* The editor repeats the validator's read-only predicate so its picker never
|
|
48
|
+
* offers a choice that the next autosave would refuse. A cloner would give the
|
|
49
|
+
* source multiple simultaneous poses, while the authored base centreline must
|
|
50
|
+
* begin inside the camera distance range. Transform and visible-trim animation
|
|
51
|
+
* are allowed; runtime samples them live and falls back at the safe-band edge.
|
|
52
|
+
*/
|
|
53
|
+
export function cameraSplineSourceIsSafe(
|
|
54
|
+
scene: Scene3D,
|
|
55
|
+
sourceId: string,
|
|
56
|
+
designHeight: number,
|
|
57
|
+
): boolean {
|
|
58
|
+
const source = scene.layersById[sourceId];
|
|
59
|
+
const spline = source?.kind === "mesh" ? meshPrimitiveOf(source.mesh) : null;
|
|
60
|
+
if (source?.kind !== "mesh" || spline?.kind !== "spline") return false;
|
|
61
|
+
|
|
62
|
+
const parent = new Map<string, string>();
|
|
63
|
+
for (const [id, layer] of Object.entries(scene.layersById)) {
|
|
64
|
+
for (const child of layerChildren(layer)) parent.set(child, id);
|
|
65
|
+
}
|
|
66
|
+
const seen = new Set<string>();
|
|
67
|
+
let id: string | undefined = source.id;
|
|
68
|
+
while (id !== undefined && !seen.has(id)) {
|
|
69
|
+
seen.add(id);
|
|
70
|
+
const layer = scene.layersById[id];
|
|
71
|
+
if (layer === undefined) return false;
|
|
72
|
+
id = parent.get(id);
|
|
73
|
+
if (id !== undefined && scene.layersById[id]?.kind === "cloner") return false;
|
|
74
|
+
}
|
|
75
|
+
if (id !== undefined) return false;
|
|
76
|
+
const scale = splineFrameScale(spline, source.transform.size);
|
|
77
|
+
const rigid = worldBaseTransform(scene, source.id);
|
|
78
|
+
const projection: [number, number, number] = [
|
|
79
|
+
-rigid.rotation[2][0] * scale[0],
|
|
80
|
+
rigid.rotation[2][1] * scale[1],
|
|
81
|
+
rigid.rotation[2][2] * scale[2],
|
|
82
|
+
];
|
|
83
|
+
const range = splineProjectedRange(spline, projection, -rigid.position[2]);
|
|
84
|
+
const nearest = planeDistance(designHeight, scene.fovDeg, MAX_FRAMING_ZOOM);
|
|
85
|
+
const farthest = planeDistance(designHeight, scene.fovDeg, MIN_FRAMING_ZOOM);
|
|
86
|
+
return range.max <= -nearest && range.min >= -farthest;
|
|
87
|
+
}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
// What this editor tab tells an agent about its stage (shot/stageHealth.ts).
|
|
2
|
+
//
|
|
3
|
+
// An agent writes a Project over MCP; this tab adopts the new revision and
|
|
4
|
+
// its stage draws it. The agent's write answer waits for that draw and
|
|
5
|
+
// reports what the stage holds once it lands: the isolated pieces, the crash,
|
|
6
|
+
// the render fallbacks, the component failures and the errors of every realm
|
|
7
|
+
// the picture depends on. It is asked through the host's channel: the dev
|
|
8
|
+
// server's change feed locally (a `relay-request` for the tool `stage`,
|
|
9
|
+
// answered at `POST /api/relay/:id/result`, renderEvents.ts), the code host's
|
|
10
|
+
// relay hosted (`provideStageHealth`, browser-host boot.ts).
|
|
11
|
+
//
|
|
12
|
+
// THE WAIT IS EVENT-DRIVEN. It wakes on the stage's `onStageHealth` (bridge
|
|
13
|
+
// v35: a presentation of another revision or module epoch, a failure), on the
|
|
14
|
+
// chrome's own state and on the chrome's error log, and one timer bounds it.
|
|
15
|
+
// A background tab throttles timers, never these events, so a stage that
|
|
16
|
+
// draws answers the moment it has.
|
|
17
|
+
//
|
|
18
|
+
// THEN THE PICTURE ITSELF. A stage that drew the revision with nothing
|
|
19
|
+
// failing can still show nothing of a model (a background or a layer painted
|
|
20
|
+
// over it, a camera that does not see it), so once the wait settles on a
|
|
21
|
+
// drawn revision the stage is asked which mesh-like layers put a pixel in its
|
|
22
|
+
// frame (bridge v36 `coverage()`), bounded by `COVERAGE_WAIT_MS`, and the
|
|
23
|
+
// answer, or why there is none, rides the report.
|
|
24
|
+
import { COVERAGE_WAIT_MS, instanceComponentIdsOf } from "@dailies-studio/shot/doc";
|
|
25
|
+
import type {
|
|
26
|
+
StageCoverage,
|
|
27
|
+
StageHealthReport,
|
|
28
|
+
StageHealthRequest,
|
|
29
|
+
StageHealthSnapshot,
|
|
30
|
+
StageLink,
|
|
31
|
+
StageRuntimeError,
|
|
32
|
+
} from "@dailies-studio/shot/doc";
|
|
33
|
+
import { runtimeErrors, subscribeRuntimeErrors } from "./runtimeErrors.js";
|
|
34
|
+
import type { ShotEditorStore } from "./store.js";
|
|
35
|
+
|
|
36
|
+
/** Where a wait stands: settled (the stage drew what was asked, or failed in
|
|
37
|
+
* a way that ends the wait), still waiting on something, or answered at once
|
|
38
|
+
* because waiting cannot change the answer. */
|
|
39
|
+
interface Verdict {
|
|
40
|
+
settled: boolean;
|
|
41
|
+
/** What the stage has not done yet; null once settled. */
|
|
42
|
+
waitingFor: string | null;
|
|
43
|
+
/** Answer now, settled or not. */
|
|
44
|
+
final: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function snapshotOf(store: ShotEditorStore): { snapshot: StageHealthSnapshot | null; error: string | null } {
|
|
48
|
+
const bridge = store.stage();
|
|
49
|
+
if (bridge === null) return { snapshot: null, error: null };
|
|
50
|
+
if (typeof bridge.health !== "function") {
|
|
51
|
+
// A v34 stage cannot be here (connectStage refuses it), but a report
|
|
52
|
+
// must never throw on one.
|
|
53
|
+
return { snapshot: null, error: "the stage does not report its health: reload the editor, which rebuilds both halves" };
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
return { snapshot: bridge.health(), error: null };
|
|
57
|
+
} catch (e) {
|
|
58
|
+
return { snapshot: null, error: `the stage could not report its health: ${e instanceof Error ? e.message : String(e)}` };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function linkOf(store: ShotEditorStore, healthError: string | null): { link: StageLink; linkError: string | null } {
|
|
63
|
+
if (healthError !== null) return { link: "failed", linkError: healthError };
|
|
64
|
+
if (store.stage() !== null) return { link: "connected", linkError: null };
|
|
65
|
+
const failed = store.stageConnectError();
|
|
66
|
+
if (failed !== null) return { link: "failed", linkError: failed };
|
|
67
|
+
return { link: store.getState().stageExpected ? "connecting" : "none", linkError: null };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** What the coverage check found, or why there is none. */
|
|
71
|
+
export interface CoverageAnswer {
|
|
72
|
+
coverage: StageCoverage | null;
|
|
73
|
+
coverageError: string | null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const NOT_CHECKED: CoverageAnswer = { coverage: null, coverageError: null };
|
|
77
|
+
|
|
78
|
+
/** The report as it stands, with `verdict`'s wait state. `extraErrors` are
|
|
79
|
+
* the host's own (the hosted code host's compile worker). */
|
|
80
|
+
export function stageHealthReport(
|
|
81
|
+
store: ShotEditorStore,
|
|
82
|
+
verdict: Pick<Verdict, "settled" | "waitingFor"> = { settled: true, waitingFor: null },
|
|
83
|
+
extraErrors: readonly StageRuntimeError[] = [],
|
|
84
|
+
checked: CoverageAnswer = NOT_CHECKED,
|
|
85
|
+
): StageHealthReport {
|
|
86
|
+
const state = store.getState();
|
|
87
|
+
const { snapshot, error } = snapshotOf(store);
|
|
88
|
+
const { link, linkError } = linkOf(store, error);
|
|
89
|
+
return {
|
|
90
|
+
v: 1,
|
|
91
|
+
project: state.name,
|
|
92
|
+
savedRev: state.rev,
|
|
93
|
+
dirty: state.dirty,
|
|
94
|
+
sceneId: state.sceneId,
|
|
95
|
+
frame: state.frame,
|
|
96
|
+
link,
|
|
97
|
+
linkError,
|
|
98
|
+
stage: snapshot,
|
|
99
|
+
errors: [...runtimeErrors(), ...extraErrors],
|
|
100
|
+
editorError: state.error,
|
|
101
|
+
settled: verdict.settled,
|
|
102
|
+
waitingFor: verdict.waitingFor,
|
|
103
|
+
coverage: checked.coverage,
|
|
104
|
+
coverageError: checked.coverageError,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Ask the stage which mesh-like layers put a pixel in its frame, once the
|
|
110
|
+
* wait settled on a DRAWN revision. A wait that did not settle, a stage that
|
|
111
|
+
* could not come up or crashed (their failure is the answer) is not asked;
|
|
112
|
+
* one that cannot answer in `COVERAGE_WAIT_MS`, or refuses, says why.
|
|
113
|
+
*/
|
|
114
|
+
export async function coverageOf(
|
|
115
|
+
store: ShotEditorStore,
|
|
116
|
+
verdict: Pick<Verdict, "settled">,
|
|
117
|
+
deps: Pick<StageWaitDeps, "setTimeout" | "clearTimeout"> = TIMERS,
|
|
118
|
+
): Promise<CoverageAnswer> {
|
|
119
|
+
if (!verdict.settled) return NOT_CHECKED;
|
|
120
|
+
const bridge = store.stage();
|
|
121
|
+
const { snapshot } = snapshotOf(store);
|
|
122
|
+
if (bridge === null || snapshot === null || snapshot.crashed !== null) return NOT_CHECKED;
|
|
123
|
+
if (typeof bridge.coverage !== "function") {
|
|
124
|
+
return { coverage: null, coverageError: "the stage does not check which layers draw: reload the editor, which rebuilds both halves" };
|
|
125
|
+
}
|
|
126
|
+
let timer: unknown = null;
|
|
127
|
+
try {
|
|
128
|
+
const coverage = await Promise.race([
|
|
129
|
+
bridge.coverage(),
|
|
130
|
+
new Promise<never>((_, reject) => {
|
|
131
|
+
timer = deps.setTimeout(
|
|
132
|
+
() => reject(new Error(`the stage's check of which layers draw did not finish within ${COVERAGE_WAIT_MS / 1000} s`)),
|
|
133
|
+
COVERAGE_WAIT_MS,
|
|
134
|
+
);
|
|
135
|
+
}),
|
|
136
|
+
]);
|
|
137
|
+
return { coverage, coverageError: null };
|
|
138
|
+
} catch (e) {
|
|
139
|
+
return { coverage: null, coverageError: e instanceof Error ? e.message : String(e) };
|
|
140
|
+
} finally {
|
|
141
|
+
if (timer !== null) deps.clearTimeout(timer);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Where a wait for `request` stands now. */
|
|
146
|
+
export function judgeStage(store: ShotEditorStore, request: StageHealthRequest): Verdict {
|
|
147
|
+
const state = store.getState();
|
|
148
|
+
if (request.name !== undefined && state.name !== request.name) {
|
|
149
|
+
return {
|
|
150
|
+
settled: false,
|
|
151
|
+
final: true,
|
|
152
|
+
waitingFor:
|
|
153
|
+
state.name === null ? "this editor tab has no Project open" : `this editor tab shows ${JSON.stringify(state.name)}`,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
if (state.name === null || state.doc === null) {
|
|
157
|
+
return { settled: false, final: true, waitingFor: "this editor tab has no Project open" };
|
|
158
|
+
}
|
|
159
|
+
const { snapshot, error } = snapshotOf(store);
|
|
160
|
+
const { link } = linkOf(store, error);
|
|
161
|
+
// A stage that cannot come up, or came down, ends the wait: it is the answer.
|
|
162
|
+
if (link === "failed") return { settled: true, final: true, waitingFor: null };
|
|
163
|
+
if (link === "none") return { settled: false, final: true, waitingFor: "this editor tab has no stage mounted" };
|
|
164
|
+
if (snapshot === null) return { settled: false, final: false, waitingFor: "the stage is still loading" };
|
|
165
|
+
if (snapshot.crashed !== null) return { settled: true, final: true, waitingFor: null };
|
|
166
|
+
const want = request.rev ?? state.rev;
|
|
167
|
+
if (state.dirty) {
|
|
168
|
+
// Unsaved edits: the tab takes no revision written elsewhere until they
|
|
169
|
+
// are saved or dropped, and its stage shows neither.
|
|
170
|
+
return {
|
|
171
|
+
settled: false,
|
|
172
|
+
final: true,
|
|
173
|
+
waitingFor: `the editor holds unsaved edits of ${JSON.stringify(state.name)}, so its stage shows them and not revision ${want ?? "(none)"}`,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
const drawn = snapshot.rendered;
|
|
177
|
+
if (want === null || drawn === null || drawn.rev !== want || drawn.docId !== state.doc.id) {
|
|
178
|
+
return { settled: false, final: false, waitingFor: `the stage has not drawn revision ${want ?? "(none)"} yet` };
|
|
179
|
+
}
|
|
180
|
+
const code = request.code;
|
|
181
|
+
if (code !== undefined && instanceComponentIdsOf(state.doc).length > 0) {
|
|
182
|
+
if (code.epoch !== undefined && (drawn.epoch ?? -1) < code.epoch) {
|
|
183
|
+
return { settled: false, final: false, waitingFor: "the stage has not drawn with the code as it was just compiled" };
|
|
184
|
+
}
|
|
185
|
+
if (code.since !== undefined && snapshot.loadedAt < code.since) {
|
|
186
|
+
return { settled: false, final: false, waitingFor: "the stage has not taken the code as it was just written" };
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return { settled: true, final: true, waitingFor: null };
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface StageWaitDeps {
|
|
193
|
+
setTimeout(run: () => void, ms: number): unknown;
|
|
194
|
+
clearTimeout(timer: unknown): void;
|
|
195
|
+
/** Run `run` in the next task. */
|
|
196
|
+
nextTask(run: () => void): void;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const TIMERS: StageWaitDeps = {
|
|
200
|
+
setTimeout: (run, ms) => setTimeout(run, ms),
|
|
201
|
+
clearTimeout: (timer) => clearTimeout(timer as ReturnType<typeof setTimeout>),
|
|
202
|
+
// A message port, not a timer: a background tab throttles timers to a
|
|
203
|
+
// second, never a port.
|
|
204
|
+
nextTask: (run) => {
|
|
205
|
+
if (typeof MessageChannel !== "function") {
|
|
206
|
+
setTimeout(run, 0);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const channel = new MessageChannel();
|
|
210
|
+
channel.port1.onmessage = () => {
|
|
211
|
+
channel.port1.close();
|
|
212
|
+
run();
|
|
213
|
+
};
|
|
214
|
+
channel.port2.postMessage(null);
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Wait, at most `request.waitMs`, for the stage to draw what `request` asks
|
|
220
|
+
* (the saved revision, and the code), then report. Answers at once when the
|
|
221
|
+
* tab shows another Project, holds unsaved edits, has no stage, or its stage
|
|
222
|
+
* cannot come up or crashed: waiting changes none of those.
|
|
223
|
+
*/
|
|
224
|
+
export function awaitStageHealth(
|
|
225
|
+
store: ShotEditorStore,
|
|
226
|
+
request: StageHealthRequest,
|
|
227
|
+
extraErrors: () => readonly StageRuntimeError[] = () => [],
|
|
228
|
+
deps: StageWaitDeps = TIMERS,
|
|
229
|
+
): Promise<StageHealthReport> {
|
|
230
|
+
return new Promise((resolve) => {
|
|
231
|
+
let done = false;
|
|
232
|
+
const stops: Array<() => void> = [];
|
|
233
|
+
const finish = (verdict: Verdict): void => {
|
|
234
|
+
if (done) return;
|
|
235
|
+
done = true;
|
|
236
|
+
for (const stop of stops) stop();
|
|
237
|
+
void coverageOf(store, verdict, deps).then((checked) => resolve(stageHealthReport(store, verdict, extraErrors(), checked)));
|
|
238
|
+
};
|
|
239
|
+
// THE REST OF THE COMMIT FIRST. The stage says it drew from inside its
|
|
240
|
+
// draw, and a piece that failed in that same commit (a placed component's
|
|
241
|
+
// boundary, a layer's apply) reports in the same task, possibly after it.
|
|
242
|
+
// So a final answer is taken in the next task, judged again.
|
|
243
|
+
let confirming = false;
|
|
244
|
+
const check = (): void => {
|
|
245
|
+
if (done || confirming || !judgeStage(store, request).final) return;
|
|
246
|
+
confirming = true;
|
|
247
|
+
deps.nextTask(() => {
|
|
248
|
+
confirming = false;
|
|
249
|
+
const verdict = judgeStage(store, request);
|
|
250
|
+
if (verdict.final) finish(verdict);
|
|
251
|
+
});
|
|
252
|
+
};
|
|
253
|
+
stops.push(store.subscribeStageHealth(check), store.subscribe(check), subscribeRuntimeErrors(check));
|
|
254
|
+
const wait = Math.max(0, Math.floor(request.waitMs));
|
|
255
|
+
const timer = deps.setTimeout(() => finish({ ...judgeStage(store, request), final: true }), wait);
|
|
256
|
+
stops.push(() => deps.clearTimeout(timer));
|
|
257
|
+
check();
|
|
258
|
+
});
|
|
259
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Every await on the stage that holds the export lock races this.
|
|
2
|
+
//
|
|
3
|
+
// A promise the stage hands back lives in the IFRAME's realm. If the stage
|
|
4
|
+
// reloads mid-call (Vite HMR remints the bridge, a crashed stage is swapped
|
|
5
|
+
// for a fresh one), that realm dies: the promise never settles, and the abort
|
|
6
|
+
// listener the stage registered on the call's signal died with it. The lock
|
|
7
|
+
// is released only when the await ends, so without this race it stayed held,
|
|
8
|
+
// Cancel did nothing, and every later export, capture and Play refused until
|
|
9
|
+
// the page was reloaded. Both halves are watched from the chrome's realm.
|
|
10
|
+
import type { ShotStageBridge } from "../bridgeTypes.js";
|
|
11
|
+
|
|
12
|
+
/** How often the attached bridge is compared with the one the call went to. */
|
|
13
|
+
const STAGE_POLL_MS = 500;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Settle with `work`, or reject first: with `cancelled` (default "export
|
|
17
|
+
* cancelled") when `signal` aborts, and with `reloaded` once `stage()` no
|
|
18
|
+
* longer answers `bridgeAtStart`.
|
|
19
|
+
*/
|
|
20
|
+
export function raceStage<T>(
|
|
21
|
+
work: Promise<T>,
|
|
22
|
+
watch: {
|
|
23
|
+
stage: () => ShotStageBridge | null;
|
|
24
|
+
bridgeAtStart: ShotStageBridge;
|
|
25
|
+
signal: AbortSignal;
|
|
26
|
+
reloaded: string;
|
|
27
|
+
cancelled?: string;
|
|
28
|
+
},
|
|
29
|
+
): Promise<T> {
|
|
30
|
+
return new Promise<T>((resolve, reject) => {
|
|
31
|
+
const timer = setInterval(() => {
|
|
32
|
+
if (watch.stage() !== watch.bridgeAtStart) stop(() => reject(new Error(watch.reloaded)));
|
|
33
|
+
}, STAGE_POLL_MS);
|
|
34
|
+
const onAbort = (): void => stop(() => reject(new Error(watch.cancelled ?? "export cancelled")));
|
|
35
|
+
function stop(settle: () => void): void {
|
|
36
|
+
clearInterval(timer);
|
|
37
|
+
watch.signal.removeEventListener("abort", onAbort);
|
|
38
|
+
settle();
|
|
39
|
+
}
|
|
40
|
+
watch.signal.addEventListener("abort", onAbort, { once: true });
|
|
41
|
+
if (watch.signal.aborted) onAbort();
|
|
42
|
+
work.then(
|
|
43
|
+
(value) => stop(() => resolve(value)),
|
|
44
|
+
(error: unknown) => stop(() => reject(error)),
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
}
|