@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,91 @@
1
+ // THE INSPECTOR'S STATUS FOOTER, pinned under the scroller: the container the
2
+ // panel is inside, as two facts. Its place on the left ("Shot 03",
3
+ // "Component", "4 shots"), its length and rate on the right ("540 frames ·
4
+ // 30 fps").
5
+ //
6
+ // ── THE CONTAINER, NEVER THE SELECTION ─────────────────────────────────────
7
+ //
8
+ // The head above names the subject, and the subject changes with every click.
9
+ // The footer names what the subject lives IN, which is the one thing that is
10
+ // true for every selection the panel can hold: a rect inside shot 3 is still in
11
+ // shot 3, a layer picked inside a definition is still on the definition's
12
+ // clock. So the ladder is the context bits alone, in `InspectorPanel`'s order
13
+ // for containers: an open definition, then the entered shot, then the project.
14
+ // The Storyboard falls through to the project, because the board plans the
15
+ // whole film and the project's length and rate are its facts too.
16
+ //
17
+ // ── NO FOOTER IS BETTER THAN A WRONG ONE ───────────────────────────────────
18
+ //
19
+ // In Components the subject is a component, not the document, so no document
20
+ // fact describes it: the footer there is the component's own
21
+ // (`ComponentFooter`, "Made by you · private · vN"). With no document open
22
+ // there is nothing to state, and it renders nothing rather than a placeholder.
23
+ //
24
+ // The rate is `fpsLabel`, the Tool footer's own wording, and the length is in
25
+ // frames because frames are what the Project section and the Shot section
26
+ // type into.
27
+ import type { Doc3D } from "@dailies-studio/shot/doc";
28
+ import { defDurationFrames, docDurationFramesCached } from "@dailies-studio/shot/doc";
29
+ import { useShotEditor } from "../../state/context.js";
30
+ import { shotNumberOf } from "../../state/storyboardModel.js";
31
+ import { workspaceOf } from "../../state/workspace.js";
32
+ import { fpsLabel } from "../toolbar/ToolFooter.js";
33
+ import { ComponentFooter } from "../studio/ComponentSidePanel.js";
34
+
35
+ const frames = (n: number): string => `${n} ${n === 1 ? "frame" : "frames"}`;
36
+
37
+ /**
38
+ * The footer's two lines for one context, or null where no fact is true.
39
+ * Pure, so the ladder is tested without a store.
40
+ */
41
+ export function inspectorFooterFacts(
42
+ doc: Doc3D | null,
43
+ enteredScene: string | null,
44
+ editingDef: string | null,
45
+ board = false,
46
+ ): { subject: string; meta: string } | null {
47
+ if (doc === null) return null;
48
+ const rate = `${fpsLabel(doc.fps)} fps`;
49
+ if (editingDef !== null) {
50
+ const def = doc.components?.[editingDef];
51
+ if (def === undefined) return null;
52
+ return { subject: "Component", meta: `${frames(defDurationFrames(def))} · ${rate}` };
53
+ }
54
+ if (enteredScene !== null) {
55
+ const scene = doc.scenesById[enteredScene];
56
+ const index = doc.scenes.indexOf(enteredScene);
57
+ if (scene === undefined || index === -1) return null;
58
+ // On the board a Shot is numbered as its strip card is (`shotNumberOf`,
59
+ // planned shots included), so the footer and the card agree.
60
+ const number = (board ? shotNumberOf(doc, enteredScene) : null) ?? String(index + 1).padStart(2, "0");
61
+ return {
62
+ subject: `Shot ${number}`,
63
+ meta: `${frames(scene.durationFrames)} · ${rate}`,
64
+ };
65
+ }
66
+ const count = doc.scenes.length;
67
+ return {
68
+ subject: `${count} ${count === 1 ? "shot" : "shots"}`,
69
+ meta: `${frames(docDurationFramesCached(doc))} · ${rate}`,
70
+ };
71
+ }
72
+
73
+ export function InspectorFooter() {
74
+ // Stable references and primitives only. The facts are derived in render,
75
+ // which runs on a document edit or a context change and never on a frame.
76
+ const doc = useShotEditor((s) => s.doc);
77
+ const enteredScene = useShotEditor((s) => s.enteredScene);
78
+ const editingDef = useShotEditor((s) => s.editingDef);
79
+ const board = useShotEditor((s) => s.storyboardOpen);
80
+ const code = useShotEditor((s) => workspaceOf(s) === "components");
81
+ // Components states whose component it is and which version is live.
82
+ if (code) return <ComponentFooter />;
83
+ const facts = inspectorFooterFacts(doc, enteredScene, editingDef, board);
84
+ if (facts === null) return null;
85
+ return (
86
+ <footer className="inspector-footer" data-testid="inspector-footer">
87
+ <span className="inspector-footer-subject">{facts.subject}</span>
88
+ <span className="inspector-footer-meta">{facts.meta}</span>
89
+ </footer>
90
+ );
91
+ }
@@ -0,0 +1,425 @@
1
+ // WHAT THIS PANEL IS DESCRIBING, said once at the top.
2
+ //
3
+ // ── THE PANEL KNEW ITS SUBJECT AND NEVER NAMED IT ───────────────────────
4
+ //
5
+ // The rail resolves a subject on every render (`InspectorPanel`'s ladder) and
6
+ // then mounts a stack of sections whose TITLES are the only thing on screen.
7
+ // So the author read "Shot / Camera / Effects" in one context and "Transform /
8
+ // Appearance" in another, with nothing saying that the first set belongs to a
9
+ // shot and the second to the rectangle they clicked. Two subjects looked like
10
+ // two unrelated panels, and the one case where it actually matters (a layer
11
+ // selected INSIDE a component definition, where the sections are identical to
12
+ // the scene's) had no tell at all.
13
+ //
14
+ // ── THE LADDER IS `InspectorPanel`'s, NOT A SECOND OPINION ──────────────
15
+ //
16
+ // Every branch below answers the same question the panel's own fork answers,
17
+ // in the same order, so the head can never name something the sections are not
18
+ // describing. In particular the SELECTION WINS OVER `editingDef`: with a layer
19
+ // picked inside a definition the panel mounts the layer's design sections, so
20
+ // the head says "Text", not "Component". The definition is the subject only
21
+ // when nothing inside it is selected, which is exactly when
22
+ // `DefinitionSection` is what renders.
23
+ //
24
+ // ── THE NAME IS THE RENAME ──────────────────────────────────────────────
25
+ //
26
+ // For the subjects that own a rename verb (a single layer, the open shot and
27
+ // the Project) the name IS the field. That is what let the Shot section drop its Name
28
+ // row: a heading and a "Name" row two lines below it, both holding the same
29
+ // string, is the panel restating itself. The other subjects render a span,
30
+ // because a title that looks editable and is not is worse than a plain one.
31
+ import { useRef, useState } from "react";
32
+ import type { KeyboardEvent, ReactElement } from "react";
33
+ import { homeOf, maskTargetOf, visibleStills } from "@dailies-studio/shot/doc";
34
+ import {
35
+ CAMERA_ICON,
36
+ COMPONENT_ICON,
37
+ DOCK_TOOL_ICONS,
38
+ MASK_ICON,
39
+ MOTION_NOTE_ICON,
40
+ RECORD_ICON,
41
+ REFERENCE_ICONS,
42
+ SCENE_ICON,
43
+ STORYBOARD_ICON,
44
+ TRANSITION_ICON,
45
+ iconFor,
46
+ isComponentGlyph,
47
+ } from "../../icons.js";
48
+ import { wordFor } from "../../layerWords.js";
49
+ import { useShotEditor, useStore } from "../../state/context.js";
50
+ import { boardSubjectOf, cardKindOf, isReferenceId, shotNameOf, stillNameOf } from "../../state/storyboardModel.js";
51
+ import { useSelectedLayers } from "./useDocWrite.js";
52
+ import { componentEditOpen, workspaceOf } from "../../state/workspace.js";
53
+ import { framesToSeconds } from "@dailies-studio/engine";
54
+ import { formatDuration, timecode } from "../timeline/model.js";
55
+
56
+ /** The Studio face's selection: none (see `studioFace`). */
57
+ const NO_LAYERS: ReturnType<typeof useSelectedLayers> = [];
58
+
59
+ interface Rename {
60
+ ariaLabel: string;
61
+ /** The subject's identity, and the field's remount key. See `RenameField`. */
62
+ id: string;
63
+ commit(next: string): void;
64
+ }
65
+
66
+ interface Subject {
67
+ /** The stable half, shown above the name: which set of sections is about to
68
+ * be read. Not drawn on the shot's head, whose `meta` line says it. */
69
+ kind: string;
70
+ /** THE SHOT'S HEAD ONLY: a fact line under the name ("Shot 03 · 0:18"), and
71
+ * the glyph on a tile instead of bare. The open shot is the container the
72
+ * author works inside, so its head reads as a place with a size rather than
73
+ * as one more object kind. Null on every other subject. */
74
+ meta: string | null;
75
+ /** Null for a subject with no name of its own. A marker is a frame, a label
76
+ * and a colour, and the label is a field in the section below. */
77
+ name: string | null;
78
+ /** NULL FOR A SUBJECT NO GLYPH DESCRIBES. Every other one here is a thing on
79
+ * the stage or on the timeline and has a glyph the outliner already uses for
80
+ * it; the Project is the panel's own frame and had to borrow one. See the
81
+ * Project branch. */
82
+ icon: ReactElement | null;
83
+ /** Paints the glyph in the accent, the outliner's rule for the component
84
+ * family. */
85
+ component: boolean;
86
+ /** Null where no store verb renames this subject. */
87
+ rename: Rename | null;
88
+ }
89
+
90
+ /**
91
+ * The name, in place, committing on blur and on Enter.
92
+ *
93
+ * NOT `TextField`, which solves exactly this and is used for every other text
94
+ * value in the rail. It hard-codes `text-input` onto its input, and that class
95
+ * is a control pill: a `--control-h` box, a filled ground and a focus ring.
96
+ * The head's name is a TITLE that happens to be editable, which is why
97
+ * `.insp-head-rename` is transparent until it is pointed at, and the two rule
98
+ * sets would fight over height and focus paint. One bare input is cheaper than
99
+ * a second styling escape hatch on a shared widget.
100
+ *
101
+ * The two traps `TextField` documents are real and are handled the same way:
102
+ * Enter BLURS and does not also commit (the blur handler is the same closure,
103
+ * so committing here as well pushes two history entries for one keystroke and
104
+ * the first Ctrl-Z appears to do nothing), and Escape sets a ref the blur
105
+ * commit reads, because `setDraft(null)` has only been queued by the time the
106
+ * synchronous blur runs.
107
+ */
108
+ function RenameField(props: { value: string; ariaLabel: string; onCommit: (next: string) => void }) {
109
+ const [draft, setDraft] = useState<string | null>(null);
110
+ const ref = useRef<HTMLInputElement | null>(null);
111
+ const cancelling = useRef(false);
112
+
113
+ const commit = (): void => {
114
+ if (cancelling.current) {
115
+ cancelling.current = false;
116
+ setDraft(null);
117
+ return;
118
+ }
119
+ if (draft === null) return;
120
+ setDraft(null);
121
+ if (draft !== props.value) props.onCommit(draft);
122
+ };
123
+
124
+ const onKeyDown = (e: KeyboardEvent<HTMLInputElement>): void => {
125
+ if (e.key === "Enter") ref.current?.blur();
126
+ else if (e.key === "Escape") {
127
+ cancelling.current = true;
128
+ ref.current?.blur();
129
+ }
130
+ };
131
+
132
+ return (
133
+ <input
134
+ ref={ref}
135
+ className="insp-head-rename"
136
+ type="text"
137
+ value={draft ?? props.value}
138
+ aria-label={props.ariaLabel}
139
+ onChange={(e) => setDraft(e.target.value)}
140
+ onBlur={commit}
141
+ onKeyDown={onKeyDown}
142
+ />
143
+ );
144
+ }
145
+
146
+ export function InspectorHead() {
147
+ const store = useStore();
148
+ const doc = useShotEditor((s) => s.doc);
149
+ const sceneId = useShotEditor((s) => s.sceneId);
150
+ const editingDef = useShotEditor((s) => s.editingDef);
151
+ /** Inside a shot. NOT `sceneId !== null`, which is never null with a document
152
+ * open: this is the context bit, written only by enter/leave. */
153
+ const inShot = useShotEditor((s) => s.enteredScene !== null);
154
+ const selectedMarker = useShotEditor((s) => s.selectedMarker);
155
+ const focused = useShotEditor((s) => s.selectedMove);
156
+ const storyboardOpen = useShotEditor((s) => s.storyboardOpen);
157
+ const storyboardSelection = useShotEditor((s) => s.storyboardSelection);
158
+ // Components' Preview tab names the definition whatever is selected inside
159
+ // it: `InspectorPanel`'s rule, so the head and the stack agree.
160
+ const studioFace = useShotEditor(
161
+ (s) => workspaceOf(s) === "components" && s.codeComponent === null && !componentEditOpen(s),
162
+ );
163
+ const selectedLayers = useSelectedLayers();
164
+ const layers = studioFace ? NO_LAYERS : selectedLayers;
165
+ if (doc === null) return null;
166
+
167
+ // RESOLVED, not merely selected, for both focused objects, the same rule
168
+ // `InspectorPanel` applies to each. A selection pointing at a marker or a
169
+ // camera move that an undo removed would otherwise name a subject with
170
+ // nothing behind it, while the panel below had already fallen through to the
171
+ // next branch.
172
+ const marker =
173
+ selectedMarker !== null && (doc.markers ?? []).some((m) => m.id === selectedMarker);
174
+ const cameraShot =
175
+ focused !== null && focused.sceneId === sceneId
176
+ ? (doc.scenesById[focused.sceneId]?.shots.find((s) => s.id === focused.shotId) ?? null)
177
+ : null;
178
+ const scene = sceneId === null ? undefined : doc.scenesById[sceneId];
179
+ const one = layers.length === 1 ? layers[0] : undefined;
180
+
181
+ const subject = ((): Subject => {
182
+ // THE BOARD FIRST, `InspectorPanel`'s ladder: while it is open nothing on
183
+ // screen is a layer, a marker or a camera move.
184
+ if (storyboardOpen) {
185
+ const only = storyboardSelection.length === 1 ? storyboardSelection[0]! : null;
186
+ if (only !== null && isReferenceId(only)) {
187
+ const item = doc.resources?.references?.find((r) => r.id === only);
188
+ if (item !== undefined) {
189
+ return {
190
+ kind: "Reference",
191
+ name: item.label,
192
+ icon: REFERENCE_ICONS[cardKindOf(item, doc.assets)],
193
+ component: item.type === "component",
194
+ meta: null,
195
+ rename: {
196
+ ariaLabel: "Reference name",
197
+ id: `sb|${item.id}`,
198
+ commit: (label) => {
199
+ const trimmed = label.trim();
200
+ if (trimmed.length > 0) store.updateReference(item.id, { label: trimmed });
201
+ },
202
+ },
203
+ };
204
+ }
205
+ }
206
+ // NO PLANNED-SHOT BRANCH. One planned shot picked is the Plan panel's
207
+ // (`boardRightPanel`), whose head names and renames it (`PartName`), so
208
+ // this panel never shows one alone.
209
+ const board = boardSubjectOf(doc, storyboardSelection);
210
+ if (board !== null && board.kind === "cut") {
211
+ // Named by the two Shots either side, and saved on the first:
212
+ // `StoryboardCutSection` edits the outgoing Shot's transition.
213
+ const a = shotNameOf(doc, board.sceneId);
214
+ return {
215
+ kind: "Transition",
216
+ name: `Between ${a} and ${shotNameOf(doc, board.cut.incoming)}`,
217
+ icon: TRANSITION_ICON,
218
+ component: false,
219
+ meta: `Transition · saved on ${a}`,
220
+ rename: null,
221
+ };
222
+ }
223
+ if (board !== null && board.kind === "gap") {
224
+ // The move between two stills, named by them and placed by their
225
+ // times.
226
+ const stills = visibleStills(doc.scenesById[board.sceneId]!);
227
+ return {
228
+ kind: "Move",
229
+ name: `${stillNameOf(stills, board.gap.from)} → ${stillNameOf(stills, board.gap.to)}`,
230
+ icon: MOTION_NOTE_ICON,
231
+ component: false,
232
+ meta: `Move · ${shotNameOf(doc, board.sceneId)} · ${timecode(board.gap.from, doc.fps)} to ${timecode(board.gap.to, doc.fps)}`,
233
+ rename: null,
234
+ };
235
+ }
236
+ if (storyboardSelection.length > 1) {
237
+ return {
238
+ kind: "Selection",
239
+ name: `${storyboardSelection.length} items`,
240
+ icon: DOCK_TOOL_ICONS.select,
241
+ component: false,
242
+ meta: null,
243
+ rename: null,
244
+ };
245
+ }
246
+ return {
247
+ kind: "Storyboard",
248
+ name: doc.title ?? doc.name,
249
+ icon: STORYBOARD_ICON,
250
+ component: false,
251
+ meta: null,
252
+ rename: null,
253
+ };
254
+ }
255
+ if (marker && !storyboardOpen) {
256
+ // A dot in a ring is the transport grammar for a mark, and it is the one
257
+ // glyph in the set that reads as a point on a timeline rather than as a
258
+ // thing on the stage. A marker owns no icon of its own because it is not
259
+ // a layer kind.
260
+ return { kind: "Marker", name: null, icon: RECORD_ICON, component: false, meta: null, rename: null };
261
+ }
262
+ // BELOW THE SELECTION, for the same reason `editingDef` is. A camera move
263
+ // is only ever the panel's FOCUSED-OBJECT SLOT (`ShotSection` sits above
264
+ // the design stack, it does not replace it), and clicking a camera bar
265
+ // leaves the layer selection alone: the camera row never calls `select`,
266
+ // and `selectMove` clears only the marker, the keyframes and the audio.
267
+ // So with a rect selected and a camera bar focused, the head said "Camera
268
+ // move" over nine sections describing the rect. The marker branch above
269
+ // stays first because that one DOES replace the panel.
270
+ if (cameraShot !== null && layers.length === 0) {
271
+ return {
272
+ kind: "Camera move",
273
+ name: cameraShot.label,
274
+ icon: CAMERA_ICON,
275
+ component: false,
276
+ meta: null,
277
+ rename: null,
278
+ };
279
+ }
280
+ if (one !== undefined) {
281
+ // A MASK SAYS SO (gap 7, Paper page 25): "Ellipse · mask" on the mask,
282
+ // "Group · masked by Circle" on the group that holds one.
283
+ const home = homeOf(doc, editingDef ?? sceneId ?? "");
284
+ const maskId = home === null ? null : maskTargetOf(home, one.id);
285
+ const maskWord =
286
+ maskId === null ? "" : maskId === one.id ? " · mask" : ` · masked by ${home!.layersById[maskId]!.label}`;
287
+ const kind = wordFor(one) + maskWord;
288
+ return {
289
+ kind,
290
+ name: one.label,
291
+ icon: maskId === null ? iconFor(one) : MASK_ICON,
292
+ component: maskId === null && isComponentGlyph(one),
293
+ meta: null,
294
+ rename: {
295
+ ariaLabel: "Layer name",
296
+ // The CONTAINER is in the key as well as the layer id: layer ids are
297
+ // scene-local, so the same id names a different layer after the
298
+ // playhead crosses a cut or the author enters a definition. Without
299
+ // it a draft typed here would commit into whatever layer inherited
300
+ // the id. Same reasoning as the panel's `subjectKey`.
301
+ id: `${editingDef ?? sceneId ?? "-"}|${one.id}`,
302
+ commit: (label) => store.renameLayer(one.id, label),
303
+ },
304
+ };
305
+ }
306
+ if (layers.length > 1) {
307
+ // The pointer, which is what "a selection" means everywhere else in this
308
+ // chrome. The layers do not agree on a kind, so no kind glyph can stand
309
+ // for them.
310
+ return {
311
+ kind: "Selection",
312
+ name: `${layers.length} layers`,
313
+ icon: DOCK_TOOL_ICONS.select,
314
+ component: false,
315
+ meta: null,
316
+ rename: null,
317
+ };
318
+ }
319
+ if (editingDef !== null) {
320
+ const def = doc.components?.[editingDef];
321
+ // No rename here even though `renameComponent` exists: a definition's
322
+ // name is the name codegen emits, so it is edited where its other
323
+ // published facts are, in the section below.
324
+ return {
325
+ kind: "Component",
326
+ name: def?.name ?? editingDef,
327
+ icon: COMPONENT_ICON,
328
+ component: true,
329
+ meta: null,
330
+ rename: null,
331
+ };
332
+ }
333
+ if (inShot && scene !== undefined && sceneId !== null) {
334
+ // The number is the shot's place in `doc.scenes` and the length is
335
+ // `formatDuration`, the same two strings the Tool footer and the left column's
336
+ // shot rows print, so one shot is never numbered or timed two ways.
337
+ const number = String(doc.scenes.indexOf(sceneId) + 1).padStart(2, "0");
338
+ return {
339
+ kind: "Shot",
340
+ name: scene.name,
341
+ icon: SCENE_ICON,
342
+ component: false,
343
+ meta: `Shot ${number} · ${formatDuration(framesToSeconds(scene.durationFrames, doc.fps))}`,
344
+ rename: {
345
+ ariaLabel: "Shot name",
346
+ id: sceneId,
347
+ commit: (name) => store.renameScene(sceneId, name),
348
+ },
349
+ };
350
+ }
351
+ // The scene context. `title` is optional through v13, so the generated
352
+ // component name is the fallback every other surface already falls back to.
353
+ //
354
+ // ── AND NO GLYPH, BECAUSE THE BORROWED ONE READ AS A BUTTON ─────────
355
+ //
356
+ // This was `kindIcon("group")` on the argument that a Project is the one
357
+ // thing here made OF the others. The glyph for that is two offset
358
+ // rectangles, which is also the universal glyph for DUPLICATE — sitting at
359
+ // 16px immediately left of the project's name, at the top of a panel whose
360
+ // every other small square is a control, it was read as a copy button and
361
+ // reported as one.
362
+ //
363
+ // No other icon is right either: the clapperboard is a single shot's and
364
+ // reusing it names the wrong altitude, and inventing a glyph for the one
365
+ // subject that is not on the stage teaches a symbol that appears nowhere
366
+ // else. The word PROJECT is already on the line, above the name, saying the same
367
+ // thing without the ambiguity — so the head runs without one here.
368
+ return {
369
+ kind: "Project",
370
+ name: doc.title ?? doc.name,
371
+ icon: null,
372
+ component: false,
373
+ meta: null,
374
+ // The title only: `doc.name` is the generated component's name, and
375
+ // SceneDocSection's Component row is its one writer.
376
+ rename: {
377
+ ariaLabel: "Project title",
378
+ id: "project",
379
+ commit: (title) => store.setProjectTitle(title),
380
+ },
381
+ };
382
+ })();
383
+
384
+ const name =
385
+ subject.name === null ? null : subject.rename === null ? (
386
+ // The title carries the full string, because the name is the one thing
387
+ // here that ellipsises and a truncated title with no way to read it is
388
+ // the defect this head exists to stop repeating.
389
+ <span className="insp-head-name" title={subject.name}>
390
+ {subject.name}
391
+ </span>
392
+ ) : (
393
+ // KEYED ON THE SUBJECT so the draft dies with it. The head itself sits
394
+ // outside the panel's subject-keyed sections on purpose (InspectorPanel
395
+ // keys each section `${subjectKey}:${id}`; the head must not replay its
396
+ // entrance on every selection change), so this is where the
397
+ // "a draft must never commit into the next subject" rule is kept:
398
+ // crossing a cut mid-rename remounts the field and drops the text
399
+ // instead of writing shot A's name into shot B.
400
+ <RenameField
401
+ key={subject.rename.id}
402
+ value={subject.name}
403
+ ariaLabel={subject.rename.ariaLabel}
404
+ onCommit={subject.rename.commit}
405
+ />
406
+ );
407
+ const shotHead = subject.meta !== null;
408
+
409
+ return (
410
+ <div className={`insp-head${shotHead ? " is-shot" : ""}`} data-testid="insp-head">
411
+ {subject.icon === null ? null : (
412
+ <span
413
+ className={`insp-head-icon${shotHead ? " is-tile" : ""}${subject.component ? " is-component" : ""}`}
414
+ >
415
+ {subject.icon}
416
+ </span>
417
+ )}
418
+ <div className="insp-head-text">
419
+ {shotHead ? null : <span className="insp-head-kind">{subject.kind}</span>}
420
+ {name}
421
+ {shotHead ? <span className="insp-head-meta">{subject.meta}</span> : null}
422
+ </div>
423
+ </div>
424
+ );
425
+ }