@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,295 @@
1
+ // WHICH SECTIONS A SUBJECT GETS, AND IN WHAT ORDER. DECLARED, NOT DERIVED.
2
+ //
3
+ // ── THE PANEL MOUNTED EVERYTHING AND LET EACH SECTION REFUSE ────────────
4
+ //
5
+ // `InspectorPanel` used to render every design section for every selection and
6
+ // each one gated itself: `layers.some((l) => l.kind === "cloner")` in one file,
7
+ // `every(isMedia)` in a second, `layers.length === 1` in three more. So the
8
+ // answer to "what does a text layer's inspector look like" was the ORDER OF THE
9
+ // JSX plus a kind predicate buried inside whichever of the sections happened to
10
+ // carry one, a file each. Nothing asserted it, two sections could disagree about
11
+ // the same selection, and a new layer kind got whatever happened to fall out.
12
+ //
13
+ // This file IS that answer, and `test/inspectorLayout.test.tsx` pins it per
14
+ // kind. `LAYER_LAYOUT` is a `Record` over the schema's own union — the rule
15
+ // `KIND_WORDS` (layerWords.ts) already follows — so a sixteenth layer kind
16
+ // is a COMPILE ERROR here rather than a rail that silently offers it nothing
17
+ // but Transform.
18
+ //
19
+ // ── KIND GATES MOVED HERE; THE REST STAYED, AND MOST OF THAT IS A CHOICE ─
20
+ //
21
+ // "Is this layer a cloner" is a question about the kind, and the table answers
22
+ // it once. The gates that stayed behind split in two, and only one half is
23
+ // out of reach.
24
+ //
25
+ // "Does this mesh wear a node graph", "is this instance's definition still
26
+ // there" are questions about the DOCUMENT. Nothing handed to this module can
27
+ // answer them, so they could not move even in principle.
28
+ //
29
+ // "Is exactly one layer selected", "is every one of them media", "which layer
30
+ // leads" could: `sectionsFor` is given `layers.map((l) => l.kind)`, the kinds
31
+ // IN SELECTION ORDER, so the count, the leader and the whole multiset are
32
+ // already in its argument. They stay in their sections anyway, because
33
+ // re-deriving them here would be a SECOND SPELLING of each section's own rule
34
+ // and two spellings are what drift — the sections keep the one copy and this
35
+ // table stays the ceiling. Every one of them is named on `sectionsFor` below,
36
+ // because a gate nobody wrote down is the gate the next author debugs twice.
37
+ import type { Layer3DKind } from "@dailies-studio/shot/doc";
38
+
39
+ /**
40
+ * Every design section, in the order a MIXED selection renders them.
41
+ *
42
+ * The order is the order the picture is described in: where the layer is
43
+ * (transform, appearance), WHEN it is (time), what it IS (the per-kind block,
44
+ * a mesh's geometry, a device's slab, a component's definition, a cloner's
45
+ * arrangement, a media layer's source), what is PAINTED onto it, what its
46
+ * content is (type, markup), and last what it DOES over time.
47
+ *
48
+ * "Time" is the layer's LIFETIME and, for a video, the footage under it: the
49
+ * window, the source edges, the speed and what happens past the recording's
50
+ * end. It sits with transform and appearance because it is a fact about the
51
+ * layer, and every kind has one.
52
+ *
53
+ * "Mask" leads (gap 7, Paper page 25): a mask paints nothing of its own, so
54
+ * what it does to the layers in front of it is the first fact about it.
55
+ *
56
+ * "Template field" (schema v50) follows the content: whether a person who
57
+ * starts from this Project swaps the layer for their own is a fact about what
58
+ * the layer shows, so it sits after the sections that say what that is.
59
+ */
60
+ export const SECTION_ORDER = [
61
+ "mask",
62
+ "transform",
63
+ "appearance",
64
+ "time",
65
+ "presets",
66
+ "mesh",
67
+ "material",
68
+ "device",
69
+ "instance",
70
+ "component",
71
+ "cloner",
72
+ "media",
73
+ "plateStyle",
74
+ "textFill",
75
+ "fill",
76
+ "stroke",
77
+ "corner",
78
+ "shadow",
79
+ "typography",
80
+ "html",
81
+ "templateField",
82
+ "splineFollow",
83
+ ] as const;
84
+
85
+ export type SectionId = (typeof SECTION_ORDER)[number];
86
+
87
+ /** Where the layer is, how it reads, when it exists and how it comes and goes.
88
+ * Every kind has all of them: a lifetime is not optional, so neither is the
89
+ * section that edits it, and every kind has an opacity a Fade can stamp
90
+ * ("presets", the Motion section: a preset writes ordinary keys).
91
+ * Any kind can be a mask too, so every kind lists "mask"; the section itself
92
+ * is a document gate (see `sectionsFor`). */
93
+ const BASE = ["mask", "transform", "appearance", "time", "presets"] as const satisfies readonly SectionId[];
94
+
95
+ /**
96
+ * The four sections that write `paint`. A kind lists only the ones its draw
97
+ * reads (F30): ellipse and path have no corner, line and arrow have no fill or
98
+ * corner, and media has no fill (see `LAYER_LAYOUT`).
99
+ *
100
+ * The six kinds that do NOT list these are refused for two overlapping reasons.
101
+ * `mesh`, `device` and `instance` DRAW but never take a rasterizer call — a
102
+ * mesh's look is its material, a device's slab colour comes from its preset
103
+ * (device.tsx reads `deviceSlab`, never `paint`), and an instance paints
104
+ * itself. `group`, `cloner` and `component` do not draw at all; they are
105
+ * transform, derivation and definition parents. For every one of the six a
106
+ * fill, a stroke, a corner radius and a shadow are document fields that move no
107
+ * pixel: the author edits one, sees nothing, and concludes the renderer is
108
+ * broken.
109
+ */
110
+ const PAINT = ["fill", "stroke", "corner", "shadow"] as const satisfies readonly SectionId[];
111
+
112
+ /** What the layer does over time beyond its keyframes. The keyframes are the
113
+ * timeline dock's channel rows and the inspector's diamonds, not a section. */
114
+ const MOTION = ["splineFollow"] as const satisfies readonly SectionId[];
115
+
116
+ /**
117
+ * The predefined control panel for each layer kind.
118
+ *
119
+ * MEDIA HAS NO `fill`, which is the one entry that is not simply "what the kind
120
+ * carries": `drawLayer` paints `paint.fill` only in the arm that is neither
121
+ * "mask" nor "plate" (raster.ts) and `MediaPlane` asks for exactly those two, so
122
+ * a photo's fill swatch writes a field and moves nothing. Stroke, corner and
123
+ * shadow ride the plate and the mask, so those three stay.
124
+ *
125
+ * TEXT'S "Fill" IS THE GLYPH COLOUR (`textFill`, F20), the Figma meaning. Its
126
+ * `paint.fill` is the plate behind the words, so that section reads
127
+ * "Background" over text (FillSection).
128
+ *
129
+ * ONLY TEXT, IMAGE AND VIDEO LIST `templateField`: they are `SWAP_KINDS`, the
130
+ * kinds `setLayerSwap` lets a template field sit on.
131
+ */
132
+ export const LAYER_LAYOUT: Record<Layer3DKind, readonly SectionId[]> = {
133
+ text: [...BASE, "textFill", ...PAINT, "typography", "templateField", ...MOTION],
134
+ image: [...BASE, "media", "plateStyle", "stroke", "corner", "shadow", "templateField", ...MOTION],
135
+ video: [...BASE, "media", "plateStyle", "stroke", "corner", "shadow", "templateField", ...MOTION],
136
+ rect: [...BASE, ...PAINT, ...MOTION],
137
+ ellipse: [...BASE, "fill", "stroke", "shadow", ...MOTION],
138
+ line: [...BASE, "stroke", "shadow", ...MOTION],
139
+ arrow: [...BASE, "stroke", "shadow", ...MOTION],
140
+ path: [...BASE, "fill", "stroke", "shadow", ...MOTION],
141
+ html: [...BASE, ...PAINT, "html", ...MOTION],
142
+ group: [...BASE, ...MOTION],
143
+ device: [...BASE, "device", ...MOTION],
144
+ mesh: [...BASE, "mesh", "material", ...MOTION],
145
+ cloner: [...BASE, "cloner", ...MOTION],
146
+ instance: [...BASE, "instance", ...MOTION],
147
+ component: [...BASE, "component", ...MOTION],
148
+ };
149
+
150
+ /**
151
+ * The sections a selection of these kinds renders, in `SECTION_ORDER`.
152
+ *
153
+ * THE UNION, NEVER THE INTERSECTION. A rect selected with a mesh keeps the
154
+ * paint block, because the rect in it still paints and `useSelectionWrite`
155
+ * already skips the layers a write cannot reach — a false cut hides a real
156
+ * control, which is strictly worse than a control that only reaches half the
157
+ * selection. That is also what the old self-gating stack produced (every kind
158
+ * gate in it was `some`, never `every`), and `inspectorPanel.test.tsx` pins it.
159
+ *
160
+ * DECLARED IS THE CEILING, NOT THE MOUNT. Nothing outside this list mounts.
161
+ * Something inside it can still withhold itself, on a question about the SHAPE
162
+ * OF THE SELECTION or about the DOCUMENT. The document ones are outside this
163
+ * module's reach. The shape ones are NOT — the argument is the kinds in
164
+ * selection order — and they are left in their sections deliberately, so each
165
+ * rule has exactly one spelling. Every withholding, and its exact condition:
166
+ *
167
+ * `component` ONE layer only. Each panel's rows are one
168
+ * `instance`, `material` definition's or one graph's own key list, so a
169
+ * fan-out would write keys the other subject has
170
+ * never heard of.
171
+ * `templateField` ONE layer only. A field's name says what THAT
172
+ * layer asks for ("Screenshot", "Headline"), so two
173
+ * layers under one name would be one question
174
+ * asked twice.
175
+ * `time` ONE layer only, and on its own reason rather than
176
+ * theirs: nothing about it is a key list. A lifetime
177
+ * belongs to one layer and every clip op takes one
178
+ * `layerId`, so fanning the edges out would need
179
+ * `moveLayers`' all-or-nothing posture, and "source
180
+ * in" has no fan-out meaning at all because the next
181
+ * layer's footage starts somewhere else entirely.
182
+ * `TimeSection`'s own header states this rule and
183
+ * names this list as the company it keeps, so the
184
+ * two are written to be read together.
185
+ * `plateStyle` `every(isMedia)`. A plate chip writes stroke,
186
+ * radius and shadows over the WHOLE selection, so a
187
+ * rect in it would be restyled from a shelf that
188
+ * never named it.
189
+ * `cloner`, `html` the FIRST selected layer's. A selection led in
190
+ * document order by anything else has no arrangement
191
+ * and no markup to show. (They arrive there by
192
+ * different routes: `html` reads through
193
+ * `useSelectionValue`, while `ClonerSection` takes
194
+ * the lead layer directly and asks about mixedness
195
+ * per field — an object read through that hook makes
196
+ * every multi-selection "Mixed" by identity.)
197
+ * `material` and, ON TOP of the one-layer rule, the document
198
+ * has to hold what it describes: a mesh with no
199
+ * node graph renders nothing at all.
200
+ * `mask` a document gate: it renders only when a selected
201
+ * layer is a mask or a group that holds one
202
+ * (`maskTargetOf`).
203
+ * `splineFollow` a document gate too: it renders only when the
204
+ * layer already follows a spline, the home holds a
205
+ * spline it could follow, or a cloner's spline
206
+ * distribution owns the path.
207
+ *
208
+ * The material gate is why "a single layer renders exactly its row of the
209
+ * table" is true of fourteen of the fifteen kinds and not of `mesh`: its
210
+ * material needs a graph behind it, which is why the fixture in
211
+ * `inspectorLayout.test.tsx` mints one before asserting the row.
212
+ * Every withholding above is pinned in that file too, so this list is asserted
213
+ * rather than merely written down.
214
+ */
215
+ export function sectionsFor(kinds: Iterable<Layer3DKind>): readonly SectionId[] {
216
+ const wanted = new Set<SectionId>();
217
+ for (const kind of kinds) for (const id of LAYER_LAYOUT[kind]) wanted.add(id);
218
+ return SECTION_ORDER.filter((id) => wanted.has(id));
219
+ }
220
+
221
+ /** What the rail is looking at when NOTHING is selected. The three are decided
222
+ * by the context bits alone: an open definition, then the entered shot, then
223
+ * the project the panel is a view of. */
224
+ export type ContainerSubject = "project" | "shot" | "definition" | "storyboard";
225
+
226
+ /**
227
+ * Every container section, by id.
228
+ *
229
+ * `shotTransition` is the PROJECT context's shot: the shot's own rows and the
230
+ * seam after it, under one head. `shot` is the same shot rows alone, for the
231
+ * inside of a shot, where the seam is off screen. `blur` and `postprocessing`
232
+ * are the two halves of one `Scene3D.effects` stack, split by what the pass
233
+ * does to the picture (see `EffectsSection`).
234
+ */
235
+ export type ContainerSectionId =
236
+ | "project"
237
+ | "makeItYours"
238
+ | "shot"
239
+ | "shotTransition"
240
+ | "camera"
241
+ | "blur"
242
+ | "postprocessing"
243
+ | "definition"
244
+ | "storyboardReference"
245
+ | "storyboardCut";
246
+
247
+ /**
248
+ * The predefined control panel for each container subject.
249
+ *
250
+ * EACH CONTEXT LEADS WITH ITSELF (Paper 27, "8 · Empty inspector"). With
251
+ * nothing selected the first read is the context the author is in: the
252
+ * Project's name, size and rate above the shots, the Shot's background and
253
+ * duration inside one. The camera follows in both, because it is what the
254
+ * stage IS (the presented shot camera above, the framed picture inside), and
255
+ * the other context's section after it. Blur and Postprocessing close the
256
+ * list, blur first because a defocus is a lens decision and a grade is not;
257
+ * each opens collapsed to one "None" line while it holds no pass
258
+ * (EffectsSection).
259
+ *
260
+ * This replaced one shared order (Camera, Project, Shot, ...) for both
261
+ * contexts. That order put the camera's numbers first in a panel whose
262
+ * subject was the Project or the Shot, so the empty inspector never said
263
+ * where the author was.
264
+ *
265
+ * Camera, Blur and Postprocessing used to sit out the project context on the
266
+ * claim that nobody could judge them there. That stopped being true: the stage
267
+ * there is the presented shot camera, `writeCamera` and `writeScene` both
268
+ * resolve the shot from the playhead, and a camera drag on the stage was
269
+ * already allowed. So the rail now offers what the stage already did.
270
+ *
271
+ * WHERE THE TWO DIFFER IS THE SEAM. PROJECT holds `shotTransition`, because a
272
+ * transition is a property of the join between two shots and that join is
273
+ * drawn there: the shot row puts a diamond on every cut. SHOT holds plain
274
+ * `shot`, because inside one shot the strip is gone and the shot after it is
275
+ * off screen, so the one thing an author cannot see is the join a transition
276
+ * describes. DEFINITION is the open component's own panel; the scene sections
277
+ * there would describe a scene the stage is not rendering.
278
+ *
279
+ * MAKE IT YOURS comes second in both Studio contexts, right after the context
280
+ * itself: in a Project started from a template, swapping its fields for one's
281
+ * own is the first work there is. It is a DATA gate, in the spirit of the
282
+ * layer withholdings: it renders only while `swapFieldsOf` lists a field.
283
+ */
284
+ export const CONTAINER_LAYOUT: Record<ContainerSubject, readonly ContainerSectionId[]> = {
285
+ project: ["project", "makeItYours", "shotTransition", "camera", "blur", "postprocessing"],
286
+ shot: ["shot", "makeItYours", "camera", "project", "blur", "postprocessing"],
287
+ definition: ["definition"],
288
+ // STORYBOARD is the board's own panel. Each section gates on WHAT the
289
+ // board's selection points at (one card, one cut), a data question
290
+ // in the spirit of the layer withholdings above, so exactly one of them
291
+ // renders at a time. With nothing of that kind selected the right column
292
+ // holds no inspector (`boardRightPanel`), so there is no Doc or Part section
293
+ // any more.
294
+ storyboard: ["storyboardReference", "storyboardCut"],
295
+ };
@@ -0,0 +1,199 @@
1
+ // THE ONE CONVERSION between what a prop row's control hands back and what the
2
+ // document may hold, for every ControlSpec row in the chrome: a placed code
3
+ // component's props, a Studio-made component's overrides and published props,
4
+ // a code component's defaults, and one use of either.
5
+ //
6
+ // ── WHY THE CONTRACT'S `coerceValue` AND NOT A CHECK OF ITS OWN ─────────
7
+ //
8
+ // Each surface used to run its own `asValue`, which took any string, any
9
+ // boolean and any short number list and refused every object. So the curve and
10
+ // gradient editors, which hand back the decoded VALUE OBJECT, ended every edit
11
+ // in an error and their props could not be changed at all, while a colour box
12
+ // stored "banana" and an enum stored an option the contract no longer has.
13
+ // `coerceValue` is the contract's own answer: it encodes a composite to its
14
+ // canonical JSON, checks enum membership and tuple shapes, and ends at the
15
+ // engine's value-shape gate (finite numbers, `#rrggbb[aa]` colours, unit
16
+ // quaternions), the gate the save itself runs.
17
+ //
18
+ // ── NULL IS "NO ASSET", NOT "NOT A VALUE" ───────────────────────────────
19
+ //
20
+ // An asset control's "None" (and an emptied id field) hands back null, which no
21
+ // document field can hold: an asset prop with no asset is a prop that stores
22
+ // nothing and falls back to its default. So "None" CLEARS the row when that
23
+ // fallback is itself no asset, and is refused with the reason when the default
24
+ // names one, rather than storing a value that would read back as the default's
25
+ // asset and look like the press had been ignored.
26
+ import { clampedStoredValue, coerceStoredValue, controlLabel, rangeWordsOf } from "@dailies-studio/contract";
27
+ import type { Contract, ControlSpec } from "@dailies-studio/contract";
28
+ import type { Value } from "@dailies-studio/engine";
29
+ import { exposedSpecOf, toTrackHex } from "@dailies-studio/shot/doc";
30
+ import { mimeForPath } from "@dailies-studio/shot/mime";
31
+ import type { ComponentDef3D, Doc3D, ExposedProp3D, ShotAssetKind } from "@dailies-studio/shot/doc";
32
+ import type { PropControlAsset } from "@dailies-studio/ui";
33
+ import { fileNameOf } from "../files/resourceParts.js";
34
+
35
+ /** The engine Value a control's value is stored as, or null when it cannot be
36
+ * one (the document would refuse it). */
37
+ export function coercePropValue(spec: ControlSpec, raw: unknown): Value | null {
38
+ const out = coerceStoredValue(spec, raw);
39
+ return out.ok ? out.value : null;
40
+ }
41
+
42
+ /** What a prop row does with a value its control handed back. */
43
+ export type PropEdit =
44
+ | { kind: "set"; value: Value }
45
+ /** Store nothing: the row falls back to its default (an asset's "None"
46
+ * over a default that names no asset). */
47
+ | { kind: "clear" }
48
+ | { kind: "refused"; reason: string };
49
+
50
+ /** No asset: what an asset control's "None" and an emptied id field commit. */
51
+ function isNoAsset(value: unknown): boolean {
52
+ return value === null || value === undefined || value === "";
53
+ }
54
+
55
+ /** The row's words for a refusal, read defensively: a hand-built spec may
56
+ * carry no key at all. */
57
+ function wordsOf(spec: ControlSpec): string {
58
+ const key = typeof spec.key === "string" ? spec.key : "";
59
+ return controlLabel(typeof spec.label === "string" ? { key, label: spec.label } : { key }) || "This prop";
60
+ }
61
+
62
+ /**
63
+ * The edit a row makes for `raw`. `fallback` is what the row shows when it
64
+ * stores nothing (the contract default, the master's value), which decides
65
+ * whether an asset's "None" can be kept by clearing.
66
+ */
67
+ export function propEditOf(spec: ControlSpec, raw: unknown, fallback: unknown): PropEdit {
68
+ const label = wordsOf(spec);
69
+ if (spec.kind === "asset" && isNoAsset(raw)) {
70
+ return isNoAsset(fallback)
71
+ ? { kind: "clear" }
72
+ : { kind: "refused", reason: `${label} cannot be set to no asset here: its default names one. Pick another asset instead.` };
73
+ }
74
+ const out = coerceStoredValue(spec, raw);
75
+ return out.ok ? { kind: "set", value: out.value } : { kind: "refused", reason: `${label} cannot hold that value (${out.error}).` };
76
+ }
77
+
78
+ /**
79
+ * A stored number or vector outside its spec's range, which its field cannot
80
+ * show truthfully (the slider sits at the end, the box shows a number the
81
+ * field would never commit): a component narrowed the range after the value
82
+ * was set, or a hand edit put it there. The row's warning, and the nearest
83
+ * value inside (`clampedStoredValue`) its "Bring inside" stores. Null when
84
+ * the value is inside, or the spec has no range.
85
+ */
86
+ export function outsideRangeOf(
87
+ spec: ControlSpec,
88
+ value: Value | undefined,
89
+ ): { words: string; title: string; inside: Value } | null {
90
+ if (value === undefined || (spec.kind !== "number" && spec.kind !== "vec2" && spec.kind !== "vec3")) return null;
91
+ const inside = clampedStoredValue(spec, value);
92
+ const range = rangeWordsOf(spec);
93
+ if (inside === value || range === null) return null;
94
+ const shown = (v: Value): string => (Array.isArray(v) ? v.join(", ") : String(v));
95
+ const label = wordsOf(spec);
96
+ return {
97
+ words: `${label} is ${shown(value)}, outside its range of ${range}.`,
98
+ title: `Set ${label} to ${shown(inside)}, the nearest value inside its range`,
99
+ inside,
100
+ };
101
+ }
102
+
103
+ /**
104
+ * The value as the row's control should be handed it. A colour is read in any
105
+ * spelling a layer holds (a paint's `rgba(30,215,96,0.18)`, a short `#fff`) and
106
+ * shown as the hex the colour field reads and writes, the respelling the
107
+ * keyframe seam makes (`toTrackHex`); one it cannot read is shown as it is.
108
+ */
109
+ export function shownPropValue(spec: ControlSpec, value: unknown): unknown {
110
+ if (spec.kind === "color" && typeof value === "string") return toTrackHex(value) ?? value;
111
+ return value;
112
+ }
113
+
114
+ /**
115
+ * What a prop row shows while it follows its master (it stores and tries
116
+ * nothing of its own): the MASTER'S VALUE, what an un-overridden placement
117
+ * draws (`masterValueOf`, `exposedMasterValue`), whenever the row's control
118
+ * can hold it. Else the spec's default, a valid typed value: a published
119
+ * prop's master falls back to its stored `default` where the definition draws
120
+ * nothing, and that can be the blank an old `expose_prop` minted.
121
+ *
122
+ * Not the spec's default first: `exposedSpecOf` takes the published `default`
123
+ * as its own, and that one drifts from the layer once the published field is
124
+ * edited anywhere but the props panel, so every row showed a value nothing on
125
+ * screen had.
126
+ */
127
+ export function masterRowValue(spec: ControlSpec, master: unknown): unknown {
128
+ const typed = "default" in spec ? spec.default : undefined;
129
+ if (master === undefined) return typed;
130
+ return coercePropValue(spec, shownPropValue(spec, master)) !== null ? master : (typed ?? master);
131
+ }
132
+
133
+ /** A spec PropControl draws as one box per part (a vec2, a vec3, a
134
+ * quaternion's Euler X, Y and Z), whatever value it holds. A verb on the
135
+ * whole track (the expose pin) sits once in such a row's label column, where
136
+ * a box's accessory would repeat in every part and crowd the first. */
137
+ export function isVectorSpec(spec: ControlSpec): boolean {
138
+ return spec.kind === "vec2" || spec.kind === "vec3" || spec.kind === "quaternion";
139
+ }
140
+
141
+ /** An exposed prop's row: its control, and whether anything in reach could
142
+ * describe one. */
143
+ export interface ExposedRow {
144
+ spec: ControlSpec;
145
+ /** The target takes `#rrggbb` only, so the colour field offers no alpha. */
146
+ opaqueColor: boolean;
147
+ /** Nothing describes the control (a kind this editor does not know, an enum
148
+ * or an asset the record cannot carry the options or kind of): the row is
149
+ * read-only, its control saying what it can ("Unknown kind: …", "No
150
+ * options"), where it used to be a bare badge. */
151
+ undescribed: boolean;
152
+ }
153
+
154
+ /**
155
+ * The row for one exposed prop of a definition, from what the prop drives
156
+ * (`exposedSpecOf`: its target's table row, contract spec or graph parameter),
157
+ * so the definition's own panel, an instance's override rows and one use's
158
+ * panel draw the same bounded, typed control for it.
159
+ */
160
+ export function exposedRowOf(
161
+ prop: ExposedProp3D,
162
+ def: ComponentDef3D,
163
+ materials: Doc3D["materials"] | undefined,
164
+ contracts: Readonly<Record<string, Contract>>,
165
+ ): ExposedRow {
166
+ const control = exposedSpecOf(prop, def, { materials, contracts });
167
+ if (control !== null) return { spec: control.spec, opaqueColor: control.opaqueColor, undescribed: false };
168
+ const spec = { key: prop.key, propName: prop.key, label: prop.label, kind: prop.kind, animatable: false };
169
+ return { spec: spec as unknown as ControlSpec, opaqueColor: false, undescribed: true };
170
+ }
171
+
172
+ /** A Project asset's kind in the contract's words (`AssetSpec.assetKind`). A
173
+ * model is a "glb" there; a video has no asset kind a contract can ask for. */
174
+ function contractAssetKind(kind: ShotAssetKind): string {
175
+ return kind === "model" ? "glb" : kind;
176
+ }
177
+
178
+ /**
179
+ * The Project's assets as an asset prop's picker offers them: by id, named by
180
+ * their file, in the contract's kinds, each with its file `name` and its MIME
181
+ * type, which the picker reads against the spec's `accept` list
182
+ * (`assetAccepted`): an extension entry (".png") against the name, a MIME
183
+ * entry ("image/svg+xml", "image/*") against the type.
184
+ *
185
+ * A Project asset records no MIME type (`ShotAsset`: a path, a hash, a kind
186
+ * and a probe), so the type is the one the studio serves its stored file as,
187
+ * from the one extension-to-MIME table (`mimeForPath`,
188
+ * `@dailies-studio/shot/mime`). A file whose extension the table does not know
189
+ * carries no type, and the picker offers it rather than hide it.
190
+ */
191
+ export function projectAssetsOf(assets: Doc3D["assets"] | undefined): PropControlAsset[] {
192
+ return Object.values(assets ?? {})
193
+ .map((asset) => {
194
+ const name = fileNameOf(asset);
195
+ const mime = mimeForPath(asset.path);
196
+ return { id: asset.id, label: name, kind: contractAssetKind(asset.kind), name, ...(mime === undefined ? {} : { mime }) };
197
+ })
198
+ .sort((a, b) => a.label.localeCompare(b.label));
199
+ }