@dailies-studio/shot-editor 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.vite/manifest.json +382 -0
- package/dist/assets/AgentPanel-CQejLbiX.js +2 -0
- package/dist/assets/AgentPanel-DJEphah0.css +1 -0
- package/dist/assets/AgentQuestionDialog-BqkD0kXF.js +1 -0
- package/dist/assets/CodeStudio-Dv4ihHpz.js +23 -0
- package/dist/assets/CommentsPanel-B4yhhT1T.js +1 -0
- package/dist/assets/ComponentLibraryRail-Ch_dsAru.js +1 -0
- package/dist/assets/ComponentStage-BRhRotyH.js +1 -0
- package/dist/assets/CurvePane-BjFVabKX.css +1 -0
- package/dist/assets/CurvePane-R22WzllJ.js +1 -0
- package/dist/assets/ExportDialog-CWLQWTmG.js +2 -0
- package/dist/assets/FontPicker-DWKaYL7F.js +1 -0
- package/dist/assets/FontPicker-v0IOIArM.css +1 -0
- package/dist/assets/GenerateDrawer-Bh3SqDKt.js +2 -0
- package/dist/assets/InsertDrawer-Ce1fod1L.js +1 -0
- package/dist/assets/LibraryBrowser-D9sEGz5w.js +2 -0
- package/dist/assets/MakeItYoursSection-CMO4319_.js +2 -0
- package/dist/assets/MaterialGraphCanvas-BFzl4wWR.js +23 -0
- package/dist/assets/MaterialGraphCanvas-BIUD59ik.css +1 -0
- package/dist/assets/MaterialWorkspace-CqTWqaRA.js +14 -0
- package/dist/assets/PreferencesDialog-CBf9_OoD.js +1 -0
- package/dist/assets/PresetsSection-CUEaoCVU.js +1 -0
- package/dist/assets/SoundHistory-BeS8EW1h.js +1 -0
- package/dist/assets/SoundMode-BmcZru3i.js +3 -0
- package/dist/assets/StockSounds-DdAUGRYK.js +1 -0
- package/dist/assets/TemplateFieldSection-CaeXpLFo.js +1 -0
- package/dist/assets/VersionHistoryPanel-CxG6XhNP.js +1 -0
- package/dist/assets/board-B88EPuLO.css +1 -0
- package/dist/assets/board-CL-he7SL.js +3 -0
- package/dist/assets/components-0oOSPN0l.js +1 -0
- package/dist/assets/googleFontRanges-gp32wJMo.js +1 -0
- package/dist/assets/googleFonts-BNon6M7X.js +1 -0
- package/dist/assets/iconsAndAliases-DL7gXP5j.js +1863 -0
- package/dist/assets/index-4F5NQmI8.css +1 -0
- package/dist/assets/index-BGHQGV5z.js +117 -0
- package/dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/dist/assets/libraryModel-CpIwfFha.js +1 -0
- package/dist/assets/lucide-6iK64tTB.js +9319 -0
- package/dist/assets/motionStamp-CH-Hew4E.js +1 -0
- package/dist/assets/takeMeasure-Tdg0TxEi.js +1 -0
- package/dist/assets/webmcp-BsB9gxWC.js +2 -0
- package/dist/index.html +34 -3
- package/package.json +12 -9
- package/src/addFamilies.ts +66 -0
- package/src/api.ts +1631 -55
- package/src/app/App.tsx +977 -198
- package/src/app/lazyPanel.tsx +137 -0
- package/src/app/lazySurfaces.tsx +203 -0
- package/src/audio/index.tsx +41 -10
- package/src/audio/meter.ts +485 -0
- package/src/audio/meterMath.ts +273 -0
- package/src/audio/meterStore.ts +155 -0
- package/src/audio/offlineMix.ts +289 -0
- package/src/audio/preview.ts +928 -118
- package/src/bridge.ts +15 -5
- package/src/bridgeTypes.ts +1611 -36
- package/src/channels.ts +17 -32
- package/src/fonts/googleFonts.ts +4 -0
- package/src/hostApi.ts +174 -0
- package/src/icons.tsx +770 -0
- package/src/layerWords.ts +61 -0
- package/src/main.tsx +56 -4
- package/src/panels/ResizeHandle.tsx +33 -43
- package/src/panels/agent/AgentDots.tsx +36 -0
- package/src/panels/agent/AgentPanel.tsx +119 -43
- package/src/panels/agent/AgentQuestionDialog.tsx +202 -0
- package/src/panels/agent/agent.css +113 -97
- package/src/panels/agent/agentGate.ts +35 -0
- package/src/panels/code/CodeDefaultsPanel.tsx +345 -0
- package/src/panels/code/CodeStudio.tsx +373 -0
- package/src/panels/code/FileTree.tsx +265 -0
- package/src/panels/code/codeBufferGuard.ts +52 -0
- package/src/panels/code/codeParts.tsx +321 -0
- package/src/panels/comments/CommentComposer.tsx +239 -0
- package/src/panels/comments/CommentThread.tsx +346 -0
- package/src/panels/comments/CommentsPanel.tsx +336 -0
- package/src/panels/comments/InboxButton.tsx +131 -0
- package/src/panels/comments/MentionMenu.tsx +98 -0
- package/src/panels/comments/parts.tsx +171 -0
- package/src/panels/export/ExportDialog.tsx +919 -96
- package/src/panels/export/ExportScrim.tsx +57 -0
- package/src/panels/files/AssetsTab.tsx +656 -0
- package/src/panels/files/FilePanel.tsx +1466 -216
- package/src/panels/files/LayerMarks.tsx +40 -0
- package/src/panels/files/LeftColumn.tsx +37 -0
- package/src/panels/files/McpSection.tsx +690 -47
- package/src/panels/files/MissingAssetsNotice.tsx +60 -0
- package/src/panels/files/assetDrag.ts +79 -0
- package/src/panels/files/resourceParts.tsx +255 -0
- package/src/panels/fonts/FontPicker.tsx +762 -0
- package/src/panels/fonts/faceCache.ts +207 -0
- package/src/panels/fonts/fontPicker.css +271 -0
- package/src/panels/fonts/pickerModel.ts +265 -0
- package/src/panels/fonts/pickerRequest.ts +46 -0
- package/src/panels/header/AccountAvatar.tsx +76 -0
- package/src/panels/header/AgentChip.tsx +77 -0
- package/src/panels/header/AppMenu.tsx +213 -0
- package/src/panels/header/Header.tsx +564 -84
- package/src/panels/header/HistoryControls.tsx +31 -5
- package/src/panels/header/PresenceStack.tsx +329 -0
- package/src/panels/header/ProjectTitle.tsx +232 -0
- package/src/panels/header/ShareButton.tsx +59 -0
- package/src/panels/header/StatusBadges.tsx +358 -27
- package/src/panels/header/SyncDeletedDialog.tsx +88 -0
- package/src/panels/header/ZoomControls.tsx +46 -15
- package/src/panels/header/agentHandoff.ts +52 -0
- package/src/panels/header/leave.ts +26 -0
- package/src/panels/help/HelpSection.tsx +189 -163
- package/src/panels/insert/InsertDrawer.tsx +723 -0
- package/src/panels/insert/iconSet.ts +109 -0
- package/src/panels/inspector/ExposeDot.tsx +117 -0
- package/src/panels/inspector/FramingRows.tsx +314 -44
- package/src/panels/inspector/InspectorFooter.tsx +91 -0
- package/src/panels/inspector/InspectorHead.tsx +425 -0
- package/src/panels/inspector/InspectorPanel.tsx +408 -124
- package/src/panels/inspector/KeyframeDot.tsx +373 -0
- package/src/panels/inspector/KeyframeSection.tsx +257 -0
- package/src/panels/inspector/MarkerSection.tsx +55 -11
- package/src/panels/inspector/ParamRow.tsx +84 -53
- package/src/panels/inspector/RightColumn.tsx +152 -0
- package/src/panels/inspector/TimeSection.tsx +866 -0
- package/src/panels/inspector/animate/EaseControl.tsx +244 -0
- package/src/panels/inspector/animate/PresetsSection.tsx +135 -0
- package/src/panels/inspector/animate/ShotSection.tsx +562 -48
- package/src/panels/inspector/design/AlignRow.tsx +95 -31
- package/src/panels/inspector/design/AppearanceSection.tsx +118 -9
- package/src/panels/inspector/design/ClonerSection.tsx +323 -62
- package/src/panels/inspector/design/ComponentSection.tsx +50 -43
- package/src/panels/inspector/design/CornerSection.tsx +45 -14
- package/src/panels/inspector/design/DefinitionProps.tsx +315 -0
- package/src/panels/inspector/design/DefinitionSection.tsx +136 -0
- package/src/panels/inspector/design/DeviceSection.tsx +210 -0
- package/src/panels/inspector/design/FillSection.tsx +83 -51
- package/src/panels/inspector/design/FontField.tsx +196 -0
- package/src/panels/inspector/design/HtmlSection.tsx +23 -12
- package/src/panels/inspector/design/InstanceSection.tsx +373 -154
- package/src/panels/inspector/design/MaskSection.tsx +84 -0
- package/src/panels/inspector/design/MaterialSection.tsx +177 -0
- package/src/panels/inspector/design/MediaSection.tsx +273 -120
- package/src/panels/inspector/design/MeshSection.tsx +910 -82
- package/src/panels/inspector/design/PaintRows.tsx +550 -0
- package/src/panels/inspector/design/PlateStyleSection.tsx +177 -0
- package/src/panels/inspector/design/ShadowSection.tsx +221 -48
- package/src/panels/inspector/design/SplineFollowSection.tsx +235 -0
- package/src/panels/inspector/design/StrokeSection.tsx +228 -43
- package/src/panels/inspector/design/TemplateFieldSection.tsx +57 -0
- package/src/panels/inspector/design/TransformSection.tsx +244 -50
- package/src/panels/inspector/design/TypographySection.tsx +679 -110
- package/src/panels/inspector/layout.ts +295 -0
- package/src/panels/inspector/propValue.ts +199 -0
- package/src/panels/inspector/scene/CameraSection.tsx +232 -22
- package/src/panels/inspector/scene/EffectsSection.tsx +722 -71
- package/src/panels/inspector/scene/MakeItYoursSection.tsx +180 -0
- package/src/panels/inspector/scene/SceneDocSection.tsx +191 -0
- package/src/panels/inspector/scene/SceneSection.tsx +219 -44
- package/src/panels/inspector/scene/TransitionSection.tsx +523 -72
- package/src/panels/inspector/storyboard/StoryboardReferenceSection.tsx +593 -0
- package/src/panels/inspector/storyboard/VideoStill.tsx +120 -0
- package/src/panels/inspector/timeModel.ts +190 -0
- package/src/panels/inspector/useDocWrite.ts +438 -146
- package/src/panels/library/LibraryBrowser.tsx +435 -0
- package/src/panels/library/LibraryGrid.tsx +190 -0
- package/src/panels/library/LibraryPreviewPanel.tsx +349 -0
- package/src/panels/library/LibraryRail.tsx +84 -0
- package/src/panels/library/LibrarySoundPanel.tsx +293 -0
- package/src/panels/library/SoundHistory.tsx +245 -0
- package/src/panels/library/StockSounds.tsx +390 -0
- package/src/panels/library/libraryModel.ts +147 -0
- package/src/panels/library/stockSearch.ts +77 -0
- package/src/panels/maskMarks.tsx +117 -0
- package/src/panels/material/MaterialCommentNode.tsx +54 -0
- package/src/panels/material/MaterialGraphCanvas.tsx +861 -0
- package/src/panels/material/MaterialGraphMenu.tsx +45 -0
- package/src/panels/material/MaterialGroupNode.tsx +56 -0
- package/src/panels/material/MaterialLibrary.tsx +253 -0
- package/src/panels/material/MaterialNode.tsx +453 -0
- package/src/panels/material/MaterialNodePalette.tsx +349 -0
- package/src/panels/material/MaterialParameterControls.tsx +525 -0
- package/src/panels/material/MaterialRerouteNode.tsx +42 -0
- package/src/panels/material/MaterialWorkspace.tsx +501 -0
- package/src/panels/material/NodePreview.tsx +70 -0
- package/src/panels/material/flowModel.ts +441 -0
- package/src/panels/material/parameterValues.ts +231 -0
- package/src/panels/material/previewScheduler.ts +235 -0
- package/src/panels/material/reactFlow.css +6 -0
- package/src/panels/material/socketGlyph.ts +85 -0
- package/src/panels/material/viewportMemory.ts +58 -0
- package/src/panels/preferences/PreferencesDialog.tsx +215 -0
- package/src/panels/share/ShareComponentDialog.tsx +247 -0
- package/src/panels/stage/StageMenu.tsx +35 -5
- package/src/panels/stage/StagePanel.tsx +338 -23
- package/src/panels/stage/cellSlots.tsx +70 -0
- package/src/panels/storyboard/BoardCanvas.tsx +739 -0
- package/src/panels/storyboard/BoardCursors.tsx +158 -0
- package/src/panels/storyboard/BoardDropDialog.tsx +161 -0
- package/src/panels/storyboard/BoardPlan.tsx +42 -0
- package/src/panels/storyboard/ComponentSheet.tsx +187 -0
- package/src/panels/storyboard/ComponentStage.tsx +235 -0
- package/src/panels/storyboard/MiniSketch.tsx +173 -0
- package/src/panels/storyboard/PartPicker.tsx +64 -0
- package/src/panels/storyboard/PlanPanel.tsx +617 -0
- package/src/panels/storyboard/ReferencePreview.tsx +217 -0
- package/src/panels/storyboard/ShotBrief.tsx +360 -0
- package/src/panels/storyboard/ShotCard.tsx +251 -0
- package/src/panels/storyboard/StagePreview.tsx +348 -0
- package/src/panels/storyboard/StillThumbs.tsx +162 -0
- package/src/panels/storyboard/StoryboardView.tsx +79 -0
- package/src/panels/storyboard/board.css +1065 -0
- package/src/panels/storyboard/board.ts +12 -0
- package/src/panels/storyboard/boardClipboard.ts +111 -0
- package/src/panels/storyboard/boardOrder.ts +68 -0
- package/src/panels/storyboard/boardRows.tsx +425 -0
- package/src/panels/storyboard/liveCap.ts +90 -0
- package/src/panels/storyboard/plan.css +295 -0
- package/src/panels/storyboard/posterCache.ts +133 -0
- package/src/panels/storyboard/shotboard/ComponentPicker.tsx +373 -0
- package/src/panels/storyboard/shotboard/ImagePicker.tsx +145 -0
- package/src/panels/storyboard/shotboard/ShotBoard.tsx +292 -0
- package/src/panels/storyboard/shotboard/SketchCanvas.tsx +443 -0
- package/src/panels/storyboard/shotboard/SketchInspector.tsx +471 -0
- package/src/panels/storyboard/shotboard/SketchItem.tsx +240 -0
- package/src/panels/storyboard/shotboard/SketchLayers.tsx +130 -0
- package/src/panels/storyboard/shotboard/SketchPlay.tsx +108 -0
- package/src/panels/storyboard/shotboard/SketchStrip.tsx +178 -0
- package/src/panels/storyboard/shotboard/SketchToolFooter.tsx +99 -0
- package/src/panels/storyboard/shotboard/sketch.css +1392 -0
- package/src/panels/storyboard/shotboard/sketchModel.ts +219 -0
- package/src/panels/storyboard/storyboardDrop.ts +164 -0
- package/src/panels/studio/ComponentLibraryRail.tsx +346 -0
- package/src/panels/studio/ComponentSidePanel.tsx +355 -0
- package/src/panels/studio/ComponentStudio.tsx +243 -0
- package/src/panels/studio/ComponentsHome.tsx +318 -0
- package/src/panels/studio/ComponentsPreview.tsx +179 -0
- package/src/panels/studio/EveryUse.tsx +244 -0
- package/src/panels/studio/ThisUsePanel.tsx +679 -0
- package/src/panels/studio/componentParts.tsx +341 -0
- package/src/panels/studio/components.ts +6 -0
- package/src/panels/studio/newCodeComponent.ts +66 -0
- package/src/panels/timeline/AudioFxButton.tsx +290 -0
- package/src/panels/timeline/AudioLane.tsx +674 -85
- package/src/panels/timeline/BlockRow.tsx +154 -85
- package/src/panels/timeline/ChannelRow.tsx +378 -129
- package/src/panels/timeline/CurvePane.tsx +508 -0
- package/src/panels/timeline/Filmstrip.tsx +361 -0
- package/src/panels/timeline/GenerateDrawer.tsx +407 -0
- package/src/panels/timeline/KeyStretch.tsx +115 -0
- package/src/panels/timeline/LifespanRow.tsx +730 -47
- package/src/panels/timeline/MarkerLane.tsx +46 -8
- package/src/panels/timeline/PlayButton.tsx +91 -0
- package/src/panels/timeline/PropertyPicker.tsx +254 -0
- package/src/panels/timeline/ShotRow.tsx +400 -0
- package/src/panels/timeline/SoundMode.tsx +1406 -0
- package/src/panels/timeline/TimelineDock.tsx +2338 -272
- package/src/panels/timeline/TransportVolume.tsx +163 -0
- package/src/panels/timeline/beatRuler.ts +74 -0
- package/src/panels/timeline/curveModel.ts +500 -0
- package/src/panels/timeline/duckUnderVoice.ts +68 -0
- package/src/panels/timeline/keyframeMenu.ts +138 -0
- package/src/panels/timeline/labelWidth.ts +49 -0
- package/src/panels/timeline/marquee.ts +155 -0
- package/src/panels/timeline/model.ts +1860 -199
- package/src/panels/timeline/snap.ts +125 -43
- package/src/panels/timeline/staggerPreview.tsx +92 -0
- package/src/panels/timeline/takeMeasure.ts +72 -0
- package/src/panels/timeline/useLive.ts +48 -0
- package/src/panels/timeline/viewport.ts +234 -0
- package/src/panels/toolbar/BackChip.tsx +116 -0
- package/src/panels/toolbar/CameraViewBar.tsx +118 -49
- package/src/panels/toolbar/CanvasBar.tsx +117 -0
- package/src/panels/toolbar/InsertButton.tsx +38 -0
- package/src/panels/toolbar/IsolationTrail.tsx +156 -0
- package/src/panels/toolbar/PanelToggles.tsx +86 -0
- package/src/panels/toolbar/ShadingBar.tsx +119 -26
- package/src/panels/toolbar/ToolDockBar.tsx +329 -80
- package/src/panels/toolbar/ToolFooter.tsx +102 -0
- package/src/panels/toolbar/ViewModeBar.tsx +247 -38
- package/src/panels/toolbar/WorkPlaneBar.tsx +94 -0
- package/src/panels/toolbar/useAddRows.tsx +326 -0
- package/src/panels/toolbar/useDismiss.ts +122 -0
- package/src/panels/versions/VersionHistoryPanel.tsx +274 -0
- package/src/panels/versions/versionModel.ts +103 -0
- package/src/panels/virtualWindow.ts +271 -0
- package/src/shotTokens.css +151 -60
- package/src/stage/FrustumGizmo.tsx +504 -84
- package/src/stage/GridPlane.tsx +225 -16
- package/src/stage/NodePreviews.tsx +628 -0
- package/src/stage/PerfHud.tsx +437 -47
- package/src/stage/SplitRenderer.tsx +816 -169
- package/src/stage/StageApp.tsx +4274 -486
- package/src/stage/StageRootBoundary.tsx +114 -0
- package/src/stage/StageTools.tsx +651 -151
- package/src/stage/TransformGizmo.tsx +696 -0
- package/src/stage/adaptivePresentation.ts +145 -0
- package/src/stage/bridgeClient.ts +2522 -41
- package/src/stage/exportWorker.ts +9 -0
- package/src/stage/feed.ts +305 -14
- package/src/stage/fontPreview.ts +176 -0
- package/src/stage/frustumGeometry.ts +319 -1
- package/src/stage/furnitureTokens.ts +33 -0
- package/src/stage/gizmoMath.ts +508 -16
- package/src/stage/gpuTimer.ts +276 -0
- package/src/stage/instanceModules.ts +194 -33
- package/src/stage/interactions/move.ts +24 -5
- package/src/stage/isolation.ts +291 -33
- package/src/stage/jsSelfProfiler.ts +325 -0
- package/src/stage/main.tsx +116 -16
- package/src/stage/modalState.ts +222 -23
- package/src/stage/moduleEpoch.ts +60 -0
- package/src/stage/motionPathStage.ts +279 -0
- package/src/stage/motionPreview.ts +74 -0
- package/src/stage/overlays/Overlays.tsx +1112 -159
- package/src/stage/overlays/Rulers.tsx +495 -0
- package/src/stage/panes.ts +159 -10
- package/src/stage/project.ts +68 -3
- package/src/stage/renderScaleController.ts +730 -0
- package/src/stage/rulers.ts +129 -0
- package/src/stage/sceneExtent.ts +75 -0
- package/src/stage/shading.ts +20 -0
- package/src/stage/splineStage.ts +632 -0
- package/src/stage/stagePerformanceTelemetry.ts +717 -0
- package/src/stage/stageTheme.ts +36 -0
- package/src/stage/stageWarmup.ts +11 -0
- package/src/stage/textAutoSize.ts +124 -0
- package/src/stage/tier1Export.ts +641 -0
- package/src/stage/tokenColor.ts +14 -9
- package/src/stage/view.ts +56 -9
- package/src/stage/workingView.ts +277 -33
- package/src/state/accountPrefs.ts +261 -0
- package/src/state/agentActions.ts +173 -15
- package/src/state/agentActivity.ts +198 -0
- package/src/state/agentQuestion.ts +239 -0
- package/src/state/bootOpen.ts +42 -0
- package/src/state/cameraVerbs.ts +139 -0
- package/src/state/clientId.ts +6 -1
- package/src/state/comments.ts +1099 -0
- package/src/state/context.tsx +19 -1
- package/src/state/editorPrefs.ts +220 -0
- package/src/state/errorReports.ts +121 -0
- package/src/state/fieldWrite.ts +161 -0
- package/src/state/fontRecents.ts +70 -0
- package/src/state/fonts.ts +656 -0
- package/src/state/graphClipboard.ts +414 -0
- package/src/state/imageThumbs.ts +216 -0
- package/src/state/insert.ts +444 -67
- package/src/state/isolationTrail.ts +92 -0
- package/src/state/keyMoves.ts +134 -0
- package/src/state/keyframeClipboard.ts +177 -0
- package/src/state/keymap.ts +1153 -117
- package/src/state/layoutPrefs.ts +272 -0
- package/src/state/layouts.ts +205 -0
- package/src/state/measureMedia.ts +167 -0
- package/src/state/menu.ts +2341 -28
- package/src/state/motionStamp.ts +7 -0
- package/src/state/panelSize.ts +375 -5
- package/src/state/pendingChanges.ts +119 -0
- package/src/state/playHold.ts +78 -0
- package/src/state/playbackPreparation.ts +562 -0
- package/src/state/posterCapture.ts +242 -0
- package/src/state/presence.ts +254 -0
- package/src/state/projectComponents.ts +160 -0
- package/src/state/renderEvents.ts +298 -18
- package/src/state/runtimeErrors.ts +46 -0
- package/src/state/selection.ts +12 -0
- package/src/state/shortcuts.ts +1606 -0
- package/src/state/sketchGuide.ts +51 -0
- package/src/state/splineRefs.ts +87 -0
- package/src/state/stageHealth.ts +259 -0
- package/src/state/stageWatchdog.ts +47 -0
- package/src/state/stillStage.ts +330 -0
- package/src/state/stillThumbs.ts +474 -0
- package/src/state/store.ts +23591 -2982
- package/src/state/storyboardModel.ts +528 -0
- package/src/state/sync.ts +1257 -0
- package/src/state/syncCache.ts +159 -0
- package/src/state/triangles.ts +13 -0
- package/src/state/types.ts +1698 -55
- package/src/state/unsavedGuard.ts +49 -0
- package/src/state/viewMode.ts +200 -0
- package/src/state/webmcp.ts +1128 -0
- package/src/state/workspace.ts +1147 -0
- package/src/styles/assets-tab.css +304 -0
- package/src/styles/canvas.css +545 -0
- package/src/styles/comments.css +1435 -0
- package/src/styles/controls.css +162 -0
- package/src/styles/dialogs.css +390 -0
- package/src/styles/insert-drawer.css +586 -0
- package/src/styles/inspector-board.css +207 -0
- package/src/styles/inspector-object.css +486 -0
- package/src/styles/inspector-shot.css +252 -0
- package/src/styles/inspector.css +360 -0
- package/src/styles/left-column.css +1628 -0
- package/src/styles/library-preview.css +575 -0
- package/src/styles/library.css +512 -0
- package/src/styles/modes/code.css +569 -0
- package/src/styles/modes/component.css +1561 -0
- package/src/styles/modes/material.css +1201 -0
- package/src/styles/modes/storyboard.css +518 -0
- package/src/styles/share-component.css +49 -0
- package/src/styles/shell.css +653 -0
- package/src/styles/shot-brief.css +360 -0
- package/src/styles/states.css +76 -0
- package/src/styles/sync.css +380 -0
- package/src/styles/timeline-graph.css +384 -0
- package/src/styles/timeline-meters.css +89 -0
- package/src/styles/timeline-rows.css +1959 -0
- package/src/styles/timeline-sound.css +1003 -0
- package/src/styles/timeline.css +754 -0
- package/src/styles/tool-footer.css +525 -0
- package/src/styles/topbar.css +886 -0
- package/src/styles/versions.css +262 -0
- package/src/styles.css +72 -2921
- package/src/tools.ts +108 -23
- package/dist/assets/index-B7notge7.css +0 -1
- package/dist/assets/index-BBE6Ta9L.js +0 -52
- package/src/panels/files/icons.tsx +0 -118
- package/src/panels/header/DocSwitcher.tsx +0 -85
- package/src/panels/header/TransportBar.tsx +0 -86
- package/src/panels/inspector/animate/BlockTiming.tsx +0 -341
- package/src/panels/inspector/animate/DuringBlocks.tsx +0 -85
- package/src/panels/inspector/animate/InOutPresets.tsx +0 -57
- package/src/panels/inspector/animate/ResolvedChannels.tsx +0 -150
- package/src/panels/inspector/animate/useBlocks.ts +0 -43
- package/src/panels/material/MaterialPicker.tsx +0 -172
- package/src/panels/timeline/SceneStrip.tsx +0 -145
- package/src/panels/toolbar/AddMenu.tsx +0 -230
- package/src/stage/MoveGizmo.tsx +0 -411
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
// WHAT A REFERENCE LOOKS LIKE, in one component so the library tile and the
|
|
2
|
+
// inspector's lead cannot drift into two answers about the same card.
|
|
3
|
+
//
|
|
4
|
+
// FOUR KINDS, FOUR ANSWERS, and each one is the most useful thing that kind
|
|
5
|
+
// has:
|
|
6
|
+
//
|
|
7
|
+
// An image is the image, lazily.
|
|
8
|
+
//
|
|
9
|
+
// A video is a `<video preload="metadata">` at a `#t=` media fragment, which
|
|
10
|
+
// is how you get a poster frame with no seek dance: the browser decodes to
|
|
11
|
+
// the fragment on its own and never plays. `muted` because a rail of six
|
|
12
|
+
// autoloading videos that could make sound is a rail nobody opens twice.
|
|
13
|
+
//
|
|
14
|
+
// A note is ITS OWN TEXT, clamped to three lines. A generic "N" glyph is the
|
|
15
|
+
// least informative thing a note can show, and the text is the whole card.
|
|
16
|
+
//
|
|
17
|
+
// A component is an icon over its export name, NEVER AN IFRAME. The board's
|
|
18
|
+
// cards mount live harnesses because a card is a card; a rail of twenty-nine
|
|
19
|
+
// harnesses is not a rail, it is twenty-nine bundles and twenty-nine module
|
|
20
|
+
// graphs behind a scroll bar.
|
|
21
|
+
//
|
|
22
|
+
// A library item is its shipped thumb (a shot's poster, a material's
|
|
23
|
+
// sphere, a pack's contact sheet) when the catalog row carries one, and its
|
|
24
|
+
// kind over its id when it does not (a blueprint ships no picture).
|
|
25
|
+
//
|
|
26
|
+
// A MISSING ASSET IS A STATE, not an empty box: an author who moved a file
|
|
27
|
+
// needs the card to say so where they are looking at it. A library item this
|
|
28
|
+
// build does not ship is the same state, for the same reason.
|
|
29
|
+
import type { ReferenceItem3D, ShotAsset } from "@dailies-studio/shot/doc";
|
|
30
|
+
import type { LibraryItem } from "../../api.js";
|
|
31
|
+
import { elementSummary, linkHost } from "../../state/storyboardModel.js";
|
|
32
|
+
|
|
33
|
+
/** A stored asset's URL. Here, with the card previews, because Studio's
|
|
34
|
+
* Brief draws cards too and loads with the shell, while ShotCard is the
|
|
35
|
+
* board's. */
|
|
36
|
+
export const assetUrl = (path: string): string => `/studio/assets/${encodeURIComponent(path)}`;
|
|
37
|
+
|
|
38
|
+
/** A card's kind as one glyph, for a thumb with no picture. A component card
|
|
39
|
+
* reads as Components shows it: a Studio-made definition is "3D", code is
|
|
40
|
+
* "</>". */
|
|
41
|
+
export function pinGlyph(item: ReferenceItem3D): string {
|
|
42
|
+
if (item.type === "component") return item.def !== undefined ? "3D" : "</>";
|
|
43
|
+
return item.type === "note" ? "N" : item.type === "link" ? "↗" : item.type.charAt(0).toUpperCase();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** What the CATALOG says a card should draw (`referenceThumbOf`). */
|
|
47
|
+
export interface ReferenceThumb {
|
|
48
|
+
libraryThumb: string | undefined;
|
|
49
|
+
libraryKind: string | undefined;
|
|
50
|
+
libraryMissing: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* What the CATALOG says a card should draw: a library card's thumb, kind and
|
|
55
|
+
* whether this build ships it at all, and a shipped component's thumb (the
|
|
56
|
+
* row whose `installedAs` is this card's component). One reader, so the lane
|
|
57
|
+
* thumbnails, the inspector lead and the board's cards cannot disagree.
|
|
58
|
+
* Pure, for a caller that draws many cards from one catalog read.
|
|
59
|
+
*/
|
|
60
|
+
export function referenceThumbOf(item: ReferenceItem3D, catalog: readonly LibraryItem[], loaded: boolean): ReferenceThumb {
|
|
61
|
+
if (item.type === "library") {
|
|
62
|
+
const row = catalog.find((r) => r.id === item.library);
|
|
63
|
+
return { libraryThumb: row?.thumb, libraryKind: row?.kind, libraryMissing: loaded && row === undefined };
|
|
64
|
+
}
|
|
65
|
+
if (item.type === "component") {
|
|
66
|
+
return { libraryThumb: catalog.find((r) => r.installedAs === item.component)?.thumb, libraryKind: undefined, libraryMissing: false };
|
|
67
|
+
}
|
|
68
|
+
return { libraryThumb: undefined, libraryKind: undefined, libraryMissing: false };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function ReferencePreview({
|
|
72
|
+
item,
|
|
73
|
+
asset,
|
|
74
|
+
fps,
|
|
75
|
+
libraryThumb,
|
|
76
|
+
libraryKind,
|
|
77
|
+
libraryMissing,
|
|
78
|
+
}: {
|
|
79
|
+
item: ReferenceItem3D;
|
|
80
|
+
asset?: ShotAsset | undefined;
|
|
81
|
+
/** Frames per second, so a stored still frame becomes the seconds a media
|
|
82
|
+
* fragment takes. Absent leaves the poster at the video's own first frame,
|
|
83
|
+
* which is the honest fallback rather than a guessed rate. */
|
|
84
|
+
fps?: { num: number; den: number } | undefined;
|
|
85
|
+
/** A `library` card's thumb URL, from its CATALOG row and never guessed
|
|
86
|
+
* from the id: the thumb route answers 404 for an item that ships none. */
|
|
87
|
+
libraryThumb?: string | undefined;
|
|
88
|
+
/** What the CATALOG row says the item is, when the caller holds one. A
|
|
89
|
+
* card's own `kind` is validated against the enum and never against the id
|
|
90
|
+
* it names, so it can be wrong; the glyph draws the item, not the claim.
|
|
91
|
+
* Absent, the document's kind is all there is to draw. */
|
|
92
|
+
libraryKind?: string | undefined;
|
|
93
|
+
/** The loaded catalog has no row at this card's id. */
|
|
94
|
+
libraryMissing?: boolean | undefined;
|
|
95
|
+
}) {
|
|
96
|
+
if (item.type === "library") {
|
|
97
|
+
if (libraryMissing === true) {
|
|
98
|
+
return (
|
|
99
|
+
<span className="reference-preview is-missing" title={`${item.library} v${item.version} is not in this build's library`}>
|
|
100
|
+
Not in this build's library
|
|
101
|
+
</span>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
if (libraryThumb !== undefined) {
|
|
105
|
+
return <img className="reference-preview" src={libraryThumb} alt="" loading="lazy" />;
|
|
106
|
+
}
|
|
107
|
+
const kind = libraryKind ?? item.kind;
|
|
108
|
+
return (
|
|
109
|
+
<span
|
|
110
|
+
className="reference-preview is-component"
|
|
111
|
+
title={
|
|
112
|
+
kind === item.kind
|
|
113
|
+
? `${kind} ${item.library} v${item.version}`
|
|
114
|
+
: `${item.library} v${item.version} is a ${kind}; this card says ${item.kind}`
|
|
115
|
+
}
|
|
116
|
+
>
|
|
117
|
+
<span className="reference-preview-glyph" aria-hidden="true">
|
|
118
|
+
{kind}
|
|
119
|
+
</span>
|
|
120
|
+
<span className="reference-preview-name">{item.library}</span>
|
|
121
|
+
</span>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
if (item.type === "note") {
|
|
125
|
+
return (
|
|
126
|
+
<span className="reference-preview is-note" title={item.text}>
|
|
127
|
+
{item.text.trim() === "" ? "Empty note" : item.text}
|
|
128
|
+
</span>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
if (item.type === "component") {
|
|
132
|
+
// A SHIPPED component draws its shipped thumb: the component on the real
|
|
133
|
+
// stage, where a live harness would frame it through `DefaultRig` and
|
|
134
|
+
// show a crop (measured 2026-09-25).
|
|
135
|
+
if (libraryThumb !== undefined) {
|
|
136
|
+
return <img className="reference-preview" src={libraryThumb} alt="" loading="lazy" />;
|
|
137
|
+
}
|
|
138
|
+
return (
|
|
139
|
+
<span className="reference-preview is-component" title={item.component}>
|
|
140
|
+
<span className="reference-preview-glyph" aria-hidden="true">
|
|
141
|
+
{pinGlyph(item)}
|
|
142
|
+
</span>
|
|
143
|
+
<span className="reference-preview-name">{item.component === undefined ? item.label : exportNameOf(item.component)}</span>
|
|
144
|
+
</span>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
if (item.type === "link") {
|
|
148
|
+
return (
|
|
149
|
+
<span className="reference-preview is-component" title={item.url}>
|
|
150
|
+
<span className="reference-preview-name">{item.title ?? linkHost(item.url)}</span>
|
|
151
|
+
</span>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
if (item.type !== "asset") {
|
|
155
|
+
return (
|
|
156
|
+
<span className="reference-preview is-component" title={item.label}>
|
|
157
|
+
<span className="reference-preview-name">{elementSummary(item)}</span>
|
|
158
|
+
</span>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
if (asset === undefined) {
|
|
162
|
+
return (
|
|
163
|
+
<span className="reference-preview is-missing" title="The file this card points at is not in the Project">
|
|
164
|
+
File missing
|
|
165
|
+
</span>
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
const src = `/studio/assets/${encodeURIComponent(asset.path)}`;
|
|
169
|
+
if (asset.kind === "image") {
|
|
170
|
+
return <img className="reference-preview" src={src} alt="" loading="lazy" />;
|
|
171
|
+
}
|
|
172
|
+
if (asset.kind === "video") {
|
|
173
|
+
const at = item.frame === undefined || fps === undefined ? null : (item.frame * fps.den) / fps.num;
|
|
174
|
+
return <MediaPoster className="reference-preview" src={src} atSeconds={at} />;
|
|
175
|
+
}
|
|
176
|
+
const glyph = asset.kind === "font" ? "Aa" : asset.kind === "audio" ? "♪" : asset.kind === "model" ? "3D" : "·";
|
|
177
|
+
return (
|
|
178
|
+
<span className="reference-preview is-kind" aria-hidden="true">
|
|
179
|
+
{glyph}
|
|
180
|
+
</span>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* A video's poster frame, shared by the board's cards and the rail's Assets
|
|
186
|
+
* grid. `#t=` is a MEDIA FRAGMENT and not a query: the browser seeks to it while
|
|
187
|
+
* loading metadata, so the poster is that still with no `seeked` listener, no
|
|
188
|
+
* canvas draw and no second network trip. Null leaves the video's own first
|
|
189
|
+
* frame.
|
|
190
|
+
*/
|
|
191
|
+
export function MediaPoster({
|
|
192
|
+
src,
|
|
193
|
+
atSeconds,
|
|
194
|
+
className,
|
|
195
|
+
}: {
|
|
196
|
+
src: string;
|
|
197
|
+
atSeconds: number | null;
|
|
198
|
+
className: string;
|
|
199
|
+
}) {
|
|
200
|
+
return (
|
|
201
|
+
<video
|
|
202
|
+
className={className}
|
|
203
|
+
src={atSeconds === null ? src : `${src}#t=${atSeconds.toFixed(3)}`}
|
|
204
|
+
preload="metadata"
|
|
205
|
+
muted
|
|
206
|
+
playsInline
|
|
207
|
+
aria-hidden="true"
|
|
208
|
+
/>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** "src/Card.tsx#Card" -> "Card". The registry id is the title; the export is
|
|
213
|
+
* what fits on a tile. */
|
|
214
|
+
function exportNameOf(componentId: string): string {
|
|
215
|
+
const at = componentId.lastIndexOf("#");
|
|
216
|
+
return at === -1 ? componentId : componentId.slice(at + 1);
|
|
217
|
+
}
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
// THE STUDIO'S BRIEF TAB (S4, Paper SB6): what the board says about the Shot
|
|
2
|
+
// under the playhead, read here while it is built, the sketches handed over as
|
|
3
|
+
// layers or as a guide, and the one write that sends the result back: "Mark
|
|
4
|
+
// shot built".
|
|
5
|
+
//
|
|
6
|
+
// head "From the board" and "Open shot board" (this shot's board).
|
|
7
|
+
// shot the number and name, the planned length, and the linked Shot's
|
|
8
|
+
// when it differs: the length the card shows, built or not.
|
|
9
|
+
// sketches each sketch drawn small with its label and time, as the still
|
|
10
|
+
// stage draws it once that is ready (`useSketchThumbs`). A press picks
|
|
11
|
+
// the sketch "Lay out Sketch N" copies into real layers in one
|
|
12
|
+
// undo step (`layOutSketch`). Lay out is the Brief's one
|
|
13
|
+
// primary while there is a sketch (Paper SB6).
|
|
14
|
+
// guide "Guide: Off | Sketch N" (`sketchGuide`): the stage draws that
|
|
15
|
+
// sketch as dashed outlines over the camera frame. A view. Its
|
|
16
|
+
// label sits in its row like every inspector row's, and past four
|
|
17
|
+
// words (Off and four sketches) the row is a Combobox, the house
|
|
18
|
+
// rule for a segmented row.
|
|
19
|
+
// words What we see (`part.notes`) and the voice line.
|
|
20
|
+
// pinned the cards pinned to this shot as a checklist. A tick comes from
|
|
21
|
+
// the data (D4): `requirementStatus` says the Shot uses it, or the
|
|
22
|
+
// author ticked it by hand (`done`). Only the hand tick is written
|
|
23
|
+
// here; the agent writes no ticks. A card that is no requirement
|
|
24
|
+
// (a note, a link, inspiration) lists with no box.
|
|
25
|
+
// style the Style row's count, linked, never copied.
|
|
26
|
+
// footer Mark shot built: `part.built.frame` = the playhead's frame in
|
|
27
|
+
// this Shot, one undo step (`markShotBuilt`). Built, it offers the
|
|
28
|
+
// playhead's frame again and Unmark.
|
|
29
|
+
//
|
|
30
|
+
// THE PART is the one LINKED to the Shot (`part.scene`): a Shot no plan links
|
|
31
|
+
// has no brief, and says so. A VIEWER reads it all with the writes off.
|
|
32
|
+
import { useState } from "react";
|
|
33
|
+
import { framesToSeconds } from "@dailies-studio/engine";
|
|
34
|
+
import { Combobox, InspectorRow, LockedControls, SegmentedControl } from "@dailies-studio/ui";
|
|
35
|
+
import { isRequirement, partFramesOf, referenceImportanceOf, requirementStatus, sceneStart } from "@dailies-studio/shot/doc";
|
|
36
|
+
import type { Doc3D, ReferenceItem3D, StoryboardPart3D, StoryboardSketch3D } from "@dailies-studio/shot/doc";
|
|
37
|
+
import { LAY_OUT_ICON, OPEN_ELSEWHERE_ICON } from "../../icons.js";
|
|
38
|
+
import { useShotEditor, useShotEditorHot, useStore } from "../../state/context.js";
|
|
39
|
+
import { storyEntries, styleItemsOf } from "../../state/storyboardModel.js";
|
|
40
|
+
import { formatDuration } from "../timeline/model.js";
|
|
41
|
+
import { MiniSketch } from "./MiniSketch.js";
|
|
42
|
+
import { assetUrl, pinGlyph } from "./ReferencePreview.js";
|
|
43
|
+
import { useSketchThumbs } from "./StillThumbs.js";
|
|
44
|
+
|
|
45
|
+
/** A thumb's picture width, CSS px (Paper SB6: 132x74). */
|
|
46
|
+
const THUMB_W = 132;
|
|
47
|
+
|
|
48
|
+
/** The most words a segmented row holds (docs/design-system.md): past it the
|
|
49
|
+
* Guide is a Combobox. */
|
|
50
|
+
const GUIDE_SEGMENTS_MAX = 4;
|
|
51
|
+
|
|
52
|
+
/** The part linked to `sceneId`, or null. */
|
|
53
|
+
export function briefPartOf(doc: Doc3D, sceneId: string | null): StoryboardPart3D | null {
|
|
54
|
+
if (sceneId === null) return null;
|
|
55
|
+
return doc.storyboard?.parts.find((p) => p.scene === sceneId) ?? null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** One pinned row's tick (D4): "data" when the Shot uses it, "hand" when the
|
|
59
|
+
* author ticked it, "open" when neither, null when it is no requirement. */
|
|
60
|
+
export function briefTick(doc: Doc3D, item: ReferenceItem3D): "data" | "hand" | "open" | null {
|
|
61
|
+
if (!isRequirement(item)) return null;
|
|
62
|
+
if (item.done === true) return "hand";
|
|
63
|
+
return requirementStatus(doc, item)?.state === "satisfied" ? "data" : "open";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** "1 · Start": a sketch's number, then its label when it has one. */
|
|
67
|
+
export function sketchName(sketch: StoryboardSketch3D, index: number): string {
|
|
68
|
+
return sketch.label === undefined ? String(index + 1) : `${index + 1} · ${sketch.label}`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function ShotBrief() {
|
|
72
|
+
const store = useStore();
|
|
73
|
+
const doc = useShotEditor((s) => s.doc);
|
|
74
|
+
const sceneId = useShotEditor((s) => s.enteredScene ?? s.sceneId);
|
|
75
|
+
const readOnly = useShotEditor((s) => s.readOnly);
|
|
76
|
+
const guide = useShotEditor((s) => s.sketchGuide);
|
|
77
|
+
// The sketch Lay out copies: the one picked, else the first.
|
|
78
|
+
const [picked, setPicked] = useState<string | null>(null);
|
|
79
|
+
// The playhead is clock-bearing, so this reads it HOT, but as one boolean:
|
|
80
|
+
// a playing clock re-renders the Brief only when it crosses the built frame.
|
|
81
|
+
// Its Shot from the same hot read: a cut the transport plays leaves the cold
|
|
82
|
+
// `sceneId` above on the Shot it left until Pause, and that Shot's clamp
|
|
83
|
+
// read the new Shot's frames as its own last one.
|
|
84
|
+
const onBuilt = useShotEditorHot(
|
|
85
|
+
(s) => (s.enteredScene ?? s.sceneId) === sceneId && playheadOnBuilt(s.doc, sceneId, s.frame),
|
|
86
|
+
);
|
|
87
|
+
const part = doc === null ? null : briefPartOf(doc, sceneId);
|
|
88
|
+
// The sketches as the still stage draws them: the still queue runs while
|
|
89
|
+
// the Brief shows (`stillThumbsActive`). The DOM drawing until then.
|
|
90
|
+
const pictures = useSketchThumbs(part?.id ?? "", (part?.sketches ?? []).map((sketch) => sketch.id));
|
|
91
|
+
if (doc === null) return null;
|
|
92
|
+
|
|
93
|
+
if (part === null || sceneId === null) {
|
|
94
|
+
return (
|
|
95
|
+
<div className="shot-brief" data-testid="shot-brief">
|
|
96
|
+
<BriefHead partId={null} />
|
|
97
|
+
<p className="shot-brief-empty" data-testid="shot-brief-empty">
|
|
98
|
+
No planned shot on the board links this Shot. Plan it on the board to see its brief here.
|
|
99
|
+
</p>
|
|
100
|
+
</div>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const fps = doc.fps;
|
|
105
|
+
const at = storyEntries(doc).findIndex((e) => (e.kind === "shot" ? e.shot.part?.id : e.part.id) === part.id);
|
|
106
|
+
const number = at < 0 ? null : String(at + 1).padStart(2, "0");
|
|
107
|
+
const pins = (doc.resources?.references ?? []).filter((r) => r.part === part.id);
|
|
108
|
+
const style = styleItemsOf(doc).length;
|
|
109
|
+
// The length the card shows (decision 1): the linked Shot's, built or not.
|
|
110
|
+
const shotFrames = partFramesOf(doc, part);
|
|
111
|
+
const built = part.built;
|
|
112
|
+
const sketches = part.sketches ?? [];
|
|
113
|
+
const chosen = sketches.findIndex((k) => k.id === picked);
|
|
114
|
+
const layIndex = chosen < 0 ? 0 : chosen;
|
|
115
|
+
const laySketch = sketches[layIndex];
|
|
116
|
+
// One primary per surface, as Paper SB6 draws it: Lay out holds it while
|
|
117
|
+
// there is a sketch to lay out, else the footer's button does.
|
|
118
|
+
const footPrimary = laySketch === undefined ? " is-primary" : "";
|
|
119
|
+
const guided = guide !== null && guide.partId === part.id && sketches.some((k) => k.id === guide.sketchId) ? guide.sketchId : null;
|
|
120
|
+
const guideTo = (value: string): void => store.setSketchGuide(value === "off" ? null : { partId: part.id, sketchId: value });
|
|
121
|
+
|
|
122
|
+
const layOut =
|
|
123
|
+
laySketch === undefined ? null : (
|
|
124
|
+
<section className="shot-brief-layout">
|
|
125
|
+
<button
|
|
126
|
+
type="button"
|
|
127
|
+
className="btn is-primary shot-brief-layout-run"
|
|
128
|
+
data-testid="shot-brief-layout"
|
|
129
|
+
disabled={readOnly}
|
|
130
|
+
onClick={() => void store.layOutSketch(part.id, laySketch.id)}
|
|
131
|
+
>
|
|
132
|
+
{LAY_OUT_ICON}
|
|
133
|
+
{`Lay out Sketch ${layIndex + 1}`}
|
|
134
|
+
</button>
|
|
135
|
+
<p className="shot-brief-help">Places images, components and text as layers. Boxes become placeholders.</p>
|
|
136
|
+
</section>
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<LockedControls value={readOnly}>
|
|
141
|
+
<div className="shot-brief" data-testid="shot-brief">
|
|
142
|
+
<div className="shot-brief-body">
|
|
143
|
+
<div className="shot-brief-origin">
|
|
144
|
+
<BriefHead partId={part.id} />
|
|
145
|
+
<header className="shot-brief-shot">
|
|
146
|
+
<span className="shot-brief-name" data-testid="shot-brief-name">
|
|
147
|
+
{number === null ? part.label : `${number} ${part.label}`}
|
|
148
|
+
</span>
|
|
149
|
+
<span className="shot-brief-length" data-testid="shot-brief-length">
|
|
150
|
+
{`· planned ${formatDuration(framesToSeconds(part.durationFrames, fps))}`}
|
|
151
|
+
{shotFrames === part.durationFrames ? null : ` · its Shot runs ${formatDuration(framesToSeconds(shotFrames, fps))}`}
|
|
152
|
+
</span>
|
|
153
|
+
</header>
|
|
154
|
+
</div>
|
|
155
|
+
<section className="shot-brief-section">
|
|
156
|
+
<h4 className="shot-brief-caps">Sketches</h4>
|
|
157
|
+
{sketches.length === 0 ? (
|
|
158
|
+
<p className="shot-brief-none" data-testid="shot-brief-no-sketches">
|
|
159
|
+
No sketches yet. Sketch this shot on its shot board.
|
|
160
|
+
</p>
|
|
161
|
+
) : (
|
|
162
|
+
<ul className="shot-brief-sketches" aria-label="Sketches">
|
|
163
|
+
{sketches.map((sketch, i) => (
|
|
164
|
+
<li key={sketch.id} className="shot-brief-sketch-item">
|
|
165
|
+
<button
|
|
166
|
+
type="button"
|
|
167
|
+
className="shot-brief-thumb"
|
|
168
|
+
data-testid={`shot-brief-sketch-${sketch.id}`}
|
|
169
|
+
data-guide={guided === sketch.id ? "" : undefined}
|
|
170
|
+
aria-pressed={i === layIndex}
|
|
171
|
+
title={`Lay out Sketch ${i + 1}`}
|
|
172
|
+
onClick={() => setPicked(sketch.id)}
|
|
173
|
+
>
|
|
174
|
+
<MiniSketch doc={doc} sketch={sketch} width={THUMB_W} picture={pictures.get(sketch.id) ?? null} />
|
|
175
|
+
</button>
|
|
176
|
+
<span className="shot-brief-sketch-label">
|
|
177
|
+
<span className="shot-brief-sketch-name">{sketchName(sketch, i)}</span>
|
|
178
|
+
{sketch.frame === undefined ? null : (
|
|
179
|
+
<span className="shot-brief-sketch-time">{formatDuration(framesToSeconds(sketch.frame, fps))}</span>
|
|
180
|
+
)}
|
|
181
|
+
</span>
|
|
182
|
+
</li>
|
|
183
|
+
))}
|
|
184
|
+
</ul>
|
|
185
|
+
)}
|
|
186
|
+
</section>
|
|
187
|
+
{layOut}
|
|
188
|
+
{/* The guide is a view, never a write: a viewer may use it too. */}
|
|
189
|
+
{sketches.length === 0 ? null : (
|
|
190
|
+
<LockedControls value={false}>
|
|
191
|
+
<InspectorRow label="Guide">
|
|
192
|
+
{sketches.length + 1 <= GUIDE_SEGMENTS_MAX ? (
|
|
193
|
+
<SegmentedControl
|
|
194
|
+
ariaLabel="Guide"
|
|
195
|
+
value={guided ?? "off"}
|
|
196
|
+
options={[
|
|
197
|
+
{ value: "off", label: "Off", testId: "shot-brief-guide-off" },
|
|
198
|
+
...sketches.map((sketch, i) => ({
|
|
199
|
+
value: sketch.id,
|
|
200
|
+
label: `Sketch ${i + 1}`,
|
|
201
|
+
title: `Draw Sketch ${i + 1} over the stage`,
|
|
202
|
+
testId: `shot-brief-guide-${sketch.id}`,
|
|
203
|
+
})),
|
|
204
|
+
]}
|
|
205
|
+
onChange={guideTo}
|
|
206
|
+
/>
|
|
207
|
+
) : (
|
|
208
|
+
<Combobox
|
|
209
|
+
ariaLabel="Guide"
|
|
210
|
+
value={guided ?? "off"}
|
|
211
|
+
options={[{ value: "off", label: "Off" }, ...sketches.map((sketch, i) => ({ value: sketch.id, label: `Sketch ${i + 1}` }))]}
|
|
212
|
+
onChange={guideTo}
|
|
213
|
+
/>
|
|
214
|
+
)}
|
|
215
|
+
</InspectorRow>
|
|
216
|
+
</LockedControls>
|
|
217
|
+
)}
|
|
218
|
+
{part.notes === undefined ? null : (
|
|
219
|
+
<section className="shot-brief-section is-words">
|
|
220
|
+
<h4 className="shot-brief-caps">What we see</h4>
|
|
221
|
+
<p className="shot-brief-text" data-testid="shot-brief-notes">{part.notes}</p>
|
|
222
|
+
</section>
|
|
223
|
+
)}
|
|
224
|
+
{part.voice === undefined ? null : (
|
|
225
|
+
<section className="shot-brief-section">
|
|
226
|
+
<h4 className="shot-brief-caps">Voice</h4>
|
|
227
|
+
<p className="shot-brief-voice" data-testid="shot-brief-voice">{`“${part.voice}”`}</p>
|
|
228
|
+
</section>
|
|
229
|
+
)}
|
|
230
|
+
<section className="shot-brief-section is-pinned">
|
|
231
|
+
<h4 className="shot-brief-caps">Pinned to this shot</h4>
|
|
232
|
+
{pins.length === 0 ? (
|
|
233
|
+
<p className="shot-brief-none">Nothing pinned. Drop cards on this shot on the board.</p>
|
|
234
|
+
) : (
|
|
235
|
+
<ul className="shot-brief-pins" aria-label="Pinned to this shot">
|
|
236
|
+
{pins.map((item) => (
|
|
237
|
+
<BriefPin key={item.id} doc={doc} item={item} />
|
|
238
|
+
))}
|
|
239
|
+
</ul>
|
|
240
|
+
)}
|
|
241
|
+
</section>
|
|
242
|
+
<div className="shot-brief-style" data-testid="shot-brief-style">
|
|
243
|
+
<span className="shot-brief-style-name">Style</span>
|
|
244
|
+
<span className="shot-brief-style-text">
|
|
245
|
+
{style === 0 ? "No Style cards yet" : `${style} ${style === 1 ? "item" : "items"}, whole reel`}
|
|
246
|
+
</span>
|
|
247
|
+
<button type="button" className="shot-brief-link" onClick={() => openBoard(store, null)}>
|
|
248
|
+
View
|
|
249
|
+
</button>
|
|
250
|
+
</div>
|
|
251
|
+
</div>
|
|
252
|
+
<footer className="shot-brief-foot">
|
|
253
|
+
<p className="shot-brief-foot-text" data-testid="shot-brief-foot-text">
|
|
254
|
+
{built === undefined
|
|
255
|
+
? "Sends the playhead's frame back to the card as its picture. The sketches stay."
|
|
256
|
+
: `On the card: frame ${built.frame}. The sketches stay.`}
|
|
257
|
+
</p>
|
|
258
|
+
{built === undefined ? (
|
|
259
|
+
<button
|
|
260
|
+
type="button"
|
|
261
|
+
className={`btn${footPrimary} shot-brief-mark`}
|
|
262
|
+
data-testid="shot-brief-mark"
|
|
263
|
+
disabled={readOnly}
|
|
264
|
+
onClick={() => store.markShotBuilt(part.id, true)}
|
|
265
|
+
>
|
|
266
|
+
Mark shot built
|
|
267
|
+
</button>
|
|
268
|
+
) : (
|
|
269
|
+
<div className="shot-brief-actions">
|
|
270
|
+
<button
|
|
271
|
+
type="button"
|
|
272
|
+
className="btn is-outline"
|
|
273
|
+
data-testid="shot-brief-unmark"
|
|
274
|
+
disabled={readOnly}
|
|
275
|
+
onClick={() => store.markShotBuilt(part.id, false)}
|
|
276
|
+
>
|
|
277
|
+
Unmark
|
|
278
|
+
</button>
|
|
279
|
+
<button
|
|
280
|
+
type="button"
|
|
281
|
+
className={`btn${footPrimary}`}
|
|
282
|
+
data-testid="shot-brief-remark"
|
|
283
|
+
disabled={readOnly || onBuilt}
|
|
284
|
+
title={onBuilt ? "The card already shows this frame." : "Show the frame under the playhead on the card"}
|
|
285
|
+
onClick={() => store.markShotBuilt(part.id, true)}
|
|
286
|
+
>
|
|
287
|
+
Use this frame
|
|
288
|
+
</button>
|
|
289
|
+
</div>
|
|
290
|
+
)}
|
|
291
|
+
</footer>
|
|
292
|
+
</div>
|
|
293
|
+
</LockedControls>
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/** The playhead's frame in the linked Shot, clamped to it, is the frame the
|
|
298
|
+
* linked part is marked built at. */
|
|
299
|
+
function playheadOnBuilt(doc: Doc3D | null, sceneId: string | null, frame: number): boolean {
|
|
300
|
+
if (doc === null || sceneId === null) return false;
|
|
301
|
+
const built = briefPartOf(doc, sceneId)?.built;
|
|
302
|
+
if (built === undefined) return false;
|
|
303
|
+
const start = sceneStart(doc, sceneId) ?? 0;
|
|
304
|
+
const span = doc.scenesById[sceneId]?.durationFrames ?? 1;
|
|
305
|
+
return Math.min(Math.max(0, frame - start), Math.max(0, span - 1)) === built.frame;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
type Store = ReturnType<typeof useStore>;
|
|
309
|
+
|
|
310
|
+
/** This shot's board when it has a plan, else the board. */
|
|
311
|
+
function openBoard(store: Store, partId: string | null): void {
|
|
312
|
+
if (partId !== null) store.openShotBoard(partId);
|
|
313
|
+
else store.setStoryboardOpen(true);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function BriefHead({ partId }: { partId: string | null }) {
|
|
317
|
+
const store = useStore();
|
|
318
|
+
return (
|
|
319
|
+
<div className="shot-brief-head">
|
|
320
|
+
<span className="shot-brief-from">From the board</span>
|
|
321
|
+
<button type="button" className="shot-brief-link" data-testid="shot-brief-open-board" onClick={() => openBoard(store, partId)}>
|
|
322
|
+
{partId === null ? "Open board" : "Open shot board"}
|
|
323
|
+
{OPEN_ELSEWHERE_ICON}
|
|
324
|
+
</button>
|
|
325
|
+
</div>
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function BriefPin({ doc, item }: { doc: Doc3D; item: ReferenceItem3D }) {
|
|
330
|
+
const store = useStore();
|
|
331
|
+
const readOnly = useShotEditor((s) => s.readOnly);
|
|
332
|
+
const tick = briefTick(doc, item);
|
|
333
|
+
const asset = item.type === "asset" ? doc.assets[item.asset] : undefined;
|
|
334
|
+
const must = referenceImportanceOf(item) === "must";
|
|
335
|
+
const name = item.label.trim() || "Untitled card";
|
|
336
|
+
return (
|
|
337
|
+
<li className="shot-brief-pin" data-testid={`shot-brief-pin-${item.id}`} data-tick={tick ?? "none"}>
|
|
338
|
+
<span className="shot-brief-pin-thumb" aria-hidden="true">
|
|
339
|
+
{asset?.kind === "image" ? <img src={assetUrl(asset.path)} alt="" draggable={false} loading="lazy" /> : pinGlyph(item)}
|
|
340
|
+
</span>
|
|
341
|
+
<span className="shot-brief-pin-name">{name}</span>
|
|
342
|
+
{tick === null ? null : (
|
|
343
|
+
<>
|
|
344
|
+
<span className={`shot-brief-pin-tag${must ? " is-must" : ""}`}>{must ? "Must" : "Optional"}</span>
|
|
345
|
+
<input
|
|
346
|
+
type="checkbox"
|
|
347
|
+
className="checkbox shot-brief-pin-check"
|
|
348
|
+
data-testid="shot-brief-pin-check"
|
|
349
|
+
aria-label={`${name}: in this shot`}
|
|
350
|
+
checked={tick !== "open"}
|
|
351
|
+
// The data's tick is not the author's to take back: the Shot uses it.
|
|
352
|
+
disabled={tick === "data" || readOnly}
|
|
353
|
+
title={tick === "data" ? "Used in this Shot" : tick === "hand" ? "Ticked by hand. Untick" : "Tick by hand"}
|
|
354
|
+
onChange={(event) => store.updateReference(item.id, { done: event.currentTarget.checked ? true : null })}
|
|
355
|
+
/>
|
|
356
|
+
</>
|
|
357
|
+
)}
|
|
358
|
+
</li>
|
|
359
|
+
);
|
|
360
|
+
}
|