@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,7 @@
1
+ // THE MOTION PRESETS' STAMP, on demand: `stampMotionPreset` and its catalog
2
+ // are a chunk of their own, kept out of the entry's budget like the Motion
3
+ // section that offers them, and fetched at idle with it
4
+ // (`prefetchInspectorSections`). The store's `applyMotionPreset` and
5
+ // `previewMotion` import this module when first used; by then the idle fetch
6
+ // has usually landed, so a pick waits on nothing.
7
+ export { stampMotionPreset } from "@dailies-studio/shot/doc";
@@ -9,9 +9,58 @@
9
9
  // which is passed in per drag — a dock taller than the window is a dock with
10
10
  // no stage behind it.
11
11
 
12
- export const RAIL_WIDTH = { min: 168, max: 460, default: 232 } as const;
12
+ import type { ShotEditorState } from "./types.js";
13
+ import { componentEditOpen, workspaceOf } from "./workspace.js";
14
+ import type { BoardRightPanel } from "./workspace.js";
15
+ import { foldedDockContentH } from "../panels/timeline/model.js";
16
+
17
+ export const RAIL_WIDTH = { min: 168, max: 460, default: 224 } as const;
13
18
  export const DOCK_HEIGHT = { min: 120, max: 640, default: 300 } as const;
14
19
 
20
+ /**
21
+ * The dock's OTHER dimension: how wide one frame is drawn, in CSS px.
22
+ *
23
+ * It sits beside the panel bounds for the reason they are here at all: the
24
+ * store's clamp, the initial state, the wheel zoom, the slider and the tests
25
+ * were four separate restatements of `0.2`, `60` and `6`, which is three
26
+ * numbers with four owners. `setDockPpf` is the one writer and it reads this.
27
+ *
28
+ * The floor is where a frame is a fifth of a pixel, which is about as far out
29
+ * as a ten-minute document can be fitted; the ceiling is 60px a frame, where
30
+ * one second fills a laptop's lane and there is nothing left to see by going
31
+ * further. The default is the zoom a document opens at before `fit` measures
32
+ * the lane it actually has.
33
+ */
34
+ export const DOCK_PPF = { min: 0.2, max: 60, default: 6 } as const;
35
+
36
+ /**
37
+ * The inspector, which was a hardcoded 288 in CSS and draggable nowhere.
38
+ *
39
+ * 288 was too narrow for its own contents and there was no way to say so: the
40
+ * camera's Zoom / Roll / Focus row had ~66px per field, so `.numfield-label`
41
+ * hit its 14px floor and the three labels rendered "Z…", "R…", "F…". The panel
42
+ * had been WORKED AROUND rather than widened — `SceneDocSection` carries a
43
+ * comment about shortening a label because "`.insp-label` is capped at 60% of a
44
+ * 288px pill" — which is the sign a constant is wrong rather than a label.
45
+ *
46
+ * 320 was the first answer, chosen while the panel still had to fit THREE
47
+ * labelled pills in a row. It does not any more: `.numfield-label` is
48
+ * `flex: none` and the two-pill rule holds the row to two, so the width that
49
+ * was buying a third column is now buying nothing but a narrower stage. On a
50
+ * 1366 laptop that column is a twentieth of the screen.
51
+ *
52
+ * 288 with 8/10 padding leaves 252px across a row: 123px per pill in a
53
+ * two-pill row, of which ~61px is label — nine characters at 12px, and the
54
+ * longest label the panel has is "Spread".
55
+ *
56
+ * 304 is the Paper redesign's column (2026-10-04). Its rows put the label
57
+ * OUTSIDE the field and add a tick slider to the axis rows, which is what the
58
+ * extra 16px pays for. Bounds: 264 is where the inputs reach their 24px floor
59
+ * and there is nothing left to give; 480 is where the panel stops being a
60
+ * rail and starts taking the stage's width for a column of controls.
61
+ */
62
+ export const INSPECTOR_WIDTH = { min: 264, max: 480, default: 304 } as const;
63
+
15
64
  /** Clamp to whole pixels. Whole, because a fractional panel width puts every
16
65
  * box positioned off it on a half pixel and the seams stop being crisp. */
17
66
  export function clampSize(value: number, min: number, max: number): number {
@@ -19,8 +68,329 @@ export function clampSize(value: number, min: number, max: number): number {
19
68
  return Math.round(Math.min(max, Math.max(min, value)));
20
69
  }
21
70
 
22
- /** The dock's ceiling for a given window: its own max, or most of the window,
23
- * whichever is smaller. */
24
- export function dockCeiling(viewportHeight: number): number {
25
- return Math.max(DOCK_HEIGHT.min, Math.min(DOCK_HEIGHT.max, Math.round(viewportHeight * 0.7)));
71
+ /**
72
+ * The docked shell's three bar heights, for the arithmetic that needs them.
73
+ * They mirror `--topbar-h`, `--panel-head-h` and `--dock-head-h` in
74
+ * packages/ui/src/tokens.css, pinned by rowMetrics.test.ts.
75
+ *
76
+ * THE TOP BAR is the window's first row. THE PANEL HEAD is the second: the
77
+ * canvas bar and both column heads, so one hairline crosses the window under
78
+ * them. THE DOCK HEAD is the timeline's head and transport, which is also the
79
+ * whole bottom row when the dock is collapsed.
80
+ */
81
+ export const TOPBAR_H = 44;
82
+ export const PANEL_HEAD_H = 40;
83
+ export const DOCK_HEAD_H = 40;
84
+
85
+ /**
86
+ * The tool footer's height: the docked row under the canvas cell that holds
87
+ * the tools. It mirrors `--tool-footer-h` in styles/shell.css `:root`, pinned
88
+ * by rowMetrics.test.ts.
89
+ *
90
+ * A ROW, NOT A FLOAT. The tools used to ride a pill over the bottom of the
91
+ * picture, so the canvas cell lost nothing to them and only the stage's inset
92
+ * did. The footer is a grid track of its own, so it takes its height from the
93
+ * canvas, and the dock's ceiling has to pay for it while it is shown.
94
+ */
95
+ export const TOOL_FOOTER_H = 48;
96
+
97
+ /** The state `toolFooterShown` reads. */
98
+ export type ToolFooterFields = Pick<
99
+ ShotEditorState,
100
+ | "name"
101
+ | "doc"
102
+ | "editingDef"
103
+ | "materialWorkspace"
104
+ | "codeComponent"
105
+ | "componentsTab"
106
+ | "storyboardOpen"
107
+ > &
108
+ Partial<Pick<ShotEditorState, "componentsOpen">>;
109
+
110
+ /**
111
+ * Whether the tool footer is on screen. ONE ANSWER for every reader: App
112
+ * mounts the row and sets its track and its inset edge from it, and
113
+ * `fitShell` charges the dock's ceiling for it. Readers asking different
114
+ * versions of the question is how a row ends up drawn with nothing in it, or
115
+ * a dock sized for a footer that is not there.
116
+ *
117
+ * A LOADED DOCUMENT. With no document there is no timeline either, and a row
118
+ * of tools over a canvas that has nothing to draw into is noise.
119
+ *
120
+ * AT EVERY LEVEL OF THE STAGE: the Project context, a shot and a definition.
121
+ * The footer is not only the tools any more. Its right half is the view track
122
+ * (Video, 3D, Camera, Split), which applies at every level, and in the Project
123
+ * context its left half names the shot under the playhead (ToolFooter.tsx).
124
+ * The TOOLS still answer to the narrower question: ToolDockBar renders only
125
+ * inside a shot or a definition, for the reason argued there.
126
+ *
127
+ * ONLY IN THE STAGE WORKSPACE. The three modes show their own content in the
128
+ * canvas cell, and the tools address the film's canvas, which none of them is.
129
+ * The one exception is Components' Edit tab on a definition
130
+ * (`componentEditOpen`): it edits the definition's layers, so the tools are
131
+ * there while editing inside one.
132
+ */
133
+ export function toolFooterShown(s: ToolFooterFields): boolean {
134
+ return (
135
+ s.name !== null &&
136
+ s.doc !== null &&
137
+ (workspaceOf(s) === "stage" || componentEditOpen(s))
138
+ );
139
+ }
140
+
141
+ /**
142
+ * The smallest canvas the docked shell leaves, whatever the author dragged.
143
+ *
144
+ * WIDTH: the canvas cell's two docked rows have to fit it. The canvas bar
145
+ * above the picture is one row of place, panes and zoom, and the tool footer
146
+ * under it is one `nowrap` row: the 377px tools, then the view track and the
147
+ * Clean view eye, which compact and fold to fit (tool-footer.css has the
148
+ * measured widths). 640 (616 of content inside the footer's 12px padding)
149
+ * holds the tools beside the COMPACT track; the full one needs a 660 column,
150
+ * and the folded picker fits down to 522.
151
+ * It also holds every canvas bar but the crowded ones that canvas.css gives
152
+ * way for. HEIGHT: enough picture between
153
+ * the canvas bar and the footer to judge a frame.
154
+ */
155
+ export const CANVAS_MIN = { width: 640, height: 240 } as const;
156
+
157
+ /**
158
+ * The dock's ceiling for a given window: what is left once the top bar, the
159
+ * panel head, the smallest canvas and (when it is shown) the tool footer have
160
+ * taken theirs, inside the dock's own bounds.
161
+ *
162
+ * THE FOOTER IS AN ARGUMENT, not a constant, because it is not always there:
163
+ * the modes collapse its row, and charging them for it would cost a 768px
164
+ * laptop 48px of storyboard strip for nothing. Every level of the stage
165
+ * workspace pays it, the Project context included. At 1366 by 768 the
166
+ * ceiling is 396 with the footer (768 - 44 - 40 - 240 - 48) and 444
167
+ * without it.
168
+ */
169
+ export function dockCeiling(viewportHeight: number, footer = false): number {
170
+ const vh = Number.isFinite(viewportHeight) ? viewportHeight : 0;
171
+ return clampSize(
172
+ vh - TOPBAR_H - PANEL_HEAD_H - CANVAS_MIN.height - (footer ? TOOL_FOOTER_H : 0),
173
+ DOCK_HEIGHT.min,
174
+ DOCK_HEIGHT.max,
175
+ );
176
+ }
177
+
178
+ /** What the grid lays out, as opposed to what the author stored. */
179
+ export interface ShellFit {
180
+ railWidth: number;
181
+ inspectorWidth: number;
182
+ /** The bottom row: the dock's height, or its head when it is collapsed. */
183
+ dockRow: number;
184
+ }
185
+
186
+ /**
187
+ * The docked shell's tracks for a window, from the sizes the author stored.
188
+ *
189
+ * DISPLAY ONLY. The stored sizes are the author's and are never rewritten
190
+ * here: a window too small for them shows the fitted sizes, and the stored
191
+ * ones come back the moment the window can hold them. The setters keep only
192
+ * each panel's own bounds (layoutPrefs.ts relies on that).
193
+ *
194
+ * THE RAIL GIVES FIRST, then the inspector, each down to its own minimum,
195
+ * until the canvas has `CANVAS_MIN.width`. Below both minimums the canvas
196
+ * takes the deficit: the chrome does not shrink past what its rows need.
197
+ *
198
+ * A COLLAPSED COLUMN STILL COUNTS. Its track keeps its width because the
199
+ * timeline's name column and meters sit under it, so collapsing a panel never
200
+ * moves a bar under the pointer, and the canvas simply spans over it.
201
+ *
202
+ * THE DOCK PAYS FOR THE TOOL FOOTER only while the footer is shown, which is
203
+ * why the footer's fields ride in with the sizes: `toolFooterShown` is the
204
+ * same question App asks before it mounts the row.
205
+ */
206
+ export function fitShell(
207
+ viewportWidth: number,
208
+ viewportHeight: number,
209
+ stored: { railWidth: number; inspectorWidth: number; dockHeight: number; dockCollapsed: boolean } & ToolFooterFields &
210
+ Partial<Pick<ShotEditorState, "enteredScene" | "dockMode">>,
211
+ ): ShellFit {
212
+ const ceiling = dockCeiling(viewportHeight, toolFooterShown(stored));
213
+ return {
214
+ ...fitColumns(viewportWidth, stored),
215
+ dockRow: stored.dockCollapsed
216
+ ? DOCK_HEAD_H
217
+ : Math.min(stored.dockHeight, ceiling, foldedDockRow(viewportWidth, viewportHeight, stored)),
218
+ };
26
219
  }
220
+
221
+ /**
222
+ * AN UNTOUCHED DOCK IS AS TALL AS ITS FOLDED ROWS. The first look at a shot is
223
+ * Shot, Camera and Sound, and a 300px dock under three rows is stage taken for
224
+ * nothing, so the row the grid gives the dock stops at the head plus the
225
+ * folded content (`foldedDockContentH`).
226
+ *
227
+ * Only the Rows view, and only while `dockHeight` is still exactly what
228
+ * `layoutFor` gave this window (the refit's own "untouched" test): a dragged
229
+ * height is the author's and always wins, and Graph and Sound need the room
230
+ * their own views draw. A definition keeps the shot's height (its Actions rows
231
+ * scroll), so entering a component never moves the dock. Infinity means "no
232
+ * opinion".
233
+ */
234
+ function foldedDockRow(
235
+ viewportWidth: number,
236
+ viewportHeight: number,
237
+ s: { dockHeight: number } & ToolFooterFields & Partial<Pick<ShotEditorState, "enteredScene" | "dockMode">>,
238
+ ): number {
239
+ if (s.doc === null || (s.dockMode ?? "rows") !== "rows") return Infinity;
240
+ if (s.dockHeight !== layoutFor(viewportWidth, viewportHeight).dockHeight) return Infinity;
241
+ return Math.max(DOCK_HEIGHT.min, DOCK_HEAD_H + foldedDockContentH(s.doc, s.enteredScene ?? null));
242
+ }
243
+
244
+ /** `fitShell`'s two side columns: the rail gives first, then the inspector,
245
+ * each down to its own minimum, until the canvas has `CANVAS_MIN.width`. */
246
+ function fitColumns(
247
+ viewportWidth: number,
248
+ stored: { railWidth: number; inspectorWidth: number },
249
+ ): { railWidth: number; inspectorWidth: number } {
250
+ const vw = Number.isFinite(viewportWidth) ? viewportWidth : 0;
251
+ let rail = stored.railWidth;
252
+ let inspector = stored.inspectorWidth;
253
+ let over = rail + inspector - Math.max(0, vw - CANVAS_MIN.width);
254
+ if (over > 0) {
255
+ const cut = Math.min(over, Math.max(0, rail - RAIL_WIDTH.min));
256
+ rail -= cut;
257
+ over -= cut;
258
+ }
259
+ if (over > 0) inspector -= Math.min(over, Math.max(0, inspector - INSPECTOR_WIDTH.min));
260
+ return { railWidth: rail, inspectorWidth: inspector };
261
+ }
262
+
263
+ /** The board's right cell at its DISPLAY widths (S1, S3, Paper SB1): the
264
+ * Plan panel, the inspector, comments and the agent at the inspector's 304,
265
+ * the component sheet at 400. Never written to `inspectorWidth`, so Studio
266
+ * keeps the author's own width. */
267
+ export const BOARD_PANEL_W = { panel: 304, component: 400 } as const;
268
+
269
+ /**
270
+ * The board's side columns as drawn. THE BOARD IS ONE FULL-WIDTH CANVAS: no
271
+ * left rail, ever, and a right cell only while `boardRightPanel` names an
272
+ * occupant. That cell draws at its display width, giving way down to the
273
+ * inspector's minimum when the window leaves the canvas under
274
+ * `CANVAS_MIN.width`.
275
+ */
276
+ export function boardColumns(
277
+ viewportWidth: number,
278
+ panel: BoardRightPanel,
279
+ ): { railWidth: number; inspectorWidth: number } {
280
+ if (panel === null) return { railWidth: 0, inspectorWidth: 0 };
281
+ const vw = Number.isFinite(viewportWidth) ? viewportWidth : 0;
282
+ const want = panel === "component" ? BOARD_PANEL_W.component : BOARD_PANEL_W.panel;
283
+ return { railWidth: 0, inspectorWidth: Math.max(INSPECTOR_WIDTH.min, Math.min(want, vw - CANVAS_MIN.width)) };
284
+ }
285
+
286
+ /**
287
+ * A layout the author already chose, as far as storage remembers it.
288
+ *
289
+ * Every field optional and read one by one: an author who dragged only the
290
+ * rail keeps their rail and still gets a fitted dock, and a storage value that
291
+ * failed to parse is simply an absent field rather than a whole layout thrown
292
+ * away. Declared beside `layoutFor` because the two are read together and this
293
+ * is the module both the store and `layoutPrefs.ts` already depend on.
294
+ */
295
+ export interface BootLayoutPrefs {
296
+ railWidth?: number;
297
+ inspectorWidth?: number;
298
+ dockHeight?: number;
299
+ railCollapsed?: boolean;
300
+ inspectorCollapsed?: boolean;
301
+ dockCollapsed?: boolean;
302
+ }
303
+
304
+ /**
305
+ * What the three panels should START at on a given window.
306
+ *
307
+ * ── WHY A FUNCTION AND NOT THREE MORE CONSTANTS ─────────────────────────
308
+ *
309
+ * The defaults above are one number each, and they were chosen on a desktop.
310
+ * The docked columns and the bottom row are subtracted from the canvas at
311
+ * EVERY window size, on a 2560 monitor and on a 1366 laptop alike, so a
312
+ * desktop's numbers leave a laptop a small picture.
313
+ *
314
+ * A FRACTION FOR THE DOCK, A BREAKPOINT FOR THE RAIL. The dock is the panel
315
+ * whose useful height really is proportional: it is a strip of rows, and 30%
316
+ * of the window shows about as many of them at any size. The rail is not —
317
+ * it holds names, and a name needs the width it needs — so it steps once,
318
+ * at the width below which the two side rails start costing more than they
319
+ * carry. The inspector does not move at all: 304 is already the width its
320
+ * own rows need, and taking more from a laptop would only make the rows worse.
321
+ *
322
+ * NEVER LARGER THAN THE DESKTOP DEFAULT. This function makes a small window
323
+ * smaller, never a large one bigger: an author who wants more dock on a big
324
+ * monitor drags for it, and a boot that silently spent 30% of a 1440p screen
325
+ * on the timeline would be taking that decision away from them.
326
+ *
327
+ * This is a BOOT value, applied once by `bootLayout` and re-applied on resize
328
+ * only to a panel the author has not touched. It is deliberately not folded
329
+ * into the constants above, which remain the answer to "what does this panel
330
+ * want" — the reset-to-default of a drag still lands there. `fitShell` is the
331
+ * other half: what a window too small for the stored sizes lays out.
332
+ */
333
+ export function layoutFor(
334
+ viewportWidth: number,
335
+ viewportHeight: number,
336
+ ): { railWidth: number; inspectorWidth: number; dockHeight: number } {
337
+ const vw = Number.isFinite(viewportWidth) ? viewportWidth : 0;
338
+ const vh = Number.isFinite(viewportHeight) ? viewportHeight : 0;
339
+ return {
340
+ railWidth: vw > 0 && vw < 1440 ? 200 : RAIL_WIDTH.default,
341
+ inspectorWidth: INSPECTOR_WIDTH.default,
342
+ // Clamped to the DEFAULT rather than to DOCK_HEIGHT.max, per the rule
343
+ // above: 30% of a 1440p window is 432px of timeline nobody asked for.
344
+ //
345
+ // AND NEVER PAST THE FOOTER'S CEILING, so the fit is a number
346
+ // `setDockHeight` keeps verbatim in every context. Under a ~531px window
347
+ // 30% is more than `dockCeiling(vh, true)` allows, and a fit the setter
348
+ // clamps is a fit nobody can recognise afterwards: the resize refit and
349
+ // `authorLayout` both read "not the fitted number" as "the author dragged
350
+ // it", so the dock stopped refitting and its clamp was saved as a
351
+ // preference. The modes' taller ceiling costs nothing here: a window that
352
+ // short has no dock to spare.
353
+ dockHeight:
354
+ vh > 0
355
+ ? Math.min(
356
+ clampSize(Math.round(vh * 0.3), DOCK_HEIGHT.min, DOCK_HEIGHT.default),
357
+ dockCeiling(vh, true),
358
+ )
359
+ : DOCK_HEIGHT.default,
360
+ };
361
+ }
362
+
363
+ /**
364
+ * The material mode's preview: THE OBJECT, the hole at the right of the
365
+ * canvas cell, and nothing else in it.
366
+ *
367
+ * THE STORED WIDTH, not the drawn one. The hole draws at most half the canvas
368
+ * cell (`--material-preview-w` in styles/modes/material.css), and the seam's
369
+ * drag caps what it stores at that same half (`setMaterialColumnWidth`'s
370
+ * `ceiling`), so a narrow window shows less without rewriting the number.
371
+ *
372
+ * PIXELS, for the reason at the top of this file: a width the author dragged
373
+ * must not move on the next window resize.
374
+ *
375
+ * Every pixel of the hole is subject. The camera fits the subject to the
376
+ * SMALLER axis of the hole (see `isolationExtent`), so while it stays a tall
377
+ * narrow slot the width is the whole budget. 560 is roughly 30% of a 1920
378
+ * window, which is what it takes to read a material rather than identify one.
379
+ *
380
+ * Bounds: under 280 the hole is narrower than the graph's own node cards and
381
+ * stops being a preview; 960 is where it starts eating the graph it exists to
382
+ * annotate.
383
+ */
384
+ export const MATERIAL_COLUMN = { min: 280, max: 960, default: 560 } as const;
385
+
386
+ /**
387
+ * A code component's live preview, beside the code pane in the canvas cell.
388
+ * Stored in pixels for the same reason, and drawn no wider than the cell
389
+ * leaves after the code pane's own minimum (`CODE_PANE_MIN`, code.css's
390
+ * `min-width`), which the seam's drag passes as its ceiling.
391
+ *
392
+ * 420 is the width the pane always had. Under 240 the loop readout and the
393
+ * picture stop fitting; 1400 is a whole laptop canvas cell.
394
+ */
395
+ export const CODE_LIVE_WIDTH = { min: 240, max: 1400, default: 420 } as const;
396
+ export const CODE_PANE_MIN = 360;
@@ -0,0 +1,119 @@
1
+ // What an author's unsent sync batches change, in words, for the dialog a
2
+ // delete under live sync shows (R10, Paper page 21 "Renamed or deleted"):
3
+ //
4
+ // One board. opacity 0 → 1
5
+ // CardBoard scale 1 → 1.1
6
+ // Badge fill #34D399 → #FF7A3D
7
+ //
8
+ // One line per thing changed, however many ops it took: the ops collapse by
9
+ // owner and field, and the values are read from the documents before and
10
+ // after, so a drag of fifty mints is one line.
11
+ import { applyOps } from "@dailies-studio/shot/doc";
12
+ import type { Doc3D, SyncOp } from "@dailies-studio/shot/doc";
13
+
14
+ export interface PendingSummary {
15
+ /** At most `max` lines, the owner column padded so the list aligns, then
16
+ * "and N more" when there are more. */
17
+ lines: string[];
18
+ /** How many things changed. */
19
+ count: number;
20
+ }
21
+
22
+ /** The ordered lists whose items are layers or scenes: an `ins` or `rm` in
23
+ * one is the other half of a `new` or `del`, or a move. */
24
+ const SEQS = new Set(["layers", "roots", "scenes"]);
25
+
26
+ type Rec = Record<string, unknown>;
27
+ const rec = (v: unknown): Rec | null => (typeof v === "object" && v !== null ? (v as Rec) : null);
28
+
29
+ function at(doc: Doc3D, p: readonly string[]): unknown {
30
+ let v: unknown = doc;
31
+ for (const k of p) v = rec(v)?.[k];
32
+ return v;
33
+ }
34
+
35
+ /** A layer's or scene's display name in either document. */
36
+ function nameOf(docs: readonly Doc3D[], id: string): string {
37
+ for (const doc of docs) {
38
+ const scene = rec(doc.scenesById)?.[id];
39
+ if (scene !== undefined) return String(rec(scene)?.["name"] ?? id);
40
+ for (const table of [doc.scenesById, rec(doc)?.["components"]]) {
41
+ for (const owner of Object.values(rec(table) ?? {})) {
42
+ const layer = rec(rec(rec(owner)?.["layersById"])?.[id]);
43
+ if (layer !== null) return String(layer["label"] ?? id);
44
+ }
45
+ }
46
+ }
47
+ return id;
48
+ }
49
+
50
+ function value(v: unknown): string | null {
51
+ if (typeof v === "number") return String(Math.round(v * 1000) / 1000);
52
+ if (typeof v === "string") return v.length <= 24 ? v : null;
53
+ if (typeof v === "boolean") return v ? "on" : "off";
54
+ return null;
55
+ }
56
+
57
+ /** The field a path names, short: its last key, with the one before when
58
+ * the last says little alone (`position.x`, `stops.0`). */
59
+ function fieldOf(p: readonly string[]): string {
60
+ const last = p[p.length - 1] ?? "";
61
+ return last.length <= 1 || /^\d+$/.test(last) ? p.slice(-2).join(".") : last;
62
+ }
63
+
64
+ export function describePending(base: Doc3D, ops: readonly SyncOp[], max = 6): PendingSummary {
65
+ let after = base;
66
+ try {
67
+ after = applyOps(base, ops).doc;
68
+ } catch {
69
+ // Names then come from the base; values read as "changed".
70
+ }
71
+ const docs = [after, base];
72
+ /** owner + field → [owner, what]. Insertion order is first-change order. */
73
+ const out = new Map<string, [string, string]>();
74
+ const put = (owner: string, field: string, what: string, weak = false): void => {
75
+ const key = `${owner}\u0000${field}`;
76
+ if (weak && out.has(key)) return;
77
+ // A layer added or removed is one line, not one per field it carries.
78
+ const whole = out.get(`${owner}\u0000`)?.[1];
79
+ if (field !== "" && (whole === "added" || whole === "removed")) return;
80
+ out.set(key, [owner, what]);
81
+ };
82
+ for (const op of ops) {
83
+ const p = op.p;
84
+ const list = op.op === "ins" || op.op === "rm" || op.op === "mv";
85
+ if (list && SEQS.has(p[p.length - 2] ?? "")) {
86
+ // An item of a layer or scene list: added or removed by its `new` or
87
+ // `del`, otherwise moved.
88
+ put(nameOf(docs, p[p.length - 1]!), "", "moved", true);
89
+ continue;
90
+ }
91
+ const li = p.lastIndexOf("layersById");
92
+ const owned = li >= 0 ? { id: p[li + 1], rest: p.slice(li + 2) } : p[0] === "scenesById" ? { id: p[1], rest: p.slice(2) } : null;
93
+ const owner = owned?.id === undefined ? "Project" : nameOf(docs, owned.id);
94
+ const rest = owned?.id === undefined ? p : owned.rest;
95
+ if (rest.length === 0) {
96
+ put(owner, "", op.op === "del" ? "removed" : op.op === "new" ? "added" : "changed");
97
+ continue;
98
+ }
99
+ if (list) {
100
+ const name = p[p.length - 2] ?? "";
101
+ put(owner, name, op.op === "ins" ? `added to ${name}` : op.op === "rm" ? `removed from ${name}` : `reordered ${name}`);
102
+ continue;
103
+ }
104
+ const field = fieldOf(rest);
105
+ const now = value(at(after, p));
106
+ if ((field === "label" || field === "name") && now !== null && op.op !== "del") {
107
+ put(owner, field, `renamed "${now}"`);
108
+ continue;
109
+ }
110
+ const was = value(at(base, p));
111
+ put(owner, field, was !== null && now !== null ? `${field} ${was} → ${now}` : `${field} changed`);
112
+ }
113
+ const rows = [...out.values()];
114
+ const shown = rows.slice(0, max);
115
+ const width = Math.max(0, ...shown.map(([owner]) => owner.length)) + 2;
116
+ const lines = shown.map(([owner, what]) => owner.padEnd(width) + what);
117
+ if (rows.length > max) lines.push(`and ${rows.length - max} more`);
118
+ return { lines, count: rows.length };
119
+ }
@@ -0,0 +1,78 @@
1
+ // THE ONE ANSWER TO "MAY THE TRANSPORT START", so the guard and the buttons
2
+ // cannot drift.
3
+ //
4
+ // `setPlaying` is the single route to playback (Space through `handleKey`, the
5
+ // Play menu row, the Play control in the dock and Code Studio's preview strip,
6
+ // and WebMCP), and it refuses a start for two reasons: the board, and an
7
+ // export lock. The menu row and the Play control grey themselves for the same
8
+ // reasons, and until this file existed each of them restated the rule in its
9
+ // own expression. The dock's own comment already claimed they were one rule,
10
+ // that "the greying-out is the button agreeing with the guard rather than a
11
+ // second rule"; this is that claim made literal, and it is the same move as
12
+ // the label, enum and route consolidation one directory over.
13
+ //
14
+ // A SCENE STILL LOADING IS NOT A REFUSAL (bridge v51). Play is always
15
+ // pressable then: the press is queued (`playIntent`), the control says it is
16
+ // waiting (`SCENE_WAITING`), and the transport starts by itself once the stage
17
+ // is ready (`stageReady`). A second press cancels the wait (`playOn`).
18
+ //
19
+ // IT ANSWERS FOR A START ONLY. Every caller pairs it with `!playOn`. A
20
+ // transport already running, or a queued Play, must always be stoppable: an
21
+ // export that begins later would otherwise leave the author with a running
22
+ // clock and a dead pause button.
23
+ //
24
+ // The string it returns is the refusal the author reads, in the error strip
25
+ // from `setPlaying` and as the button's own title. There is no separate code
26
+ // for the reason because nothing branches on which reason it was.
27
+ import type { ShotEditorState } from "./types.js";
28
+ import { workspaceOf } from "./workspace.js";
29
+
30
+ /** The board's refusal, one sentence for Space, the menu row and WebMCP. */
31
+ export const BOARD_DOES_NOT_PLAY = "The storyboard doesn't play. Open Studio to play the film.";
32
+
33
+ /** The Play control's title while a queued Play waits for the scene
34
+ * (`playIntent` armed) or for the stage to hand over (starting). A wait, not
35
+ * a refusal: it plays by itself. */
36
+ export const SCENE_WAITING = "Getting the scene ready to play. Space cancels.";
37
+
38
+ /** How far a Play pass has drawn, in whole percent. The one rounding for the
39
+ * Play control's title, the store's progress writes and WebMCP's answer. */
40
+ export function preparingPercent({ done, total }: { readonly done: number; readonly total: number }): number {
41
+ return total > 0 ? Math.floor((done * 100) / total) : 0;
42
+ }
43
+
44
+ /** The Play control's title while a Play pass draws (`playIntent` preparing). */
45
+ export function preparingTitle(intent: { readonly done: number; readonly total: number }): string {
46
+ return `Preparing playback, ${preparingPercent(intent)}%. Space cancels.`;
47
+ }
48
+
49
+ /** IS PLAY ON: the transport running, or a queued Play waiting to start it.
50
+ * Every toggle calls `setPlaying(!playOn(state))`, so a second press cancels
51
+ * the wait. */
52
+ export function playOn(state: Pick<ShotEditorState, "playing" | "playIntent">): boolean {
53
+ return state.playing || state.playIntent !== null;
54
+ }
55
+
56
+ /** IS THE STAGE READY TO PLAY: it owes the open subject no presentation
57
+ * (`stageBusy`, bridge v51), and a stage on its way has reported in. Ready
58
+ * with no stage expected at all: a bare store, a unit test and SSR. */
59
+ export function stageReady(state: Pick<ShotEditorState, "stageBusy" | "stageExpected" | "stageInfo">): boolean {
60
+ return !state.stageBusy && !(state.stageExpected && state.stageInfo === null);
61
+ }
62
+
63
+ export function playHold(state: ShotEditorState): string | null {
64
+ // THE BOARD PLANS, IT DOES NOT PLAY. A Shot there is a few stills and the
65
+ // author's notes about it, so the transport stays at rest and the scrubber
66
+ // is the only way through the Shot. Code Studio opened over the board is
67
+ // its own workspace, and plays.
68
+ if (workspaceOf(state) === "storyboard") return BOARD_DOES_NOT_PLAY;
69
+ // A capture loop owns the clock while an export runs. The stage defers chrome
70
+ // seeks, so playback would not move the picture: it would only overwrite the
71
+ // frame the export restores at the end and play the preview audio over it.
72
+ if (state.exportLock !== null) {
73
+ return `playback is held while the ${
74
+ state.exportLock.where === "browser" ? "in-browser" : "studio server"
75
+ } export renders. Cancel it to play`;
76
+ }
77
+ return null;
78
+ }