@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,562 @@
1
+ // Which frames the stage draws once, before playback starts, so that playback
2
+ // never pays a first-use cost.
3
+ //
4
+ // ── WHY PLAYBACK NEEDS THIS AT ALL ─────────────────────────────────────────
5
+ //
6
+ // The first time a frame is really drawn, the GPU process does work the
7
+ // warm-up cannot do ahead of it: the first submit of a new pipeline, of a
8
+ // transition's render targets, of a caption's rasters. Measured on
9
+ // examples/training-season-reel (1080p, WebGPU, RTX 3060): the first loop
10
+ // stalled 3.0 s in total with gaps up to 530 ms, and every later loop about
11
+ // 1.1 s with none over 110 ms. The warm-up compiles STAND-INS of the next
12
+ // scene while the transport runs; a stand-in builds the program but not the
13
+ // first real draw, and it only gets the frames before the cut to do it in.
14
+ //
15
+ // Drawing these frames once through the ordinary seek path, with the stage in
16
+ // its playing presentation, pays that cost under a frozen picture (bridge
17
+ // v51): in the background while the author sits paused, or for a queued Play.
18
+ // Measured end to end on the landscape cut: the first loop's stalls fell from
19
+ // 3.2 s to about 0.3 s and its worst gap from 284 ms to under 100 ms, for a
20
+ // pass of about 3 s. HyperFrames makes the same trade for its shader
21
+ // transitions: it holds `play()` while it renders every transition frame once.
22
+ //
23
+ // ── WHICH FRAMES, AND IN WHICH ORDER ───────────────────────────────────────
24
+ //
25
+ // The frames where something can appear that the GPU has not drawn yet:
26
+ //
27
+ // - a Shot's first frame, where its scene mounts;
28
+ // - a transition window's first and last frames and the first frame after
29
+ // it, where the held Shot leaves (the stalls sat on both ends). Under
30
+ // `hold` the outgoing Shot is one frozen picture for the whole window, so
31
+ // the frames between buy nothing but the keys inside it of the incoming
32
+ // Shot's fades, blurs and component props: that Shot plays on into the TO
33
+ // operand, a target keyed apart from the canvas when the Shot has no post
34
+ // chain, and the one frame per state the rule below picks can land outside
35
+ // the window. Under `run` the
36
+ // outgoing Shot plays on past its own end, and every window frame is a
37
+ // picture of it drawn nowhere else, so all of them;
38
+ // - a layer's first frame;
39
+ // - the frames inside the Shot where one of its tracks can change what the
40
+ // renderer builds (`trackEventFrames`): one frame of each blending a fade
41
+ // draws (blending is part of a pipeline) and of each side of a blur's 0,
42
+ // both ends of a component prop, a move's last key, each step of a raster
43
+ // input. A tweened colour, raster input or geometry input builds nothing it
44
+ // can keep. Every frame of an animation was measured and bought nothing
45
+ // over its two ends (154 frames against 250, the same stalls).
46
+ //
47
+ // In playing order from the playhead, with the playhead's own Shot LAST: a
48
+ // Play pass then ends inside the Shot it hands over in, so the hand-over's
49
+ // start frame needs no remount. With the loop off, only the frames playback
50
+ // can reach from the playhead in its direction.
51
+ //
52
+ // ── WHAT IS REMEMBERED ────────────────────────────────────────────────────
53
+ //
54
+ // Each frame carries a KEY: what its pixels depend on, as content, because a
55
+ // save replaces the whole document object. The parts, each memoised by the
56
+ // identity of what it reads:
57
+ //
58
+ // - the document-wide inputs every Shot draws with: size, rate, the assets
59
+ // that are not audio, materials, material lighting, component definitions;
60
+ // - the Shot as it draws: `drawnScene`, less its name, its audio and its
61
+ // guides, so a still, a resource, a rename, a sound or a guide re-keys
62
+ // nothing;
63
+ // - the Shot before it, on the incoming transition window's frames only (the
64
+ // only frames that draw both);
65
+ // - the placed code components' module epoch (`preparationKey().modules`), on
66
+ // the Shots that place one;
67
+ // - the isolated layer, on the frames of the Shot that holds it;
68
+ // - the Shot-local frame.
69
+ //
70
+ // The store adds what the stage shows (the layout, the shading, the board) in
71
+ // front of every key, and `PreparedFrames` drops everything when the stage's
72
+ // base moves (`preparationKey().base`). A frame is credited only for what the
73
+ // stage reported of it (`credit`), so a timed-out frame is never prepared.
74
+ //
75
+ // ── WHY A FRAME WAS PENDING (the perf flag only) ──────────────────────────
76
+ //
77
+ // Under the chrome's `?perf=1` or `?perf=log`, each frame also carries its key
78
+ // in parts, `PreparedFrames` remembers the parts it last credited for each
79
+ // frame in each view, and every pass names why each of its frames is pending:
80
+ // the first part that moved, a first timeout, the clear that dropped it, or
81
+ // never drawn (`PreparedFrames.explain`, `window.__dailiesPrep`). With the
82
+ // flag off none of it runs.
83
+ import {
84
+ INSTANCE_PROP_PREFIX,
85
+ drawnScene,
86
+ sceneWindows,
87
+ shotsPlacing,
88
+ trackEventFrames,
89
+ transitionAt,
90
+ } from "@dailies-studio/shot/doc";
91
+ import type { Doc3D, Layer3D, Scene3D } from "@dailies-studio/shot/doc";
92
+ import type { ShotPreparedOutcome } from "../bridgeTypes.js";
93
+
94
+ /** The chrome's perf flag as its URL set it: the two values the stage URL
95
+ * forwards (`stageSrc`), or null. */
96
+ export type PreparationPerf = "1" | "log" | null;
97
+
98
+ /** Read once at load, like the stage's `PERF_HUD_ENABLED`, and written again
99
+ * only by the test seam below. */
100
+ let perf: PreparationPerf = chromePerfFlag();
101
+
102
+ /** The chrome's `?perf`, ALLOWLISTED: the one reading of it, for this file and
103
+ * for the stage URL StagePanel builds, which must never carry anything else. */
104
+ export function chromePerfFlag(): PreparationPerf {
105
+ const value = typeof window === "undefined" ? null : new URLSearchParams(window.location.search).get("perf");
106
+ return value === "1" || value === "log" ? value : null;
107
+ }
108
+
109
+ /** Test seam: the perf flag as the URL would set it. A `PreparedFrames` reads
110
+ * it when it is made, `playbackPreparation` on every call. Drops the last
111
+ * report. */
112
+ export function setPreparationPerf(next: PreparationPerf): void {
113
+ perf = next;
114
+ report = null;
115
+ }
116
+
117
+ export interface PreparationFrame {
118
+ /** MASTER frame to seek. */
119
+ frame: number;
120
+ /** What this frame's pixels depend on, for `PreparedFrames`. */
121
+ key: string;
122
+ /** The key in parts, under the perf flag only. */
123
+ parts?: PreparationKeyParts;
124
+ }
125
+
126
+ /** A frame's key in parts, which `PreparedFrames.explain` compares. */
127
+ export interface PreparationKeyParts {
128
+ /** Which frame this is across edits: the Shot's id and the Shot-local frame. */
129
+ id: string;
130
+ /** What the stage shows: the prefix the store adds, so empty as
131
+ * `playbackPreparation` lists it. */
132
+ view: string;
133
+ /** The document-wide inputs. */
134
+ shared: string;
135
+ /** The Shot before, on this Shot's incoming transition window (empty
136
+ * elsewhere and for the first Shot). */
137
+ prev: string;
138
+ /** This Shot. */
139
+ shot: string;
140
+ /** The placed modules' epoch, or empty for a Shot that places no code. */
141
+ modules: string;
142
+ /** The isolated layer, or empty when it is not in this Shot. */
143
+ isolation: string;
144
+ /** The Shot-local frame. */
145
+ local: number;
146
+ }
147
+
148
+ /** Where the transport starts, which orders the list. */
149
+ export interface PreparationStart {
150
+ /** The playhead, a MASTER frame. */
151
+ frame: number;
152
+ /** The transport wraps its window (`playbackLoops`). */
153
+ loop: boolean;
154
+ /** The sign of the rate it starts at. */
155
+ direction: 1 | -1;
156
+ }
157
+
158
+ /** What the stage shows besides the document, per frame. */
159
+ export interface PreparationInputs {
160
+ /** The layer the stage isolates, or null. */
161
+ isolation: string | null;
162
+ /** The placed code components' module epoch (`preparationKey().modules`). */
163
+ modules: string;
164
+ }
165
+
166
+ /**
167
+ * The frames to prepare inside a playback window, in the order to draw them.
168
+ *
169
+ * `window` is the transport's loop (`playbackWindow`): only frames playback
170
+ * will reach are prepared.
171
+ */
172
+ export function playbackPreparation(
173
+ doc: Doc3D,
174
+ window: { start: number; frames: number },
175
+ start: PreparationStart,
176
+ inputs: PreparationInputs,
177
+ ): PreparationFrame[] {
178
+ const end = window.start + window.frames;
179
+ const shared = sharedHashOf(doc);
180
+ const placing = placingOf(doc);
181
+ const withParts = perf !== null;
182
+ const shots: ShotFrames[] = [];
183
+ let previousHash = "";
184
+ for (const scene of sceneWindows(doc)) {
185
+ const body = doc.scenesById[scene.id];
186
+ const length = scene.end - scene.start;
187
+ if (body === undefined || length <= 0) continue;
188
+ const { hash, events, stateKeys } = shotFactsOf(body, doc.fps);
189
+ const blendsFrom = previousHash;
190
+ previousHash = hash;
191
+ if (scene.end <= window.start || scene.start >= end) continue;
192
+ // The blend into this Shot, and its window's last local frame (the first
193
+ // after the blend), or -1 when nothing blends into it.
194
+ const into = transitionAt(doc, scene.start);
195
+ const blend = into?.incoming === scene.id ? into : null;
196
+ const blended = blend === null ? -1 : blend.durationFrames;
197
+ const local = new Set<number>(events);
198
+ if (blend !== null) {
199
+ // `run` (`outgoingSceneFrameAt`): every window frame; `hold`, or none
200
+ // set: the window's first and last frames, the one after it, and this
201
+ // Shot's state keys between them (see the header).
202
+ if (doc.scenesById[blend.outgoing]?.transition?.outgoing === "run") {
203
+ for (let at = 0; at <= blended; at += 1) local.add(at);
204
+ } else {
205
+ local.add(0).add(blended - 1).add(blended);
206
+ // ponytail: listed for a Shot with a post chain too, whose operand
207
+ // draws its scene through a source keyed as its presenter's, so they
208
+ // buy nothing there; the chain test (`hasPostChain`) lives with three.
209
+ // Skip them once a three-free one exists.
210
+ for (const at of stateKeys) if (at >= 1 && at <= blended - 2) local.add(at);
211
+ }
212
+ }
213
+ const modules = placing.has(scene.id) ? inputs.modules : "";
214
+ const isolation = inputs.isolation !== null && body.layersById[inputs.isolation] !== undefined ? inputs.isolation : "";
215
+ const frames: PreparationFrame[] = [];
216
+ for (const at of [...local].sort((a, b) => a - b)) {
217
+ if (at < 0 || at >= length) continue;
218
+ const frame = scene.start + at;
219
+ if (frame < window.start || frame >= end) continue;
220
+ const prev = at <= blended ? blendsFrom : "";
221
+ const key = `${shared}|${prev}>${hash}${modules === "" ? "" : `~${modules}`}@${at}${isolation === "" ? "" : `!${isolation}`}`;
222
+ frames.push(
223
+ withParts
224
+ ? { frame, key, parts: { id: `${scene.id}@${at}`, view: "", shared, prev, shot: hash, modules, isolation, local: at } }
225
+ : { frame, key },
226
+ );
227
+ }
228
+ shots.push({ start: scene.start, end: scene.end, frames });
229
+ }
230
+ return inPlayingOrder(shots, window, start);
231
+ }
232
+
233
+ /** One Shot's frames inside the window, ascending. */
234
+ interface ShotFrames {
235
+ start: number;
236
+ end: number;
237
+ frames: PreparationFrame[];
238
+ }
239
+
240
+ /** The Shots in playing order from the playhead's, which comes LAST, each
241
+ * ascending; with the loop off, only the frames reachable in `direction`. */
242
+ function inPlayingOrder(
243
+ shots: readonly ShotFrames[],
244
+ window: { start: number; frames: number },
245
+ { frame, loop, direction }: PreparationStart,
246
+ ): PreparationFrame[] {
247
+ const count = shots.length;
248
+ if (count === 0) return [];
249
+ // Where the transport's first frame is, by `playbackTargetFrame`'s rule
250
+ // (Header.tsx): outside the window it starts at the in point, and with the
251
+ // loop off a start on the far edge plays again from the near one.
252
+ const last = window.start + window.frames - 1;
253
+ let from = frame >= window.start && frame <= last ? frame : window.start;
254
+ if (!loop && from === (direction < 0 ? window.start : last)) from = direction < 0 ? last : window.start;
255
+ const home = Math.max(
256
+ 0,
257
+ shots.findIndex((shot) => from >= shot.start && from < shot.end),
258
+ );
259
+ const order: number[] = [];
260
+ for (let step = 1; step < count; step += 1) {
261
+ const at = home + step * direction;
262
+ if (at >= 0 && at < count) order.push(at);
263
+ else if (loop) order.push(((at % count) + count) % count);
264
+ }
265
+ order.push(home);
266
+ const out: PreparationFrame[] = [];
267
+ for (const at of order) {
268
+ for (const entry of shots[at]!.frames) {
269
+ if (!loop && (direction > 0 ? entry.frame < from : entry.frame > from)) continue;
270
+ out.push(entry);
271
+ }
272
+ }
273
+ return out;
274
+ }
275
+
276
+ /** What a Shot's frames key on, where its events are, and its state keys
277
+ * (`stateKeyFrames`): once per Shot object, which an edit elsewhere in the
278
+ * document keeps, and per rate, which a spring's frames move with. */
279
+ interface ShotFacts {
280
+ hash: string;
281
+ events: readonly number[];
282
+ stateKeys: readonly number[];
283
+ }
284
+ const shotFacts = new WeakMap<Scene3D, ShotFacts & { fps: Doc3D["fps"] }>();
285
+
286
+ function shotFactsOf(body: Scene3D, fps: Doc3D["fps"]): ShotFacts {
287
+ let facts = shotFacts.get(body);
288
+ if (facts === undefined || facts.fps.num !== fps.num || facts.fps.den !== fps.den) {
289
+ const { name: _name, audio: _audio, guides: _guides, ...drawn } = drawnScene(body);
290
+ facts = { hash: contentHash(drawn), events: sceneEventFrames(body, fps), stateKeys: stateKeyFrames(body), fps };
291
+ shotFacts.set(body, facts);
292
+ }
293
+ return facts;
294
+ }
295
+
296
+ /** The last shared hash and the six fields it was made of, by identity. */
297
+ let sharedMemo: { of: readonly unknown[]; hash: string } | null = null;
298
+
299
+ function sharedHashOf(doc: Doc3D): string {
300
+ const of = [doc.size, doc.fps, doc.assets, doc.materials, doc.materialLighting, doc.components];
301
+ const memo = sharedMemo;
302
+ if (memo !== null && of.every((value, at) => value === memo.of[at])) return memo.hash;
303
+ // Audio draws no pixel: an import of a sound re-keys nothing.
304
+ const assets = Object.fromEntries(Object.entries(doc.assets).filter(([, asset]) => asset.kind !== "audio"));
305
+ const hash = contentHash({
306
+ size: doc.size,
307
+ fps: doc.fps,
308
+ assets,
309
+ materials: doc.materials,
310
+ materialLighting: doc.materialLighting,
311
+ components: doc.components,
312
+ });
313
+ sharedMemo = { of, hash };
314
+ return hash;
315
+ }
316
+
317
+ /** The Shots that place a code component (`shotsPlacing`), per document. */
318
+ const placingMemo = new WeakMap<Doc3D, ReadonlySet<string>>();
319
+
320
+ function placingOf(doc: Doc3D): ReadonlySet<string> {
321
+ let placing = placingMemo.get(doc);
322
+ if (placing === undefined) {
323
+ placing = new Set(shotsPlacing(doc, []));
324
+ placingMemo.set(doc, placing);
325
+ }
326
+ return placing;
327
+ }
328
+
329
+ /** The Shot-local frames where a layer starts, or one of its tracks can
330
+ * change what the renderer builds (`trackEventFrames`). */
331
+ function sceneEventFrames(scene: Scene3D, fps: Doc3D["fps"]): number[] {
332
+ const length = Math.max(0, Math.trunc(scene.durationFrames));
333
+ const out = [0];
334
+ for (const layer of Object.values(scene.layersById)) {
335
+ if (layer.lifetime !== undefined) out.push(layer.lifetime.in);
336
+ for (const [path, track] of Object.entries(layer.tracks ?? {})) {
337
+ out.push(...trackEventFrames(path, track, fps, lifeInShot(layer, length)));
338
+ }
339
+ }
340
+ return out;
341
+ }
342
+
343
+ /** The frames of every key a fade, a blur or a component prop track has where
344
+ * its layer draws: what a held window's interior adds (see the header). */
345
+ function stateKeyFrames(scene: Scene3D): number[] {
346
+ const length = Math.max(0, Math.trunc(scene.durationFrames));
347
+ const out: number[] = [];
348
+ for (const layer of Object.values(scene.layersById)) {
349
+ const life = lifeInShot(layer, length);
350
+ for (const [path, track] of Object.entries(layer.tracks ?? {})) {
351
+ if (path !== "transform.opacity" && path !== "blurPx" && !path.startsWith(INSTANCE_PROP_PREFIX)) continue;
352
+ for (const key of track.keyframes) if (key.frame >= life.in && key.frame < life.out) out.push(key.frame);
353
+ }
354
+ }
355
+ return out;
356
+ }
357
+
358
+ /** A layer's lifetime inside its Shot: no lifetime is the whole Shot, so a key
359
+ * past the Shot's end is no frame the layer draws, and the state it reaches
360
+ * inside is found on the curve instead. */
361
+ function lifeInShot(layer: Layer3D, length: number): { in: number; out: number } {
362
+ return { in: layer.lifetime?.in ?? 0, out: Math.min(layer.lifetime?.out ?? length, length) };
363
+ }
364
+
365
+ /**
366
+ * FNV-1a over a value's JSON. Not a security hash: two inputs colliding costs
367
+ * one skipped preparation, which is a stall, never a wrong picture.
368
+ */
369
+ function contentHash(value: unknown): string {
370
+ const text = JSON.stringify(value) ?? "";
371
+ let hash = 0x811c9dc5;
372
+ for (let i = 0; i < text.length; i += 1) {
373
+ hash ^= text.charCodeAt(i);
374
+ hash = Math.imul(hash, 0x01000193);
375
+ }
376
+ return (hash >>> 0).toString(36) + text.length.toString(36);
377
+ }
378
+
379
+ /** Why the prepared set was last cleared: a new renderer (`onReady`), the
380
+ * stage's base moved (`preparationKey().base`), another Project opened, or
381
+ * the set ran past `PREPARED_LIMIT`. */
382
+ export type PreparedClear = "new stage" | "base" | "Project" | "overflow";
383
+
384
+ /** Why a frame is pending, in the order `explain` asks: drawn only in another
385
+ * view, else the first part of its key that differs from the parts this view
386
+ * last credited it with, else one timeout of that very key, else the clear
387
+ * that dropped it, else never drawn. */
388
+ const PREPARATION_REASONS = [
389
+ "view",
390
+ "shared",
391
+ "previous Shot",
392
+ "Shot",
393
+ "modules",
394
+ "isolation",
395
+ "timed out",
396
+ "cleared: new stage",
397
+ "cleared: base",
398
+ "cleared: Project",
399
+ "cleared: overflow",
400
+ "never drawn",
401
+ ] as const;
402
+ export type PreparationReason = (typeof PREPARATION_REASONS)[number];
403
+
404
+ /** What `window.__dailiesPrep` holds under the perf flag. */
405
+ export interface PreparationReport {
406
+ /** The passes begun: for a queued Play, and while paused. */
407
+ passes: { foreground: number; background: number };
408
+ /** Why the prepared set was last cleared; null: never. */
409
+ cleared: PreparedClear | null;
410
+ /** The last pass begun. */
411
+ last: PreparationBreakdown | null;
412
+ }
413
+
414
+ /** One pass: per reason, how many of its frames were pending for it, and the
415
+ * first few as `<Shot id>@<local frame>`. */
416
+ export interface PreparationBreakdown {
417
+ background: boolean;
418
+ frames: number;
419
+ reasons: Partial<Record<PreparationReason, { count: number; examples: string[] }>>;
420
+ }
421
+
422
+ /** Examples kept per reason. */
423
+ const EXAMPLES = 3;
424
+
425
+ /** The report of the latest `PreparedFrames` made under the perf flag. */
426
+ let report: PreparationReport | null = null;
427
+
428
+ /** That report, or null with the perf flag off. */
429
+ export function preparationReport(): PreparationReport | null {
430
+ return report;
431
+ }
432
+
433
+ /** What a `PreparedFrames` keeps under the perf flag. */
434
+ interface PreparationDiagnostics {
435
+ /** The parts each frame was last credited with in each view, by
436
+ * `drawnKey`. */
437
+ drawn: Map<string, PreparationKeyParts>;
438
+ /** Every `PreparationKeyParts.id` credited in any view. */
439
+ drawnAnywhere: Set<string>;
440
+ report: PreparationReport;
441
+ /** `?perf=log`: one console line per pass as well. */
442
+ log: boolean;
443
+ }
444
+
445
+ /** ponytail: the record is bounded by a whole clear, like the runtime's raster
446
+ * key history. It serves the perf report alone, and what a clear costs is a
447
+ * few frames reading "never drawn" until they are drawn again. */
448
+ const DRAWN_LIMIT = 4096;
449
+
450
+ /** How many keys a `PreparedFrames` holds, credited, timed out once and given
451
+ * up together, before it starts over: a long session of edits mints new keys
452
+ * and never retires old ones. */
453
+ const PREPARED_LIMIT = 20_000;
454
+
455
+ const drawnKey = (parts: PreparationKeyParts): string => `${parts.view}#${parts.id}`;
456
+
457
+ /** A new report, which `preparationReport` and `window.__dailiesPrep` show
458
+ * from now on: the page has one store. */
459
+ function startDiagnostics(log: boolean): PreparationDiagnostics {
460
+ const own: PreparationReport = { passes: { foreground: 0, background: 0 }, cleared: null, last: null };
461
+ report = own;
462
+ if (typeof window !== "undefined") (window as unknown as { __dailiesPrep?: PreparationReport }).__dailiesPrep = own;
463
+ return { drawn: new Map(), drawnAnywhere: new Set(), report: own, log };
464
+ }
465
+
466
+ function reasonOf(
467
+ parts: PreparationKeyParts,
468
+ sameView: PreparationKeyParts | undefined,
469
+ drawnElsewhere: boolean,
470
+ timedOut: boolean,
471
+ cleared: PreparedClear | null,
472
+ ): PreparationReason {
473
+ if (timedOut) return "timed out";
474
+ // Never drawn in this view: the view is what moved, if any other drew it.
475
+ if (sameView === undefined) return drawnElsewhere ? "view" : "never drawn";
476
+ if (parts.shared !== sameView.shared) return "shared";
477
+ if (parts.prev !== sameView.prev) return "previous Shot";
478
+ if (parts.shot !== sameView.shot) return "Shot";
479
+ if (parts.modules !== sameView.modules) return "modules";
480
+ if (parts.isolation !== sameView.isolation) return "isolation";
481
+ // The very key it was credited with: only a clear drops a credited key.
482
+ return cleared === null ? "never drawn" : `cleared: ${cleared}`;
483
+ }
484
+
485
+ /**
486
+ * The keys this stage has drawn, the ones it gave up on, and the ones that
487
+ * timed out once. Owned by the store, which clears it whenever the GPU state
488
+ * the keys stand for is replaced: a new renderer, a moved base, another
489
+ * Project.
490
+ */
491
+ export class PreparedFrames {
492
+ /** Presented in the playing presentation by their own publication, or
493
+ * drawn whole by the transport. */
494
+ private readonly keys = new Set<string>();
495
+ /** Timed out twice: not asked for again until the key or the base moves. */
496
+ private readonly gaveUp = new Set<string>();
497
+ /** Timed out once, with no external claim pending at the deadline. */
498
+ private readonly timedOut = new Set<string>();
499
+ /** Under the perf flag only, read when the store makes this. */
500
+ private readonly diagnostics: PreparationDiagnostics | null = perf === null ? null : startDiagnostics(perf === "log");
501
+
502
+ /** `frames` less what is prepared or given up. */
503
+ pending(frames: readonly PreparationFrame[]): PreparationFrame[] {
504
+ return frames.filter((entry) => !this.keys.has(entry.key) && !this.gaveUp.has(entry.key));
505
+ }
506
+
507
+ /** One frame, by how the stage said it ended (bridge v51). `"presented"`
508
+ * prepares its key alone; a second `"timeout"` gives the key up; a
509
+ * `"timeout-pending"` (a load still out at the deadline) counts nothing, so
510
+ * the frame is asked for again. */
511
+ credit(entry: PreparationFrame, outcome: ShotPreparedOutcome): void {
512
+ if (outcome === "timeout-pending") return;
513
+ if (this.keys.size + this.gaveUp.size + this.timedOut.size >= PREPARED_LIMIT) this.clear("overflow");
514
+ if (outcome === "timeout") {
515
+ if (this.timedOut.delete(entry.key)) this.gaveUp.add(entry.key);
516
+ else this.timedOut.add(entry.key);
517
+ return;
518
+ }
519
+ this.timedOut.delete(entry.key);
520
+ this.keys.add(entry.key);
521
+ const diagnostics = this.diagnostics;
522
+ if (diagnostics === null || entry.parts === undefined) return;
523
+ if (diagnostics.drawn.size >= DRAWN_LIMIT) {
524
+ diagnostics.drawn.clear();
525
+ diagnostics.drawnAnywhere.clear();
526
+ }
527
+ diagnostics.drawn.set(drawnKey(entry.parts), entry.parts);
528
+ diagnostics.drawnAnywhere.add(entry.parts.id);
529
+ }
530
+
531
+ clear(reason: PreparedClear): void {
532
+ this.keys.clear();
533
+ this.gaveUp.clear();
534
+ this.timedOut.clear();
535
+ if (this.diagnostics !== null) this.diagnostics.report.cleared = reason;
536
+ }
537
+
538
+ /** Under the perf flag only: why each frame of a pass that begins is
539
+ * pending, kept as the report's `last`, and under `?perf=log` one console
540
+ * line. */
541
+ explain(frames: readonly PreparationFrame[], background: boolean): void {
542
+ const diagnostics = this.diagnostics;
543
+ if (diagnostics === null) return;
544
+ const { drawn, drawnAnywhere, report: own } = diagnostics;
545
+ const reasons: PreparationBreakdown["reasons"] = {};
546
+ for (const { key, parts } of frames) {
547
+ if (parts === undefined) continue;
548
+ const reason = reasonOf(parts, drawn.get(drawnKey(parts)), drawnAnywhere.has(parts.id), this.timedOut.has(key), own.cleared);
549
+ const row = (reasons[reason] ??= { count: 0, examples: [] });
550
+ row.count += 1;
551
+ if (row.examples.length < EXAMPLES) row.examples.push(parts.id);
552
+ }
553
+ own.passes[background ? "background" : "foreground"] += 1;
554
+ own.last = { background, frames: frames.length, reasons };
555
+ if (!diagnostics.log) return;
556
+ const words = PREPARATION_REASONS.flatMap((reason) => {
557
+ const row = reasons[reason];
558
+ return row === undefined ? [] : [`${reason} ${row.count} (${row.examples.join(", ")})`];
559
+ });
560
+ console.debug(`[prep] ${background ? "background" : "play"} pass, ${frames.length} frames: ${words.join("; ")}`);
561
+ }
562
+ }