@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
|
@@ -1,110 +1,359 @@
|
|
|
1
|
-
// The tool dock: one button per DOCK_TOOLS row, plus the shape flyout
|
|
1
|
+
// The tool dock: one button per DOCK_TOOLS row, plus the shape flyout, the
|
|
2
|
+
// Insert drawer's +, the Comment tool and the Animate mode. Eleven controls:
|
|
3
|
+
// one run of ten (two `.tool-group`s, the menu and Comment), one rule, then
|
|
4
|
+
// the mode.
|
|
2
5
|
//
|
|
3
6
|
// Everything here is derived from `TOOL_SPECS`. The icon map is keyed on
|
|
4
7
|
// `DockTool` and `FlyoutTool`, so a tool added to the table without a glyph is
|
|
5
8
|
// a COMPILE ERROR rather than an empty button — which is the whole reason the
|
|
6
9
|
// table's surfaces are types rather than strings.
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
//
|
|
11
|
+
// ── THE ROW IS GROUPED, AND THE GROUPING IS THE TABLE'S ──────────────────
|
|
12
|
+
//
|
|
13
|
+
// A flat run of ten controls said all ten were the same kind of thing. Two of
|
|
14
|
+
// them say what a press MEANS, six make something, one is a menu and the last
|
|
15
|
+
// is a mode. The groups are SEMANTIC (`role="group"`, named for a screen
|
|
16
|
+
// reader) and the row draws ONE rule, before the mode, which is Paper's footer:
|
|
17
|
+
// Pick, Draw and Add read as one run of aimed controls, and only the mode is
|
|
18
|
+
// a different kind of thing at a glance. The two tool groups come from
|
|
19
|
+
// `DOCK_GROUPS`, which is derived from `ToolSpec.group`: this file never asks
|
|
20
|
+
// which group a tool is in, so a new tool cannot land in the dock ungrouped
|
|
21
|
+
// and it cannot land in a group the table disagrees with.
|
|
22
|
+
import { Fragment, useRef, useState } from "react";
|
|
23
|
+
import type { ReactNode } from "react";
|
|
24
|
+
import { DOCK_GROUPS, FLYOUT_TOOLS, specOf } from "../../tools.js";
|
|
9
25
|
import type { DockTool, FlyoutTool, ShotTool } from "../../tools.js";
|
|
10
26
|
import { useShotEditor, useStore } from "../../state/context.js";
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const FLYOUT_GLYPHS: Record<FlyoutTool, string> = {
|
|
25
|
-
ellipse: "◯",
|
|
26
|
-
line: "╱",
|
|
27
|
-
arrow: "↗",
|
|
28
|
-
};
|
|
27
|
+
import { isSceneContext, toolLayoutMode } from "../../state/viewMode.js";
|
|
28
|
+
import { toolRefusal } from "../../state/keymap.js";
|
|
29
|
+
import { isolationInsertRefusal } from "../../state/isolationTrail.js";
|
|
30
|
+
import { toolKey } from "../../state/shortcuts.js";
|
|
31
|
+
import { NO_COMMENT, readOnlyReason } from "../../state/workspace.js";
|
|
32
|
+
import { COMMENT_ICON } from "../comments/parts.js";
|
|
33
|
+
import { toolFooterShown } from "../../state/panelSize.js";
|
|
34
|
+
import { InsertButton } from "./InsertButton.js";
|
|
35
|
+
import { useDismiss } from "./useDismiss.js";
|
|
36
|
+
// The shared set (basics overhaul): the text glyphs became SVGs with the same
|
|
37
|
+
// typed-map guarantee — a dock tool added to tools.ts without a glyph in
|
|
38
|
+
// icons.tsx does not build.
|
|
39
|
+
import { DOCK_TOOL_ICONS, FLYOUT_TOOL_ICONS, RECORD_ICON, SHAPES_ICON } from "../../icons.js";
|
|
29
40
|
|
|
30
41
|
export function ToolDockBar() {
|
|
31
42
|
const store = useStore();
|
|
32
43
|
const tool = useShotEditor((s) => s.tool);
|
|
33
44
|
const animateMode = useShotEditor((s) => s.animateMode);
|
|
34
|
-
|
|
45
|
+
// WHAT IS ON SCREEN. In Video the frame is, whatever layout waits
|
|
46
|
+
// underneath, and `setTool` brings that layout to the frame when a
|
|
47
|
+
// camera-pane tool is armed from there. So a dock that read the chosen
|
|
48
|
+
// layout would grey out the rect tool while the author looked straight at
|
|
49
|
+
// the surface it draws on. Inside a definition every tool's pane is
|
|
50
|
+
// (`toolLayoutMode`).
|
|
51
|
+
const layoutMode = useShotEditor(toolLayoutMode);
|
|
52
|
+
const readOnly = useShotEditor((s) => s.readOnly && readOnlyReason(s));
|
|
53
|
+
const leafIsolation = useShotEditor(isolationInsertRefusal);
|
|
54
|
+
// The footer is shown at every level of the stage (`toolFooterShown`), and
|
|
55
|
+
// this bar is the narrower answer inside it: the footer's row AND a shot or
|
|
56
|
+
// a definition. It reads both rather than trusting ToolFooter's branch, so
|
|
57
|
+
// the bar is correct wherever it is rendered (the tests render it bare).
|
|
58
|
+
const shown = useShotEditor((s) => toolFooterShown(s) && !isSceneContext(s));
|
|
59
|
+
const commenting = useShotEditor((s) => s.boardTool === "comment");
|
|
60
|
+
const canComment = useShotEditor((s) => s.canComment);
|
|
35
61
|
const [flyoutOpen, setFlyoutOpen] = useState(false);
|
|
36
|
-
|
|
62
|
+
const shapesAnchor = useRef<HTMLDivElement>(null);
|
|
63
|
+
useDismiss(flyoutOpen, shapesAnchor, () => setFlyoutOpen(false));
|
|
64
|
+
// ── THE WHOLE DOCK IS ABSENT OUTSIDE A SHOT, AND IN THE MODES ────────────
|
|
65
|
+
//
|
|
66
|
+
// Every control it holds is an insert, and `insertContext` refuses every
|
|
67
|
+
// insert in the Project context, so this used to render ten buttons of which
|
|
68
|
+
// ten were dead there: seven tools, the shape flyout, Add, and an Animate
|
|
69
|
+
// toggle whose only subject is a layer that cannot be selected without
|
|
70
|
+
// opening a shot first. The modes own the canvas cell outright, so a dock
|
|
71
|
+
// under it would address a picture that is not on screen. In the modes the
|
|
72
|
+
// footer's row closes (`toolFooterShown`). In the Project context the row
|
|
73
|
+
// stays, for the view track on its right, and ToolFooter puts the shot under
|
|
74
|
+
// the playhead where these tools would be.
|
|
75
|
+
//
|
|
76
|
+
// That reverses the disabled-not-absent argument below FOR THESE CASES, and
|
|
77
|
+
// deliberately. The argument is right about the LAYOUT refusal, where the
|
|
78
|
+
// author is one digit away and the tool is genuinely a capability they are
|
|
79
|
+
// about to use again. The context refusal is a different shape: the Project
|
|
80
|
+
// context has its own complete verb set (add, reorder, trim, split, delete,
|
|
81
|
+
// open) in the scene strip, and a dock of greyed-out element tools over it
|
|
82
|
+
// teaches a map of the editor that is wrong at this level. Nobody is stranded:
|
|
83
|
+
// the shots list and the strip both carry a `›` that opens one, and the keys
|
|
84
|
+
// still answer with `toolRefusal`'s sentence, which is now the only place that
|
|
85
|
+
// sentence is needed.
|
|
86
|
+
if (!shown) return null;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* DISABLED, NOT ABSENT — which is the one place this bar parts company with
|
|
90
|
+
* the bars in the top strip. ShadingBar and CameraViewBar unmount in the
|
|
91
|
+
* layout that has no working pane, because what they address is a pane that
|
|
92
|
+
* is not on screen. A creating tool is not addressed to a pane, it is a
|
|
93
|
+
* CAPABILITY of the editor, and an author who cannot find the rect tool
|
|
94
|
+
* concludes the shot lane has none — so the button stays, and its title is
|
|
95
|
+
* where the layout answer is taught. `toolRefusal` writes that sentence, and
|
|
96
|
+
* the keystroke's refusal says exactly the same thing.
|
|
97
|
+
*
|
|
98
|
+
* SPLIT KEEPS THEM ENABLED: the camera pane is the right half, and every
|
|
99
|
+
* insert lane it feeds works there.
|
|
100
|
+
*
|
|
101
|
+
* ISOLATED IN A LEAF DISABLES THEM TOO: an insert joins the isolated layer,
|
|
102
|
+
* and a rectangle cannot hold one (`isolationInsertRefusal`).
|
|
103
|
+
*
|
|
104
|
+
* The Project context never reaches this function: the whole bar is
|
|
105
|
+
* unmounted there, for the reason argued at the early return above.
|
|
106
|
+
*/
|
|
107
|
+
const refusalFor = (t: ShotTool): string | null => toolRefusal(t, layoutMode, false, readOnly, leafIsolation);
|
|
108
|
+
|
|
109
|
+
const toolButton = (t: DockTool) => (
|
|
110
|
+
<ToolButton
|
|
111
|
+
key={t}
|
|
112
|
+
armed={tool === t}
|
|
113
|
+
refusal={refusalFor(t)}
|
|
114
|
+
title={toolTitle(t)}
|
|
115
|
+
icon={DOCK_TOOL_ICONS[t]}
|
|
116
|
+
onClick={() => store.setTool(t)}
|
|
117
|
+
/>
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const shapes = (
|
|
121
|
+
<div className="tool-flyout-anchor" ref={shapesAnchor}>
|
|
122
|
+
{/* ONE FIXED GLYPH, the Shapes mark, whatever is armed. The trigger used
|
|
123
|
+
to wear the armed or last-used shape, which made it look like a fourth
|
|
124
|
+
kind of tool; it is a MENU of three, and the wash is what says one of
|
|
125
|
+
the three is in play. The flyout's rows wear the shapes themselves.
|
|
37
126
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
127
|
+
THE TITLE STAYS "Shapes", and must never become the armed tool's
|
|
128
|
+
label: the dock's tests find each tool's button by a title that
|
|
129
|
+
STARTS WITH its label, so "Ellipse…" here would make one button
|
|
130
|
+
answer for two tools and the flyout's own row would go unchecked.
|
|
131
|
+
|
|
132
|
+
Armed from `state.tool`, not from the row's click, because the row is
|
|
133
|
+
not the only way in: `O`, `L` and `⇧L` arm these three too. */}
|
|
134
|
+
<button
|
|
135
|
+
type="button"
|
|
136
|
+
className={`tool-button has-caret${FLYOUT_TOOLS.includes(tool as FlyoutTool) ? " is-armed" : ""}`}
|
|
137
|
+
aria-haspopup="menu"
|
|
138
|
+
aria-expanded={flyoutOpen}
|
|
139
|
+
// The glyph is fixed, so the NAME carries which shape is armed: a
|
|
140
|
+
// screen reader hears "Shapes: Ellipse" where a sighted author sees the
|
|
141
|
+
// wash. The title stays "Shapes" (see above).
|
|
142
|
+
aria-label={FLYOUT_TOOLS.includes(tool as FlyoutTool) ? `Shapes: ${specOf(tool).label}` : "Shapes"}
|
|
143
|
+
title="Shapes"
|
|
144
|
+
onClick={() => setFlyoutOpen((v) => !v)}
|
|
145
|
+
>
|
|
146
|
+
<span className="tool-icon" aria-hidden="true">
|
|
147
|
+
{SHAPES_ICON}
|
|
148
|
+
</span>
|
|
149
|
+
<span className="tool-caret" aria-hidden />
|
|
150
|
+
</button>
|
|
151
|
+
{flyoutOpen ? (
|
|
152
|
+
<div className="tool-flyout" role="menu">
|
|
153
|
+
{FLYOUT_TOOLS.map((t) => (
|
|
154
|
+
<ToolFlyoutRow
|
|
155
|
+
key={t}
|
|
156
|
+
// A RADIO row: one of the three is armed at a time, and the
|
|
157
|
+
// armed one says so to a screen reader, not only by its wash.
|
|
158
|
+
checked={tool === t}
|
|
159
|
+
refusal={refusalFor(t)}
|
|
160
|
+
title={toolTitle(t)}
|
|
161
|
+
icon={FLYOUT_TOOL_ICONS[t]}
|
|
162
|
+
label={specOf(t).label}
|
|
163
|
+
onClick={() => {
|
|
164
|
+
store.setTool(t);
|
|
165
|
+
setFlyoutOpen(false);
|
|
166
|
+
}}
|
|
167
|
+
/>
|
|
168
|
+
))}
|
|
169
|
+
</div>
|
|
170
|
+
) : null}
|
|
171
|
+
</div>
|
|
172
|
+
);
|
|
43
173
|
|
|
44
174
|
return (
|
|
45
175
|
<div className="tool-dock" role="toolbar" aria-label="Tools" data-testid="tool-dock">
|
|
46
|
-
{
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
176
|
+
{DOCK_GROUPS.map(({ label: group, tools }) => (
|
|
177
|
+
<Fragment key={group}>
|
|
178
|
+
<div className="tool-group" role="group" aria-label={group}>
|
|
179
|
+
{tools.map((t) =>
|
|
180
|
+
// THE SHAPES TRIGGER LIVES INSIDE THE DRAW GROUP, beside the
|
|
181
|
+
// rect it flies out of — it is one of the six that make
|
|
182
|
+
// something, and putting it after the group's rule would say it
|
|
183
|
+
// is a fourth kind of control. It rides `rect` rather than being
|
|
184
|
+
// appended to the group, because "beside rect" is the placement
|
|
185
|
+
// and the group's order is the table's.
|
|
186
|
+
t === "rect" ? (
|
|
187
|
+
<Fragment key={t}>
|
|
188
|
+
{toolButton(t)}
|
|
189
|
+
{shapes}
|
|
190
|
+
</Fragment>
|
|
191
|
+
) : (
|
|
192
|
+
toolButton(t)
|
|
193
|
+
),
|
|
194
|
+
)}
|
|
195
|
+
</div>
|
|
196
|
+
</Fragment>
|
|
57
197
|
))}
|
|
58
198
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
type="button"
|
|
76
|
-
role="menuitem"
|
|
77
|
-
className={`tool-button${tool === t ? " is-armed" : ""}`}
|
|
78
|
-
title={label(t)}
|
|
79
|
-
onClick={() => {
|
|
80
|
-
store.setTool(t);
|
|
81
|
-
setFlyoutOpen(false);
|
|
82
|
-
}}
|
|
83
|
-
>
|
|
84
|
-
{FLYOUT_GLYPHS[t]} {specOf(t).label}
|
|
85
|
-
</button>
|
|
86
|
-
))}
|
|
87
|
-
</div>
|
|
88
|
-
) : null}
|
|
89
|
-
</div>
|
|
199
|
+
{/* NOT a tool either: it opens the Insert drawer, the kinds a DRAG
|
|
200
|
+
CANNOT EXPRESS (a file, a registry choice, an operation on the
|
|
201
|
+
selection) beside icons, shaders and backgrounds. See InsertButton.
|
|
202
|
+
It rides the run unruled, because it is still something the author
|
|
203
|
+
aims at and presses, and its wash says the drawer is open. */}
|
|
204
|
+
<InsertButton />
|
|
205
|
+
{/* THE COMMENT TOOL (S5), the board's own: armed, the next click on
|
|
206
|
+
the camera pane leaves a Studio comment at the playhead. A Viewer
|
|
207
|
+
who may comment keeps it while the tools above are read-only. */}
|
|
208
|
+
<ToolButton
|
|
209
|
+
armed={commenting}
|
|
210
|
+
refusal={canComment ? null : NO_COMMENT}
|
|
211
|
+
title="Comment on the picture at the playhead (C)"
|
|
212
|
+
icon={COMMENT_ICON}
|
|
213
|
+
onClick={() => store.setBoardTool(commenting ? null : "comment")}
|
|
214
|
+
/>
|
|
90
215
|
|
|
91
|
-
{/* NOT a tool
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
216
|
+
{/* NOT a tool, and the row's one rule says so. Animate changes what an
|
|
217
|
+
edit MEANS while any tool is held, see tools.ts. */}
|
|
218
|
+
<span className="tool-separator" aria-hidden />
|
|
219
|
+
{/* IT GETS A WORD, and it is the only control here that has one. Until
|
|
220
|
+
now it was a bare `⏺` at the end of seven tool icons — a glyph in the
|
|
221
|
+
transport vocabulary sitting in a drawing dock, with the tooltip as
|
|
222
|
+
the only thing that said "Animate". The tools stay iconic because
|
|
223
|
+
they are a mutually-exclusive set an author learns once and then aims
|
|
224
|
+
at, and Add stays iconic because its caret says what
|
|
225
|
+
it is; a MODE is neither — it is either on or off, it changes what
|
|
226
|
+
every one of those tools MEANS while it is on, and a state has to say
|
|
227
|
+
at rest that it is on.
|
|
95
228
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
229
|
+
── AND THE WORD IS AFFORDABLE ─────────────────────────────────────
|
|
230
|
+
|
|
231
|
+
Measured off the stylesheet rather than eyeballed. The footer's
|
|
232
|
+
buttons are the house 28px control (`.tool-footer .tool-button`), the
|
|
233
|
+
gaps are --space-2 (4px). Six direct children of `.tool-dock`:
|
|
234
|
+
|
|
235
|
+
Pick group 2 × 28 + 1 gap × 4 = 60
|
|
236
|
+
Draw group 6 × 28 (5 tools + the shapes trigger)
|
|
237
|
+
+ 5 gaps × 4 = 188
|
|
238
|
+
Add one 28px trigger = 28
|
|
239
|
+
Comment one 28px tool = 28
|
|
240
|
+
separator 1 + margin 1 + 1 = 3
|
|
241
|
+
Animate 8 + 14 icon + 6 gap + ~47 label + 8 = 83
|
|
242
|
+
──────────────────────────────────────────────────────────────
|
|
243
|
+
children 390, + 5 dock gaps × 4 = 410
|
|
244
|
+
|
|
245
|
+
The dock has no padding or border of its own: the footer owns both,
|
|
246
|
+
16px a side, so the row alone is about 442. It shares the footer
|
|
247
|
+
with the view track on the right, and the TRACK is what gives way
|
|
248
|
+
when the two do not fit: it goes compact and then folds to one
|
|
249
|
+
picker (tool-footer.css has the measured thresholds), and these
|
|
250
|
+
tools never fold. dockedShellE2e measures the footer at three
|
|
251
|
+
widths, so a change to this row that breaks the fit fails there.
|
|
252
|
+
|
|
253
|
+
So the "is the word worth its width" argument is settled by having
|
|
254
|
+
the space, and the word was the right answer anyway, because a mode
|
|
255
|
+
has to say at rest that it is on. */}
|
|
99
256
|
<button
|
|
100
257
|
type="button"
|
|
101
|
-
className={`tool-button tool-animate${animateMode ? " is-armed" : ""}`}
|
|
258
|
+
className={`tool-button tool-animate is-labelled${animateMode ? " is-armed" : ""}`}
|
|
102
259
|
aria-pressed={animateMode}
|
|
103
|
-
|
|
260
|
+
// The accessible name is the word alone, not the word plus the glyph.
|
|
261
|
+
aria-label="Animate"
|
|
262
|
+
title="Animate (⇧A): edits write keyframes at the playhead"
|
|
104
263
|
onClick={() => store.setAnimateMode(!animateMode)}
|
|
105
264
|
>
|
|
106
|
-
|
|
265
|
+
<span className="tool-icon" aria-hidden="true">
|
|
266
|
+
{RECORD_ICON}
|
|
267
|
+
</span>
|
|
268
|
+
<span className="tool-label">Animate</span>
|
|
107
269
|
</button>
|
|
108
270
|
</div>
|
|
109
271
|
);
|
|
110
272
|
}
|
|
273
|
+
|
|
274
|
+
/** A tool button's title: its label, then its key ("Rect (R)"). */
|
|
275
|
+
export function toolTitle(t: ShotTool): string {
|
|
276
|
+
const key = toolKey(t);
|
|
277
|
+
return `${specOf(t).label}${key === null ? "" : ` (${key})`}`;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* ONE TOOL BUTTON, shared by this dock and the Insert button
|
|
282
|
+
* (InsertButton.tsx), so both draw the same armed wash and disable the same way.
|
|
283
|
+
* `refusal` is the sentence a disabled button says in its title, and null
|
|
284
|
+
* means the button works and its title is `title`.
|
|
285
|
+
*
|
|
286
|
+
* `label` is a labelled button's (no caller passes one since the board's
|
|
287
|
+
* tool rail went): the button's name, kept
|
|
288
|
+
* whatever the title says, and drawn under the glyph as `caption` (the label
|
|
289
|
+
* itself unless a shorter word is given). The Studio dock passes neither.
|
|
290
|
+
*/
|
|
291
|
+
export function ToolButton(props: {
|
|
292
|
+
armed: boolean;
|
|
293
|
+
refusal: string | null;
|
|
294
|
+
title: string;
|
|
295
|
+
icon: ReactNode;
|
|
296
|
+
label?: string;
|
|
297
|
+
caption?: string;
|
|
298
|
+
onClick: () => void;
|
|
299
|
+
}) {
|
|
300
|
+
return (
|
|
301
|
+
<button
|
|
302
|
+
type="button"
|
|
303
|
+
className={`tool-button${props.armed ? " is-armed" : ""}`}
|
|
304
|
+
aria-pressed={props.armed}
|
|
305
|
+
aria-label={props.label}
|
|
306
|
+
disabled={props.refusal !== null}
|
|
307
|
+
title={props.refusal ?? props.title}
|
|
308
|
+
onClick={props.onClick}
|
|
309
|
+
>
|
|
310
|
+
<span className="tool-icon" aria-hidden="true">
|
|
311
|
+
{props.icon}
|
|
312
|
+
</span>
|
|
313
|
+
{props.label === undefined ? null : (
|
|
314
|
+
<span className="tool-caption" aria-hidden="true">
|
|
315
|
+
{props.caption ?? props.label}
|
|
316
|
+
</span>
|
|
317
|
+
)}
|
|
318
|
+
</button>
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* ONE ROW OF A TOOL FLYOUT. With `checked` it is a radio row (one tool of the
|
|
324
|
+
* set is armed); without it a plain menu item (an insert that arms nothing).
|
|
325
|
+
* `chip` is the key that arms the tool, which only the board rail shows: the
|
|
326
|
+
* Studio footer stays as it is.
|
|
327
|
+
*/
|
|
328
|
+
export function ToolFlyoutRow(props: {
|
|
329
|
+
checked?: boolean;
|
|
330
|
+
refusal: string | null;
|
|
331
|
+
title: string;
|
|
332
|
+
icon: ReactNode;
|
|
333
|
+
label: string;
|
|
334
|
+
chip?: string;
|
|
335
|
+
onClick: () => void;
|
|
336
|
+
}) {
|
|
337
|
+
const radio = props.checked !== undefined;
|
|
338
|
+
return (
|
|
339
|
+
<button
|
|
340
|
+
type="button"
|
|
341
|
+
role={radio ? "menuitemradio" : "menuitem"}
|
|
342
|
+
{...(radio ? { "aria-checked": props.checked } : {})}
|
|
343
|
+
className={`tool-button${props.checked === true ? " is-armed" : ""}`}
|
|
344
|
+
disabled={props.refusal !== null}
|
|
345
|
+
title={props.refusal ?? props.title}
|
|
346
|
+
onClick={props.onClick}
|
|
347
|
+
>
|
|
348
|
+
<span className="tool-icon" aria-hidden="true">
|
|
349
|
+
{props.icon}
|
|
350
|
+
</span>{" "}
|
|
351
|
+
{props.label}
|
|
352
|
+
{props.chip === undefined ? null : (
|
|
353
|
+
<kbd className="tool-key-chip" aria-hidden="true">
|
|
354
|
+
{props.chip}
|
|
355
|
+
</kbd>
|
|
356
|
+
)}
|
|
357
|
+
</button>
|
|
358
|
+
);
|
|
359
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// THE TOOL FOOTER'S ROW: what is on the left, then the view track on the right.
|
|
2
|
+
//
|
|
3
|
+
// App mounts this inside the `.tool-footer` PanelBoundary wherever the footer
|
|
4
|
+
// is shown (`toolFooterShown`): every level of the stage workspace, and never
|
|
5
|
+
// in a mode. The two halves are pushed apart (`justify-content:
|
|
6
|
+
// space-between`, tool-footer.css), so the track sits at the right edge in
|
|
7
|
+
// every context and the left half changes under it.
|
|
8
|
+
//
|
|
9
|
+
// ── THE LEFT HALF IS THE TOOLS, OR THE SHOT THEY WOULD DRAW INTO ───────────
|
|
10
|
+
//
|
|
11
|
+
// Inside a shot or a definition the left half is ToolDockBar. In the Project
|
|
12
|
+
// context every tool there would be dead (ToolDockBar has the argument), so the
|
|
13
|
+
// left half names the shot under the playhead instead: what the picture above
|
|
14
|
+
// is showing, at the level where the picture is a sequence of shots. With no
|
|
15
|
+
// shot under the playhead it shows nothing, rather than a placeholder that
|
|
16
|
+
// would describe a picture that is not there.
|
|
17
|
+
//
|
|
18
|
+
// ── THE RIGHT HALF IS THE VIEW TRACK ───────────────────────────────────────
|
|
19
|
+
//
|
|
20
|
+
// ViewModeBar, which applies at every level and gates itself (it is absent
|
|
21
|
+
// inside a definition, which has no shot camera). It gives way before the
|
|
22
|
+
// tools do: it compacts, then folds to one picker, on a container query on
|
|
23
|
+
// this row (tool-footer.css has the measured widths). The tools never fold.
|
|
24
|
+
import { FPS_OPTIONS } from "@dailies-studio/timeline";
|
|
25
|
+
import { framesToSeconds } from "@dailies-studio/engine";
|
|
26
|
+
import type { Rational } from "@dailies-studio/engine";
|
|
27
|
+
import { masterToSceneCached } from "@dailies-studio/shot/doc";
|
|
28
|
+
import { useShotEditor, useShotEditorHot } from "../../state/context.js";
|
|
29
|
+
import type { ShotEditorState } from "../../state/types.js";
|
|
30
|
+
import { isSceneContext } from "../../state/viewMode.js";
|
|
31
|
+
import { formatDuration } from "../timeline/model.js";
|
|
32
|
+
import { ToolDockBar } from "./ToolDockBar.js";
|
|
33
|
+
import { ViewModeBar } from "./ViewModeBar.js";
|
|
34
|
+
|
|
35
|
+
/** The rate as the Project's own picker words it: an `FPS_OPTIONS` label when
|
|
36
|
+
* the rational is one of them (so 30000/1001 reads "29.97", never "29.970"),
|
|
37
|
+
* else three decimals with the trailing zeros dropped. */
|
|
38
|
+
export function fpsLabel(fps: Rational): string {
|
|
39
|
+
const known = FPS_OPTIONS.find((o) => o.fps.num * fps.den === fps.num * o.fps.den);
|
|
40
|
+
return known?.label ?? String(Number((fps.num / fps.den).toFixed(3)));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The shot under the playhead, as two strings, or null with none.
|
|
45
|
+
*
|
|
46
|
+
* STRINGS, NEVER AN OBJECT: the footer survives playback, and `useShotEditor`
|
|
47
|
+
* compares with `Object.is`, so each line is resolved inside its own selector
|
|
48
|
+
* and only a change of words re-renders the row.
|
|
49
|
+
*
|
|
50
|
+
* THE PLAYHEAD'S SHOT, NEVER THE PIN. `state.sceneId` is a pin that a bare
|
|
51
|
+
* `setScene` moves without seeking, and a zero-length shot hands the frame to
|
|
52
|
+
* its neighbour while the pin stays on it, so it can name a shot the stage is
|
|
53
|
+
* not drawing. The footer describes the picture above it, so it resolves the
|
|
54
|
+
* frame first, as `insertContext` and the bridge do, and falls back to the pin
|
|
55
|
+
* only where the frame lands in no shot.
|
|
56
|
+
*
|
|
57
|
+
* The NUMBER is the shot's place in `doc.scenes`, the order the left column's
|
|
58
|
+
* Shots list and the timeline draw. The DURATION is `formatDuration`, the
|
|
59
|
+
* same string the left column's shot rows print, so one length is never spelled
|
|
60
|
+
* two ways on one screen.
|
|
61
|
+
*/
|
|
62
|
+
export function shotMeta(
|
|
63
|
+
s: Pick<ShotEditorState, "doc" | "sceneId" | "frame">,
|
|
64
|
+
): { name: string; line: string } | null {
|
|
65
|
+
const { doc } = s;
|
|
66
|
+
if (doc === null) return null;
|
|
67
|
+
const sceneId = masterToSceneCached(doc, s.frame)?.sceneId ?? s.sceneId;
|
|
68
|
+
if (sceneId === null) return null;
|
|
69
|
+
const scene = doc.scenesById[sceneId];
|
|
70
|
+
const index = doc.scenes.indexOf(sceneId);
|
|
71
|
+
if (scene === undefined || index === -1) return null;
|
|
72
|
+
const number = String(index + 1).padStart(2, "0");
|
|
73
|
+
return {
|
|
74
|
+
name: scene.name,
|
|
75
|
+
line: `Shot ${number} · ${formatDuration(framesToSeconds(scene.durationFrames, doc.fps))} · ${fpsLabel(doc.fps)} fps`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function ShotMeta() {
|
|
80
|
+
// Hot: the Shot under the playhead moves at every cut the transport plays,
|
|
81
|
+
// which the cold lane sleeps through (store `set`). Strings, so the row
|
|
82
|
+
// renders at a cut and not per frame.
|
|
83
|
+
const name = useShotEditorHot((s) => shotMeta(s)?.name ?? null);
|
|
84
|
+
const line = useShotEditorHot((s) => shotMeta(s)?.line ?? null);
|
|
85
|
+
if (name === null || line === null) return null;
|
|
86
|
+
return (
|
|
87
|
+
<div className="shot-meta" data-testid="shot-meta">
|
|
88
|
+
<span className="shot-meta-name">{name}</span>
|
|
89
|
+
<span className="shot-meta-line">{line}</span>
|
|
90
|
+
</div>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function ToolFooter() {
|
|
95
|
+
const project = useShotEditor(isSceneContext);
|
|
96
|
+
return (
|
|
97
|
+
<>
|
|
98
|
+
{project ? <ShotMeta /> : <ToolDockBar />}
|
|
99
|
+
<ViewModeBar />
|
|
100
|
+
</>
|
|
101
|
+
);
|
|
102
|
+
}
|