@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,593 @@
|
|
|
1
|
+
// One selected card, LEADING WITH WHAT IT IS AND WHERE IT SITS IN THE PLAN:
|
|
2
|
+
// the picture, its lane, when that plays, and, for a requirement, whether the
|
|
3
|
+
// video has it (the status, Place and the Done tick, `RequirementRows`). Then
|
|
4
|
+
// what the card names, kind by kind: a text card's copy, a transition's kind
|
|
5
|
+
// and length, a sound's role, file and hit, a native card's kind and variant.
|
|
6
|
+
// Then what it is for and how hard it binds (`CardUseRows`, the block every
|
|
7
|
+
// board panel shares), and the note. What is left is one fold down, under
|
|
8
|
+
// More, and More shows only when the card has something there.
|
|
9
|
+
//
|
|
10
|
+
// NEVER A COMPONENT CARD. One component card selected is the component sheet's
|
|
11
|
+
// (`boardRightPanel`), which carries its stage, its props, its Frame, Use and
|
|
12
|
+
// Importance; the branches this section kept for one were unreachable in the
|
|
13
|
+
// product and are gone.
|
|
14
|
+
//
|
|
15
|
+
// THE NAME ROW IS GONE. `InspectorHead` renames a reference in place, which is
|
|
16
|
+
// the design system's stated rule: a panel names its subject before it lists
|
|
17
|
+
// its properties, so restating the name as a form row two lines below its own
|
|
18
|
+
// heading is the panel saying one thing twice.
|
|
19
|
+
//
|
|
20
|
+
// THE PREVIEW LEADS, through the same `ReferencePreview` the rail's tiles
|
|
21
|
+
// render. One component, so the tile and the lead cannot drift into two
|
|
22
|
+
// answers about one card. A video's lead is its still (`VideoStill`), which
|
|
23
|
+
// owns the box and says under it when its frame is past the recording's end.
|
|
24
|
+
//
|
|
25
|
+
// EVERY READ-ONLY VALUE is a `ReadoutRow`, the house readout, and every
|
|
26
|
+
// number a person drags has its scrub half (`useScrub`), so the board's other
|
|
27
|
+
// panels see the value move with the pointer. The rows and their buttons are
|
|
28
|
+
// the house's (widgets.css), so the sections need no scope of their own.
|
|
29
|
+
import { useEffect, useRef, useState } from "react";
|
|
30
|
+
import {
|
|
31
|
+
DEVICE_PRESET_IDS,
|
|
32
|
+
MESH_PRIMITIVE_KINDS,
|
|
33
|
+
NATIVE_LAYER_KINDS,
|
|
34
|
+
SOUND_ROLES,
|
|
35
|
+
partWindowsOf,
|
|
36
|
+
updateReference,
|
|
37
|
+
} from "@dailies-studio/shot/doc";
|
|
38
|
+
import type { Doc3D, ReferenceItem3D } from "@dailies-studio/shot/doc";
|
|
39
|
+
import { framesToSeconds } from "@dailies-studio/engine";
|
|
40
|
+
import { glPresetSpecs } from "@dailies-studio/transitions";
|
|
41
|
+
import { Combobox, FieldLabels, InspectorRow, InspectorSection, NumberField, SegmentedControl, TextField, useLocked } from "@dailies-studio/ui";
|
|
42
|
+
import { useShotEditor, useStore } from "../../../state/context.js";
|
|
43
|
+
import { isReferenceId } from "../../../state/storyboardModel.js";
|
|
44
|
+
import { CardNoteRow, CardUseRows, ReadoutRow, RequirementRows } from "../../storyboard/boardRows.js";
|
|
45
|
+
import { PartPicker } from "../../storyboard/PartPicker.js";
|
|
46
|
+
import { ReferencePreview } from "../../storyboard/ReferencePreview.js";
|
|
47
|
+
import { AUDIO_ACCEPT_ATTRIBUTE } from "../../storyboard/storyboardDrop.js";
|
|
48
|
+
import { VideoStill } from "./VideoStill.js";
|
|
49
|
+
import { formatDuration, timecode } from "../../timeline/model.js";
|
|
50
|
+
import { useScrub } from "../useDocWrite.js";
|
|
51
|
+
|
|
52
|
+
/** A typed or dragged whole number at or above `floor`, or null for a value
|
|
53
|
+
* that is no number. What every number row here writes. */
|
|
54
|
+
function wholeAtLeast(raw: unknown, floor: number): number | null {
|
|
55
|
+
return typeof raw === "number" && Number.isFinite(raw) ? Math.max(floor, Math.round(raw)) : null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** The last frame a video card can name: the recording's probed length in
|
|
59
|
+
* the Project's frames, the frame that starts before its end. Undefined when
|
|
60
|
+
* nobody has probed it, and the still says so instead if the frame is past
|
|
61
|
+
* it (`storyboardVideoSeconds`). */
|
|
62
|
+
export function videoFrameMax(seconds: number | undefined, fps: Doc3D["fps"]): number | undefined {
|
|
63
|
+
if (seconds === undefined || !Number.isFinite(seconds) || seconds <= 0) return undefined;
|
|
64
|
+
return Math.max(0, Math.ceil((seconds * fps.num) / fps.den) - 1);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function StoryboardReferenceSection() {
|
|
68
|
+
const store = useStore();
|
|
69
|
+
const open = useShotEditor((s) => s.storyboardOpen);
|
|
70
|
+
const selection = useShotEditor((s) => s.storyboardSelection);
|
|
71
|
+
const doc = useShotEditor((s) => s.doc);
|
|
72
|
+
const moreOpen = useShotEditor((s) => s.referenceMoreOpen);
|
|
73
|
+
const id = open && selection.length === 1 && isReferenceId(selection[0]!) ? selection[0]! : null;
|
|
74
|
+
const item = id === null ? undefined : doc?.resources?.references?.find((r) => r.id === id);
|
|
75
|
+
const libraryId = item?.type === "library" ? item.library : null;
|
|
76
|
+
// A LIBRARY CARD'S TWO SOURCES: the catalog row (is it in this build, what
|
|
77
|
+
// is it for, how long) and the item detail (its README, its ops). Both are
|
|
78
|
+
// selected by stable identity, so neither re-renders this panel on an
|
|
79
|
+
// unrelated store write.
|
|
80
|
+
const catalogLoaded = useShotEditor((s) => s.libraryCatalogLoaded);
|
|
81
|
+
const shipped = useShotEditor((s) => (libraryId === null ? undefined : s.libraryCatalog.find((row) => row.id === libraryId)));
|
|
82
|
+
const detail = useShotEditor((s) => (libraryId === null ? undefined : s.libraryItems[libraryId]));
|
|
83
|
+
// THE THIRD ANSWER TO "IS IT IN THIS BUILD". The registry omits an item it
|
|
84
|
+
// refused from the catalog, so without this row an item this build ships
|
|
85
|
+
// BROKEN reads as one it never shipped, and the notice below would offer a
|
|
86
|
+
// confident wrong diagnosis of a local fault the server already named.
|
|
87
|
+
const refused = useShotEditor((s) =>
|
|
88
|
+
libraryId === null ? undefined : s.libraryCatalogProblems.find((problem) => problem.id === libraryId),
|
|
89
|
+
);
|
|
90
|
+
// ONE VERB AT A TIME. A claim copies a whole Project and an import uploads a
|
|
91
|
+
// pack's files, neither is instant, and nothing else here disables the row:
|
|
92
|
+
// a second press on a claim mints a SECOND Project the generation fence then
|
|
93
|
+
// discards without a word. `StoryboardAddBar.run`'s shape.
|
|
94
|
+
const [busy, setBusy] = useState(false);
|
|
95
|
+
const run = (work: Promise<void>): void => {
|
|
96
|
+
setBusy(true);
|
|
97
|
+
void work.finally(() => setBusy(false));
|
|
98
|
+
};
|
|
99
|
+
// A VIEWER'S PANEL LOCKS EVERY VERB THAT WRITES. `LockedControls` reaches
|
|
100
|
+
// the widgets; these are plain buttons, so they read the lock themselves.
|
|
101
|
+
const locked = useLocked();
|
|
102
|
+
|
|
103
|
+
// HOOKS BEFORE THE EARLY RETURNS, the marker section's rule.
|
|
104
|
+
// The catalog first, because it answers whether this build ships the item
|
|
105
|
+
// at all; the detail only for a row the catalog has, since a 404 for an id
|
|
106
|
+
// the missing notice already explains would be noise in the error strip.
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
if (libraryId === null) return;
|
|
109
|
+
if (!catalogLoaded) {
|
|
110
|
+
void store.refreshLibraryCatalog();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (shipped !== undefined) void store.loadLibraryItem(libraryId);
|
|
114
|
+
}, [libraryId, catalogLoaded, shipped, store]);
|
|
115
|
+
// The video's Frame, dragged: the still follows the pointer.
|
|
116
|
+
const frameScrub = useScrub((d, raw) => {
|
|
117
|
+
const frame = wholeAtLeast(raw, 0);
|
|
118
|
+
return id === null || frame === null ? d : updateReference(d, id, { frame });
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
if (doc === null || id === null || item === undefined) return null;
|
|
122
|
+
const parts = doc.storyboard?.parts ?? [];
|
|
123
|
+
const asset = item.type === "asset" ? doc.assets[item.asset] : undefined;
|
|
124
|
+
const isVideo = asset?.kind === "video";
|
|
125
|
+
|
|
126
|
+
// WHEN THE ATTACHED PART PLAYS. Derived from the prefix sum, never stored,
|
|
127
|
+
// so it cannot drift from a divider drag on the bar.
|
|
128
|
+
const window = item.part === undefined ? undefined : partWindowsOf(parts).find((w) => w.id === item.part);
|
|
129
|
+
// The loaded catalog has no row at this card's id. Only a LOADED catalog
|
|
130
|
+
// may say so: before it answers, "missing" would be a claim nobody made.
|
|
131
|
+
const libraryMissing = item.type === "library" && catalogLoaded && shipped === undefined;
|
|
132
|
+
// WHICH KIND THE PANEL ACTS ON. A card's `kind` is validated against the
|
|
133
|
+
// enum and never against the id it names, so `shot` can sit over a shipped
|
|
134
|
+
// blueprint. The registry owns the answer, exactly as the agent brief has
|
|
135
|
+
// it (`storyboard.ts`): dispatching on the document offered "Claim as
|
|
136
|
+
// Project" for a blueprint, which the server refuses with a 400, and left
|
|
137
|
+
// "Copy ops" disabled forever with "Waiting for the item's ops" for a
|
|
138
|
+
// material or a shot cited as `blueprint`. The document's kind is the
|
|
139
|
+
// fallback for a card whose row has not arrived, and the disagreement is
|
|
140
|
+
// SAID rather than silently resolved: the card is what an author fixes.
|
|
141
|
+
const libraryKind = item.type !== "library" ? undefined : (shipped?.kind ?? item.kind);
|
|
142
|
+
const kindDisagrees = item.type === "library" && shipped?.kind !== undefined && shipped.kind !== item.kind;
|
|
143
|
+
// A blueprint is copied by hand: its ops, with `$name` placeholders the
|
|
144
|
+
// author substitutes before applying them. The clipboard is the door, and
|
|
145
|
+
// its absence is said rather than swallowed.
|
|
146
|
+
const copyOps = (): void => {
|
|
147
|
+
const ops = detail?.blueprint?.ops;
|
|
148
|
+
if (ops === undefined) return;
|
|
149
|
+
const clipboard = typeof navigator === "undefined" ? undefined : navigator.clipboard;
|
|
150
|
+
if (clipboard === undefined) {
|
|
151
|
+
store.reportError("The clipboard is not available here, so the ops could not be copied.");
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
void clipboard
|
|
155
|
+
.writeText(JSON.stringify(ops, null, 2))
|
|
156
|
+
.catch((e: unknown) => store.reportError(e instanceof Error ? e.message : String(e)));
|
|
157
|
+
};
|
|
158
|
+
// WHAT IS UNDER MORE: a video's Frame, where a still came from, a library
|
|
159
|
+
// item's docs. A card with none of them has no fold at all: an empty More
|
|
160
|
+
// opened onto nothing.
|
|
161
|
+
const more = (item.type === "asset" && (isVideo || item.source !== undefined)) || item.type === "library";
|
|
162
|
+
const frame = item.type === "asset" ? (item.frame ?? 0) : 0;
|
|
163
|
+
const frameMax = videoFrameMax(asset?.media?.durationSeconds, doc.fps);
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<>
|
|
167
|
+
<InspectorSection title="Reference" persistKey="shot:storyboard-reference" collapsible={false}>
|
|
168
|
+
{/* THE PICTURE FIRST. What a card IS, before any property of it. */}
|
|
169
|
+
{item.type === "asset" && isVideo && asset !== undefined ? (
|
|
170
|
+
<VideoStill id={id} assetId={item.asset} path={asset.path} frame={frame} fps={doc.fps} label={item.label} />
|
|
171
|
+
) : (
|
|
172
|
+
<div className="insp-reference-lead">
|
|
173
|
+
<ReferencePreview
|
|
174
|
+
item={item}
|
|
175
|
+
{...(asset === undefined ? {} : { asset })}
|
|
176
|
+
fps={doc.fps}
|
|
177
|
+
{...(shipped?.thumb === undefined ? {} : { libraryThumb: shipped.thumb })}
|
|
178
|
+
{...(libraryKind === undefined ? {} : { libraryKind })}
|
|
179
|
+
{...(libraryMissing ? { libraryMissing } : {})}
|
|
180
|
+
/>
|
|
181
|
+
</div>
|
|
182
|
+
)}
|
|
183
|
+
<InspectorRow label="Lane">
|
|
184
|
+
<PartPicker
|
|
185
|
+
parts={parts}
|
|
186
|
+
value={item.part ?? null}
|
|
187
|
+
noneLabel="Global"
|
|
188
|
+
ariaLabel="Lane"
|
|
189
|
+
onChange={(part) => store.updateReference(id, { part })}
|
|
190
|
+
/>
|
|
191
|
+
</InspectorRow>
|
|
192
|
+
{window === undefined ? null : (
|
|
193
|
+
<ReadoutRow label="Plays">
|
|
194
|
+
{timecode(window.start, doc.fps)} to {timecode(window.end, doc.fps)}
|
|
195
|
+
</ReadoutRow>
|
|
196
|
+
)}
|
|
197
|
+
<RequirementRows doc={doc} item={item} />
|
|
198
|
+
<ElementRows doc={doc} item={item} />
|
|
199
|
+
{/* The two halves the old single Priority control conflated, in the
|
|
200
|
+
block every board panel draws. */}
|
|
201
|
+
<CardUseRows card={item} />
|
|
202
|
+
{/* WHAT THE CARD NAMES, for a library pick: the item, and the two
|
|
203
|
+
lines the library skill tells an agent to choose by. Read from the
|
|
204
|
+
catalog row, never from the document, which carries only the id,
|
|
205
|
+
the version and the kind. */}
|
|
206
|
+
{item.type === "library" ? (
|
|
207
|
+
<>
|
|
208
|
+
<ReadoutRow label="Item" title={`${item.library} v${item.version}`}>
|
|
209
|
+
{libraryKind} · {item.library} v{item.version}
|
|
210
|
+
</ReadoutRow>
|
|
211
|
+
{/* THE CARD IS WRONG ABOUT ITS OWN ITEM, said where the author is
|
|
212
|
+
looking at it and in the brief's own words, so the panel and
|
|
213
|
+
the brief cannot give one card two answers. The verb below
|
|
214
|
+
follows the item, which is the only one the server accepts. */}
|
|
215
|
+
{kindDisagrees ? (
|
|
216
|
+
<div className="insp-notice is-warn">
|
|
217
|
+
This build ships a {libraryKind}, but this card says {item.kind}. The action below follows the item; rewrite
|
|
218
|
+
the card to agree with it.
|
|
219
|
+
</div>
|
|
220
|
+
) : null}
|
|
221
|
+
{libraryMissing ? (
|
|
222
|
+
<div className="insp-notice is-warn">
|
|
223
|
+
{refused === undefined
|
|
224
|
+
? "Not in this build's library. The card keeps its id and version; another build may ship it."
|
|
225
|
+
: // The registry read it and REFUSED it, which is a local
|
|
226
|
+
// fault with a stated fix, not an item another build has.
|
|
227
|
+
`This build ships the item but its library refused to read it. ${refused.error}`}
|
|
228
|
+
</div>
|
|
229
|
+
) : null}
|
|
230
|
+
{shipped?.useFor === undefined ? null : (
|
|
231
|
+
<ReadoutRow label="Use for" prose>
|
|
232
|
+
{shipped.useFor}
|
|
233
|
+
</ReadoutRow>
|
|
234
|
+
)}
|
|
235
|
+
{shipped?.avoidFor === undefined ? null : (
|
|
236
|
+
<ReadoutRow label="Avoid for" prose>
|
|
237
|
+
{shipped.avoidFor}
|
|
238
|
+
</ReadoutRow>
|
|
239
|
+
)}
|
|
240
|
+
{shipped?.lengthFrames === undefined ? null : (
|
|
241
|
+
<ReadoutRow label="Length">
|
|
242
|
+
{formatDuration(framesToSeconds(shipped.lengthFrames, doc.fps))} · {shipped.lengthFrames}f
|
|
243
|
+
</ReadoutRow>
|
|
244
|
+
)}
|
|
245
|
+
</>
|
|
246
|
+
) : null}
|
|
247
|
+
{item.type === "note" ? (
|
|
248
|
+
<InspectorRow label="Text" align="start">
|
|
249
|
+
<TextField
|
|
250
|
+
multiline
|
|
251
|
+
value={item.text}
|
|
252
|
+
ariaLabel="Note text"
|
|
253
|
+
onCommit={(text) => {
|
|
254
|
+
const trimmed = text.trim();
|
|
255
|
+
if (trimmed.length > 0 && trimmed !== item.text) store.updateReference(id, { text: trimmed });
|
|
256
|
+
}}
|
|
257
|
+
/>
|
|
258
|
+
</InspectorRow>
|
|
259
|
+
) : (
|
|
260
|
+
<CardNoteRow card={item} />
|
|
261
|
+
)}
|
|
262
|
+
<InspectorRow>
|
|
263
|
+
{/* THE ONE VERB A LIBRARY PICK HAS, beside Remove, by kind: a shot
|
|
264
|
+
becomes a Project, a material or an image pack lands in THIS
|
|
265
|
+
one, a blueprint is copied by hand. Disabled with the reason in
|
|
266
|
+
`title` while the item is missing or its ops have not arrived.
|
|
267
|
+
BY THE REGISTRY'S KIND (`libraryKind`), never the document's: an
|
|
268
|
+
item whose kind the card gets wrong would otherwise offer the
|
|
269
|
+
verb its server route refuses. An id the registry knows as a
|
|
270
|
+
`component` has no verb here at all: dropping one installs it
|
|
271
|
+
and the card becomes a `component` reference. */}
|
|
272
|
+
{item.type === "library" && libraryId !== null ? (
|
|
273
|
+
libraryKind === "shot" ? (
|
|
274
|
+
<button
|
|
275
|
+
type="button"
|
|
276
|
+
className="btn"
|
|
277
|
+
disabled={libraryMissing || busy || locked}
|
|
278
|
+
title={
|
|
279
|
+
libraryMissing
|
|
280
|
+
? "This build does not ship the item"
|
|
281
|
+
: busy
|
|
282
|
+
? "Copying the Project…"
|
|
283
|
+
: "Copy this shot into a new Project and open it"
|
|
284
|
+
}
|
|
285
|
+
onClick={() => run(store.claimLibraryShot(libraryId))}
|
|
286
|
+
>
|
|
287
|
+
Claim as Project
|
|
288
|
+
</button>
|
|
289
|
+
) : libraryKind === "material" ? (
|
|
290
|
+
<button
|
|
291
|
+
type="button"
|
|
292
|
+
className="btn"
|
|
293
|
+
disabled={libraryMissing || busy || locked}
|
|
294
|
+
title={
|
|
295
|
+
libraryMissing
|
|
296
|
+
? "This build does not ship the item"
|
|
297
|
+
: busy
|
|
298
|
+
? "Writing into the Project…"
|
|
299
|
+
: "Add this preset to the Project's materials under a fresh id"
|
|
300
|
+
}
|
|
301
|
+
onClick={() => run(store.importLibraryIntoProject(libraryId, "material"))}
|
|
302
|
+
>
|
|
303
|
+
Import into this Project
|
|
304
|
+
</button>
|
|
305
|
+
) : libraryKind === "images" ? (
|
|
306
|
+
<button
|
|
307
|
+
type="button"
|
|
308
|
+
className="btn"
|
|
309
|
+
disabled={libraryMissing || busy || locked}
|
|
310
|
+
title={
|
|
311
|
+
libraryMissing
|
|
312
|
+
? "This build does not ship the item"
|
|
313
|
+
: busy
|
|
314
|
+
? "Writing into the Project…"
|
|
315
|
+
: "Register every file in the pack as a Project asset"
|
|
316
|
+
}
|
|
317
|
+
onClick={() => run(store.importLibraryIntoProject(libraryId, "images"))}
|
|
318
|
+
>
|
|
319
|
+
Add to Project assets
|
|
320
|
+
</button>
|
|
321
|
+
) : libraryKind === "blueprint" ? (
|
|
322
|
+
<button
|
|
323
|
+
type="button"
|
|
324
|
+
className="btn"
|
|
325
|
+
disabled={detail?.blueprint === undefined}
|
|
326
|
+
title={
|
|
327
|
+
libraryMissing
|
|
328
|
+
? "This build does not ship the item"
|
|
329
|
+
: detail?.blueprint === undefined
|
|
330
|
+
? "Waiting for the item's ops"
|
|
331
|
+
: "Copy the ops as JSON; substitute your layer ids for its placeholders, then apply them"
|
|
332
|
+
}
|
|
333
|
+
onClick={copyOps}
|
|
334
|
+
>
|
|
335
|
+
Copy ops
|
|
336
|
+
</button>
|
|
337
|
+
) : null
|
|
338
|
+
) : null}
|
|
339
|
+
<button type="button" className="btn is-danger" disabled={locked} onClick={() => store.deleteStoryboardItems([id])}>
|
|
340
|
+
Delete
|
|
341
|
+
</button>
|
|
342
|
+
</InspectorRow>
|
|
343
|
+
</InspectorSection>
|
|
344
|
+
{/* ── MORE ──────────────────────────────────────────────────────
|
|
345
|
+
COLLAPSED BY DEFAULT, held by the `referenceMoreOpen` view pref so
|
|
346
|
+
an author who works in these rows keeps them open. Everything in
|
|
347
|
+
here is real and none of it is what this panel is opened to
|
|
348
|
+
decide.
|
|
349
|
+
|
|
350
|
+
DELETE STAYS OUT OF THE FOLD, above this. A destructive verb behind
|
|
351
|
+
a disclosure is a verb an author cannot find. */}
|
|
352
|
+
{more ? (
|
|
353
|
+
<InspectorSection
|
|
354
|
+
title="More"
|
|
355
|
+
collapsed={!moreOpen}
|
|
356
|
+
onCollapsedChange={(collapsed) => store.setReferenceMoreOpen(!collapsed)}
|
|
357
|
+
>
|
|
358
|
+
{item.type === "asset" && isVideo ? (
|
|
359
|
+
<>
|
|
360
|
+
<InspectorRow>
|
|
361
|
+
<FieldLabels value="compact">
|
|
362
|
+
<NumberField
|
|
363
|
+
value={frame}
|
|
364
|
+
label="Frame"
|
|
365
|
+
ariaLabel="Frame, video"
|
|
366
|
+
min={0}
|
|
367
|
+
{...(frameMax === undefined ? {} : { max: frameMax })}
|
|
368
|
+
step={1}
|
|
369
|
+
onCommit={(next) => {
|
|
370
|
+
const at = wholeAtLeast(next, 0);
|
|
371
|
+
if (at !== null) store.updateReference(id, { frame: at });
|
|
372
|
+
}}
|
|
373
|
+
onScrubStart={frameScrub.start}
|
|
374
|
+
onScrub={frameScrub.move}
|
|
375
|
+
onScrubEnd={frameScrub.end}
|
|
376
|
+
/>
|
|
377
|
+
</FieldLabels>
|
|
378
|
+
</InspectorRow>
|
|
379
|
+
<ReadoutRow label="Timecode">{timecode(frame, doc.fps)}</ReadoutRow>
|
|
380
|
+
</>
|
|
381
|
+
) : null}
|
|
382
|
+
{item.type === "asset" && item.source !== undefined ? (
|
|
383
|
+
<ReadoutRow label="Source" prose>
|
|
384
|
+
{item.source.asset !== undefined
|
|
385
|
+
? `Still from a video at frame ${item.source.frame}`
|
|
386
|
+
: `Captured from this Project at frame ${item.source.frame}`}
|
|
387
|
+
</ReadoutRow>
|
|
388
|
+
) : null}
|
|
389
|
+
{/* THE README, AS PLAIN TEXT. A `<pre>` and not rendered markdown:
|
|
390
|
+
the docs are the agent's reading material, quoted here so an
|
|
391
|
+
author can see what the model will be told, and a second
|
|
392
|
+
markdown renderer in this chrome would be a second answer about
|
|
393
|
+
how that text looks. */}
|
|
394
|
+
{item.type === "library" ? (
|
|
395
|
+
detail === undefined ? (
|
|
396
|
+
<ReadoutRow label="Docs" prose>
|
|
397
|
+
{libraryMissing ? "No docs: this build does not ship the item." : "Loading the item's docs…"}
|
|
398
|
+
</ReadoutRow>
|
|
399
|
+
) : (
|
|
400
|
+
<InspectorRow label="Docs" align="start" className="insp-readout">
|
|
401
|
+
<pre className="insp-docs">{detail.docs}</pre>
|
|
402
|
+
</InspectorRow>
|
|
403
|
+
)
|
|
404
|
+
) : null}
|
|
405
|
+
</InspectorSection>
|
|
406
|
+
) : null}
|
|
407
|
+
</>
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const titleCase = (text: string): string => text.charAt(0).toUpperCase() + text.slice(1);
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* WHAT AN ELEMENT CARD NAMES, kind by kind. Every control writes through
|
|
415
|
+
* `updateReference`, whose patch keys are the schema's (`PATCH_KEYS`), and
|
|
416
|
+
* writes null for a quiet default so an untouched card carries no keys. A
|
|
417
|
+
* value chosen again is the same document there, so a re-pick writes nothing.
|
|
418
|
+
*/
|
|
419
|
+
function ElementRows({ doc, item }: { doc: Doc3D; item: ReferenceItem3D }) {
|
|
420
|
+
const store = useStore();
|
|
421
|
+
const id = item.id;
|
|
422
|
+
const fileRef = useRef<HTMLInputElement | null>(null);
|
|
423
|
+
const [busy, setBusy] = useState(false);
|
|
424
|
+
const locked = useLocked();
|
|
425
|
+
// The drag halves of the two number rows below, by key.
|
|
426
|
+
const lengthScrub = useScrub((d, raw) => {
|
|
427
|
+
const durationFrames = wholeAtLeast(raw, 1);
|
|
428
|
+
return durationFrames === null ? d : updateReference(d, id, { durationFrames });
|
|
429
|
+
});
|
|
430
|
+
const hitScrub = useScrub((d, raw) => {
|
|
431
|
+
const ms = wholeAtLeast(raw, 0);
|
|
432
|
+
return ms === null ? d : updateReference(d, id, { hitMs: ms === 0 ? null : ms });
|
|
433
|
+
});
|
|
434
|
+
switch (item.type) {
|
|
435
|
+
case "text":
|
|
436
|
+
return (
|
|
437
|
+
<InspectorRow label="Copy" align="start">
|
|
438
|
+
<TextField
|
|
439
|
+
multiline
|
|
440
|
+
value={item.copy}
|
|
441
|
+
ariaLabel="Copy"
|
|
442
|
+
onCommit={(copy) => {
|
|
443
|
+
const next = copy.trim();
|
|
444
|
+
if (next.length > 0 && next !== item.copy) store.updateReference(id, { copy: next });
|
|
445
|
+
}}
|
|
446
|
+
/>
|
|
447
|
+
</InspectorRow>
|
|
448
|
+
);
|
|
449
|
+
case "transition": {
|
|
450
|
+
const specs = Object.values(glPresetSpecs);
|
|
451
|
+
const known = specs.some((spec) => spec.id === item.kind);
|
|
452
|
+
return (
|
|
453
|
+
<>
|
|
454
|
+
<InspectorRow label="Kind">
|
|
455
|
+
<Combobox
|
|
456
|
+
options={[
|
|
457
|
+
...specs.map((spec) => ({ value: spec.id, label: spec.label })),
|
|
458
|
+
...(known ? [] : [{ value: item.kind, label: `${item.kind} (unknown)` }]),
|
|
459
|
+
]}
|
|
460
|
+
value={item.kind}
|
|
461
|
+
ariaLabel="Transition"
|
|
462
|
+
onChange={(kind) => store.updateReference(id, { kind })}
|
|
463
|
+
/>
|
|
464
|
+
</InspectorRow>
|
|
465
|
+
<InspectorRow>
|
|
466
|
+
<FieldLabels value="compact">
|
|
467
|
+
<NumberField
|
|
468
|
+
// An absent length is the preset's own, so the field shows the
|
|
469
|
+
// dash rather than a 0 its own minimum refuses.
|
|
470
|
+
value={item.durationFrames ?? Number.NaN}
|
|
471
|
+
label="Length"
|
|
472
|
+
ariaLabel="Length, transition frames"
|
|
473
|
+
min={1}
|
|
474
|
+
step={1}
|
|
475
|
+
unit="f"
|
|
476
|
+
onCommit={(frames) => {
|
|
477
|
+
const durationFrames = wholeAtLeast(frames, 1);
|
|
478
|
+
if (durationFrames !== null) store.updateReference(id, { durationFrames });
|
|
479
|
+
}}
|
|
480
|
+
onScrubStart={lengthScrub.start}
|
|
481
|
+
onScrub={lengthScrub.move}
|
|
482
|
+
onScrubEnd={lengthScrub.end}
|
|
483
|
+
/>
|
|
484
|
+
</FieldLabels>
|
|
485
|
+
</InspectorRow>
|
|
486
|
+
</>
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
case "sound": {
|
|
490
|
+
const asset = item.asset === undefined ? undefined : doc.assets[item.asset];
|
|
491
|
+
const pick = (file: File): void => {
|
|
492
|
+
setBusy(true);
|
|
493
|
+
void store.setSoundFile(id, file).finally(() => setBusy(false));
|
|
494
|
+
};
|
|
495
|
+
return (
|
|
496
|
+
<>
|
|
497
|
+
<InspectorRow label="Role">
|
|
498
|
+
<SegmentedControl
|
|
499
|
+
options={SOUND_ROLES.map((value) => ({ value, label: value === "sfx" ? "Effect" : titleCase(value) }))}
|
|
500
|
+
value={item.role}
|
|
501
|
+
ariaLabel="Role"
|
|
502
|
+
onChange={(role) => store.updateReference(id, { role: role as typeof item.role })}
|
|
503
|
+
/>
|
|
504
|
+
</InspectorRow>
|
|
505
|
+
<InspectorRow label="File" className="insp-file-row">
|
|
506
|
+
<span className="insp-dim is-text" title={asset?.path}>
|
|
507
|
+
{item.asset === undefined ? "No file yet" : asset === undefined ? "File missing" : asset.path.replace(/^[0-9a-f]{8}-/u, "")}
|
|
508
|
+
</span>
|
|
509
|
+
<button type="button" className="btn" disabled={busy || locked} onClick={() => fileRef.current?.click()}>
|
|
510
|
+
{item.asset === undefined ? "Choose file…" : "Replace…"}
|
|
511
|
+
</button>
|
|
512
|
+
{item.asset === undefined ? null : (
|
|
513
|
+
<button
|
|
514
|
+
type="button"
|
|
515
|
+
className="btn"
|
|
516
|
+
disabled={locked}
|
|
517
|
+
title="Back to a named need: the card keeps its role and loses its file and hit"
|
|
518
|
+
onClick={() => store.updateReference(id, { asset: null })}
|
|
519
|
+
>
|
|
520
|
+
Clear
|
|
521
|
+
</button>
|
|
522
|
+
)}
|
|
523
|
+
<input
|
|
524
|
+
ref={fileRef}
|
|
525
|
+
type="file"
|
|
526
|
+
hidden
|
|
527
|
+
accept={AUDIO_ACCEPT_ATTRIBUTE}
|
|
528
|
+
onChange={(event) => {
|
|
529
|
+
const file = event.currentTarget.files?.[0];
|
|
530
|
+
event.currentTarget.value = "";
|
|
531
|
+
if (file !== undefined) pick(file);
|
|
532
|
+
}}
|
|
533
|
+
/>
|
|
534
|
+
</InspectorRow>
|
|
535
|
+
{item.asset === undefined ? null : (
|
|
536
|
+
<InspectorRow>
|
|
537
|
+
<FieldLabels value="compact">
|
|
538
|
+
<NumberField
|
|
539
|
+
value={item.hitMs ?? 0}
|
|
540
|
+
label="Hit"
|
|
541
|
+
ariaLabel="Hit, where the sound lands in milliseconds"
|
|
542
|
+
min={0}
|
|
543
|
+
step={10}
|
|
544
|
+
unit="ms"
|
|
545
|
+
onCommit={(ms) => {
|
|
546
|
+
const next = wholeAtLeast(ms, 0);
|
|
547
|
+
if (next !== null) store.updateReference(id, { hitMs: next === 0 ? null : next });
|
|
548
|
+
}}
|
|
549
|
+
onScrubStart={hitScrub.start}
|
|
550
|
+
onScrub={hitScrub.move}
|
|
551
|
+
onScrubEnd={hitScrub.end}
|
|
552
|
+
/>
|
|
553
|
+
</FieldLabels>
|
|
554
|
+
</InspectorRow>
|
|
555
|
+
)}
|
|
556
|
+
</>
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
case "native": {
|
|
560
|
+
const variants =
|
|
561
|
+
item.kind === "mesh" ? MESH_PRIMITIVE_KINDS : item.kind === "device" ? DEVICE_PRESET_IDS : null;
|
|
562
|
+
return (
|
|
563
|
+
<>
|
|
564
|
+
<InspectorRow label="Kind">
|
|
565
|
+
<Combobox
|
|
566
|
+
options={NATIVE_LAYER_KINDS.map((kind) => ({ value: kind, label: kind === "html" ? "Html snippet" : titleCase(kind) }))}
|
|
567
|
+
value={item.kind}
|
|
568
|
+
ariaLabel="Layer kind"
|
|
569
|
+
// A variant belongs to ONE kind, so a kind change drops it, and
|
|
570
|
+
// only a change: the kind chosen again keeps its Shape or Device.
|
|
571
|
+
onChange={(kind) => {
|
|
572
|
+
if (kind !== item.kind) store.updateReference(id, { kind, variant: null });
|
|
573
|
+
}}
|
|
574
|
+
/>
|
|
575
|
+
</InspectorRow>
|
|
576
|
+
{variants === null ? null : (
|
|
577
|
+
<InspectorRow label={item.kind === "mesh" ? "Shape" : "Device"}>
|
|
578
|
+
<Combobox
|
|
579
|
+
options={[{ value: "", label: "Default" }, ...variants.map((value) => ({ value, label: titleCase(value) }))]}
|
|
580
|
+
value={item.variant ?? ""}
|
|
581
|
+
ariaLabel="Variant"
|
|
582
|
+
placeholder="Default"
|
|
583
|
+
onChange={(variant) => store.updateReference(id, { variant: variant === "" ? null : variant })}
|
|
584
|
+
/>
|
|
585
|
+
</InspectorRow>
|
|
586
|
+
)}
|
|
587
|
+
</>
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
default:
|
|
591
|
+
return null;
|
|
592
|
+
}
|
|
593
|
+
}
|