@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,61 @@
1
+ // The human word for a layer: what the inspector's head, the isolation
2
+ // refusal and anything else that names a layer by its kind all say.
3
+ //
4
+ // Plain data, no React, so the state modules can read it as well as panels.
5
+ import { meshPrimitiveOf } from "@dailies-studio/shot/doc";
6
+ import type { Layer3D, Layer3DKind, MeshPrimitiveKind } from "@dailies-studio/shot/doc";
7
+
8
+ /**
9
+ * The human word for a layer kind.
10
+ *
11
+ * A TYPED RECORD over the schema's own union, in the spirit of `KIND_ICONS`: a
12
+ * sixteenth layer kind is a compile error here rather than a head that quietly
13
+ * says nothing for the one kind nobody remembered. The words are what the Add
14
+ * menu and the outliner call these things, not the wire spelling ("rect" is a
15
+ * Rectangle to an author and only ever a `rect` to the document).
16
+ */
17
+ const KIND_WORDS: Record<Layer3DKind, string> = {
18
+ text: "Text",
19
+ image: "Image",
20
+ video: "Video",
21
+ rect: "Rectangle",
22
+ ellipse: "Ellipse",
23
+ line: "Line",
24
+ arrow: "Arrow",
25
+ path: "Path",
26
+ html: "HTML",
27
+ group: "Group",
28
+ device: "Device",
29
+ mesh: "Mesh",
30
+ cloner: "Cloner",
31
+ instance: "Component",
32
+ component: "Component",
33
+ };
34
+
35
+ /**
36
+ * The word for a parametric mesh, mirroring `PRIMITIVE_ICONS` one for one.
37
+ *
38
+ * Without it a spline drew the curve glyph beside the word "Mesh", which is
39
+ * the head disagreeing with its own icon: `iconFor` already answers by what
40
+ * the layer IS to an author, and the word has to answer the same way or the
41
+ * pair reads as a bug.
42
+ */
43
+ const MESH_WORDS: Record<MeshPrimitiveKind, string> = {
44
+ box: "Box",
45
+ sphere: "Sphere",
46
+ cylinder: "Cylinder",
47
+ cone: "Cone",
48
+ capsule: "Capsule",
49
+ torus: "Torus",
50
+ pyramid: "Pyramid",
51
+ plane: "Plane",
52
+ spline: "Spline",
53
+ };
54
+
55
+ export function wordFor(layer: Layer3D): string {
56
+ if (layer.kind === "mesh") {
57
+ const primitive = meshPrimitiveOf(layer.mesh);
58
+ if (primitive !== null) return MESH_WORDS[primitive.kind];
59
+ }
60
+ return KIND_WORDS[layer.kind];
61
+ }
package/src/main.tsx CHANGED
@@ -1,15 +1,67 @@
1
+ // FIRST, and not for tidiness: the index opens with the cascade-layer order,
2
+ // and CSS a component imports itself (App's subtree) would otherwise be
3
+ // emitted ahead of it and fix its layer's rank by arriving first.
4
+ import "./styles.css";
1
5
  import { StrictMode } from "react";
6
+ import { PanelBoundary, StudioMotionProvider } from "@dailies-studio/ui";
7
+ import { StudioThemeProvider } from "@dailies-studio/ui/theme";
2
8
  import { createRoot } from "react-dom/client";
3
9
  import { createShotEditorStore } from "./state/store.js";
10
+ import { startBootOpen } from "./state/bootOpen.js";
11
+ import { persistLayoutPrefs, readLayoutPrefs } from "./state/layoutPrefs.js";
12
+ import { persistEditorPrefs } from "./state/editorPrefs.js";
4
13
  import { StoreProvider } from "./state/context.js";
5
14
  import { App } from "./app/App.js";
6
- import "./styles.css";
7
15
 
8
16
  const store = createShotEditorStore();
17
+ // The layout is settled BEFORE the first commit, not in a mount effect, so the
18
+ // panels are never painted at the defaults and then snapped to the author's
19
+ // sizes. `window` is unconditional here — this module ends by reaching into
20
+ // `document` for the root element — so there is nothing to guard.
21
+ //
22
+ // Read then subscribe, in that order: the seed inside `persistLayoutPrefs` has
23
+ // to be the layout `bootLayout` just applied, or the boot's own application of
24
+ // the record is indistinguishable from a drag — and a size this window CLAMPED
25
+ // is then written back at the clamped value, so the number the author chose is
26
+ // gone on the wider window that could have honoured it. What keeps the
27
+ // window-fitted sizes out of the record is `authorLayout`, not this order.
28
+ // layoutPrefs.ts owns both rules and states them whole.
29
+ store.bootLayout(window.innerWidth, window.innerHeight, readLayoutPrefs());
30
+ persistLayoutPrefs(store);
31
+ // The store read the editor preferences at birth, so this subscribes with that
32
+ // as its seed and writes only when a toggle changes one.
33
+ persistEditorPrefs(store);
34
+ // The document fetch starts HERE, at module evaluation — before createRoot and
35
+ // the first commit — so the round trip overlaps the mount instead of following
36
+ // it. `useOpenFromUrl` adopts the promise for its deep-link continuations.
37
+ // Module-scope start also means StrictMode's double effect adopts one fetch
38
+ // instead of relying on the generation fence to absorb a second.
39
+ startBootOpen(store);
40
+ // The browser agent's tool surface, offered here for the same reason the two
41
+ // calls above are: the store exists before React does, so no component owns the
42
+ // registration and there is no mount order to get wrong. A browser without
43
+ // `document.modelContext` gets nothing and pays nothing: the tool table is a
44
+ // chunk of its own, fetched only where the API exists.
45
+ if (document.modelContext !== undefined) void import("./state/webmcp.js").then((m) => m.startModelContext(store));
9
46
  createRoot(document.getElementById("root")!).render(
10
47
  <StrictMode>
11
- <StoreProvider store={store}>
12
- <App />
13
- </StoreProvider>
48
+ <StudioThemeProvider>
49
+ <StudioMotionProvider enabled>
50
+ <StoreProvider store={store}>
51
+ {/* THE LAST RESORT, and the only boundary allowed above the stage.
52
+ Everything a panel or a mode can throw is caught
53
+ nearer the throw; what reaches here is a throw in the shell
54
+ itself, and React's answer to that is to unmount the whole root
55
+ and leave a WHITE PAGE with the error only in the console. This
56
+ cannot save the stage — a catch unmounts it either way — but it
57
+ turns a blank window into a named error the author can report,
58
+ and a retry that costs no more than the reload they would
59
+ otherwise do by hand. */}
60
+ <PanelBoundary label="Dailies">
61
+ <App />
62
+ </PanelBoundary>
63
+ </StoreProvider>
64
+ </StudioMotionProvider>
65
+ </StudioThemeProvider>
14
66
  </StrictMode>,
15
67
  );
@@ -17,15 +17,24 @@
17
17
  // size exactly once per gesture — at the press — so it asks for it then, and
18
18
  // the hosts subscribe to nothing on its behalf.
19
19
  //
20
- // ── WRITES ARE COALESCED TO THE FRAME ────────────────────────────────────
20
+ // ── WRITES ARE COALESCED TO THE FRAME, BY startDrag ──────────────────────
21
21
  //
22
22
  // A pointer reports far above display rate; each `onChange` is a store write
23
- // and a full listener sweep. One write per frame, last position wins, the
24
- // release flushes whatever is pending so the final size always lands.
23
+ // and a full listener sweep. `startDrag` itself now delivers one move per
24
+ // frame, last position wins, and settles the pending move on release — this
25
+ // file's own rAF coalescer moved there so every chrome drag gets it.
25
26
  //
26
- // Pointer capture, so a fast drag that leaves the 8px strip keeps resizing
27
- // rather than dropping the gesture, and so the release always lands here.
28
- import { useEffect, useRef } from "react";
27
+ // ── THE LIFECYCLE IS THE WORKSPACE'S, NOT THIS FILE'S ────────────────────
28
+ //
29
+ // `startDrag` (packages/ui/src/drag.ts) owns pointer capture and all three
30
+ // abort paths: pointercancel, Escape, and the lostpointercapture a mid-drag
31
+ // unmount produces. Hand-rolling capture with React's pointerup/pointercancel
32
+ // props reaches only the first of them, which is what left the panel edge as
33
+ // the one chrome drag an author could not back out of.
34
+ //
35
+ // An abort RESTORES THE BASE, because the coalesced writes already landed on
36
+ // the host: "this gesture did not happen" has to mean the size it started at.
37
+ import { startDrag } from "@dailies-studio/ui";
29
38
 
30
39
  export interface ResizeHandleProps {
31
40
  /** "x" drags left-right (a side rail), "y" up-down (a bottom dock). */
@@ -53,24 +62,8 @@ export function ResizeHandle({
53
62
  className,
54
63
  label,
55
64
  }: ResizeHandleProps) {
56
- const drag = useRef<{ base: number; origin: number } | null>(null);
57
- const pending = useRef<number | null>(null);
58
- const raf = useRef(0);
59
- useEffect(
60
- () => () => {
61
- if (raf.current !== 0) cancelAnimationFrame(raf.current);
62
- },
63
- [],
64
- );
65
65
  const posOf = (e: { clientX: number; clientY: number }): number =>
66
66
  axis === "x" ? e.clientX : e.clientY;
67
- const flush = (): void => {
68
- raf.current = 0;
69
- if (pending.current === null) return;
70
- const next = pending.current;
71
- pending.current = null;
72
- onChange(next);
73
- };
74
67
 
75
68
  return (
76
69
  <div
@@ -81,32 +74,29 @@ export function ResizeHandle({
81
74
  role="separator"
82
75
  aria-orientation={axis === "x" ? "vertical" : "horizontal"}
83
76
  aria-label={label}
84
- title={`${label} — drag to resize, double-click to reset`}
77
+ title={`${label}: drag to resize, double-click to reset`}
85
78
  onDoubleClick={onReset}
86
79
  onPointerDown={(e) => {
87
80
  // Or the browser starts a text selection across the panels the drag
88
81
  // passes over, and the whole chrome flashes blue mid-resize.
89
82
  e.preventDefault();
90
- e.currentTarget.setPointerCapture(e.pointerId);
91
- drag.current = { base: getValue(), origin: posOf(e) };
92
- }}
93
- onPointerMove={(e) => {
94
- const d = drag.current;
95
- if (d === null) return;
96
- pending.current = d.base + (posOf(e) - d.origin) * sign;
97
- if (raf.current === 0) raf.current = requestAnimationFrame(flush);
98
- }}
99
- onPointerUp={() => {
100
- drag.current = null;
101
- // The release's position always lands, even mid-frame.
102
- flush();
103
- }}
104
- // Pen and touch can have the gesture cancelled out from under them; the
105
- // pointerup that would clear this never arrives, and without this the
106
- // next hover over the strip would resize with a stale base.
107
- onPointerCancel={() => {
108
- drag.current = null;
109
- pending.current = null;
83
+ // Both captured at the press, and both live in this closure rather
84
+ // than in a ref: there is exactly one gesture at a time, and a ref
85
+ // that outlives it is the stale base a cancelled pointer used to
86
+ // leave behind.
87
+ const base = getValue();
88
+ const origin = posOf(e);
89
+ startDrag(e, {
90
+ // Already frame-coalesced by startDrag, and the release delivers the
91
+ // pending move before onEnd — so the final size always lands, and an
92
+ // abort's base restore below can never be overwritten by it.
93
+ onMove(ev) {
94
+ onChange(base + (posOf(ev) - origin) * sign);
95
+ },
96
+ onEnd(commit) {
97
+ if (!commit) onChange(base);
98
+ },
99
+ });
110
100
  }}
111
101
  />
112
102
  );
@@ -0,0 +1,36 @@
1
+ // AN MCP AGENT IS WORKING HERE: three animated dots in the Agent's colour, the
2
+ // one mark every surface uses for it (the component card, the code tab, the
3
+ // layer row, the status chip). Driven by the agent activity store
4
+ // (state/agentActivity.ts), never by a timer of its own.
5
+ import { useSyncExternalStore } from "react";
6
+ import type { ReactNode } from "react";
7
+ import { useShotEditor, useStore } from "../../state/context.js";
8
+ import { agentBuildingParts } from "../../state/agentActivity.js";
9
+ import type { AgentActivityState } from "../../state/agentActivity.js";
10
+
11
+ export function useAgentActivity(): AgentActivityState {
12
+ const { agentActivity } = useStore();
13
+ return useSyncExternalStore(agentActivity.subscribe, agentActivity.getState);
14
+ }
15
+
16
+ /** The dots, with `label` for assistive tech ("Agent is writing this file"). */
17
+ export function AgentDots(props: { label: string }): ReactNode {
18
+ return (
19
+ <span className="agent-dots" role="status" aria-label={props.label} title={props.label} data-testid="agent-dots">
20
+ <span />
21
+ <span />
22
+ <span />
23
+ </span>
24
+ );
25
+ }
26
+
27
+ /** `boardBuilding` plus the parts an MCP agent is building now: what a shot
28
+ * card's Building status reads. */
29
+ export function useBuildingParts(): readonly { part: string }[] {
30
+ const building = useShotEditor((s) => s.boardBuilding);
31
+ const doc = useShotEditor((s) => s.doc);
32
+ const name = useShotEditor((s) => s.name);
33
+ const activity = useAgentActivity();
34
+ const agents = agentBuildingParts(doc, activity, name);
35
+ return agents.length === 0 ? building : [...building, ...agents];
36
+ }
@@ -8,7 +8,7 @@
8
8
  // A shot proposal is not a diff — a diff of a Doc3D JSON is unreadable and,
9
9
  // worse, a lie about what the change IS. What an author has to judge is how
10
10
  // LONG the video is now and what moves in it, so that is the card: the intent
11
- // as the title, the duration and the block/camera-move counts as chips, and the
11
+ // as the title, the duration and the camera-move count as a chip, and the
12
12
  // scene/layer outline the server already rendered.
13
13
  //
14
14
  // Keydown stops at the panel root so typing a prompt never reaches the global
@@ -17,6 +17,7 @@
17
17
  import "./agent.css";
18
18
  import { useEffect, useRef, useState } from "react";
19
19
  import type { KeyboardEvent as ReactKeyboardEvent } from "react";
20
+ import { PanelBoundary, SegmentedControl } from "@dailies-studio/ui";
20
21
  import { isDocProposalItem } from "@dailies-studio/agent-client";
21
22
  import type {
22
23
  AgentFileProposalItem,
@@ -25,6 +26,10 @@ import type {
25
26
  AgentTranscriptItem,
26
27
  } from "@dailies-studio/agent-client";
27
28
  import { useShotEditor, useStore } from "../../state/context.js";
29
+ import { isCloudWorkspace } from "../../state/posterCapture.js";
30
+ import { shortcutFor } from "../../state/shortcuts.js";
31
+ import type { ShotEditorState } from "../../state/types.js";
32
+ import { formatDuration } from "../timeline/model.js";
28
33
  import {
29
34
  applyAgentProposal,
30
35
  askAgent,
@@ -88,15 +93,45 @@ function Outline(props: { lines: readonly string[] }) {
88
93
  );
89
94
  }
90
95
 
96
+ /**
97
+ * The Shots a proposal redraws beyond the one an "Add motion" request named
98
+ * (or, without one, the entered Shot), by name. Empty when the card edits
99
+ * another Project, when nothing names a Shot, or on a create.
100
+ */
101
+ export function strayShotsOf(state: ShotEditorState, item: AgentShotProposalItem): string[] {
102
+ const changed = item.summary.changedShots;
103
+ if (changed === undefined || state.name !== item.docName) return [];
104
+ const target = state.motionRequest?.sceneId ?? state.enteredScene;
105
+ if (target === null) return [];
106
+ return changed
107
+ .filter((id) => id !== target)
108
+ .map((id) => state.doc?.scenesById[id]?.name ?? id);
109
+ }
110
+
91
111
  function ShotCard(props: { item: AgentShotProposalItem }) {
92
112
  const { item } = props;
113
+ const store = useStore();
93
114
  const openName = useShotEditor((s) => s.name);
115
+ const openTitle = useShotEditor((s) => s.doc?.title ?? s.name);
116
+ const motionPart = useShotEditor((s) => s.motionRequest?.partId ?? null);
117
+ // Joined to a string so the selector stays identity-stable between renders.
118
+ const strays = useShotEditor((s) => strayShotsOf(s, item).join("\u0000"));
119
+ const [copied, setCopied] = useState(false);
94
120
  const { summary } = item;
121
+ const copyPrompt = (): void => {
122
+ const prompt = motionPart === null ? null : store.motionPromptFor(motionPart);
123
+ if (prompt === null) return;
124
+ void navigator.clipboard.writeText(prompt).then(
125
+ () => setCopied(true),
126
+ () => store.reportError("Could not copy the prompt. The browser refused clipboard access."),
127
+ );
128
+ };
95
129
  // Three cases, one of which needs a warning. Same shot: the SSE bus adopts
96
130
  // it. A CREATE of another name: applying opens it. An EDIT of another shot:
97
131
  // it lands on disk but this editor stays where it is — say so rather than
98
132
  // letting the card imply the author is looking at the result.
99
133
  const editsElsewhere = openName !== null && openName !== item.docName && item.baseRev !== null;
134
+ const title = summary.title ?? summary.shotName;
100
135
  return (
101
136
  <div className={`agent-card agent-card-shot agent-card-${item.status}`}>
102
137
  <div className="agent-card-head">
@@ -106,26 +141,22 @@ function ShotCard(props: { item: AgentShotProposalItem }) {
106
141
  <CardActions item={item} />
107
142
  </div>
108
143
  <div className="agent-card-meta">
109
- <span className="agent-card-doc" title={`scene "${summary.shotName}"`}>
110
- {summary.shotName}
144
+ <span className="agent-card-doc" title={`Project “${title}”`}>
145
+ {title}
111
146
  </span>
112
147
  {/* DURATION first: a shot document is a video, and "how long is it now"
113
148
  is the first thing a reviewer asks. */}
114
- <span className="agent-card-count">{summary.durationFrames}f</span>
149
+ <span className="agent-card-count">
150
+ {summary.fps === undefined
151
+ ? `${summary.durationFrames}f`
152
+ : formatDuration(summary.durationFrames / summary.fps)}
153
+ </span>
115
154
  <span className="agent-card-count">
116
155
  {summary.sceneCount} {summary.sceneCount === 1 ? "shot" : "shots"}
117
156
  </span>
118
157
  <span className="agent-card-count">
119
158
  {summary.layerCount} {summary.layerCount === 1 ? "layer" : "layers"}
120
159
  </span>
121
- {/* The MOTION half. Silent at zero — a chip reading "0 blocks" on a
122
- static card is noise, and this lane's whole animation system is
123
- blocks, so their absence is itself the information. */}
124
- {summary.blockCount > 0 && (
125
- <span className="agent-card-count">
126
- {summary.blockCount} {summary.blockCount === 1 ? "block" : "blocks"}
127
- </span>
128
- )}
129
160
  {summary.shotCount > 0 && (
130
161
  <span className="agent-card-count">
131
162
  {summary.shotCount} {summary.shotCount === 1 ? "camera move" : "camera moves"}
@@ -133,6 +164,17 @@ function ShotCard(props: { item: AgentShotProposalItem }) {
133
164
  )}
134
165
  </div>
135
166
  <Outline lines={summary.outline} />
167
+ {strays !== "" && item.status === "pending" && (
168
+ <div className="agent-card-note agent-card-warning">
169
+ Also changes {strays.split("\u0000").map((name) => `“${name}”`).join(", ")}, not only the
170
+ Shot you asked about.
171
+ </div>
172
+ )}
173
+ {motionPart !== null && (
174
+ <button type="button" className="btn agent-copy-prompt" onClick={copyPrompt}>
175
+ {copied ? "Copied" : "Copy prompt"}
176
+ </button>
177
+ )}
136
178
  {item.error !== null && <div className="error-strip agent-card-error">{item.error}</div>}
137
179
  {/* APPLIED WITH WARNINGS is its own state: the document was written, but
138
180
  codegen refused (a hand-edited generated file) — so the component that
@@ -140,24 +182,24 @@ function ShotCard(props: { item: AgentShotProposalItem }) {
140
182
  one place a half-landed change reads as a landed one. */}
141
183
  {item.status === "applied" && item.warning !== null && (
142
184
  <div className="agent-card-note agent-card-warning">
143
- Applied with warnings — the scene document was saved, but: {item.warning}
185
+ Applied with warnings. The Project was saved, but: {item.warning}
144
186
  </div>
145
187
  )}
146
188
  {item.status === "applied" && item.error === null && item.warning === null && (
147
189
  <div className="agent-card-note">
148
- Applied — the change is live in the editor. Ctrl+Z takes it back.
190
+ Applied: the change is live in the editor. {shortcutFor("edit.undo")} takes it back.
149
191
  </div>
150
192
  )}
151
193
  {item.status === "stale" && (
152
194
  <div className="agent-card-note">
153
- The scene changed after this was proposed — ask the agent again so it can re-read the
154
- document and re-propose.
195
+ The Project changed after this was proposed. Ask the agent again so it can re-read it
196
+ and re-propose.
155
197
  </div>
156
198
  )}
157
199
  {editsElsewhere && item.status === "pending" && (
158
200
  <div className="agent-card-note">
159
- Edits scene “{item.docName}”, not the open one — applying writes it, but this editor stays
160
- on “{openName}”.
201
+ Edits Project “{title}”, not the open one. Applying writes it, but this editor stays on
202
+ “{openTitle}”.
161
203
  </div>
162
204
  )}
163
205
  </div>
@@ -198,7 +240,7 @@ function FileCard(props: { item: AgentFileProposalItem }) {
198
240
  {item.error !== null && <div className="error-strip agent-card-error">{item.error}</div>}
199
241
  {item.status === "stale" && (
200
242
  <div className="agent-card-note">
201
- The file changed on disk after this was proposed — ask the agent again to re-read and
243
+ The file changed on disk after this was proposed. Ask the agent again to re-read and
202
244
  re-propose.
203
245
  </div>
204
246
  )}
@@ -228,7 +270,7 @@ function TranscriptItem(props: { item: AgentTranscriptItem }) {
228
270
  <span className={`agent-card-status is-${item.status}`}>{item.status}</span>
229
271
  </div>
230
272
  <div className="agent-card-note">
231
- A {item.proposalKind} document — “{item.docName}”. Open that editor to review and apply
273
+ A {item.proposalKind} document: “{item.docName}”. Open that editor to review and apply
232
274
  it.
233
275
  </div>
234
276
  </div>
@@ -246,6 +288,9 @@ function KeySetup(props: { compact: boolean; onDone?: () => void }) {
246
288
  const credentialsError = useShotEditor((s) => s.agentCredentialsError);
247
289
  const [key, setKey] = useState("");
248
290
  const [saving, setSaving] = useState(false);
291
+ // Hosted, the key is one row per workspace that every owner and admin's
292
+ // turns run on, not a file on this machine (`workspaceAgent.ts`).
293
+ const hosted = isCloudWorkspace();
249
294
 
250
295
  const save = async (): Promise<void> => {
251
296
  if (key.trim() === "" || saving) return;
@@ -263,8 +308,18 @@ function KeySetup(props: { compact: boolean; onDone?: () => void }) {
263
308
  {!props.compact && (
264
309
  <p className="agent-setup-blurb">
265
310
  The agent builds scenes through the studio's validated document API and needs an Anthropic
266
- API key. Bring your own: it is stored in <code>.studio/agent/</code> (kept out of git) on
267
- this machine, sent only to Anthropic, and never shown again.
311
+ API key.{" "}
312
+ {hosted ? (
313
+ <>
314
+ It is stored encrypted for this workspace, sent only to Anthropic, and never shown
315
+ again. Every owner and admin here uses this key, and saving replaces the current one.
316
+ </>
317
+ ) : (
318
+ <>
319
+ Bring your own: it is stored in <code>.studio/agent/</code> (kept out of git) on this
320
+ machine, sent only to Anthropic, and never shown again.
321
+ </>
322
+ )}
268
323
  </p>
269
324
  )}
270
325
  {credentials?.source === "env" && (
@@ -274,7 +329,7 @@ function KeySetup(props: { compact: boolean; onDone?: () => void }) {
274
329
  )}
275
330
  {credentials?.source === "stored" && (
276
331
  <p className="agent-setup-blurb">
277
- Using your stored key (…{credentials.last4}).{" "}
332
+ {hosted ? "Using this workspace's key" : "Using your stored key"} (…{credentials.last4}).{" "}
278
333
  <button type="button" className="btn is-danger" onClick={() => void clearAgentKey(store)}>
279
334
  Remove key
280
335
  </button>
@@ -316,10 +371,34 @@ export function AgentPanel() {
316
371
  const agentError = useShotEditor((s) => s.agentError);
317
372
  const agentModel = useShotEditor((s) => s.agentModel);
318
373
  const costUsd = useShotEditor((s) => s.agentCostUsd);
319
- const name = useShotEditor((s) => s.name);
374
+ const name = useShotEditor((s) => s.doc?.title ?? s.name);
320
375
  const [prompt, setPrompt] = useState("");
321
376
  const [keyOpen, setKeyOpen] = useState(false);
322
377
  const listRef = useRef<HTMLDivElement | null>(null);
378
+ const inputRef = useRef<HTMLTextAreaElement | null>(null);
379
+
380
+ // A prefill from the storyboard (a part's motion prompt, or a move's motion notes): adopted once per
381
+ // identity, `appMenu`'s mailbox rule, and the caret lands at its end so the
382
+ // author finishes the sentence rather than finding it.
383
+ const prefill = useShotEditor((s) => s.agentPrefill);
384
+ const focusPrefill = useRef(false);
385
+ useEffect(() => {
386
+ if (prefill === null) return;
387
+ setPrompt(prefill.text);
388
+ focusPrefill.current = true;
389
+ store.consumeAgentPrefill(prefill);
390
+ }, [prefill, store]);
391
+
392
+ useEffect(() => {
393
+ const el = inputRef.current;
394
+ // The first credential probe may still have the composer disabled when
395
+ // its prefill arrives. Focus once the actual input can accept typing.
396
+ if (focusPrefill.current && el !== null && !el.disabled) {
397
+ focusPrefill.current = false;
398
+ el.focus();
399
+ el.setSelectionRange(el.value.length, el.value.length);
400
+ }
401
+ }, [prefill, prompt, credentials?.configured, running]);
323
402
 
324
403
  // One credentials probe per opening; a saved/removed key refreshes through
325
404
  // the actions themselves.
@@ -350,24 +429,19 @@ export function AgentPanel() {
350
429
 
351
430
  return (
352
431
  <div className="agent-panel" data-testid="agent-panel" onKeyDown={onKeyDown}>
353
- <div className="panel-title agent-title">
354
- <span className="agent-title-label">Agent</span>
432
+ {/* INSIDE the positioned container, per the boundary's placement rule. */}
433
+ <PanelBoundary label="Agent">
434
+ {/* No "Agent" word here: the column head's tab already names the panel. */}
435
+ <div className="agent-title">
355
436
  {credentials !== null && credentials.configured && (
356
- <div className="agent-models" role="tablist">
357
- {credentials.models.map((m) => (
358
- <button
359
- key={m}
360
- type="button"
361
- role="tab"
362
- aria-selected={m === model}
363
- className={`btn${m === model ? " is-active" : ""}`}
364
- title={m}
365
- onClick={() => store.setAgentModel(m === credentials.model ? null : m)}
366
- >
367
- {modelLabel(m)}
368
- </button>
369
- ))}
370
- </div>
437
+ <SegmentedControl
438
+ className="agent-models"
439
+ ariaLabel="Model"
440
+ value={model}
441
+ options={credentials.models.map((m) => ({ value: m, label: modelLabel(m), title: m }))}
442
+ // Picking the server's default stores null: no override.
443
+ onChange={(m) => store.setAgentModel(m === credentials.model ? null : m)}
444
+ />
371
445
  )}
372
446
  <button
373
447
  type="button"
@@ -415,8 +489,8 @@ export function AgentPanel() {
415
489
 
416
490
  <div className="agent-transcript" ref={listRef}>
417
491
  {items.length === 0 ? (
418
- <div className="panel-empty">
419
- Ask for a scene — “a product video: the screenshot pushes in while the headline fades
492
+ <div className="insp-empty">
493
+ Ask for a scene, for example “a product video: the screenshot pushes in while the headline fades
420
494
  up”. You get real layers at real depths; nothing lands until you apply it.
421
495
  </div>
422
496
  ) : (
@@ -437,6 +511,7 @@ export function AgentPanel() {
437
511
  </span>
438
512
  )}
439
513
  <textarea
514
+ ref={inputRef}
440
515
  className="agent-input"
441
516
  rows={2}
442
517
  placeholder={
@@ -473,6 +548,7 @@ export function AgentPanel() {
473
548
  </button>
474
549
  )}
475
550
  </div>
551
+ </PanelBoundary>
476
552
  </div>
477
553
  );
478
554
  }