@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,679 @@
1
+ // THIS USE (C4): one place that uses a component, and only what it changed.
2
+ //
3
+ // A use is named by its key (`cardUseKey`, `layerUseKey`), so every surface
4
+ // that shows one passes the same key to the same store verbs:
5
+ //
6
+ // ThisUsePanel the whole panel: the head, then every prop of the master
7
+ // with a blue dot on the ones this use changed. The
8
+ // Components right panel shows it for the use picked in Every
9
+ // use, and the board's card sheet shows it for a card.
10
+ // ThisUseBlock the head alone, over the Studio inspector's own prop rows
11
+ // for a selected component or instance layer.
12
+ // ComponentOriginPanel
13
+ // the Components right panel when a Shot door opened the
14
+ // component (C7): this use's panel, then where it sits in
15
+ // that Shot and the master's other uses.
16
+ // InTheStudioBlock
17
+ // the Studio inspector's way into Components for a selected
18
+ // component or instance layer.
19
+ //
20
+ // Writes go through `setUseProp` (one undo step, equal-to-master stores
21
+ // nothing), `resetComponentUse` (Reset all to master) and
22
+ // `detachComponentUse`. A code component's contract is loaded here, since its
23
+ // props and their defaults come from it.
24
+ //
25
+ // THE ROW IS `UsePropRow`, and the Studio inspector's override rows for a
26
+ // placed Studio-made component (ComponentSection) are this same row: one use's
27
+ // prop is one control wherever it is shown, written by one rule
28
+ // (`writeUseValue`).
29
+ import { useEffect, useMemo, useRef } from "react";
30
+ import type { ReactNode } from "react";
31
+ import { PropRow, useLocked } from "@dailies-studio/ui";
32
+ import type { PropControlAsset, ScrubHandlers } from "@dailies-studio/ui";
33
+ import {
34
+ appliedOverride,
35
+ defDurationFrames,
36
+ homeOf,
37
+ instanceExportOf,
38
+ isDefId,
39
+ type ComponentDef3D,
40
+ type ComponentUse,
41
+ type ExposedProp3D,
42
+ } from "@dailies-studio/shot/doc";
43
+ import { controlLabel, orderSpecs, type ControlSpec } from "@dailies-studio/contract";
44
+ import { framesToSeconds, type Value } from "@dailies-studio/engine";
45
+ import { COMPONENT_ICON } from "../../icons.js";
46
+ import { useShotEditor, useStore } from "../../state/context.js";
47
+ import type { ComponentUpdateRemoved, ComponentsOrigin, ComponentsSelection } from "../../state/types.js";
48
+ import {
49
+ BUILTIN_NO_MASTER,
50
+ changeLabel,
51
+ contractOfUse,
52
+ copyUpdateOf,
53
+ detachRefusal,
54
+ isBuiltinComponent,
55
+ layerUseKey,
56
+ masterValueOf,
57
+ propLabelOf,
58
+ sameUseValue,
59
+ shotLabel,
60
+ useByKey,
61
+ useKeyOf,
62
+ usePropRefusal,
63
+ useRowText,
64
+ usesOfSubject,
65
+ useTitle,
66
+ workspaceRowOf,
67
+ writeUseValue,
68
+ } from "../../state/workspace.js";
69
+ import { clock, formatDuration, lifespanOf } from "../timeline/model.js";
70
+ import { useScrub } from "../inspector/useDocWrite.js";
71
+ import { exposedRowOf, masterRowValue, outsideRangeOf, projectAssetsOf, propEditOf, shownPropValue } from "../inspector/propValue.js";
72
+ import type { ExposedRow } from "../inspector/propValue.js";
73
+
74
+ /** The master a use links to, as Components selects it. */
75
+ function masterOf(use: ComponentUse): ComponentsSelection | null {
76
+ if (use.def !== undefined) return { kind: "studio", def: use.def };
77
+ return use.component === undefined ? null : { kind: "code", module: use.component };
78
+ }
79
+
80
+ /** The use a key names in the open document, live. */
81
+ function useUse(useKey: string): ComponentUse | null {
82
+ const doc = useShotEditor((s) => s.doc);
83
+ const contracts = useShotEditor((s) => s.contracts);
84
+ return useMemo(() => (doc === null ? null : useByKey(doc, useKey, contracts)), [doc, useKey, contracts]);
85
+ }
86
+
87
+ /** A code use's contract, loaded once per module. */
88
+ function useContractOf(use: ComponentUse | null): void {
89
+ const store = useStore();
90
+ const module = use?.component ?? null;
91
+ useEffect(() => {
92
+ if (module !== null) void store.loadContract(module);
93
+ }, [store, module]);
94
+ }
95
+
96
+ /** "Phone 3D" and the master's version this use follows: the copy's own
97
+ * version for a copied definition, else the workspace's latest. */
98
+ function useMasterFacts(use: ComponentUse | null): { name: string; version: number | null } {
99
+ const doc = useShotEditor((s) => s.doc);
100
+ const library = useShotEditor((s) => s.library);
101
+ const list = useShotEditor((s) => s.workspaceComponents);
102
+ if (use === null || doc === null) return { name: "", version: null };
103
+ const sel = masterOf(use);
104
+ const row = workspaceRowOf(list, doc.id, sel);
105
+ if (use.def !== undefined) {
106
+ const def = doc.components?.[use.def];
107
+ return { name: def?.name ?? "Component", version: def?.origin?.version ?? row?.version ?? null };
108
+ }
109
+ const id = use.component ?? "";
110
+ return { name: library.find((r) => r.id === id)?.name ?? instanceExportOf(id), version: row?.version ?? null };
111
+ }
112
+
113
+ /**
114
+ * The head: "This use", where it is, what it links to, Edit master and
115
+ * Detach, and Update when the copy's source has a newer version.
116
+ */
117
+ export function ThisUseBlock(props: { useKey: string; resetAll?: boolean; note?: string }) {
118
+ const store = useStore();
119
+ const doc = useShotEditor((s) => s.doc);
120
+ const readOnly = useShotEditor((s) => s.readOnly);
121
+ const use = useUse(props.useKey);
122
+ const facts = useMasterFacts(use);
123
+ // A built-in ships inside a package: nothing to open, so no Edit master.
124
+ const builtin = useShotEditor((s) => isBuiltinComponent(s.library, use?.component));
125
+ useContractOf(use);
126
+ if (doc === null || use === null) return null;
127
+ const sel = masterOf(use);
128
+ // A code component and a board card cannot be detached. The button says so
129
+ // before it is pressed (the house refusal: dimmed, still pressable, its
130
+ // title and its press give the reason), in the store's own words.
131
+ const refused = detachRefusal(use, props.useKey);
132
+ return (
133
+ <div className="this-use-head" data-testid="this-use-head">
134
+ <div className="this-use-titles">
135
+ <span className="this-use-caps">This use</span>
136
+ <span className="this-use-title" data-testid="this-use-title">
137
+ {useTitle(doc, use)}
138
+ </span>
139
+ <span className="this-use-linked" data-testid="this-use-linked">
140
+ Linked to {facts.name} master{facts.version === null ? "" : ` v${facts.version}`}
141
+ </span>
142
+ </div>
143
+ {props.note === undefined ? null : (
144
+ <p className="this-use-help" data-testid="this-use-note">
145
+ {props.note}
146
+ </p>
147
+ )}
148
+ {/* The house row of buttons (`.insp-buttons`): 28px house buttons that
149
+ share the row by their words, as every verb row in the inspector. */}
150
+ <div className="insp-buttons">
151
+ <button
152
+ type="button"
153
+ className="btn"
154
+ data-testid="this-use-edit-master"
155
+ disabled={sel === null || builtin}
156
+ title={builtin ? BUILTIN_NO_MASTER : "Edit the master. Props without a dot follow the change."}
157
+ onClick={() => {
158
+ if (sel !== null) void store.editComponentMaster(sel);
159
+ }}
160
+ >
161
+ Edit master
162
+ </button>
163
+ <button
164
+ type="button"
165
+ className="btn"
166
+ data-testid="this-use-detach"
167
+ disabled={readOnly}
168
+ {...(refused !== null ? { "aria-disabled": true } : {})}
169
+ title={refused ?? "Make this use its own copy. It stops following the master."}
170
+ onClick={() => store.detachComponentUse(props.useKey)}
171
+ >
172
+ Detach
173
+ </button>
174
+ </div>
175
+ {props.resetAll === true ? (
176
+ <button
177
+ type="button"
178
+ className="this-use-reset-all is-inline"
179
+ data-testid="this-use-reset-all"
180
+ disabled={readOnly || use.overrides.length === 0}
181
+ onClick={() => store.resetComponentUse(props.useKey)}
182
+ >
183
+ Reset all to master
184
+ </button>
185
+ ) : null}
186
+ {use.def === undefined ? null : <UpdateAvailable defId={use.def} />}
187
+ </div>
188
+ );
189
+ }
190
+
191
+ /**
192
+ * "Update available · vN" for a copied definition whose source moved on: the
193
+ * workspace's latest for a `cpt_` copy, the Community listing's for a `cml-`
194
+ * one. A code component never has one (it is live everywhere). Before an
195
+ * update that drops props a use changed, the list of them, then Update
196
+ * anyway or Cancel. A Community update always asks first, with the same
197
+ * list read from the listing: the server writes it, so after it comes the
198
+ * list again with Revert update until the next change.
199
+ */
200
+ export function UpdateAvailable(props: { defId: string }) {
201
+ const store = useStore();
202
+ const def = useShotEditor((s) => s.doc?.components?.[props.defId]);
203
+ const list = useShotEditor((s) => s.workspaceComponents);
204
+ const listings = useShotEditor((s) => s.componentListingUpdates);
205
+ const pending = useShotEditor((s) => (s.componentUpdate?.defId === props.defId ? s.componentUpdate : null));
206
+ const applied = useShotEditor((s) => (s.componentUpdated?.defId === props.defId ? s.componentUpdated : null));
207
+ const canRevert = useShotEditor((s) => s.componentUpdated !== null && s.doc === s.componentUpdated.after && !s.readOnly);
208
+ const readOnly = useShotEditor((s) => s.readOnly);
209
+ const source = def?.origin?.source ?? null;
210
+ useEffect(() => {
211
+ if (source === null) return;
212
+ if (store.getState().workspaceComponents === null) void store.refreshWorkspaceComponents();
213
+ void store.refreshListingUpdates();
214
+ }, [store, source]);
215
+ const update = copyUpdateOf(def, list, listings);
216
+ if (update === null && applied === null) return null;
217
+ return (
218
+ <div className="this-use-update" data-testid="this-use-update">
219
+ {update === null ? null : (
220
+ <div className="this-use-update-row">
221
+ <span className="use-chip" data-testid="this-use-update-chip">
222
+ Update available · v{update.version}
223
+ </span>
224
+ <button
225
+ type="button"
226
+ className="use-update-button"
227
+ data-testid="this-use-update-apply"
228
+ disabled={readOnly || pending !== null}
229
+ onClick={() => void store.updateComponentCopy(props.defId)}
230
+ >
231
+ Update
232
+ </button>
233
+ </div>
234
+ )}
235
+ {pending === null ? null : (
236
+ <div className="this-use-update-confirm" data-testid="this-use-update-confirm">
237
+ {pending.community ? (
238
+ <p className="this-use-help" data-testid="this-use-update-note">
239
+ The server writes v{pending.version} into this Project, so Undo may not take it back. Revert update can,
240
+ until your next change.
241
+ {pending.removed === null
242
+ ? ` Changes with no prop in v${pending.version} are kept aside and listed after.`
243
+ : pending.removed.length === 0
244
+ ? ""
245
+ : ` These changes have no prop in v${pending.version} and are kept aside, not applied:`}
246
+ </p>
247
+ ) : (
248
+ <p className="this-use-help" data-testid="this-use-update-note">
249
+ v{pending.version} has no prop for some changes these uses made. They are kept aside, not applied:
250
+ </p>
251
+ )}
252
+ {pending.removed === null || pending.removed.length === 0 ? null : <RemovedList removed={pending.removed} />}
253
+ <div className="insp-buttons">
254
+ <button
255
+ type="button"
256
+ className="use-update-button"
257
+ data-testid="this-use-update-confirm-apply"
258
+ onClick={() => void store.updateComponentCopy(props.defId, true)}
259
+ >
260
+ {pending.removed === null || pending.removed.length === 0 ? "Update" : "Update anyway"}
261
+ </button>
262
+ <button
263
+ type="button"
264
+ className="btn"
265
+ data-testid="this-use-update-cancel"
266
+ onClick={() => store.cancelComponentUpdate()}
267
+ >
268
+ Cancel
269
+ </button>
270
+ </div>
271
+ </div>
272
+ )}
273
+ {applied === null ? null : (
274
+ <div className="this-use-update-confirm" data-testid="this-use-updated">
275
+ <p className="this-use-help" data-testid="this-use-updated-note">
276
+ Updated to v{applied.version}.
277
+ {applied.removed.length === 0 ? "" : " These changes have no prop in it and are kept aside, not applied:"}
278
+ </p>
279
+ {applied.removed.length === 0 ? null : <RemovedList removed={applied.removed} />}
280
+ <div className="insp-buttons">
281
+ {canRevert ? (
282
+ <button
283
+ type="button"
284
+ className="use-update-button"
285
+ data-testid="this-use-update-revert"
286
+ onClick={() => store.revertComponentUpdate()}
287
+ >
288
+ Revert update
289
+ </button>
290
+ ) : null}
291
+ <button
292
+ type="button"
293
+ className="btn"
294
+ data-testid="this-use-updated-done"
295
+ onClick={() => store.cancelComponentUpdate()}
296
+ >
297
+ Done
298
+ </button>
299
+ </div>
300
+ </div>
301
+ )}
302
+ </div>
303
+ );
304
+ }
305
+
306
+ function RemovedList(props: { removed: readonly ComponentUpdateRemoved[] }) {
307
+ return (
308
+ <ul className="this-use-removed">
309
+ {props.removed.map((r) => (
310
+ <li key={r.where} data-testid="this-use-removed">
311
+ <span className="this-use-removed-where">{r.where}</span>
312
+ <span className="this-use-removed-keys">{r.keys.join(", ")}</span>
313
+ </li>
314
+ ))}
315
+ </ul>
316
+ );
317
+ }
318
+
319
+ /** One prop of a master, as a use's row draws it. A definition's carries the
320
+ * exposed record and the definition, which a stored override is read
321
+ * against (`appliedOverride`: its `renamedFrom` keys, its target). */
322
+ interface MasterProp extends ExposedRow {
323
+ exposed?: { prop: ExposedProp3D; def: ComponentDef3D };
324
+ }
325
+
326
+ /** The master's props, as rows: a definition's exposed props, each from what
327
+ * it drives (`exposedRowOf`), or a code component's contract keys in its own
328
+ * order (the live contract, else a placed layer's snapshot), every kind
329
+ * listed (a slot or an event reads "set in code", as it does in the Studio).
330
+ * Null while a code component's contract is not in reach. */
331
+ function useMasterProps(use: ComponentUse | null): MasterProp[] | null {
332
+ const doc = useShotEditor((s) => s.doc);
333
+ const contracts = useShotEditor((s) => s.contracts);
334
+ return useMemo(() => {
335
+ if (use === null || doc === null) return [];
336
+ if (use.def !== undefined) {
337
+ const def = doc.components?.[use.def];
338
+ if (def === undefined) return [];
339
+ return def.exposed.map((prop) => ({ ...exposedRowOf(prop, def, doc.materials, contracts), exposed: { prop, def } }));
340
+ }
341
+ const contract = contractOfUse(doc, contracts, use);
342
+ if (contract === null) return null;
343
+ return orderSpecs(contract).map((spec) => ({ spec, opaqueColor: false, undescribed: false }));
344
+ }, [use, doc, contracts]);
345
+ }
346
+
347
+ /** What one use stores for one prop that reaches the screen: a definition's
348
+ * override as the renderer writes it (`appliedOverride`: under a
349
+ * `renamedFrom` key too, and nothing for a value it quarantines, whose row
350
+ * follows the master as the usage index counts it), or a code use's prop. */
351
+ function storedOf(use: ComponentUse, prop: MasterProp): Value | undefined {
352
+ return prop.exposed !== undefined
353
+ ? appliedOverride(prop.exposed.def, prop.exposed.prop, use.values)?.value
354
+ : use.values[prop.spec.key];
355
+ }
356
+
357
+ /**
358
+ * THE WHOLE PANEL: the head, then every prop of the master. A prop this use
359
+ * changed wears the blue dot and its own Reset; the rest follow the master.
360
+ */
361
+ export function ThisUsePanel(props: { useKey: string; note?: string; propsLabel?: string; children?: ReactNode }) {
362
+ const store = useStore();
363
+ const doc = useShotEditor((s) => s.doc);
364
+ const contracts = useShotEditor((s) => s.contracts);
365
+ const readOnly = useShotEditor((s) => s.readOnly);
366
+ const use = useUse(props.useKey);
367
+ const masterProps = useMasterProps(use);
368
+ const assetTable = doc?.assets;
369
+ const assets = useMemo(() => projectAssetsOf(assetTable), [assetTable]);
370
+ // A contract never arrives for a component the registry no longer has: once
371
+ // the registry has answered without it, the panel says so rather than
372
+ // reading for ever.
373
+ const unlisted = useShotEditor(
374
+ (s) => s.libraryLoaded && use?.component !== undefined && !s.library.some((r) => r.id === use.component),
375
+ );
376
+ if (use === null || doc === null) {
377
+ return (
378
+ <section className="this-use" data-testid="this-use">
379
+ <p className="insp-empty" data-testid="this-use-gone">
380
+ This use is gone. It was deleted or detached.
381
+ </p>
382
+ </section>
383
+ );
384
+ }
385
+ return (
386
+ <section className="this-use" data-testid="this-use" aria-label="This use">
387
+ <ThisUseBlock useKey={props.useKey} {...(props.note === undefined ? {} : { note: props.note })} />
388
+ <div className="this-use-props">
389
+ <div className="this-use-props-head">
390
+ <span className="this-use-caps">{props.propsLabel ?? "Props"}</span>
391
+ <button
392
+ type="button"
393
+ className="this-use-reset-all"
394
+ data-testid="this-use-reset-all"
395
+ disabled={readOnly || use.overrides.length === 0}
396
+ onClick={() => store.resetComponentUse(props.useKey)}
397
+ >
398
+ Reset all to master
399
+ </button>
400
+ </div>
401
+ {masterProps === null ? (
402
+ <p className="insp-empty" data-testid="this-use-props-unread">
403
+ {unlisted
404
+ ? "This component is not in the project's registry, so its props cannot be read."
405
+ : "Reading its props…"}
406
+ </p>
407
+ ) : masterProps.length === 0 ? (
408
+ <p className="insp-empty">This component has no props.</p>
409
+ ) : (
410
+ masterProps.map((prop) => (
411
+ <UsePropRow
412
+ key={prop.spec.key}
413
+ useKey={props.useKey}
414
+ row={prop}
415
+ stored={storedOf(use, prop)}
416
+ master={masterValueOf(doc, contracts, use, prop.spec.key)}
417
+ assets={assets}
418
+ />
419
+ ))
420
+ )}
421
+ <p className="this-use-help">Blue dot: changed here only. Props without a dot follow the master when you edit it.</p>
422
+ </div>
423
+ {props.children}
424
+ </section>
425
+ );
426
+ }
427
+
428
+ /**
429
+ * C7: the right panel while a Shot door's component is on Preview. This use
430
+ * first (its props change this Shot only), then where the layer sits in the
431
+ * Shot, read-only (moving and timing it is the Studio's job), then the
432
+ * master's other uses.
433
+ */
434
+ export function ComponentOriginPanel(props: { origin: ComponentsOrigin }) {
435
+ const { origin } = props;
436
+ return (
437
+ <ThisUsePanel useKey={origin.useKey} note="Changes here apply to this Shot only." propsLabel="Props · this use">
438
+ <InTheShot useKey={origin.useKey} />
439
+ <OtherUses origin={origin} />
440
+ </ThisUsePanel>
441
+ );
442
+ }
443
+
444
+ /** "Placed at" and "On screen" for the layer a use names. */
445
+ function InTheShot(props: { useKey: string }) {
446
+ const doc = useShotEditor((s) => s.doc);
447
+ const use = useUse(props.useKey);
448
+ if (doc === null || use === null || use.layerId === undefined) return null;
449
+ const container = use.sceneId ?? use.inDef ?? null;
450
+ const layer = container === null ? undefined : homeOf(doc, container)?.layersById[use.layerId];
451
+ if (container === null || layer === undefined) return null;
452
+ const def = isDefId(container) ? doc.components?.[container] : undefined;
453
+ const length = def !== undefined ? defDurationFrames(def) : (doc.scenesById[container]?.durationFrames ?? 1);
454
+ const life = lifespanOf(layer, length);
455
+ const [x, y, z] = layer.transform.position;
456
+ const round = (n: number): number => Math.round(n);
457
+ return (
458
+ <div className="this-use-props" data-testid="origin-in-the-shot">
459
+ <div className="this-use-props-head">
460
+ <span className="this-use-caps">In the Shot</span>
461
+ </div>
462
+ <dl className="origin-facts">
463
+ <dt>Placed at</dt>
464
+ <dd data-testid="origin-placed-at">
465
+ {round(x)}, {round(y)}, {round(z)}
466
+ </dd>
467
+ <dt>On screen</dt>
468
+ <dd data-testid="origin-on-screen">
469
+ {clock(life.in, doc.fps)} to {clock(life.out, doc.fps)} ·{" "}
470
+ {formatDuration(framesToSeconds(life.out - life.in, doc.fps))}
471
+ </dd>
472
+ </dl>
473
+ <p className="this-use-help">Move and time it in the Studio after Back to Shot.</p>
474
+ </div>
475
+ );
476
+ }
477
+
478
+ /** The master's other uses in this document, with what each changed. */
479
+ function OtherUses(props: { origin: ComponentsOrigin }) {
480
+ const doc = useShotEditor((s) => s.doc);
481
+ const contracts = useShotEditor((s) => s.contracts);
482
+ const { sel, useKey } = props.origin;
483
+ const others = useMemo(
484
+ () => (doc === null ? [] : usesOfSubject(doc, sel, contracts).filter((u) => useKeyOf(u) !== useKey)),
485
+ [doc, sel, contracts, useKey],
486
+ );
487
+ if (doc === null) return null;
488
+ const master: Pick<ComponentUse, "def" | "component"> = sel.kind === "studio" ? { def: sel.def } : { component: sel.module };
489
+ const labelOf = (key: string): string => propLabelOf(doc, contracts, master, key);
490
+ return (
491
+ <div className="this-use-props" data-testid="origin-other-uses">
492
+ <div className="this-use-props-head">
493
+ <span className="this-use-caps">Other uses</span>
494
+ </div>
495
+ {others.length === 0 ? (
496
+ <p className="insp-empty">Only used here.</p>
497
+ ) : (
498
+ <ul className="origin-uses">
499
+ {others.map((u) => {
500
+ const text = useRowText(doc, u);
501
+ return (
502
+ <li key={useKeyOf(u)} className="origin-use" data-testid="origin-other-use">
503
+ <span className="origin-use-title">{text.title}</span>
504
+ <span className="origin-use-changes">{changeLabel(u, labelOf)}</span>
505
+ </li>
506
+ );
507
+ })}
508
+ </ul>
509
+ )}
510
+ </div>
511
+ );
512
+ }
513
+
514
+ /**
515
+ * THE STUDIO'S WAY INTO COMPONENTS for one selected component or instance
516
+ * layer: it opens that component standalone, on Preview, with Back to Shot
517
+ * (`openComponentContext`, the double-click's verb).
518
+ */
519
+ export function InTheStudioBlock(props: { sceneId: string; layerId: string }) {
520
+ const store = useStore();
521
+ const doc = useShotEditor((s) => s.doc);
522
+ const use = useUse(layerUseKey(props.sceneId, props.layerId));
523
+ const facts = useMasterFacts(use);
524
+ const builtin = useShotEditor((s) => isBuiltinComponent(s.library, use?.component));
525
+ if (doc === null || use === null) return null;
526
+ return (
527
+ <div className="in-the-studio" data-testid="in-the-studio">
528
+ <span className="this-use-caps">In the Studio · {shotLabel(doc, props.sceneId)}</span>
529
+ <div className="in-the-studio-row">
530
+ <span className="in-the-studio-icon" aria-hidden="true">
531
+ {COMPONENT_ICON}
532
+ </span>
533
+ <span className="in-the-studio-name" data-testid="in-the-studio-name">
534
+ {facts.name}
535
+ </span>
536
+ </div>
537
+ <button
538
+ type="button"
539
+ className="in-the-studio-open"
540
+ data-testid="open-in-components"
541
+ disabled={builtin}
542
+ title={builtin ? BUILTIN_NO_MASTER : "See it alone in Components"}
543
+ onClick={() => void store.openComponentContext(props.layerId)}
544
+ >
545
+ Open in Components →
546
+ </button>
547
+ <p className="this-use-help">Or double-click it on the stage. Both land here.</p>
548
+ </div>
549
+ );
550
+ }
551
+
552
+ /** What an animated prop's row says, read-only. */
553
+ const ANIMATED_HERE = "Animated in the Shot: edit it there";
554
+
555
+ /**
556
+ * A use's DRAG, through the same rule as its commit (`writeUseValue`), inside
557
+ * the store's scrub bracket, so the whole gesture is one undo step. A refusal
558
+ * (a locked layer, a value the prop cannot hold) writes nothing and is said
559
+ * ONCE, at the release, rather than per pointer event or not at all: a thumb
560
+ * that moved while the document did not, with no reason given, read as a
561
+ * broken control.
562
+ */
563
+ function useUseScrub(useKey: string, spec: ControlSpec, fallback: unknown): ScrubHandlers {
564
+ const store = useStore();
565
+ const refusal = useRef<string | null>(null);
566
+ const scrub = useScrub((doc, raw) => {
567
+ const edit = propEditOf(spec, raw, fallback);
568
+ if (edit.kind === "refused") {
569
+ refusal.current = edit.reason;
570
+ return doc;
571
+ }
572
+ const out = writeUseValue(doc, store.getState().contracts, useKey, spec.key, edit.kind === "set" ? edit.value : null);
573
+ refusal.current = out.refusal;
574
+ return out.doc;
575
+ });
576
+ return {
577
+ ...scrub,
578
+ end: (commit) => {
579
+ scrub.end(commit);
580
+ if (commit && refusal.current !== null) store.reportError(refusal.current);
581
+ refusal.current = null;
582
+ },
583
+ };
584
+ }
585
+
586
+ /**
587
+ * ONE PROP OF ONE USE: the master's value until this use changes it, then the
588
+ * blue dot and its own Reset. The board's component sheet, Components' THIS
589
+ * USE and the Studio inspector's override rows for a placed Studio-made
590
+ * component (ComponentSection) all draw this row.
591
+ *
592
+ * READ-ONLY, with the reason, for a prop the use cannot change here: an
593
+ * animated instance prop (only its keyframes change it, in the Shot), and a
594
+ * prop nothing in reach can describe (`ExposedRow.undescribed`).
595
+ */
596
+ export function UsePropRow(props: {
597
+ useKey: string;
598
+ row: ExposedRow;
599
+ /** What the use stores for the prop that reaches the screen (`storedOf`:
600
+ * read through `renamedFrom`, a quarantined value read as none). */
601
+ stored: Value | undefined;
602
+ /** The master's value (`masterValueOf`): what the use follows while it
603
+ * stores nothing, and what a value equal to it is stored as. */
604
+ master: Value | undefined;
605
+ assets: readonly PropControlAsset[];
606
+ }) {
607
+ const { useKey, row, stored, master } = props;
608
+ const { spec } = row;
609
+ const store = useStore();
610
+ const locked = useLocked();
611
+ const label = controlLabel(spec);
612
+ const animated = useShotEditor((s) => (s.doc === null ? null : usePropRefusal(s.doc, useKey, spec.key, label)));
613
+ // What the row shows while the use stores nothing: the master's value, what
614
+ // this use draws then (`masterRowValue`), so an inherited row reads what is
615
+ // on screen even after the master's field was edited on its own layer.
616
+ const fallback = masterRowValue(spec, master);
617
+ const changed = stored !== undefined && !(master !== undefined && sameUseValue(stored, master, spec.kind));
618
+ const scrub = useUseScrub(useKey, spec, fallback);
619
+ const commit = (raw: unknown): void => {
620
+ const edit = propEditOf(spec, raw, fallback);
621
+ if (edit.kind === "refused") store.reportError(edit.reason);
622
+ else store.setUseProp(useKey, spec.key, edit.kind === "set" ? edit.value : null);
623
+ };
624
+ const readOnly = animated !== null || row.undescribed;
625
+ // A stored value outside a range the component narrowed (or a hand edit
626
+ // put there), said under the row with the verb that brings it inside.
627
+ // Not while the row is read-only: an animated prop's keyframes are its
628
+ // value, and an undescribed one has no range to speak of.
629
+ const outside = readOnly ? null : outsideRangeOf(spec, stored);
630
+ return (
631
+ <PropRow
632
+ spec={spec}
633
+ value={shownPropValue(spec, stored ?? fallback)}
634
+ commit={commit}
635
+ scrub={scrub}
636
+ changed={changed}
637
+ inherited={stored === undefined}
638
+ // A stored value is an opinion even when it matches the master, and
639
+ // only a clear makes the use follow the master's next edit. An animated
640
+ // prop's clear is refused by the write itself, so it offers none.
641
+ {...(stored !== undefined && animated === null
642
+ ? {
643
+ reset: {
644
+ onReset: () => store.setUseProp(useKey, spec.key, null),
645
+ title: "Follow the master again",
646
+ props: { "data-testid": `this-use-reset-${spec.key}` },
647
+ },
648
+ }
649
+ : {})}
650
+ {...(readOnly ? { readOnly: true } : {})}
651
+ {...(animated !== null ? { keyed: true } : {})}
652
+ {...(row.opaqueColor ? { opaqueColor: true } : {})}
653
+ notice={
654
+ outside === null ? undefined : (
655
+ <>
656
+ <span>{outside.words}</span>
657
+ <div className="insp-buttons">
658
+ <button
659
+ type="button"
660
+ className="btn"
661
+ disabled={locked}
662
+ data-testid={`this-use-inside-${spec.key}`}
663
+ title={outside.title}
664
+ onClick={() => store.setUseProp(useKey, spec.key, outside.inside)}
665
+ >
666
+ Bring inside
667
+ </button>
668
+ </div>
669
+ </>
670
+ )
671
+ }
672
+ assets={props.assets}
673
+ rowProps={{
674
+ "data-testid": `this-use-prop-${spec.key}`,
675
+ title: animated !== null ? ANIMATED_HERE : changed ? "Changed here only" : "Follows the master",
676
+ }}
677
+ />
678
+ );
679
+ }