@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
@@ -1,85 +0,0 @@
1
- // The During list: the blocks the Animate gesture writes, plus a palette to add
2
- // one without a gesture.
3
- //
4
- // Each row FOCUSES rather than expanding inline. `state.selectedBlock` is the
5
- // same bit the dock's bars write, so clicking a row here highlights the bar
6
- // there and puts its timing in one editor below — instead of N accordion
7
- // editors that each claim to be "the" timing controls.
8
- import { motionPresets, presetsForSlot } from "@dailies-studio/shot/doc";
9
- import { InspectorSection } from "@dailies-studio/ui";
10
- import { useShotEditor, useStore } from "../../../state/context.js";
11
- import { useSelectedLayers } from "../useDocWrite.js";
12
- import { useBlocksInSlot } from "./useBlocks.js";
13
-
14
- const DEFAULT_FRAMES = 24;
15
-
16
- export function DuringBlocks() {
17
- const store = useStore();
18
- const layers = useSelectedLayers();
19
- const blocks = useBlocksInSlot("during");
20
- const focused = useShotEditor((s) => s.selectedBlock);
21
- // The inspector's subject scene. Its layers are the selection's, so this is
22
- // the scene every row here belongs to by construction.
23
- const sceneId = useShotEditor((s) => s.sceneId);
24
- const multi = layers.length > 1;
25
- if (layers.length === 0 || sceneId === null) return null;
26
-
27
- return (
28
- <InspectorSection title="During" persistKey="shot:animate:during">
29
- {blocks.length === 0 ? (
30
- <p className="inspector-empty">
31
- Press ⇧A, then drag on the canvas. The edit becomes a block ending at the playhead.
32
- </p>
33
- ) : (
34
- <ul className="animate-blocks" aria-label="During blocks">
35
- {blocks.map(({ layer, block }) => {
36
- const on = focused?.layerId === layer.id && focused.blockId === block.id;
37
- const label = motionPresets[block.preset]?.label ?? block.preset;
38
- return (
39
- <li key={`${layer.id}:${block.id}`}>
40
- <button
41
- type="button"
42
- className="animate-block-row"
43
- aria-pressed={on}
44
- aria-label={`Block ${label} on ${layer.label}`}
45
- onClick={() => store.selectBlock({ sceneId, layerId: layer.id, blockId: block.id })}
46
- >
47
- <span className="animate-block-name">
48
- {label}
49
- {/* Which layer, but only when there IS more than one — on a
50
- single selection the suffix would be noise on every row. */}
51
- {multi && <em className="animate-block-owner"> · {layer.label}</em>}
52
- </span>
53
- <span className="animate-block-span">
54
- f{block.frame}–{block.frame + Math.max(1, Math.trunc(block.durationFrames))}
55
- </span>
56
- </button>
57
- <button
58
- type="button"
59
- className="animate-block-remove"
60
- aria-label={`Remove ${label} on ${layer.label}`}
61
- onClick={() => store.removeBlock(layer.id, block.id)}
62
- >
63
- ✕
64
- </button>
65
- </li>
66
- );
67
- })}
68
- </ul>
69
- )}
70
- <div className="animate-palette" role="group" aria-label="During presets">
71
- {presetsForSlot("during").map((preset) => (
72
- <button
73
- key={preset.id}
74
- type="button"
75
- className="animate-preset"
76
- aria-label={`Add ${preset.label}`}
77
- onClick={() => store.addBlock("during", preset.id, DEFAULT_FRAMES)}
78
- >
79
- + {preset.label}
80
- </button>
81
- ))}
82
- </div>
83
- </InspectorSection>
84
- );
85
- }
@@ -1,57 +0,0 @@
1
- // The In and Out palettes: click a preset, every selected layer gets that block.
2
- //
3
- // ── WHY THEY STACK RATHER THAN REPLACE ─────────────────────────────────
4
- //
5
- // Clicking Fade then Slide gives a layer that fades AND slides, because the
6
- // channel combinators commute — the fold has no ordering rule to get wrong. So
7
- // the palette is a set of buttons, not a radio group, and a preset already on
8
- // the layer shows as active and REMOVES on a second click. A replace-only
9
- // palette would make "fade and slide in" unauthorable, which is the single most
10
- // common entrance in the entire category.
11
- import { presetsForSlot } from "@dailies-studio/shot/doc";
12
- import type { BlockSlot } from "@dailies-studio/shot/doc";
13
- import { InspectorSection } from "@dailies-studio/ui";
14
- import { useStore } from "../../../state/context.js";
15
- import { useSelectedLayers } from "../useDocWrite.js";
16
- import { useBlocksInSlot } from "./useBlocks.js";
17
-
18
- /** The default window for a palette-added entrance or exit. */
19
- const DEFAULT_FRAMES = 12;
20
-
21
- export function InOutPresets(props: { slot: BlockSlot; title: string }) {
22
- const store = useStore();
23
- const layers = useSelectedLayers();
24
- const present = useBlocksInSlot(props.slot);
25
- if (layers.length === 0) return null;
26
-
27
- // A preset counts as "on" when EVERY selected layer carries it. Partial
28
- // coverage reads as off, so one more click completes the set rather than
29
- // clearing the layers that already had it.
30
- const coverage = new Map<string, number>();
31
- for (const { block } of present) coverage.set(block.preset, (coverage.get(block.preset) ?? 0) + 1);
32
-
33
- return (
34
- <InspectorSection title={props.title} persistKey={`shot:animate:${props.slot}`}>
35
- <div className="animate-palette" role="group" aria-label={`${props.title} presets`}>
36
- {presetsForSlot(props.slot).map((preset) => {
37
- const on = (coverage.get(preset.id) ?? 0) >= layers.length;
38
- return (
39
- <button
40
- key={preset.id}
41
- type="button"
42
- className="animate-preset"
43
- aria-label={`${props.title} ${preset.label}`}
44
- aria-pressed={on}
45
- onClick={() => {
46
- if (on) store.removeBlocksByPreset(props.slot, preset.id);
47
- else store.addBlock(props.slot, preset.id, DEFAULT_FRAMES);
48
- }}
49
- >
50
- {preset.label}
51
- </button>
52
- );
53
- })}
54
- </div>
55
- </InspectorSection>
56
- );
57
- }
@@ -1,150 +0,0 @@
1
- // What the block stack ADDS UP TO on this layer, at this frame.
2
- //
3
- // ── WHY A READOUT AND NOT SEVEN MORE FIELDS ─────────────────────────────
4
- //
5
- // Blocks are DELTA writers and they compose (resolve.ts). So "what is this
6
- // layer's opacity right now" has no single author: it is the base times every
7
- // active block's contribution, and there is nothing for a field to write into
8
- // that would not have to pick one of the contributors and hide the rest. The
9
- // Design tab already solves the writable half — `setEffectiveField` compensates
10
- // a typed value back through the fold — and this is the other half: a stacked
11
- // delta model where the author can see the sum is legible, and one where they
12
- // cannot is a pile of numbers that do not match the screen.
13
- //
14
- // ── IT CANNOT DISAGREE WITH THE STAGE, BY CONSTRUCTION ─────────────────
15
- //
16
- // Every number here comes out of `resolveLayerAt`, which is the same function
17
- // the runtime writes onto the mesh and the same one the renderer samples. There
18
- // is no second fold in this file and there must never be one: a readout that
19
- // re-derived the composition would be a second answer to a question that has
20
- // exactly one, and it would drift the first time a channel gained a combinator.
21
- //
22
- // ── "WRITING" MEANS DECLARED, NOT DIFFERENT ────────────────────────────
23
- //
24
- // A channel is marked when a live block's delta CONTAINS it, not when the
25
- // folded value happens to differ from identity. The two come apart constantly:
26
- // an out-fade at its first frame writes opacity 1, and an in-fade that finished
27
- // forty frames ago still writes opacity 1 and still owns the channel. Marking
28
- // on "differs from identity" would say "nothing is animating this" one frame
29
- // before a fade visibly starts, and would need a second copy of resolve.ts's
30
- // identity table to say it. Declared is both cheaper and truer: the mark means
31
- // "a block governs this channel", which is exactly what an author about to type
32
- // in the Design tab needs to know.
33
- import { InspectorSection, formatValue } from "@dailies-studio/ui";
34
- import {
35
- blockProgressAt,
36
- deltaFor,
37
- layerDeltaAt,
38
- motionPresets,
39
- resolveLayerAt,
40
- } from "@dailies-studio/shot/doc";
41
- import type { Layer3D, LayerDelta } from "@dailies-studio/shot/doc";
42
- import type { Rational } from "@dailies-studio/engine";
43
- import { CHANNELS } from "../../../channels.js";
44
- import type { Channel } from "../../../channels.js";
45
- import { useShotEditor } from "../../../state/context.js";
46
- import { useInspectorFrame, useSelectedLayers } from "../useDocWrite.js";
47
-
48
- export function ResolvedChannels() {
49
- const layers = useSelectedLayers();
50
- const { sceneFrame } = useInspectorFrame();
51
- const fps = useShotEditor((s) => s.doc?.fps ?? null);
52
- // THE FIRST selected layer. A fan-out would have to answer "what is the
53
- // resolved opacity of four layers", which is either four readouts or a
54
- // "Mixed" that tells the author nothing about the composition they came here
55
- // to understand. One subject, named in the header when there is a choice.
56
- const layer = layers[0];
57
- if (layer === undefined || fps === null) return null;
58
-
59
- const state = resolveLayerAt(layer, sceneFrame, fps);
60
- const delta = layerDeltaAt(layer, sceneFrame, fps);
61
- const writers = writersAt(layer, sceneFrame, fps);
62
-
63
- return (
64
- <InspectorSection
65
- title="Resolved"
66
- persistKey="shot:animate:resolved"
67
- action={
68
- <span className="insp-dim">
69
- {layers.length > 1 ? `${layer.label} · ` : ""}f{sceneFrame}
70
- </span>
71
- }
72
- >
73
- <dl className="resolved-list" aria-label="Resolved channels">
74
- {CHANNELS.map((channel) => {
75
- const by = writers.get(channel.key);
76
- return (
77
- <div
78
- key={channel.key}
79
- className="resolved-row"
80
- data-channel={channel.key}
81
- data-live={by !== undefined}
82
- >
83
- <dt className="resolved-label">{channel.label}</dt>
84
- <dd className="resolved-value">{channel.read(state)}</dd>
85
- <dd
86
- className="resolved-by"
87
- title={by === undefined ? undefined : `${by.join(", ")} → ${deltaText(channel.key, delta)}`}
88
- >
89
- {by?.join(", ") ?? ""}
90
- </dd>
91
- </div>
92
- );
93
- })}
94
- </dl>
95
- </InspectorSection>
96
- );
97
- }
98
-
99
- /**
100
- * Which live blocks declare each channel, by preset label.
101
- *
102
- * `blockProgressAt` + `deltaFor` is the same pair `layerDeltaAt` folds with, so
103
- * a block counted here is exactly a block that contributed to the numbers
104
- * beside it — including the outside-the-window holds, which are the cases a
105
- * naive "is the playhead inside the bar" test gets wrong in both directions.
106
- */
107
- function writersAt(layer: Layer3D, sceneFrame: number, fps: Rational): Map<Channel, string[]> {
108
- const out = new Map<Channel, string[]>();
109
- for (const block of layer.blocks) {
110
- const p = blockProgressAt(block, sceneFrame, fps);
111
- if (p === null) continue;
112
- const label = motionPresets[block.preset]?.label ?? block.preset;
113
- for (const key of Object.keys(deltaFor(block.preset, block.slot, block.params, p)) as Channel[]) {
114
- const at = out.get(key);
115
- if (at === undefined) out.set(key, [label]);
116
- // Two Fades on one channel are one name: the row says WHAT governs the
117
- // channel, and the count is the dock's job.
118
- else if (!at.includes(label)) at.push(label);
119
- }
120
- }
121
- return out;
122
- }
123
-
124
- /** The fold's own contribution to one channel, in that channel's combinator's
125
- * terms — a multiply reads "×", an add reads signed. It is the answer to "how
126
- * much of this number is the blocks", which the resolved value alone hides. */
127
- function deltaText(key: Channel, d: Required<LayerDelta>): string {
128
- switch (key) {
129
- case "opacity":
130
- return `×${formatValue(d.opacity, 0.01)}`;
131
- case "offset":
132
- return d.offset.map(signed).join(", ");
133
- case "scale":
134
- return d.scale.map((v) => `×${formatValue(v, 0.01)}`).join(", ");
135
- case "tilt":
136
- return d.tilt.map((v) => `${signed(v)}°`).join(", ");
137
- case "roll":
138
- return `${signed(d.roll)}°`;
139
- case "blurPx":
140
- return `${formatValue(d.blurPx, 0.1)} px`;
141
- case "reveal":
142
- return `${formatValue(d.reveal * 100, 1)}%`;
143
- case "textPhase":
144
- return `${formatValue(d.textPhase * 100, 1)}%`;
145
- }
146
- }
147
-
148
- function signed(v: number): string {
149
- return `${v >= 0 ? "+" : ""}${formatValue(v, 0.1)}`;
150
- }
@@ -1,43 +0,0 @@
1
- // What the Animate panel reads: the selection's blocks, and the focused one.
2
- //
3
- // The focused block is `state.selectedBlock`, which the timeline dock ALSO
4
- // writes when a bar is clicked. One bit, two surfaces: clicking a bar in the
5
- // dock puts its timing and easing in the inspector, and adding a block from the
6
- // inspector focuses its bar. Two independent "which block" states would drift
7
- // apart within one session.
8
- import { useShotEditor } from "../../../state/context.js";
9
- import { useSelectedLayers } from "../useDocWrite.js";
10
- import type { AnimBlock, BlockSlot, Layer3D } from "@dailies-studio/shot/doc";
11
-
12
- export interface BlockRef {
13
- layer: Layer3D;
14
- block: AnimBlock;
15
- }
16
-
17
- /** Every block on the selection in one slot, layer-major then frame-major.
18
- * Sorted, because a fan-out across four layers otherwise lists in whatever
19
- * order each layer happened to accumulate its blocks. */
20
- export function useBlocksInSlot(slot: BlockSlot): BlockRef[] {
21
- const layers = useSelectedLayers();
22
- const out: BlockRef[] = [];
23
- for (const layer of layers) {
24
- for (const block of layer.blocks) {
25
- if (block.slot === slot) out.push({ layer, block });
26
- }
27
- }
28
- out.sort((a, b) => a.block.frame - b.block.frame || a.block.id.localeCompare(b.block.id));
29
- return out;
30
- }
31
-
32
- /** The block the timing and easing controls are about, or null. */
33
- export function useFocusedBlock(): BlockRef | null {
34
- const focused = useShotEditor((s) => s.selectedBlock);
35
- const layers = useSelectedLayers();
36
- if (focused === null) return null;
37
- const layer = layers.find((l) => l.id === focused.layerId);
38
- const block = layer?.blocks.find((b) => b.id === focused.blockId);
39
- // A block whose layer left the selection is NOT shown: the panel's subject is
40
- // the selection, and showing a stray block would let the author edit
41
- // something the canvas is not highlighting.
42
- return layer !== undefined && block !== undefined ? { layer, block } : null;
43
- }
@@ -1,172 +0,0 @@
1
- // Pick a TSL generator to paint over a model's albedo.
2
- //
3
- // ── NO GL IN HERE, AND THAT IS NOT A COMPROMISE ─────────────────────────
4
- //
5
- // The shot chrome is three-free by test, so a live preview tile would have to
6
- // live in the stage iframe and be pushed across the bridge. It would also buy
7
- // nothing: the studio already SHIPS a rendered PNG for every catalog entry
8
- // (`packages/effects/thumbs`, served at the server's own thumbs route), made by
9
- // the same generators on the same renderer. A live tile would show the same
10
- // image for more machinery and one GL context per card.
11
- //
12
- // ── WHY IT IS A DIALOG AND NOT A PANEL ──────────────────────────────────
13
- //
14
- // Picking a material is a MODE the author enters from one place and leaves the
15
- // moment they choose — the same shape `ExportDialog` has. A permanent panel
16
- // would need a permanent home in a shell whose three columns are all spoken
17
- // for, and would ask "which layer is this for?" on every render instead of
18
- // once at the point the author asked.
19
- import { useEffect, useMemo, useState } from "react";
20
- import { useShotEditor, useStore } from "../../state/context.js";
21
- import type { ComponentRow } from "../../api.js";
22
-
23
- /** The one module whose builtins are TSL generators. Paper's shaders are DOM
24
- * background layers and particles are emitters; neither is a surface a mesh
25
- * can wear, and both would be a card that produced a document the runtime
26
- * cannot resolve. */
27
- const EFFECTS_MODULE = "@dailies-studio/effects";
28
-
29
- /** Fixed shelf order, mirroring the 2D lane's Library. A category this chrome
30
- * does not know (a newer server) appends after, alphabetically, rather than
31
- * vanishing. */
32
- const CATEGORY_ORDER = ["noise", "patterns", "organic", "space", "material", "decor"];
33
-
34
- const CATEGORY_LABELS: Record<string, string> = {
35
- noise: "Noise",
36
- patterns: "Patterns",
37
- organic: "Organic",
38
- space: "Space",
39
- material: "Material",
40
- decor: "Decor",
41
- };
42
-
43
- function categoryLabel(category: string): string {
44
- return CATEGORY_LABELS[category] ?? category.charAt(0).toUpperCase() + category.slice(1);
45
- }
46
-
47
- /** A stable colour per id, for a card whose thumbnail has not been generated.
48
- * Deterministic so the same generator always wears the same placeholder. */
49
- function thumbGradient(id: string): string {
50
- let h = 2166136261;
51
- for (let i = 0; i < id.length; i += 1) {
52
- h ^= id.charCodeAt(i);
53
- h = Math.imul(h, 16777619);
54
- }
55
- h = h >>> 0;
56
- const hue1 = h % 360;
57
- const hue2 = (hue1 + 40 + ((h >>> 9) % 160)) % 360;
58
- return `linear-gradient(${(h >>> 17) % 360}deg, hsl(${hue1} 45% 30%), hsl(${hue2} 60% 55%))`;
59
- }
60
-
61
- export function MaterialPicker() {
62
- const store = useStore();
63
- const request = useShotEditor((s) => s.materialPicker);
64
- const library = useShotEditor((s) => s.library);
65
- const libraryLoaded = useShotEditor((s) => s.libraryLoaded);
66
- const [query, setQuery] = useState("");
67
-
68
- useEffect(() => {
69
- if (!libraryLoaded) void store.refreshLibrary();
70
- }, [libraryLoaded, store]);
71
-
72
- const shelves = useMemo(() => {
73
- const needle = query.trim().toLowerCase();
74
- const rows = library.filter(
75
- (row): row is ComponentRow & { effect: NonNullable<ComponentRow["effect"]> } =>
76
- row.builtin === true && row.host === "three" && row.rel === EFFECTS_MODULE && row.effect !== undefined,
77
- );
78
- const matching =
79
- needle === ""
80
- ? rows
81
- : rows.filter(
82
- (row) =>
83
- row.name.toLowerCase().includes(needle) ||
84
- row.effect.tags.some((t) => t.toLowerCase().includes(needle)),
85
- );
86
- const byCategory = new Map<string, typeof matching>();
87
- for (const row of matching) {
88
- const list = byCategory.get(row.effect.category);
89
- if (list) list.push(row);
90
- else byCategory.set(row.effect.category, [row]);
91
- }
92
- return [...byCategory.entries()].sort((a, b) => {
93
- const ai = CATEGORY_ORDER.indexOf(a[0]);
94
- const bi = CATEGORY_ORDER.indexOf(b[0]);
95
- if (ai === bi) return a[0].localeCompare(b[0]);
96
- // An unknown category sorts after every known one rather than at the top.
97
- return (ai < 0 ? CATEGORY_ORDER.length : ai) - (bi < 0 ? CATEGORY_ORDER.length : bi);
98
- });
99
- }, [library, query]);
100
-
101
- if (request === null) return null;
102
- const count = request.layerIds.length;
103
-
104
- return (
105
- <div className="dialog-overlay" onPointerDown={() => store.closeMaterialPicker()}>
106
- <div
107
- className="dialog material-picker"
108
- role="dialog"
109
- aria-label="Choose a material"
110
- onPointerDown={(e) => e.stopPropagation()}
111
- >
112
- <div className="dialog-title">Material</div>
113
- <div className="dialog-field">
114
- <span className="dialog-label">{count === 1 ? "1 mesh layer" : `${count} mesh layers`}</span>
115
- <input
116
- className="material-search"
117
- type="search"
118
- placeholder="Search materials"
119
- value={query}
120
- onChange={(e) => setQuery(e.target.value)}
121
- autoFocus
122
- />
123
- </div>
124
- <div className="dialog-body">
125
- {!libraryLoaded ? (
126
- <p className="dialog-message">Loading…</p>
127
- ) : shelves.length === 0 ? (
128
- <p className="dialog-message">No material matches “{query}”.</p>
129
- ) : (
130
- shelves.map(([category, rows]) => (
131
- <section key={category} className="material-shelf">
132
- <h3>{categoryLabel(category)}</h3>
133
- <div className="material-grid">
134
- {rows.map((row) => (
135
- <button
136
- key={row.id}
137
- type="button"
138
- className="material-card"
139
- title={
140
- row.effect.softwareRaster === "unfinished"
141
- ? `${row.name} — may not finish a software-rasterized render (--gl swangle); use --gl angle.`
142
- : row.name
143
- }
144
- onClick={() => store.applyMeshMaterial(request.layerIds, row.id)}
145
- >
146
- {row.effect.thumb === undefined ? (
147
- <span className="material-thumb" style={{ background: thumbGradient(row.id) }} />
148
- ) : (
149
- <img className="material-thumb" src={row.effect.thumb} alt="" />
150
- )}
151
- <span className="material-name">{row.name}</span>
152
- {row.effect.softwareRaster === "unfinished" ? (
153
- <span className="material-badge" aria-hidden="true">
154
- slow
155
- </span>
156
- ) : null}
157
- </button>
158
- ))}
159
- </div>
160
- </section>
161
- ))
162
- )}
163
- </div>
164
- <div className="dialog-actions">
165
- <button type="button" onClick={() => store.closeMaterialPicker()}>
166
- Cancel
167
- </button>
168
- </div>
169
- </div>
170
- </div>
171
- );
172
- }
@@ -1,145 +0,0 @@
1
- // The SCENE LANE: scenes back to back over the master strip.
2
- //
3
- // Slim and secondary, and the ONLY home for the three verbs that are about
4
- // scenes rather than about time — create, reorder, trim. The tracks below show
5
- // every scene at once now, so this lane no longer decides what is on screen; it
6
- // is the handle on the document's coarsest structure, sitting directly above the
7
- // boundaries it draws.
8
- //
9
- // A bar's WIDTH is `scene.durationFrames` and its POSITION is a prefix sum over
10
- // `doc.scenes` — derived, never stored. So trimming a bar writes one field and
11
- // every bar after it moves for free, and reordering is a splice. Storing
12
- // per-scene offsets would desync on both, and the desync only shows up in an
13
- // export.
14
- import { frameToPx, startDrag } from "@dailies-studio/timeline";
15
- import type { PointerEvent as ReactPointerEvent } from "react";
16
- import { useShotEditor, useStore } from "../../state/context.js";
17
- import { frameDelta, sceneBars } from "./model.js";
18
-
19
- /** Its own component so the per-frame tick re-renders one absolutely
20
- * positioned div, not every scene bar above it. */
21
- function ScenePlayhead({ ppf }: { ppf: number }) {
22
- const frame = useShotEditor((s) => s.frame);
23
- return <div className="scene-playhead" style={{ left: frameToPx(frame, ppf) }} />;
24
- }
25
-
26
- export function SceneStrip({ ppf, labelWidth }: { ppf: number; labelWidth: number }) {
27
- const store = useStore();
28
- const doc = useShotEditor((s) => s.doc);
29
- const sceneId = useShotEditor((s) => s.sceneId);
30
- if (doc === null) return null;
31
- const bars = sceneBars(doc);
32
-
33
- return (
34
- <div className="scene-strip" data-testid="scene-strip">
35
- <div className="scene-strip-label" style={{ width: labelWidth }}>
36
- <span>Shots</span>
37
- <button
38
- type="button"
39
- className="scene-strip-add"
40
- aria-label="Add shot"
41
- title="Add a shot at the end, and go to it"
42
- onClick={() => store.addScene()}
43
- >
44
- +
45
- </button>
46
- </div>
47
- <div className="scene-strip-lane">
48
- {bars.map((bar, index) => (
49
- <div
50
- key={bar.id}
51
- className={`scene-bar${bar.id === sceneId ? " is-current" : ""}`}
52
- style={{ left: frameToPx(bar.start, ppf), width: Math.max(8, frameToPx(bar.end - bar.start, ppf)) }}
53
- data-scene={bar.id}
54
- draggable
55
- onDragStart={(e) => e.dataTransfer.setData("text/plain", bar.id)}
56
- onDragOver={(e) => e.preventDefault()}
57
- onDrop={(e) => {
58
- e.preventDefault();
59
- const from = e.dataTransfer.getData("text/plain");
60
- if (from.length > 0 && from !== bar.id) store.reorderScene(from, index);
61
- }}
62
- onClick={() => {
63
- // Clicking a scene both SELECTS it and moves the playhead into
64
- // it: the micro lane follows the playhead, so selecting without
65
- // seeking would show one scene's tracks under another's ruler.
66
- // The frame is read AT THE CLICK, not subscribed: a handler
67
- // needs the current value once, and the subscription was what
68
- // re-rendered every bar on every playback frame.
69
- store.setScene(bar.id);
70
- const frame = store.getState().frame;
71
- if (frame < bar.start || frame >= bar.end) store.seek(bar.start);
72
- }}
73
- // Zoom the dock to this shot. A COMPOUND on purpose: the single
74
- // click above fires first on both clicks, so the shot is selected
75
- // and the playhead is inside it before the lane reframes around
76
- // it. `\` (fit) is the way back out.
77
- onDoubleClick={() => store.fitDock(bar.id)}
78
- title="Double-click to zoom the timeline to this shot"
79
- >
80
- <span className="scene-bar-name">{bar.name}</span>
81
- <SceneTrimHandle
82
- onDrag={(deltaPx) => store.trimScene(bar.id, bar.end - bar.start + frameDelta(deltaPx, ppf))}
83
- onStart={() => store.beginBlockDrag()}
84
- onEnd={(commit) => store.endBlockDrag(commit)}
85
- />
86
- </div>
87
- ))}
88
- {/* The boundaries themselves. A diamond per cut, filled when the shot
89
- before it blends into the one after — strip geometry rather than bar
90
- geometry, because a transition is about the SEAM and the bars stay
91
- scene-local. Nothing after the last bar: there is no seam there. */}
92
- {bars.slice(0, -1).map((bar) => (
93
- <button
94
- key={`cut-${bar.id}`}
95
- type="button"
96
- className={`scene-cut${doc.scenesById[bar.id]?.transition !== undefined ? " is-blend" : ""}`}
97
- style={{ left: frameToPx(bar.end, ppf) }}
98
- aria-label={`Transition after ${bar.name}`}
99
- title={
100
- doc.scenesById[bar.id]?.transition === undefined
101
- ? `Cut after ${bar.name}`
102
- : `${doc.scenesById[bar.id]!.transition!.kind} after ${bar.name}`
103
- }
104
- onClick={(e) => {
105
- e.stopPropagation();
106
- // Select the OUTGOING shot: that is where the transition is
107
- // stored and where the inspector edits it. The playhead goes to
108
- // the last frame it owns, so the stage shows the frame the blend
109
- // starts from.
110
- store.setScene(bar.id);
111
- store.seek(Math.max(bar.start, bar.end - 1));
112
- }}
113
- />
114
- ))}
115
- {/* One playhead across the whole master timeline, so the macro lane
116
- always shows where the export is. */}
117
- <ScenePlayhead ppf={ppf} />
118
- </div>
119
- </div>
120
- );
121
- }
122
-
123
- function SceneTrimHandle({
124
- onStart,
125
- onDrag,
126
- onEnd,
127
- }: {
128
- onStart(): void;
129
- onDrag(deltaPx: number): void;
130
- onEnd(commit: boolean): void;
131
- }) {
132
- const onPointerDown = (e: ReactPointerEvent<HTMLSpanElement>): void => {
133
- e.preventDefault();
134
- e.stopPropagation();
135
- const startX = e.clientX;
136
- onStart();
137
- // Absolute from the PRESS, never cumulative — the same rule every drag in
138
- // this lane follows, and the reason a coalesced move cannot make it drift.
139
- startDrag(e, {
140
- onMove: (ev) => onDrag(ev.clientX - startX),
141
- onEnd: (commit) => onEnd(commit),
142
- });
143
- };
144
- return <span className="scene-trim" data-handle="scene-out" onPointerDown={onPointerDown} aria-hidden="true" />;
145
- }