@dailies-studio/shot-editor 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (432) hide show
  1. package/dist/.vite/manifest.json +382 -0
  2. package/dist/assets/AgentPanel-CQejLbiX.js +2 -0
  3. package/dist/assets/AgentPanel-DJEphah0.css +1 -0
  4. package/dist/assets/AgentQuestionDialog-BqkD0kXF.js +1 -0
  5. package/dist/assets/CodeStudio-Dv4ihHpz.js +23 -0
  6. package/dist/assets/CommentsPanel-B4yhhT1T.js +1 -0
  7. package/dist/assets/ComponentLibraryRail-Ch_dsAru.js +1 -0
  8. package/dist/assets/ComponentStage-BRhRotyH.js +1 -0
  9. package/dist/assets/CurvePane-BjFVabKX.css +1 -0
  10. package/dist/assets/CurvePane-R22WzllJ.js +1 -0
  11. package/dist/assets/ExportDialog-CWLQWTmG.js +2 -0
  12. package/dist/assets/FontPicker-DWKaYL7F.js +1 -0
  13. package/dist/assets/FontPicker-v0IOIArM.css +1 -0
  14. package/dist/assets/GenerateDrawer-Bh3SqDKt.js +2 -0
  15. package/dist/assets/InsertDrawer-Ce1fod1L.js +1 -0
  16. package/dist/assets/LibraryBrowser-D9sEGz5w.js +2 -0
  17. package/dist/assets/MakeItYoursSection-CMO4319_.js +2 -0
  18. package/dist/assets/MaterialGraphCanvas-BFzl4wWR.js +23 -0
  19. package/dist/assets/MaterialGraphCanvas-BIUD59ik.css +1 -0
  20. package/dist/assets/MaterialWorkspace-CqTWqaRA.js +14 -0
  21. package/dist/assets/PreferencesDialog-CBf9_OoD.js +1 -0
  22. package/dist/assets/PresetsSection-CUEaoCVU.js +1 -0
  23. package/dist/assets/SoundHistory-BeS8EW1h.js +1 -0
  24. package/dist/assets/SoundMode-BmcZru3i.js +3 -0
  25. package/dist/assets/StockSounds-DdAUGRYK.js +1 -0
  26. package/dist/assets/TemplateFieldSection-CaeXpLFo.js +1 -0
  27. package/dist/assets/VersionHistoryPanel-CxG6XhNP.js +1 -0
  28. package/dist/assets/board-B88EPuLO.css +1 -0
  29. package/dist/assets/board-CL-he7SL.js +3 -0
  30. package/dist/assets/components-0oOSPN0l.js +1 -0
  31. package/dist/assets/googleFontRanges-gp32wJMo.js +1 -0
  32. package/dist/assets/googleFonts-BNon6M7X.js +1 -0
  33. package/dist/assets/iconsAndAliases-DL7gXP5j.js +1863 -0
  34. package/dist/assets/index-4F5NQmI8.css +1 -0
  35. package/dist/assets/index-BGHQGV5z.js +117 -0
  36. package/dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  37. package/dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  38. package/dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  39. package/dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  40. package/dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  41. package/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  42. package/dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  43. package/dist/assets/libraryModel-CpIwfFha.js +1 -0
  44. package/dist/assets/lucide-6iK64tTB.js +9319 -0
  45. package/dist/assets/motionStamp-CH-Hew4E.js +1 -0
  46. package/dist/assets/takeMeasure-Tdg0TxEi.js +1 -0
  47. package/dist/assets/webmcp-BsB9gxWC.js +2 -0
  48. package/dist/index.html +34 -3
  49. package/package.json +12 -9
  50. package/src/addFamilies.ts +66 -0
  51. package/src/api.ts +1631 -55
  52. package/src/app/App.tsx +977 -198
  53. package/src/app/lazyPanel.tsx +137 -0
  54. package/src/app/lazySurfaces.tsx +203 -0
  55. package/src/audio/index.tsx +41 -10
  56. package/src/audio/meter.ts +485 -0
  57. package/src/audio/meterMath.ts +273 -0
  58. package/src/audio/meterStore.ts +155 -0
  59. package/src/audio/offlineMix.ts +289 -0
  60. package/src/audio/preview.ts +928 -118
  61. package/src/bridge.ts +15 -5
  62. package/src/bridgeTypes.ts +1611 -36
  63. package/src/channels.ts +17 -32
  64. package/src/fonts/googleFonts.ts +4 -0
  65. package/src/hostApi.ts +174 -0
  66. package/src/icons.tsx +770 -0
  67. package/src/layerWords.ts +61 -0
  68. package/src/main.tsx +56 -4
  69. package/src/panels/ResizeHandle.tsx +33 -43
  70. package/src/panels/agent/AgentDots.tsx +36 -0
  71. package/src/panels/agent/AgentPanel.tsx +119 -43
  72. package/src/panels/agent/AgentQuestionDialog.tsx +202 -0
  73. package/src/panels/agent/agent.css +113 -97
  74. package/src/panels/agent/agentGate.ts +35 -0
  75. package/src/panels/code/CodeDefaultsPanel.tsx +345 -0
  76. package/src/panels/code/CodeStudio.tsx +373 -0
  77. package/src/panels/code/FileTree.tsx +265 -0
  78. package/src/panels/code/codeBufferGuard.ts +52 -0
  79. package/src/panels/code/codeParts.tsx +321 -0
  80. package/src/panels/comments/CommentComposer.tsx +239 -0
  81. package/src/panels/comments/CommentThread.tsx +346 -0
  82. package/src/panels/comments/CommentsPanel.tsx +336 -0
  83. package/src/panels/comments/InboxButton.tsx +131 -0
  84. package/src/panels/comments/MentionMenu.tsx +98 -0
  85. package/src/panels/comments/parts.tsx +171 -0
  86. package/src/panels/export/ExportDialog.tsx +919 -96
  87. package/src/panels/export/ExportScrim.tsx +57 -0
  88. package/src/panels/files/AssetsTab.tsx +656 -0
  89. package/src/panels/files/FilePanel.tsx +1466 -216
  90. package/src/panels/files/LayerMarks.tsx +40 -0
  91. package/src/panels/files/LeftColumn.tsx +37 -0
  92. package/src/panels/files/McpSection.tsx +690 -47
  93. package/src/panels/files/MissingAssetsNotice.tsx +60 -0
  94. package/src/panels/files/assetDrag.ts +79 -0
  95. package/src/panels/files/resourceParts.tsx +255 -0
  96. package/src/panels/fonts/FontPicker.tsx +762 -0
  97. package/src/panels/fonts/faceCache.ts +207 -0
  98. package/src/panels/fonts/fontPicker.css +271 -0
  99. package/src/panels/fonts/pickerModel.ts +265 -0
  100. package/src/panels/fonts/pickerRequest.ts +46 -0
  101. package/src/panels/header/AccountAvatar.tsx +76 -0
  102. package/src/panels/header/AgentChip.tsx +77 -0
  103. package/src/panels/header/AppMenu.tsx +213 -0
  104. package/src/panels/header/Header.tsx +564 -84
  105. package/src/panels/header/HistoryControls.tsx +31 -5
  106. package/src/panels/header/PresenceStack.tsx +329 -0
  107. package/src/panels/header/ProjectTitle.tsx +232 -0
  108. package/src/panels/header/ShareButton.tsx +59 -0
  109. package/src/panels/header/StatusBadges.tsx +358 -27
  110. package/src/panels/header/SyncDeletedDialog.tsx +88 -0
  111. package/src/panels/header/ZoomControls.tsx +46 -15
  112. package/src/panels/header/agentHandoff.ts +52 -0
  113. package/src/panels/header/leave.ts +26 -0
  114. package/src/panels/help/HelpSection.tsx +189 -163
  115. package/src/panels/insert/InsertDrawer.tsx +723 -0
  116. package/src/panels/insert/iconSet.ts +109 -0
  117. package/src/panels/inspector/ExposeDot.tsx +117 -0
  118. package/src/panels/inspector/FramingRows.tsx +314 -44
  119. package/src/panels/inspector/InspectorFooter.tsx +91 -0
  120. package/src/panels/inspector/InspectorHead.tsx +425 -0
  121. package/src/panels/inspector/InspectorPanel.tsx +408 -124
  122. package/src/panels/inspector/KeyframeDot.tsx +373 -0
  123. package/src/panels/inspector/KeyframeSection.tsx +257 -0
  124. package/src/panels/inspector/MarkerSection.tsx +55 -11
  125. package/src/panels/inspector/ParamRow.tsx +84 -53
  126. package/src/panels/inspector/RightColumn.tsx +152 -0
  127. package/src/panels/inspector/TimeSection.tsx +866 -0
  128. package/src/panels/inspector/animate/EaseControl.tsx +244 -0
  129. package/src/panels/inspector/animate/PresetsSection.tsx +135 -0
  130. package/src/panels/inspector/animate/ShotSection.tsx +562 -48
  131. package/src/panels/inspector/design/AlignRow.tsx +95 -31
  132. package/src/panels/inspector/design/AppearanceSection.tsx +118 -9
  133. package/src/panels/inspector/design/ClonerSection.tsx +323 -62
  134. package/src/panels/inspector/design/ComponentSection.tsx +50 -43
  135. package/src/panels/inspector/design/CornerSection.tsx +45 -14
  136. package/src/panels/inspector/design/DefinitionProps.tsx +315 -0
  137. package/src/panels/inspector/design/DefinitionSection.tsx +136 -0
  138. package/src/panels/inspector/design/DeviceSection.tsx +210 -0
  139. package/src/panels/inspector/design/FillSection.tsx +83 -51
  140. package/src/panels/inspector/design/FontField.tsx +196 -0
  141. package/src/panels/inspector/design/HtmlSection.tsx +23 -12
  142. package/src/panels/inspector/design/InstanceSection.tsx +373 -154
  143. package/src/panels/inspector/design/MaskSection.tsx +84 -0
  144. package/src/panels/inspector/design/MaterialSection.tsx +177 -0
  145. package/src/panels/inspector/design/MediaSection.tsx +273 -120
  146. package/src/panels/inspector/design/MeshSection.tsx +910 -82
  147. package/src/panels/inspector/design/PaintRows.tsx +550 -0
  148. package/src/panels/inspector/design/PlateStyleSection.tsx +177 -0
  149. package/src/panels/inspector/design/ShadowSection.tsx +221 -48
  150. package/src/panels/inspector/design/SplineFollowSection.tsx +235 -0
  151. package/src/panels/inspector/design/StrokeSection.tsx +228 -43
  152. package/src/panels/inspector/design/TemplateFieldSection.tsx +57 -0
  153. package/src/panels/inspector/design/TransformSection.tsx +244 -50
  154. package/src/panels/inspector/design/TypographySection.tsx +679 -110
  155. package/src/panels/inspector/layout.ts +295 -0
  156. package/src/panels/inspector/propValue.ts +199 -0
  157. package/src/panels/inspector/scene/CameraSection.tsx +232 -22
  158. package/src/panels/inspector/scene/EffectsSection.tsx +722 -71
  159. package/src/panels/inspector/scene/MakeItYoursSection.tsx +180 -0
  160. package/src/panels/inspector/scene/SceneDocSection.tsx +191 -0
  161. package/src/panels/inspector/scene/SceneSection.tsx +219 -44
  162. package/src/panels/inspector/scene/TransitionSection.tsx +523 -72
  163. package/src/panels/inspector/storyboard/StoryboardReferenceSection.tsx +593 -0
  164. package/src/panels/inspector/storyboard/VideoStill.tsx +120 -0
  165. package/src/panels/inspector/timeModel.ts +190 -0
  166. package/src/panels/inspector/useDocWrite.ts +438 -146
  167. package/src/panels/library/LibraryBrowser.tsx +435 -0
  168. package/src/panels/library/LibraryGrid.tsx +190 -0
  169. package/src/panels/library/LibraryPreviewPanel.tsx +349 -0
  170. package/src/panels/library/LibraryRail.tsx +84 -0
  171. package/src/panels/library/LibrarySoundPanel.tsx +293 -0
  172. package/src/panels/library/SoundHistory.tsx +245 -0
  173. package/src/panels/library/StockSounds.tsx +390 -0
  174. package/src/panels/library/libraryModel.ts +147 -0
  175. package/src/panels/library/stockSearch.ts +77 -0
  176. package/src/panels/maskMarks.tsx +117 -0
  177. package/src/panels/material/MaterialCommentNode.tsx +54 -0
  178. package/src/panels/material/MaterialGraphCanvas.tsx +861 -0
  179. package/src/panels/material/MaterialGraphMenu.tsx +45 -0
  180. package/src/panels/material/MaterialGroupNode.tsx +56 -0
  181. package/src/panels/material/MaterialLibrary.tsx +253 -0
  182. package/src/panels/material/MaterialNode.tsx +453 -0
  183. package/src/panels/material/MaterialNodePalette.tsx +349 -0
  184. package/src/panels/material/MaterialParameterControls.tsx +525 -0
  185. package/src/panels/material/MaterialRerouteNode.tsx +42 -0
  186. package/src/panels/material/MaterialWorkspace.tsx +501 -0
  187. package/src/panels/material/NodePreview.tsx +70 -0
  188. package/src/panels/material/flowModel.ts +441 -0
  189. package/src/panels/material/parameterValues.ts +231 -0
  190. package/src/panels/material/previewScheduler.ts +235 -0
  191. package/src/panels/material/reactFlow.css +6 -0
  192. package/src/panels/material/socketGlyph.ts +85 -0
  193. package/src/panels/material/viewportMemory.ts +58 -0
  194. package/src/panels/preferences/PreferencesDialog.tsx +215 -0
  195. package/src/panels/share/ShareComponentDialog.tsx +247 -0
  196. package/src/panels/stage/StageMenu.tsx +35 -5
  197. package/src/panels/stage/StagePanel.tsx +338 -23
  198. package/src/panels/stage/cellSlots.tsx +70 -0
  199. package/src/panels/storyboard/BoardCanvas.tsx +739 -0
  200. package/src/panels/storyboard/BoardCursors.tsx +158 -0
  201. package/src/panels/storyboard/BoardDropDialog.tsx +161 -0
  202. package/src/panels/storyboard/BoardPlan.tsx +42 -0
  203. package/src/panels/storyboard/ComponentSheet.tsx +187 -0
  204. package/src/panels/storyboard/ComponentStage.tsx +235 -0
  205. package/src/panels/storyboard/MiniSketch.tsx +173 -0
  206. package/src/panels/storyboard/PartPicker.tsx +64 -0
  207. package/src/panels/storyboard/PlanPanel.tsx +617 -0
  208. package/src/panels/storyboard/ReferencePreview.tsx +217 -0
  209. package/src/panels/storyboard/ShotBrief.tsx +360 -0
  210. package/src/panels/storyboard/ShotCard.tsx +251 -0
  211. package/src/panels/storyboard/StagePreview.tsx +348 -0
  212. package/src/panels/storyboard/StillThumbs.tsx +162 -0
  213. package/src/panels/storyboard/StoryboardView.tsx +79 -0
  214. package/src/panels/storyboard/board.css +1065 -0
  215. package/src/panels/storyboard/board.ts +12 -0
  216. package/src/panels/storyboard/boardClipboard.ts +111 -0
  217. package/src/panels/storyboard/boardOrder.ts +68 -0
  218. package/src/panels/storyboard/boardRows.tsx +425 -0
  219. package/src/panels/storyboard/liveCap.ts +90 -0
  220. package/src/panels/storyboard/plan.css +295 -0
  221. package/src/panels/storyboard/posterCache.ts +133 -0
  222. package/src/panels/storyboard/shotboard/ComponentPicker.tsx +373 -0
  223. package/src/panels/storyboard/shotboard/ImagePicker.tsx +145 -0
  224. package/src/panels/storyboard/shotboard/ShotBoard.tsx +292 -0
  225. package/src/panels/storyboard/shotboard/SketchCanvas.tsx +443 -0
  226. package/src/panels/storyboard/shotboard/SketchInspector.tsx +471 -0
  227. package/src/panels/storyboard/shotboard/SketchItem.tsx +240 -0
  228. package/src/panels/storyboard/shotboard/SketchLayers.tsx +130 -0
  229. package/src/panels/storyboard/shotboard/SketchPlay.tsx +108 -0
  230. package/src/panels/storyboard/shotboard/SketchStrip.tsx +178 -0
  231. package/src/panels/storyboard/shotboard/SketchToolFooter.tsx +99 -0
  232. package/src/panels/storyboard/shotboard/sketch.css +1392 -0
  233. package/src/panels/storyboard/shotboard/sketchModel.ts +219 -0
  234. package/src/panels/storyboard/storyboardDrop.ts +164 -0
  235. package/src/panels/studio/ComponentLibraryRail.tsx +346 -0
  236. package/src/panels/studio/ComponentSidePanel.tsx +355 -0
  237. package/src/panels/studio/ComponentStudio.tsx +243 -0
  238. package/src/panels/studio/ComponentsHome.tsx +318 -0
  239. package/src/panels/studio/ComponentsPreview.tsx +179 -0
  240. package/src/panels/studio/EveryUse.tsx +244 -0
  241. package/src/panels/studio/ThisUsePanel.tsx +679 -0
  242. package/src/panels/studio/componentParts.tsx +341 -0
  243. package/src/panels/studio/components.ts +6 -0
  244. package/src/panels/studio/newCodeComponent.ts +66 -0
  245. package/src/panels/timeline/AudioFxButton.tsx +290 -0
  246. package/src/panels/timeline/AudioLane.tsx +674 -85
  247. package/src/panels/timeline/BlockRow.tsx +154 -85
  248. package/src/panels/timeline/ChannelRow.tsx +378 -129
  249. package/src/panels/timeline/CurvePane.tsx +508 -0
  250. package/src/panels/timeline/Filmstrip.tsx +361 -0
  251. package/src/panels/timeline/GenerateDrawer.tsx +407 -0
  252. package/src/panels/timeline/KeyStretch.tsx +115 -0
  253. package/src/panels/timeline/LifespanRow.tsx +730 -47
  254. package/src/panels/timeline/MarkerLane.tsx +46 -8
  255. package/src/panels/timeline/PlayButton.tsx +91 -0
  256. package/src/panels/timeline/PropertyPicker.tsx +254 -0
  257. package/src/panels/timeline/ShotRow.tsx +400 -0
  258. package/src/panels/timeline/SoundMode.tsx +1406 -0
  259. package/src/panels/timeline/TimelineDock.tsx +2338 -272
  260. package/src/panels/timeline/TransportVolume.tsx +163 -0
  261. package/src/panels/timeline/beatRuler.ts +74 -0
  262. package/src/panels/timeline/curveModel.ts +500 -0
  263. package/src/panels/timeline/duckUnderVoice.ts +68 -0
  264. package/src/panels/timeline/keyframeMenu.ts +138 -0
  265. package/src/panels/timeline/labelWidth.ts +49 -0
  266. package/src/panels/timeline/marquee.ts +155 -0
  267. package/src/panels/timeline/model.ts +1860 -199
  268. package/src/panels/timeline/snap.ts +125 -43
  269. package/src/panels/timeline/staggerPreview.tsx +92 -0
  270. package/src/panels/timeline/takeMeasure.ts +72 -0
  271. package/src/panels/timeline/useLive.ts +48 -0
  272. package/src/panels/timeline/viewport.ts +234 -0
  273. package/src/panels/toolbar/BackChip.tsx +116 -0
  274. package/src/panels/toolbar/CameraViewBar.tsx +118 -49
  275. package/src/panels/toolbar/CanvasBar.tsx +117 -0
  276. package/src/panels/toolbar/InsertButton.tsx +38 -0
  277. package/src/panels/toolbar/IsolationTrail.tsx +156 -0
  278. package/src/panels/toolbar/PanelToggles.tsx +86 -0
  279. package/src/panels/toolbar/ShadingBar.tsx +119 -26
  280. package/src/panels/toolbar/ToolDockBar.tsx +329 -80
  281. package/src/panels/toolbar/ToolFooter.tsx +102 -0
  282. package/src/panels/toolbar/ViewModeBar.tsx +247 -38
  283. package/src/panels/toolbar/WorkPlaneBar.tsx +94 -0
  284. package/src/panels/toolbar/useAddRows.tsx +326 -0
  285. package/src/panels/toolbar/useDismiss.ts +122 -0
  286. package/src/panels/versions/VersionHistoryPanel.tsx +274 -0
  287. package/src/panels/versions/versionModel.ts +103 -0
  288. package/src/panels/virtualWindow.ts +271 -0
  289. package/src/shotTokens.css +151 -60
  290. package/src/stage/FrustumGizmo.tsx +504 -84
  291. package/src/stage/GridPlane.tsx +225 -16
  292. package/src/stage/NodePreviews.tsx +628 -0
  293. package/src/stage/PerfHud.tsx +437 -47
  294. package/src/stage/SplitRenderer.tsx +816 -169
  295. package/src/stage/StageApp.tsx +4274 -486
  296. package/src/stage/StageRootBoundary.tsx +114 -0
  297. package/src/stage/StageTools.tsx +651 -151
  298. package/src/stage/TransformGizmo.tsx +696 -0
  299. package/src/stage/adaptivePresentation.ts +145 -0
  300. package/src/stage/bridgeClient.ts +2522 -41
  301. package/src/stage/exportWorker.ts +9 -0
  302. package/src/stage/feed.ts +305 -14
  303. package/src/stage/fontPreview.ts +176 -0
  304. package/src/stage/frustumGeometry.ts +319 -1
  305. package/src/stage/furnitureTokens.ts +33 -0
  306. package/src/stage/gizmoMath.ts +508 -16
  307. package/src/stage/gpuTimer.ts +276 -0
  308. package/src/stage/instanceModules.ts +194 -33
  309. package/src/stage/interactions/move.ts +24 -5
  310. package/src/stage/isolation.ts +291 -33
  311. package/src/stage/jsSelfProfiler.ts +325 -0
  312. package/src/stage/main.tsx +116 -16
  313. package/src/stage/modalState.ts +222 -23
  314. package/src/stage/moduleEpoch.ts +60 -0
  315. package/src/stage/motionPathStage.ts +279 -0
  316. package/src/stage/motionPreview.ts +74 -0
  317. package/src/stage/overlays/Overlays.tsx +1112 -159
  318. package/src/stage/overlays/Rulers.tsx +495 -0
  319. package/src/stage/panes.ts +159 -10
  320. package/src/stage/project.ts +68 -3
  321. package/src/stage/renderScaleController.ts +730 -0
  322. package/src/stage/rulers.ts +129 -0
  323. package/src/stage/sceneExtent.ts +75 -0
  324. package/src/stage/shading.ts +20 -0
  325. package/src/stage/splineStage.ts +632 -0
  326. package/src/stage/stagePerformanceTelemetry.ts +717 -0
  327. package/src/stage/stageTheme.ts +36 -0
  328. package/src/stage/stageWarmup.ts +11 -0
  329. package/src/stage/textAutoSize.ts +124 -0
  330. package/src/stage/tier1Export.ts +641 -0
  331. package/src/stage/tokenColor.ts +14 -9
  332. package/src/stage/view.ts +56 -9
  333. package/src/stage/workingView.ts +277 -33
  334. package/src/state/accountPrefs.ts +261 -0
  335. package/src/state/agentActions.ts +173 -15
  336. package/src/state/agentActivity.ts +198 -0
  337. package/src/state/agentQuestion.ts +239 -0
  338. package/src/state/bootOpen.ts +42 -0
  339. package/src/state/cameraVerbs.ts +139 -0
  340. package/src/state/clientId.ts +6 -1
  341. package/src/state/comments.ts +1099 -0
  342. package/src/state/context.tsx +19 -1
  343. package/src/state/editorPrefs.ts +220 -0
  344. package/src/state/errorReports.ts +121 -0
  345. package/src/state/fieldWrite.ts +161 -0
  346. package/src/state/fontRecents.ts +70 -0
  347. package/src/state/fonts.ts +656 -0
  348. package/src/state/graphClipboard.ts +414 -0
  349. package/src/state/imageThumbs.ts +216 -0
  350. package/src/state/insert.ts +444 -67
  351. package/src/state/isolationTrail.ts +92 -0
  352. package/src/state/keyMoves.ts +134 -0
  353. package/src/state/keyframeClipboard.ts +177 -0
  354. package/src/state/keymap.ts +1153 -117
  355. package/src/state/layoutPrefs.ts +272 -0
  356. package/src/state/layouts.ts +205 -0
  357. package/src/state/measureMedia.ts +167 -0
  358. package/src/state/menu.ts +2341 -28
  359. package/src/state/motionStamp.ts +7 -0
  360. package/src/state/panelSize.ts +375 -5
  361. package/src/state/pendingChanges.ts +119 -0
  362. package/src/state/playHold.ts +78 -0
  363. package/src/state/playbackPreparation.ts +562 -0
  364. package/src/state/posterCapture.ts +242 -0
  365. package/src/state/presence.ts +254 -0
  366. package/src/state/projectComponents.ts +160 -0
  367. package/src/state/renderEvents.ts +298 -18
  368. package/src/state/runtimeErrors.ts +46 -0
  369. package/src/state/selection.ts +12 -0
  370. package/src/state/shortcuts.ts +1606 -0
  371. package/src/state/sketchGuide.ts +51 -0
  372. package/src/state/splineRefs.ts +87 -0
  373. package/src/state/stageHealth.ts +259 -0
  374. package/src/state/stageWatchdog.ts +47 -0
  375. package/src/state/stillStage.ts +330 -0
  376. package/src/state/stillThumbs.ts +474 -0
  377. package/src/state/store.ts +23591 -2982
  378. package/src/state/storyboardModel.ts +528 -0
  379. package/src/state/sync.ts +1257 -0
  380. package/src/state/syncCache.ts +159 -0
  381. package/src/state/triangles.ts +13 -0
  382. package/src/state/types.ts +1698 -55
  383. package/src/state/unsavedGuard.ts +49 -0
  384. package/src/state/viewMode.ts +200 -0
  385. package/src/state/webmcp.ts +1128 -0
  386. package/src/state/workspace.ts +1147 -0
  387. package/src/styles/assets-tab.css +304 -0
  388. package/src/styles/canvas.css +545 -0
  389. package/src/styles/comments.css +1435 -0
  390. package/src/styles/controls.css +162 -0
  391. package/src/styles/dialogs.css +390 -0
  392. package/src/styles/insert-drawer.css +586 -0
  393. package/src/styles/inspector-board.css +207 -0
  394. package/src/styles/inspector-object.css +486 -0
  395. package/src/styles/inspector-shot.css +252 -0
  396. package/src/styles/inspector.css +360 -0
  397. package/src/styles/left-column.css +1628 -0
  398. package/src/styles/library-preview.css +575 -0
  399. package/src/styles/library.css +512 -0
  400. package/src/styles/modes/code.css +569 -0
  401. package/src/styles/modes/component.css +1561 -0
  402. package/src/styles/modes/material.css +1201 -0
  403. package/src/styles/modes/storyboard.css +518 -0
  404. package/src/styles/share-component.css +49 -0
  405. package/src/styles/shell.css +653 -0
  406. package/src/styles/shot-brief.css +360 -0
  407. package/src/styles/states.css +76 -0
  408. package/src/styles/sync.css +380 -0
  409. package/src/styles/timeline-graph.css +384 -0
  410. package/src/styles/timeline-meters.css +89 -0
  411. package/src/styles/timeline-rows.css +1959 -0
  412. package/src/styles/timeline-sound.css +1003 -0
  413. package/src/styles/timeline.css +754 -0
  414. package/src/styles/tool-footer.css +525 -0
  415. package/src/styles/topbar.css +886 -0
  416. package/src/styles/versions.css +262 -0
  417. package/src/styles.css +72 -2921
  418. package/src/tools.ts +108 -23
  419. package/dist/assets/index-B7notge7.css +0 -1
  420. package/dist/assets/index-BBE6Ta9L.js +0 -52
  421. package/src/panels/files/icons.tsx +0 -118
  422. package/src/panels/header/DocSwitcher.tsx +0 -85
  423. package/src/panels/header/TransportBar.tsx +0 -86
  424. package/src/panels/inspector/animate/BlockTiming.tsx +0 -341
  425. package/src/panels/inspector/animate/DuringBlocks.tsx +0 -85
  426. package/src/panels/inspector/animate/InOutPresets.tsx +0 -57
  427. package/src/panels/inspector/animate/ResolvedChannels.tsx +0 -150
  428. package/src/panels/inspector/animate/useBlocks.ts +0 -43
  429. package/src/panels/material/MaterialPicker.tsx +0 -172
  430. package/src/panels/timeline/SceneStrip.tsx +0 -145
  431. package/src/panels/toolbar/AddMenu.tsx +0 -230
  432. package/src/stage/MoveGizmo.tsx +0 -411
@@ -1,67 +1,220 @@
1
- // The right rail: Design when a layer is selected, Scene when nothing is.
1
+ // The right rail: Design when a layer is selected, the container when nothing is.
2
2
  //
3
- // ── TWO MODE BITS, AND THE TAB ONLY MOVES ONE ───────────────────────────
3
+ // ── THE RAIL'S SUBJECT FOLLOWS THE CONTEXT BIT ──────────────────────────
4
4
  //
5
- // Clicking these tabs sets `inspectorMode`, which is a VIEW choice. It does NOT
6
- // set `animateMode`, which is a BEHAVIOUR choice and belongs to ⇧A alone.
7
- // Collapsing them would mean that looking at the blocks silently armed block
8
- // authoring on the next canvas drag — a data-corrupting surprise dressed as a
9
- // convenience.
5
+ // With an empty selection this panel used to mount the same four sections in
6
+ // BOTH contexts — the shot, its camera, its post stack and its transition — all
7
+ // of them reading `state.sceneId`, which is derived from the playhead. So in the
8
+ // scene context the rail described whichever shot the playhead happened to be
9
+ // over and changed under the author on every scrub across a cut, while the
10
+ // document's own fields (name, size, rate) had no panel anywhere in the chrome.
11
+ // Every other panel in this shell already branches on `state.enteredScene`;
12
+ // this one did not, which is the whole of that defect.
10
13
  //
11
- // The reverse dependency DOES exist and is deliberate: turning animate ON moves
12
- // the tab to Animate, because the author is about to author blocks and wants to
13
- // see them. One way only.
14
- import { SegmentedControl } from "@dailies-studio/ui";
15
- import { useShotEditor, useStore } from "../../state/context.js";
14
+ // The split is by WHAT THE SUBJECT IS, not by taste, and `layout.ts` states
15
+ // it once for both contexts: Camera, Project, Shot, Blur, Postprocessing. The
16
+ // one difference is the SEAM. The project context's shot is "Shot &
17
+ // transition", because a transition is a property of the join between two
18
+ // shots and that join is drawn there; inside a shot the strip is gone and the
19
+ // shot after it is off screen, so the shot section there holds the shot alone.
20
+ //
21
+ // ── ONE PANEL, DRIVEN BY WHAT IS FOCUSED — THE TABS ARE GONE ────────────
22
+ //
23
+ // There used to be a Design/Animate segmented control here and an
24
+ // `inspectorMode` bit behind it. It made sense when animation WAS blocks: two
25
+ // disjoint vocabularies, two faces. It stopped making sense when keyframes
26
+ // became the lead system, because a keyframe is not a second mode of a layer —
27
+ // it is a value of one of the design properties, authored from a diamond that
28
+ // sits in the Design row itself. An author keyframing opacity had to look at
29
+ // the opacity field on one tab and its easing on the other.
30
+ //
31
+ // So the rail is now: a FOCUSED-OBJECT SLOT at the top, then the design stack.
32
+ // At most one object is focused — the store already enforces that pairwise
33
+ // (selecting a camera move clears the keyframe and the marker, and so on) — and the
34
+ // resolution order below matches `deleteSelection`'s subject ladder exactly, so
35
+ // the panel and the Delete key can never be looking at two different things.
36
+ //
37
+ // marker -> REPLACES the panel (it has no layer subject at all)
38
+ // keyframe -> KeyframeSection on top, design stack below
39
+ // camera -> ShotSection on top, container sections below
40
+ // none -> the stack alone
41
+ //
42
+ // STACK, NEVER REPLACE, for everything but the marker: hiding the Transform
43
+ // field whose track the focused diamond belongs to would hide the one control
44
+ // the author reaches for next. The marker is the exception because it has no
45
+ // layer behind it, and the store does not clear `selection` when one is picked
46
+ // — so stacking there would show design sections for layers nobody is looking
47
+ // at.
48
+ //
49
+ // ── ⇧A SURVIVES, AS THE BEHAVIOUR BIT IT ALWAYS WAS ────────────────────
50
+ //
51
+ // `animateMode` is NOT the deleted tab. It is record mode: while it is on, an
52
+ // edit writes keyframes at the playhead instead of moving the layer's base
53
+ // value. It is bound to ⇧A and keeps its armed toolbar button. What it lost is
54
+ // the line that also moved the tab — there is no tab to move. Its feedback is
55
+ // the diamonds that appear in the Design rows and the dock.
56
+ //
57
+ // ── THE PANEL OWNS TWO THINGS NO SECTION CAN OWN ───────────────────────
58
+ //
59
+ // The SUBJECT KEY (`subjectKey` below) and the STACK ITSELF. Both are
60
+ // properties of the selection as a whole, so a section asking them of itself
61
+ // would be twenty-one sections each answering separately — and the two failures
62
+ // they close are exactly the failures of a panel that never asked: widget state
63
+ // that outlived its subject, and live controls in front of a layer none of them
64
+ // can reach.
65
+ //
66
+ // WHICH sections and in WHAT ORDER is `layout.ts`'s table, not this file's JSX,
67
+ // where it is one `Record` over the schema's own union and a contract test can
68
+ // read it. It is the CEILING and not the mount: seven sections still refuse a
69
+ // selection whose kind the table declares them for, on a count, an ordering or
70
+ // a document question that a table keyed by kind has no business restating.
71
+ // `sectionsFor`'s own doc names all seven with their exact conditions.
72
+ import type { ComponentType } from "react";
73
+ import { FieldLabels, PanelBoundary } from "@dailies-studio/ui";
74
+ import { useShotEditor } from "../../state/context.js";
16
75
  import { useSelectedLayers } from "./useDocWrite.js";
17
76
  import { TransformSection } from "./design/TransformSection.js";
77
+ import { MaskSection } from "./design/MaskSection.js";
78
+ import { SplineFollowSection } from "./design/SplineFollowSection.js";
18
79
  import { AppearanceSection } from "./design/AppearanceSection.js";
80
+ import { TimeSection } from "./TimeSection.js";
19
81
  import { FillSection } from "./design/FillSection.js";
20
82
  import { StrokeSection } from "./design/StrokeSection.js";
21
83
  import { ShadowSection } from "./design/ShadowSection.js";
22
84
  import { CornerSection } from "./design/CornerSection.js";
23
85
  import { HtmlSection } from "./design/HtmlSection.js";
24
- import { TextStaggerSection, TypographySection } from "./design/TypographySection.js";
86
+ import { TextFillSection, TypographySection } from "./design/TypographySection.js";
25
87
  import { MeshSection } from "./design/MeshSection.js";
88
+ import { MaterialSection } from "./design/MaterialSection.js";
89
+ import { DeviceSection } from "./design/DeviceSection.js";
26
90
  import { ClonerSection } from "./design/ClonerSection.js";
27
91
  import { MediaSection } from "./design/MediaSection.js";
92
+ import { PlateStyleSection } from "./design/PlateStyleSection.js";
28
93
  import { InstanceSection } from "./design/InstanceSection.js";
29
94
  import { ComponentSection } from "./design/ComponentSection.js";
95
+ import { DefinitionSection } from "./design/DefinitionSection.js";
30
96
  import { SceneSection } from "./scene/SceneSection.js";
97
+ import { SceneDocSection } from "./scene/SceneDocSection.js";
98
+ import { ShotTransitionSection, StoryboardCutSection } from "./scene/TransitionSection.js";
99
+ // A board card's section rides in the board's chunk, and the two template
100
+ // sections are chunks of their own fetched at idle (app/lazySurfaces.tsx).
101
+ import { MakeItYoursSection, PresetsSection, StoryboardReferenceSection, TemplateFieldSection } from "../../app/lazySurfaces.js";
31
102
  import { CameraSection } from "./scene/CameraSection.js";
32
- import { EffectsSection } from "./scene/EffectsSection.js";
33
- import { TransitionSection } from "./scene/TransitionSection.js";
34
- import { InOutPresets } from "./animate/InOutPresets.js";
35
- import { DuringBlocks } from "./animate/DuringBlocks.js";
36
- import { BlockTiming } from "./animate/BlockTiming.js";
37
- import { ResolvedChannels } from "./animate/ResolvedChannels.js";
103
+ import { BlurSection, PostprocessingSection } from "./scene/EffectsSection.js";
38
104
  import { ShotSection } from "./animate/ShotSection.js";
39
105
  import { MarkerSection } from "./MarkerSection.js";
40
- import { CAMERA_ROW_ID } from "../timeline/model.js";
106
+ import { KeyframeSection } from "./KeyframeSection.js";
107
+ import { InspectorHead } from "./InspectorHead.js";
108
+ import { CodeDefaultsPanel, CodeSubjectHead } from "../code/CodeDefaultsPanel.js";
109
+ import { ComponentActions, ComponentHistory } from "../studio/ComponentSidePanel.js";
110
+ import { ComponentOriginPanel, InTheStudioBlock, ThisUseBlock, ThisUsePanel } from "../studio/ThisUsePanel.js";
111
+ import {
112
+ componentEditOpen,
113
+ componentsSubject,
114
+ layerUseKey,
115
+ sameComponent,
116
+ usesViewOf,
117
+ workspaceOf,
118
+ } from "../../state/workspace.js";
119
+ import { CONTAINER_LAYOUT, sectionsFor } from "./layout.js";
120
+ import type { ContainerSectionId, ContainerSubject, SectionId } from "./layout.js";
121
+
122
+ /** The Studio face's selection: none (see `studioFace`). One array, so the
123
+ * panel's memoised readers see the same empty selection every render. */
124
+ const NO_LAYERS: ReturnType<typeof useSelectedLayers> = [];
125
+
126
+ /**
127
+ * The section id -> component map, and the only place the two vocabularies
128
+ * meet.
129
+ *
130
+ * A `Record` over `SectionId`, so a section named in `SECTION_ORDER` with no
131
+ * component behind it does not compile — the table there and this registry
132
+ * cannot drift into a layout that asks for a section this file cannot render.
133
+ */
134
+ const SECTIONS: Record<SectionId, ComponentType> = {
135
+ mask: MaskSection,
136
+ transform: TransformSection,
137
+ appearance: AppearanceSection,
138
+ time: TimeSection,
139
+ presets: PresetsSection,
140
+ mesh: MeshSection,
141
+ material: MaterialSection,
142
+ device: DeviceSection,
143
+ instance: InstanceSection,
144
+ component: ComponentSection,
145
+ cloner: ClonerSection,
146
+ media: MediaSection,
147
+ plateStyle: PlateStyleSection,
148
+ textFill: TextFillSection,
149
+ fill: FillSection,
150
+ stroke: StrokeSection,
151
+ corner: CornerSection,
152
+ shadow: ShadowSection,
153
+ typography: TypographySection,
154
+ html: HtmlSection,
155
+ templateField: TemplateFieldSection,
156
+ splineFollow: SplineFollowSection,
157
+ };
158
+
159
+ /** The container section id -> component map. A `Record` over the union, for
160
+ * `SECTIONS`' reason: a layout naming an id with no component does not
161
+ * compile. */
162
+ const CONTAINER_SECTIONS: Record<ContainerSectionId, ComponentType> = {
163
+ project: SceneDocSection,
164
+ makeItYours: MakeItYoursSection,
165
+ shot: SceneSection,
166
+ shotTransition: ShotTransitionSection,
167
+ camera: CameraSection,
168
+ blur: BlurSection,
169
+ postprocessing: PostprocessingSection,
170
+ definition: DefinitionSection,
171
+ storyboardReference: StoryboardReferenceSection,
172
+ storyboardCut: StoryboardCutSection,
173
+ };
41
174
 
42
175
  export function InspectorPanel() {
43
- const store = useStore();
44
176
  const doc = useShotEditor((s) => s.doc);
45
- const mode = useShotEditor((s) => s.inspectorMode);
46
- // The camera's row holds SHOTS, not blocks, and a shot belongs to the scene
47
- // rather than to any layer. So it is the one Animate subject that does not
48
- // come from the selection, and it wins: a bar the author just clicked is what
49
- // they are looking at.
177
+ // The Field labels pref (Preferences > Inspector): every number field in
178
+ // the inspector shows its glyph, or its full name above the pill. Only the
179
+ // inspector provides it, so toolbar fields keep their glyphs.
180
+ const fieldLabels = useShotEditor((s) => s.fieldLabels);
181
+ // A camera move belongs to the scene rather than to any layer. So it is the
182
+ // one focused subject that does not come from the selection, and it wins: a
183
+ // bar the author just clicked is what they are looking at.
50
184
  //
51
185
  // It RESOLVES THE SHOT rather than testing the row id, because this branch
52
186
  // replaces the whole tab: a focus that ShotSection cannot resolve would render
53
- // the Animate tab as literally nothing, no placeholder and no layer sections.
187
+ // the top slot as a heading over nothing, with no shot behind it.
54
188
  // Two ways to get there, both reachable — focusing a bar in one scene and
55
189
  // scrubbing into another (the panel reads the PLAYHEAD's scene), and undoing
56
190
  // the ⇧C that created the shot the focus points at.
57
191
  const cameraShot = useShotEditor((s) => {
58
- const focused = s.selectedBlock;
59
- if (focused === null || focused.layerId !== CAMERA_ROW_ID || focused.sceneId !== s.sceneId) return false;
60
- return s.doc?.scenesById[focused.sceneId]?.shots.some((shot) => shot.id === focused.blockId) ?? false;
192
+ const focused = s.selectedMove;
193
+ if (focused === null || focused.sceneId !== s.sceneId) return false;
194
+ return s.doc?.scenesById[focused.sceneId]?.shots.some((shot) => shot.id === focused.shotId) ?? false;
61
195
  });
62
- const layers = useSelectedLayers();
196
+ // ON COMPONENTS' PREVIEW TAB THE SUBJECT IS THE DEFINITION, whatever is
197
+ // selected inside it: a selection carried over from Edit, or a click on the
198
+ // subject in the hole, would otherwise swap the definition's published
199
+ // surface for one layer's sections. The Edit tab is the full inspector (a
200
+ // selected layer's sections, the definition's with nothing selected).
201
+ // `InspectorHead` reads the same rule.
202
+ const studioFace = useShotEditor(
203
+ (s) => workspaceOf(s) === "components" && s.codeComponent === null && !componentEditOpen(s),
204
+ );
205
+ /** A definition open in Components, on either tab. */
206
+ const defOpen = useShotEditor(
207
+ (s) => workspaceOf(s) === "components" && s.codeComponent === null && s.editingDef !== null,
208
+ );
209
+ const selectedLayers = useSelectedLayers();
210
+ const layers = studioFace ? NO_LAYERS : selectedLayers;
211
+ // THE BOARD IS A SUBJECT OF ITS OWN, above the layer selection: the shell
212
+ // still holds a layer selection under the board, but nothing on screen is
213
+ // that layer, and the head and the stack must describe what is on screen.
214
+ const storyboardOpen = useShotEditor((s) => s.storyboardOpen);
215
+ const storyboardKey = useShotEditor((s) => s.storyboardSelection.join(","));
63
216
  // THE FIRST SUBJECT, above the mode fork and above the selection. It matches
64
- // `deleteSelection`'s order — marker, then block, then layers — so the panel
217
+ // `deleteSelection`'s order — marker, then camera move, then layers — so the panel
65
218
  // and the Delete key can never be looking at two different things. A marker
66
219
  // is neither a design property nor an animation, so it replaces the body
67
220
  // rather than living in one of the tabs.
@@ -70,109 +223,240 @@ export function InspectorPanel() {
70
223
  // the camera branch below does: this replaces the whole panel, so a selection
71
224
  // pointing at a marker that is gone would render the rail as literally
72
225
  // nothing. Undoing the `M` that created it is the one-keystroke way there.
73
- const markerSelected = useShotEditor(
74
- (s) => s.selectedMarker !== null && (s.doc?.markers ?? []).some((m) => m.id === s.selectedMarker),
226
+ //
227
+ // Returns the ID and not a boolean, because it is also this branch's remount
228
+ // key — see `subjectKey`.
229
+ const markerId = useShotEditor((s) =>
230
+ s.selectedMarker !== null && (s.doc?.markers ?? []).some((m) => m.id === s.selectedMarker)
231
+ ? s.selectedMarker
232
+ : null,
233
+ );
234
+ // ── THE ONE KEY THAT KILLS WIDGET-LOCAL STALENESS ──────────────────────
235
+ //
236
+ // Deriving the panel is already live: nothing here is memoized, so a
237
+ // document edit repaints every row. What is NOT live is the state the shared
238
+ // widgets keep INSIDE themselves, which React happily carries across a
239
+ // selection change because neither the element type nor its position moved:
240
+ //
241
+ // ColorPicker's `picked` resyncs only when `value` changes IDENTITY, so
242
+ // selecting a second layer whose fill is the same hex string never
243
+ // resyncs the square, the hue bar or the alpha bar;
244
+ // NumberField's `draft` survives while its input holds focus, so the next
245
+ // Enter commits layer A's typed text into layer B;
246
+ // a section's own error/busy flag (HtmlSection's `syncing`,
247
+ // InstanceSection's `rebindError`) is raised against a layer and outlives
248
+ // the selection that raised it.
249
+ //
250
+ // One remount closes all three, and the key is the SUBJECT and nothing else:
251
+ //
252
+ // the SCENE, because `sceneId` follows the playhead and layer ids are
253
+ // scene-local, so the same id names a different layer after a crossing;
254
+ // the SELECTED IDS, JOINED rather than compared by array identity, because
255
+ // the store mints a fresh array on edits that do not move the selection —
256
+ // and a key on identity would remount on every one of them.
257
+ //
258
+ // Deliberately NOT in it: any value, the document rev, and the playhead
259
+ // frame. This panel re-renders on every coalesced frame and on every
260
+ // keystroke, and a key that moved with any of those would remount MID-DRAG.
261
+ // That is not cosmetic: NumberField, ColorPicker's DragArea and the store's
262
+ // scrub bracket all cancel an open gesture from their unmount effect, so
263
+ // every drag would die on its first move. A scene crossing DURING playback
264
+ // is the one remount a gesture can meet, and it is a real subject change.
265
+ const sceneId = useShotEditor((s) => s.sceneId);
266
+ const editingDef = useShotEditor((s) => s.editingDef);
267
+ /** Inside a shot. NOT `sceneId !== null`, which is never null with a document
268
+ * open: this is the context bit, written only by enter/leave. */
269
+ const inShot = useShotEditor((s) => s.enteredScene !== null);
270
+ const selectionKey = useShotEditor((s) => s.selection.join(","));
271
+ // ── CODE STUDIO'S SUBJECT: ONE CODE COMPONENT, ABOVE EVERYTHING ────────
272
+ // The stage draws that component alone, so no layer, shot or marker is on
273
+ // screen, and the panel describes the component's defaults on both faces.
274
+ // Above the document check: the subject is a file, not the document. Keyed
275
+ // on the component, so a row's widget-local draft dies with its subject.
276
+ const codeComponent = useShotEditor((s) => (workspaceOf(s) === "components" ? s.codeComponent : null));
277
+ // COMPONENTS' WAYS OUT AND ITS HISTORY (C1, C2): the actions block under the
278
+ // head, and History in the props' place while it is open.
279
+ const historyOpen = useShotEditor((s) => s.componentHistory !== null);
280
+ // THE USE PICKED IN EVERY USE (C4) is the subject while it is picked: the
281
+ // centre lists uses, so the panel describes the one in focus. Keyed on it,
282
+ // so one use's drafts never land in the next.
283
+ const pickedUse = useShotEditor((s) => usesViewOf(s)?.use ?? null);
284
+ // A SHOT DOOR'S COMPONENT ON PREVIEW (C7): the use the author came from is
285
+ // the subject, so the panel says what changes here and where it sits.
286
+ const origin = useShotEditor((s) =>
287
+ s.componentsOrigin !== null &&
288
+ workspaceOf(s) === "components" &&
289
+ s.componentsTab === "preview" &&
290
+ sameComponent(s.componentsOrigin.sel, componentsSubject(s))
291
+ ? s.componentsOrigin
292
+ : null,
75
293
  );
294
+ if (pickedUse !== null) {
295
+ return (
296
+ <aside className="inspector" data-testid="inspector">
297
+ <PanelBoundary label="Inspector">
298
+ <FieldLabels value={fieldLabels}>
299
+ <div className="inspector-body">
300
+ <ThisUsePanel key={pickedUse} useKey={pickedUse} />
301
+ </div>
302
+ </FieldLabels>
303
+ </PanelBoundary>
304
+ </aside>
305
+ );
306
+ }
307
+ if (origin !== null) {
308
+ return (
309
+ <aside className="inspector" data-testid="inspector">
310
+ <PanelBoundary label="Inspector">
311
+ <FieldLabels value={fieldLabels}>
312
+ <div className="inspector-body">
313
+ <ComponentOriginPanel key={origin.useKey} origin={origin} />
314
+ </div>
315
+ </FieldLabels>
316
+ </PanelBoundary>
317
+ </aside>
318
+ );
319
+ }
320
+ if (codeComponent !== null) {
321
+ return (
322
+ <aside className="inspector" data-testid="inspector">
323
+ <PanelBoundary label="Inspector">
324
+ <FieldLabels value={fieldLabels}>
325
+ <CodeSubjectHead componentId={codeComponent} />
326
+ <ComponentActions />
327
+ <div className="inspector-body" data-testid="code-defaults-rail">
328
+ {historyOpen ? (
329
+ <ComponentHistory />
330
+ ) : (
331
+ <CodeDefaultsPanel key={codeComponent} componentId={codeComponent} />
332
+ )}
333
+ </div>
334
+ </FieldLabels>
335
+ </PanelBoundary>
336
+ </aside>
337
+ );
338
+ }
76
339
  if (doc === null) return null;
77
- if (markerSelected) {
340
+ if (markerId !== null && !storyboardOpen) {
78
341
  return (
79
342
  <aside className="inspector" data-testid="inspector">
80
- <MarkerSection />
343
+ <PanelBoundary label="Inspector">
344
+ {/* The head renders on THIS branch too. It is the branch that
345
+ replaces the whole panel, so leaving it out would make the marker
346
+ the one subject in the rail that is never named. */}
347
+ <InspectorHead />
348
+ <div className="inspector-body">
349
+ <FieldLabels value={fieldLabels}>
350
+ <MarkerSection key={markerId} />
351
+ </FieldLabels>
352
+ </div>
353
+ </PanelBoundary>
81
354
  </aside>
82
355
  );
83
356
  }
357
+ // The open definition is part of the SUBJECT: entering or leaving one swaps
358
+ // what every section describes, which is exactly a remount.
359
+ //
360
+ // ONE SECTION IS KEYED APART, `project` (`SceneDocSection`), because the
361
+ // scene is not its subject: the project's name, size, rate and length are
362
+ // the same facts on both sides of a cut. Keying it on the scene threw away a
363
+ // name the author was mid-way through typing whenever the playhead crossed
364
+ // one. It is keyed on the CONTEXT instead, because its collapse bit and its
365
+ // default differ per context and `useCollapsed` reads them once, at mount.
366
+ const subjectKey = storyboardOpen
367
+ ? `sb|${storyboardKey}`
368
+ : `${editingDef ?? sceneId ?? "-"}|${studioFace ? "" : selectionKey}`;
369
+ // WHAT THE STACK IS A PANEL OF. Null means the selection, and otherwise the
370
+ // ladder is `InspectorHead`'s own — an open definition, then the entered
371
+ // shot, then the project the panel is a view of — so the head can never name
372
+ // something the sections below it are not describing.
373
+ const container: ContainerSubject | null = storyboardOpen
374
+ ? "storyboard"
375
+ : layers.length > 0
376
+ ? null
377
+ : editingDef !== null
378
+ ? "definition"
379
+ : inShot
380
+ ? "shot"
381
+ : "project";
84
382
 
85
383
  return (
86
384
  <aside className="inspector" data-testid="inspector">
87
- <SegmentedControl
88
- ariaLabel="Inspector mode"
89
- value={mode}
90
- options={[
91
- { value: "design", label: "Design" },
92
- { value: "animate", label: "Animate" },
93
- ]}
94
- onChange={(next) => store.setInspectorMode(next as "design" | "animate")}
95
- />
385
+ {/* INSIDE the positioned aside, per the boundary's placement rule: a
386
+ section reading an unexpected node shape shows the card here, and
387
+ the stage keeps the document's unsaved edits alive. */}
388
+ <PanelBoundary label="Inspector">
389
+ <FieldLabels value={fieldLabels}>
390
+ {/* ── WHAT THE RAIL IS LOOKING AT ──────────────────────────────────
391
+ FIRST, and OUTSIDE the subject-keyed stack below. Its own resolution
392
+ walks the same ladder this component does, so it always names the
393
+ sections that follow it; keeping it out of the key is what stops it
394
+ replaying its entrance on every selection change, and the one piece
395
+ of it that must not survive a subject change (a rename draft) is
396
+ keyed inside the head instead. It also sits OUTSIDE the scroller
397
+ below, so the subject stays named however far the stack scrolls. */}
398
+ <InspectorHead />
399
+ {defOpen && layers.length === 0 ? <ComponentActions /> : null}
400
+
401
+ <div className="inspector-body">
402
+ {defOpen && layers.length === 0 && historyOpen ? <ComponentHistory /> : <>
403
+ {/* ── THE FOCUSED-OBJECT SLOT ──────────────────────────────────────
404
+ At most one of these renders: the store keeps `selectedKeyframe`,
405
+ `selectedMove` and `selectedMarker` pairwise exclusive, and the
406
+ marker took its own branch above. Each self-gates, so with nothing
407
+ focused this whole slot is nothing at all.
408
+
409
+ NOT keyed like the stack below. Its remount key is the SUBJECT
410
+ (scene + selection), and these three are focused and cleared without
411
+ the selection moving — keying them on it would leave a stale editor
412
+ up, while folding their identity INTO the key would remount every
413
+ design section whenever a bar was clicked. Each carries its own key
414
+ instead. */}
415
+ {storyboardOpen ? null : <KeyframeSection />}
416
+ {storyboardOpen || !cameraShot ? null : <ShotSection />}
96
417
 
97
- {mode === "animate" ? (
98
- cameraShot ? (
99
- <ShotSection />
100
- ) : layers.length === 0 ? (
101
- // Nothing selected: the tab has no subject. Saying what to do beats an
102
- // empty panel that reads as broken.
103
- <p className="inspector-empty" data-testid="animate-placeholder">
104
- Select a layer to add an entrance, an exit, or a During block.
105
- </p>
106
- ) : (
107
- <>
108
- {/* First, because it is the only thing here that describes the
109
- layer rather than proposing an edit to it: what the stack adds
110
- up to at this frame is the context every choice below is made
111
- against. */}
112
- <ResolvedChannels />
113
- <InOutPresets slot="in" title="In" />
114
- <DuringBlocks />
115
- <InOutPresets slot="out" title="Out" />
116
- {/* Last, because it is about ONE block and everything above chooses
117
- which. A timing editor above the list it belongs to would read as
118
- the panel's subject rather than the focused row's. */}
119
- <BlockTiming />
120
- </>
121
- )
122
- ) : layers.length === 0 ? (
123
- <>
124
- <SceneSection />
125
- {/* Between the scene and its post stack, which is the order the
126
- picture is made in: the scene, the camera looking at it, then what
127
- happens to the frame after. */}
128
- <CameraSection />
129
- <EffectsSection />
130
- {/* …and last, what happens when the frame stops being this shot's. */}
131
- <TransitionSection />
132
- </>
133
- ) : (
134
- <>
135
- <TransformSection />
136
- <AppearanceSection />
137
- {/* Above the paint sections: a mesh's look comes from its material,
138
- and `paint` is inert on it (types.ts), so the model IS the
139
- subject the fills below have nothing to say about. */}
140
- <MeshSection />
141
- {/* Beside the model section for the same reason it sits above the
142
- paint ones: an instance paints itself, so its contract IS the
143
- subject and the fills below have nothing to say about it. */}
144
- <InstanceSection />
145
- {/* …and a component placement, for the same reason again: what it
146
- draws comes from its definition, so the fills below are inert. */}
147
- <ComponentSection />
148
- {/* Beside the model section and above the paint ones for the same
149
- reason: a cloner paints nothing of its own, so what it DOES is the
150
- subject the fills below have nothing to say about. */}
151
- <ClonerSection />
152
- {/* Above the paint sections for the same reason the three geometry
153
- sections are: a media layer PAINTS ITSELF from its asset, and
154
- `paint.fill` never reaches it (the runtime asks the rasterizer
155
- only for a "mask" and a "plate", and the fill branch lives in
156
- neither) — so the source IS the subject the fill below has
157
- nothing to say about. Corner, stroke and shadow still apply,
158
- through exactly those two rasters. */}
159
- <MediaSection />
160
- <FillSection />
161
- <StrokeSection />
162
- <CornerSection />
163
- <ShadowSection />
164
- <TypographySection />
165
- {/* Beside Typography, because it is the other kind whose content is
166
- authored here rather than dragged on the stage. Below it because a
167
- snippet's two fields are taller than everything above them. */}
168
- <HtmlSection />
169
- {/* Directly under Typography, because it says how that type moves —
170
- and it is the one Design-tab section that only matters once a
171
- `stagger` block exists, so it sits last and collapsed. */}
172
- <TextStaggerSection />
173
- </>
174
- )}
418
+ {/* THE STACK IS A LIST, not a run of self-gating JSX. `layout.ts` says
419
+ which sections and in what order; the registries above say what each
420
+ one is.
421
+
422
+ EACH SECTION CARRIES THE SUBJECT IN ITS KEY, and not a keyed Fragment
423
+ around them all, because one of them must NOT remount with the
424
+ subject: `project` survives a cut (see `subjectKey`). Keys on the
425
+ children of one array let that one section opt out while every other
426
+ still remounts when the subject changes, which is the whole point:
427
+ widget-local drafts must not leak from one subject into the next. */}
428
+ {container === null
429
+ ? (() => {
430
+ const kinds = layers.map((layer) => layer.kind);
431
+ const ids = sectionsFor(kinds);
432
+ const stack = ids.map((id) => {
433
+ const Section = SECTIONS[id];
434
+ return <Section key={`${subjectKey}:${id}`} />;
435
+ });
436
+ // ONE COMPONENT USE SELECTED: THIS USE's head over its own rows
437
+ // (what it links to, Edit master, Detach, Reset all to master).
438
+ const only = layers.length === 1 ? layers[0] : undefined;
439
+ const home = editingDef ?? sceneId;
440
+ const use =
441
+ only !== undefined && home !== null && (only.kind === "component" || only.kind === "instance")
442
+ ? layerUseKey(home, only.id)
443
+ : null;
444
+ const head = use === null ? [] : [<ThisUseBlock key={`${subjectKey}:this-use`} useKey={use} resetAll />];
445
+ // In a Shot, the way into Components comes first, at rest.
446
+ const door =
447
+ use !== null && editingDef === null && sceneId !== null && only !== undefined
448
+ ? [<InTheStudioBlock key={`${subjectKey}:in-the-studio`} sceneId={sceneId} layerId={only.id} />]
449
+ : [];
450
+ return [...door, ...head, ...stack];
451
+ })()
452
+ : CONTAINER_LAYOUT[container].map((id) => {
453
+ const Section = CONTAINER_SECTIONS[id];
454
+ return <Section key={id === "project" ? `project|${container}` : `${subjectKey}:${id}`} />;
455
+ })}
456
+ </>}
457
+ </div>
458
+ </FieldLabels>
459
+ </PanelBoundary>
175
460
  </aside>
176
461
  );
177
462
  }
178
-