@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,137 @@
1
+ // ON-DEMAND PANELS: the chrome's load diet (docs/performance-chrome-load-2026-10.md).
2
+ //
3
+ // The entry chunk holds the shell and Studio. Every other workspace, dialog
4
+ // and drawer is a `lazyPanel`: its module (and whatever only it imports, the
5
+ // CodeMirror and React Flow stacks among them) is a chunk fetched the first
6
+ // time it renders. The shell that decides WHETHER it renders stays eager and
7
+ // returns null while it is not wanted, so a closed panel costs nothing.
8
+ //
9
+ // WHY NOT `React.lazy` ALONE. A lazy component suspends on its first render
10
+ // even when its module is already in memory, so a panel the idle prefetch has
11
+ // fetched would still flash its fallback for a frame, and every unit test
12
+ // that mounts a shell would have to await a panel it already imported. Here
13
+ // a loaded module renders in the same commit, and only a real fetch shows the
14
+ // fallback.
15
+ //
16
+ // A FAILED FETCH (a deploy replaced the chunk under an open tab, a dropped
17
+ // connection) throws with a sentence saying what to do, and the boundary's
18
+ // Try again fetches again. EVERY PANEL CARRIES ITS OWN `PanelBoundary`, named by
19
+ // its `label`: several call sites (the right column, the dialogs, the Insert
20
+ // drawer) have no boundary above them but the root's, and a throw there
21
+ // unmounts the whole editor, stage and all, for a chunk that did not arrive.
22
+ import { Suspense, use, useState, type ComponentType, type ReactNode } from "react";
23
+ import { PanelBoundary } from "@dailies-studio/ui";
24
+
25
+ export interface LazyPanel<P extends object> {
26
+ (props: P): ReactNode;
27
+ /** Fetch the module now; safe to call often. */
28
+ preload(): Promise<unknown>;
29
+ }
30
+
31
+ /** Every chunk's `preload`, for `preloadPanels`. */
32
+ const preloads: (() => Promise<unknown>)[] = [];
33
+
34
+ export const PANEL_LOAD_FAILED = "This part of Dailies did not load. Reload the page to get the latest version.";
35
+
36
+ /**
37
+ * A chunk several panels come from. They share ONE fetch and one loaded
38
+ * module, so once any of them has loaded, every other renders at once: the
39
+ * board's right-column panels never wait on a chunk the board already has.
40
+ */
41
+ export function lazyChunk<M>(load: () => Promise<M>): {
42
+ preload: () => Promise<M>;
43
+ /** A panel from this chunk. `label` names it on the crash card; `fallback`
44
+ * is drawn in its place while the fetch runs: the panel's own skeleton, so
45
+ * nothing around it moves when it lands. */
46
+ panel: <P extends object>(label: string, pick: (module: M) => ComponentType<P>, fallback?: ReactNode) => LazyPanel<P>;
47
+ } {
48
+ let loaded: { module: M } | null = null;
49
+ let pending: Promise<M> | null = null;
50
+ // ONE PROMISE PER ATTEMPT. A render that suspended on a fetch that then
51
+ // failed must meet the SAME rejected promise when React renders it again,
52
+ // or the error never reaches the boundary: a fresh fetch suspends again,
53
+ // and the panel refetches its chunk forever behind its skeleton. A failed
54
+ // attempt is forgotten only by the boundary's catch (so Try again fetches
55
+ // anew) and by a `preload` that failed (so the next open fetches anew).
56
+ const attempt = (): Promise<M> =>
57
+ (pending ??= load().then(
58
+ (module) => (loaded = { module }).module,
59
+ (cause: unknown) => {
60
+ throw new Error(PANEL_LOAD_FAILED, { cause });
61
+ },
62
+ ));
63
+ const preload = (): Promise<M> => {
64
+ const tried = attempt();
65
+ tried.catch(() => {
66
+ if (pending === tried) pending = null;
67
+ });
68
+ return tried;
69
+ };
70
+ const forget = (): void => {
71
+ if (loaded === null) pending = null;
72
+ };
73
+ preloads.push(preload);
74
+ const panel = <P extends object>(
75
+ label: string,
76
+ pick: (module: M) => ComponentType<P>,
77
+ fallback: ReactNode = null,
78
+ ): LazyPanel<P> => {
79
+ function Body(props: P) {
80
+ const Panel = pick(loaded === null ? use(attempt()) : loaded.module);
81
+ return <Panel {...props} />;
82
+ }
83
+ function Lazy(props: P) {
84
+ return (
85
+ <PanelBoundary label={label} onCatch={forget}>
86
+ <Suspense fallback={fallback}>
87
+ <Body {...props} />
88
+ </Suspense>
89
+ </PanelBoundary>
90
+ );
91
+ }
92
+ return Object.assign(Lazy, { preload });
93
+ };
94
+ return { preload, panel };
95
+ }
96
+
97
+ /** A panel that is a chunk of its own: `load` resolves to the component. */
98
+ export function lazyPanel<P extends object>(
99
+ label: string,
100
+ load: () => Promise<ComponentType<P>>,
101
+ fallback: ReactNode = null,
102
+ ): LazyPanel<P> {
103
+ return lazyChunk(load).panel(label, (component) => component, fallback);
104
+ }
105
+
106
+ /**
107
+ * True from the first render where `on` is true, for the rest of the
108
+ * component's life. A shell latches its panel: the chunk is fetched the first
109
+ * time the panel is wanted, and after that the panel stays mounted and gates
110
+ * itself, exactly as it did when it loaded with the entry, so its state and
111
+ * its close transition survive.
112
+ */
113
+ export function useLatch(on: boolean): boolean {
114
+ const [latched, setLatched] = useState(on);
115
+ if (on && !latched) setLatched(true);
116
+ return latched || on;
117
+ }
118
+
119
+ /** Load every panel declared so far. Tests call it so a mounted shell renders
120
+ * its panels in the same commit, as a warm session does. */
121
+ export async function preloadPanels(): Promise<void> {
122
+ await Promise.all(preloads.map((preload) => preload()));
123
+ }
124
+
125
+ /**
126
+ * Run `work` once the page is idle after first paint, so a prefetch never
127
+ * competes with the boot. Returns a cancel. `requestIdleCallback` is missing
128
+ * in Safari and jsdom; a timeout stands in.
129
+ */
130
+ export function whenIdle(work: () => void): () => void {
131
+ if (typeof window.requestIdleCallback === "function") {
132
+ const id = window.requestIdleCallback(work, { timeout: 4000 });
133
+ return () => window.cancelIdleCallback(id);
134
+ }
135
+ const id = window.setTimeout(work, 1500);
136
+ return () => window.clearTimeout(id);
137
+ }
@@ -0,0 +1,203 @@
1
+ // WHAT LOADS ON DEMAND, in one list (docs/performance-chrome-load-2026-10.md).
2
+ //
3
+ // The /scene entry is the shell and Studio. Each surface here is a chunk the
4
+ // shell fetches the first time it is wanted (app/lazyPanel.tsx): the
5
+ // Storyboard, Components, Code Studio with CodeMirror, the material nodes
6
+ // with React Flow, the Library, Export, Version history, Preferences and
7
+ // Insert, the font picker, the inspector's two template sections, and the
8
+ // Agent and Comments panels. Timeline views that load when
9
+ // they open (Sound, Graph, Generate) are declared beside the dock that shows
10
+ // them (TimelineDock.tsx).
11
+ //
12
+ // Each export keeps the name of the panel it stands for, so a call site reads
13
+ // as it did when the panel loaded with the entry. A GATED one is that panel's
14
+ // eager shell: null until the panel is first wanted, then latched (`useLatch`)
15
+ // so the panel gates itself from there on. The others are mounted by a call
16
+ // site that already decides when.
17
+ //
18
+ // A FALLBACK IS THE PANEL'S OWN SKELETON, drawn in the panel's place while
19
+ // its chunk loads, so nothing around it moves when it lands. A LABEL names
20
+ // the panel on the crash card its own boundary draws when the chunk does not
21
+ // arrive (lazyPanel.tsx).
22
+ import { useSyncExternalStore } from "react";
23
+ import type { ComponentType, ReactNode } from "react";
24
+ import { useShotEditor, useStore } from "../state/context.js";
25
+ import type { ShotEditorState } from "../state/types.js";
26
+ import { workspaceOf } from "../state/workspace.js";
27
+ import { InCell } from "../panels/stage/cellSlots.js";
28
+ import { lazyChunk, lazyPanel, useLatch, type LazyPanel } from "./lazyPanel.js";
29
+
30
+ // One chunk each: a surface's panels share their imports, and the board's
31
+ // right-column panels must be ready the moment the board is.
32
+ const storyboard = lazyChunk(() => import("../panels/storyboard/board.js"));
33
+ const components = lazyChunk(() => import("../panels/studio/components.js"));
34
+
35
+ /** A shell: null until `wanted` first holds, then the panel, for good. */
36
+ function gated<P extends object>(Panel: LazyPanel<P>, wanted: (s: ShotEditorState) => boolean): ComponentType<P> {
37
+ return function Gate(props: P) {
38
+ return useLatch(useShotEditor(wanted)) ? <Panel {...props} /> : null;
39
+ };
40
+ }
41
+
42
+ /** Draws `children` only while `wanted` holds: a skeleton for a surface that
43
+ * was left before its chunk arrived must not stand over the next one. */
44
+ function While({ wanted, children }: { wanted: (s: ShotEditorState) => boolean; children: ReactNode }) {
45
+ return useShotEditor(wanted) ? children : null;
46
+ }
47
+
48
+ const onBoard = (s: ShotEditorState): boolean => workspaceOf(s) === "storyboard";
49
+ const inComponents = (s: ShotEditorState): boolean => workspaceOf(s) === "components";
50
+ const inCode = (s: ShotEditorState): boolean => inComponents(s) && s.codeComponent !== null && s.componentsTab === "edit";
51
+ const inMaterial = (s: ShotEditorState): boolean => workspaceOf(s) === "material";
52
+
53
+ /** The board's skeleton: its bar and the empty desk, in the canvas cell. */
54
+ const BOARD_SKELETON = (
55
+ <While wanted={onBoard}>
56
+ <InCell name="centre">
57
+ <div className="board-skeleton" aria-busy="true">
58
+ <div className="panel-head" />
59
+ </div>
60
+ </InCell>
61
+ </While>
62
+ );
63
+
64
+ /** A mode's skeleton: its left column with its head, and its canvas. */
65
+ function modeSkeleton(wanted: (s: ShotEditorState) => boolean): ReactNode {
66
+ return (
67
+ <While wanted={wanted}>
68
+ <InCell name="left">
69
+ <div className="mode-skeleton" aria-busy="true">
70
+ <div className="panel-head" />
71
+ </div>
72
+ </InCell>
73
+ <InCell name="centre">
74
+ <div className="mode-skeleton is-canvas" aria-busy="true" />
75
+ </InCell>
76
+ </While>
77
+ );
78
+ }
79
+
80
+ /** A right-column panel that brings its own head: the head, on the column's
81
+ * ground. */
82
+ const HEAD_SKELETON = <div className="panel-head" aria-busy="true" />;
83
+
84
+ // ── THE STORYBOARD ──────────────────────────────────────────────────────────
85
+ export const StoryboardView = gated(
86
+ storyboard.panel("Storyboard", (m) => m.StoryboardView, BOARD_SKELETON),
87
+ onBoard,
88
+ );
89
+ export const ComponentSheet = storyboard.panel("Component sheet", (m) => m.ComponentSheet, HEAD_SKELETON);
90
+ export const PlanOccupant = storyboard.panel("Plan", (m) => m.PlanOccupant, HEAD_SKELETON);
91
+ export const SketchInspector = storyboard.panel("Sketch inspector", (m) => m.SketchInspector, HEAD_SKELETON);
92
+ /** The inspector's section for a board card (InspectorPanel), shown only on
93
+ * the board, so it rides in the board's chunk. */
94
+ export const StoryboardReferenceSection = storyboard.panel("Card", (m) => m.StoryboardReferenceSection);
95
+
96
+ /** Fetch the Storyboard while the page is idle, so the first switch to it is
97
+ * as quick as every later one. */
98
+ export const prefetchStoryboard = storyboard.preload;
99
+
100
+ // ── THE INSPECTOR'S ON-DEMAND SECTIONS, fetched at idle ────────────────────
101
+ /** "Template field" (one text, image or video layer), "Make it yours" (no
102
+ * selection, a Project with fields) and "Motion" (the motion presets, every
103
+ * layer), drawn by InspectorPanel. Each is a chunk of its own, kept out of
104
+ * the entry's budget, and fetched at idle like the Storyboard
105
+ * (`prefetchInspectorSections`, App.tsx), so a selection made after that
106
+ * draws it in the same commit; before it lands it draws nothing. */
107
+ export const TemplateFieldSection = lazyPanel("Template field", () =>
108
+ import("../panels/inspector/design/TemplateFieldSection.js").then((m) => m.TemplateFieldSection),
109
+ );
110
+ export const MakeItYoursSection = lazyPanel("Make it yours", () =>
111
+ import("../panels/inspector/scene/MakeItYoursSection.js").then((m) => m.MakeItYoursSection),
112
+ );
113
+ export const PresetsSection = lazyPanel("Motion", () =>
114
+ import("../panels/inspector/animate/PresetsSection.js").then((m) => m.PresetsSection),
115
+ );
116
+ export const prefetchInspectorSections = (): Promise<unknown> =>
117
+ Promise.all([
118
+ TemplateFieldSection.preload(),
119
+ MakeItYoursSection.preload(),
120
+ PresetsSection.preload(),
121
+ // The stamp the Motion section's picks run (`applyMotionPreset`).
122
+ import("../state/motionStamp.js"),
123
+ ]);
124
+
125
+ // ── COMPONENTS AND CODE ─────────────────────────────────────────────────────
126
+ // Preview and the Studio share a chunk and load together, so the Preview
127
+ // shell, mounted for the whole workspace, draws the one skeleton.
128
+ export const ComponentsPreview = gated(
129
+ components.panel("Components", (m) => m.ComponentsPreview, modeSkeleton(inComponents)),
130
+ inComponents,
131
+ );
132
+ export const ComponentStudio = gated(
133
+ components.panel("Component studio", (m) => m.ComponentStudio),
134
+ inComponents,
135
+ );
136
+ export const CodeStudio = gated(
137
+ lazyPanel("Code studio", () => import("../panels/code/CodeStudio.js").then((m) => m.CodeStudio), modeSkeleton(inCode)),
138
+ inCode,
139
+ );
140
+
141
+ // ── THE MATERIAL NODES ──────────────────────────────────────────────────────
142
+ export const MaterialWorkspace = gated(
143
+ lazyPanel("Material workspace", () => import("../panels/material/MaterialWorkspace.js").then((m) => m.MaterialWorkspace), modeSkeleton(inMaterial)),
144
+ inMaterial,
145
+ );
146
+
147
+ // ── DIALOGS AND DRAWERS: on open ───────────────────────────────────────────
148
+ export const LibraryBrowser = gated(
149
+ lazyPanel("Library", () => import("../panels/library/LibraryBrowser.js").then((m) => m.LibraryBrowser)),
150
+ (s) => s.libraryBrowserOpen,
151
+ );
152
+ export const PreferencesDialog = gated(
153
+ lazyPanel("Preferences", () => import("../panels/preferences/PreferencesDialog.js").then((m) => m.PreferencesDialog)),
154
+ (s) => s.prefsOpen,
155
+ );
156
+ export const InsertDrawer = gated(
157
+ lazyPanel("Insert", () => import("../panels/insert/InsertDrawer.js").then((m) => m.InsertDrawer)),
158
+ (s) => s.insertDrawer !== null && !s.readOnly,
159
+ );
160
+ /** Mounted by App only while `exportOpen`. */
161
+ export const ExportDialog = lazyPanel("Export", () => import("../panels/export/ExportDialog.js").then((m) => m.ExportDialog));
162
+ /** Mounted by RightColumn only while `versionsOpen`; it takes the column,
163
+ * head and all. */
164
+ export const VersionHistoryPanel = lazyPanel(
165
+ "Version history",
166
+ () => import("../panels/versions/VersionHistoryPanel.js").then((m) => m.VersionHistoryPanel),
167
+ HEAD_SKELETON,
168
+ );
169
+
170
+ const AgentQuestionPanel = lazyPanel("Agent question", () =>
171
+ import("../panels/agent/AgentQuestionDialog.js").then((m) => m.AgentQuestionDialog),
172
+ );
173
+ /** The agent's question to the person (state/agentQuestion.ts): its chunk
174
+ * loads the first time a question opens, or a studio server render starts
175
+ * for an export ask (the chunk reports it when it ends), and stays.
176
+ * Unconditional in App, whatever workspace is on screen. */
177
+ export function AgentQuestionDialog() {
178
+ const store = useStore();
179
+ const wanted = useSyncExternalStore(store.agentQuestion.subscribe, () => {
180
+ const s = store.agentQuestion.getState();
181
+ return s.open || s.exportAsk?.serverJob !== undefined;
182
+ });
183
+ return useLatch(wanted) ? <AgentQuestionPanel /> : null;
184
+ }
185
+
186
+ // ── THE FONT PICKER: on open ───────────────────────────────────────────────
187
+ /** Mounted by the inspector's Font field (FontField.tsx) only while open,
188
+ * inside the field box; its module owns the Popover. Preloaded as the pointer
189
+ * or focus reaches the field. Its skeleton is a ring in the box's accessory
190
+ * lane, where a write's progress sits. */
191
+ export const FontPicker = lazyPanel(
192
+ "Font picker",
193
+ () => import("../panels/fonts/FontPicker.js").then((m) => m.FontPicker),
194
+ <span className="field-accessory">
195
+ <span className="font-field-wait" aria-busy="true" />
196
+ </span>,
197
+ );
198
+
199
+ // ── THE AGENT AND COMMENTS: on first open ──────────────────────────────────
200
+ /** Kept mounted by RightColumn after its first open, under an `<Activity>`. */
201
+ export const AgentPanel = lazyPanel("Agent", () => import("../panels/agent/AgentPanel.js").then((m) => m.AgentPanel));
202
+ /** Mounted by RightColumn while the Comments tab is the occupant. */
203
+ export const CommentsPanel = lazyPanel("Comments", () => import("../panels/comments/CommentsPanel.js").then((m) => m.CommentsPanel));
@@ -10,11 +10,13 @@
10
10
  // state (session, never document), so the dock head's controls and this bridge
11
11
  // read one bit and cannot disagree.
12
12
  import { useEffect } from "react";
13
+ import { MIX_SAMPLE_RATE } from "@dailies-studio/engine";
13
14
  import { useStore } from "../state/context.js";
15
+ import { transportAudible } from "../state/types.js";
14
16
  import { createAudioPreview } from "./preview.js";
15
17
  import type { AudioContextLike, AudioPreview, AudioPreviewDeps } from "./preview.js";
16
18
 
17
- export { SCRUB_JUMP_FRAMES, createAudioPreview } from "./preview.js";
19
+ export { DRIFT_FRAMES, createAudioPreview } from "./preview.js";
18
20
  export type {
19
21
  AudioBufferLike,
20
22
  AudioBufferSourceNodeLike,
@@ -26,17 +28,22 @@ export type {
26
28
  TransportSnapshot,
27
29
  } from "./preview.js";
28
30
 
29
- async function fetchBytes(url: string): Promise<ArrayBuffer> {
30
- const res = await fetch(url);
31
+ async function fetchBytes(url: string, priority?: "low"): Promise<ArrayBuffer> {
32
+ const res = await fetch(url, { priority: priority ?? "auto" });
31
33
  if (!res.ok) throw new Error(`GET ${url} -> ${res.status}`);
32
34
  return res.arrayBuffer();
33
35
  }
34
36
 
37
+ /** ONE offline context decodes every clip, so a decode ahead needs no realtime
38
+ * context, and none exists before a press. At the export mix's rate. */
39
+ let decoder: OfflineAudioContext | null = null;
40
+
35
41
  const browserDeps: AudioPreviewDeps = {
36
- // Lazy: the first play edge is the user gesture that may create the context.
42
+ // Lazy: the first press (a queued Play's arm, or the play edge) creates it.
37
43
  createContext: () => new AudioContext() as unknown as AudioContextLike,
38
44
  fetchBytes,
39
- decode: (ctx, bytes) => (ctx as unknown as AudioContext).decodeAudioData(bytes),
45
+ // A COPY, because `decodeAudioData` detaches the buffer it is handed.
46
+ decode: (bytes) => (decoder ??= new OfflineAudioContext(2, 1, MIX_SAMPLE_RATE)).decodeAudioData(bytes.slice(0)),
40
47
  };
41
48
 
42
49
  /** `create` is the test seam; production gets Web Audio. */
@@ -49,6 +56,35 @@ export function AudioPreviewBridge(props: { create?: () => AudioPreview } = {}):
49
56
  let volume: number | null = null;
50
57
  const push = (): void => {
51
58
  const s = store.getState();
59
+ // THE TRANSPORT FIRST. An unmute reschedules against the snapshot the
60
+ // scheduler holds, so it has to hold THIS one: pushing the monitor bits
61
+ // first anchored a session on the frame from the PREVIOUS notification
62
+ // whenever the two changed together. The comment here used to argue the
63
+ // opposite order for the same reason, and had the dependency backwards.
64
+ preview.update({
65
+ playing: s.playing,
66
+ frame: s.frame,
67
+ doc: s.doc,
68
+ // ONE PREDICATE, and it is not this file's. A component context drives
69
+ // a definition-local clock and never moves `frame`; a shuttle rate
70
+ // other than 1 would need reversed buffers or a time stretcher. Both
71
+ // are "the picture's clock and the audio clock would disagree", which
72
+ // is why they are decided together in `transportAudible` (state/types
73
+ // .ts) rather than assembled here out of two field reads.
74
+ audible: transportAudible(s),
75
+ scene: s.enteredScene,
76
+ // Per-tab monitoring: the bridge is the one place solo reaches.
77
+ solo: s.soloTracks,
78
+ // A queued Play (bridge v51). The store notifies inside the `set`
79
+ // that arms it, which is the press, so the context wakes there.
80
+ armed: s.playIntent !== null,
81
+ // The instant the transport started, which the picture clock counts
82
+ // from too (Header.tsx).
83
+ origin: s.playOrigin,
84
+ // A stage attached that owes the open subject no picture: the ready
85
+ // edge the decode ahead waits for.
86
+ presented: s.stageInfo !== null && !s.stageBusy,
87
+ });
52
88
  if (s.previewMuted !== muted) {
53
89
  muted = s.previewMuted;
54
90
  preview.setMasterMute(muted);
@@ -57,11 +93,6 @@ export function AudioPreviewBridge(props: { create?: () => AudioPreview } = {}):
57
93
  volume = s.previewVolume;
58
94
  preview.setMasterVolume(volume);
59
95
  }
60
- // AFTER the monitor bits: an unmute that reschedules must do so knowing
61
- // the transport it is rescheduling against, and `update` is what records
62
- // it. On the very first push both orders agree, because the scheduler
63
- // starts paused.
64
- preview.update({ playing: s.playing, frame: s.frame, doc: s.doc });
65
96
  };
66
97
  push();
67
98
  const unsub = store.subscribe(push);