@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.
Files changed (432) hide show
  1. package/dist/.vite/manifest.json +382 -0
  2. package/dist/assets/AgentPanel-CQejLbiX.js +2 -0
  3. package/dist/assets/AgentPanel-DJEphah0.css +1 -0
  4. package/dist/assets/AgentQuestionDialog-BqkD0kXF.js +1 -0
  5. package/dist/assets/CodeStudio-Dv4ihHpz.js +23 -0
  6. package/dist/assets/CommentsPanel-B4yhhT1T.js +1 -0
  7. package/dist/assets/ComponentLibraryRail-Ch_dsAru.js +1 -0
  8. package/dist/assets/ComponentStage-BRhRotyH.js +1 -0
  9. package/dist/assets/CurvePane-BjFVabKX.css +1 -0
  10. package/dist/assets/CurvePane-R22WzllJ.js +1 -0
  11. package/dist/assets/ExportDialog-CWLQWTmG.js +2 -0
  12. package/dist/assets/FontPicker-DWKaYL7F.js +1 -0
  13. package/dist/assets/FontPicker-v0IOIArM.css +1 -0
  14. package/dist/assets/GenerateDrawer-Bh3SqDKt.js +2 -0
  15. package/dist/assets/InsertDrawer-Ce1fod1L.js +1 -0
  16. package/dist/assets/LibraryBrowser-D9sEGz5w.js +2 -0
  17. package/dist/assets/MakeItYoursSection-CMO4319_.js +2 -0
  18. package/dist/assets/MaterialGraphCanvas-BFzl4wWR.js +23 -0
  19. package/dist/assets/MaterialGraphCanvas-BIUD59ik.css +1 -0
  20. package/dist/assets/MaterialWorkspace-CqTWqaRA.js +14 -0
  21. package/dist/assets/PreferencesDialog-CBf9_OoD.js +1 -0
  22. package/dist/assets/PresetsSection-CUEaoCVU.js +1 -0
  23. package/dist/assets/SoundHistory-BeS8EW1h.js +1 -0
  24. package/dist/assets/SoundMode-BmcZru3i.js +3 -0
  25. package/dist/assets/StockSounds-DdAUGRYK.js +1 -0
  26. package/dist/assets/TemplateFieldSection-CaeXpLFo.js +1 -0
  27. package/dist/assets/VersionHistoryPanel-CxG6XhNP.js +1 -0
  28. package/dist/assets/board-B88EPuLO.css +1 -0
  29. package/dist/assets/board-CL-he7SL.js +3 -0
  30. package/dist/assets/components-0oOSPN0l.js +1 -0
  31. package/dist/assets/googleFontRanges-gp32wJMo.js +1 -0
  32. package/dist/assets/googleFonts-BNon6M7X.js +1 -0
  33. package/dist/assets/iconsAndAliases-DL7gXP5j.js +1863 -0
  34. package/dist/assets/index-4F5NQmI8.css +1 -0
  35. package/dist/assets/index-BGHQGV5z.js +117 -0
  36. package/dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  37. package/dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  38. package/dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  39. package/dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  40. package/dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  41. package/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  42. package/dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  43. package/dist/assets/libraryModel-CpIwfFha.js +1 -0
  44. package/dist/assets/lucide-6iK64tTB.js +9319 -0
  45. package/dist/assets/motionStamp-CH-Hew4E.js +1 -0
  46. package/dist/assets/takeMeasure-Tdg0TxEi.js +1 -0
  47. package/dist/assets/webmcp-BsB9gxWC.js +2 -0
  48. package/dist/index.html +34 -3
  49. package/package.json +12 -9
  50. package/src/addFamilies.ts +66 -0
  51. package/src/api.ts +1631 -55
  52. package/src/app/App.tsx +977 -198
  53. package/src/app/lazyPanel.tsx +137 -0
  54. package/src/app/lazySurfaces.tsx +203 -0
  55. package/src/audio/index.tsx +41 -10
  56. package/src/audio/meter.ts +485 -0
  57. package/src/audio/meterMath.ts +273 -0
  58. package/src/audio/meterStore.ts +155 -0
  59. package/src/audio/offlineMix.ts +289 -0
  60. package/src/audio/preview.ts +928 -118
  61. package/src/bridge.ts +15 -5
  62. package/src/bridgeTypes.ts +1611 -36
  63. package/src/channels.ts +17 -32
  64. package/src/fonts/googleFonts.ts +4 -0
  65. package/src/hostApi.ts +174 -0
  66. package/src/icons.tsx +770 -0
  67. package/src/layerWords.ts +61 -0
  68. package/src/main.tsx +56 -4
  69. package/src/panels/ResizeHandle.tsx +33 -43
  70. package/src/panels/agent/AgentDots.tsx +36 -0
  71. package/src/panels/agent/AgentPanel.tsx +119 -43
  72. package/src/panels/agent/AgentQuestionDialog.tsx +202 -0
  73. package/src/panels/agent/agent.css +113 -97
  74. package/src/panels/agent/agentGate.ts +35 -0
  75. package/src/panels/code/CodeDefaultsPanel.tsx +345 -0
  76. package/src/panels/code/CodeStudio.tsx +373 -0
  77. package/src/panels/code/FileTree.tsx +265 -0
  78. package/src/panels/code/codeBufferGuard.ts +52 -0
  79. package/src/panels/code/codeParts.tsx +321 -0
  80. package/src/panels/comments/CommentComposer.tsx +239 -0
  81. package/src/panels/comments/CommentThread.tsx +346 -0
  82. package/src/panels/comments/CommentsPanel.tsx +336 -0
  83. package/src/panels/comments/InboxButton.tsx +131 -0
  84. package/src/panels/comments/MentionMenu.tsx +98 -0
  85. package/src/panels/comments/parts.tsx +171 -0
  86. package/src/panels/export/ExportDialog.tsx +919 -96
  87. package/src/panels/export/ExportScrim.tsx +57 -0
  88. package/src/panels/files/AssetsTab.tsx +656 -0
  89. package/src/panels/files/FilePanel.tsx +1466 -216
  90. package/src/panels/files/LayerMarks.tsx +40 -0
  91. package/src/panels/files/LeftColumn.tsx +37 -0
  92. package/src/panels/files/McpSection.tsx +690 -47
  93. package/src/panels/files/MissingAssetsNotice.tsx +60 -0
  94. package/src/panels/files/assetDrag.ts +79 -0
  95. package/src/panels/files/resourceParts.tsx +255 -0
  96. package/src/panels/fonts/FontPicker.tsx +762 -0
  97. package/src/panels/fonts/faceCache.ts +207 -0
  98. package/src/panels/fonts/fontPicker.css +271 -0
  99. package/src/panels/fonts/pickerModel.ts +265 -0
  100. package/src/panels/fonts/pickerRequest.ts +46 -0
  101. package/src/panels/header/AccountAvatar.tsx +76 -0
  102. package/src/panels/header/AgentChip.tsx +77 -0
  103. package/src/panels/header/AppMenu.tsx +213 -0
  104. package/src/panels/header/Header.tsx +564 -84
  105. package/src/panels/header/HistoryControls.tsx +31 -5
  106. package/src/panels/header/PresenceStack.tsx +329 -0
  107. package/src/panels/header/ProjectTitle.tsx +232 -0
  108. package/src/panels/header/ShareButton.tsx +59 -0
  109. package/src/panels/header/StatusBadges.tsx +358 -27
  110. package/src/panels/header/SyncDeletedDialog.tsx +88 -0
  111. package/src/panels/header/ZoomControls.tsx +46 -15
  112. package/src/panels/header/agentHandoff.ts +52 -0
  113. package/src/panels/header/leave.ts +26 -0
  114. package/src/panels/help/HelpSection.tsx +189 -163
  115. package/src/panels/insert/InsertDrawer.tsx +723 -0
  116. package/src/panels/insert/iconSet.ts +109 -0
  117. package/src/panels/inspector/ExposeDot.tsx +117 -0
  118. package/src/panels/inspector/FramingRows.tsx +314 -44
  119. package/src/panels/inspector/InspectorFooter.tsx +91 -0
  120. package/src/panels/inspector/InspectorHead.tsx +425 -0
  121. package/src/panels/inspector/InspectorPanel.tsx +408 -124
  122. package/src/panels/inspector/KeyframeDot.tsx +373 -0
  123. package/src/panels/inspector/KeyframeSection.tsx +257 -0
  124. package/src/panels/inspector/MarkerSection.tsx +55 -11
  125. package/src/panels/inspector/ParamRow.tsx +84 -53
  126. package/src/panels/inspector/RightColumn.tsx +152 -0
  127. package/src/panels/inspector/TimeSection.tsx +866 -0
  128. package/src/panels/inspector/animate/EaseControl.tsx +244 -0
  129. package/src/panels/inspector/animate/PresetsSection.tsx +135 -0
  130. package/src/panels/inspector/animate/ShotSection.tsx +562 -48
  131. package/src/panels/inspector/design/AlignRow.tsx +95 -31
  132. package/src/panels/inspector/design/AppearanceSection.tsx +118 -9
  133. package/src/panels/inspector/design/ClonerSection.tsx +323 -62
  134. package/src/panels/inspector/design/ComponentSection.tsx +50 -43
  135. package/src/panels/inspector/design/CornerSection.tsx +45 -14
  136. package/src/panels/inspector/design/DefinitionProps.tsx +315 -0
  137. package/src/panels/inspector/design/DefinitionSection.tsx +136 -0
  138. package/src/panels/inspector/design/DeviceSection.tsx +210 -0
  139. package/src/panels/inspector/design/FillSection.tsx +83 -51
  140. package/src/panels/inspector/design/FontField.tsx +196 -0
  141. package/src/panels/inspector/design/HtmlSection.tsx +23 -12
  142. package/src/panels/inspector/design/InstanceSection.tsx +373 -154
  143. package/src/panels/inspector/design/MaskSection.tsx +84 -0
  144. package/src/panels/inspector/design/MaterialSection.tsx +177 -0
  145. package/src/panels/inspector/design/MediaSection.tsx +273 -120
  146. package/src/panels/inspector/design/MeshSection.tsx +910 -82
  147. package/src/panels/inspector/design/PaintRows.tsx +550 -0
  148. package/src/panels/inspector/design/PlateStyleSection.tsx +177 -0
  149. package/src/panels/inspector/design/ShadowSection.tsx +221 -48
  150. package/src/panels/inspector/design/SplineFollowSection.tsx +235 -0
  151. package/src/panels/inspector/design/StrokeSection.tsx +228 -43
  152. package/src/panels/inspector/design/TemplateFieldSection.tsx +57 -0
  153. package/src/panels/inspector/design/TransformSection.tsx +244 -50
  154. package/src/panels/inspector/design/TypographySection.tsx +679 -110
  155. package/src/panels/inspector/layout.ts +295 -0
  156. package/src/panels/inspector/propValue.ts +199 -0
  157. package/src/panels/inspector/scene/CameraSection.tsx +232 -22
  158. package/src/panels/inspector/scene/EffectsSection.tsx +722 -71
  159. package/src/panels/inspector/scene/MakeItYoursSection.tsx +180 -0
  160. package/src/panels/inspector/scene/SceneDocSection.tsx +191 -0
  161. package/src/panels/inspector/scene/SceneSection.tsx +219 -44
  162. package/src/panels/inspector/scene/TransitionSection.tsx +523 -72
  163. package/src/panels/inspector/storyboard/StoryboardReferenceSection.tsx +593 -0
  164. package/src/panels/inspector/storyboard/VideoStill.tsx +120 -0
  165. package/src/panels/inspector/timeModel.ts +190 -0
  166. package/src/panels/inspector/useDocWrite.ts +438 -146
  167. package/src/panels/library/LibraryBrowser.tsx +435 -0
  168. package/src/panels/library/LibraryGrid.tsx +190 -0
  169. package/src/panels/library/LibraryPreviewPanel.tsx +349 -0
  170. package/src/panels/library/LibraryRail.tsx +84 -0
  171. package/src/panels/library/LibrarySoundPanel.tsx +293 -0
  172. package/src/panels/library/SoundHistory.tsx +245 -0
  173. package/src/panels/library/StockSounds.tsx +390 -0
  174. package/src/panels/library/libraryModel.ts +147 -0
  175. package/src/panels/library/stockSearch.ts +77 -0
  176. package/src/panels/maskMarks.tsx +117 -0
  177. package/src/panels/material/MaterialCommentNode.tsx +54 -0
  178. package/src/panels/material/MaterialGraphCanvas.tsx +861 -0
  179. package/src/panels/material/MaterialGraphMenu.tsx +45 -0
  180. package/src/panels/material/MaterialGroupNode.tsx +56 -0
  181. package/src/panels/material/MaterialLibrary.tsx +253 -0
  182. package/src/panels/material/MaterialNode.tsx +453 -0
  183. package/src/panels/material/MaterialNodePalette.tsx +349 -0
  184. package/src/panels/material/MaterialParameterControls.tsx +525 -0
  185. package/src/panels/material/MaterialRerouteNode.tsx +42 -0
  186. package/src/panels/material/MaterialWorkspace.tsx +501 -0
  187. package/src/panels/material/NodePreview.tsx +70 -0
  188. package/src/panels/material/flowModel.ts +441 -0
  189. package/src/panels/material/parameterValues.ts +231 -0
  190. package/src/panels/material/previewScheduler.ts +235 -0
  191. package/src/panels/material/reactFlow.css +6 -0
  192. package/src/panels/material/socketGlyph.ts +85 -0
  193. package/src/panels/material/viewportMemory.ts +58 -0
  194. package/src/panels/preferences/PreferencesDialog.tsx +215 -0
  195. package/src/panels/share/ShareComponentDialog.tsx +247 -0
  196. package/src/panels/stage/StageMenu.tsx +35 -5
  197. package/src/panels/stage/StagePanel.tsx +338 -23
  198. package/src/panels/stage/cellSlots.tsx +70 -0
  199. package/src/panels/storyboard/BoardCanvas.tsx +739 -0
  200. package/src/panels/storyboard/BoardCursors.tsx +158 -0
  201. package/src/panels/storyboard/BoardDropDialog.tsx +161 -0
  202. package/src/panels/storyboard/BoardPlan.tsx +42 -0
  203. package/src/panels/storyboard/ComponentSheet.tsx +187 -0
  204. package/src/panels/storyboard/ComponentStage.tsx +235 -0
  205. package/src/panels/storyboard/MiniSketch.tsx +173 -0
  206. package/src/panels/storyboard/PartPicker.tsx +64 -0
  207. package/src/panels/storyboard/PlanPanel.tsx +617 -0
  208. package/src/panels/storyboard/ReferencePreview.tsx +217 -0
  209. package/src/panels/storyboard/ShotBrief.tsx +360 -0
  210. package/src/panels/storyboard/ShotCard.tsx +251 -0
  211. package/src/panels/storyboard/StagePreview.tsx +348 -0
  212. package/src/panels/storyboard/StillThumbs.tsx +162 -0
  213. package/src/panels/storyboard/StoryboardView.tsx +79 -0
  214. package/src/panels/storyboard/board.css +1065 -0
  215. package/src/panels/storyboard/board.ts +12 -0
  216. package/src/panels/storyboard/boardClipboard.ts +111 -0
  217. package/src/panels/storyboard/boardOrder.ts +68 -0
  218. package/src/panels/storyboard/boardRows.tsx +425 -0
  219. package/src/panels/storyboard/liveCap.ts +90 -0
  220. package/src/panels/storyboard/plan.css +295 -0
  221. package/src/panels/storyboard/posterCache.ts +133 -0
  222. package/src/panels/storyboard/shotboard/ComponentPicker.tsx +373 -0
  223. package/src/panels/storyboard/shotboard/ImagePicker.tsx +145 -0
  224. package/src/panels/storyboard/shotboard/ShotBoard.tsx +292 -0
  225. package/src/panels/storyboard/shotboard/SketchCanvas.tsx +443 -0
  226. package/src/panels/storyboard/shotboard/SketchInspector.tsx +471 -0
  227. package/src/panels/storyboard/shotboard/SketchItem.tsx +240 -0
  228. package/src/panels/storyboard/shotboard/SketchLayers.tsx +130 -0
  229. package/src/panels/storyboard/shotboard/SketchPlay.tsx +108 -0
  230. package/src/panels/storyboard/shotboard/SketchStrip.tsx +178 -0
  231. package/src/panels/storyboard/shotboard/SketchToolFooter.tsx +99 -0
  232. package/src/panels/storyboard/shotboard/sketch.css +1392 -0
  233. package/src/panels/storyboard/shotboard/sketchModel.ts +219 -0
  234. package/src/panels/storyboard/storyboardDrop.ts +164 -0
  235. package/src/panels/studio/ComponentLibraryRail.tsx +346 -0
  236. package/src/panels/studio/ComponentSidePanel.tsx +355 -0
  237. package/src/panels/studio/ComponentStudio.tsx +243 -0
  238. package/src/panels/studio/ComponentsHome.tsx +318 -0
  239. package/src/panels/studio/ComponentsPreview.tsx +179 -0
  240. package/src/panels/studio/EveryUse.tsx +244 -0
  241. package/src/panels/studio/ThisUsePanel.tsx +679 -0
  242. package/src/panels/studio/componentParts.tsx +341 -0
  243. package/src/panels/studio/components.ts +6 -0
  244. package/src/panels/studio/newCodeComponent.ts +66 -0
  245. package/src/panels/timeline/AudioFxButton.tsx +290 -0
  246. package/src/panels/timeline/AudioLane.tsx +674 -85
  247. package/src/panels/timeline/BlockRow.tsx +154 -85
  248. package/src/panels/timeline/ChannelRow.tsx +378 -129
  249. package/src/panels/timeline/CurvePane.tsx +508 -0
  250. package/src/panels/timeline/Filmstrip.tsx +361 -0
  251. package/src/panels/timeline/GenerateDrawer.tsx +407 -0
  252. package/src/panels/timeline/KeyStretch.tsx +115 -0
  253. package/src/panels/timeline/LifespanRow.tsx +730 -47
  254. package/src/panels/timeline/MarkerLane.tsx +46 -8
  255. package/src/panels/timeline/PlayButton.tsx +91 -0
  256. package/src/panels/timeline/PropertyPicker.tsx +254 -0
  257. package/src/panels/timeline/ShotRow.tsx +400 -0
  258. package/src/panels/timeline/SoundMode.tsx +1406 -0
  259. package/src/panels/timeline/TimelineDock.tsx +2338 -272
  260. package/src/panels/timeline/TransportVolume.tsx +163 -0
  261. package/src/panels/timeline/beatRuler.ts +74 -0
  262. package/src/panels/timeline/curveModel.ts +500 -0
  263. package/src/panels/timeline/duckUnderVoice.ts +68 -0
  264. package/src/panels/timeline/keyframeMenu.ts +138 -0
  265. package/src/panels/timeline/labelWidth.ts +49 -0
  266. package/src/panels/timeline/marquee.ts +155 -0
  267. package/src/panels/timeline/model.ts +1860 -199
  268. package/src/panels/timeline/snap.ts +125 -43
  269. package/src/panels/timeline/staggerPreview.tsx +92 -0
  270. package/src/panels/timeline/takeMeasure.ts +72 -0
  271. package/src/panels/timeline/useLive.ts +48 -0
  272. package/src/panels/timeline/viewport.ts +234 -0
  273. package/src/panels/toolbar/BackChip.tsx +116 -0
  274. package/src/panels/toolbar/CameraViewBar.tsx +118 -49
  275. package/src/panels/toolbar/CanvasBar.tsx +117 -0
  276. package/src/panels/toolbar/InsertButton.tsx +38 -0
  277. package/src/panels/toolbar/IsolationTrail.tsx +156 -0
  278. package/src/panels/toolbar/PanelToggles.tsx +86 -0
  279. package/src/panels/toolbar/ShadingBar.tsx +119 -26
  280. package/src/panels/toolbar/ToolDockBar.tsx +329 -80
  281. package/src/panels/toolbar/ToolFooter.tsx +102 -0
  282. package/src/panels/toolbar/ViewModeBar.tsx +247 -38
  283. package/src/panels/toolbar/WorkPlaneBar.tsx +94 -0
  284. package/src/panels/toolbar/useAddRows.tsx +326 -0
  285. package/src/panels/toolbar/useDismiss.ts +122 -0
  286. package/src/panels/versions/VersionHistoryPanel.tsx +274 -0
  287. package/src/panels/versions/versionModel.ts +103 -0
  288. package/src/panels/virtualWindow.ts +271 -0
  289. package/src/shotTokens.css +151 -60
  290. package/src/stage/FrustumGizmo.tsx +504 -84
  291. package/src/stage/GridPlane.tsx +225 -16
  292. package/src/stage/NodePreviews.tsx +628 -0
  293. package/src/stage/PerfHud.tsx +437 -47
  294. package/src/stage/SplitRenderer.tsx +816 -169
  295. package/src/stage/StageApp.tsx +4274 -486
  296. package/src/stage/StageRootBoundary.tsx +114 -0
  297. package/src/stage/StageTools.tsx +651 -151
  298. package/src/stage/TransformGizmo.tsx +696 -0
  299. package/src/stage/adaptivePresentation.ts +145 -0
  300. package/src/stage/bridgeClient.ts +2522 -41
  301. package/src/stage/exportWorker.ts +9 -0
  302. package/src/stage/feed.ts +305 -14
  303. package/src/stage/fontPreview.ts +176 -0
  304. package/src/stage/frustumGeometry.ts +319 -1
  305. package/src/stage/furnitureTokens.ts +33 -0
  306. package/src/stage/gizmoMath.ts +508 -16
  307. package/src/stage/gpuTimer.ts +276 -0
  308. package/src/stage/instanceModules.ts +194 -33
  309. package/src/stage/interactions/move.ts +24 -5
  310. package/src/stage/isolation.ts +291 -33
  311. package/src/stage/jsSelfProfiler.ts +325 -0
  312. package/src/stage/main.tsx +116 -16
  313. package/src/stage/modalState.ts +222 -23
  314. package/src/stage/moduleEpoch.ts +60 -0
  315. package/src/stage/motionPathStage.ts +279 -0
  316. package/src/stage/motionPreview.ts +74 -0
  317. package/src/stage/overlays/Overlays.tsx +1112 -159
  318. package/src/stage/overlays/Rulers.tsx +495 -0
  319. package/src/stage/panes.ts +159 -10
  320. package/src/stage/project.ts +68 -3
  321. package/src/stage/renderScaleController.ts +730 -0
  322. package/src/stage/rulers.ts +129 -0
  323. package/src/stage/sceneExtent.ts +75 -0
  324. package/src/stage/shading.ts +20 -0
  325. package/src/stage/splineStage.ts +632 -0
  326. package/src/stage/stagePerformanceTelemetry.ts +717 -0
  327. package/src/stage/stageTheme.ts +36 -0
  328. package/src/stage/stageWarmup.ts +11 -0
  329. package/src/stage/textAutoSize.ts +124 -0
  330. package/src/stage/tier1Export.ts +641 -0
  331. package/src/stage/tokenColor.ts +14 -9
  332. package/src/stage/view.ts +56 -9
  333. package/src/stage/workingView.ts +277 -33
  334. package/src/state/accountPrefs.ts +261 -0
  335. package/src/state/agentActions.ts +173 -15
  336. package/src/state/agentActivity.ts +198 -0
  337. package/src/state/agentQuestion.ts +239 -0
  338. package/src/state/bootOpen.ts +42 -0
  339. package/src/state/cameraVerbs.ts +139 -0
  340. package/src/state/clientId.ts +6 -1
  341. package/src/state/comments.ts +1099 -0
  342. package/src/state/context.tsx +19 -1
  343. package/src/state/editorPrefs.ts +220 -0
  344. package/src/state/errorReports.ts +121 -0
  345. package/src/state/fieldWrite.ts +161 -0
  346. package/src/state/fontRecents.ts +70 -0
  347. package/src/state/fonts.ts +656 -0
  348. package/src/state/graphClipboard.ts +414 -0
  349. package/src/state/imageThumbs.ts +216 -0
  350. package/src/state/insert.ts +444 -67
  351. package/src/state/isolationTrail.ts +92 -0
  352. package/src/state/keyMoves.ts +134 -0
  353. package/src/state/keyframeClipboard.ts +177 -0
  354. package/src/state/keymap.ts +1153 -117
  355. package/src/state/layoutPrefs.ts +272 -0
  356. package/src/state/layouts.ts +205 -0
  357. package/src/state/measureMedia.ts +167 -0
  358. package/src/state/menu.ts +2341 -28
  359. package/src/state/motionStamp.ts +7 -0
  360. package/src/state/panelSize.ts +375 -5
  361. package/src/state/pendingChanges.ts +119 -0
  362. package/src/state/playHold.ts +78 -0
  363. package/src/state/playbackPreparation.ts +562 -0
  364. package/src/state/posterCapture.ts +242 -0
  365. package/src/state/presence.ts +254 -0
  366. package/src/state/projectComponents.ts +160 -0
  367. package/src/state/renderEvents.ts +298 -18
  368. package/src/state/runtimeErrors.ts +46 -0
  369. package/src/state/selection.ts +12 -0
  370. package/src/state/shortcuts.ts +1606 -0
  371. package/src/state/sketchGuide.ts +51 -0
  372. package/src/state/splineRefs.ts +87 -0
  373. package/src/state/stageHealth.ts +259 -0
  374. package/src/state/stageWatchdog.ts +47 -0
  375. package/src/state/stillStage.ts +330 -0
  376. package/src/state/stillThumbs.ts +474 -0
  377. package/src/state/store.ts +23591 -2982
  378. package/src/state/storyboardModel.ts +528 -0
  379. package/src/state/sync.ts +1257 -0
  380. package/src/state/syncCache.ts +159 -0
  381. package/src/state/triangles.ts +13 -0
  382. package/src/state/types.ts +1698 -55
  383. package/src/state/unsavedGuard.ts +49 -0
  384. package/src/state/viewMode.ts +200 -0
  385. package/src/state/webmcp.ts +1128 -0
  386. package/src/state/workspace.ts +1147 -0
  387. package/src/styles/assets-tab.css +304 -0
  388. package/src/styles/canvas.css +545 -0
  389. package/src/styles/comments.css +1435 -0
  390. package/src/styles/controls.css +162 -0
  391. package/src/styles/dialogs.css +390 -0
  392. package/src/styles/insert-drawer.css +586 -0
  393. package/src/styles/inspector-board.css +207 -0
  394. package/src/styles/inspector-object.css +486 -0
  395. package/src/styles/inspector-shot.css +252 -0
  396. package/src/styles/inspector.css +360 -0
  397. package/src/styles/left-column.css +1628 -0
  398. package/src/styles/library-preview.css +575 -0
  399. package/src/styles/library.css +512 -0
  400. package/src/styles/modes/code.css +569 -0
  401. package/src/styles/modes/component.css +1561 -0
  402. package/src/styles/modes/material.css +1201 -0
  403. package/src/styles/modes/storyboard.css +518 -0
  404. package/src/styles/share-component.css +49 -0
  405. package/src/styles/shell.css +653 -0
  406. package/src/styles/shot-brief.css +360 -0
  407. package/src/styles/states.css +76 -0
  408. package/src/styles/sync.css +380 -0
  409. package/src/styles/timeline-graph.css +384 -0
  410. package/src/styles/timeline-meters.css +89 -0
  411. package/src/styles/timeline-rows.css +1959 -0
  412. package/src/styles/timeline-sound.css +1003 -0
  413. package/src/styles/timeline.css +754 -0
  414. package/src/styles/tool-footer.css +525 -0
  415. package/src/styles/topbar.css +886 -0
  416. package/src/styles/versions.css +262 -0
  417. package/src/styles.css +72 -2921
  418. package/src/tools.ts +108 -23
  419. package/dist/assets/index-B7notge7.css +0 -1
  420. package/dist/assets/index-BBE6Ta9L.js +0 -52
  421. package/src/panels/files/icons.tsx +0 -118
  422. package/src/panels/header/DocSwitcher.tsx +0 -85
  423. package/src/panels/header/TransportBar.tsx +0 -86
  424. package/src/panels/inspector/animate/BlockTiming.tsx +0 -341
  425. package/src/panels/inspector/animate/DuringBlocks.tsx +0 -85
  426. package/src/panels/inspector/animate/InOutPresets.tsx +0 -57
  427. package/src/panels/inspector/animate/ResolvedChannels.tsx +0 -150
  428. package/src/panels/inspector/animate/useBlocks.ts +0 -43
  429. package/src/panels/material/MaterialPicker.tsx +0 -172
  430. package/src/panels/timeline/SceneStrip.tsx +0 -145
  431. package/src/panels/toolbar/AddMenu.tsx +0 -230
  432. package/src/stage/MoveGizmo.tsx +0 -411
@@ -0,0 +1,500 @@
1
+ // THE GRAPH EDITOR'S ADAPTER: shot tracks, seen through `TimelineModel`.
2
+ //
3
+ // ── WHY THERE IS NO SVG IN THIS LANE ────────────────────────────────────────
4
+ //
5
+ // `@dailies-studio/timeline`'s `CurveGraph` is a finished value-space curve
6
+ // editor — dense engine sampling so a spring's overshoot is real, keyframe
7
+ // drags in both axes, bezier handles in value space, ctrl+wheel zoom, one
8
+ // history scrub per drag — and it renders and gestures ENTIRELY through a
9
+ // `TimelineModel`. It was built for the motion editor and this lane simply
10
+ // never mounted it. So the work here is a MAPPING, and a second curve editor is
11
+ // not written.
12
+ //
13
+ // model.ts's header explains why the DOCK does not use `TimelineModel`: a bar
14
+ // lane is intervals and that contract is instants. A curve is instants, so the
15
+ // same argument points the other way here.
16
+ //
17
+ // ── THE THREE THINGS THE MAPPING HAS TO GET RIGHT ───────────────────────────
18
+ //
19
+ // FRAMES ARE CONTAINER-LOCAL. Keyframe frames are scene-local in the document
20
+ // and `CurveGraph` draws its own ruler from 0, so the curve lives in the
21
+ // container's own clock end to end. Only `setFrame` crosses back into
22
+ // master time, through `sceneStart` — THE prefix sum, never a second one.
23
+ // A VECTOR TRACK IS ONE TRACK. `transform.position` is a single vec3 track,
24
+ // so its components share keyframe FRAMES. They are drawn as sub-rows and
25
+ // each one writes the whole vector back with its own slot replaced; the
26
+ // shared frames are the honest drawing of what the document holds, and
27
+ // splitting them would be a schema change.
28
+ // A DRAG IS ONE SCRUB. `gesture` is the dock's own bracket
29
+ // (`beginBlockDrag` / `captureCurveOps` / `endBlockDrag`), so a curve drag
30
+ // is one undo entry and Escape restores the base — the same promise every
31
+ // other gesture in this dock makes.
32
+ import { keyframeAddrKey } from "@dailies-studio/timeline";
33
+ import type { FocusedCurve, KeyframeAddr, TimelineModel, TimelineRow } from "@dailies-studio/timeline";
34
+ import {
35
+ containerFrame,
36
+ homeOf,
37
+ layerChildren,
38
+ layerTrackablePath,
39
+ sceneStart,
40
+ sceneTrackablePath,
41
+ trackablePath,
42
+ } from "@dailies-studio/shot/doc";
43
+ import type { Doc3D, ShotTrack } from "@dailies-studio/shot/doc";
44
+ import type { Rational, TrackKind, Value } from "@dailies-studio/engine";
45
+ import { evaluateTrack } from "@dailies-studio/engine";
46
+ import type { CurveKeyRef, CurveOp, KeyframeSel } from "../../state/types.js";
47
+ import { frontFirst } from "./model.js";
48
+ import type { ShotEditorStore } from "../../state/store.js";
49
+
50
+ /** One curve's address: a track, and which component of it when it is a
51
+ * vector. The pane's focus and every row id are this. */
52
+ export interface CurveSubject {
53
+ containerId: string;
54
+ /** Null = the SHOT itself (its background and post stack). */
55
+ layerId: string | null;
56
+ path: string;
57
+ /** Which component of a vector track, or absent for a scalar. */
58
+ component?: number;
59
+ }
60
+
61
+ const SEP = "|";
62
+
63
+ /** `TimelineModel` row ids are OPAQUE to the shared components, so this lane
64
+ * gets to choose the encoding. A PIPE, because every part that goes into one
65
+ * is an id slug (sc_…, l3_…, cmp_…) or a dotted path, and none can contain it. */
66
+ export function curveRowId(s: CurveSubject): string {
67
+ return [s.containerId, s.layerId ?? "", s.path, s.component ?? ""].join(SEP);
68
+ }
69
+
70
+ export function parseCurveRowId(id: string): CurveSubject | null {
71
+ const [containerId, layerId, path, component] = id.split(SEP);
72
+ if (containerId === undefined || layerId === undefined || path === undefined) return null;
73
+ return {
74
+ containerId,
75
+ layerId: layerId === "" ? null : layerId,
76
+ path,
77
+ ...(component === undefined || component === "" ? {} : { component: Number(component) }),
78
+ };
79
+ }
80
+
81
+ export function sameSubject(a: CurveSubject | null, b: CurveSubject | null): boolean {
82
+ return a !== null && b !== null && curveRowId(a) === curveRowId(b);
83
+ }
84
+
85
+ /** The component labels a vector track's sub-rows carry. `transform.size` is
86
+ * width and height rather than x and y, which is what the inspector calls it. */
87
+ function componentNames(path: string, kind: TrackKind): readonly string[] {
88
+ if (kind === "vec2") return path === "transform.size" ? ["W", "H"] : ["X", "Y"];
89
+ if (kind === "vec3") return ["X", "Y", "Z"];
90
+ return [];
91
+ }
92
+
93
+ /** Is this kind drawable in VALUE SPACE? A colour and a boolean have no axis, so
94
+ * their rows stay dope rows: diamonds, no curve. */
95
+ function numericKind(kind: TrackKind): boolean {
96
+ return kind === "number" || kind === "vec2" || kind === "vec3";
97
+ }
98
+
99
+ /** The tracks of one subject, as rows — a vector expanded into its components,
100
+ * which is the only way a vec3 reaches a value-space curve at all. */
101
+ export function curveRowsOf(
102
+ doc: Doc3D,
103
+ containerId: string,
104
+ layerId: string | null,
105
+ ): Array<TimelineRow & { subject: CurveSubject }> {
106
+ const tracks = curveTracksOf(doc, containerId, layerId);
107
+ if (tracks === undefined) return [];
108
+ // The layer itself, for the LAYER-scoped lookup below: `instance.props.<key>`
109
+ // is typed by the component's contract, so a global lookup cannot label it or
110
+ // report its kind. Same `homeOf` route `tracksOf` takes.
111
+ const layer = layerId === null ? undefined : homeOf(doc, containerId)?.layersById[layerId];
112
+ const out: Array<TimelineRow & { subject: CurveSubject }> = [];
113
+ // Sorted by path so two layers with the same tracks list them the same way —
114
+ // `channelRows`' rule, for its reason: a `Record`'s own order is not one.
115
+ for (const path of Object.keys(tracks).sort()) {
116
+ const track = tracks[path]!;
117
+ const spec =
118
+ layerId === null
119
+ ? sceneTrackablePath(path)
120
+ : layer === undefined
121
+ ? trackablePath(path)
122
+ : layerTrackablePath(layer, path);
123
+ const label = spec?.label ?? path;
124
+ const kind = spec?.kind ?? track.kind;
125
+ const keyframes = track.keyframes.map((k) => ({
126
+ id: k.id,
127
+ frame: k.frame,
128
+ easeType: k.easeOut.type,
129
+ }));
130
+ const names = componentNames(path, kind);
131
+ if (names.length === 0) {
132
+ const subject: CurveSubject = { containerId, layerId, path };
133
+ out.push({ id: curveRowId(subject), label, depth: 0, numberTrack: numericKind(kind), keyframes, subject });
134
+ continue;
135
+ }
136
+ // The parent row is the TRACK — one row per component under it, because
137
+ // that is where the keyframes really live and a reader has to see that the
138
+ // frames are shared.
139
+ const parent: CurveSubject = { containerId, layerId, path };
140
+ out.push({ id: curveRowId(parent), label, depth: 0, numberTrack: false, keyframes, subject: parent });
141
+ names.forEach((name, component) => {
142
+ const subject: CurveSubject = { containerId, layerId, path, component };
143
+ out.push({
144
+ id: curveRowId(subject),
145
+ label: name,
146
+ depth: 1,
147
+ numberTrack: true,
148
+ keyframes,
149
+ subject,
150
+ });
151
+ });
152
+ }
153
+ return out;
154
+ }
155
+
156
+ /** The tracks of a curve subject. EXPORTED because the pane needs the real
157
+ * track — its kind, and which key is last — to build a keyframe menu, and a
158
+ * second lookup there would be a second spelling of the `homeOf` rule. */
159
+ export function curveTracksOf(
160
+ doc: Doc3D,
161
+ containerId: string,
162
+ layerId: string | null,
163
+ ): Record<string, ShotTrack> | undefined {
164
+ if (layerId === null) return doc.scenesById[containerId]?.tracks;
165
+ // THROUGH `homeOf`, which is the one function that reads a scene and a
166
+ // definition through the same shape — a local branch here would be a second
167
+ // copy of that rule, and the def arm spells its roots differently.
168
+ return homeOf(doc, containerId)?.layersById[layerId]?.tracks;
169
+ }
170
+
171
+ /** The number a curve draws for a value: the value itself, or one component of
172
+ * it. Non-numeric collapses to 0 — a row that reaches here is one the pane's
173
+ * `numberTrack` gate should not have focused. */
174
+ function numberOf(value: Value | undefined, component: number | undefined): number {
175
+ if (component !== undefined) return Array.isArray(value) ? Number(value[component] ?? 0) : 0;
176
+ return typeof value === "number" ? value : 0;
177
+ }
178
+
179
+ /**
180
+ * The value axis's unit, as a spread so an unknown unit leaves the field
181
+ * ABSENT (`exactOptionalPropertyTypes`).
182
+ *
183
+ * The doc's trackable paths carry no unit metadata, only a naming rule: every
184
+ * angle in degrees ends in `Deg` (`transform.rollDeg`, `mesh.primitive.arcDeg`,
185
+ * `splineFollow.bankDeg`, …). That suffix is the one unit this can say
186
+ * without guessing, and the inspector's own rows already label those "°".
187
+ * The keyframe inspector's Value field reads this same function.
188
+ */
189
+ export function unitOf(path: string): { unit: string } | Record<never, never> {
190
+ return path.endsWith("Deg") ? { unit: "°" } : {};
191
+ }
192
+
193
+ /**
194
+ * One subject's curve: its keys as numbers and THE ENGINE'S OWN SAMPLER, so the
195
+ * drawn curve and the rendered frame are one function. A local re-implementation
196
+ * would lose the spring's inherited boundary velocity, which is exactly the
197
+ * shape an author opens this panel to look at. Null when the track is gone or
198
+ * has no keys.
199
+ */
200
+ function curveOf(doc: Doc3D, subject: CurveSubject, fps: Rational): FocusedCurve | null {
201
+ const track = curveTracksOf(doc, subject.containerId, subject.layerId)?.[subject.path];
202
+ if (track === undefined || track.keyframes.length === 0) return null;
203
+ return {
204
+ rowId: curveRowId(subject),
205
+ keyframes: track.keyframes.map((k) => ({
206
+ id: k.id,
207
+ frame: k.frame,
208
+ value: numberOf(k.value, subject.component),
209
+ easeOut: k.easeOut,
210
+ })),
211
+ sample: (from, to, n) => {
212
+ const out: Array<{ frame: number; value: number }> = [];
213
+ const step = n <= 1 ? 0 : (to - from) / (n - 1);
214
+ for (let i = 0; i < n; i += 1) {
215
+ const f = from + step * i;
216
+ out.push({ frame: f, value: numberOf(evaluateTrack(track, f, fps), subject.component) });
217
+ }
218
+ return out;
219
+ },
220
+ };
221
+ }
222
+
223
+ /** The number a curve row reads at a CONTAINER-LOCAL frame, for the list's
224
+ * value column. Null when the track is gone or has no keys. */
225
+ export function curveValueAt(doc: Doc3D, subject: CurveSubject, localFrame: number, fps: Rational): number | null {
226
+ const track = curveTracksOf(doc, subject.containerId, subject.layerId)?.[subject.path];
227
+ if (track === undefined || track.keyframes.length === 0) return null;
228
+ return numberOf(evaluateTrack(track, localFrame, fps), subject.component);
229
+ }
230
+
231
+ /**
232
+ * Everything `CurveGraph` reads and writes, over one focused track.
233
+ *
234
+ * A PLAIN FUNCTION, not a hook: the pane holds the memo (it knows which of its
235
+ * inputs are identity-stable) and this stays testable without a renderer.
236
+ */
237
+ export function shotCurveModel(args: {
238
+ store: ShotEditorStore;
239
+ doc: Doc3D;
240
+ /** The container the rows belong to, and its own duration. */
241
+ containerId: string;
242
+ containerFrames: number;
243
+ /** The MASTER playhead. Converted to container-local here and nowhere else. */
244
+ frame: number;
245
+ fps: Rational;
246
+ pxPerFrame: number;
247
+ focus: CurveSubject | null;
248
+ rows: Array<TimelineRow & { subject: CurveSubject }>;
249
+ /** The WHOLE selection, not just its primary: the graph lights every key it
250
+ * holds, which is what a marquee or a shift-click has to produce. */
251
+ selected: readonly { path: string; frame: number; layerId: string | null; containerId: string }[];
252
+ /** Def-local clocks do not convert: a definition has no master position. */
253
+ defOpen: boolean;
254
+ /** The OTHER curves the author has asked to see beside the focused one
255
+ * (shift-click in the list). The focused subject is skipped if listed. */
256
+ visible?: readonly CurveSubject[];
257
+ /** Each row's list colour, by row id, so the graph draws a curve in the
258
+ * colour of its dot. */
259
+ colors?: ReadonlyMap<string, string>;
260
+ }): TimelineModel {
261
+ const { store, doc, containerId, fps, focus, rows } = args;
262
+ const track = focus === null ? undefined : curveTracksOf(doc, focus.containerId, focus.layerId)?.[focus.path];
263
+ const colorOf = (s: CurveSubject): { color: string } | Record<never, never> => {
264
+ const c = args.colors?.get(curveRowId(s));
265
+ return c === undefined ? {} : { color: c };
266
+ };
267
+ const curves = (args.visible ?? [])
268
+ .filter((s) => !sameSubject(s, focus))
269
+ .flatMap((s) => {
270
+ const c = curveOf(doc, s, fps);
271
+ return c === null ? [] : [{ ...c, ...colorOf(s) }];
272
+ });
273
+
274
+ const keyOf = (subject: CurveSubject, keyframeId: string): CurveKeyRef => ({
275
+ containerId: subject.containerId,
276
+ layerId: subject.layerId,
277
+ path: subject.path,
278
+ keyframeId,
279
+ ...(subject.component === undefined ? {} : { component: subject.component }),
280
+ });
281
+
282
+ /** A shared `KeyframeAddr` back into this lane's own address. Null when the
283
+ * row is not one of ours or the keyframe has gone. */
284
+ const refOf = (addr: KeyframeAddr): CurveKeyRef | null => {
285
+ const subject = parseCurveRowId(addr.rowId);
286
+ if (subject === null) return null;
287
+ return keyOf(subject, addr.keyframeId);
288
+ };
289
+
290
+ const focusedCurve = focus === null || track === undefined ? null : curveOf(doc, focus, fps);
291
+
292
+ // The SELECTION, mapped from the store's position address onto the id one the
293
+ // shared components use. The store keeps positions on purpose (a key can be
294
+ // replaced by a drag landing on its frame); this direction is a lookup, and
295
+ // the reverse — id to position — happens inside the capture against the base.
296
+ const selectedAddrs: KeyframeAddr[] = [];
297
+ if (focus !== null) {
298
+ for (const at of args.selected) {
299
+ const owner = curveTracksOf(doc, at.containerId, at.layerId)?.[at.path];
300
+ const key = owner?.keyframes.find((k) => k.frame === at.frame);
301
+ if (key === undefined) continue;
302
+ // Every row that draws this track — the parent and each component — shows
303
+ // the same keyframe, so the selection lights up on whichever is focused.
304
+ const subject: CurveSubject = {
305
+ containerId: at.containerId,
306
+ layerId: at.layerId,
307
+ path: at.path,
308
+ ...(focus.path === at.path && focus.component !== undefined ? { component: focus.component } : {}),
309
+ };
310
+ selectedAddrs.push({ rowId: curveRowId(subject), keyframeId: key.id });
311
+ }
312
+ }
313
+
314
+ return {
315
+ rows,
316
+ durationFrames: args.containerFrames,
317
+ fps,
318
+ frame: args.defOpen
319
+ ? args.frame
320
+ : containerFrame(doc, containerId, args.frame),
321
+ pxPerFrame: args.pxPerFrame,
322
+ // The dock's own zoom bounds, shared deliberately: the graph and the rows
323
+ // are two faces of one timeline and a second zoom range would make ⌘-wheel
324
+ // mean two different things in one panel.
325
+ pxPerFrameBounds: { min: 0.2, max: 60 },
326
+ selectedKeyframes: new Set(selectedAddrs.map(keyframeAddrKey)),
327
+ selectedAddrs,
328
+ curves,
329
+ focusedCurve:
330
+ focus === null || focusedCurve === null
331
+ ? null
332
+ : {
333
+ // Keys and the engine sampler (`curveOf`).
334
+ ...focusedCurve,
335
+ ...colorOf(focus),
336
+ ...unitOf(focus.path),
337
+ },
338
+
339
+ setFrame(next) {
340
+ // The graph's only caller is CurveGraph's `scrubTo`, a pointer drag on
341
+ // the ruler and the graph background, so it takes the clock exactly like
342
+ // the dock's ruler does.
343
+ store.pauseForScrub();
344
+ // BACK INTO MASTER TIME, through the one prefix sum. A definition has no
345
+ // master position at all, so it seeks its own clock.
346
+ if (args.defOpen) {
347
+ store.seekDef(next);
348
+ return;
349
+ }
350
+ store.seek(next + (sceneStart(doc, containerId) ?? 0));
351
+ },
352
+ setPxPerFrame(px) {
353
+ store.setDockPpf(px);
354
+ },
355
+ selectKeyframes(refs, mode = "set") {
356
+ // ID TO POSITION, here and only here. The shared components address a key
357
+ // by its stable id (a React key that moved mid-drag would remount the
358
+ // circle holding pointer capture); the store keeps positions, because a
359
+ // drag landing on an occupied frame REPLACES the key an id would still
360
+ // point at. This is the one seam between the two.
361
+ const at = refs.flatMap((addr) => {
362
+ const ref = refOf(addr);
363
+ if (ref === null) return [];
364
+ const owner = curveTracksOf(doc, ref.containerId, ref.layerId)?.[ref.path];
365
+ const key = owner?.keyframes.find((k) => k.id === ref.keyframeId);
366
+ return key === undefined
367
+ ? []
368
+ : [{ containerId: ref.containerId, layerId: ref.layerId, path: ref.path, frame: key.frame }];
369
+ });
370
+ if (at.length === 0) {
371
+ // An empty "set" is a deselect — a marquee that caught nothing. An
372
+ // empty add/toggle is not: it would clear a selection the author was
373
+ // extending.
374
+ if (mode === "set") store.selectKeyframe(null);
375
+ return;
376
+ }
377
+ store.focusScene(at[0]!.containerId);
378
+ // FOLDED IN ORDER, so the last one the gesture named ends up primary —
379
+ // which is what makes a shift-click read as "extend to here".
380
+ at.forEach((k, i) => store.selectKeyframes(k, i === 0 ? mode : "add"));
381
+ },
382
+ toggleKeyframe(rowId, frame) {
383
+ const subject = parseCurveRowId(rowId);
384
+ if (subject === null) return;
385
+ store.focusScene(subject.containerId);
386
+ // AT THE CLICKED FRAME, not the playhead's. The diamond verbs key where
387
+ // the playhead is because that is what a diamond means; a double-click in
388
+ // a curve names a point ON the curve, and moving the playhead to reach it
389
+ // would be the panel answering a different question.
390
+ store.toggleKeyframeAt(subject.containerId, subject.layerId, subject.path, frame);
391
+ },
392
+ setEase(refs, ease) {
393
+ // One batched write, so an ease on N keys is ONE undo step.
394
+ const keys: KeyframeSel[] = [];
395
+ for (const addr of refs) {
396
+ const ref = refOf(addr);
397
+ if (ref === null) continue;
398
+ const owner = curveTracksOf(doc, ref.containerId, ref.layerId)?.[ref.path];
399
+ const key = owner?.keyframes.find((k) => k.id === ref.keyframeId);
400
+ if (key === undefined) continue;
401
+ keys.push({ containerId: ref.containerId, layerId: ref.layerId, path: ref.path, frame: key.frame });
402
+ }
403
+ store.setKeyframesEase(keys, ease);
404
+ },
405
+ gesture: {
406
+ begin: () => store.beginBlockDrag(),
407
+ capture: (ops) => {
408
+ const mapped: CurveOp[] = [];
409
+ for (const op of ops) {
410
+ if (op.kind === "setValue") {
411
+ const key = refOf(op.ref);
412
+ if (key !== null) mapped.push({ kind: "setValue", key, value: op.value });
413
+ continue;
414
+ }
415
+ const keys = op.refs.map(refOf).filter((k): k is CurveKeyRef => k !== null);
416
+ if (keys.length === 0) continue;
417
+ if (op.kind === "move") {
418
+ // `snap` rides through verbatim — the ANCHOR (`keys[0]`) survives
419
+ // the map because `refs.map` preserves order, which is the whole
420
+ // contract the op's own comment states.
421
+ mapped.push({
422
+ kind: "move",
423
+ keys,
424
+ deltaFrames: op.deltaFrames,
425
+ ...(op.snap === undefined ? {} : { snap: op.snap }),
426
+ });
427
+ } else mapped.push({ kind: "setEase", keys, ease: op.ease });
428
+ }
429
+ store.captureCurveOps(mapped);
430
+ },
431
+ end: (commit) => store.endBlockDrag(commit),
432
+ },
433
+ };
434
+ }
435
+
436
+ /**
437
+ * The layer a curve pane should be showing, given what is selected.
438
+ *
439
+ * A LADDER, and the last rung is the one that matters: a pane that opened empty
440
+ * whenever nothing happened to be selected would read as broken in the most
441
+ * common case there is — an author switches to the graph to look at the
442
+ * animation they can already see in the rows.
443
+ *
444
+ * a focused KEYFRAME the most specific thing the author has pointed at,
445
+ * and it carries its own container (in the scene
446
+ * context the playhead's shot and the clicked
447
+ * diamond's shot can differ).
448
+ * the SELECTED layer what every other panel is showing.
449
+ * the shot's own tracks when it has some: a post-stack animation belongs
450
+ * to the shot and to no layer.
451
+ * the first layer that so the pane opens on something rather than on a
452
+ * carries a track sentence.
453
+ */
454
+ export function curveSubjectLayer(
455
+ state: {
456
+ selectedKeyframe: { containerId: string; layerId: string | null } | null;
457
+ selection: readonly string[];
458
+ containerId: string | null;
459
+ },
460
+ doc?: Doc3D,
461
+ ): { containerId: string; layerId: string | null } | null {
462
+ const key = state.selectedKeyframe;
463
+ if (key !== null) return { containerId: key.containerId, layerId: key.layerId };
464
+ const containerId = state.containerId;
465
+ if (containerId === null) return null;
466
+ const first = state.selection[0];
467
+ if (first !== undefined) return { containerId, layerId: first };
468
+ if (doc === undefined) return { containerId, layerId: null };
469
+ if (Object.keys(doc.scenesById[containerId]?.tracks ?? {}).length > 0) return { containerId, layerId: null };
470
+ return { containerId, layerId: animatedLayers(doc, containerId)[0] ?? null };
471
+ }
472
+
473
+ /**
474
+ * Every layer in a container that carries a track, IN OUTLINE ORDER, walking
475
+ * the forest: the order every other list in this chrome uses (front first,
476
+ * `frontFirst`), and the only one where "the first" means what a reader would
477
+ * point at, the highest row. A layer inside a group is reachable, which a flat
478
+ * scan of the roots would have missed. A group with tracks of its own is listed
479
+ * before its children.
480
+ */
481
+ export function animatedLayers(doc: Doc3D, containerId: string): string[] {
482
+ const home = homeOf(doc, containerId);
483
+ const out: string[] = [];
484
+ const walk = (ids: readonly string[]): void => {
485
+ for (const { id } of frontFirst(ids)) {
486
+ const layer = home?.layersById[id];
487
+ if (layer === undefined) continue;
488
+ if (Object.keys(layer.tracks ?? {}).length > 0) out.push(id);
489
+ walk(layerChildren(layer));
490
+ }
491
+ };
492
+ walk(home?.layers ?? []);
493
+ return out;
494
+ }
495
+
496
+ /** The ALL ANIMATED scope's rows: the shot's own tracks, then every animated
497
+ * layer's, each owner's rows in `curveRowsOf` order. */
498
+ export function allAnimatedRows(doc: Doc3D, containerId: string): Array<TimelineRow & { subject: CurveSubject }> {
499
+ return [null, ...animatedLayers(doc, containerId)].flatMap((layerId) => curveRowsOf(doc, containerId, layerId));
500
+ }
@@ -0,0 +1,68 @@
1
+ // "Duck under voice": the mixer's one-press duck, written as the per-clip
2
+ // `duck` the schema already has (audioDuck.ts derives the dip from it in all
3
+ // three mixers). No new field: the button is a shorthand for setting every
4
+ // bed's `duck.sources` to the voice clips, and its pressed state is read back
5
+ // from those same sources, so an author who edits one duck by hand sees the
6
+ // button let go.
7
+ //
8
+ // A VOICE TRACK IS FOUND BY ITS NAME, because the document has no track role.
9
+ // Sound effects are never ducked: a hit under a line is meant to be heard.
10
+ import { authoredAudioClips, audioTracksOf, removeAudioDuck, updateAudioClip } from "@dailies-studio/shot/doc";
11
+ import type { Doc3D } from "@dailies-studio/shot/doc";
12
+
13
+ const VOICE_RE = /\b(voice|voices|vo|voice-?over|narration|narrator|dialog|dialogue|speech)\b/i;
14
+ const SFX_RE = /\b(sfx|fx|effects?|foley)\b/i;
15
+
16
+ export interface VoiceDuck {
17
+ /** Clip ids on voice tracks (a recording's sound counts). */
18
+ sources: string[];
19
+ /** Real audio clips on the other, non-effects tracks. */
20
+ targets: string[];
21
+ }
22
+
23
+ export function voiceDuckPlan(doc: Doc3D): VoiceDuck {
24
+ const voice = new Set(audioTracksOf(doc).filter((t) => VOICE_RE.test(t.name)).map((t) => t.id));
25
+ const sfx = new Set(audioTracksOf(doc).filter((t) => SFX_RE.test(t.name)).map((t) => t.id));
26
+ const sources: string[] = [];
27
+ const targets: string[] = [];
28
+ for (const m of authoredAudioClips(doc)) {
29
+ if (voice.has(m.trackId)) sources.push(m.clip.id);
30
+ else if (!sfx.has(m.trackId) && m.layerId === undefined) targets.push(m.clip.id);
31
+ }
32
+ return { sources, targets };
33
+ }
34
+
35
+ /** `available`: there is a voice to duck under and a bed to duck. `active`:
36
+ * every bed already ducks under every voice clip. */
37
+ export function voiceDuckState(doc: Doc3D): { available: boolean; active: boolean } {
38
+ const { sources, targets } = voiceDuckPlan(doc);
39
+ if (sources.length === 0 || targets.length === 0) return { available: false, active: false };
40
+ const byId = new Map(authoredAudioClips(doc).map((m) => [m.clip.id, m.clip]));
41
+ const active = targets.every((id) => {
42
+ const have = byId.get(id)?.duck?.sources ?? [];
43
+ return sources.every((s) => have.includes(s));
44
+ });
45
+ return { available: true, active };
46
+ }
47
+
48
+ /** On: add the voice clips to every bed's duck (keeping any other sources and
49
+ * the strength). Off: take them out again, and drop a duck left empty. */
50
+ export function applyVoiceDuck(doc: Doc3D, on: boolean): Doc3D {
51
+ const { sources, targets } = voiceDuckPlan(doc);
52
+ if (sources.length === 0) return doc;
53
+ const byId = new Map(authoredAudioClips(doc).map((m) => [m.clip.id, m.clip]));
54
+ let next = doc;
55
+ for (const id of targets) {
56
+ const duck = byId.get(id)?.duck;
57
+ const have = duck?.sources ?? [];
58
+ const merged = on ? [...have, ...sources.filter((s) => !have.includes(s))] : have.filter((s) => !sources.includes(s));
59
+ if (merged.length === have.length && merged.every((s, i) => s === have[i])) continue;
60
+ next =
61
+ merged.length === 0
62
+ ? removeAudioDuck(next, id)
63
+ : updateAudioClip(next, id, {
64
+ duck: { sources: merged, ...(duck?.strength === undefined ? {} : { strength: duck.strength }) },
65
+ });
66
+ }
67
+ return next;
68
+ }