@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
package/src/bridgeTypes.ts
CHANGED
|
@@ -21,7 +21,34 @@
|
|
|
21
21
|
// `three`. The stage PROJECTS; the chrome receives screen-space numbers as
|
|
22
22
|
// plain data. test/sourceHygiene.test.ts is the gate, and the temptation it
|
|
23
23
|
// exists to catch is importing `Vector3` "just for the projection maths".
|
|
24
|
-
import type {
|
|
24
|
+
import type {
|
|
25
|
+
CameraGate,
|
|
26
|
+
CoverageRequest,
|
|
27
|
+
Doc3D,
|
|
28
|
+
ExportFormat,
|
|
29
|
+
FramingDelta,
|
|
30
|
+
GestureDelta,
|
|
31
|
+
GestureKind,
|
|
32
|
+
MeshMaterialSlotInfo,
|
|
33
|
+
MotionPresetRequest,
|
|
34
|
+
PathData,
|
|
35
|
+
PieceFailure,
|
|
36
|
+
SnapGuide,
|
|
37
|
+
SplinePoint3D,
|
|
38
|
+
StageCoverage,
|
|
39
|
+
StageHealthSnapshot,
|
|
40
|
+
} from "@dailies-studio/shot/doc";
|
|
41
|
+
// Tier-1 export speaks the shared wire protocol's capability shape verbatim —
|
|
42
|
+
// no duplication needed here: both documents resolve the SAME package, so this
|
|
43
|
+
// is one definition, not a copy (the motion editor duplicates because it sits
|
|
44
|
+
// across a package boundary; this file does not).
|
|
45
|
+
import type { Mp4Encoding, Tier1Capability } from "@dailies-studio/shot/tier1";
|
|
46
|
+
// Engine `Value` only — the wire shape of an instance prop. Type-only and
|
|
47
|
+
// three-free, the same import the instance inspector makes.
|
|
48
|
+
import type { Value } from "@dailies-studio/engine";
|
|
49
|
+
// A component's contract types an `instance.props.<key>` key (Count up), and
|
|
50
|
+
// the stage has no registry of its own to read one from.
|
|
51
|
+
import type { Contract } from "@dailies-studio/contract";
|
|
25
52
|
// ONE definition of the tool union, in the table that also answers what each
|
|
26
53
|
// tool's key, surface, cursor and draw behaviour are. Re-exported here so the
|
|
27
54
|
// stage can take the protocol from one import.
|
|
@@ -47,9 +74,10 @@ export type { ShadingMode, StageLayout, StagePane, WorkingView };
|
|
|
47
74
|
* for a working pane would get a silently unchanged camera pane — exactly the
|
|
48
75
|
* half-working state the refusal exists for.
|
|
49
76
|
*
|
|
50
|
-
* 3: the camera lane. A v2 stage
|
|
51
|
-
* turning follow on would throw inside the
|
|
52
|
-
* armed button over a pane that is not
|
|
77
|
+
* 3: the camera lane. A v2 stage had no `setCameraFollowsView` (v29's
|
|
78
|
+
* `setPilot` now), so a v3 chrome turning follow on would throw inside the
|
|
79
|
+
* push and, worse, would show its armed button over a pane that is not
|
|
80
|
+
* following anything.
|
|
53
81
|
*
|
|
54
82
|
* 4: `onWorkingViewChange` carries a WorkingViewOrigin. A v3 stage sends none,
|
|
55
83
|
* so every one of its view changes reads as "the author moved the view" — and
|
|
@@ -114,8 +142,715 @@ export type { ShadingMode, StageLayout, StagePane, WorkingView };
|
|
|
114
142
|
* that never appears on a toon mesh, and an outliner whose triangle budget
|
|
115
143
|
* reports an empty scene however heavy the models are. Nothing throws and
|
|
116
144
|
* nothing is wrong on screen; the author simply believes three features are
|
|
117
|
-
* broken and one number is true.
|
|
118
|
-
|
|
145
|
+
* broken and one number is true.
|
|
146
|
+
*
|
|
147
|
+
* 12: `exportCapability` and `exportMovie` — Tier-1 in-browser export, and
|
|
148
|
+
* the bridge's first Promise-returning members (same-origin, so the promise
|
|
149
|
+
* and the finished Blob cross as plain references). A v11 stage under a v12
|
|
150
|
+
* chrome throws "exportMovie is not a function" the moment the dialog's
|
|
151
|
+
* browser path runs; the gate turns that into the rebuild message at
|
|
152
|
+
* connect.
|
|
153
|
+
*
|
|
154
|
+
* 13: `capturePoster` — the dashboard's card thumbnail, read off the live GL
|
|
155
|
+
* canvas. A v12 stage under a v13 chrome would simply never produce a
|
|
156
|
+
* poster, which is the quietest possible failure (a gradient placeholder
|
|
157
|
+
* forever, and nothing in the console); the version gate turns it into the
|
|
158
|
+
* rebuild message instead.
|
|
159
|
+
*
|
|
160
|
+
* 14: `setComponentContext` — the component context (unify P2). A v13 stage
|
|
161
|
+
* has no verb, so a v14 chrome entering a definition would throw inside the
|
|
162
|
+
* push; and the quiet direction is worse: the chrome's outline, dock and
|
|
163
|
+
* inspector would all address the definition while the stage kept rendering
|
|
164
|
+
* the SCENE at master time — every def-local seek the dock issues would
|
|
165
|
+
* scrub the scene instead, and a pick would land on layers the chrome
|
|
166
|
+
* considers out of scope. `seek` also changes MEANING under a context
|
|
167
|
+
* (def-local frames), which no optional-feature fallback can express.
|
|
168
|
+
*
|
|
169
|
+
* 15: 3D spline authoring. Work-plane state, spline drafts, point-edit
|
|
170
|
+
* gestures and projected non-quad selection shapes all cross the bridge. A
|
|
171
|
+
* v14 stage would leave Shift+P armed over an orbiting pane and a v14 chrome
|
|
172
|
+
* would ignore the point edits a v15 stage emits, so neither direction has a
|
|
173
|
+
* truthful optional fallback.
|
|
174
|
+
*
|
|
175
|
+
* 16: material-workspace preview ownership and shader compile diagnostics.
|
|
176
|
+
* The stage must stop scene picking/transforms while the graph owns the
|
|
177
|
+
* pointer, and the chrome must distinguish a last-good preview from a graph
|
|
178
|
+
* the GPU rejected. A v15 half would silently violate one of those claims.
|
|
179
|
+
*
|
|
180
|
+
* 17: material SLOTS and node PREVIEWS. `setMaterialPreview` addresses a
|
|
181
|
+
* submesh slot rather than a whole layer, `onMaterialCompile` reports per
|
|
182
|
+
* slot, `onMeshMaterialSlots` pushes the parsed glTF material list, and
|
|
183
|
+
* `requestNodePreviews` answers with thumbnails. Neither half degrades
|
|
184
|
+
* honestly: a v16 stage under a v17 chrome would leave the slot rail empty
|
|
185
|
+
* forever and throw on a preview request, and a v17 stage under a v16 chrome
|
|
186
|
+
* would call a slot handler that is not there from inside the model-load
|
|
187
|
+
* effect.
|
|
188
|
+
*
|
|
189
|
+
* 18: `onFitRequest` — the stage asking the chrome to hand the camera back.
|
|
190
|
+
* In the material workspace every drag orbits, and an orbited camera stays the
|
|
191
|
+
* author's forever by design, so a double-click on the object is the gesture
|
|
192
|
+
* that re-derives the head-on frame. It is stage -> chrome and fires from
|
|
193
|
+
* inside a pointer lane, so a v18 stage under a v17 chrome throws mid-gesture
|
|
194
|
+
* exactly as the version-11 handlers did.
|
|
195
|
+
*
|
|
196
|
+
* 19: `GestureDelta.suppressGuides` — the stage telling the chrome that CTRL
|
|
197
|
+
* is held, so the smart guides step aside for a delta that is already on a
|
|
198
|
+
* round number. Both halves fail silently without the bump, in opposite
|
|
199
|
+
* directions and both invisibly: a v19 stage under a v18 chrome quantises the
|
|
200
|
+
* emit and then has the guides pull it back off, so holding ctrl looks like it
|
|
201
|
+
* does nothing at all; a v18 stage under a v19 chrome never sets the flag, so
|
|
202
|
+
* the guides stay on and the same thing happens. There is no wrong PIXEL to
|
|
203
|
+
* see either way — only a modifier that appears not to work — which is exactly
|
|
204
|
+
* the class of mismatch a version gate exists to turn into a refusal.
|
|
205
|
+
*
|
|
206
|
+
* 20: `setPlaying` — the chrome telling the stage the transport is running, so
|
|
207
|
+
* the stage can defer work that the next seek is about to redo anyway. A v19
|
|
208
|
+
* stage under a v20 chrome simply never learns it is playing and behaves
|
|
209
|
+
* exactly as it did at v19, which is why this bump is about honesty rather
|
|
210
|
+
* than corruption: the mismatch costs performance, never pixels.
|
|
211
|
+
*
|
|
212
|
+
* 21: `ShotComponentContext.zoom` — the Studio's zoom over the definition's
|
|
213
|
+
* head-on render. An additive optional field, and bumped anyway on version
|
|
214
|
+
* 19's rule: a v20 stage ignores it, so the chrome's zoom control moves a
|
|
215
|
+
* number nothing on screen answers to. There is no wrong PIXEL to see, only a
|
|
216
|
+
* control that appears not to work, which is exactly the class of mismatch
|
|
217
|
+
* this gate exists to turn into a refusal rather than a support question.
|
|
218
|
+
*
|
|
219
|
+
* 22: `hoverLayer` and `setGridVisible`, one release. `hoverLayer` is the
|
|
220
|
+
* chrome telling the stage which layer a timeline row under the cursor names,
|
|
221
|
+
* so the stage lights that layer's outline without a click (and without
|
|
222
|
+
* changing the selection) — imperative on the stage side (a feed write and
|
|
223
|
+
* one SVG leaf repaint, zero GL draws — the reason it is NOT a state push).
|
|
224
|
+
* `setGridVisible` toggles the working pane's grid floor, workspace state on
|
|
225
|
+
* `setShadingMode`'s pattern. A v21 stage under a v22 chrome would throw on
|
|
226
|
+
* either missing verb — hover on the first row crossing, grid on the first
|
|
227
|
+
* toggle — which is version 18's mid-gesture failure class and exactly what
|
|
228
|
+
* the gate refuses up front.
|
|
229
|
+
*
|
|
230
|
+
* 23: `ShotComponentContext` becomes a union, so the context can name a CODE
|
|
231
|
+
* component ("<module>#<Export>") and not only an authored definition. A v22
|
|
232
|
+
* stage handed a code context reads `ctx.def` as undefined, fails its own
|
|
233
|
+
* "is this definition in the document" check and stores null: the chrome
|
|
234
|
+
* enters the code studio, the stage keeps rendering the shot behind the hole,
|
|
235
|
+
* and the author sees a panel over the wrong picture. A wrong PIXEL, which is
|
|
236
|
+
* version 18's class and the reason this is a bump rather than an additive
|
|
237
|
+
* field.
|
|
238
|
+
*
|
|
239
|
+
* 24: `onWaypointGesture`, the camera lane's second verb. A path move's
|
|
240
|
+
* waypoints became grabbable in the working pane, and the drag rides the
|
|
241
|
+
* EXISTING `onFramingGestureStart`/`End` bracket — one scrub, one undo entry —
|
|
242
|
+
* but it writes a WAYPOINT rather than the framing, so it needs a message of
|
|
243
|
+
* its own. A v23 chrome under a v24 stage would throw on the first waypoint
|
|
244
|
+
* drag: version 22's missing-verb class, refused up front instead.
|
|
245
|
+
*
|
|
246
|
+
* 25: `onStageBusy`, the readiness lane. The chrome holds playback while the
|
|
247
|
+
* stage is still loading (renderer init, fonts, textures, models), because
|
|
248
|
+
* play against a scene that has not landed runs the clock over a blank
|
|
249
|
+
* picture. A v24 stage under a v25 chrome never calls the handler, so the
|
|
250
|
+
* chrome would read "ready" forever and the hold would silently not exist —
|
|
251
|
+
* no wrong pixel, but a guard that is present in the source and absent in the
|
|
252
|
+
* product, which is the worst of both. Refused up front instead.
|
|
253
|
+
*
|
|
254
|
+
* 26: `onPerformance`, the presentation readout. The stage already measures
|
|
255
|
+
* what it PRESENTS, once a second, because the adaptive quality policy is
|
|
256
|
+
* driven by it; the chrome had no way to read it, so the only number it could
|
|
257
|
+
* have shown was its own seek cadence, and the stage coalesces requests and
|
|
258
|
+
* drops publications precisely when the two diverge. A number that reads 60
|
|
259
|
+
* while the picture runs at 18 is worse than no number. A v25 stage under a
|
|
260
|
+
* v26 chrome never calls the handler, so the badge would simply never appear:
|
|
261
|
+
* silent in the direction that looks like it works, which is version 25's
|
|
262
|
+
* class exactly. Refused up front instead.
|
|
263
|
+
*
|
|
264
|
+
* 27: `ShotCodeContext.props`, the defaults rail's live preview. The code
|
|
265
|
+
* studio's component face scrubs a contract default and the stage must show
|
|
266
|
+
* it before the commit lands in source, so the override rides the context —
|
|
267
|
+
* additive and optional, but bumped on v21's rule: a v26 stage's
|
|
268
|
+
* `validComponentContext` REBUILDS the code arm as `{ code, zoom }` and
|
|
269
|
+
* silently strips the field, so the rail's scrub would move a control
|
|
270
|
+
* nothing on screen answers to. Refused up front instead.
|
|
271
|
+
*
|
|
272
|
+
* 28: `setVideo`, the watch-only frame. Video stopped being a pane layout and
|
|
273
|
+
* became a flag over the picture, and the stage is where the flag does its
|
|
274
|
+
* work: it empties the selection it draws furniture for, refuses every grab
|
|
275
|
+
* and draw gesture, drops the hover raycast, and abandons a live modal, pen
|
|
276
|
+
* or spline draft. A v27 stage under a v28 chrome never receives the message,
|
|
277
|
+
* so it would keep drawing handles over a finished picture and keep taking
|
|
278
|
+
* transform drags on it. An author "watching" would be editing by accident,
|
|
279
|
+
* and nothing anywhere would say so. Silent in the direction that looks like
|
|
280
|
+
* it works, which is version 25's class exactly. Refused up front instead.
|
|
281
|
+
*
|
|
282
|
+
* 29: the camera lane, made legible. `setPilot` replaces
|
|
283
|
+
* `setCameraFollowsView`: piloting drives the shot camera from the CAMERA
|
|
284
|
+
* pane's own navigation (orbit, pan, wheel) through the framing gesture lane,
|
|
285
|
+
* where follow projected 3D-view orbits onto a camera that cannot tilt and
|
|
286
|
+
* left the two panes disagreeing mid-drag. `setCameraGate` tells the stage
|
|
287
|
+
* what a camera write would do at the playhead, so the gizmo dims and the
|
|
288
|
+
* press refuses BEFORE the drag instead of after it. `onFramingGesture` grew
|
|
289
|
+
* an origin (a wheel has no release, so the chrome brackets it with silence)
|
|
290
|
+
* and answers whether it wrote, so the badge can flash a refusal.
|
|
291
|
+
* `onLeavePilot` is the badge's own EJECT, and `onCameraDriver` names the
|
|
292
|
+
* component driving the render camera. A v28 stage under a v29 chrome throws
|
|
293
|
+
* on the attach push (`setPilot`), and the quiet direction is worse: a v29
|
|
294
|
+
* stage under a v28 chrome would keep the pane's wheel and drags on the
|
|
295
|
+
* viewport while the badge said the camera was being piloted. Version 25's
|
|
296
|
+
* class exactly. Refused up front instead.
|
|
297
|
+
*
|
|
298
|
+
* 30: `setStoryboardPreview`, the board's hole. The Storyboard used to be
|
|
299
|
+
* chrome over an unchanged stage; it now leaves a `.stage-window` in its
|
|
300
|
+
* bottom strip, and `measureInset` hands that rect down as the whole visible
|
|
301
|
+
* stage. A v29 stage under a v30 chrome never receives the flag, so it would
|
|
302
|
+
* keep the layout the author left behind it and draw selection handles,
|
|
303
|
+
* gizmos and the grid into a 300px monitor. Worse, the picture there would be
|
|
304
|
+
* whatever the stage was last framed at rather than the shot: the derived fit
|
|
305
|
+
* rides this bit too. Silent in the direction that looks like it works, which
|
|
306
|
+
* is version 28's class exactly. Refused up front instead.
|
|
307
|
+
*
|
|
308
|
+
* 31: `preparePlayback`, the preparing pass before Play. A v30 stage under a
|
|
309
|
+
* v31 chrome has no such method, and a chrome that called it would throw on
|
|
310
|
+
* every Play. Refused up front instead.
|
|
311
|
+
*
|
|
312
|
+
* 32: `captureFrame`, the storyboard's "Frame from Shot" drawn by the stage
|
|
313
|
+
* itself, because the hosted editor has no server renderer to ask, and the
|
|
314
|
+
* GIF export kind (`ShotExportMovieRequest.format`, `Tier1Capability.gif`).
|
|
315
|
+
* A v31 stage has no `captureFrame`, so a v32 chrome would throw on every
|
|
316
|
+
* capture; and it ignores `format`, so a GIF export would come back an MP4.
|
|
317
|
+
* Refused up front instead.
|
|
318
|
+
*
|
|
319
|
+
* 33: `capturePoster` YIELDS and REMEMBERS. The chrome takes no lock for a
|
|
320
|
+
* poster, so the stage now aborts one for anything the author starts on it
|
|
321
|
+
* (Play, an export or `captureFrame`, a scrub, an edit, a press), and answers
|
|
322
|
+
* null at once for a document whose capture failed. The chrome relies on
|
|
323
|
+
* both: it asks again on every null. A v32 stage under it would re-run a
|
|
324
|
+
* failing capture, up to a minute in export framing, on every ask, and an
|
|
325
|
+
* export started mid-poster would refuse "already running". Refused up
|
|
326
|
+
* front instead.
|
|
327
|
+
*
|
|
328
|
+
* 34: `onPieceFailures`, one broken piece isolated. The stage now draws the
|
|
329
|
+
* rest of a Shot when a layer, a background, a post stack or a transition
|
|
330
|
+
* throws, and sends the chrome the whole list of what it isolated (and
|
|
331
|
+
* `loadDoc` carries the document's revision, stamped on each failure). A v33
|
|
332
|
+
* chrome under a v34 stage has no such handler, so the one message that says
|
|
333
|
+
* a piece is missing would throw from inside the stage's apply pass; a v33
|
|
334
|
+
* stage under a v34 chrome never sends it, so a broken layer would read as a
|
|
335
|
+
* healthy stage. Silent in the direction that looks like it works, version
|
|
336
|
+
* 25's class. Refused up front instead.
|
|
337
|
+
*
|
|
338
|
+
* 35: `health()` and `onStageHealth`, the stage reporting on itself to an
|
|
339
|
+
* agent that cannot see it. `health()` answers what the stage holds (the
|
|
340
|
+
* crash, a lost context, the isolated pieces, the render fallbacks, the
|
|
341
|
+
* component failures, the uncaught errors of its document and its export
|
|
342
|
+
* worker, and what it last PRESENTED: the saved revision, the module epoch,
|
|
343
|
+
* the frame), and `onStageHealth` says it changed, never per frame. `loadDoc`
|
|
344
|
+
* of the document already on stage now only records its revision, which is
|
|
345
|
+
* how the chrome's own save marks the picture as that revision. A v34 stage
|
|
346
|
+
* under a v35 chrome has no `health()`, so every MCP write would wait out
|
|
347
|
+
* its check and answer "pending" over a stage that drew it; a v35 stage
|
|
348
|
+
* under a v34 chrome calls a handler that is not there from inside its
|
|
349
|
+
* presentation. Refused up front instead.
|
|
350
|
+
*
|
|
351
|
+
* 36: `coverage()`, which mesh-like layers put a pixel in the frame. A
|
|
352
|
+
* write whose every piece drew can still show nothing of a model: a
|
|
353
|
+
* gradient background drawn over it, a layer that paints over it, a camera
|
|
354
|
+
* that does not see it. The stage now draws its frame offscreen, whole and
|
|
355
|
+
* without each mesh, device or placed component layer, and says which of
|
|
356
|
+
* them changed no pixel (shot stageCoverage.ts). A v35 stage under a v36
|
|
357
|
+
* chrome has no `coverage()`, so every health report would say the layers
|
|
358
|
+
* were not checked and an agent would learn to ignore it; a v36 stage under
|
|
359
|
+
* a v35 chrome is never asked, which reads as a stage whose layers all
|
|
360
|
+
* draw. Silent in the direction that looks like it works, version 25's
|
|
361
|
+
* class. Refused up front instead.
|
|
362
|
+
*
|
|
363
|
+
* 37: `setBoardFrame`, the storyboard's Frame view framing the live stage:
|
|
364
|
+
* a tag, a numbered dot on each pinned beat's layer, and an onion skin of
|
|
365
|
+
* the previous still. Unlike `setStoryboardPreview` it keeps the stage
|
|
366
|
+
* editable, so it fits the shot into the hole without hiding furniture or
|
|
367
|
+
* refusing a click, and it parks every view gesture so the fit is the only
|
|
368
|
+
* framing on screen. A v36 stage under a v37 chrome throws "setBoardFrame
|
|
369
|
+
* is not a function" the moment the Frame view opens; a v37 stage under a
|
|
370
|
+
* v36 chrome is never framed, so the board's window would show the
|
|
371
|
+
* author's pan and zoom instead of the shot. Refused up front instead.
|
|
372
|
+
*
|
|
373
|
+
* 38: `editText` and `onTextEdit`, the stage's inline text editor. A Text
|
|
374
|
+
* click inserts a layer and opens it for typing; a double-click on a text
|
|
375
|
+
* layer opens it again. A v37 stage under a v38 chrome throws "editText is
|
|
376
|
+
* not a function" on the first Text click; a v38 stage under a v37 chrome
|
|
377
|
+
* calls a handler that is not there when the editor closes, and the words
|
|
378
|
+
* are lost. Refused up front instead. Also `designPointAt`, the query a
|
|
379
|
+
* drop on the frame converts its point through: a v37 stage under a v38
|
|
380
|
+
* chrome throws "designPointAt is not a function" on the first drop. And
|
|
381
|
+
* `onInstanceNaturalSize`, what a box-ignoring instance module draws: a v38
|
|
382
|
+
* stage under a v37 chrome calls a handler that is not there on the first
|
|
383
|
+
* placed component.
|
|
384
|
+
*
|
|
385
|
+
* 39: `exportMovie` takes a master `window`, the work area. A v38 stage
|
|
386
|
+
* under a v39 chrome ignores the field and exports the whole film into a
|
|
387
|
+
* file named for the work area, with audio cut to the window: silent in the
|
|
388
|
+
* direction that looks like it works. Refused up front instead.
|
|
389
|
+
*
|
|
390
|
+
* 40: `onTextAutoSize`, an auto-width text box's measured size (`TextBox`).
|
|
391
|
+
* A v40 stage under a v39 chrome calls a handler that is not there on the
|
|
392
|
+
* first auto text box; a v39 stage under a v40 chrome never measures, so the
|
|
393
|
+
* box keeps its click estimate. Refused up front instead.
|
|
394
|
+
*
|
|
395
|
+
* 41: `setReadOnly`, a viewer's stage. A v40 stage under a v41 chrome throws
|
|
396
|
+
* "setReadOnly is not a function" on attach; a v41 stage under a v40 chrome
|
|
397
|
+
* is never told, which is the editable stage it always was. Refused up front
|
|
398
|
+
* instead.
|
|
399
|
+
*
|
|
400
|
+
* 42: Storyboard comments. `ShotBoardFrame` gains `pins` and `comment`, and
|
|
401
|
+
* the handlers gain `onCommentAt` and `onCommentPin`. A v41 stage under a
|
|
402
|
+
* v42 chrome draws no pins and never reports a comment click; a v42 stage
|
|
403
|
+
* under a v41 chrome calls handlers that are not there. Refused up front
|
|
404
|
+
* instead.
|
|
405
|
+
*
|
|
406
|
+
* 43: `setPeerSelections`, other people's selections (live collaboration,
|
|
407
|
+
* R7). A v42 stage under a v43 chrome throws "setPeerSelections is not a
|
|
408
|
+
* function" on the first peer; a v43 stage under a v42 chrome is never
|
|
409
|
+
* told, so it draws no peer outlines. Refused up front instead.
|
|
410
|
+
*
|
|
411
|
+
* 44: Rulers, guides and the motion path key drag. The stage gains
|
|
412
|
+
* `setEditorChrome` and `setMotionPaths`; the handlers gain the guide
|
|
413
|
+
* gestures (`onGuideGestureStart`, `onGuideGesture`, `onGuideGestureEnd`,
|
|
414
|
+
* `onGuideSet`, `onGuideRemove`) and the path key drag
|
|
415
|
+
* (`onPathKeyGestureStart`, `onPathKeyGesture`, `onPathKeyGestureEnd`,
|
|
416
|
+
* plus `onPathKeyDoubleClick` and `onContextMenu`'s optional `pathKey`), whose
|
|
417
|
+
* `part` already names the Bezier handles so schema v40 needs no second
|
|
418
|
+
* bump. A v43 stage under a v44 chrome throws "setEditorChrome is not a
|
|
419
|
+
* function" on attach; a v44 stage under a v43 chrome calls guide handlers
|
|
420
|
+
* that are not there on the first ruler drag. Refused up front instead.
|
|
421
|
+
*
|
|
422
|
+
* 45: The Components workspace's preview and Studio comments. Both arms of
|
|
423
|
+
* `ShotComponentContext` gain `background` (dark, light or brand, drawn as
|
|
424
|
+
* the working pane's clear colour) and `loopFrames` (the stage wraps every
|
|
425
|
+
* seek inside the context to that length). The stage gains
|
|
426
|
+
* `setStudioComments`, pins anchored to a Shot and a frame with no still,
|
|
427
|
+
* and the handlers gain `onStudioCommentAt`. A v44 stage under a v45 chrome
|
|
428
|
+
* throws "setStudioComments is not a function" on attach and ignores the
|
|
429
|
+
* background and the loop; a v45 stage under a v44 chrome calls a handler
|
|
430
|
+
* that is not there on the first Studio comment. Refused up front instead.
|
|
431
|
+
* The board no longer frames the stage, so v45 also drops `setBoardFrame`
|
|
432
|
+
* (v37) and `onCommentAt` (v42); the pins `ShotBoardPin` describes are the
|
|
433
|
+
* Studio's now.
|
|
434
|
+
*
|
|
435
|
+
* 46: The Components props panel tries values without saving them.
|
|
436
|
+
* `ShotDefContext` gains `props` (exposed key -> Value), drawn the way a
|
|
437
|
+
* placement's overrides are. A v45 stage under a v46 chrome ignores them, so
|
|
438
|
+
* the panel would show a tried value the preview never draws. Refused up
|
|
439
|
+
* front instead.
|
|
440
|
+
*
|
|
441
|
+
* 47: The Studio's sketch guide. The stage gains `setSketchGuide`, one
|
|
442
|
+
* storyboard sketch as plain shapes in design px, drawn as dashed outlines
|
|
443
|
+
* over the camera frame. A v46 stage under a v47 chrome throws
|
|
444
|
+
* "setSketchGuide is not a function" on attach. Refused up front instead.
|
|
445
|
+
*
|
|
446
|
+
* 48: A definition is authored only on the Components Edit tab.
|
|
447
|
+
* `ShotDefContext` gains `edit`, and only then does the definition's one
|
|
448
|
+
* pane take the authoring lanes (the draw tools, the pen, drops and the
|
|
449
|
+
* Select grammar). The Preview tab shows the same definition and orbits.
|
|
450
|
+
* A v47 stage under a v48 chrome would author on Preview too, so a drag
|
|
451
|
+
* there moved the master definition. Refused up front instead.
|
|
452
|
+
*
|
|
453
|
+
* 49: `exportMovie` takes a `quantizer`, the quality's CRF as a fixed H.264
|
|
454
|
+
* QP, and its result says how the encoder ran (`encoding`). A bitrate encode
|
|
455
|
+
* can open soft (KAN-23), so the stage encodes at the QP wherever a hardware
|
|
456
|
+
* encoder honours one. A v48 stage under a v49 chrome ignores the field and
|
|
457
|
+
* silently ships the bitrate encode, and the dialog never learns which
|
|
458
|
+
* encoder ran: silent in the direction that looks like it works, version
|
|
459
|
+
* 25's class. Refused up front instead.
|
|
460
|
+
*
|
|
461
|
+
* 50: The font picker's stage preview. The stage gains `setFontPreview`, a
|
|
462
|
+
* font shown on some text layers without a document write. A v49 stage
|
|
463
|
+
* under a v50 chrome throws "setFontPreview is not a function" on the first
|
|
464
|
+
* hover in the picker. Refused up front instead.
|
|
465
|
+
*
|
|
466
|
+
* 51: Honest readiness, the queued Play, and background preparation that
|
|
467
|
+
* runs. `onStageBusy` now says the stage owes the open subject its first
|
|
468
|
+
* whole presentation, not that a load is open. `preparePlayback` loses
|
|
469
|
+
* `background` and takes a `pace`, reports each frame's outcome, ends with
|
|
470
|
+
* a reason (`yielded`, `refused`) and hands over on the start frame
|
|
471
|
+
* (`handedOver`). The stage gains `preparationKey()` and `takePlayed()`. A
|
|
472
|
+
* v50 stage under a v51 chrome would report busy for ordinary loads,
|
|
473
|
+
* resolve before the start frame is presented, and ignore `pace`; a v51
|
|
474
|
+
* stage under a v50 chrome would call `pace()` on a request that has none.
|
|
475
|
+
* Refused up front instead.
|
|
476
|
+
*
|
|
477
|
+
* 52: The playback render scale's report and its preference. A played frame
|
|
478
|
+
* may render below the display's density while the GPU cannot keep up (the
|
|
479
|
+
* stage's renderScaleController.ts decides, on stage-local inputs), so
|
|
480
|
+
* `StagePerformanceReport` gains `gpuMs` (the second's GPU p95, null without
|
|
481
|
+
* a timer) and `renderScale` (the share of the display's density its last
|
|
482
|
+
* frame rendered at), and `EditorChrome` gains `playbackResolution` (the
|
|
483
|
+
* Preferences row: `auto`, `full` or `fast`). A v51 stage under a v52 chrome
|
|
484
|
+
* sends neither field, and the fps chip reads both; a v52 stage under a v51
|
|
485
|
+
* chrome is never told a mode, so it runs Auto, and the chip never says the
|
|
486
|
+
* picture renders below the display's density: silent in the direction that
|
|
487
|
+
* looks like it works, version 25's class. Refused up front instead.
|
|
488
|
+
*
|
|
489
|
+
* 53: The motion preset picker's stage preview. The stage gains
|
|
490
|
+
* `setMotionPreview`, a preset's keys shown on some layers without a
|
|
491
|
+
* document write, while the chrome seeks the stage through the preset's
|
|
492
|
+
* frames. A v52 stage under a v53 chrome throws "setMotionPreview is not a
|
|
493
|
+
* function" on the first hover in the Motion section. Refused up front
|
|
494
|
+
* instead.
|
|
495
|
+
*/
|
|
496
|
+
export const SHOT_BRIDGE_VERSION = 53;
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* A motion preset the Motion section shows on some layers before it is
|
|
500
|
+
* applied (bridge v53). Never written to a Doc3D. The stage stamps it on its
|
|
501
|
+
* own copy with the same `stampMotionPreset` a commit runs, so the preview is
|
|
502
|
+
* exactly the keys an apply writes.
|
|
503
|
+
*/
|
|
504
|
+
export interface ShotMotionPreview {
|
|
505
|
+
/** The container that holds the layers: the Shot's scene id, or the open
|
|
506
|
+
* definition's id. */
|
|
507
|
+
containerId: string;
|
|
508
|
+
layerIds: readonly string[];
|
|
509
|
+
/** The stamp, `at` included (the chrome's playhead, container-local). */
|
|
510
|
+
request: MotionPresetRequest;
|
|
511
|
+
/** The registry's contracts for the placed components among `layerIds`,
|
|
512
|
+
* by component id: what types a Count up's `instance.props.progress`. */
|
|
513
|
+
contracts?: Readonly<Record<string, Contract>>;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/** One file of a previewed face: a font url the stage loads itself, and the
|
|
517
|
+
* characters it covers (a CSS `unicode-range`; absent, the whole file). */
|
|
518
|
+
export interface ShotFontPreviewFace {
|
|
519
|
+
url: string;
|
|
520
|
+
unicodeRange?: string;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/** A font the font picker shows on some text layers before it is applied
|
|
524
|
+
* (bridge v50). Never written to a Doc3D. */
|
|
525
|
+
export interface ShotFontPreview {
|
|
526
|
+
/** The container that holds the layers: the Shot's scene id, or the open
|
|
527
|
+
* definition's id. */
|
|
528
|
+
containerId: string;
|
|
529
|
+
/** The text layers that show the font. Other layers, and other kinds, are
|
|
530
|
+
* left as they are. */
|
|
531
|
+
layerIds: readonly string[];
|
|
532
|
+
/** The family's display name, kept in the stack after the preview face. */
|
|
533
|
+
family: string;
|
|
534
|
+
/** The generic family drawn while the faces load, and where they have no
|
|
535
|
+
* glyph (`sans-serif`, `serif`, `monospace`, `cursive`). */
|
|
536
|
+
fallback: string;
|
|
537
|
+
/** The style the faces are, which the layers draw in for the preview. */
|
|
538
|
+
style: "normal" | "italic";
|
|
539
|
+
/** The faces' `font-weight` descriptor range: a variable file's `wght`
|
|
540
|
+
* axis, or `[1, 1000]` for one static file. Each layer keeps its own
|
|
541
|
+
* weight, and the browser never synthesises bold over the range. */
|
|
542
|
+
weightRange: readonly [number, number];
|
|
543
|
+
/** The faces, the family's default subset first. The stage fetches every
|
|
544
|
+
* one as soon as the preview arrives (a face joins the stage's font set
|
|
545
|
+
* only once it has loaded), so list the files the layers' text needs
|
|
546
|
+
* (`subsetsForText`), not each of the family's subsets. The same files,
|
|
547
|
+
* style and weight range sent again keep the faces already loaded. */
|
|
548
|
+
faces: readonly ShotFontPreviewFace[];
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/** The component preview's backdrop (bridge v45). `brand` is the Project's
|
|
552
|
+
* first brand colour, and dark when it has none. */
|
|
553
|
+
export type ShotComponentBackground = "dark" | "light" | "brand";
|
|
554
|
+
|
|
555
|
+
/** The colour `brand` resolves to: the first colour row of the PROJECT's
|
|
556
|
+
* branding, or null when it has none (the caller then draws dark). One rule
|
|
557
|
+
* for both documents, so the stage and the board's card stage cannot pick
|
|
558
|
+
* different rows. */
|
|
559
|
+
export function brandBackdrop(doc: Pick<Doc3D, "resources"> | null): string | null {
|
|
560
|
+
for (const item of doc?.resources?.branding ?? []) {
|
|
561
|
+
if (item.type === "color" && /^#[0-9a-fA-F]{6}$/.test(item.value)) return item.value;
|
|
562
|
+
}
|
|
563
|
+
return null;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/** The most frames a preview loop may hold: ten minutes at 60 fps. A bound,
|
|
567
|
+
* so a junk number cannot make the wrap a no-op that reads as a loop. */
|
|
568
|
+
export const MAX_LOOP_FRAMES = 36_000;
|
|
569
|
+
|
|
570
|
+
/** A Studio comment's place (bridge v45): a Shot, a Shot-local frame, the
|
|
571
|
+
* topmost layer under the click, and the point as 0..1 of the frame rect.
|
|
572
|
+
* No still: a Studio comment is left on the moving picture at a timecode. */
|
|
573
|
+
export interface ShotStudioAnchor {
|
|
574
|
+
kind: "studio";
|
|
575
|
+
sceneId: string;
|
|
576
|
+
/** Shot-local, frames from the Shot's start. */
|
|
577
|
+
frame: number;
|
|
578
|
+
layerId: string | null;
|
|
579
|
+
u: number;
|
|
580
|
+
v: number;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/** One Studio comment pin (bridge v45). The stage draws it while stopped on
|
|
584
|
+
* its anchor's Shot and frame, so the chrome sends every pin once rather
|
|
585
|
+
* than re-pushing per frame. */
|
|
586
|
+
export interface ShotStudioPin {
|
|
587
|
+
threadId: string;
|
|
588
|
+
anchor: ShotStudioAnchor;
|
|
589
|
+
/** As `ShotBoardPin`. */
|
|
590
|
+
initials: string;
|
|
591
|
+
color: string;
|
|
592
|
+
active: boolean;
|
|
593
|
+
label: string;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/** What the Studio's comment layer lays over the camera pane (bridge v45).
|
|
597
|
+
* See `setStudioComments`. */
|
|
598
|
+
export interface ShotStudioComments {
|
|
599
|
+
pins: readonly ShotStudioPin[];
|
|
600
|
+
/** The comment tool is armed: a primary click on the camera frame is
|
|
601
|
+
* `onStudioCommentAt` instead of a pick. */
|
|
602
|
+
armed: boolean;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/** One outline of the Studio's sketch guide (bridge v47): a sketch item's
|
|
606
|
+
* box in design px, `at` its centre (origin at the canvas centre, +y down,
|
|
607
|
+
* the layer units), with its corner radius and its label chip. */
|
|
608
|
+
export interface ShotSketchGuideRect {
|
|
609
|
+
at: readonly [number, number];
|
|
610
|
+
size: readonly [number, number];
|
|
611
|
+
/** Corner radius, design px; absent is square. */
|
|
612
|
+
radius?: number;
|
|
613
|
+
label?: string;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/** A sketch arrow (bridge v47): a motion note, drawn from `from` to `to`. */
|
|
617
|
+
export interface ShotSketchGuideArrow {
|
|
618
|
+
from: readonly [number, number];
|
|
619
|
+
to: readonly [number, number];
|
|
620
|
+
label?: string;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/** THE SKETCH GUIDE (bridge v47): what "Guide: Sketch N" draws over the
|
|
624
|
+
* camera frame. Plain shapes, so the stage needs no storyboard code. */
|
|
625
|
+
export interface ShotSketchGuide {
|
|
626
|
+
rects: readonly ShotSketchGuideRect[];
|
|
627
|
+
arrows: readonly ShotSketchGuideArrow[];
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/** The most shapes a guide carries: a sketch's own item limit, with room
|
|
631
|
+
* for nothing more. A bound, so a junk message cannot flood the overlay. */
|
|
632
|
+
export const MAX_SKETCH_GUIDE_SHAPES = 32;
|
|
633
|
+
|
|
634
|
+
/** One other person's selection (bridge v43): outlined in their colour with
|
|
635
|
+
* their name, under this tab's own selection, and never clickable. */
|
|
636
|
+
export interface ShotPeerSelection {
|
|
637
|
+
ids: readonly string[];
|
|
638
|
+
name: string;
|
|
639
|
+
/** `#rrggbb`. */
|
|
640
|
+
color: string;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/** One comment pin as the stage draws it on the camera pane's frame
|
|
644
|
+
* (bridge v42; the Studio's pins from v45). */
|
|
645
|
+
export interface ShotBoardPin {
|
|
646
|
+
threadId: string;
|
|
647
|
+
/** Where on the picture, 0..1 across and down the frame rect. */
|
|
648
|
+
u: number;
|
|
649
|
+
v: number;
|
|
650
|
+
/** Up to two letters, the thread author's initials. */
|
|
651
|
+
initials: string;
|
|
652
|
+
/** The author's colour, a hex string: the stage has no chrome tokens. */
|
|
653
|
+
color: string;
|
|
654
|
+
/** The open thread's pin, drawn with a ring. */
|
|
655
|
+
active: boolean;
|
|
656
|
+
/** The pin's accessible name. */
|
|
657
|
+
label: string;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* One piece the stage isolated: which kind (a layer, a placed code component,
|
|
662
|
+
* a layer inside a component definition, a Shot's background, its post stack,
|
|
663
|
+
* a transition), where (the Shot, the layer, the field when known), what it
|
|
664
|
+
* threw, and the frame and document revision it was first seen at. The
|
|
665
|
+
* runtime's own record (`PieceFailure`, pieceFailures.ts), verbatim.
|
|
666
|
+
*/
|
|
667
|
+
export type StagePieceFailure = PieceFailure;
|
|
668
|
+
|
|
669
|
+
/** What the stage's shader compiler most recently established for one graph.
|
|
670
|
+
* It is live runtime state, never persisted with the material definition.
|
|
671
|
+
*
|
|
672
|
+
* `slot` is the glTF material index the report is about, or null for the
|
|
673
|
+
* layer-wide binding. A model with a Glass slot over a Studio base compiles two
|
|
674
|
+
* materials and can fail at exactly one of them, so a diagnostic that named
|
|
675
|
+
* only the layer would put a red badge on a graph that is fine. */
|
|
676
|
+
export type MaterialCompileDiagnostic =
|
|
677
|
+
| { status: "compiling"; materialId: string; layerId: string; slot: number | null }
|
|
678
|
+
| { status: "ready"; materialId: string; layerId: string; slot: number | null }
|
|
679
|
+
| { status: "error"; materialId: string; layerId: string; slot: number | null; message: string };
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* WHICH SURFACE the material workspace is editing.
|
|
683
|
+
*
|
|
684
|
+
* `slot: null` is the layer-wide binding — the whole model, and the only
|
|
685
|
+
* possibility for a primitive. A number is a glTF material index, stable
|
|
686
|
+
* because an asset id is a content hash (see `materialSlots.ts`).
|
|
687
|
+
*/
|
|
688
|
+
export interface MaterialPreviewTarget {
|
|
689
|
+
layerId: string;
|
|
690
|
+
slot: number | null;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/** The chrome's ask for a batch of node thumbnails. */
|
|
694
|
+
export interface NodePreviewRequest {
|
|
695
|
+
materialId: string;
|
|
696
|
+
layerId: string;
|
|
697
|
+
slot: number | null;
|
|
698
|
+
/** The VIEWPORT-VISIBLE nodes only, chosen by the chrome. The stage clamps
|
|
699
|
+
* to `MAX_NODE_PREVIEWS` rather than refusing, because a request that is one
|
|
700
|
+
* node too long is a scroll position, not a bug. */
|
|
701
|
+
nodeIds: readonly string[];
|
|
702
|
+
/** Thumbnail edge in device px, clamped to [32, 256]. */
|
|
703
|
+
size: number;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
export type NodePreviewResult =
|
|
707
|
+
| { nodeId: string; bitmap: ImageBitmap; message?: undefined }
|
|
708
|
+
| { nodeId: string; bitmap: null; message: string };
|
|
709
|
+
|
|
710
|
+
export interface NodePreviewBatch {
|
|
711
|
+
materialId: string;
|
|
712
|
+
/** The graph the stage actually drew. The chrome drops a batch whose
|
|
713
|
+
* signature is no longer current rather than painting a stale thumbnail
|
|
714
|
+
* over a graph the author has since edited. */
|
|
715
|
+
semanticSignature: string;
|
|
716
|
+
size: number;
|
|
717
|
+
results: readonly NodePreviewResult[];
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/** One atlas readback is one GPU stall, so the batch is bounded. 64 cells at
|
|
721
|
+
* 96px is a 768x768 target, which is cheaper than the graph it describes. */
|
|
722
|
+
export const MAX_NODE_PREVIEWS = 64;
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* The stage's component context: render ONE component standalone.
|
|
726
|
+
*
|
|
727
|
+
* The subject mounts on its own canvas (drawn as a plate over the working
|
|
728
|
+
* pane's clay backdrop, no scene, no post stack, no scene camera), and while a
|
|
729
|
+
* context is set the frames the chrome pushes through `seek` are SUBJECT-LOCAL
|
|
730
|
+
* (0 = the subject's own start).
|
|
731
|
+
*
|
|
732
|
+
* TWO SUBJECTS, ONE CONTEXT (v23). A shot places two things that are both
|
|
733
|
+
* called "component": an authored definition in `doc.components`, and a code
|
|
734
|
+
* component from the author's repo placed as an `instance` layer. Only the
|
|
735
|
+
* first could ever be opened, because only the first had something for the
|
|
736
|
+
* stage to render. The `code` arm gives the second one a subject too, and it
|
|
737
|
+
* does so WITHOUT a second render path: the stage builds a synthetic
|
|
738
|
+
* definition holding one instance of that component at contract defaults
|
|
739
|
+
* (`codePreviewDef`), so both arms land in the same mount.
|
|
740
|
+
*
|
|
741
|
+
* The zoom is on both arms; everything else differs, which is why this is a
|
|
742
|
+
* union and not one interface with optional halves.
|
|
743
|
+
*/
|
|
744
|
+
export type ShotComponentContext = ShotDefContext | ShotCodeContext;
|
|
745
|
+
|
|
746
|
+
/** A definition the loaded document holds. */
|
|
747
|
+
export interface ShotDefContext {
|
|
748
|
+
/** A `cmp_` id in the loaded document. */
|
|
749
|
+
def: string;
|
|
750
|
+
/**
|
|
751
|
+
* The chrome's zoom over the head-on render: 1 fits the whole canvas, 2
|
|
752
|
+
* shows it twice as large. Absent = 1.
|
|
753
|
+
*
|
|
754
|
+
* IT CROSSES AS A NUMBER AND NOT AS A CAMERA, because the frame is derived
|
|
755
|
+
* on the stage side (`componentFrame(size)`) and only the stage knows the
|
|
756
|
+
* pane it has to fit into. The zoom scales that frame's half-extents before
|
|
757
|
+
* the fit, so the "honest visible rect" promise the derived rig makes holds
|
|
758
|
+
* at every magnification instead of only at 1.
|
|
759
|
+
*/
|
|
760
|
+
zoom?: number;
|
|
761
|
+
/** The preview's backdrop (v45), the working pane's clear colour. Absent =
|
|
762
|
+
* the working pane's own token, as before v45. */
|
|
763
|
+
background?: ShotComponentBackground;
|
|
764
|
+
/** The preview loop's length in frames (v45): every seek inside the
|
|
765
|
+
* context wraps to `frame % loopFrames`. Absent = no wrap. */
|
|
766
|
+
loopFrames?: number;
|
|
767
|
+
/** TRIED values from the Components props panel (v46), exposed key ->
|
|
768
|
+
* Value, drawn exactly as a placement's overrides are. Editor-only and
|
|
769
|
+
* never persisted: "Apply to all instances" is what writes the definition.
|
|
770
|
+
* Absent or empty = the definition's own values. */
|
|
771
|
+
props?: Readonly<Record<string, Value>>;
|
|
772
|
+
/** True on the Components Edit tab (v48): the definition is being authored,
|
|
773
|
+
* so its one pane is the frame the draw tools, the pen, drops and the
|
|
774
|
+
* Select grammar map through. Absent on the Preview tab, which only views
|
|
775
|
+
* the definition: a drag there orbits and nothing on it writes the master. */
|
|
776
|
+
edit?: true;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
/**
|
|
780
|
+
* A code component from the author's repo, by REGISTRY ID.
|
|
781
|
+
*
|
|
782
|
+
* The id is all that crosses. The stage rebuilds the subject from it with the
|
|
783
|
+
* same pure function the chrome would, so the two sides cannot hold different
|
|
784
|
+
* subjects for one id, and a document is not involved at all: a code component
|
|
785
|
+
* can be opened from any context, including one where nothing places it.
|
|
786
|
+
*/
|
|
787
|
+
export interface ShotCodeContext {
|
|
788
|
+
/** "<module>#<Export>", the registry id and `ComponentRow.id`. */
|
|
789
|
+
code: string;
|
|
790
|
+
/** As `ShotDefContext.zoom`. */
|
|
791
|
+
zoom?: number;
|
|
792
|
+
/** As `ShotDefContext.background` (v45). */
|
|
793
|
+
background?: ShotComponentBackground;
|
|
794
|
+
/** As `ShotDefContext.loopFrames` (v45). */
|
|
795
|
+
loopFrames?: number;
|
|
796
|
+
/**
|
|
797
|
+
* Live default OVERRIDES from the defaults rail, contract KEY -> engine
|
|
798
|
+
* Value (curve/gradient as their encoded strings, `instance.props`' own
|
|
799
|
+
* form — `buildProps` decodes). Absent or empty = every prop at its
|
|
800
|
+
* declared default, exactly the v23 behaviour.
|
|
801
|
+
*
|
|
802
|
+
* EDITOR-ONLY, NEVER PERSISTED: the stage merges these over the synthetic
|
|
803
|
+
* preview instance's props for THIS render; committing a value goes through
|
|
804
|
+
* the defaults-persist API and lands in source, at which point the chrome
|
|
805
|
+
* drops the override. The def identity stays stable — only the props map
|
|
806
|
+
* changes — so nothing remounts under a scrub.
|
|
807
|
+
*/
|
|
808
|
+
props?: Readonly<Record<string, Value>>;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
/** `ShotCodeContext.props` values a stage may accept from a chrome: finite
|
|
812
|
+
* numbers, strings, booleans, and finite numeric tuples of 2..4 — the wire
|
|
813
|
+
* shapes of every animatable contract kind. Anything else is DROPPED, not
|
|
814
|
+
* refused: one malformed key must not blank an otherwise valid preview.
|
|
815
|
+
* Returns undefined when nothing survives, so the caller can omit the field
|
|
816
|
+
* entirely and keep the v23 object shape.
|
|
817
|
+
*
|
|
818
|
+
* KNOWN CEILING: a string on a curve/gradient KEY is decoded by `buildProps`
|
|
819
|
+
* inside the render, and an undecodable one throws there — the same refusal
|
|
820
|
+
* a corrupt document value has always produced. This validator cannot see
|
|
821
|
+
* contract kinds, so it cannot close that; the shipped rail closes it by
|
|
822
|
+
* construction (it validates + encodes composite values before they reach
|
|
823
|
+
* the bridge), and any other chrome owes the same care. */
|
|
824
|
+
export function validPreviewProps(raw: unknown): Record<string, Value> | undefined {
|
|
825
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return undefined;
|
|
826
|
+
const out: Record<string, Value> = {};
|
|
827
|
+
for (const [key, value] of Object.entries(raw as Record<string, unknown>)) {
|
|
828
|
+
if (typeof value === "string" || typeof value === "boolean") {
|
|
829
|
+
out[key] = value;
|
|
830
|
+
continue;
|
|
831
|
+
}
|
|
832
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
833
|
+
out[key] = value;
|
|
834
|
+
continue;
|
|
835
|
+
}
|
|
836
|
+
if (
|
|
837
|
+
Array.isArray(value) &&
|
|
838
|
+
value.length >= 2 &&
|
|
839
|
+
value.length <= 4 &&
|
|
840
|
+
value.every((n) => typeof n === "number" && Number.isFinite(n))
|
|
841
|
+
) {
|
|
842
|
+
out[key] = value as Value;
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
return Object.keys(out).length === 0 ? undefined : out;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
/** The subject a context names, for callers that only need to tell one context
|
|
849
|
+
* from another: the fake bridge's log line, and the stage's own re-push
|
|
850
|
+
* equality check. */
|
|
851
|
+
export function componentContextSubject(ctx: ShotComponentContext): string {
|
|
852
|
+
return "code" in ctx ? ctx.code : ctx.def;
|
|
853
|
+
}
|
|
119
854
|
|
|
120
855
|
/** What the stage reports once it has a renderer and a document. */
|
|
121
856
|
export interface ShotStageInfo {
|
|
@@ -130,6 +865,37 @@ export interface ShotStageInfo {
|
|
|
130
865
|
backend: string;
|
|
131
866
|
}
|
|
132
867
|
|
|
868
|
+
/** One second of presentation, as the stage measured it.
|
|
869
|
+
*
|
|
870
|
+
* `expectedFrames` is what the document's rate asked for over the same window,
|
|
871
|
+
* so a reader can say "28 of 30" rather than only "28" — the pair is what makes
|
|
872
|
+
* the number judgeable. */
|
|
873
|
+
export interface StagePerformanceReport {
|
|
874
|
+
presentedFps: number;
|
|
875
|
+
expectedFps: number;
|
|
876
|
+
droppedPublications: number;
|
|
877
|
+
/** The GPU's own time per frame over the same second, its p95 in ms (v52),
|
|
878
|
+
* off three's timestamp queries: render passes only, so an upload or a
|
|
879
|
+
* compile is not in it (the stage's gpuTimer.ts). Null when the renderer
|
|
880
|
+
* has no timer or no frame's time landed in the window. */
|
|
881
|
+
gpuMs: number | null;
|
|
882
|
+
/** The share of the display's density the window's last frame rendered at
|
|
883
|
+
* (v52): 1, or a step below it while the playback render scale holds one
|
|
884
|
+
* (the stage's renderScaleController.ts). The canvas itself never resizes. */
|
|
885
|
+
renderScale: number;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
/** The Preferences row "Playback resolution" (v52). `auto` lets the stage
|
|
889
|
+
* render a played frame below the display's density while the GPU cannot
|
|
890
|
+
* keep up, `full` never does, and `fast` starts at 0.7 of it and never goes
|
|
891
|
+
* above. Paused frames, stills and exports are always at full density. */
|
|
892
|
+
export const PLAYBACK_RESOLUTIONS = ["auto", "full", "fast"] as const;
|
|
893
|
+
export type PlaybackResolution = (typeof PLAYBACK_RESOLUTIONS)[number];
|
|
894
|
+
|
|
895
|
+
export function isPlaybackResolution(value: unknown): value is PlaybackResolution {
|
|
896
|
+
return (PLAYBACK_RESOLUTIONS as readonly unknown[]).includes(value);
|
|
897
|
+
}
|
|
898
|
+
|
|
133
899
|
/** A screen-space quad for one layer: TL, TR, BR, BL as x,y pairs, in CSS
|
|
134
900
|
* pixels relative to the stage viewport's top-left.
|
|
135
901
|
*
|
|
@@ -141,6 +907,82 @@ export interface ShotScreenQuad {
|
|
|
141
907
|
pts: readonly [number, number, number, number, number, number, number, number];
|
|
142
908
|
}
|
|
143
909
|
|
|
910
|
+
/** Editor-only construction plane. `selection` means the named layer's local
|
|
911
|
+
* XY plane, and falls back visibly to world XY when the layer disappears. */
|
|
912
|
+
export type WorkPlaneTarget =
|
|
913
|
+
| { kind: "xy" | "xz" | "yz" | "view" }
|
|
914
|
+
| { kind: "selection"; layerId: string };
|
|
915
|
+
|
|
916
|
+
/** A work plane resolved into design coordinates (+Y down, +Z away). */
|
|
917
|
+
export interface ResolvedWorkPlane {
|
|
918
|
+
target: WorkPlaneTarget;
|
|
919
|
+
origin: readonly [number, number, number];
|
|
920
|
+
xAxis: readonly [number, number, number];
|
|
921
|
+
yAxis: readonly [number, number, number];
|
|
922
|
+
normal: readonly [number, number, number];
|
|
923
|
+
fallback: boolean;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
/** The stage's world-space draft. The chrome recentres it into one spline
|
|
927
|
+
* layer at commit, assigning stable point ids in the process. */
|
|
928
|
+
export interface SplineCreateDraft {
|
|
929
|
+
basis: SplineBasis;
|
|
930
|
+
closed: boolean;
|
|
931
|
+
points: readonly SplinePoint3D[];
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/** The interpolation new spline drafts use. Workspace state, never document data. */
|
|
935
|
+
export type SplineBasis = "bezier" | "catmull-rom";
|
|
936
|
+
|
|
937
|
+
export type SplinePointPart = "anchor" | "in" | "out";
|
|
938
|
+
|
|
939
|
+
/** Which part of a motion path key a drag holds (v44): the key's own dot, or
|
|
940
|
+
* one of its spatial Bezier handles (schema v40). The chrome refuses `"in"`
|
|
941
|
+
* and `"out"` off a bezier path, and on the side no segment uses. */
|
|
942
|
+
export type PathKeyPart = "key" | "in" | "out";
|
|
943
|
+
|
|
944
|
+
/** A path key drag's offset from where it started, in the layer's stored
|
|
945
|
+
* position units: parent space, +y DOWN, +z away, the numbers the
|
|
946
|
+
* inspector's Position row shows. The stage measures
|
|
947
|
+
* the whole drag, never a step, so a dropped event loses nothing. */
|
|
948
|
+
export interface PathKeyDelta {
|
|
949
|
+
dx: number;
|
|
950
|
+
dy: number;
|
|
951
|
+
dz: number;
|
|
952
|
+
/** A handle drag only (Alt): move this handle alone. Without it the chrome
|
|
953
|
+
* turns the opposite handle to stay in line, keeping its length. Read per
|
|
954
|
+
* move, so the pair can break mid-drag. */
|
|
955
|
+
breakPair?: boolean;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
/** The per-viewer preferences the stage acts on: its furniture (v44) and the
|
|
959
|
+
* playback resolution (v52). */
|
|
960
|
+
export interface EditorChrome {
|
|
961
|
+
/** Rulers along the camera pane's top and left edges. */
|
|
962
|
+
rulers: boolean;
|
|
963
|
+
/** Smart guides: a dragged guide snaps to the frame's edges and centre. */
|
|
964
|
+
smartGuides: boolean;
|
|
965
|
+
/** What a played frame may render at (v52, `PlaybackResolution`). It moves
|
|
966
|
+
* no furniture and ends no preparing pass, which draws at full density. */
|
|
967
|
+
playbackResolution: PlaybackResolution;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
/** How a guide drag ended (v44). `"remove"` is a guide dragged back onto its
|
|
971
|
+
* ruler; a guide created from the ruler and dropped there is never added. */
|
|
972
|
+
export type GuideGestureOutcome = "commit" | "remove" | "cancel";
|
|
973
|
+
|
|
974
|
+
export interface SplineEditContext {
|
|
975
|
+
layerId: string;
|
|
976
|
+
selectedPointIds: readonly string[];
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
export interface SplinePointPatch {
|
|
980
|
+
layerId: string;
|
|
981
|
+
pointId: string;
|
|
982
|
+
part: SplinePointPart;
|
|
983
|
+
value: readonly [number, number, number];
|
|
984
|
+
}
|
|
985
|
+
|
|
144
986
|
/** The stage's view of the working area: how much of the frame is on screen and
|
|
145
987
|
* where. Owned by the stage (it is a camera `setViewOffset`), mirrored to the
|
|
146
988
|
* chrome so the zoom readout and "fit" have something to read and write. */
|
|
@@ -178,6 +1020,71 @@ export interface ShotBridgeHandlers {
|
|
|
178
1020
|
onReady(info: ShotStageInfo): void;
|
|
179
1021
|
/** The stage failed in a way the author needs to see. */
|
|
180
1022
|
onError(message: string): void;
|
|
1023
|
+
/**
|
|
1024
|
+
* The stage still OWES THE OPEN SUBJECT its first whole presentation, or no
|
|
1025
|
+
* longer does (v51).
|
|
1026
|
+
*
|
|
1027
|
+
* The subject is what the stage shows: the Project (`doc.id`), a component
|
|
1028
|
+
* context, or a material preview's layer and slot. A whole presentation is
|
|
1029
|
+
* a clock echo of the current subject, drawn with no external readiness
|
|
1030
|
+
* claim open and every placed component's module installed. Once this
|
|
1031
|
+
* renderer has drawn one, the subject is latched and loads no longer make
|
|
1032
|
+
* the stage busy: a font, a texture, a model or a paused video seek arriving
|
|
1033
|
+
* later holds nothing. A new subject, a new renderer (a new export canvas)
|
|
1034
|
+
* or a new stage document owes one again.
|
|
1035
|
+
*
|
|
1036
|
+
* A PAUSED VIDEO SEEK holds the subject's FIRST whole presentation only. It
|
|
1037
|
+
* never holds again after that, and the latch never re-arms on Pause.
|
|
1038
|
+
*
|
|
1039
|
+
* False with no document, and false while the stage cannot present at all
|
|
1040
|
+
* (a fatal error, a lost context, a renderer compile failure), so nothing
|
|
1041
|
+
* waits on it for ever. A standing fallback (a texture, html, font or glyph
|
|
1042
|
+
* failure) does not release the hold: the stage still presents, so the
|
|
1043
|
+
* latch closes anyway.
|
|
1044
|
+
*
|
|
1045
|
+
* Sent on connect and then on every CHANGE of the value, coalesced to a
|
|
1046
|
+
* microtask and deduped stage-side.
|
|
1047
|
+
*
|
|
1048
|
+
* THIS IS NOT THE EXPORT GATE'S QUESTION. A capture waits on every external
|
|
1049
|
+
* claim at every frame it takes, a paused video seek included. See
|
|
1050
|
+
* `bridgeClient.ts`.
|
|
1051
|
+
*/
|
|
1052
|
+
onStageBusy(pending: boolean): void;
|
|
1053
|
+
/**
|
|
1054
|
+
* The pieces the stage isolated (v34), WHOLE, on every change: a layer, a
|
|
1055
|
+
* background, a post stack or a transition that threw while the rest of the
|
|
1056
|
+
* Shot kept drawing. Empty once every piece renders again. Sent from inside
|
|
1057
|
+
* the stage's apply pass, so it must not throw.
|
|
1058
|
+
*
|
|
1059
|
+
* The same list refuses an exact export or still of any frame a listed piece
|
|
1060
|
+
* belongs to, by name (the stage's own gate, `bridgeClient.ts`).
|
|
1061
|
+
*/
|
|
1062
|
+
onPieceFailures(failures: readonly StagePieceFailure[]): void;
|
|
1063
|
+
/**
|
|
1064
|
+
* What `health()` answers changed (v35): a presentation of another
|
|
1065
|
+
* document, revision or module epoch, a piece, a render fallback, a
|
|
1066
|
+
* component failure, the crash, or an uncaught error. Also sent when
|
|
1067
|
+
* `preparationKey().base` moves (v51), so a chrome with nothing left to
|
|
1068
|
+
* prepare looks again. No payload: the chrome reads `health()` when it
|
|
1069
|
+
* wants the answer, which is when an agent asks. Never per frame. Sent from
|
|
1070
|
+
* inside the stage's presentation, so it must not throw.
|
|
1071
|
+
*/
|
|
1072
|
+
onStageHealth(): void;
|
|
1073
|
+
/**
|
|
1074
|
+
* What the stage PRESENTED over the last second, or null once it stops.
|
|
1075
|
+
*
|
|
1076
|
+
* Sent once per closed telemetry window, and windows roll only during
|
|
1077
|
+
* playback, so this is 1Hz while playing and silent otherwise. Null on pause
|
|
1078
|
+
* is a retraction rather than a zero: no frames are expected of a stopped
|
|
1079
|
+
* stage, and 0 fps would read as a stall.
|
|
1080
|
+
*
|
|
1081
|
+
* It has to come from the stage. The chrome knows what it ASKED for, and the
|
|
1082
|
+
* stage coalesces requests and drops publications exactly when the ask and
|
|
1083
|
+
* the picture come apart, which is the only time the number is interesting.
|
|
1084
|
+
*/
|
|
1085
|
+
onPerformance(report: StagePerformanceReport | null): void;
|
|
1086
|
+
/** The real stage is the material specimen; report what its compiler did. */
|
|
1087
|
+
onMaterialCompile(diagnostic: MaterialCompileDiagnostic): void;
|
|
181
1088
|
/**
|
|
182
1089
|
* A pick, in DOCUMENT order front-to-back — the WHOLE ordered hit list, not
|
|
183
1090
|
* just the nearest.
|
|
@@ -202,6 +1109,10 @@ export interface ShotBridgeHandlers {
|
|
|
202
1109
|
* isolation stack, and then two places would decide what entering means.
|
|
203
1110
|
*/
|
|
204
1111
|
onEnterLayer(hits: readonly string[], pane: StagePane): void;
|
|
1112
|
+
/** The inline text editor closed with this content (v38). One edit, by id:
|
|
1113
|
+
* a click outside can move the selection before the editor's blur lands.
|
|
1114
|
+
* Empty (or blank) content removes the layer. */
|
|
1115
|
+
onTextEdit(layerId: string, content: string): void;
|
|
205
1116
|
/**
|
|
206
1117
|
* A RIGHT PRESS: the same ordered hit stack `onPick` sends, plus the point to
|
|
207
1118
|
* open a menu at.
|
|
@@ -214,8 +1125,16 @@ export interface ShotBridgeHandlers {
|
|
|
214
1125
|
* `at` is in CLIENT coordinates and needs no translation: the stage iframe is
|
|
215
1126
|
* `position: fixed; inset: 0`, so a point in the stage's document is the same
|
|
216
1127
|
* point in the chrome's.
|
|
1128
|
+
*
|
|
1129
|
+
* `pathKey` (v44) is the motion path key dot under the press, when there is
|
|
1130
|
+
* one: the menu is then that key's (seek, curved path, delete).
|
|
217
1131
|
*/
|
|
218
|
-
onContextMenu(
|
|
1132
|
+
onContextMenu(
|
|
1133
|
+
hits: readonly string[],
|
|
1134
|
+
pane: StagePane,
|
|
1135
|
+
at: { x: number; y: number },
|
|
1136
|
+
pathKey?: { layerId: string; keyId: string },
|
|
1137
|
+
): void;
|
|
219
1138
|
/**
|
|
220
1139
|
* A mesh layer's triangle count, once its model has loaded — or null when the
|
|
221
1140
|
* layer unmounts or its model is swapped.
|
|
@@ -229,6 +1148,37 @@ export interface ShotBridgeHandlers {
|
|
|
229
1148
|
* heavy scene, and neither half can read a `BufferGeometry`.
|
|
230
1149
|
*/
|
|
231
1150
|
onMeshStats(layerId: string, triangles: number | null): void;
|
|
1151
|
+
/**
|
|
1152
|
+
* The glTF materials a model actually ships, pushed once when it parses.
|
|
1153
|
+
*
|
|
1154
|
+
* The same "known exactly once, at parse" argument `onMeshStats` makes: a
|
|
1155
|
+
* material's index, name, colour and map set live in the FILE, not in the
|
|
1156
|
+
* document, so no amount of reading `Doc3D` tells the chrome that slot 3 is
|
|
1157
|
+
* called "Screen" and carries a base-colour map. Without it the slot rail
|
|
1158
|
+
* could only offer bare indices.
|
|
1159
|
+
*
|
|
1160
|
+
* `null` on unmount or a model swap, so a stale list never outlives the
|
|
1161
|
+
* model it described.
|
|
1162
|
+
*/
|
|
1163
|
+
onMeshMaterialSlots(layerId: string, slots: readonly MeshMaterialSlotInfo[] | null): void;
|
|
1164
|
+
/**
|
|
1165
|
+
* What an instance module that never read its box draws at scale 1, design
|
|
1166
|
+
* px (v38): pushed once after its first commit while the layer has no
|
|
1167
|
+
* `instance.naturalSize`. The chrome stores it only for a component it just
|
|
1168
|
+
* placed, and sets the box to it in the same history entry (F41).
|
|
1169
|
+
*/
|
|
1170
|
+
onInstanceNaturalSize(layerId: string, size: readonly [number, number]): void;
|
|
1171
|
+
/** An auto-width text box's measured size, design px (v40, `autoTextSize`):
|
|
1172
|
+
* pushed when the stored `transform.size` is off. The chrome writes it in
|
|
1173
|
+
* the current history entry, keeping the box's aligned edge. */
|
|
1174
|
+
onTextAutoSize(layerId: string, size: readonly [number, number]): void;
|
|
1175
|
+
/** A comment pin was clicked (v42): from v45, a Studio pin on the camera
|
|
1176
|
+
* pane. */
|
|
1177
|
+
onCommentPin(threadId: string): void;
|
|
1178
|
+
/** A click on the camera frame with the Studio comment tool armed (v45):
|
|
1179
|
+
* the Shot and Shot-local frame on screen, the point, and the topmost
|
|
1180
|
+
* layer under it. */
|
|
1181
|
+
onStudioCommentAt(anchor: ShotStudioAnchor): void;
|
|
232
1182
|
/**
|
|
233
1183
|
* The key-light gizmo's drag, as the same three-call shape every other
|
|
234
1184
|
* gesture uses: open a scrub, re-derive from its base on every emit, commit
|
|
@@ -271,6 +1221,23 @@ export interface ShotBridgeHandlers {
|
|
|
271
1221
|
* view change is a mirror the chrome is free to throttle.
|
|
272
1222
|
*/
|
|
273
1223
|
onIsolationOrbitTaken(): void;
|
|
1224
|
+
/**
|
|
1225
|
+
* GIVE THE CAMERA BACK: re-derive the head-on rig for whatever this pane is
|
|
1226
|
+
* looking at. The exact inverse of `onIsolationOrbitTaken`.
|
|
1227
|
+
*
|
|
1228
|
+
* The hand-over above is one-way by design, and Home is the key that undoes
|
|
1229
|
+
* it — but the material workspace covers the panel that key belongs to, and
|
|
1230
|
+
* in that mode EVERY drag orbits, so the first accidental nudge left the
|
|
1231
|
+
* object crooked with no visible way back. A double-click on the object is
|
|
1232
|
+
* the gesture, and it starts on the stage because the chrome cannot receive
|
|
1233
|
+
* it: the workspace body is `pointer-events: none` so its drags reach the
|
|
1234
|
+
* stage, which also means nothing there is clickable.
|
|
1235
|
+
*
|
|
1236
|
+
* It carries no argument on purpose. WHAT to re-derive is the chrome's
|
|
1237
|
+
* question — it owns the isolation and the component context that decide it —
|
|
1238
|
+
* and this is only the news that the author asked.
|
|
1239
|
+
*/
|
|
1240
|
+
onFitRequest(): void;
|
|
274
1241
|
/** The stage's own pan/zoom changed. Camera pane only: the working pane's
|
|
275
1242
|
* view is a `WorkingView`, and the two are not the same shape. */
|
|
276
1243
|
onViewChange(view: ShotView): void;
|
|
@@ -319,18 +1286,46 @@ export interface ShotBridgeHandlers {
|
|
|
319
1286
|
// for being under a shot. One scrub is open at a time either way (engine's
|
|
320
1287
|
// history throws on a second), which the pointer already guarantees.
|
|
321
1288
|
//
|
|
322
|
-
// It brackets
|
|
323
|
-
//
|
|
324
|
-
//
|
|
325
|
-
// already crosses as `onWorkingViewChange`.
|
|
1289
|
+
// It brackets the camera gizmo's drags in the working pane and, while
|
|
1290
|
+
// PILOTING (v29), the Camera pane's own navigation: an orbit, a pan and a
|
|
1291
|
+
// wheel there are framing deltas like any other.
|
|
326
1292
|
/** Answers whether the scrub opened, for `onGestureStart`'s reason. */
|
|
327
1293
|
onFramingGestureStart(): boolean;
|
|
328
|
-
/**
|
|
329
|
-
|
|
1294
|
+
/**
|
|
1295
|
+
* Measured FROM THE PRESS, same rule as `onGesture`. `dzoom` is a factor.
|
|
1296
|
+
*
|
|
1297
|
+
* `origin: "wheel"` (v29) is a notch with no press and no release around
|
|
1298
|
+
* it: the chrome opens the scrub itself and closes it over silence, the way
|
|
1299
|
+
* follow's wheel used to be bracketed. ANSWERS whether the document took
|
|
1300
|
+
* the write — false is the fork's refusal (a held camera, a path) — so the
|
|
1301
|
+
* pilot badge can flash rather than the pane silently not moving.
|
|
1302
|
+
*/
|
|
1303
|
+
onFramingGesture(delta: FramingDelta, origin?: "wheel"): boolean;
|
|
330
1304
|
onFramingGestureEnd(commit: boolean): void;
|
|
1305
|
+
/** The pilot badge's own EJECT (v29): hands off the camera, which stays
|
|
1306
|
+
* where it is. The chrome owns the mode, so this is only the news. */
|
|
1307
|
+
onLeavePilot(): void;
|
|
1308
|
+
/** Which component drives the render camera this frame, by name, or null
|
|
1309
|
+
* when the document's rig does (v29). Pushed on change, never per frame. */
|
|
1310
|
+
onCameraDriver(name: string | null): void;
|
|
1311
|
+
/**
|
|
1312
|
+
* A PATH MOVE'S WAYPOINT, dragged in the working pane.
|
|
1313
|
+
*
|
|
1314
|
+
* The same bracket as the three above — the scrub is already open and the
|
|
1315
|
+
* camera lane is already the one that owns it — but a different write: this
|
|
1316
|
+
* moves one pose in a list rather than the framing the camera resolves to.
|
|
1317
|
+
* `writeFraming` REFUSES a drag over a path for exactly that reason (there is
|
|
1318
|
+
* no single end for a gesture to land on), and this is the answer to the
|
|
1319
|
+
* refusal: name the pose.
|
|
1320
|
+
*
|
|
1321
|
+
* `dx`/`dy` are design px MEASURED FROM THE PRESS, `onGesture`'s rule, so a
|
|
1322
|
+
* coalesced move cannot make the drag drift.
|
|
1323
|
+
*/
|
|
1324
|
+
onWaypointGesture(shotId: string, index: number, delta: { dx: number; dy: number }): void;
|
|
331
1325
|
|
|
332
1326
|
/**
|
|
333
|
-
* INSERT A LAYER. The
|
|
1327
|
+
* INSERT A LAYER. The frame pane's draw lane (the camera pane over a Shot,
|
|
1328
|
+
* an open definition's one pane inside it), and the pen's commit.
|
|
334
1329
|
*
|
|
335
1330
|
* ── THE POINTS ARE DESIGN COORDINATES, NOT SCREEN ONES ─────────────────
|
|
336
1331
|
*
|
|
@@ -353,8 +1348,16 @@ export interface ShotBridgeHandlers {
|
|
|
353
1348
|
* carries handles now and crosses as `onPenCommit` below — but `onDraw`
|
|
354
1349
|
* still accepts `"path"`, because `layerFromDraw` remains the way an
|
|
355
1350
|
* agent-free caller mints a polyline path.
|
|
1351
|
+
*
|
|
1352
|
+
* `under` is the pick under a TEXT tool CLICK (no drag), front first. A
|
|
1353
|
+
* click on a text layer edits it rather than stacking a new one, the
|
|
1354
|
+
* Figma and Paper rule; the chrome decides, since it owns the layer kinds.
|
|
356
1355
|
*/
|
|
357
|
-
onDraw(
|
|
1356
|
+
onDraw(
|
|
1357
|
+
tool: InsertTool,
|
|
1358
|
+
points: readonly (readonly [number, number])[],
|
|
1359
|
+
under?: readonly string[],
|
|
1360
|
+
): void;
|
|
358
1361
|
|
|
359
1362
|
/**
|
|
360
1363
|
* COMMIT THE PEN'S PATH: anchors, their bezier handles, and whether the loop
|
|
@@ -374,6 +1377,60 @@ export interface ShotBridgeHandlers {
|
|
|
374
1377
|
*/
|
|
375
1378
|
onPenCommit(data: PathData): void;
|
|
376
1379
|
|
|
1380
|
+
/** Commit a working-pane 3D spline draft as one layer and one undo entry. */
|
|
1381
|
+
onSplineCreateCommit(draft: SplineCreateDraft): void;
|
|
1382
|
+
/** Point-mode selection remains chrome-owned, just like layer selection. */
|
|
1383
|
+
onSplinePointPick(layerId: string, pointId: string, additive: boolean): void;
|
|
1384
|
+
/** A point/handle drag, bracketed into one document history entry. */
|
|
1385
|
+
onSplinePointGestureStart(layerId: string, pointId: string, part: SplinePointPart): boolean;
|
|
1386
|
+
onSplinePointGesture(patch: SplinePointPatch): void;
|
|
1387
|
+
onSplinePointGestureEnd(commit: boolean): void;
|
|
1388
|
+
/**
|
|
1389
|
+
* A ruler guide drag, bracketed into one history entry (v44).
|
|
1390
|
+
*
|
|
1391
|
+
* `guideId` null CREATES a guide on `axis`, pulled out of a ruler; an id
|
|
1392
|
+
* moves that guide. Returns false when the chrome refuses (a viewer, an
|
|
1393
|
+
* unknown id), and the stage then draws nothing. `at` is the guide's
|
|
1394
|
+
* position in the inspector's units: centre origin, y UP, which is what the
|
|
1395
|
+
* ruler under it reads.
|
|
1396
|
+
*/
|
|
1397
|
+
onGuideGestureStart(guideId: string | null, axis: "x" | "y"): boolean;
|
|
1398
|
+
onGuideGesture(at: number): void;
|
|
1399
|
+
onGuideGestureEnd(outcome: GuideGestureOutcome): void;
|
|
1400
|
+
/** Set one guide's position from the numeric entry: one history entry. */
|
|
1401
|
+
onGuideSet(guideId: string, at: number): void;
|
|
1402
|
+
/** Delete one guide (a selected guide and Delete). */
|
|
1403
|
+
onGuideRemove(guideId: string): void;
|
|
1404
|
+
/**
|
|
1405
|
+
* A motion path key drag, bracketed into one history entry (v44).
|
|
1406
|
+
*
|
|
1407
|
+
* `keyId` is a key on the layer's `transform.position` track. Each
|
|
1408
|
+
* `onPathKeyGesture` carries the WHOLE offset since the start, in position
|
|
1409
|
+
* units, and the chrome writes start + offset. `part` is `"key"` for the
|
|
1410
|
+
* dot, or a Bezier handle (`"in"`, `"out"`) on a bezier path: the chrome
|
|
1411
|
+
* then writes the handle's offset, mirroring the other one unless the delta
|
|
1412
|
+
* says `breakPair`.
|
|
1413
|
+
*/
|
|
1414
|
+
onPathKeyGestureStart(layerId: string, keyId: string, part: PathKeyPart): boolean;
|
|
1415
|
+
onPathKeyGesture(delta: PathKeyDelta): void;
|
|
1416
|
+
onPathKeyGestureEnd(commit: boolean): void;
|
|
1417
|
+
/** A double-click on a motion path key dot (v44). The chrome toggles the
|
|
1418
|
+
* key between corner and smooth on a bezier path, and seeks to it on any
|
|
1419
|
+
* other. */
|
|
1420
|
+
onPathKeyDoubleClick(layerId: string, keyId: string): void;
|
|
1421
|
+
/** Insert an anchor after a segment's leading point. */
|
|
1422
|
+
onSplineSegmentInsert(
|
|
1423
|
+
layerId: string,
|
|
1424
|
+
afterPointId: string,
|
|
1425
|
+
point: SplinePoint3D,
|
|
1426
|
+
/** Local progress in the authored span, used for a shape-preserving Bezier split. */
|
|
1427
|
+
spanProgress?: number,
|
|
1428
|
+
): void;
|
|
1429
|
+
/** Delete selected anchors in point mode, subject to the valid-curve floor. */
|
|
1430
|
+
onSplinePointDelete(layerId: string, pointIds: readonly string[]): void;
|
|
1431
|
+
/** Enter confirms point mode and Escape leaves it when no drag is live. */
|
|
1432
|
+
onSplinePointModeEnd(layerId: string): void;
|
|
1433
|
+
|
|
377
1434
|
/** A key the STAGE received. Returns true when the chrome consumed it, so the
|
|
378
1435
|
* stage knows whether to preventDefault. Keyboard events go to ONE document,
|
|
379
1436
|
* and once the canvas has focus that document is the stage. */
|
|
@@ -440,12 +1497,36 @@ export interface ShotStageBridge {
|
|
|
440
1497
|
* called: there is nothing worth painting before a chrome exists, and the
|
|
441
1498
|
* document arrives immediately after. */
|
|
442
1499
|
connect(handlers: ShotBridgeHandlers): void;
|
|
443
|
-
/** Replace the document. Cheap when the reference is unchanged.
|
|
444
|
-
|
|
1500
|
+
/** Replace the document. Cheap when the reference is unchanged. `rev` is
|
|
1501
|
+
* the saved revision it is (v34), or null for an edit not yet saved: it is
|
|
1502
|
+
* stamped on a piece failure first seen while this document is on stage. */
|
|
1503
|
+
loadDoc(doc: Doc3D, rev?: string | null): void;
|
|
445
1504
|
/** Park the studio clock on an integer MASTER frame and repaint. */
|
|
446
1505
|
seek(frame: number): void;
|
|
1506
|
+
/**
|
|
1507
|
+
* The transport is running, or has stopped.
|
|
1508
|
+
*
|
|
1509
|
+
* SCHEDULING ONLY. The stage may use this to decide WHEN work happens — a
|
|
1510
|
+
* repaint left for the next seek, a resolution held down until the transport
|
|
1511
|
+
* stops — and may never let it reach a cache key or a sampled value. Every
|
|
1512
|
+
* frame that is rested on, captured or exported is drawn by the same code
|
|
1513
|
+
* whether or not it was played through, and two machines playing one document
|
|
1514
|
+
* still ask for the same pixels.
|
|
1515
|
+
*
|
|
1516
|
+
* A stage that ignores this call is CORRECT, only slower, which is what makes
|
|
1517
|
+
* the v20 gate a soft one.
|
|
1518
|
+
*
|
|
1519
|
+
* `true` also lets a freeze a preparing pass left standing lift on the first
|
|
1520
|
+
* complete presentation of the current frame in EITHER presentation (v51),
|
|
1521
|
+
* not only a paused one. Never at once: the canvas may still hold another
|
|
1522
|
+
* Shot's picture.
|
|
1523
|
+
*/
|
|
1524
|
+
setPlaying(playing: boolean): void;
|
|
447
1525
|
/** Which layers are selected, for the overlays. */
|
|
448
1526
|
setSelection(ids: readonly string[]): void;
|
|
1527
|
+
/** Other people's selections, drawn as outlines in their colours (v43).
|
|
1528
|
+
* Ids the drawn shot does not hold draw nothing. An empty list clears. */
|
|
1529
|
+
setPeerSelections(peers: readonly ShotPeerSelection[]): void;
|
|
449
1530
|
/** Screen quads for the current selection at the current frame, or null when
|
|
450
1531
|
* nothing is selected. The chrome polls this from its own render rather than
|
|
451
1532
|
* being pushed at, so an overlay re-render is never scheduled by the stage.
|
|
@@ -455,21 +1536,46 @@ export interface ShotStageBridge {
|
|
|
455
1536
|
* keeps getting the answer it always got. */
|
|
456
1537
|
selectionQuads(pane?: StagePane): readonly ShotScreenQuad[] | null;
|
|
457
1538
|
/**
|
|
458
|
-
* Which tool is armed, because it decides
|
|
459
|
-
*
|
|
460
|
-
*
|
|
461
|
-
*
|
|
1539
|
+
* Which tool is armed, because it decides what a press does (pick, draw, pen)
|
|
1540
|
+
* and the cursor. The plane a move unprojects onto is not a tool: a plain
|
|
1541
|
+
* drag slides along the layer's own plane and an Alt-drag keeps it flat (see
|
|
1542
|
+
* stage/interactions/move.ts).
|
|
462
1543
|
*/
|
|
463
1544
|
setTool(tool: ShotTool): void;
|
|
1545
|
+
/** Editor-only construction plane, re-pushed on attach and scene change. */
|
|
1546
|
+
setWorkPlane(target: WorkPlaneTarget): void;
|
|
1547
|
+
/** Interpolation for the next spline draft. A draft freezes it on its first anchor. */
|
|
1548
|
+
setSplineBasis(basis: SplineBasis): void;
|
|
1549
|
+
/** Enter/leave spline point mode and mirror the selected anchors. */
|
|
1550
|
+
setSplineEditContext(context: SplineEditContext | null): void;
|
|
464
1551
|
/** Smart-guide lines the chrome's snapping landed on, in DESIGN frame
|
|
465
1552
|
* coordinates. Pushed rather than polled because they change only while a
|
|
466
1553
|
* gesture is running and must vanish the instant it ends. */
|
|
467
1554
|
setSnapGuides(guides: readonly SnapGuide[]): void;
|
|
1555
|
+
/**
|
|
1556
|
+
* The layer a CHROME surface is pointing at (a timeline row under the
|
|
1557
|
+
* cursor), or null when it left. The stage lights that layer's outline
|
|
1558
|
+
* through the same hover path its own pointer uses — pointing at the row
|
|
1559
|
+
* answers "which one is this" without a click and without touching the
|
|
1560
|
+
* selection.
|
|
1561
|
+
*
|
|
1562
|
+
* Imperative on the stage side by design: under `frameloop="never"` every
|
|
1563
|
+
* state push is a React commit and therefore a GL draw, and a hover must
|
|
1564
|
+
* cost one SVG leaf repaint and zero draws (v22).
|
|
1565
|
+
*/
|
|
1566
|
+
hoverLayer(layerId: string | null): void;
|
|
468
1567
|
/** Drive the working-area view. */
|
|
469
1568
|
setView(view: ShotView): void;
|
|
470
1569
|
/** Fit the design frame to the CAMERA PANE with a margin. Returns the view it
|
|
471
1570
|
* landed on so the chrome's readout stays in step. */
|
|
472
1571
|
fitView(): ShotView;
|
|
1572
|
+
/** A point of the STAGE DOCUMENT (its client px, what a `drop` event on it
|
|
1573
|
+
* reports) as design px from the canvas centre, the coordinates `onDraw`
|
|
1574
|
+
* hands over, or null when it is not over the frame pane (the camera pane
|
|
1575
|
+
* over a Shot, an open definition's one pane inside it, where the point is
|
|
1576
|
+
* from the definition's canvas centre). A drop onto the frame places at
|
|
1577
|
+
* the point the author let go (v38). */
|
|
1578
|
+
designPointAt(clientX: number, clientY: number): readonly [number, number] | null;
|
|
473
1579
|
/**
|
|
474
1580
|
* How many views are on screen, and how the width is divided.
|
|
475
1581
|
*
|
|
@@ -478,6 +1584,115 @@ export interface ShotStageBridge {
|
|
|
478
1584
|
* is re-pushed on every attach.
|
|
479
1585
|
*/
|
|
480
1586
|
setStageLayout(layout: StageLayout): void;
|
|
1587
|
+
/**
|
|
1588
|
+
* THE AUTHOR IS WATCHING: draw the picture and nothing else.
|
|
1589
|
+
*
|
|
1590
|
+
* Video is the export's frame with every piece of authoring furniture taken
|
|
1591
|
+
* off it: no selection handles, no union box, no hover outline, no marquee,
|
|
1592
|
+
* no draw or transform gestures, no pen or spline draft. What stays is the
|
|
1593
|
+
* frame border, navigation (wheel, space-drag) and the plain click, which is
|
|
1594
|
+
* how an author picks the layer they want to work on and lands back in Edit.
|
|
1595
|
+
*
|
|
1596
|
+
* A FLAG AND NOT A LAYOUT, deliberately. The stage forces the camera-only
|
|
1597
|
+
* panes while this is on and hands the author's real layout back untouched
|
|
1598
|
+
* when it goes off, so `setStageLayout` keeps saying which EDITOR is waiting
|
|
1599
|
+
* underneath and this says whether anything is drawn on top of it.
|
|
1600
|
+
*
|
|
1601
|
+
* WORKSPACE STATE, like the layout: never written to a Doc3D, never in an
|
|
1602
|
+
* export, and re-pushed on every attach.
|
|
1603
|
+
*/
|
|
1604
|
+
setVideo(on: boolean): void;
|
|
1605
|
+
/**
|
|
1606
|
+
* The Project is VIEW ONLY for this person (v41): their role lets them look
|
|
1607
|
+
* but not edit. The stage keeps what looking needs (hover, click-select, the
|
|
1608
|
+
* marquee, the outlines, navigation) and drops what editing needs: no
|
|
1609
|
+
* handles, no drag gestures, no draw tools, no double-click text edit, no
|
|
1610
|
+
* camera framing drag, no key light drag. The chrome refuses every write as
|
|
1611
|
+
* well, so this only spares a viewer gestures that would be refused anyway.
|
|
1612
|
+
*
|
|
1613
|
+
* WORKSPACE STATE, like `setVideo`: never written to a Doc3D, re-pushed on
|
|
1614
|
+
* every attach.
|
|
1615
|
+
*/
|
|
1616
|
+
setReadOnly(on: boolean): void;
|
|
1617
|
+
/**
|
|
1618
|
+
* THE BOARD IS WATCHING, through a hole the size of a postcard.
|
|
1619
|
+
*
|
|
1620
|
+
* The same picture `setVideo` asks for (the camera pane, no furniture,
|
|
1621
|
+
* `watching` in StageApp answers for both), and a SECOND flag rather than a
|
|
1622
|
+
* second caller of the first: `setVideo` is the author choosing Video, it
|
|
1623
|
+
* writes the focus layout, empties the selection through the chrome's own
|
|
1624
|
+
* `setVideo` verb and collapses the inspector the board needs, and it is
|
|
1625
|
+
* refused outright while a component definition is open. None of that is
|
|
1626
|
+
* true of a board that simply wants to see the frame it is planning.
|
|
1627
|
+
*
|
|
1628
|
+
* It also carries the FRAMING, which `setVideo` does not: while this is on
|
|
1629
|
+
* the camera pane's view is derived from `fit()` every render instead of
|
|
1630
|
+
* read from `state.view`, so the shot lands whole inside the hole and
|
|
1631
|
+
* nothing has to be put back when the board closes.
|
|
1632
|
+
*
|
|
1633
|
+
* WORKSPACE STATE, like the layout: never written to a Doc3D and never in
|
|
1634
|
+
* an export. Only the component stage (ComponentStage) sends it, on its own
|
|
1635
|
+
* bridge: the shot stage starts with it off and the chrome never turns it on.
|
|
1636
|
+
*/
|
|
1637
|
+
setStoryboardPreview(on: boolean): void;
|
|
1638
|
+
/**
|
|
1639
|
+
* THE STUDIO'S COMMENT LAYER (bridge v45), or null for none.
|
|
1640
|
+
*
|
|
1641
|
+
* Pins draw over the camera pane's frame while stopped on their anchor's
|
|
1642
|
+
* Shot and frame; a click on one calls `onCommentPin`. Armed, a primary
|
|
1643
|
+
* press on the frame calls `onStudioCommentAt` instead of picking. Not
|
|
1644
|
+
* drawn inside a component context or in the material workspace.
|
|
1645
|
+
*
|
|
1646
|
+
* WORKSPACE STATE: never written to a Doc3D, re-pushed on every attach.
|
|
1647
|
+
*/
|
|
1648
|
+
setStudioComments(comments: ShotStudioComments | null): void;
|
|
1649
|
+
/**
|
|
1650
|
+
* THE SKETCH GUIDE (bridge v47), or null for none: one storyboard sketch
|
|
1651
|
+
* drawn as dashed outlines and labels in the camera frame, so it follows
|
|
1652
|
+
* the camera pane's view. Not drawn while watching, inside a component
|
|
1653
|
+
* context or in the material workspace.
|
|
1654
|
+
*
|
|
1655
|
+
* WORKSPACE STATE: never written to a Doc3D, re-pushed on every attach.
|
|
1656
|
+
*/
|
|
1657
|
+
setSketchGuide(guide: ShotSketchGuide | null): void;
|
|
1658
|
+
/**
|
|
1659
|
+
* THE FONT PREVIEW (bridge v50), or null for none: the font picker's
|
|
1660
|
+
* hovered or arrowed-to family drawn on the given text layers. Only the
|
|
1661
|
+
* picture changes: picking, overlays, auto-width measuring, stills,
|
|
1662
|
+
* coverage, health and every export keep the real document, and a face
|
|
1663
|
+
* that fails to load reports nothing and holds no readiness claim. While a
|
|
1664
|
+
* preview changes a text layer of the open document, `coverage()` refuses
|
|
1665
|
+
* (its picture is not the Shot's) and `capturePoster` answers null; a
|
|
1666
|
+
* preview arriving mid-poster aborts the poster. An export or a capture
|
|
1667
|
+
* draws the real document and the preview shows again when it ends. Until
|
|
1668
|
+
* the faces land the layers draw `family`, then `fallback`.
|
|
1669
|
+
*
|
|
1670
|
+
* WORKSPACE STATE: never written to a Doc3D, cleared on every attach and
|
|
1671
|
+
* when the document closes.
|
|
1672
|
+
*/
|
|
1673
|
+
setFontPreview(preview: ShotFontPreview | null): void;
|
|
1674
|
+
/**
|
|
1675
|
+
* THE MOTION PREVIEW (bridge v53), or null for none: the Motion section's
|
|
1676
|
+
* active preset stamped on the given layers. Only the picture changes, as
|
|
1677
|
+
* with the font preview: picking, overlays, health and every export keep
|
|
1678
|
+
* the real document, and a presentation drawn under it is never reported
|
|
1679
|
+
* as the Project's (`health()` reads pending until it clears). The chrome
|
|
1680
|
+
* moves through the preset's frames with ordinary seeks and seeks back to
|
|
1681
|
+
* the playhead when it clears. While it changes the open document,
|
|
1682
|
+
* `coverage()` refuses, `capturePoster` answers null and a preparing pass
|
|
1683
|
+
* gives way.
|
|
1684
|
+
*
|
|
1685
|
+
* WORKSPACE STATE: never written to a Doc3D, cleared on every attach and
|
|
1686
|
+
* when the document closes.
|
|
1687
|
+
*/
|
|
1688
|
+
setMotionPreview(preview: ShotMotionPreview | null): void;
|
|
1689
|
+
/**
|
|
1690
|
+
* OPEN THE INLINE TEXT EDITOR on one text layer, or null to close it
|
|
1691
|
+
* without committing (v38). The stage draws the editor over the layer, with
|
|
1692
|
+
* the content selected, and answers `onTextEdit` on Escape or a click
|
|
1693
|
+
* outside. Workspace state: never written to a Doc3D.
|
|
1694
|
+
*/
|
|
1695
|
+
editText(layerId: string | null): void;
|
|
481
1696
|
/**
|
|
482
1697
|
* ISOLATE A SUBTREE, or null for the whole scene.
|
|
483
1698
|
*
|
|
@@ -493,6 +1708,26 @@ export interface ShotStageBridge {
|
|
|
493
1708
|
* "the shot", which is exactly the split that already exists.
|
|
494
1709
|
*/
|
|
495
1710
|
setIsolation(layerId: string | null): void;
|
|
1711
|
+
/** Give the working pane to the material workspace. The target remains
|
|
1712
|
+
* rendered and navigable, but scene picking, transforms and draw tools stop.
|
|
1713
|
+
*
|
|
1714
|
+
* v17 addresses a SLOT rather than a layer, because a model's submeshes each
|
|
1715
|
+
* carry their own graph and the workspace edits exactly one of them. */
|
|
1716
|
+
setMaterialPreview(target: MaterialPreviewTarget | null): void;
|
|
1717
|
+
/**
|
|
1718
|
+
* ENTER OR LEAVE THE COMPONENT CONTEXT (v14): render one definition
|
|
1719
|
+
* standalone, or null for the ordinary scene render.
|
|
1720
|
+
*
|
|
1721
|
+
* WORKSPACE STATE like isolation: never written to a Doc3D, never in an
|
|
1722
|
+
* export, re-pushed on every attach. The stage is handed the def id and
|
|
1723
|
+
* derives everything from the document it already has. While a context is
|
|
1724
|
+
* set, `seek` frames are DEF-LOCAL; `setIsolation` and the camera/split
|
|
1725
|
+
* machinery are inert (the context owns the whole viewport). The chrome
|
|
1726
|
+
* clears isolation before setting a context — the two are mutually
|
|
1727
|
+
* exclusive views, and the stage refuses nothing here because the chrome
|
|
1728
|
+
* owns the mode.
|
|
1729
|
+
*/
|
|
1730
|
+
setComponentContext(ctx: ShotComponentContext | null): void;
|
|
496
1731
|
/**
|
|
497
1732
|
* Inside isolation, does the AUTHOR own the working camera?
|
|
498
1733
|
*
|
|
@@ -509,6 +1744,10 @@ export interface ShotStageBridge {
|
|
|
509
1744
|
*
|
|
510
1745
|
* `setIsolation` resets it to false on its own, so entering a subtree never
|
|
511
1746
|
* inherits the last one's mode.
|
|
1747
|
+
*
|
|
1748
|
+
* `false` while isolated is also Home: the stage re-fits the held isolation
|
|
1749
|
+
* frame from the current playhead. That frame otherwise stays still across
|
|
1750
|
+
* edits and playback.
|
|
512
1751
|
*/
|
|
513
1752
|
setIsolationOrbit(taken: boolean): void;
|
|
514
1753
|
/**
|
|
@@ -517,11 +1756,12 @@ export interface ShotStageBridge {
|
|
|
517
1756
|
*
|
|
518
1757
|
* ── WHY THE STAGE CANNOT MEASURE THIS ITSELF ────────────────────────────
|
|
519
1758
|
*
|
|
520
|
-
* A pane
|
|
521
|
-
*
|
|
522
|
-
*
|
|
523
|
-
*
|
|
524
|
-
*
|
|
1759
|
+
* A pane runs to the WINDOW'S OWN EDGES — `paneRects` insets nothing for the
|
|
1760
|
+
* chrome, and in a split the two panes divide the window between them —
|
|
1761
|
+
* because the stage iframe is pinned `position: fixed; inset: 0` and the
|
|
1762
|
+
* chrome's panels are docked ON TOP of it. So the top of the working pane is
|
|
1763
|
+
* behind the shell header, and there is no measurement the stage's document
|
|
1764
|
+
* can take to discover that — the panels are in the other document.
|
|
525
1765
|
*
|
|
526
1766
|
* `Overlays` carried a hardcoded 116 for the top edge and a note saying the
|
|
527
1767
|
* real fix was this message, "worth it when a second overlay needs the same
|
|
@@ -530,9 +1770,23 @@ export interface ShotStageBridge {
|
|
|
530
1770
|
* thing that says a modal transform is live, has never been visible in the
|
|
531
1771
|
* default layout at all.
|
|
532
1772
|
*
|
|
533
|
-
*
|
|
534
|
-
*
|
|
535
|
-
*
|
|
1773
|
+
* ── WHAT IT MOVES, AND WHAT IT MUST NEVER MOVE ──────────────────────────
|
|
1774
|
+
*
|
|
1775
|
+
* It moves the things that have to be SEEN: the overlay's furniture, the
|
|
1776
|
+
* derived head-on framing, the camera pane's zoom-to-fit, and where the split
|
|
1777
|
+
* SEAM falls (the ratio is the working pane's share of the width, and the
|
|
1778
|
+
* width it divides has to be the width the author can see — dividing the
|
|
1779
|
+
* whole window put the seam at 683 on a 1366 laptop whose visible canvas ran
|
|
1780
|
+
* 212..1066, handing the working pane 471 visible px against 383 with a fifth
|
|
1781
|
+
* of it behind the rail).
|
|
1782
|
+
*
|
|
1783
|
+
* It moves NEITHER THE SCISSOR NOR THE HIT TEST. `paneRects` takes the inset
|
|
1784
|
+
* for the seam alone; the rects it returns still partition the WHOLE
|
|
1785
|
+
* viewport, so the stage keeps drawing full-bleed under the docked chrome
|
|
1786
|
+
* and `paneAt` keeps answering for every pixel of it. Insetting those rects
|
|
1787
|
+
* instead would shrink the rendered picture to fit the chrome and leave dead
|
|
1788
|
+
* gutters where the panels sit. Which pixels are visible is a separate
|
|
1789
|
+
* question, asked separately, by `insetRect`.
|
|
536
1790
|
*
|
|
537
1791
|
* Editor state, never a document field.
|
|
538
1792
|
*/
|
|
@@ -545,6 +1799,27 @@ export interface ShotStageBridge {
|
|
|
545
1799
|
* here — it is always the graded render, by construction.
|
|
546
1800
|
*/
|
|
547
1801
|
setShadingMode(mode: ShadingMode): void;
|
|
1802
|
+
/**
|
|
1803
|
+
* The working pane's grid floor, on or off (v22).
|
|
1804
|
+
*
|
|
1805
|
+
* WORKSPACE STATE by `setShadingMode`'s rule: never written to a Doc3D,
|
|
1806
|
+
* never in an export (the grid is an EDITOR_LAYER object the shot camera
|
|
1807
|
+
* cannot see), re-pushed on every attach. The spline work-plane aid is NOT
|
|
1808
|
+
* gated by this — a drawing aid for an open gesture is not furniture.
|
|
1809
|
+
*/
|
|
1810
|
+
setGridVisible(visible: boolean): void;
|
|
1811
|
+
/**
|
|
1812
|
+
* The rulers and smart guides, on or off (v44), and the playback
|
|
1813
|
+
* resolution (v52).
|
|
1814
|
+
*
|
|
1815
|
+
* WORKSPACE STATE by `setGridVisible`'s rule: a per-viewer preference,
|
|
1816
|
+
* never written to a Doc3D, never in an export, re-pushed on every attach.
|
|
1817
|
+
* The guides themselves are document data and arrive with `loadDoc`.
|
|
1818
|
+
*/
|
|
1819
|
+
setEditorChrome(chrome: EditorChrome): void;
|
|
1820
|
+
/** Motion paths for the selected layers, on or off (v44). Workspace state
|
|
1821
|
+
* by `setGridVisible`'s rule, re-pushed on every attach. */
|
|
1822
|
+
setMotionPaths(on: boolean): void;
|
|
548
1823
|
/** Drive the working pane's orbit camera. */
|
|
549
1824
|
setWorkingView(view: WorkingView): void;
|
|
550
1825
|
/** Frame the whole canvas in the working pane. Returns the view it landed on,
|
|
@@ -552,15 +1827,28 @@ export interface ShotStageBridge {
|
|
|
552
1827
|
* owns the lens the distance is derived from. */
|
|
553
1828
|
fitWorkingView(): WorkingView;
|
|
554
1829
|
/**
|
|
555
|
-
*
|
|
1830
|
+
* PILOTING is armed, or not (v29).
|
|
556
1831
|
*
|
|
557
|
-
* The stage needs it for two things it is the only half able to do:
|
|
558
|
-
*
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
*
|
|
1832
|
+
* The stage needs it for two things it is the only half able to do: route
|
|
1833
|
+
* the Camera pane's navigation (middle-drag orbit, shift-drag pan, wheel
|
|
1834
|
+
* zoom) down the framing gesture lane instead of the viewport, so one drag
|
|
1835
|
+
* is one undo entry; and draw the affordance INSIDE the pane. Blender's
|
|
1836
|
+
* long-running complaint about its "Lock Camera to View" is that it is easy
|
|
1837
|
+
* to forget it is on, and a checkbox in a panel the author is not looking at
|
|
1838
|
+
* is exactly how.
|
|
1839
|
+
*
|
|
1840
|
+
* `text` is the badge's words when something holds the camera (a finished
|
|
1841
|
+
* move with Animate off, a path, a component driving it), composed by the
|
|
1842
|
+
* chrome because the chrome knows why; null draws the plain badge.
|
|
1843
|
+
*/
|
|
1844
|
+
setPilot(on: boolean, text: string | null): void;
|
|
1845
|
+
/**
|
|
1846
|
+
* What a camera write would do at the playhead (v29), or null with no
|
|
1847
|
+
* document. The gizmo dims when it is not `free`, the pointer lane refuses
|
|
1848
|
+
* the press with the gate's own sentence, and the hover names the move —
|
|
1849
|
+
* all BEFORE a drag, where the error strip used to speak after one.
|
|
562
1850
|
*/
|
|
563
|
-
|
|
1851
|
+
setCameraGate(gate: CameraGate | null): void;
|
|
564
1852
|
/** Drop the document: the stage renders nothing and every layer plane
|
|
565
1853
|
* unmounts, releasing its raster pins and texture bindings. The close
|
|
566
1854
|
* half of `loadDoc`. */
|
|
@@ -571,10 +1859,297 @@ export interface ShotStageBridge {
|
|
|
571
1859
|
* closed a panel. Not called on scene switch: surviving a switch warm is
|
|
572
1860
|
* the whole reason the cache is module-level. */
|
|
573
1861
|
clearCaches(): void;
|
|
1862
|
+
/**
|
|
1863
|
+
* Tier-1 export: what THIS browser can encode at the document's dimensions.
|
|
1864
|
+
* Empirical (a VideoEncoder/AudioEncoder probe inside the encode worker),
|
|
1865
|
+
* never UA sniffing. Cached per dimensions on the stage side.
|
|
1866
|
+
*/
|
|
1867
|
+
exportCapability(): Promise<Tier1Capability>;
|
|
1868
|
+
/**
|
|
1869
|
+
* Render the shot in place and encode an MP4, or a GIF (v32), in THIS
|
|
1870
|
+
* browser.
|
|
1871
|
+
*
|
|
1872
|
+
* The stage flips into export framing — design viewport, no view offset,
|
|
1873
|
+
* dpr 1, raster scale 1, overlays unmounted: the same numbers a Tier-2
|
|
1874
|
+
* render pins — drives every frame through the same draw latch the still
|
|
1875
|
+
* lane uses, and restores the author's framing and playhead when done.
|
|
1876
|
+
* While it runs, chrome `seek`/`loadDoc` pushes are DEFERRED (applied on
|
|
1877
|
+
* completion), never interleaved: a mid-capture re-render would let the
|
|
1878
|
+
* encoder stamp one frame's timestamp on another frame's pixels.
|
|
1879
|
+
*
|
|
1880
|
+
* One at a time — a second call rejects while one runs. Cancel via
|
|
1881
|
+
* `signal`; cancellation restores the stage and resolves nothing.
|
|
1882
|
+
*/
|
|
1883
|
+
exportMovie(request: ShotExportMovieRequest): Promise<ShotExportMovieResult>;
|
|
1884
|
+
/**
|
|
1885
|
+
* The Project's poster frame (`posterFrame`, the frame the local CLI
|
|
1886
|
+
* renders) as a JPEG at most `maxWidth` wide: the dashboard's card
|
|
1887
|
+
* thumbnail.
|
|
1888
|
+
*
|
|
1889
|
+
* Captured the way an export frame is: export framing, then the in-draw
|
|
1890
|
+
* snapshot from the matching presentation, then the author's stage back.
|
|
1891
|
+
* The playback framebuffer is unpreserved, so the live canvas is never read.
|
|
1892
|
+
*
|
|
1893
|
+
* Null (never a throw) when there is nothing to capture or the stage is
|
|
1894
|
+
* busy: no document, an export in flight, playback or its preparing pass
|
|
1895
|
+
* running, a component or material being edited, or a capture that refused.
|
|
1896
|
+
* Null uploads nothing: an existing poster remains, and a card that never
|
|
1897
|
+
* had one keeps its deterministic gradient, so this is never worth an error.
|
|
1898
|
+
*
|
|
1899
|
+
* The chrome takes no lock for it, so the poster YIELDS: anything the author
|
|
1900
|
+
* starts on the stage mid-capture (Play, an export or `captureFrame`, a
|
|
1901
|
+
* scrub, an edit, a component, a press, a font preview) aborts it, runs
|
|
1902
|
+
* once the stage has left its export framing, and the poster answers null.
|
|
1903
|
+
* A document whose
|
|
1904
|
+
* capture failed answers null at once until it changes, so the chrome may
|
|
1905
|
+
* ask again whenever it likes.
|
|
1906
|
+
*/
|
|
1907
|
+
capturePoster(maxWidth: number): Promise<Blob | null>;
|
|
1908
|
+
/**
|
|
1909
|
+
* One exact still of the whole timeline (v32): the storyboard's "Frame
|
|
1910
|
+
* from Shot". Captured the way `capturePoster` is (export framing, the
|
|
1911
|
+
* in-draw snapshot at `frame`, the author's stage back), then scaled to the
|
|
1912
|
+
* asked size and encoded.
|
|
1913
|
+
*
|
|
1914
|
+
* Rejects with the reason, unlike the poster: the author asked for this
|
|
1915
|
+
* picture, and a silent nothing would read as a dead menu row. The chrome
|
|
1916
|
+
* holds its export lock around the call, which pauses the transport.
|
|
1917
|
+
*/
|
|
1918
|
+
captureFrame(request: ShotCaptureFrameRequest): Promise<Blob>;
|
|
1919
|
+
/**
|
|
1920
|
+
* THUMBNAILS for a batch of nodes in the open material graph.
|
|
1921
|
+
*
|
|
1922
|
+
* The same request/response shape `capturePoster` established, and for the
|
|
1923
|
+
* same reason: the chrome is three-free by test, so it cannot render a node's
|
|
1924
|
+
* value itself. The stage compiles one unlit preview material per requested
|
|
1925
|
+
* node, draws them into ONE atlas render target and reads it back once —
|
|
1926
|
+
* one GPU stall per batch rather than per thumbnail.
|
|
1927
|
+
*
|
|
1928
|
+
* Null (never a throw) when there is nothing to draw: no stage, an export in
|
|
1929
|
+
* flight, no material preview target set, or a newer request superseded this
|
|
1930
|
+
* one. A missing thumbnail is a blank card, which is worth no error.
|
|
1931
|
+
*
|
|
1932
|
+
* EDITOR ONLY. The component that answers this is mounted only while the
|
|
1933
|
+
* stage is not exporting, and the CLI's render page never mounts it at all,
|
|
1934
|
+
* so no export can be reached from here.
|
|
1935
|
+
*/
|
|
1936
|
+
requestNodePreviews(request: NodePreviewRequest): Promise<NodePreviewBatch | null>;
|
|
1937
|
+
/**
|
|
1938
|
+
* DRAW EACH OF `frames` ONCE, so playback does not pay a first-use cost on
|
|
1939
|
+
* any of them (`playbackPreparation.ts` says what that cost is and which
|
|
1940
|
+
* frames carry it). One pass serves a queued Play and the background alike:
|
|
1941
|
+
* `pace()` says which it is, and is asked again at every hop and at the end
|
|
1942
|
+
* of the list, so a Play pressed during a background pass upgrades it.
|
|
1943
|
+
*
|
|
1944
|
+
* EVERY PASS DRAWS UNDER A FROZEN PICTURE. The frame on screen is presented
|
|
1945
|
+
* again, copied inside that presentation and laid over the canvas with a
|
|
1946
|
+
* shield above every overlay; a freeze an earlier pass left standing is
|
|
1947
|
+
* adopted instead. A press or a wheel on the shield ends the pass
|
|
1948
|
+
* (`"press"`). The stage then switches to its PLAYING presentation (the
|
|
1949
|
+
* warm-up's playing roles), because that is what playback will draw with,
|
|
1950
|
+
* and publishes each frame with a fresh token, the frame already on screen
|
|
1951
|
+
* included. It waits for that frame's playing presentation with a deadline,
|
|
1952
|
+
* so one frame that never lands cannot hold Play for ever, and reports the
|
|
1953
|
+
* frame's outcome to `onProgress`.
|
|
1954
|
+
*
|
|
1955
|
+
* At the end of the list under a `"play"` pace it HANDS OVER: the start
|
|
1956
|
+
* frame is presented again in the playing presentation, the freeze lifts
|
|
1957
|
+
* inside that presentation, and it resolves `handedOver` with the stage
|
|
1958
|
+
* left playing, for the chrome to start the transport at once (a start
|
|
1959
|
+
* frame that is not presented within 5 s restores instead). Under an
|
|
1960
|
+
* `"idle"` pace, and on a cancel, a yield or an export, it restores the
|
|
1961
|
+
* stage's own playing flag and the start frame, and the freeze lifts on the
|
|
1962
|
+
* first complete presentation of the current frame (a later seek moves the
|
|
1963
|
+
* lift to the newer frame, and a scrub lifts it within 150 ms). A
|
|
1964
|
+
* press on the shield after the restore takes the freeze down at once.
|
|
1965
|
+
*
|
|
1966
|
+
* Refused (`refused`, none of `frames` drawn) with no document, no canvas
|
|
1967
|
+
* or a component context, and when the freeze itself times out. Under
|
|
1968
|
+
* export framing a `"play"` pace waits for a poster to step aside and an
|
|
1969
|
+
* `"idle"` pace yields (`"export"`). A stage interaction live at the start,
|
|
1970
|
+
* or begun during the pass, yields (`"interaction"`); the other early ends
|
|
1971
|
+
* are the rest of `ShotPreparePlaybackYield`. Never rejects: preparation is
|
|
1972
|
+
* an optimisation, and a stage that cannot do it is only slower.
|
|
1973
|
+
*
|
|
1974
|
+
* One at a time: a second call cancels the first.
|
|
1975
|
+
*/
|
|
1976
|
+
preparePlayback(request: ShotPreparePlaybackRequest): Promise<ShotPreparePlaybackResult>;
|
|
1977
|
+
/**
|
|
1978
|
+
* What the GPU state behind prepared frames stands on (v51), for the
|
|
1979
|
+
* chrome's preparation keys. Synchronous and cheap. When `base` moves the
|
|
1980
|
+
* chrome drops every key; `modules` joins only the keys of Shots that place
|
|
1981
|
+
* code components.
|
|
1982
|
+
*/
|
|
1983
|
+
preparationKey(): ShotPreparationKey;
|
|
1984
|
+
/**
|
|
1985
|
+
* The `(frame, document)` pairs of every whole presentation the TRANSPORT
|
|
1986
|
+
* drew in the playing presentation since it started, then cleared (v51),
|
|
1987
|
+
* so the chrome can credit what playback drew as prepared at Pause.
|
|
1988
|
+
*
|
|
1989
|
+
* Never a preparing pass's frames, and none while a component context or a
|
|
1990
|
+
* font preview shows. Reset when the transport starts and on `loadDoc` of
|
|
1991
|
+
* another document id.
|
|
1992
|
+
*/
|
|
1993
|
+
takePlayed(): ReadonlyArray<{ frame: number; document: Doc3D }>;
|
|
1994
|
+
/**
|
|
1995
|
+
* What the stage knows about itself (v35), for an agent that cannot see it:
|
|
1996
|
+
* the crash, a lost context, the isolated pieces, the render fallbacks, the
|
|
1997
|
+
* component failures, the uncaught errors of this document and its export
|
|
1998
|
+
* worker, and what it last presented (a complete picture, readiness clear)
|
|
1999
|
+
* with the saved revision and module epoch it drew. Synchronous and cheap:
|
|
2000
|
+
* a copy of what the stage already keeps for its export gate.
|
|
2001
|
+
*/
|
|
2002
|
+
health(): StageHealthSnapshot;
|
|
2003
|
+
/**
|
|
2004
|
+
* Which mesh-like layers put a pixel in the frame on stage (v36): for the
|
|
2005
|
+
* Shot under the playhead, at the frame last drawn, each mesh, device and
|
|
2006
|
+
* placed component layer the document says shows there (in the Shot or in
|
|
2007
|
+
* a placed component definition, at most `cap`, the rest listed as
|
|
2008
|
+
* skipped) is drawn away once and the frame compared with itself drawn
|
|
2009
|
+
* whole, offscreen, through the Shot's camera in export framing, its bins,
|
|
2010
|
+
* its post chain and its colour boundary. Nothing is presented, and the
|
|
2011
|
+
* author's picture, playhead and every flag it flips are as they were
|
|
2012
|
+
* after, a throw included. Works in a hidden tab.
|
|
2013
|
+
*
|
|
2014
|
+
* Rejects with the reason it could not check: no Shot under the playhead,
|
|
2015
|
+
* a component shown alone, an isolated layer or a material preview (the
|
|
2016
|
+
* picture is not the Shot's then), an export, Play or its preparing pass,
|
|
2017
|
+
* a playhead that moved. A preparing pass under an `"idle"` pace is ended
|
|
2018
|
+
* first and resolves `yielded: "coverage"`.
|
|
2019
|
+
*/
|
|
2020
|
+
coverage(request?: CoverageRequest): Promise<StageCoverage>;
|
|
574
2021
|
/** Tear the stage down (a chrome unmount, or a bridge version mismatch). */
|
|
575
2022
|
dispose(): void;
|
|
576
2023
|
}
|
|
577
2024
|
|
|
2025
|
+
/** Who is waiting on a preparing pass (v51), asked at every hop. `"play"`: a
|
|
2026
|
+
* queued Play. `"idle"`: nobody, the author sits paused. */
|
|
2027
|
+
export type ShotPreparePace = "play" | "idle";
|
|
2028
|
+
|
|
2029
|
+
/** How one frame of a preparing pass ended (v51). `"presented"`: its own
|
|
2030
|
+
* publication was presented in the playing presentation. `"timeout"`: its
|
|
2031
|
+
* deadline passed with no external readiness claim pending.
|
|
2032
|
+
* `"timeout-pending"`: its deadline passed while an external claim (a font,
|
|
2033
|
+
* a texture, an html layer, a video seek) was still pending. */
|
|
2034
|
+
export type ShotPreparedOutcome = "presented" | "timeout" | "timeout-pending";
|
|
2035
|
+
|
|
2036
|
+
/** Why a preparing pass ended before its list did (v51). */
|
|
2037
|
+
export type ShotPreparePlaybackYield =
|
|
2038
|
+
| "press" // a press or wheel on the shield (cancels a queued Play)
|
|
2039
|
+
| "input" // author input while pace() was "idle": the request's signal aborted with the reason "input"
|
|
2040
|
+
| "interaction" // a live stage interaction started (or was live at the start)
|
|
2041
|
+
| "push" // a stage push that changes the picture or the overlays
|
|
2042
|
+
| "resize" // a window resize
|
|
2043
|
+
| "hidden" // the document became hidden
|
|
2044
|
+
| "coverage" // a coverage() check needed the author's frame
|
|
2045
|
+
| "export"; // export framing (an export, a poster, a still, a capture)
|
|
2046
|
+
|
|
2047
|
+
/** The chrome's request for the preparing pass (`preparePlayback`). */
|
|
2048
|
+
export interface ShotPreparePlaybackRequest {
|
|
2049
|
+
/** MASTER frames, in the order to draw them. */
|
|
2050
|
+
frames: readonly number[];
|
|
2051
|
+
/** After each frame: presented, or its deadline passed (with or without an
|
|
2052
|
+
* external claim pending at the deadline). */
|
|
2053
|
+
onProgress?: ((framesDone: number, totalFrames: number, outcome: ShotPreparedOutcome) => void) | undefined;
|
|
2054
|
+
/** Aborting it cancels the pass, and the stage restores. Aborted with the
|
|
2055
|
+
* reason `"input"` (author input under an `"idle"` pace), the pass
|
|
2056
|
+
* resolves `yielded: "input"`. */
|
|
2057
|
+
signal?: AbortSignal | undefined;
|
|
2058
|
+
/** Asked at every hop and at the end of the list. `"play"`: a queued Play
|
|
2059
|
+
* is waiting (hop through a MessageChannel; hand over at the end).
|
|
2060
|
+
* `"idle"`: nothing is waiting (hop through requestIdleCallback with a
|
|
2061
|
+
* 100 ms timeout; restore at the end). */
|
|
2062
|
+
pace: () => ShotPreparePace;
|
|
2063
|
+
/** How long `frames[index]` may take to present, in ms, asked as it is
|
|
2064
|
+
* published: the chrome's second-timeout rule asks for 500 after a
|
|
2065
|
+
* timeout in the same Shot. Absent, or not a positive number, it is
|
|
2066
|
+
* `PREPARE_FRAME_DEADLINE_MS` (5 s), which is also the ceiling. */
|
|
2067
|
+
deadlineMs?: ((index: number) => number) | undefined;
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
export interface ShotPreparePlaybackResult {
|
|
2071
|
+
/** Every frame was presented or timed out. */
|
|
2072
|
+
completed: boolean;
|
|
2073
|
+
/** Frames whose own publication was presented in the playing presentation. */
|
|
2074
|
+
presented: number;
|
|
2075
|
+
/** Ended early, for this reason. */
|
|
2076
|
+
yielded?: ShotPreparePlaybackYield;
|
|
2077
|
+
/** Could not run at all, and why: no document, no canvas, a component
|
|
2078
|
+
* context, or a freeze that timed out. None of `frames` was drawn. */
|
|
2079
|
+
refused?: string;
|
|
2080
|
+
/** Ended in the playing presentation on the start frame with the freeze
|
|
2081
|
+
* lifted: start the transport now. */
|
|
2082
|
+
handedOver?: true;
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
/** What the GPU state behind prepared frames stands on (v51
|
|
2086
|
+
* `preparationKey()`). */
|
|
2087
|
+
export interface ShotPreparationKey {
|
|
2088
|
+
/** Moves when the GPU state prepared frames stand for is replaced:
|
|
2089
|
+
* `performance.timeOrigin : gpuEpoch : canvas CSS size @ resolved pixel
|
|
2090
|
+
* ratio : raster rung`. The GPU epoch moves on a new renderer, at the END
|
|
2091
|
+
* of export framing (an export, a poster, a still, `captureFrame`), on
|
|
2092
|
+
* `clearCaches` and on `closeDoc`, and each move is announced through
|
|
2093
|
+
* `onStageHealth`. A coverage check moves nothing: it draws into targets
|
|
2094
|
+
* of its own. */
|
|
2095
|
+
base: string;
|
|
2096
|
+
/** The placed code components' module epoch : hot-update count. */
|
|
2097
|
+
modules: string;
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
/** The chrome's request for one exact still (`captureFrame`, v32). */
|
|
2101
|
+
export interface ShotCaptureFrameRequest {
|
|
2102
|
+
/** A MASTER frame of the whole timeline. */
|
|
2103
|
+
frame: number;
|
|
2104
|
+
/** The delivered size, in px. The frame is drawn at the design size, as an
|
|
2105
|
+
* export frame is, and scaled to this. */
|
|
2106
|
+
width: number;
|
|
2107
|
+
height: number;
|
|
2108
|
+
format: "png" | "jpeg" | "webp";
|
|
2109
|
+
signal?: AbortSignal | undefined;
|
|
2110
|
+
}
|
|
2111
|
+
|
|
2112
|
+
/** The chrome's request for a Tier-1 (in-browser) movie export. */
|
|
2113
|
+
export interface ShotExportMovieRequest {
|
|
2114
|
+
/** Absent = mp4. A GIF (v32) takes no audio, bitrate or quantizer, and
|
|
2115
|
+
* matches the server GIF's palette, timing and loop rules (tier1/gifSink.ts). */
|
|
2116
|
+
format?: ExportFormat | undefined;
|
|
2117
|
+
/** Scene id to export; absent or "" = the whole timeline (the same
|
|
2118
|
+
* WHOLE_TIMELINE convention the render route takes). */
|
|
2119
|
+
sceneId?: string | undefined;
|
|
2120
|
+
/** Master frames of the whole timeline to export, the work area (v39).
|
|
2121
|
+
* Refused with a `sceneId`. Absent = the whole scope. */
|
|
2122
|
+
window?: { start: number; frames: number } | undefined;
|
|
2123
|
+
/** Target video bitrate, bits/s — derived by the chrome from the shared
|
|
2124
|
+
* quality table (bitsPerPixel × w × h × fps) so the browser and server
|
|
2125
|
+
* paths honour the same quality choice. Absent = the encoder default. */
|
|
2126
|
+
videoBitrate?: number | undefined;
|
|
2127
|
+
/** The H.264 QP for every P frame, a whole number 0..51 (v49): the quality's
|
|
2128
|
+
* CRF from the same table. The stage encodes at it where a hardware encoder
|
|
2129
|
+
* honours a fixed QP, and at `videoBitrate` everywhere else. Absent =
|
|
2130
|
+
* `videoBitrate` only. */
|
|
2131
|
+
quantizer?: number | undefined;
|
|
2132
|
+
/** The document's audio, already mixed OFFLINE by the chrome (planar f32,
|
|
2133
|
+
* 48 kHz stereo). Absent = export silent. The chrome owns the mix because
|
|
2134
|
+
* audio was never part of the stage: the preview's clips play from the
|
|
2135
|
+
* chrome document, and the stage neither draws nor samples them. */
|
|
2136
|
+
audio?: { sampleRate: number; channels: Float32Array[] } | undefined;
|
|
2137
|
+
onProgress?: ((framesDone: number, totalFrames: number) => void) | undefined;
|
|
2138
|
+
signal?: AbortSignal | undefined;
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
export interface ShotExportMovieResult {
|
|
2142
|
+
blob: Blob;
|
|
2143
|
+
extension: string;
|
|
2144
|
+
/** Set when the document HAS audio but this browser could not encode it —
|
|
2145
|
+
* the export shipped silent and the dialog says why (the motion lane's
|
|
2146
|
+
* exact affordance). */
|
|
2147
|
+
audioSkippedReason?: string;
|
|
2148
|
+
/** How the MP4's encoder ran (v49): a fixed QP or a bitrate, on a hardware
|
|
2149
|
+
* or a software encoder. Absent for a GIF. */
|
|
2150
|
+
encoding?: Mp4Encoding;
|
|
2151
|
+
}
|
|
2152
|
+
|
|
578
2153
|
declare global {
|
|
579
2154
|
interface Window {
|
|
580
2155
|
__shotStudio?: ShotStageBridge;
|