@ignix-social/editor 0.1.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 (586) hide show
  1. package/LICENSE +190 -0
  2. package/NOTICE +54 -0
  3. package/README.md +23 -0
  4. package/bin/ignix-editor.mjs +8 -0
  5. package/package.json +53 -0
  6. package/patches/index.mjs +53 -0
  7. package/scripts/build-ffmpeg-macos.sh +35 -0
  8. package/scripts/build-whisper-macos.sh +21 -0
  9. package/scripts/vendor.mjs +41 -0
  10. package/skills/ignix-editor/SKILL.md +132 -0
  11. package/src/audio.mjs +31 -0
  12. package/src/binaries.json +46 -0
  13. package/src/binaries.mjs +83 -0
  14. package/src/cli.mjs +254 -0
  15. package/src/prepare.mjs +74 -0
  16. package/src/runtime/ignix-frame.js +92 -0
  17. package/src/transcribe.mjs +71 -0
  18. package/src/validate.mjs +71 -0
  19. package/templates/blank/index.html +41 -0
  20. package/vendor/hyperframes/README.md +181 -0
  21. package/vendor/hyperframes/UPSTREAM.json +12 -0
  22. package/vendor/hyperframes/bin/hyperframes-localize-fonts.mjs +12 -0
  23. package/vendor/hyperframes/bin/hyperframes.mjs +11 -0
  24. package/vendor/hyperframes/dist/add-LR3ZR2A5.js +79 -0
  25. package/vendor/hyperframes/dist/agentPromptGenerator-VIIPZCJ3.js +143 -0
  26. package/vendor/hyperframes/dist/animatedGifPrep-P2T6YM7Z.js +34 -0
  27. package/vendor/hyperframes/dist/asset-BE2DOV72.js +26 -0
  28. package/vendor/hyperframes/dist/assetCataloger-VBLPHX24.js +340 -0
  29. package/vendor/hyperframes/dist/auth-RCQB2ZT7.js +60 -0
  30. package/vendor/hyperframes/dist/autoUpdate-RJAX3DAZ.js +268 -0
  31. package/vendor/hyperframes/dist/backgroundChecks-H2LCUIMJ.js +61 -0
  32. package/vendor/hyperframes/dist/backgroundChecksWorker.js +26 -0
  33. package/vendor/hyperframes/dist/batchRender-FT7AP7XH.js +355 -0
  34. package/vendor/hyperframes/dist/beat-analyzer.global.js +338 -0
  35. package/vendor/hyperframes/dist/beats-Y2EOP72P.js +309 -0
  36. package/vendor/hyperframes/dist/benchmark-MZ7GY3JW.js +231 -0
  37. package/vendor/hyperframes/dist/browser-HUTAMRQE.js +237 -0
  38. package/vendor/hyperframes/dist/bundleWithLocalizedFonts-5QOPOB5D.js +52 -0
  39. package/vendor/hyperframes/dist/capture-RLZA6EMR.js +4079 -0
  40. package/vendor/hyperframes/dist/capture-SZZ4IYJK.js +290 -0
  41. package/vendor/hyperframes/dist/captureFile-LYOJOUIE.js +15 -0
  42. package/vendor/hyperframes/dist/captureTimeout-PA4FYWT5.js +27 -0
  43. package/vendor/hyperframes/dist/catalog-KYU55EWR.js +1001 -0
  44. package/vendor/hyperframes/dist/check-TCG4PXLR.js +1697 -0
  45. package/vendor/hyperframes/dist/checkBrowser-RPMO4OW5.js +1032 -0
  46. package/vendor/hyperframes/dist/chunk-2EAXUCCE.js +88 -0
  47. package/vendor/hyperframes/dist/chunk-2EGFTPWD.js +1077 -0
  48. package/vendor/hyperframes/dist/chunk-2PSPARWP.js +6058 -0
  49. package/vendor/hyperframes/dist/chunk-2YN64IN5.js +5747 -0
  50. package/vendor/hyperframes/dist/chunk-3GXQPCJC.js +682 -0
  51. package/vendor/hyperframes/dist/chunk-3ZP5DXE7.js +15 -0
  52. package/vendor/hyperframes/dist/chunk-4NWOGZZS.js +1990 -0
  53. package/vendor/hyperframes/dist/chunk-4PFZPP2N.js +587 -0
  54. package/vendor/hyperframes/dist/chunk-4THIAPBL.js +128 -0
  55. package/vendor/hyperframes/dist/chunk-4YYJOFKS.js +28 -0
  56. package/vendor/hyperframes/dist/chunk-54HJ63Q2.js +29 -0
  57. package/vendor/hyperframes/dist/chunk-5ETJX6WM.js +89 -0
  58. package/vendor/hyperframes/dist/chunk-5IAKAQA7.js +389 -0
  59. package/vendor/hyperframes/dist/chunk-5Z63TBTX.js +37 -0
  60. package/vendor/hyperframes/dist/chunk-6BEFEWFB.js +25 -0
  61. package/vendor/hyperframes/dist/chunk-6CSYCFQV.js +68 -0
  62. package/vendor/hyperframes/dist/chunk-6CTIGJY7.js +154 -0
  63. package/vendor/hyperframes/dist/chunk-7HG4BFIN.js +93 -0
  64. package/vendor/hyperframes/dist/chunk-7JZ4FXP2.js +118 -0
  65. package/vendor/hyperframes/dist/chunk-A2Z4Z4VL.js +2961 -0
  66. package/vendor/hyperframes/dist/chunk-AMKC3AXA.js +25 -0
  67. package/vendor/hyperframes/dist/chunk-AVUUN2XD.js +4847 -0
  68. package/vendor/hyperframes/dist/chunk-AWDFDFI3.js +46 -0
  69. package/vendor/hyperframes/dist/chunk-AWNBM3MZ.js +94 -0
  70. package/vendor/hyperframes/dist/chunk-BXCMXMJQ.js +73 -0
  71. package/vendor/hyperframes/dist/chunk-BZ56MTDX.js +6 -0
  72. package/vendor/hyperframes/dist/chunk-CFKU7HTK.js +171 -0
  73. package/vendor/hyperframes/dist/chunk-CWPVM2QV.js +308 -0
  74. package/vendor/hyperframes/dist/chunk-DPVXBVLL.js +31292 -0
  75. package/vendor/hyperframes/dist/chunk-DQBY7FRR.js +397 -0
  76. package/vendor/hyperframes/dist/chunk-E6RPWJVC.js +213 -0
  77. package/vendor/hyperframes/dist/chunk-EISRN4E6.js +294 -0
  78. package/vendor/hyperframes/dist/chunk-EOVYQ3IG.js +143 -0
  79. package/vendor/hyperframes/dist/chunk-F3WZGU7C.js +479 -0
  80. package/vendor/hyperframes/dist/chunk-FCSIGXXP.js +366 -0
  81. package/vendor/hyperframes/dist/chunk-FI4I7CME.js +56 -0
  82. package/vendor/hyperframes/dist/chunk-FLWXXDNS.js +15 -0
  83. package/vendor/hyperframes/dist/chunk-GK4AIFIH.js +11171 -0
  84. package/vendor/hyperframes/dist/chunk-GMECXFAN.js +57 -0
  85. package/vendor/hyperframes/dist/chunk-GULOKZLI.js +155 -0
  86. package/vendor/hyperframes/dist/chunk-H4YZZ2VQ.js +68 -0
  87. package/vendor/hyperframes/dist/chunk-H6QMKUYA.js +477 -0
  88. package/vendor/hyperframes/dist/chunk-HBBJFK6I.js +273 -0
  89. package/vendor/hyperframes/dist/chunk-HRUGC23L.js +212 -0
  90. package/vendor/hyperframes/dist/chunk-HVW7ABXD.js +19 -0
  91. package/vendor/hyperframes/dist/chunk-HW6OYASV.js +344 -0
  92. package/vendor/hyperframes/dist/chunk-HWKCIWQT.js +3578 -0
  93. package/vendor/hyperframes/dist/chunk-I465DBM6.js +1214 -0
  94. package/vendor/hyperframes/dist/chunk-IGLEPPTN.js +24 -0
  95. package/vendor/hyperframes/dist/chunk-IGNAAHS3.js +433 -0
  96. package/vendor/hyperframes/dist/chunk-IHFUKJOR.js +85 -0
  97. package/vendor/hyperframes/dist/chunk-IQ3OUQ5Z.js +213 -0
  98. package/vendor/hyperframes/dist/chunk-ISN5GRYI.js +20 -0
  99. package/vendor/hyperframes/dist/chunk-IUZFXWSV.js +446 -0
  100. package/vendor/hyperframes/dist/chunk-JH556Q42.js +647 -0
  101. package/vendor/hyperframes/dist/chunk-JTHMTOMQ.js +601 -0
  102. package/vendor/hyperframes/dist/chunk-K2EQN4VU.js +405 -0
  103. package/vendor/hyperframes/dist/chunk-K2FTXJYH.js +16044 -0
  104. package/vendor/hyperframes/dist/chunk-K4WIOZFP.js +32 -0
  105. package/vendor/hyperframes/dist/chunk-K4WKGXRC.js +18 -0
  106. package/vendor/hyperframes/dist/chunk-KBJUXVOJ.js +172 -0
  107. package/vendor/hyperframes/dist/chunk-KC5XXX3X.js +590 -0
  108. package/vendor/hyperframes/dist/chunk-KNU5COPB.js +29 -0
  109. package/vendor/hyperframes/dist/chunk-KZI44OPA.js +185 -0
  110. package/vendor/hyperframes/dist/chunk-L3YOGIPG.js +48 -0
  111. package/vendor/hyperframes/dist/chunk-LAOCA3MQ.js +189 -0
  112. package/vendor/hyperframes/dist/chunk-LCSMOLGX.js +312 -0
  113. package/vendor/hyperframes/dist/chunk-LFGJWOVA.js +61 -0
  114. package/vendor/hyperframes/dist/chunk-LHSR3M4M.js +498 -0
  115. package/vendor/hyperframes/dist/chunk-LYNI3FOL.js +123 -0
  116. package/vendor/hyperframes/dist/chunk-M2WBOQ2Q.js +54 -0
  117. package/vendor/hyperframes/dist/chunk-MRF4AMKD.js +104 -0
  118. package/vendor/hyperframes/dist/chunk-MWB3ZIFM.js +852 -0
  119. package/vendor/hyperframes/dist/chunk-NGKM64BP.js +39 -0
  120. package/vendor/hyperframes/dist/chunk-NXMYHJAL.js +43 -0
  121. package/vendor/hyperframes/dist/chunk-OAF4XJOW.js +192 -0
  122. package/vendor/hyperframes/dist/chunk-OFQWTKPW.js +117 -0
  123. package/vendor/hyperframes/dist/chunk-P6LJ4Y32.js +4662 -0
  124. package/vendor/hyperframes/dist/chunk-PBN6GBJE.js +108 -0
  125. package/vendor/hyperframes/dist/chunk-PDAMK4Q5.js +28 -0
  126. package/vendor/hyperframes/dist/chunk-PFCFR3KZ.js +20 -0
  127. package/vendor/hyperframes/dist/chunk-PJ3HDUCY.js +108 -0
  128. package/vendor/hyperframes/dist/chunk-PMRBLBUP.js +152 -0
  129. package/vendor/hyperframes/dist/chunk-PPQUYWTW.js +240 -0
  130. package/vendor/hyperframes/dist/chunk-Q5X2B5WT.js +29 -0
  131. package/vendor/hyperframes/dist/chunk-Q7IU7MOR.js +351 -0
  132. package/vendor/hyperframes/dist/chunk-QC4FJVLM.js +371 -0
  133. package/vendor/hyperframes/dist/chunk-QNYYOUU3.js +1318 -0
  134. package/vendor/hyperframes/dist/chunk-RDNNAKEP.js +161 -0
  135. package/vendor/hyperframes/dist/chunk-RMHUQGRK.js +657 -0
  136. package/vendor/hyperframes/dist/chunk-RQVDTPGD.js +6 -0
  137. package/vendor/hyperframes/dist/chunk-RVCWIIZ7.js +68 -0
  138. package/vendor/hyperframes/dist/chunk-S3D6GE5W.js +72 -0
  139. package/vendor/hyperframes/dist/chunk-S3S4TGEH.js +424 -0
  140. package/vendor/hyperframes/dist/chunk-S7NPLFWV.js +11395 -0
  141. package/vendor/hyperframes/dist/chunk-SHB5VDMH.js +51 -0
  142. package/vendor/hyperframes/dist/chunk-TCLGPL65.js +860 -0
  143. package/vendor/hyperframes/dist/chunk-THXFSPLV.js +40 -0
  144. package/vendor/hyperframes/dist/chunk-TJSTGSAW.js +354 -0
  145. package/vendor/hyperframes/dist/chunk-TQFG7HTI.js +1024 -0
  146. package/vendor/hyperframes/dist/chunk-TVCRUG2S.js +265 -0
  147. package/vendor/hyperframes/dist/chunk-TWWSYAKJ.js +24 -0
  148. package/vendor/hyperframes/dist/chunk-U7CZBDMV.js +27 -0
  149. package/vendor/hyperframes/dist/chunk-UEZXMWG3.js +139 -0
  150. package/vendor/hyperframes/dist/chunk-UYEZTK4U.js +61 -0
  151. package/vendor/hyperframes/dist/chunk-VC76R6W2.js +27 -0
  152. package/vendor/hyperframes/dist/chunk-VFCKXTBB.js +159 -0
  153. package/vendor/hyperframes/dist/chunk-VWG7OQKU.js +22 -0
  154. package/vendor/hyperframes/dist/chunk-VXVRPIJA.js +105 -0
  155. package/vendor/hyperframes/dist/chunk-WBLXWOYK.js +15 -0
  156. package/vendor/hyperframes/dist/chunk-WERLJGIC.js +20 -0
  157. package/vendor/hyperframes/dist/chunk-WMQNIQDJ.js +2057 -0
  158. package/vendor/hyperframes/dist/chunk-WPHMNO44.js +4528 -0
  159. package/vendor/hyperframes/dist/chunk-X5HWXQPU.js +113 -0
  160. package/vendor/hyperframes/dist/chunk-X7MTZ4T2.js +6 -0
  161. package/vendor/hyperframes/dist/chunk-XH4DSOS5.js +59 -0
  162. package/vendor/hyperframes/dist/chunk-XS4EJSKU.js +23 -0
  163. package/vendor/hyperframes/dist/chunk-XT5P4QMO.js +181 -0
  164. package/vendor/hyperframes/dist/chunk-XT7X6QCP.js +6 -0
  165. package/vendor/hyperframes/dist/chunk-XUHOIDKG.js +6 -0
  166. package/vendor/hyperframes/dist/chunk-XUXGIA7H.js +485 -0
  167. package/vendor/hyperframes/dist/chunk-XZABUQTX.js +113 -0
  168. package/vendor/hyperframes/dist/chunk-Y6W4DVPS.js +356 -0
  169. package/vendor/hyperframes/dist/chunk-YEIFI443.js +44 -0
  170. package/vendor/hyperframes/dist/chunk-YQZNILVH.js +375 -0
  171. package/vendor/hyperframes/dist/chunk-Z27A7NUB.js +65 -0
  172. package/vendor/hyperframes/dist/chunk-Z6B37SNM.js +3081 -0
  173. package/vendor/hyperframes/dist/chunk-ZJUKFZ2P.js +10954 -0
  174. package/vendor/hyperframes/dist/chunk-ZKDMAOFU.js +32 -0
  175. package/vendor/hyperframes/dist/chunk-ZMXUQLI2.js +17219 -0
  176. package/vendor/hyperframes/dist/chunk-ZTZ7NCJT.js +58 -0
  177. package/vendor/hyperframes/dist/chunk-ZTZA4UWZ.js +108 -0
  178. package/vendor/hyperframes/dist/clean-W57E5YQ3.js +293 -0
  179. package/vendor/hyperframes/dist/cli.js +495 -0
  180. package/vendor/hyperframes/dist/cloud-FFTJGZ24.js +70 -0
  181. package/vendor/hyperframes/dist/cloudrun-AJUTHUEA.js +763 -0
  182. package/vendor/hyperframes/dist/colors-HKWSZCGK.js +15 -0
  183. package/vendor/hyperframes/dist/commands/contrast-audit.browser.js +459 -0
  184. package/vendor/hyperframes/dist/commands/layout-audit.browser.js +2102 -0
  185. package/vendor/hyperframes/dist/commands/motion-sample.browser.js +74 -0
  186. package/vendor/hyperframes/dist/commands/motion-signature.browser.js +374 -0
  187. package/vendor/hyperframes/dist/compare-AYCTT55F.js +421 -0
  188. package/vendor/hyperframes/dist/compiler-QO36EXLS.js +121 -0
  189. package/vendor/hyperframes/dist/component-VFFR2O7T.js +176 -0
  190. package/vendor/hyperframes/dist/compositions-QTVN3U2A.js +228 -0
  191. package/vendor/hyperframes/dist/contactSheet-27SRU7A4.js +22 -0
  192. package/vendor/hyperframes/dist/delete-ZAKYCB7I.js +114 -0
  193. package/vendor/hyperframes/dist/deploy-MX76RZ36.js +101 -0
  194. package/vendor/hyperframes/dist/destroy-H2TZBYHH.js +42 -0
  195. package/vendor/hyperframes/dist/deterministicFonts-HAEMV4TM.js +50 -0
  196. package/vendor/hyperframes/dist/dist-EWXJGN63.js +129 -0
  197. package/vendor/hyperframes/dist/dist-FNNGCKFS.js +29 -0
  198. package/vendor/hyperframes/dist/dist-S3PJNPXQ.js +392 -0
  199. package/vendor/hyperframes/dist/docker/Dockerfile.render +65 -0
  200. package/vendor/hyperframes/dist/docs/compositions.md +67 -0
  201. package/vendor/hyperframes/dist/docs/data-attributes.md +27 -0
  202. package/vendor/hyperframes/dist/docs/examples.md +19 -0
  203. package/vendor/hyperframes/dist/docs/gsap.md +26 -0
  204. package/vendor/hyperframes/dist/docs/rendering.md +35 -0
  205. package/vendor/hyperframes/dist/docs/troubleshooting.md +29 -0
  206. package/vendor/hyperframes/dist/docs-QAPJEGLS.js +131 -0
  207. package/vendor/hyperframes/dist/doctor-AI7C3FON.js +67 -0
  208. package/vendor/hyperframes/dist/dom-IROKGVJI.js +14 -0
  209. package/vendor/hyperframes/dist/dotEnv-AECLXQSO.js +14 -0
  210. package/vendor/hyperframes/dist/events-7LALYNKZ.js +92 -0
  211. package/vendor/hyperframes/dist/events-FQY3HGKZ.js +88 -0
  212. package/vendor/hyperframes/dist/feedback-WCMDMSTK.js +472 -0
  213. package/vendor/hyperframes/dist/ffmpeg-QIUFEFTY.js +35 -0
  214. package/vendor/hyperframes/dist/figma-64WY462P.js +63 -0
  215. package/vendor/hyperframes/dist/fontData.generated-NXAOI4GH.js +13 -0
  216. package/vendor/hyperframes/dist/fontLocalizeCli.js +132 -0
  217. package/vendor/hyperframes/dist/get-FPOMJMZB.js +103 -0
  218. package/vendor/hyperframes/dist/gpuPolicy-2ZUZE5D6.js +38 -0
  219. package/vendor/hyperframes/dist/grade-compare-E2CKPST4.js +647 -0
  220. package/vendor/hyperframes/dist/gsapParser-DIYYX6JT.js +2846 -0
  221. package/vendor/hyperframes/dist/gsapParserAcorn-E3GEIRZB.js +28 -0
  222. package/vendor/hyperframes/dist/help-YRQIDDML.js +197 -0
  223. package/vendor/hyperframes/dist/history-PP5NDRV3.js +571 -0
  224. package/vendor/hyperframes/dist/hyperframe-runtime.js +1081 -0
  225. package/vendor/hyperframes/dist/hyperframe.manifest.json +22 -0
  226. package/vendor/hyperframes/dist/hyperframe.runtime.iife.js +1081 -0
  227. package/vendor/hyperframes/dist/hyperframes-player.global.js +474 -0
  228. package/vendor/hyperframes/dist/hyperframes-slideshow.global.js +149 -0
  229. package/vendor/hyperframes/dist/info-SEX3B7JL.js +153 -0
  230. package/vendor/hyperframes/dist/init-U3AKHO5B.js +1147 -0
  231. package/vendor/hyperframes/dist/inspect-Q3K6EDEK.js +97 -0
  232. package/vendor/hyperframes/dist/installer-K6O5WF44.js +37 -0
  233. package/vendor/hyperframes/dist/keyframes-DC64JCI3.js +2602 -0
  234. package/vendor/hyperframes/dist/lambda-D7UMN4DJ.js +451 -0
  235. package/vendor/hyperframes/dist/layout-XSPPDHOO.js +86 -0
  236. package/vendor/hyperframes/dist/lib-TPG2ZMAX.js +128 -0
  237. package/vendor/hyperframes/dist/lint-7DQZE7L3.js +164 -0
  238. package/vendor/hyperframes/dist/lintProject-OHBBM3DJ.js +27 -0
  239. package/vendor/hyperframes/dist/list-4K5MVDQX.js +162 -0
  240. package/vendor/hyperframes/dist/login-NTX4OWXL.js +377 -0
  241. package/vendor/hyperframes/dist/logout-Q654A3SI.js +100 -0
  242. package/vendor/hyperframes/dist/manager-67P2XFXQ.js +34 -0
  243. package/vendor/hyperframes/dist/manager-CT3D67CG.js +38 -0
  244. package/vendor/hyperframes/dist/manager-GFN75DM4.js +30 -0
  245. package/vendor/hyperframes/dist/media-treatment-5FYAOPNL.js +972 -0
  246. package/vendor/hyperframes/dist/media-use-4XXGABIL.js +113 -0
  247. package/vendor/hyperframes/dist/models-C4E4IWJD.js +137 -0
  248. package/vendor/hyperframes/dist/motionShot-S4MIGMT5.js +614 -0
  249. package/vendor/hyperframes/dist/normalize-O76AC4HE.js +333 -0
  250. package/vendor/hyperframes/dist/normalize-audio-CSFTXLXD.js +276 -0
  251. package/vendor/hyperframes/dist/open-2ZD6BHZG.js +115 -0
  252. package/vendor/hyperframes/dist/pipeline-TNGWUZQC.js +54 -0
  253. package/vendor/hyperframes/dist/play-CTMUXX6E.js +349 -0
  254. package/vendor/hyperframes/dist/policies-FSDZVS2E.js +292 -0
  255. package/vendor/hyperframes/dist/preflight-SMNV6RW2.js +45 -0
  256. package/vendor/hyperframes/dist/present-WQVHV5CR.js +350 -0
  257. package/vendor/hyperframes/dist/preview-JOJXTH75.js +1820 -0
  258. package/vendor/hyperframes/dist/producer-ECLEN5RP.js +13 -0
  259. package/vendor/hyperframes/dist/progress-FBIEEB7Y.js +73 -0
  260. package/vendor/hyperframes/dist/projectConfig-HYJMJ5BY.js +56 -0
  261. package/vendor/hyperframes/dist/publication-HQ5Y3KBM.js +29 -0
  262. package/vendor/hyperframes/dist/publish-VHDYQASC.js +430 -0
  263. package/vendor/hyperframes/dist/refresh-K24ETHMA.js +53 -0
  264. package/vendor/hyperframes/dist/remove-background-W2YX2NVH.js +253 -0
  265. package/vendor/hyperframes/dist/render-AO5VX3YI.js +177 -0
  266. package/vendor/hyperframes/dist/render-LNO62LEL.js +2367 -0
  267. package/vendor/hyperframes/dist/render-TTQI7TGN.js +796 -0
  268. package/vendor/hyperframes/dist/render-batch-YH7CTWNY.js +284 -0
  269. package/vendor/hyperframes/dist/renderCancellation-JPIHE47X.js +35 -0
  270. package/vendor/hyperframes/dist/renderSetupWorker.js +79 -0
  271. package/vendor/hyperframes/dist/resolver-IZ647GBZ.js +38 -0
  272. package/vendor/hyperframes/dist/runtimeVersion.js +18 -0
  273. package/vendor/hyperframes/dist/screenshotCapture-ECBTLCU6.js +179 -0
  274. package/vendor/hyperframes/dist/shaderTransitionWorker.js +44 -0
  275. package/vendor/hyperframes/dist/sherpa-KKLNW6U2.js +314 -0
  276. package/vendor/hyperframes/dist/sherpaWorker.js +77 -0
  277. package/vendor/hyperframes/dist/sites-TNVKZS73.js +52 -0
  278. package/vendor/hyperframes/dist/skill-ZHVLH7KX.js +15 -0
  279. package/vendor/hyperframes/dist/skills/hyperframes/SKILL.md +152 -0
  280. package/vendor/hyperframes/dist/skills/hyperframes/references/brief-contract.md +108 -0
  281. package/vendor/hyperframes/dist/skills/hyperframes/references/brief-format.md +72 -0
  282. package/vendor/hyperframes/dist/skills/hyperframes/references/capability-menu.md +47 -0
  283. package/vendor/hyperframes/dist/skills/hyperframes/references/frame-worker-core.md +80 -0
  284. package/vendor/hyperframes/dist/skills/hyperframes/references/intent-interview.md +73 -0
  285. package/vendor/hyperframes/dist/skills/hyperframes/references/pitch-round.md +40 -0
  286. package/vendor/hyperframes/dist/skills/hyperframes/references/plugin-installation.md +43 -0
  287. package/vendor/hyperframes/dist/skills/hyperframes/references/production-loop.md +26 -0
  288. package/vendor/hyperframes/dist/skills/hyperframes/references/review-loop.md +37 -0
  289. package/vendor/hyperframes/dist/skills/hyperframes/references/route-briefs.md +11 -0
  290. package/vendor/hyperframes/dist/skills/hyperframes/references/routes/embedded-captions.md +11 -0
  291. package/vendor/hyperframes/dist/skills/hyperframes/references/routes/faceless-explainer.md +12 -0
  292. package/vendor/hyperframes/dist/skills/hyperframes/references/routes/general-video.md +12 -0
  293. package/vendor/hyperframes/dist/skills/hyperframes/references/routes/motion-graphics.md +11 -0
  294. package/vendor/hyperframes/dist/skills/hyperframes/references/routes/music-to-video.md +12 -0
  295. package/vendor/hyperframes/dist/skills/hyperframes/references/routes/pr-to-video.md +28 -0
  296. package/vendor/hyperframes/dist/skills/hyperframes/references/routes/product-launch-video.md +13 -0
  297. package/vendor/hyperframes/dist/skills/hyperframes/references/routes/remotion-to-hyperframes.md +9 -0
  298. package/vendor/hyperframes/dist/skills/hyperframes/references/routes/slideshow.md +11 -0
  299. package/vendor/hyperframes/dist/skills/hyperframes/references/routes/talking-head-recut.md +11 -0
  300. package/vendor/hyperframes/dist/skills/hyperframes/references/script-format.md +52 -0
  301. package/vendor/hyperframes/dist/skills/hyperframes/references/skill-lifecycle.md +35 -0
  302. package/vendor/hyperframes/dist/skills/hyperframes/references/storyboard-format.md +99 -0
  303. package/vendor/hyperframes/dist/skills/hyperframes/references/subagent-dispatch.md +35 -0
  304. package/vendor/hyperframes/dist/skills/hyperframes/references/workflow-catalog.md +10 -0
  305. package/vendor/hyperframes/dist/skills/hyperframes/scripts/lib/frame-packets-core.mjs +194 -0
  306. package/vendor/hyperframes/dist/skills/hyperframes/scripts/plugin-cli.mjs +88 -0
  307. package/vendor/hyperframes/dist/skills/hyperframes/scripts/plugin-cli.test.mjs +117 -0
  308. package/vendor/hyperframes/dist/skills/hyperframes-cli/SKILL.md +189 -0
  309. package/vendor/hyperframes/dist/skills/hyperframes-cli/references/beats.md +19 -0
  310. package/vendor/hyperframes/dist/skills/hyperframes-cli/references/cloud.md +163 -0
  311. package/vendor/hyperframes/dist/skills/hyperframes-cli/references/cloudrun.md +62 -0
  312. package/vendor/hyperframes/dist/skills/hyperframes-cli/references/compare-and-batch.md +105 -0
  313. package/vendor/hyperframes/dist/skills/hyperframes-cli/references/doctor-browser.md +57 -0
  314. package/vendor/hyperframes/dist/skills/hyperframes-cli/references/init-and-scaffold.md +74 -0
  315. package/vendor/hyperframes/dist/skills/hyperframes-cli/references/lambda.md +185 -0
  316. package/vendor/hyperframes/dist/skills/hyperframes-cli/references/lint-validate-inspect.md +132 -0
  317. package/vendor/hyperframes/dist/skills/hyperframes-cli/references/preview-render.md +193 -0
  318. package/vendor/hyperframes/dist/skills/hyperframes-cli/references/upgrade-info-misc.md +134 -0
  319. package/vendor/hyperframes/dist/skills/media-use/SKILL.md +100 -0
  320. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/CREDITS.md +35 -0
  321. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/chime.mp3 +0 -0
  322. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/click-soft.mp3 +0 -0
  323. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/click.mp3 +0 -0
  324. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/error.mp3 +0 -0
  325. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/glitch-1.mp3 +0 -0
  326. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/glitch-2.mp3 +0 -0
  327. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/glitch-3.mp3 +0 -0
  328. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/impact-bass-1.mp3 +0 -0
  329. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/impact-bass-2.mp3 +0 -0
  330. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/key-press.mp3 +0 -0
  331. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/manifest.json +97 -0
  332. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/notification.mp3 +0 -0
  333. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/ping.mp3 +0 -0
  334. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/pop.mp3 +0 -0
  335. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/riser.mp3 +0 -0
  336. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/sparkle.mp3 +0 -0
  337. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/typing.mp3 +0 -0
  338. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/whoosh-cinematic.mp3 +0 -0
  339. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/whoosh-short.mp3 +0 -0
  340. package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/whoosh.mp3 +0 -0
  341. package/vendor/hyperframes/dist/skills/media-use/audio/references/bgm.md +76 -0
  342. package/vendor/hyperframes/dist/skills/media-use/audio/references/captions/authoring.md +163 -0
  343. package/vendor/hyperframes/dist/skills/media-use/audio/references/captions/motion.md +87 -0
  344. package/vendor/hyperframes/dist/skills/media-use/audio/references/captions/transcript-handling.md +97 -0
  345. package/vendor/hyperframes/dist/skills/media-use/audio/references/remove-background.md +143 -0
  346. package/vendor/hyperframes/dist/skills/media-use/audio/references/requirements.md +29 -0
  347. package/vendor/hyperframes/dist/skills/media-use/audio/references/sfx.md +42 -0
  348. package/vendor/hyperframes/dist/skills/media-use/audio/references/transcribe.md +52 -0
  349. package/vendor/hyperframes/dist/skills/media-use/audio/references/tts-to-captions.md +35 -0
  350. package/vendor/hyperframes/dist/skills/media-use/audio/references/tts.md +260 -0
  351. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/audio.mjs +311 -0
  352. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/audio.test.mjs +159 -0
  353. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/gemini-pipeline.test.mjs +131 -0
  354. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/heygen-tts.mjs +122 -0
  355. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/heygen-tts.test.mjs +38 -0
  356. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/heygen-voice.mjs +98 -0
  357. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/heygen-voice.test.mjs +233 -0
  358. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/audio-meta.mjs +39 -0
  359. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/audio-meta.test.mjs +136 -0
  360. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/bgm-volume.mjs +4 -0
  361. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/bgm.mjs +257 -0
  362. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/bgm.test.mjs +74 -0
  363. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/concurrency.mjs +14 -0
  364. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/concurrency.test.mjs +41 -0
  365. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/gemini-auth.mjs +43 -0
  366. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/gemini-auth.py +52 -0
  367. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/gemini-auth.test.mjs +86 -0
  368. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/gemini-auth_test.py +90 -0
  369. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/gemini-tts.mjs +122 -0
  370. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/gemini-tts.test.mjs +243 -0
  371. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/heygen.mjs +197 -0
  372. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/heygen.test.mjs +185 -0
  373. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/media-record.mjs +114 -0
  374. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/media-record.test.mjs +205 -0
  375. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/python.mjs +77 -0
  376. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/python.test.mjs +136 -0
  377. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/sfx.mjs +165 -0
  378. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/sfx.test.mjs +121 -0
  379. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/tts.mjs +389 -0
  380. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/tts.spawn.test.mjs +158 -0
  381. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/tts.test.mjs +230 -0
  382. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lyria-recipe.py +136 -0
  383. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/wait-bgm.mjs +175 -0
  384. package/vendor/hyperframes/dist/skills/media-use/audio/scripts/wait-bgm.test.mjs +108 -0
  385. package/vendor/hyperframes/dist/skills/media-use/luts/README.md +28 -0
  386. package/vendor/hyperframes/dist/skills/media-use/luts/index.json +57 -0
  387. package/vendor/hyperframes/dist/skills/media-use/references/audio.md +20 -0
  388. package/vendor/hyperframes/dist/skills/media-use/references/grading.md +160 -0
  389. package/vendor/hyperframes/dist/skills/media-use/references/media-treatment-recipes.md +929 -0
  390. package/vendor/hyperframes/dist/skills/media-use/references/media-treatments.md +202 -0
  391. package/vendor/hyperframes/dist/skills/media-use/references/memory.md +37 -0
  392. package/vendor/hyperframes/dist/skills/media-use/references/meta.md +61 -0
  393. package/vendor/hyperframes/dist/skills/media-use/references/operations.md +327 -0
  394. package/vendor/hyperframes/dist/skills/media-use/references/resolve.md +150 -0
  395. package/vendor/hyperframes/dist/skills/media-use/references/setup-providers.md +80 -0
  396. package/vendor/hyperframes/dist/skills/media-use/references/telemetry-dashboard.md +49 -0
  397. package/vendor/hyperframes/dist/skills/media-use/scripts/audio-duck.mjs +113 -0
  398. package/vendor/hyperframes/dist/skills/media-use/scripts/compatibility.test.mjs +96 -0
  399. package/vendor/hyperframes/dist/skills/media-use/scripts/dither.mjs +328 -0
  400. package/vendor/hyperframes/dist/skills/media-use/scripts/dither.test.mjs +176 -0
  401. package/vendor/hyperframes/dist/skills/media-use/scripts/eval.mjs +369 -0
  402. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/adopt.mjs +128 -0
  403. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/adopt.test.mjs +95 -0
  404. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/bgm-provider.mjs +20 -0
  405. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/brand-provider.mjs +59 -0
  406. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/bundled-sfx-provider.mjs +119 -0
  407. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/bundled-sfx-provider.test.mjs +139 -0
  408. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/cache.mjs +148 -0
  409. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/candidates.mjs +91 -0
  410. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/candidates.test.mjs +155 -0
  411. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/codex-provider.mjs +161 -0
  412. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/codex-provider.test.mjs +34 -0
  413. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/config-lock.d.mts +3 -0
  414. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/config-lock.mjs +45 -0
  415. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/config-lock.test.mjs +79 -0
  416. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/coverage.test.mjs +136 -0
  417. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/cube-build.mjs +181 -0
  418. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/cube-build.test.mjs +80 -0
  419. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/cube-validate.mjs +198 -0
  420. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/cube-validate.test.mjs +125 -0
  421. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/cutlist.mjs +184 -0
  422. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/cutlist.test.mjs +162 -0
  423. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/duck.mjs +95 -0
  424. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/duck.test.mjs +153 -0
  425. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/error-diffusion.mjs +230 -0
  426. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/error-diffusion.test.mjs +102 -0
  427. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/ff-binaries.mjs +37 -0
  428. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/freeze.mjs +72 -0
  429. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/freeze.test.mjs +138 -0
  430. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/grade-analyzer.mjs +265 -0
  431. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/grade-analyzer.test.mjs +285 -0
  432. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/heygen-cli.mjs +191 -0
  433. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/heygen-cli.test.mjs +301 -0
  434. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/heygen-search.mjs +45 -0
  435. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/heygen-search.test.mjs +49 -0
  436. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/heygen-video-provider.mjs +138 -0
  437. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/heygen-video-provider.test.mjs +435 -0
  438. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/image-provider.mjs +44 -0
  439. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/index-gen.mjs +63 -0
  440. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/local-media-search.mjs +32 -0
  441. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/local-models.mjs +318 -0
  442. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/local-models.test.mjs +220 -0
  443. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/local-run.mjs +78 -0
  444. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/local-run.test.mjs +121 -0
  445. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/logo-provider.mjs +244 -0
  446. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/logo-provider.test.mjs +298 -0
  447. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/ltx-video-provider.mjs +94 -0
  448. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/ltx-video-provider.test.mjs +316 -0
  449. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/lut-preset-provider.mjs +271 -0
  450. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/lut-preset-provider.test.mjs +199 -0
  451. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/manifest.d.mts +19 -0
  452. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/manifest.mjs +279 -0
  453. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/manifest.test.mjs +397 -0
  454. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/match.mjs +47 -0
  455. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/media-fetch.mjs +85 -0
  456. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/media-fetch.test.mjs +197 -0
  457. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/media-home.mjs +20 -0
  458. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/media-home.test.mjs +61 -0
  459. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/media-search.d.mts +9 -0
  460. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/media-search.mjs +107 -0
  461. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/mflux-provider.mjs +128 -0
  462. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/mflux-provider.test.mjs +174 -0
  463. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/misses.mjs +49 -0
  464. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/misses.test.mjs +89 -0
  465. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/npx-sync.mjs +31 -0
  466. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/npx-sync.test.mjs +50 -0
  467. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/parakeet-words.mjs +27 -0
  468. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/parakeet-words.test.mjs +44 -0
  469. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/prefs-store.mjs +180 -0
  470. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/prefs-store.test.mjs +189 -0
  471. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/probe.mjs +41 -0
  472. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/probe.test.mjs +148 -0
  473. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/providers.mjs +5 -0
  474. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/recipe-store.mjs +367 -0
  475. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/recipe-store.test.mjs +367 -0
  476. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/registry.mjs +212 -0
  477. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/registry.test.mjs +262 -0
  478. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/search.mjs +24 -0
  479. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/search.test.mjs +32 -0
  480. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/sfx-provider.mjs +23 -0
  481. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/specs.mjs +132 -0
  482. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/specs.test.mjs +157 -0
  483. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/stats.mjs +117 -0
  484. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/stats.test.mjs +165 -0
  485. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/svg-sanitize.mjs +21 -0
  486. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/telemetry.mjs +210 -0
  487. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/telemetry.test.mjs +437 -0
  488. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/test-home.test.mjs +10 -0
  489. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/transcriptCutFade.mjs +21 -0
  490. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/transcriptCutFade.test.mjs +33 -0
  491. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/tts-local-provider.mjs +94 -0
  492. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/tts-local-provider.test.mjs +72 -0
  493. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/usage.mjs +57 -0
  494. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/usage.test.mjs +54 -0
  495. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/voice-provider.mjs +57 -0
  496. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/voice-provider.test.mjs +46 -0
  497. package/vendor/hyperframes/dist/skills/media-use/scripts/lib/words.mjs +18 -0
  498. package/vendor/hyperframes/dist/skills/media-use/scripts/prefs.mjs +70 -0
  499. package/vendor/hyperframes/dist/skills/media-use/scripts/recipe.mjs +103 -0
  500. package/vendor/hyperframes/dist/skills/media-use/scripts/resolve-plugin.test.mjs +62 -0
  501. package/vendor/hyperframes/dist/skills/media-use/scripts/resolve.mjs +1369 -0
  502. package/vendor/hyperframes/dist/skills/media-use/scripts/transcribe.mjs +194 -0
  503. package/vendor/hyperframes/dist/skills/media-use/scripts/transcribe.test.mjs +112 -0
  504. package/vendor/hyperframes/dist/skills/media-use/scripts/transcript-cut.mjs +270 -0
  505. package/vendor/hyperframes/dist/skills/media-use/scripts/transcript-cut.test.mjs +117 -0
  506. package/vendor/hyperframes/dist/skills-MJ2J4GEM.js +808 -0
  507. package/vendor/hyperframes/dist/skillsUpdateCheck-TKTYQN5R.js +26 -0
  508. package/vendor/hyperframes/dist/slideshow-EJ4IMY6P.js +24 -0
  509. package/vendor/hyperframes/dist/snapshot-KIVDUUMN.js +875 -0
  510. package/vendor/hyperframes/dist/src-6YQBJGWR.js +202 -0
  511. package/vendor/hyperframes/dist/src-PVYUYV3M.js +471 -0
  512. package/vendor/hyperframes/dist/state-KAXGHF77.js +26 -0
  513. package/vendor/hyperframes/dist/staticProjectServer-7EU666GS.js +49 -0
  514. package/vendor/hyperframes/dist/status-YM52BQ6S.js +311 -0
  515. package/vendor/hyperframes/dist/studio/assets/hyperframes-player-Cp8e_Zst.js +473 -0
  516. package/vendor/hyperframes/dist/studio/assets/index-BX3KHhGX.js +71 -0
  517. package/vendor/hyperframes/dist/studio/assets/index-CASEBNy2.js +1 -0
  518. package/vendor/hyperframes/dist/studio/assets/index-D11atkBt.css +1 -0
  519. package/vendor/hyperframes/dist/studio/assets/index-DMTt9nTf.js +531 -0
  520. package/vendor/hyperframes/dist/studio/assets/index-oE1pOdAy.js +399 -0
  521. package/vendor/hyperframes/dist/studio/chunk-5VSXRGIX.js +948 -0
  522. package/vendor/hyperframes/dist/studio/chunk-5VSXRGIX.js.map +1 -0
  523. package/vendor/hyperframes/dist/studio/chunk-7UQWVN52.js +938 -0
  524. package/vendor/hyperframes/dist/studio/chunk-7UQWVN52.js.map +1 -0
  525. package/vendor/hyperframes/dist/studio/chunk-EEXSYY5F.js +190 -0
  526. package/vendor/hyperframes/dist/studio/chunk-EEXSYY5F.js.map +1 -0
  527. package/vendor/hyperframes/dist/studio/chunk-FOEID72M.js +1441 -0
  528. package/vendor/hyperframes/dist/studio/chunk-FOEID72M.js.map +1 -0
  529. package/vendor/hyperframes/dist/studio/chunk-PZ5AY32C.js +10 -0
  530. package/vendor/hyperframes/dist/studio/chunk-PZ5AY32C.js.map +1 -0
  531. package/vendor/hyperframes/dist/studio/chunk-TDWGXBUT.js +1103 -0
  532. package/vendor/hyperframes/dist/studio/chunk-TDWGXBUT.js.map +1 -0
  533. package/vendor/hyperframes/dist/studio/domEditingLayers-IEVLO54Z.js +47 -0
  534. package/vendor/hyperframes/dist/studio/domEditingLayers-IEVLO54Z.js.map +1 -0
  535. package/vendor/hyperframes/dist/studio/favicon.svg +14 -0
  536. package/vendor/hyperframes/dist/studio/icons/timeline/audio.svg +7 -0
  537. package/vendor/hyperframes/dist/studio/icons/timeline/captions.svg +5 -0
  538. package/vendor/hyperframes/dist/studio/icons/timeline/composition.svg +12 -0
  539. package/vendor/hyperframes/dist/studio/icons/timeline/image.svg +18 -0
  540. package/vendor/hyperframes/dist/studio/icons/timeline/music.svg +10 -0
  541. package/vendor/hyperframes/dist/studio/icons/timeline/text.svg +3 -0
  542. package/vendor/hyperframes/dist/studio/index.css +165 -0
  543. package/vendor/hyperframes/dist/studio/index.css.map +1 -0
  544. package/vendor/hyperframes/dist/studio/index.d.ts +4296 -0
  545. package/vendor/hyperframes/dist/studio/index.html +23 -0
  546. package/vendor/hyperframes/dist/studio/index.js +99693 -0
  547. package/vendor/hyperframes/dist/studio/index.js.map +1 -0
  548. package/vendor/hyperframes/dist/studio/player.d.ts +30 -0
  549. package/vendor/hyperframes/dist/studio/player.js +10 -0
  550. package/vendor/hyperframes/dist/studio/player.js.map +1 -0
  551. package/vendor/hyperframes/dist/studio/styles/tailwind-preset.d.ts +39 -0
  552. package/vendor/hyperframes/dist/studio/styles/tailwind-preset.js +50 -0
  553. package/vendor/hyperframes/dist/studio/styles/tailwind-preset.js.map +1 -0
  554. package/vendor/hyperframes/dist/studio/styles.css +1 -0
  555. package/vendor/hyperframes/dist/studio/ui.d.ts +296 -0
  556. package/vendor/hyperframes/dist/studio/ui.js +66 -0
  557. package/vendor/hyperframes/dist/studio/ui.js.map +1 -0
  558. package/vendor/hyperframes/dist/studio-api-PNQZRPX5.js +136 -0
  559. package/vendor/hyperframes/dist/studioSelectionClient-IUUPKUHZ.js +25 -0
  560. package/vendor/hyperframes/dist/studioServer-UWRBPIOJ.js +1457 -0
  561. package/vendor/hyperframes/dist/synthesize-K62TIZWI.js +182 -0
  562. package/vendor/hyperframes/dist/system-EZYZNUFD.js +44 -0
  563. package/vendor/hyperframes/dist/telemetry-2YC4SGQU.js +144 -0
  564. package/vendor/hyperframes/dist/telemetry-QMYM4WME.js +95 -0
  565. package/vendor/hyperframes/dist/templates/_shared/AGENTS.md +107 -0
  566. package/vendor/hyperframes/dist/templates/_shared/CLAUDE.md +107 -0
  567. package/vendor/hyperframes/dist/templates/blank/index.html +55 -0
  568. package/vendor/hyperframes/dist/templates/from-file/index.html +75 -0
  569. package/vendor/hyperframes/dist/templates/warm-grain/compositions/captions.html +154 -0
  570. package/vendor/hyperframes/dist/templates/warm-grain/compositions/graphics.html +162 -0
  571. package/vendor/hyperframes/dist/templates/warm-grain/compositions/intro.html +87 -0
  572. package/vendor/hyperframes/dist/templates/warm-grain/index.html +264 -0
  573. package/vendor/hyperframes/dist/templates/warm-grain/registry-item.json +34 -0
  574. package/vendor/hyperframes/dist/timeline-77Z3BBQM.js +1377 -0
  575. package/vendor/hyperframes/dist/tokens-OBGTYE4Z.js +92 -0
  576. package/vendor/hyperframes/dist/transcribe-7NVFHCGA.js +387 -0
  577. package/vendor/hyperframes/dist/transcribe-BNSJRR4M.js +62 -0
  578. package/vendor/hyperframes/dist/tts-P3LIPIL5.js +234 -0
  579. package/vendor/hyperframes/dist/updateCheck-UDWIJ4ZQ.js +39 -0
  580. package/vendor/hyperframes/dist/upgrade-CT3CPO3E.js +231 -0
  581. package/vendor/hyperframes/dist/urlDownloader-H6WRI2UE.js +39 -0
  582. package/vendor/hyperframes/dist/usage-EC3KFUIJ.js +2139 -0
  583. package/vendor/hyperframes/dist/validate-65QDZJWZ.js +70 -0
  584. package/vendor/hyperframes/dist/video-FGSGKRSV.js +261 -0
  585. package/vendor/hyperframes/dist/workspaceBuildCheck-TOLGAI4T.js +133 -0
  586. package/vendor/hyperframes/package.json +80 -0
@@ -0,0 +1,4296 @@
1
+ export { Button, ButtonSize, ButtonVariant, ContextMenu, HyperframesLoader, HyperframesLoaderProps, HyperframesLogo, IconButton, Input, InputProps, Menu, MenuItem, MenuItemTone, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuShortcut, NumberField, NumberFieldProps, Popover, PopupPreviewState, PreviewState, Select, SelectOption, SelectProps, Slider, SliderProps, Tab, TabPanel, Tabs, TabsList, Toggle, ToggleProps, Tooltip, buttonBase, buttonSizes, buttonVariants, cn, fieldBase, fieldText, popupSurface } from './ui.js';
2
+ import * as react from 'react';
3
+ import { RefObject, MutableRefObject, ReactNode, DragEventHandler, ComponentProps, RefCallback, MouseEvent, CSSProperties, UIEvent, PointerEvent } from 'react';
4
+ import { RuntimeTimelineClipIdentity, HyperframePickerElementInfo } from '@hyperframes/core';
5
+ import { GsapAnimation, ParsedGsap, PropertyGroupName } from '@hyperframes/core/gsap-parser';
6
+ import { GsapAnimation as GsapAnimation$1, ArcPathSegment } from '@hyperframes/parsers/gsap-parser';
7
+ import { Composition } from '@hyperframes/sdk';
8
+ import * as react_jsx_runtime from 'react/jsx-runtime';
9
+ import * as zustand from 'zustand';
10
+ import { StoreApi } from 'zustand';
11
+ export { Player } from './player.js';
12
+ import { MusicBeatAnalysis } from '@hyperframes/core/beats';
13
+ import * as _hyperframes_parsers from '@hyperframes/parsers';
14
+ import { CanvasResolution } from '@hyperframes/parsers';
15
+ export { SeamTransitionFrameSource, SeamTransitionLoopHandle, SeamTransitionLoopOptions, playSeamTransitionLoop } from '@hyperframes/shader-transitions';
16
+ import '@base-ui/react/tabs';
17
+ import 'node_modules/cn/dist/types';
18
+ import '@base-ui/react/context-menu';
19
+ import '@base-ui/react/menu';
20
+ import '@base-ui/react/popover';
21
+
22
+ interface ShortcutHint {
23
+ key: string;
24
+ label: string;
25
+ }
26
+ interface ShortcutSection {
27
+ title: string;
28
+ hints: readonly ShortcutHint[];
29
+ }
30
+ /** What PlayerControls' shortcuts panel lists unless an embedder passes its own sections. */
31
+ declare const DEFAULT_SHORTCUT_SECTIONS: readonly ShortcutSection[];
32
+
33
+ interface PlayerControlsProps {
34
+ onTogglePlay: () => void;
35
+ onSeek: (time: number) => void;
36
+ disabled?: boolean;
37
+ isFullscreen?: boolean;
38
+ onToggleFullscreen?: () => void;
39
+ /** Replaces the shortcuts panel's list, e.g. DEFAULT_SHORTCUT_SECTIONS with entries dropped or relabelled. */
40
+ shortcutSections?: readonly ShortcutSection[];
41
+ }
42
+ declare const PlayerControls: react.NamedExoticComponent<PlayerControlsProps>;
43
+
44
+ declare function TimelineRulerPart(): react_jsx_runtime.JSX.Element;
45
+
46
+ interface UserBeat {
47
+ time: number;
48
+ strength: number;
49
+ }
50
+ interface BeatEditState {
51
+ /** Music src these edits apply to; edits reset when the src changes. */
52
+ src: string;
53
+ /** Beats the user added (audio-file coords). */
54
+ added: UserBeat[];
55
+ /** Audio-file times of detected beats the user removed. */
56
+ removed: number[];
57
+ }
58
+
59
+ /**
60
+ * Shared type definitions for the timeline playback subsystem.
61
+ * Kept in a separate module so adapter, DOM, and hook modules can all import
62
+ * from here without creating circular dependencies.
63
+ */
64
+
65
+ interface ClipManifestClip extends RuntimeTimelineClipIdentity {
66
+ zIndex?: number;
67
+ stackingContextId?: string | null;
68
+ compositionAncestors?: string[];
69
+ playbackStart?: number;
70
+ playbackRate?: number;
71
+ }
72
+
73
+ type TimelineTimeDisplayMode = "time" | "frame";
74
+
75
+ interface AnimationKeyframeTarget {
76
+ animationId: string;
77
+ tweenPercentage: number;
78
+ }
79
+
80
+ /** Minimal keyframe cache types — mirrors GsapKeyframesData without pulling in Node-only gsap-parser. */
81
+ interface KeyframeCacheEntry {
82
+ format: string;
83
+ keyframes: Array<{
84
+ percentage: number;
85
+ /** Original tween-relative percentage (server mutations need this, not the clip-relative `percentage`). */
86
+ tweenPercentage?: number;
87
+ /** Which property group the source tween belongs to (position, scale, rotation, visual, etc.). */
88
+ propertyGroup?: string;
89
+ /** Source tween id — lets the inline clip-row ease button target a specific segment. */
90
+ animationId?: string;
91
+ properties: Record<string, number | string>;
92
+ ease?: string;
93
+ /** Source animation/keyframe targets that collide at this clip percentage. */
94
+ collidingAnimationTargets?: AnimationKeyframeTarget[];
95
+ }>;
96
+ ease?: string;
97
+ easeEach?: string;
98
+ }
99
+ interface FocusedEaseSegment {
100
+ animationId: string;
101
+ collidingAnimationTargets?: AnimationKeyframeTarget[];
102
+ tweenPercentage: number;
103
+ elementId: string;
104
+ projectId: string | null;
105
+ sessionEpoch: number;
106
+ nonce: number;
107
+ }
108
+ type FocusedEaseSegmentTarget = Omit<FocusedEaseSegment, "projectId" | "sessionEpoch" | "nonce">;
109
+ /**
110
+ * A request to reveal one automated parameter in the audio FX rack.
111
+ *
112
+ * `elementKey` is the timeline element whose rack it belongs to — a group's own
113
+ * id for a group lane, the clip's key otherwise — so the panel can refuse a
114
+ * request aimed at something it is not showing.
115
+ */
116
+ interface RevealedAudioFxTarget {
117
+ elementKey: string;
118
+ /** The lane's own `fx.<node>.<param>` / `volume` target. */
119
+ automationTarget: string;
120
+ projectId: string | null;
121
+ sessionEpoch: number;
122
+ nonce: number;
123
+ }
124
+ type RevealedAudioFxTargetRequest = Omit<RevealedAudioFxTarget, "projectId" | "sessionEpoch" | "nonce">;
125
+ interface KeyframeSlice {
126
+ /** Selected collapsed (`element:pct`) or expanded (`element:group:animation:clipPct`) diamonds. */
127
+ selectedKeyframes: Set<string>;
128
+ toggleSelectedKeyframe: (key: string) => void;
129
+ clearSelectedKeyframes: () => void;
130
+ /** Clips whose keyframe property lanes are expanded in the timeline. */
131
+ expandedClipIds: Set<string>;
132
+ toggleClipExpanded: (id: string) => void;
133
+ setClipExpanded: (id: string, expanded: boolean) => void;
134
+ /** Union-expand clips (keyframed clips are expanded by default on load). */
135
+ expandClips: (ids: readonly string[]) => void;
136
+ /**
137
+ * Groups whose member rows the caret has HIDDEN (structural, not lanes).
138
+ *
139
+ * Inverted deliberately. As an expanded-set, "not in the set" could not tell
140
+ * never-touched from deliberately-collapsed, so every group defaulted to
141
+ * collapsed — and since nothing seeds the set on create, grouping three
142
+ * tracks made all three vanish behind a header the user had not yet learned
143
+ * to open. Groups are expanded until someone closes one.
144
+ */
145
+ collapsedGroupIds: Set<string>;
146
+ toggleGroupExpanded: (id: string) => void;
147
+ /** Rows (clip id or group id) whose automation-lane rows the `∿` button opened. */
148
+ expandedLaneOwnerIds: Set<string>;
149
+ toggleLaneOwnerExpanded: (id: string) => void;
150
+ /**
151
+ * Project/session/element-scoped request. Its nonce is monotonic across store
152
+ * resets so a stale consumer can never collide with a later request.
153
+ */
154
+ focusedEaseSegment: FocusedEaseSegment | null;
155
+ focusedEaseRequestNonce: number;
156
+ setFocusedEaseSegment: (target: FocusedEaseSegmentTarget) => void;
157
+ clearFocusedEaseSegment: (nonce: number) => void;
158
+ /**
159
+ * "Show me this automated parameter in the rack" — raised by clicking an
160
+ * automation lane's label in the timeline, consumed by the property panel.
161
+ *
162
+ * Session-stamped and nonce-guarded exactly like `focusedEaseSegment`: a
163
+ * request outlives the click, so one made against a different project or
164
+ * before a reload must not reopen a rack on whatever is mounted later.
165
+ */
166
+ revealedAudioFxTarget: RevealedAudioFxTarget | null;
167
+ revealedAudioFxNonce: number;
168
+ setRevealedAudioFxTarget: (target: RevealedAudioFxTargetRequest) => void;
169
+ clearRevealedAudioFxTarget: (nonce: number) => void;
170
+ /** Keyframe data per element id, populated from parsed GSAP animations. */
171
+ keyframeCache: Map<string, KeyframeCacheEntry>;
172
+ /** Unmerged source tweens per element; expanded property lanes read this, never keyframeCache. */
173
+ gsapAnimations: Map<string, GsapAnimation[]>;
174
+ setGsapAnimations: (elementId: string, animations: GsapAnimation[] | undefined) => void;
175
+ setKeyframeCache: (elementId: string, data: KeyframeCacheEntry | undefined) => void;
176
+ }
177
+
178
+ /**
179
+ * The active selection box on one automation lane.
180
+ *
181
+ * A store slice, not lane-local state, for the same reason keyframe selection
182
+ * is one: Delete/copy/paste handlers and the shape menu live outside the lane
183
+ * component and need to read it. Ephemeral by construction — nothing
184
+ * serializes store state, and the selection must never survive into a render.
185
+ */
186
+
187
+ interface AutomationSelection {
188
+ /** TimelineElement key (key ?? id) of the clip that owns the lane. */
189
+ elementKey: string;
190
+ /** Lane target: "volume" or "fx.<nodeId>.<param>". */
191
+ target: string;
192
+ /** Clip-local seconds; always t0 <= t1 (ordered on write). */
193
+ t0: number;
194
+ t1: number;
195
+ /**
196
+ * The box's value bounds, in the parameter's own units; always v0 <= v1.
197
+ *
198
+ * What makes the selection a box rather than a time span: a point is caught
199
+ * only if it falls inside both axes. Span operations — copy, paste, shape
200
+ * insert, simplify — still read t0/t1 alone, because they act on the envelope
201
+ * over a stretch of time rather than on a set of breakpoints.
202
+ */
203
+ v0: number;
204
+ v1: number;
205
+ }
206
+ interface AutomationSelectionSlice {
207
+ automationSelection: AutomationSelection | null;
208
+ setAutomationSelection: (sel: AutomationSelection) => void;
209
+ clearAutomationSelection: () => void;
210
+ }
211
+
212
+ /**
213
+ * The two editing-mode toggles the timeline toolbar owns.
214
+ *
215
+ * A store slice rather than toolbar-local state because both are read far from
216
+ * where they are set: the motion-path arm is consumed by the canvas click
217
+ * handler and published by MotionPathOverlay, and the auto-keyframe flag
218
+ * decides what a drag/resize/rotate does inside the edit commit path.
219
+ *
220
+ * `motionPathArmed` is also cleared by playerStore on selection change — arming
221
+ * survives neither a new element nor a project switch, so those resets stay
222
+ * with the state they clear alongside.
223
+ */
224
+
225
+ interface EditingModeSlice {
226
+ /** Motion-path "set destination" mode. Armed from the preview toolbar
227
+ * (replaces the old double-click-on-canvas UX); while armed, one canvas
228
+ * click places the new path's destination. */
229
+ motionPathArmed: boolean;
230
+ setMotionPathArmed: (armed: boolean) => void;
231
+ /** Published by MotionPathOverlay so the toolbar shows the button only when
232
+ * the selected element can actually take a path. */
233
+ motionPathCreateAvailable: boolean;
234
+ setMotionPathCreateAvailable: (available: boolean) => void;
235
+ /** Global toggle for the "Add keyframe" diamond in the timeline toolbar
236
+ * (#1808). When false, a manual drag/resize/rotate edit on an element that
237
+ * already has a live tween shifts every keyframe by the edit's delta
238
+ * (preserving the animation's shape) instead of inserting/updating a
239
+ * keyframe at the playhead. */
240
+ autoKeyframeEnabled: boolean;
241
+ setAutoKeyframeEnabled: (enabled: boolean) => void;
242
+ }
243
+
244
+ interface TimelineFocusRequest {
245
+ id: string;
246
+ projectId: string | null;
247
+ sessionEpoch: number;
248
+ nonce: number;
249
+ }
250
+
251
+ type ThumbnailMode = "adaptive" | "hidden";
252
+
253
+ interface ThumbnailSlice {
254
+ thumbnailMode: ThumbnailMode;
255
+ /** Monotonic identity, per composition path, for persisted content shown by mounted thumbnails. */
256
+ thumbnailRevisions: Readonly<Record<string, number>>;
257
+ setThumbnailMode: (mode: ThumbnailMode) => void;
258
+ /** `null` moves every composition, e.g. after a root or asset change. */
259
+ bumpThumbnailRevisions: (compositions: readonly string[] | null) => void;
260
+ }
261
+
262
+ /** Gates `timelineReady` on the composition's declared readiness inputs
263
+ * (media, compute, and the paint-and-idle default) instead of just a known
264
+ * duration. The generation counter is module-scope, not store state: it
265
+ * guards an in-flight settlement, not something a component reads, so
266
+ * bumping it shouldn't trigger a render. */
267
+
268
+ interface PlaybackReadinessSlice {
269
+ timelineReady: boolean;
270
+ /** Latched when the project's first preview shows its first frame (or fails), kept through edit
271
+ * reloads, so work that must not compete with the boot waits for it once. */
272
+ previewBooted: boolean;
273
+ setTimelineReady: (ready: boolean) => void;
274
+ markPreviewBooted: () => void;
275
+ playLocked: boolean;
276
+ setPlayLocked: (locked: boolean) => void;
277
+ /** Sets timelineReady once doc's readiness inputs settle, or immediately
278
+ * if doc is null. A wait a later call supersedes never wins the race.
279
+ * Waits for doc's load step first: it pauses and rewinds the preview, so a
280
+ * Play enabled before it would be undone. */
281
+ requestTimelineReady: (doc: Document | null) => void;
282
+ /** Called by the preview's load step for the document it ran on. */
283
+ markPreviewLoadStep: (doc: Document) => void;
284
+ }
285
+ declare function createPlaybackReadinessSlice(set: StoreApi<PlaybackReadinessSlice>["setState"]): PlaybackReadinessSlice;
286
+
287
+ interface TimelineTimeRange$1 {
288
+ t0: number;
289
+ t1: number;
290
+ }
291
+ interface RangeSelectionSlice {
292
+ /** Shift-drag ruler range in seconds, normalized so t0 <= t1. */
293
+ rangeSelection: TimelineTimeRange$1 | null;
294
+ }
295
+
296
+ /**
297
+ * One row in the timeline: a clip as Studio needs it, translated from the
298
+ * runtime's manifest at createTimelineElementFromManifestClip.
299
+ *
300
+ * Split out of playerStore, which had reached the 600-line studio ceiling and
301
+ * could not carry another field. Re-exported from there, so every existing
302
+ * importer is unaffected.
303
+ */
304
+
305
+ interface TimelineElement {
306
+ id: string;
307
+ label?: string;
308
+ transitionLabel?: string;
309
+ key?: string;
310
+ kind?: ClipManifestClip["kind"];
311
+ tag: string;
312
+ start: number;
313
+ duration: number;
314
+ track: number;
315
+ /**
316
+ * The data-track-index as written in the source file. Set at the manifest
317
+ * translation boundary (createTimelineElementFromManifestClip) from the
318
+ * runtime clip's verbatim track, and preserved through display-lane remaps
319
+ * (normalizeToZones packs sparse authored tracks onto contiguous display
320
+ * lanes; expanded sub-comp children get synthetic display rows). Lane edits
321
+ * must persist THIS space — writing a display-lane number into a sparse file
322
+ * re-targets the wrong track. For an expanded child the value is in its OWN
323
+ * source file's coordinate space, not the host timeline's.
324
+ */
325
+ authoredTrack?: number;
326
+ /** Resolved z-index for stacking-aware timeline ordering. */
327
+ zIndex?: number;
328
+ /** True when the effective z-index was authored inline or through CSS, not auto. */
329
+ hasExplicitZIndex?: boolean;
330
+ /** Canonical CSS stacking context this element's z-index participates in. */
331
+ stackingContextId?: string | null;
332
+ /** Nearest parent composition context, matching RuntimeTimelineClip. */
333
+ parentCompositionId?: string | null;
334
+ /** Composition ancestry from root to nearest parent, matching RuntimeTimelineClip. */
335
+ compositionAncestors?: string[];
336
+ domId?: string;
337
+ /** Stable `data-hf-id` attribute value — used as primary patch target when present */
338
+ hfId?: string;
339
+ /** Best-effort selector used when patching source HTML back from timeline edits */
340
+ selector?: string;
341
+ /** Zero-based occurrence index for non-unique selectors */
342
+ selectorIndex?: number;
343
+ /** Source composition file that owns this element, when known */
344
+ sourceFile?: string;
345
+ src?: string;
346
+ playbackStart?: number;
347
+ playbackStartAttr?: "media-start" | "playback-start";
348
+ playbackRate?: number;
349
+ sourceDuration?: number;
350
+ volume?: number;
351
+ /** A video with sound to mix (`data-has-audio`, or unmuted without it); `muted` silences it. */
352
+ hasAudio?: boolean;
353
+ muted?: boolean;
354
+ /** Clip-edge fades from `data-fade-in` / `data-fade-out`, seconds; absent means none. */
355
+ fadeIn?: number;
356
+ fadeOut?: number;
357
+ /** Verbatim `data-fx-chain` / `data-automation`; see automationLaneData. */
358
+ fxChain?: string;
359
+ automation?: string;
360
+ /** Path from data-composition-src — identifies sub-composition elements */
361
+ compositionSrc?: string;
362
+ /** Set by data-timeline-locked on the host element — disables move and trim in Studio. */
363
+ timelineLocked?: boolean;
364
+ /** Set by data-hidden on the host element — hides the clip in preview and render. */
365
+ hidden?: boolean;
366
+ /** Value of data-timeline-role attribute — used to identify music vs. voiceover. */
367
+ timelineRole?: string;
368
+ /** Verbatim `data-audio-group` — the id of the `<hf-audio-group>` this clip belongs to, when any. */
369
+ audioGroup?: string;
370
+ /** The owning group's `data-label` (falls back to its id) — resolved once per parse. */
371
+ audioGroupLabel?: string;
372
+ /** The owning group's `data-volume` (defaults to 1) — resolved once per parse. */
373
+ audioGroupVolume?: number;
374
+ /** The owning group's `data-hidden` (defaults to false) — resolved once per parse. */
375
+ audioGroupHidden?: boolean;
376
+ /** The owning group's serialized `data-fx-chain`, when set — resolved once per parse. */
377
+ audioGroupFxChain?: string;
378
+ audioGroupAutomation?: string;
379
+ link?: string;
380
+ compositionScope?: string;
381
+ syncOrigin?: string;
382
+ /**
383
+ * Master start of the composition this row runs in, which its tweens and its
384
+ * `data-start` are local to; 0 at the root. Writes go through toAuthoredStart.
385
+ */
386
+ parentCompositionStart?: number;
387
+ /** A legacy root-global media start: its `data-start` is already master time. */
388
+ authoredStartIsMasterTime?: boolean;
389
+ /** Legacy marker for an inline sub-composition child; current rows never set it. */
390
+ expandedHostKey?: string;
391
+ /** A text layer's words and look, which its row draws live instead of a captured picture. */
392
+ text?: TimelineText;
393
+ }
394
+ interface TimelineText {
395
+ value: string;
396
+ fontFamily?: string;
397
+ fontWeight?: string;
398
+ color?: string;
399
+ /** The layer's own opaque background colour, when it paints one. */
400
+ background?: string;
401
+ }
402
+ /**
403
+ * The fields `updateElement` may write.
404
+ *
405
+ * Deliberately a narrow allow-list rather than `Partial<TimelineElement>`: most
406
+ * of an element is derived from the document at parse time, and letting a
407
+ * caller poke those would put the store out of step with the file it mirrors.
408
+ *
409
+ * The `audioGroup*` entries are the GROUP's state, mirrored onto every member —
410
+ * a group row derives its label, fader, mute and chain from these, so a group
411
+ * write has to be able to land here or the header goes on rendering whatever it
412
+ * parsed at load.
413
+ */
414
+ type TimelineElementPatch = Partial<Pick<TimelineElement, "start" | "duration" | "track" | "zIndex" | "hasExplicitZIndex" | "playbackStart" | "hidden" | "audioGroup" | "audioGroupLabel" | "audioGroupVolume" | "audioGroupHidden" | "audioGroupFxChain" | "audioGroupAutomation" | "text">>;
415
+ /**
416
+ * The `data-*` state an expanded sub-composition child needs but cannot reach.
417
+ *
418
+ * A child row is synthesized from a manifest clip with no element to read, and
419
+ * for a real sub-composition it has no flat store twin either: such clips are
420
+ * dropped before the flat store is built. Read off the live preview instead
421
+ * (`collectSubCompositionHostState`) and carried on the store by dom id.
422
+ *
423
+ * Without it the eye reported every hidden child visible, so clicking it wrote
424
+ * `data-hidden` a second time instead of removing it, and the element could
425
+ * never be shown again, not even after a reload, since the attribute is in the
426
+ * source.
427
+ */
428
+ interface SubCompositionHostState {
429
+ hidden?: boolean;
430
+ timelineLocked?: boolean;
431
+ timelineRole?: string;
432
+ fxChain?: string;
433
+ automation?: string;
434
+ }
435
+
436
+ type TimeListener = (time: number) => void;
437
+ declare const liveTime: {
438
+ notify: (time: number) => void;
439
+ notifySeek: (time: number) => void;
440
+ seekCount: () => number;
441
+ latest: () => number;
442
+ subscribe: (listener: TimeListener) => () => boolean;
443
+ };
444
+
445
+ type ZoomMode = "fit" | "manual";
446
+ type TimelineTool = "select" | "razor";
447
+ interface SelectElementOptions {
448
+ preserveSet?: boolean;
449
+ }
450
+ type PlayerStoreSlices = KeyframeSlice & AutomationSelectionSlice & ThumbnailSlice & EditingModeSlice & ReturnType<typeof createPlaybackReadinessSlice> & RangeSelectionSlice;
451
+ interface PlayerState extends PlayerStoreSlices {
452
+ isPlaying: boolean;
453
+ currentTime: number;
454
+ duration: number;
455
+ /** Increments exactly once when the Studio switches to a different project. */
456
+ timelineSessionEpoch: number;
457
+ /** Project owning the current timeline session; null outside a project-scoped reset. */
458
+ timelineProjectId: string | null;
459
+ /** True while a beat dot is being dragged — hides the playhead guideline. */
460
+ beatDragging: boolean;
461
+ elements: TimelineElement[];
462
+ selectedElementId: string | null;
463
+ playbackRate: number;
464
+ audioMuted: boolean;
465
+ audioVolume: number;
466
+ loopEnabled: boolean;
467
+ /** Timeline zoom: 'fit' auto-scales to viewport, 'manual' uses manualZoomPercent */
468
+ zoomMode: ZoomMode;
469
+ /** Timeline zoom percent relative to the fit width when in manual mode */
470
+ manualZoomPercent: number;
471
+ userZoomCount: number;
472
+ /**
473
+ * Bumped on every live z-index edit (handleDomZIndexReorderCommit apply AND
474
+ * rollback). Flashless z commits (skipReload) never reload the iframe or
475
+ * bump refreshKey, so DOM-derived views (the Layers panel's z-sorted tree)
476
+ * subscribe to this to re-read the live DOM while playback is paused.
477
+ */
478
+ zEditVersion: number;
479
+ /** Work-area in-point (seconds). When set, loop starts here and A jumps here. */
480
+ inPoint: number | null;
481
+ /** Work-area out-point (seconds). When set, loop ends here and E jumps here. */
482
+ outPoint: number | null;
483
+ activeTool: TimelineTool;
484
+ setActiveTool: (tool: TimelineTool) => void;
485
+ selectLeftward: () => void;
486
+ selectRightward: () => void;
487
+ /** Tween-relative percentage of the last-clicked keyframe diamond. Operations
488
+ * (drag, resize, rotate) target this instead of recomputing from playhead. */
489
+ activeKeyframePct: number | null;
490
+ setActiveKeyframePct: (pct: number | null) => void;
491
+ /** Multi-select: additional selected elements beyond selectedElementId. */
492
+ selectedElementIds: Set<string>;
493
+ clearSelectedElementIds: () => void;
494
+ /** Replace the whole multi-selection at once (marquee live updates). */
495
+ setSelectedElementIds: (ids: Set<string>) => void;
496
+ /** Timeline magnet toggle — when false, clip drags/trims/drops never snap. */
497
+ timelineSnapEnabled: boolean;
498
+ setTimelineSnapEnabled: (enabled: boolean) => void;
499
+ /** Keeps the main track gapless on delete; distinct from the magnet above. */
500
+ rippleEditEnabled: boolean;
501
+ setRippleEditEnabled: (enabled: boolean) => void;
502
+ /** Transport + ruler readout: timecode ("time") or frame number ("frame"). */
503
+ timeDisplayMode: TimelineTimeDisplayMode;
504
+ setTimeDisplayMode: (mode: TimelineTimeDisplayMode) => void;
505
+ /** Pin the timeline zoom to its current scale before a duration change, so
506
+ * it stops rescaling every clip. No-op once already pinned. */
507
+ pinTimelineZoom: (currentPixelsPerSecond: number, fitPixelsPerSecond: number) => void;
508
+ /** The timeline's live pixels-per-second + fit basis, published by <Timeline>. */
509
+ timelinePps: number;
510
+ timelineFitPps: number;
511
+ setTimelineScale: (pps: number, fitPps: number) => void;
512
+ setSelection: (ids: Iterable<string>, anchor?: string | null) => void;
513
+ addSelectedElementId: (id: string) => void;
514
+ toggleSelectedElementId: (id: string) => void;
515
+ clearSelection: () => void;
516
+ setIsPlaying: (playing: boolean) => void;
517
+ setCurrentTime: (time: number) => void;
518
+ setDuration: (duration: number) => void;
519
+ setPlaybackRate: (rate: number) => void;
520
+ setAudioMuted: (muted: boolean) => void;
521
+ setAudioVolume: (volume: number) => void;
522
+ setLoopEnabled: (enabled: boolean) => void;
523
+ setBeatDragging: (dragging: boolean) => void;
524
+ setElements: (elements: TimelineElement[]) => void;
525
+ setSelectedElementId: (id: string | null, options?: SelectElementOptions) => void;
526
+ /** Move the selection anchor within an active multi-selection without collapsing it. */
527
+ setSelectionAnchor: (id: string | null) => void;
528
+ updateElement: (elementId: string, updates: TimelineElementPatch) => void;
529
+ setZoomMode: (mode: ZoomMode) => void;
530
+ setManualZoomPercent: (percent: number) => void;
531
+ bumpZEditVersion: () => void;
532
+ setInPoint: (time: number | null) => void;
533
+ setOutPoint: (time: number | null) => void;
534
+ /** Owns the hard project boundary; repeated calls for one project are no-ops. */
535
+ beginTimelineSession: (projectId: string) => void;
536
+ /** Clears project data without creating a new hard-project session. */
537
+ reset: () => void;
538
+ /** Request a seek from outside the player loop (e.g. Layers panel);
539
+ * useTimelinePlayer subscribes and calls adapter.seek() + liveTime.notify(). */
540
+ requestedSeekTime: number | null;
541
+ requestSeek: (time: number) => void;
542
+ clearSeekRequest: () => void;
543
+ /** Request the transport start or stop from outside the player loop: the FX
544
+ * rack starts playback to audition a preset (silent while paused) and
545
+ * restores the playhead on leave, without costing the author their place.
546
+ * A nonce, not a bare boolean, so two hovers in a row both register. */
547
+ playbackRequest: {
548
+ playing: boolean;
549
+ returnTo: number | null;
550
+ nonce: number;
551
+ } | null;
552
+ requestPlayback: (playing: boolean, returnTo?: number | null) => void;
553
+ clearPlaybackRequest: () => void;
554
+ /**
555
+ * Request the timeline to scroll a clip into view (e.g. clicking an
556
+ * already-added asset card in the sidebar). Consumed and cleared by
557
+ * useTimelineRevealClip. The nonce makes repeat requests for the same
558
+ * clip observable so a second click re-reveals after the user scrolls away.
559
+ */
560
+ clipRevealRequest: {
561
+ elementId: string;
562
+ nonce: number;
563
+ } | null;
564
+ requestClipReveal: (elementId: string) => void;
565
+ clearClipRevealRequest: () => void;
566
+ timelineFocus: TimelineFocusRequest | null;
567
+ timelineFocusNonce: number;
568
+ requestTimelineFocus: (id: string) => void;
569
+ clearTimelineFocus: (nonce: number) => void;
570
+ lintFindingsByElement: Map<string, {
571
+ count: number;
572
+ messages: string[];
573
+ }>;
574
+ setLintFindingsByElement: (map: Map<string, {
575
+ count: number;
576
+ messages: string[];
577
+ }>) => void;
578
+ beatAnalysis: MusicBeatAnalysis | null;
579
+ setBeatAnalysis: (analysis: MusicBeatAnalysis | null) => void;
580
+ /** User edits (add/move/delete) layered over the detected beat grid. */
581
+ beatEdits: BeatEditState | null;
582
+ setBeatEdits: (edits: BeatEditState | null) => void;
583
+ /** Undo/redo stacks for beat edits (in-memory, session-only). */
584
+ beatUndo: BeatHistoryEntry[];
585
+ beatRedo: BeatHistoryEntry[];
586
+ commitBeatEdits: (next: BeatEditState | null, label: string) => void;
587
+ undoBeatEdits: () => string | null;
588
+ redoBeatEdits: () => string | null;
589
+ resetBeatHistory: () => void;
590
+ beatPersist: (() => void) | null;
591
+ setBeatPersist: (fn: (() => void) | null) => void;
592
+ clipManifest: ClipManifestClip[] | null;
593
+ setClipManifest: (clips: ClipManifestClip[] | null) => void;
594
+ clipParentMap: Map<string, string>;
595
+ setClipParentMap: (map: Map<string, string>) => void;
596
+ /**
597
+ * Sub-composition DOM descendants (groups + their children) that have no
598
+ * `data-start`, so they're absent from the clip manifest/tree. Collected
599
+ * studio-side from the live preview so the timeline can expand a sub-comp row
600
+ * to show its DOM-only children. Keeps the manifest lean (timed clips only).
601
+ */
602
+ domClipChildren: DomClipChild[];
603
+ setDomClipChildren: (children: DomClipChild[]) => void;
604
+ /**
605
+ * Host-element state for every id'd element inside a sub-composition, keyed by
606
+ * dom id. Collected from the live preview because it is the only place that
607
+ * sees it: these elements are filtered out of `elements` before the flat store
608
+ * is built, and the clip manifest carries timing, not attributes.
609
+ */
610
+ subCompositionHostState: Map<string, SubCompositionHostState>;
611
+ setSubCompositionHostState: (state: Map<string, SubCompositionHostState>) => void;
612
+ }
613
+ /** A sub-comp DOM-only timeline child (no data-start) and its nesting context. */
614
+ interface DomClipChild {
615
+ id: string;
616
+ parentId: string;
617
+ /** The manifest sub-comp host clip id this descendant ultimately lives under. */
618
+ hostId: string;
619
+ label: string;
620
+ stackingContextId: string;
621
+ /**
622
+ * The child's audio-group state, read off its live element during the DOM
623
+ * walk — the only place that sees it. A sub-composition can declare a group
624
+ * and its members entirely within itself, and those members never reach the
625
+ * flat store, so an expanded child has no twin to inherit membership from.
626
+ */
627
+ audioGroup?: string;
628
+ audioGroupLabel?: string;
629
+ audioGroupVolume?: number;
630
+ audioGroupHidden?: boolean;
631
+ audioGroupFxChain?: string;
632
+ /** The group element's `data-automation`, mirrored the same way. */
633
+ audioGroupAutomation?: string;
634
+ }
635
+ interface BeatHistoryEntry {
636
+ restore: BeatEditState | null;
637
+ at: number;
638
+ label: string;
639
+ }
640
+ declare const usePlayerStore: zustand.UseBoundStore<zustand.StoreApi<PlayerState>>;
641
+
642
+ interface PatchOperation {
643
+ type: "inline-style" | "attribute" | "text-content" | "html-attribute" | "rich-text";
644
+ property: string;
645
+ value: string | null;
646
+ childSelector?: string;
647
+ childIndex?: number;
648
+ }
649
+ interface PatchTarget {
650
+ id?: string | null;
651
+ hfId?: string;
652
+ selector?: string;
653
+ selectorIndex?: number;
654
+ }
655
+ /**
656
+ * Find which source file contains an element by its ID.
657
+ */
658
+ declare function resolveSourceFile(elementId: string | null, selector: string, files: Record<string, string>): string | null;
659
+ /**
660
+ * Apply a patch operation to an HTML source file.
661
+ */
662
+ declare function applyPatch(html: string, elementId: string, op: PatchOperation): string;
663
+
664
+ interface DomEditCapabilities {
665
+ canSelect: boolean;
666
+ canEditStyles: boolean;
667
+ /** Can take a non-destructive `clip-path: inset()` crop — broader than
668
+ * canEditStyles (a sub-composition host is croppable from the parent view). */
669
+ canCrop: boolean;
670
+ /** Directly editable authored left/top style fields. Canvas drag uses manual edits instead. */
671
+ canMove: boolean;
672
+ /** Directly editable authored width/height style fields. Canvas resize uses manual edits instead. */
673
+ canResize: boolean;
674
+ canApplyManualOffset: boolean;
675
+ canApplyManualSize: boolean;
676
+ canApplyManualRotation: boolean;
677
+ reasonIfDisabled?: string;
678
+ commitCheckPending?: boolean;
679
+ }
680
+ interface DomEditTextField {
681
+ key: string;
682
+ label: string;
683
+ value: string;
684
+ tagName: string;
685
+ attributes: Array<{
686
+ name: string;
687
+ value: string;
688
+ }>;
689
+ inlineStyles: Record<string, string>;
690
+ computedStyles: Record<string, string>;
691
+ source: "self" | "child" | "text-node";
692
+ sourceChildIndex?: number;
693
+ }
694
+ interface DomEditSelection extends PatchTarget {
695
+ element: HTMLElement;
696
+ label: string;
697
+ tagName: string;
698
+ sourceFile: string;
699
+ compositionPath: string;
700
+ compositionSrc?: string;
701
+ isCompositionHost: boolean;
702
+ isInsideLockedComposition: boolean;
703
+ boundingBox: {
704
+ x: number;
705
+ y: number;
706
+ width: number;
707
+ height: number;
708
+ };
709
+ textContent: string | null;
710
+ dataAttributes: Record<string, string>;
711
+ inlineStyles: Record<string, string>;
712
+ computedStyles: Record<string, string>;
713
+ textFields: DomEditTextField[];
714
+ capabilities: DomEditCapabilities;
715
+ existsInSource?: boolean;
716
+ gsapAnimations?: GsapAnimation$1[];
717
+ }
718
+ interface DomEditLayerItem {
719
+ key: string;
720
+ element: HTMLElement;
721
+ label: string;
722
+ tagName: string;
723
+ depth: number;
724
+ childCount: number;
725
+ id?: string;
726
+ hfId?: string;
727
+ selector?: string;
728
+ selectorIndex?: number;
729
+ sourceFile: string;
730
+ }
731
+ interface DomEditContextOptions {
732
+ activeCompositionPath: string | null;
733
+ isMasterView: boolean;
734
+ preferClipAncestor?: boolean;
735
+ /** The group wrapper the user has drilled into (null = top level). Selection
736
+ * resolution treats groups as a unit unless drilled into one. */
737
+ activeGroupElement?: HTMLElement | null;
738
+ }
739
+
740
+ declare function resolveDomEditSelection(startEl: HTMLElement | null, options: DomEditContextOptions & {
741
+ projectId?: string | null;
742
+ skipSourceProbe?: boolean;
743
+ exactTarget?: boolean;
744
+ previous?: DomEditSelection | null;
745
+ }): Promise<DomEditSelection | null>;
746
+
747
+ /**
748
+ * Agent prompt builder for HyperFrames element edit requests.
749
+ */
750
+
751
+ /**
752
+ * The subset of an element selection shared by the Studio DOM editor (`DomEditSelection`) and the
753
+ * runtime picker (`HyperframePickerElementInfo`); a field absent from a caller's type is simply omitted.
754
+ */
755
+ interface AgentPromptElementInfo {
756
+ id: string | null;
757
+ selector?: string | null;
758
+ /** Disambiguates duplicate selectors in `DomEditSelection`. The picker
759
+ * payload has no such concept (one picked node, not a candidate list), so
760
+ * a picker-built prompt always prints index 0 — expected, not a gap. */
761
+ selectorIndex?: number;
762
+ tagName: string;
763
+ label?: string;
764
+ boundingBox: {
765
+ x: number;
766
+ y: number;
767
+ width: number;
768
+ height: number;
769
+ };
770
+ textContent: string | null;
771
+ src?: string | null;
772
+ textFields?: DomEditTextField[];
773
+ inlineStyles?: Record<string, string>;
774
+ computedStyles?: Record<string, string>;
775
+ }
776
+ /**
777
+ * Same convention as `buildElementAgentPrompt`, for a host app embedding only the player: built from
778
+ * the runtime picker's own payload, not `DomEditSelection`. Null selection yields a bare prompt, no guardrails.
779
+ */
780
+ declare function buildPickerAgentPrompt({ selection, userInstruction, }: {
781
+ selection: HyperframePickerElementInfo | null;
782
+ userInstruction?: string;
783
+ }): string;
784
+ declare function buildPickerAgentContextPreview(selection: HyperframePickerElementInfo | null): string;
785
+
786
+ interface SdkSessionPublication {
787
+ candidate: Composition;
788
+ expectedSession: Composition;
789
+ targetPath: string;
790
+ }
791
+ type SdkSessionPublicationResult = "published" | "rejected-active-target" | "rejected-inactive-target";
792
+ type PublishSdkSession = (publication: SdkSessionPublication) => SdkSessionPublicationResult;
793
+
794
+ type TimelineLayerDropPlacement = {
795
+ type: "onto";
796
+ layerId: string;
797
+ } | {
798
+ type: "between";
799
+ beforeLayerId: string;
800
+ afterLayerId: string;
801
+ } | {
802
+ type: "above";
803
+ layerId: string;
804
+ } | {
805
+ type: "below";
806
+ layerId: string;
807
+ };
808
+ interface TimelineStackingZIndexChange {
809
+ key: string;
810
+ zIndex: number;
811
+ domId?: string;
812
+ selector?: string;
813
+ selectorIndex?: number;
814
+ sourceFile?: string;
815
+ }
816
+ interface TimelineStackingReorderIntent {
817
+ contextKey: string;
818
+ placement: TimelineLayerDropPlacement;
819
+ zIndexChanges: TimelineStackingZIndexChange[];
820
+ }
821
+
822
+ type BlockedTimelineEditIntent = "move" | "resize-start" | "resize-end";
823
+ interface TimelineRangeSelection {
824
+ start: number;
825
+ end: number;
826
+ anchorX: number;
827
+ anchorY: number;
828
+ }
829
+
830
+ interface RecordEditInput$5 {
831
+ label: string;
832
+ coalesceKey?: string;
833
+ coalesceMs?: number;
834
+ files: Record<string, {
835
+ before: string;
836
+ after: string;
837
+ }>;
838
+ created?: string[];
839
+ }
840
+
841
+ interface ImportedFontAsset {
842
+ family: string;
843
+ path: string;
844
+ url: string;
845
+ weight?: string;
846
+ style?: "normal" | "italic";
847
+ }
848
+
849
+ /** Durable evidence returned by the one Studio DOM persistence actor. */
850
+ interface DomEditPersistOutcome {
851
+ sourceFile: string;
852
+ version: string;
853
+ changed: boolean;
854
+ }
855
+ /**
856
+ * Durability report for a patch-batches commit. `durable === false` means the
857
+ * server could not locate at least one patch target on disk — the preview was
858
+ * reloaded to reconverge, and dependent follow-up writes (the z→lane timeline
859
+ * mirror) must be skipped. `allMatched` retains the underlying match detail.
860
+ * `changed === false` means no source file was written: every patch was a
861
+ * byte-identical no-op, or the atomic gesture was refused before any write.
862
+ */
863
+ interface DomEditPatchBatchesResult {
864
+ durable: boolean;
865
+ allMatched: boolean;
866
+ changed: boolean;
867
+ }
868
+ /** Several data-* and HTML attribute ops on one element as ONE persist and ONE undo entry. */
869
+ type CommitDomAttributeBatch = (selection: DomEditSelection, operations: PatchOperation[], options: {
870
+ label: string;
871
+ prepareContent?: (html: string) => string;
872
+ }) => Promise<boolean>;
873
+
874
+ interface RecordEditInput$4 {
875
+ label: string;
876
+ coalesceKey?: string;
877
+ files: Record<string, {
878
+ before: string;
879
+ after: string;
880
+ }>;
881
+ }
882
+ type TimelineZIndexReorderCommit = (entries: Array<{
883
+ element: HTMLElement;
884
+ zIndex: number;
885
+ id?: string;
886
+ selector?: string;
887
+ selectorIndex?: number;
888
+ sourceFile: string;
889
+ key?: string;
890
+ }>, coalesceKey?: string) => Promise<DomEditPatchBatchesResult | undefined | void>;
891
+ interface UseTimelineEditingOptions {
892
+ projectId: string | null;
893
+ activeCompPath: string | null;
894
+ timelineElements: TimelineElement[];
895
+ showToast: (message: string, tone?: "error" | "info") => void;
896
+ writeProjectFile: (path: string, content: string, expectedContent?: string) => Promise<void>;
897
+ observeProjectFileVersion?: (path: string, version: string | null) => void;
898
+ recordEdit: (input: RecordEditInput$4) => Promise<void>;
899
+ reloadPreview: () => void;
900
+ previewIframeRef: RefObject<HTMLIFrameElement | null>;
901
+ pendingTimelineEditPathRef: MutableRefObject<Set<string>>;
902
+ uploadProjectFiles: (files: Iterable<File>, dir?: string) => Promise<string[]>;
903
+ isRecordingRef?: RefObject<boolean>;
904
+ /** Stage 7 §3.2: SDK session for routing timing ops through setTiming. */
905
+ sdkSession?: Composition | null;
906
+ /** Publish a fully persisted candidate SDK session. */
907
+ publishSdkSession?: PublishSdkSession;
908
+ /** Resync the SDK session after a server-authoritative timeline write. */
909
+ forceReloadSdkSession?: () => void;
910
+ /** Reparse authored animations after a timing rewrite changes their positions. */
911
+ invalidateGsapCache?: () => void;
912
+ handleDomZIndexReorderCommitRef?: MutableRefObject<TimelineZIndexReorderCommit | null>;
913
+ /** Refuses a hand edit at the persist boundary when set; absent = Studio unchanged. */
914
+ canEdit?: CanEditTimelineElement;
915
+ }
916
+ /** What a timeline move commits: the new start and track, plus the z-index
917
+ * reorder a vertical drag resolves to (absent for a pure horizontal move). */
918
+ type TimelineMoveUpdates = Pick<TimelineElement, "start" | "track"> & {
919
+ stackingReorder?: TimelineStackingReorderIntent | null;
920
+ };
921
+
922
+ declare class StudioSaveHttpError extends Error {
923
+ readonly statusCode: number;
924
+ readonly alreadyToasted: boolean;
925
+ constructor(message: string, statusCode: number, options?: {
926
+ alreadyToasted?: boolean;
927
+ });
928
+ }
929
+ declare class StudioFileConflictError extends StudioSaveHttpError {
930
+ readonly filePath: string;
931
+ readonly currentVersion: string | null;
932
+ readonly currentContent: string | null;
933
+ readonly attemptedContent: string;
934
+ constructor(input: {
935
+ filePath: string;
936
+ currentVersion: string | null;
937
+ currentContent: string | null;
938
+ attemptedContent: string;
939
+ });
940
+ }
941
+ type StudioSaveDrainResult<Failure = unknown> = {
942
+ status: "clean";
943
+ } | {
944
+ status: "conflict";
945
+ error: StudioFileConflictError;
946
+ } | {
947
+ status: "failed";
948
+ error: Failure;
949
+ };
950
+
951
+ type StudioPendingEditsDrainResult = StudioSaveDrainResult;
952
+ interface StudioEditInFlight {
953
+ reverted: () => boolean;
954
+ within: <T>(run: () => T) => T;
955
+ drawUnlessUndone: (draw: () => void) => void;
956
+ drawKeepingUndone: <T>(draw: () => T) => T;
957
+ markSaved: () => void;
958
+ }
959
+ declare function revertNewestStudioPendingEdit(): (() => void) | null;
960
+ declare function flushStudioPendingEdits({ onlyCurrent, }?: {
961
+ onlyCurrent?: boolean | undefined;
962
+ }): Promise<StudioPendingEditsDrainResult>;
963
+
964
+ /** Value-only channels a `tl.set(...)` patch may touch. */
965
+ interface SetPatchProps {
966
+ x?: number;
967
+ y?: number;
968
+ rotation?: number;
969
+ rotationX?: number;
970
+ rotationY?: number;
971
+ rotationZ?: number;
972
+ z?: number;
973
+ transformPerspective?: number;
974
+ scaleX?: number;
975
+ scaleY?: number;
976
+ scale?: number;
977
+ opacity?: number;
978
+ }
979
+ /** A single keyframe step's numeric channels (the GSAP array-keyframe form). */
980
+ type KeyframeStep = Record<string, number>;
981
+ type RuntimeTweenChange = {
982
+ kind: "set";
983
+ props: SetPatchProps;
984
+ } | {
985
+ kind: "keyframes";
986
+ keyframes: KeyframeStep[];
987
+ } | {
988
+ kind: "keyframe-rebuild";
989
+ pct: number;
990
+ props: KeyframeStep;
991
+ } | {
992
+ kind: "global-set";
993
+ props: SetPatchProps;
994
+ };
995
+
996
+ type KeyframeUsageAction = "add" | "convert" | "remove_all" | "reset";
997
+
998
+ interface MutationResult {
999
+ ok: boolean;
1000
+ changed?: boolean;
1001
+ mutationChanges?: boolean[];
1002
+ parsed?: ParsedGsap;
1003
+ before?: string;
1004
+ after?: string;
1005
+ scriptText?: string;
1006
+ }
1007
+ interface CommitMutationOptions {
1008
+ label: string;
1009
+ keyframeTelemetry?: boolean;
1010
+ keyframeAction?: KeyframeUsageAction;
1011
+ keyframeProperty?: string;
1012
+ /** Observe the durable writer result without duplicating the request path. */
1013
+ onResult?: (result: MutationResult) => void;
1014
+ coalesceKey?: string;
1015
+ coalesceMs?: number;
1016
+ softReload?: boolean;
1017
+ skipReload?: boolean;
1018
+ /**
1019
+ * Write the source but leave the preview alone; the caller renders once when it
1020
+ * is done. For a multi-write action like a group drag, rendering after each
1021
+ * write shows a source where the members not yet written still hold their old
1022
+ * values, so they snap back until their own write lands. This also defers the
1023
+ * in-place runtime patch's seek, which re-renders the whole timeline and repaints
1024
+ * the queued members the same way. Unlike `skipReload` this changes nothing about
1025
+ * error handling — a failed write still throws.
1026
+ */
1027
+ deferPreviewSync?: boolean;
1028
+ /** Carries a deferred write not yet on screen (no patch, or a missed one) to the final render. */
1029
+ previewFallbackLatch?: {
1030
+ pending: boolean;
1031
+ };
1032
+ beforeReload?: () => void;
1033
+ pendingEdit?: StudioEditInFlight;
1034
+ /**
1035
+ * Serialize this commit against others sharing the same key. Used to chain
1036
+ * per-animationId GSAP meta updates. Every commit independently takes the
1037
+ * project/file mutation lock, so this key only adds ordering and can never
1038
+ * bypass whole-file serialization.
1039
+ */
1040
+ serializeKey?: string;
1041
+ /**
1042
+ * Value-only edit fast path. When present, `runCommit` first tries to patch the
1043
+ * one changed tween in the preview's runtime timeline in place
1044
+ * (`patchRuntimeTweenInPlace`) — instant, no composition re-run, no iframe
1045
+ * remount. On a successful patch the reload is skipped entirely (panels still
1046
+ * refresh); when the patch can't be confidently applied it falls back to the
1047
+ * existing soft/full reload path. Structural edits omit this and reload as before.
1048
+ */
1049
+ instantPatch?: {
1050
+ selector: string;
1051
+ change: RuntimeTweenChange;
1052
+ };
1053
+ /**
1054
+ * The same fast path for a batched commit: one patch per element the batch
1055
+ * wrote, applied in order. All of them must land for the reload to be skipped
1056
+ * — one that can't be applied leaves the preview half-patched, so the whole
1057
+ * batch falls back to the reload. Only the last patch re-renders (see
1058
+ * `deferSeek`), so a ten-element batch repaints once.
1059
+ */
1060
+ instantPatches?: Array<{
1061
+ selector: string;
1062
+ change: RuntimeTweenChange;
1063
+ }>;
1064
+ }
1065
+
1066
+ interface TimelineGroupMoveChange {
1067
+ element: TimelineElement;
1068
+ start: number;
1069
+ track?: number;
1070
+ audioGroup?: null;
1071
+ }
1072
+ interface TimelineGroupResizeChange {
1073
+ element: TimelineElement;
1074
+ start: number;
1075
+ duration: number;
1076
+ playbackStart?: number;
1077
+ }
1078
+ interface TimelineGroupCommitOptions {
1079
+ beforeTiming?: Promise<void>;
1080
+ coalesceKey?: string;
1081
+ /** Overrides the default "Move timeline clips" undo-history label. Coalescing
1082
+ * keeps the LAST entry's label (editHistory.ts), so a mechanical follow-up
1083
+ * move folded into another gesture's coalesceKey (e.g. the ripple after a
1084
+ * delete) should carry that gesture's own label, not its own. */
1085
+ label?: string;
1086
+ /** Skips this call's own generic failure toast (the error is still logged
1087
+ * to the console) — for a caller that shows its own more specific message
1088
+ * on the same failure, so the user isn't told about one action twice. */
1089
+ suppressFailureToast?: boolean;
1090
+ }
1091
+
1092
+ type TimelineAtomicMoveUpdates = Pick<TimelineElement, "start" | "track"> & {
1093
+ audioGroup?: null;
1094
+ };
1095
+ type TimelineMoveOperation = "timing" | "lane-reorder" | "track-insert";
1096
+
1097
+ interface TimelineKeyframeTarget {
1098
+ percentage: number;
1099
+ tweenPercentage?: number;
1100
+ propertyGroup?: string;
1101
+ animationId?: string;
1102
+ collidingAnimationTargets?: AnimationKeyframeTarget[];
1103
+ }
1104
+
1105
+ interface TimelinePropertyGroupKeyframeToggle {
1106
+ animationId: string;
1107
+ propertyGroup: PropertyGroupName;
1108
+ tweenPercentage: number;
1109
+ properties: Record<string, number | string>;
1110
+ remove: boolean;
1111
+ }
1112
+ /** Where an outside drop lands; `insertRow` opens a new track at that row boundary of `trackOrder`. */
1113
+ type TimelineDropPlacement = {
1114
+ start: number;
1115
+ track: number;
1116
+ } & ({
1117
+ insertRow?: null;
1118
+ trackOrder?: undefined;
1119
+ } | {
1120
+ insertRow: number;
1121
+ trackOrder: readonly number[];
1122
+ });
1123
+ /**
1124
+ * Shared callback signatures for timeline editing operations.
1125
+ * Used by NLELayout, Timeline, and any component that passes through
1126
+ * the standard set of timeline mutation handlers.
1127
+ */
1128
+ interface TimelineDropCallbacks {
1129
+ onFileDrop?: (files: File[], placement?: TimelineDropPlacement) => Promise<void> | void;
1130
+ onAssetDrop?: (assetPath: string, placement: TimelineDropPlacement) => Promise<void> | void;
1131
+ onBlockDrop?: (blockName: string, placement: {
1132
+ start: number;
1133
+ track: number;
1134
+ }) => Promise<void> | void;
1135
+ onCompositionDrop?: (sourcePath: string, placement: {
1136
+ start: number;
1137
+ track: number;
1138
+ }) => Promise<void> | void;
1139
+ }
1140
+ type TimelineLinkEdit = {
1141
+ kind: "unlink";
1142
+ elements: readonly TimelineElement[];
1143
+ } | {
1144
+ kind: "link";
1145
+ elements: readonly TimelineElement[];
1146
+ } | {
1147
+ kind: "detach";
1148
+ element: TimelineElement;
1149
+ } | {
1150
+ kind: "merge";
1151
+ video: TimelineElement;
1152
+ audio: TimelineElement;
1153
+ } | {
1154
+ kind: "move-into-sync";
1155
+ element: TimelineElement;
1156
+ start: number;
1157
+ } | {
1158
+ kind: "slip-into-sync";
1159
+ element: TimelineElement;
1160
+ mediaStart: number;
1161
+ };
1162
+ interface TimelineEditCallbacks {
1163
+ onMoveElement?: (element: TimelineElement, updates: TimelineAtomicMoveUpdates) => Promise<void> | void;
1164
+ /** Atomic multi-clip move (single undo) for main-track ripple + track-insert.
1165
+ * `coalesceKey` (drag-commit gesture id) merges the move history entry with a
1166
+ * lane change's follow-up z-reorder entry into one undo step. */
1167
+ onMoveElements?: (edits: Array<{
1168
+ element: TimelineElement;
1169
+ updates: TimelineAtomicMoveUpdates;
1170
+ }>, coalesceKey?: string, operation?: TimelineMoveOperation) => Promise<void> | void;
1171
+ onResizeElement?: (element: TimelineElement, updates: Pick<TimelineElement, "start" | "duration" | "playbackStart">) => Promise<void> | void;
1172
+ onResizeElements?: (changes: Array<{
1173
+ element: TimelineElement;
1174
+ start: number;
1175
+ duration: number;
1176
+ playbackStart?: number;
1177
+ }>, options?: {
1178
+ coalesceKey?: string;
1179
+ }) => Promise<void> | void;
1180
+ /**
1181
+ * `displayNumber` is the row the CLICKED control announced. It travels with
1182
+ * the click because the header and the undo-history label derive the row from
1183
+ * two different orderings: the header's comes from the group-aware row list
1184
+ * (synthetic anchor rows, members pulled contiguous), the history's from a
1185
+ * plain ascending sort of element-bearing keys. Once a group exists those
1186
+ * disagree, so the same click said "Hide track 2" and recorded "Hide track 1".
1187
+ * Passing the rendered number keeps one answer instead of two derivations.
1188
+ */
1189
+ onToggleTrackHidden?: (track: number, hidden: boolean, displayNumber?: number | null) => Promise<void> | void;
1190
+ /** B7's bus strip: live-write the group's own attribute while dragging. */
1191
+ onSetAudioGroupAttributeLive?: (groupId: string, attr: string, value: string | null) => void;
1192
+ onRevertAudioGroupAttributeLive?: (groupId: string, attr: string) => void;
1193
+ /** ...and persist one undo entry on release. */
1194
+ onSetAudioGroupAttributeQuiet?: (groupId: string, attr: string, value: string | null, label: string) => Promise<TimelineEditOutcome | void>;
1195
+ /** C1's ungrouped-track FX pointer: "Group these clips" — write
1196
+ * `data-audio-group` on every one of them, atomically. Same shape B6's
1197
+ * carve auto-grouping uses. */
1198
+ onGroupClips?: (clipIds: readonly string[], groupId: string, groupLabel?: string) => Promise<void>;
1199
+ /** C1's single-clip FX write: addressed by the clip itself rather than the
1200
+ * current selection, mirroring `onSetAudioGroupAttributeLive/Quiet`. */
1201
+ onSetElementAttributeLive?: (element: TimelineElement, attr: string, value: string | null) => void;
1202
+ onRevertElementAttributeLive?: (element: TimelineElement, attr: string) => void;
1203
+ onSetElementAttributeQuiet?: (element: TimelineElement, attr: string, value: string | null, label: string) => Promise<TimelineEditOutcome | void>;
1204
+ /** One attribute on several clips, saved as one undo step. */
1205
+ onSetElementsAttributeQuiet?: (edits: ReadonlyArray<{
1206
+ element: TimelineElement;
1207
+ value: string | null;
1208
+ }>, attr: string, label: string) => Promise<TimelineEditOutcome | void>;
1209
+ onBlockedEditAttempt?: (element: TimelineElement, intent: BlockedTimelineEditIntent) => void;
1210
+ onLinkEdit?: (edit: TimelineLinkEdit) => Promise<void> | void;
1211
+ onDeleteElementOnly?: (element: TimelineElement) => Promise<void> | void;
1212
+ onSplitElement?: (element: TimelineElement, splitTime: number) => Promise<void> | void;
1213
+ onRazorSplit?: (element: TimelineElement, splitTime: number) => Promise<void> | void;
1214
+ onRazorSplitAll?: (splitTime: number) => Promise<void> | void;
1215
+ onFreezeFrame?: (element: TimelineElement, time: number) => Promise<void> | void;
1216
+ clipMenuTools?: boolean;
1217
+ onNotice?: (message: string, tone?: "error" | "info") => void;
1218
+ onDeleteKeyframe?: (elementId: string, keyframe: TimelineKeyframeTarget) => void;
1219
+ onDeleteAllKeyframes?: (element: TimelineElement, animationId?: string) => void;
1220
+ onMoveKeyframeToPlayhead?: (element: TimelineElement, keyframe: TimelineKeyframeTarget) => void;
1221
+ /** Drag-to-retime: `keyframe` identifies the dragged keyframe (its percentage
1222
+ * is clip-relative), `toClipPercentage` is the neighbour-clamped drop. */
1223
+ onMoveKeyframe?: (elementId: string, keyframe: TimelineKeyframeTarget, toClipPercentage: number) => Promise<boolean>;
1224
+ onToggleKeyframeAtPlayhead?: (element: TimelineElement) => void;
1225
+ onTogglePropertyGroupKeyframe?: (element: TimelineElement, target: TimelinePropertyGroupKeyframeToggle) => Promise<void> | void;
1226
+ }
1227
+
1228
+ interface TimelineTrackStyle {
1229
+ clip: string;
1230
+ accent: string;
1231
+ label: string;
1232
+ clipActive?: string;
1233
+ }
1234
+ interface TimelineTheme {
1235
+ shellBackground: string;
1236
+ shellBorder: string;
1237
+ rulerBorder: string;
1238
+ rowBackground: string;
1239
+ rowBorder: string;
1240
+ gutterBackground: string;
1241
+ gutterBorder: string;
1242
+ textPrimary: string;
1243
+ textSecondary: string;
1244
+ tickText: string;
1245
+ tickMajor: string;
1246
+ tickMinor: string;
1247
+ clipBackground: string;
1248
+ clipBackgroundActive: string;
1249
+ clipBackgroundHover: string;
1250
+ clipBackgroundDragging: string;
1251
+ clipBorder: string;
1252
+ clipBorderHover: string;
1253
+ clipBorderActive: string;
1254
+ handleColor: string;
1255
+ panelResizeSeam: string;
1256
+ panelResizeActive: string;
1257
+ clipRadius: string;
1258
+ audioClipRadius: string;
1259
+ transitionZone: string;
1260
+ transitionBadge: string;
1261
+ transitionBadgeInk: string;
1262
+ }
1263
+
1264
+ interface TimelineTimeRange {
1265
+ readonly start: number;
1266
+ readonly end: number;
1267
+ }
1268
+ interface TimelineClipInterval {
1269
+ readonly element: TimelineElement;
1270
+ readonly identity: string;
1271
+ readonly ordinal: number;
1272
+ readonly start: number;
1273
+ readonly end: number;
1274
+ }
1275
+ interface TimelineClipRowIndex {
1276
+ readonly byStart: readonly TimelineClipInterval[];
1277
+ readonly treeLeafCount: number;
1278
+ readonly maxPositiveEndTree: readonly number[];
1279
+ readonly maxPointStartTree: readonly number[];
1280
+ readonly byIdentity: ReadonlyMap<string, readonly TimelineClipInterval[]>;
1281
+ }
1282
+ interface TimelineClipIndex {
1283
+ readonly rows: ReadonlyMap<number, TimelineClipRowIndex>;
1284
+ }
1285
+
1286
+ declare const TRACK_H = 48;
1287
+ interface TimelineTrackPadding {
1288
+ top?: number;
1289
+ bottom?: number;
1290
+ }
1291
+ interface TimelineRowGeometry {
1292
+ readonly rowKeys: readonly number[];
1293
+ readonly rowHeights: readonly number[];
1294
+ /** Cumulative row boundaries, including the final bottom boundary. */
1295
+ readonly rowOffsets: readonly number[];
1296
+ readonly rowsHeight: number;
1297
+ readonly padding: Readonly<Required<TimelineTrackPadding>>;
1298
+ readonly canvasHeight: number;
1299
+ getRowIndex(rowKey: number): number;
1300
+ getRowHeight(row: number): number;
1301
+ getRowTop(row: number): number;
1302
+ getRowFromY(contentY: number): number;
1303
+ getRowPositionFromY(contentY: number): {
1304
+ rowFloat: number;
1305
+ row: number;
1306
+ fraction: number;
1307
+ rowHeight: number;
1308
+ };
1309
+ }
1310
+
1311
+ type TimelineEditOverrides = Pick<TimelineEditCallbacks, "onMoveElement" | "onMoveElements" | "onResizeElement" | "onResizeElements" | "onBlockedEditAttempt" | "onSplitElement">;
1312
+
1313
+ /** With both set, a lane move restacks the preview's z-index to match the rows; each overrides Studio's own. */
1314
+ interface TimelineStackingSyncProps {
1315
+ previewIframeRef?: RefObject<HTMLIFrameElement | null>;
1316
+ onZIndexReorder?: TimelineZIndexReorderCommit;
1317
+ }
1318
+
1319
+ interface TimelineClipRenderContext {
1320
+ priority: "overscan" | "visible" | "interaction";
1321
+ rich: boolean;
1322
+ }
1323
+ interface TimelineClipMenuItem {
1324
+ id: string;
1325
+ label: string;
1326
+ icon?: ReactNode;
1327
+ shortcut?: string;
1328
+ disabled?: boolean;
1329
+ onSelect: () => void;
1330
+ }
1331
+ interface TimelineProps extends TimelineDropCallbacks, TimelineEditOverrides, TimelineStackingSyncProps {
1332
+ /** Project-scoped reset boundary; soft source refreshes retain the same epoch. */
1333
+ sessionEpoch?: number;
1334
+ onSeek?: (time: number, options?: {
1335
+ keepPlaying?: boolean;
1336
+ follow?: boolean;
1337
+ }) => void;
1338
+ onDrillDown?: (element: TimelineElement) => void;
1339
+ /** Picture only: takes no pointer input. Interactive content goes in renderClipOverlay. */
1340
+ renderClipContent?: (element: TimelineElement, style: {
1341
+ clip: string;
1342
+ label: string;
1343
+ }, context: TimelineClipRenderContext) => ReactNode;
1344
+ renderClipOverlay?: (element: TimelineElement) => ReactNode;
1345
+ onDeleteElement?: (element: TimelineElement) => Promise<void> | void;
1346
+ onSelectElement?: (element: TimelineElement | null) => void;
1347
+ /** Notification only; null when cleared. The value lives in usePlayerStore.rangeSelection. */
1348
+ onRangeSelect?: (range: TimelineTimeRange$1 | null) => void;
1349
+ onCopyClip?: () => boolean;
1350
+ onPasteClip?: () => Promise<void>;
1351
+ onDuplicateClip?: () => Promise<boolean>;
1352
+ canPasteClip?: () => boolean;
1353
+ clipMenuItems?: (element: TimelineElement) => readonly TimelineClipMenuItem[];
1354
+ splitShortcut?: string;
1355
+ theme?: Partial<TimelineTheme>;
1356
+ showAudioEffects?: boolean;
1357
+ showKeyframes?: boolean;
1358
+ trackPadding?: TimelineTrackPadding;
1359
+ readOnly?: boolean;
1360
+ onReadOnlyPress?: () => void;
1361
+ }
1362
+
1363
+ interface TimelineEmptyStateProps {
1364
+ isDragOver: boolean;
1365
+ onFileDrop?: boolean;
1366
+ onDragOver: DragEventHandler<HTMLDivElement>;
1367
+ onDragLeave: DragEventHandler<HTMLDivElement>;
1368
+ onDrop: DragEventHandler<HTMLDivElement>;
1369
+ }
1370
+ declare function TimelineEmptyState({ isDragOver, onFileDrop, onDragOver, onDragLeave, onDrop, }: TimelineEmptyStateProps): react_jsx_runtime.JSX.Element;
1371
+
1372
+ interface Rect$1 {
1373
+ left: number;
1374
+ top: number;
1375
+ width: number;
1376
+ height: number;
1377
+ }
1378
+
1379
+ type TimelineSnapType = "beat" | "playhead" | "clip-edge" | "grid";
1380
+ interface TimelineSnapTarget {
1381
+ time: number;
1382
+ type: TimelineSnapType;
1383
+ }
1384
+
1385
+ interface DraggedClipState {
1386
+ /** Pointer captured by the viewport coordinator; null for a keyboard pickup. */
1387
+ pointerId: number | null;
1388
+ element: TimelineElement;
1389
+ originClientX: number;
1390
+ originClientY: number;
1391
+ originScrollLeft: number;
1392
+ originScrollTop: number;
1393
+ pointerClientX: number;
1394
+ pointerClientY: number;
1395
+ pointerOffsetX: number;
1396
+ pointerOffsetY: number;
1397
+ previewStart: number;
1398
+ previewTrack: number;
1399
+ /**
1400
+ * The lane the POINTER aims at, before the kind-zone clamp picks `previewTrack`.
1401
+ * The commit reads it to tell a deliberate vertical lane change (stacking sync
1402
+ * allowed) from a horizontal drag. Absent: the commit falls back to `previewTrack`.
1403
+ */
1404
+ desiredTrack?: number;
1405
+ /**
1406
+ * When non-null, the drop inserts a NEW track at this visual row boundary
1407
+ * (0 = above the top lane, trackOrder.length = below the bottom) instead of
1408
+ * landing on previewTrack. Drives the opened preview lane.
1409
+ */
1410
+ insertRow: number | null;
1411
+ /** Snap target the clip will land on, for the guide highlight. */
1412
+ snapTime: number | null;
1413
+ snapType: TimelineSnapType | null;
1414
+ started: boolean;
1415
+ altKey?: boolean;
1416
+ }
1417
+ interface ResizingClipState {
1418
+ /** Pointer captured by the stable viewport coordinator for this gesture. */
1419
+ pointerId: number;
1420
+ element: TimelineElement;
1421
+ edge: "start" | "end";
1422
+ originClientX: number;
1423
+ /**
1424
+ * scrollLeft at gesture start. Edge auto-scroll moves the content under a
1425
+ * stationary pointer, so the trim math folds (current − origin) scrollLeft
1426
+ * into the pointer x — mirroring resolveTimelineMove's scroll compensation.
1427
+ * Optional so pre-existing constructors/tests stay valid; when absent the
1428
+ * first preview update captures the current scrollLeft.
1429
+ */
1430
+ originScrollLeft?: number;
1431
+ previewStart: number;
1432
+ previewDuration: number;
1433
+ previewPlaybackStart?: number;
1434
+ /** Snap target the trimmed edge landed on, for the guide highlight. */
1435
+ snapTime?: number | null;
1436
+ snapType?: TimelineSnapType | null;
1437
+ /** Coordinator-owned group projection; canonical elements change only on commit. */
1438
+ groupPreview?: readonly {
1439
+ key: string;
1440
+ start: number;
1441
+ duration: number;
1442
+ playbackStart?: number;
1443
+ }[];
1444
+ started: boolean;
1445
+ altKey?: boolean;
1446
+ }
1447
+ interface BlockedClipState {
1448
+ pointerId: number;
1449
+ element: TimelineElement;
1450
+ intent: BlockedTimelineEditIntent;
1451
+ originClientX: number;
1452
+ originClientY: number;
1453
+ started: boolean;
1454
+ }
1455
+
1456
+ type TrackVisualStyle = TimelineTrackStyle;
1457
+
1458
+ /** One resolved audio group, positioned in the row order. */
1459
+ interface TimelineTrackGroupInfo {
1460
+ id: string;
1461
+ label: string;
1462
+ /**
1463
+ * Synthetic sort key for the group's own row — the same fractional-key
1464
+ * convention sub-composition expansion already uses (see
1465
+ * timelineTrackDisplay.ts): the first (lowest) member track's number minus
1466
+ * 0.5, so it slots in immediately above that member.
1467
+ */
1468
+ anchorKey: number;
1469
+ /** Member track numbers, ascending. */
1470
+ memberTracks: number[];
1471
+ /**
1472
+ * Every clip under this group, in member-track order — INDEPENDENT of whether
1473
+ * the group is expanded.
1474
+ *
1475
+ * Collapsing a group stops emitting its member rows into `tracks`, so anything
1476
+ * that recovered member elements by looking them up there got an empty list in
1477
+ * the default (collapsed) state — silently disabling the
1478
+ * automation-lane count, and the bus strip's member labels. Membership is not
1479
+ * a display concern, so it does not travel through the display list.
1480
+ */
1481
+ memberElements: TimelineElement[];
1482
+ /** The group element's `data-volume`, mirrored from a member's parse (B7's slider). */
1483
+ volume: number;
1484
+ /** The group element's `data-hidden`, mirrored from a member's parse (B5's group mute). */
1485
+ hidden: boolean;
1486
+ /** The group element's serialized `data-fx-chain`, mirrored from a member's parse (C1's FX entry). */
1487
+ fxChain?: string;
1488
+ /** The group element's serialized `data-automation` — the group's OWN lanes,
1489
+ * which are what its `∿` discloses (groups doc §5). */
1490
+ automation?: string;
1491
+ }
1492
+ /**
1493
+ * The track number of each timeline row, top to bottom: pass the player store's `elements` and
1494
+ * `collapsedGroupIds`. A group's anchor row is its first member's track minus 0.5.
1495
+ */
1496
+ declare function displayTrackOrder(elements: readonly TimelineElement[], collapsedGroupIds: ReadonlySet<string>): number[];
1497
+
1498
+ interface TimelineVirtualRow {
1499
+ readonly index: number;
1500
+ readonly rowKey: number;
1501
+ }
1502
+
1503
+ /**
1504
+ * Pure geometry for the LIVE multi-selection drag preview.
1505
+ *
1506
+ * Visual model (matches main): while a selected clip is dragged, ALL selected
1507
+ * clips move together LIVE as one rigid formation following the cursor. The
1508
+ * GRABBED clip is drawn as the free-floating ghost; every OTHER selected member
1509
+ * ("passenger") slides by the SAME time delta via a cheap compositor
1510
+ * `translateX` (no re-layout). Passengers do NOT stay still, and they do NOT lag
1511
+ * behind individually — the whole formation moves by one delta, spacing locked.
1512
+ *
1513
+ * That single delta is the GRABBED clip's `draggedPreviewStart − draggedOriginStart`.
1514
+ * The preview start is ALREADY group-clamped upstream (computeDragPreview floors it
1515
+ * at groupMoveFloor), so this delta is the clamped delta:
1516
+ * the instant any member would cross 0 the grabbed clip stops and every passenger
1517
+ * stops with it — the formation never deforms. On DROP the commit shifts every
1518
+ * moving clip (resolveGroupMovers) by this same delta (see timelineClipDragCommit).
1519
+ *
1520
+ * Track changes apply to the grabbed clip only (mirroring the commit); passengers
1521
+ * keep their lanes, so only their x moves.
1522
+ */
1523
+ interface MultiDragPreviewInput {
1524
+ /** The drag is live (past the movement threshold). */
1525
+ dragStarted: boolean;
1526
+ /** Key of the clip under the pointer. */
1527
+ draggedKey: string;
1528
+ /** The dragged clip's committed start (pre-drag). */
1529
+ draggedOriginStart: number;
1530
+ /** The dragged clip's live preview start (already group-clamped upstream). */
1531
+ draggedPreviewStart: number;
1532
+ /** The current multi-selection (store.selectedElementIds). */
1533
+ selectedKeys: ReadonlySet<string>;
1534
+ }
1535
+
1536
+ interface TimelineLogicalItem {
1537
+ id: string;
1538
+ kind: "clip" | "keyframe" | "ease";
1539
+ rowId: string;
1540
+ elementId: string;
1541
+ /** The item's time anchor. Clips use their midpoint; ease controls use the segment midpoint. */
1542
+ time: number;
1543
+ element?: TimelineElement;
1544
+ keyframeTarget?: TimelineKeyframeTarget;
1545
+ }
1546
+ interface TimelineLogicalRow {
1547
+ id: string;
1548
+ kind: "row";
1549
+ physicalTrackKey: number;
1550
+ logicalIndex: number;
1551
+ level: 1 | 2 | 3;
1552
+ parentId: string | null;
1553
+ elementId: string | null;
1554
+ /** Set only on a group's own row (level 1, no clips of its own). */
1555
+ groupId?: string;
1556
+ expandable: boolean;
1557
+ expanded: boolean;
1558
+ propertyGroup?: PropertyGroupName;
1559
+ items: readonly TimelineLogicalItem[];
1560
+ }
1561
+
1562
+ /**
1563
+ * Props shared by the scroll container ({@link import("./TimelineCanvas")}) and
1564
+ * the lane renderer ({@link import("./TimelineLanes")}). TimelineCanvas passes
1565
+ * these straight through via spread, so they are declared once here and both
1566
+ * prop types compose from this base — no duplicated prop list. Kept in its own
1567
+ * module so neither side has to import the other just to name the contract.
1568
+ */
1569
+ interface TimelineLaneBaseProps {
1570
+ pps: number;
1571
+ contentOrigin: number;
1572
+ contentGutter: number;
1573
+ trackContentWidth: number;
1574
+ theme: TimelineTheme;
1575
+ showAudioEffects?: boolean;
1576
+ displayTrackOrder: number[];
1577
+ rowHeights: readonly number[];
1578
+ rowGeometry: TimelineRowGeometry;
1579
+ virtualRows: readonly TimelineVirtualRow[];
1580
+ logicalRows: readonly TimelineLogicalRow[];
1581
+ focusedTargetId: string | null;
1582
+ rowsVirtualized: boolean;
1583
+ clipIndex: TimelineClipIndex;
1584
+ renderTimeRange: TimelineTimeRange;
1585
+ visibleTimeRange: TimelineTimeRange;
1586
+ pinnedClipIdentities: ReadonlySet<string>;
1587
+ trackOrder: number[];
1588
+ tracks: [number, TimelineElement[]][];
1589
+ trackStyles: Map<number, TrackVisualStyle>;
1590
+ laneCounts: ReadonlyMap<string, number>;
1591
+ selectedElementId: string | null;
1592
+ selectedElementIds: Set<string>;
1593
+ hoveredClip: string | null;
1594
+ draggedClip: DraggedClipState | null;
1595
+ blockedClipRef: React.RefObject<BlockedClipState | null>;
1596
+ suppressClickRef: React.RefObject<boolean>;
1597
+ scrollRef: React.RefObject<HTMLDivElement | null>;
1598
+ renderClipContent?: TimelineProps["renderClipContent"];
1599
+ renderClipOverlay?: TimelineProps["renderClipOverlay"];
1600
+ onDrillDown?: (element: TimelineElement) => void;
1601
+ onSelectElement?: (element: TimelineElement | null) => void;
1602
+ setHoveredClip: (key: string | null) => void;
1603
+ setShowPopover: (v: boolean) => void;
1604
+ setRangeSelection: (v: null) => void;
1605
+ setResizingClip: (v: ResizingClipState | null) => void;
1606
+ setDraggedClip: (v: DraggedClipState | null) => void;
1607
+ setSelectedElementId: (id: string | null) => void;
1608
+ getPreviewElement: (element: TimelineElement) => TimelineElement;
1609
+ getTrackStyle: (tag: string) => TrackVisualStyle;
1610
+ keyframeCache?: Map<string, KeyframeCacheEntry>;
1611
+ gsapAnimations: Map<string, GsapAnimation[]>;
1612
+ selectedKeyframes: Set<string>;
1613
+ currentTime: number;
1614
+ onSeek?: (time: number) => void;
1615
+ onSelectSegment?: (elementId: string, target: TimelineKeyframeTarget) => void;
1616
+ onClickKeyframe?: (element: TimelineElement, target: TimelineKeyframeTarget) => void;
1617
+ onShiftClickKeyframe?: (elementId: string, target: TimelineKeyframeTarget) => void;
1618
+ onContextMenuKeyframe?: (e: React.MouseEvent, elementId: string, target: TimelineKeyframeTarget) => void;
1619
+ onMoveKeyframe?: (elementId: string, keyframe: TimelineKeyframeTarget, toClipPercentage: number, propertyGroup?: string, tweenPercentage?: number, animationId?: string) => Promise<boolean>;
1620
+ onContextMenuClip?: (e: React.MouseEvent, element: TimelineElement) => void;
1621
+ /**
1622
+ * Right-click on EMPTY lane space (not on a clip — those preventDefault
1623
+ * before this fires — not the gutter/ruler, not below the lanes). `time` is
1624
+ * the timeline time (seconds) under the pointer on that lane.
1625
+ */
1626
+ onContextMenuLane?: (e: React.MouseEvent, track: number, time: number) => void;
1627
+ beatAnalysis?: MusicBeatAnalysis | null;
1628
+ /** Resolved audio groups, positioned in row order — see useTimelineTrackDerivations. */
1629
+ groups: readonly TimelineTrackGroupInfo[];
1630
+ }
1631
+
1632
+ /** An empty interval on the lane, [start, end) in seconds. */
1633
+ interface TrackGapInterval {
1634
+ start: number;
1635
+ end: number;
1636
+ }
1637
+
1638
+ /**
1639
+ * One lane's gap strips for the TimelineCanvas overlay.
1640
+ *
1641
+ * kind "hover" — the gap(s) a hovered "Close gap" / "Close all gaps" menu
1642
+ * row would collapse: the loud affordance.
1643
+ * kind "selected" — every empty interval on a click-selected clip's lane: the
1644
+ * quiet always-on hint (single click-selection only — a
1645
+ * marquee multi-select spans lanes and would paint noise).
1646
+ */
1647
+ interface TimelineLaneGapStrips {
1648
+ track: number;
1649
+ intervals: TrackGapInterval[];
1650
+ kind: "hover" | "selected";
1651
+ }
1652
+
1653
+ interface KeyframeDiamondContextMenuState {
1654
+ x: number;
1655
+ y: number;
1656
+ /** Timeline project session that created this portaled target. */
1657
+ sessionEpoch?: number;
1658
+ element: TimelineElement;
1659
+ elementId: string;
1660
+ percentage: number;
1661
+ tweenPercentage?: number;
1662
+ propertyGroup?: string;
1663
+ animationId?: string;
1664
+ currentEase?: string;
1665
+ }
1666
+
1667
+ type TimelineCanvasState = Omit<TimelineLaneBaseProps, "setRangeSelection" | "setResizingClip" | "setDraggedClip" | "renderClipContent" | "renderClipOverlay"> & {
1668
+ major: number[];
1669
+ minor: number[];
1670
+ totalH: number;
1671
+ effectiveDuration: number;
1672
+ majorTickInterval: number;
1673
+ rangeSelection: TimelineRangeSelection | null;
1674
+ marqueeRect: Rect$1 | null;
1675
+ resizingClip: ResizingClipState | null;
1676
+ isScrubbing: boolean;
1677
+ playheadRef: React.RefObject<HTMLDivElement | null>;
1678
+ laneGapStrips: TimelineLaneGapStrips[];
1679
+ dropPreview: TimelineDropPlacement | null;
1680
+ acceptsMediaDrop: boolean;
1681
+ setRangeSelection: (value: TimelineRangeSelection | null) => void;
1682
+ setResizingClip: (value: ResizingClipState | null) => void;
1683
+ setDraggedClip: (value: TimelineLaneBaseProps["draggedClip"]) => void;
1684
+ beatDragging: boolean;
1685
+ onResizeElement: TimelineEditCallbacks["onResizeElement"];
1686
+ onMoveElement: TimelineEditCallbacks["onMoveElement"];
1687
+ draggedElement: TimelineElement | null;
1688
+ snapGuide: TimelineSnapTarget | null;
1689
+ multiDragPreview: MultiDragPreviewInput | null;
1690
+ onToggleTrackHidden: TimelineEditCallbacks["onToggleTrackHidden"];
1691
+ onTogglePropertyGroupKeyframe: TimelineEditCallbacks["onTogglePropertyGroupKeyframe"];
1692
+ onRazorSplit: TimelineEditCallbacks["onRazorSplit"];
1693
+ onRazorSplitAll: TimelineEditCallbacks["onRazorSplitAll"];
1694
+ };
1695
+ interface ClipContextMenuState {
1696
+ x: number;
1697
+ y: number;
1698
+ element: TimelineElement;
1699
+ sessionEpoch: number;
1700
+ }
1701
+ interface TrackGapContextMenuState {
1702
+ x: number;
1703
+ y: number;
1704
+ gapWidth: number | null;
1705
+ canCloseGap: boolean;
1706
+ canCloseAllGaps: boolean;
1707
+ hasAnyGaps: boolean;
1708
+ }
1709
+ interface TimelineOverlaysState {
1710
+ elements: readonly TimelineElement[];
1711
+ elementsRef: {
1712
+ current: readonly TimelineElement[];
1713
+ };
1714
+ theme: TimelineTheme;
1715
+ showShortcutHint: boolean;
1716
+ showPopover: boolean;
1717
+ rangeSelection: TimelineRangeSelection | null;
1718
+ setShowPopover: (value: boolean) => void;
1719
+ setRangeSelection: (value: TimelineRangeSelection | null) => void;
1720
+ kfContextMenu: KeyframeDiamondContextMenuState | null;
1721
+ setKfContextMenu: (value: KeyframeDiamondContextMenuState | null) => void;
1722
+ onDeleteKeyframe: TimelineEditCallbacks["onDeleteKeyframe"];
1723
+ onDeleteAllKeyframes: TimelineEditCallbacks["onDeleteAllKeyframes"];
1724
+ onMoveKeyframeToPlayhead: TimelineEditCallbacks["onMoveKeyframeToPlayhead"];
1725
+ clipContextMenu: ClipContextMenuState | null;
1726
+ setClipContextMenu: (value: ClipContextMenuState | null) => void;
1727
+ currentTime: number;
1728
+ onSplitElement: TimelineEditCallbacks["onSplitElement"];
1729
+ pinZoomBeforeEdit: () => void;
1730
+ onDeleteElement?: (element: TimelineElement) => Promise<void> | void;
1731
+ onCopyClip?: () => boolean;
1732
+ onPasteClip?: () => Promise<void>;
1733
+ onDuplicateClip?: () => Promise<boolean>;
1734
+ canPasteClip?: () => boolean;
1735
+ clipMenuItems?: TimelineProps["clipMenuItems"];
1736
+ splitShortcut?: TimelineProps["splitShortcut"];
1737
+ gapContextMenu: TrackGapContextMenuState | null;
1738
+ onDismissGapContextMenu: () => void;
1739
+ onCloseTrackGap: () => void;
1740
+ onCloseAllTrackGaps: () => void;
1741
+ onHoverGapAction: (action: "close-gap" | "close-all" | null) => void;
1742
+ }
1743
+ interface TimelineContainerProps {
1744
+ ref: RefCallback<HTMLDivElement>;
1745
+ "aria-label": string;
1746
+ "data-timeline-element-count": number;
1747
+ className: string;
1748
+ onMouseMove: (event: MouseEvent<HTMLDivElement>) => void;
1749
+ onMouseLeave: () => void;
1750
+ style: CSSProperties;
1751
+ }
1752
+ interface TimelineViewportProps {
1753
+ ref: RefCallback<HTMLDivElement>;
1754
+ "data-timeline-scroll-viewport": boolean;
1755
+ "data-timeline-auto-scroll-left-inset": number;
1756
+ "data-timeline-content-origin": number;
1757
+ tabIndex: number;
1758
+ className: string;
1759
+ onScroll: (event: UIEvent<HTMLDivElement>) => void;
1760
+ onFocus: (event: React.FocusEvent<HTMLDivElement>) => void;
1761
+ onBlur: (event: React.FocusEvent<HTMLDivElement>) => void;
1762
+ onDragOver: (event: React.DragEvent<HTMLDivElement>) => void;
1763
+ onDragLeave: (event: React.DragEvent<HTMLDivElement>) => void;
1764
+ onDrop: (event: React.DragEvent<HTMLDivElement>) => void;
1765
+ onPointerDown: (event: PointerEvent<HTMLDivElement>) => void;
1766
+ onPointerMove: (event: PointerEvent<HTMLDivElement>) => void;
1767
+ onPointerUp: (event: PointerEvent<HTMLDivElement>) => void;
1768
+ onPointerCancel: (event: PointerEvent<HTMLDivElement>) => void;
1769
+ onLostPointerCapture: (event: PointerEvent<HTMLDivElement>) => void;
1770
+ }
1771
+ interface TimelineState {
1772
+ timelineReady: boolean;
1773
+ elements: readonly TimelineElement[];
1774
+ selectedElementId: string | null;
1775
+ sessionEpoch: number;
1776
+ keyframeCache: Map<string, KeyframeCacheEntry>;
1777
+ canvas: TimelineCanvasState;
1778
+ overlays: TimelineOverlaysState;
1779
+ }
1780
+ interface TimelineActions {
1781
+ renderClipContent: TimelineLaneBaseProps["renderClipContent"];
1782
+ renderClipOverlay: TimelineLaneBaseProps["renderClipOverlay"];
1783
+ setFocusedEaseSegment: (target: {
1784
+ animationId: string;
1785
+ collidingAnimationTargets?: AnimationKeyframeTarget[];
1786
+ tweenPercentage: number;
1787
+ elementId: string;
1788
+ }) => void;
1789
+ }
1790
+ interface TimelineMeta {
1791
+ emptyState: ComponentProps<typeof TimelineEmptyState>;
1792
+ containerProps: TimelineContainerProps;
1793
+ viewportProps: TimelineViewportProps;
1794
+ razorGuide: ReactNode;
1795
+ }
1796
+ interface TimelineContextValue {
1797
+ state: TimelineState;
1798
+ actions: TimelineActions;
1799
+ meta: TimelineMeta;
1800
+ }
1801
+ declare function TimelineProvider({ children, readOnly, onReadOnlyPress, ...props }: TimelineProps & {
1802
+ children: ReactNode;
1803
+ }): react_jsx_runtime.JSX.Element;
1804
+ declare function useTimelineContext(): TimelineContextValue;
1805
+
1806
+ declare function TimelineOverlays(): react_jsx_runtime.JSX.Element;
1807
+
1808
+ /** The provider-backed canvas shell. */
1809
+ declare function TimelineFrame(): react_jsx_runtime.JSX.Element;
1810
+ /** The provider-backed ruler. */
1811
+ declare const TimelineRuler: typeof TimelineRulerPart;
1812
+ /**
1813
+ * The provider-backed lane renderer. TimelineFrame remains the composed Studio
1814
+ * canvas; this part is exported for hosts that own the canvas arrangement.
1815
+ */
1816
+ declare function TimelineLanes(): react_jsx_runtime.JSX.Element;
1817
+ /** The provider-backed playhead indicator. */
1818
+ declare function TimelinePlayhead(): react_jsx_runtime.JSX.Element;
1819
+ /** The provider-backed razor guide. */
1820
+ declare function TimelineRazorGuide(): react.ReactNode;
1821
+
1822
+ declare function TimelineEmptyStatePart(): react_jsx_runtime.JSX.Element;
1823
+ declare function TimelineShortcutHint(): react_jsx_runtime.JSX.Element;
1824
+ declare function TimelineEditPopover(): react_jsx_runtime.JSX.Element;
1825
+ declare function TimelineClipMenu(): react_jsx_runtime.JSX.Element;
1826
+ declare function TimelineKeyframeMenu(): react_jsx_runtime.JSX.Element;
1827
+ declare function TimelineGapMenu(): react_jsx_runtime.JSX.Element;
1828
+
1829
+ declare const Timeline: react.NamedExoticComponent<TimelineProps> & {
1830
+ Provider: typeof TimelineProvider;
1831
+ Frame: typeof TimelineFrame;
1832
+ Ruler: typeof TimelineRulerPart;
1833
+ Lanes: typeof TimelineLanes;
1834
+ Playhead: typeof TimelinePlayhead;
1835
+ RazorGuide: typeof TimelineRazorGuide;
1836
+ ShortcutHint: typeof TimelineShortcutHint;
1837
+ EditPopover: typeof TimelineEditPopover;
1838
+ ClipMenu: typeof TimelineClipMenu;
1839
+ KeyframeMenu: typeof TimelineKeyframeMenu;
1840
+ GapMenu: typeof TimelineGapMenu;
1841
+ EmptyState: typeof TimelineEmptyStatePart;
1842
+ Overlays: typeof TimelineOverlays;
1843
+ };
1844
+
1845
+ type ThumbnailPriority = "overscan" | "visible" | "interaction";
1846
+
1847
+ interface VideoThumbnailProps {
1848
+ videoSrc: string;
1849
+ label: string;
1850
+ labelColor: string;
1851
+ duration?: number;
1852
+ sourceStart?: number;
1853
+ sourceRangeDuration?: number;
1854
+ projectId?: string;
1855
+ sessionEpoch?: number;
1856
+ priority?: ThumbnailPriority;
1857
+ }
1858
+ /** Sparse, bounded video frames supplied by the shared thumbnail scheduler. */
1859
+ declare const VideoThumbnail: react.NamedExoticComponent<VideoThumbnailProps>;
1860
+
1861
+ interface CompositionThumbnailProps {
1862
+ previewUrl: string;
1863
+ label: string;
1864
+ labelColor: string;
1865
+ selector?: string;
1866
+ selectorIndex?: number;
1867
+ seekTime?: number;
1868
+ duration?: number;
1869
+ width?: number;
1870
+ height?: number;
1871
+ projectId?: string;
1872
+ sessionEpoch?: number;
1873
+ contentRevision?: number;
1874
+ priority?: ThumbnailPriority;
1875
+ rich?: boolean;
1876
+ }
1877
+ /** Server-rendered composition poster, deduplicated and budgeted by project/session. */
1878
+ declare const CompositionThumbnail: react.NamedExoticComponent<CompositionThumbnailProps>;
1879
+
1880
+ /**
1881
+ * React callbacks for synchronising the player store from iframe runtime data.
1882
+ *
1883
+ * Covers four related concerns:
1884
+ * - processTimelineMessage — turn a clip-manifest postMessage into TimelineElements
1885
+ * - enrichMissingCompositions — fill gaps the manifest misses (element-ref starts)
1886
+ * - initializeAdapter — called after iframe load: seek, set duration, read elements
1887
+ * - onIframeLoad — orchestrates initializeAdapter with a message-based fallback
1888
+ */
1889
+
1890
+ type PreviewIframeRole = "live" | "shadow";
1891
+ interface PreviewIframeSlot {
1892
+ gen: number;
1893
+ role: PreviewIframeRole;
1894
+ url?: string;
1895
+ }
1896
+
1897
+ /**
1898
+ * Runtime iframe integration utilities.
1899
+ *
1900
+ * Handles the boundary between the studio host page and the preview iframe:
1901
+ * - Viewport normalisation on load
1902
+ * - Auto-healing missing data-composition-id attributes
1903
+ * - Unmuting media via postMessage
1904
+ * - Resolving the underlying <iframe> from any wrapper element
1905
+ * - Scanning the DOM for composition hosts the manifest missed
1906
+ * (element-reference starts that the CDN runtime fails to resolve)
1907
+ */
1908
+
1909
+ /**
1910
+ * Resolve the underlying iframe from any host element. Supports:
1911
+ * - Direct `<iframe>` element (most common — studio's own `Player.tsx`)
1912
+ * - Custom elements (e.g. `<hyperframes-player>`) whose shadow DOM contains an iframe
1913
+ * - Wrapper elements whose light DOM contains a descendant iframe
1914
+ *
1915
+ * Exported so web-component consumers can pre-resolve the iframe before
1916
+ * assigning it to `iframeRef` returned by `useTimelinePlayer`. Returns `null`
1917
+ * when the element has no associated iframe yet.
1918
+ *
1919
+ * @example
1920
+ * ```tsx
1921
+ * const { iframeRef } = useTimelinePlayer();
1922
+ * const playerElRef = useRef<HyperframesPlayer>(null);
1923
+ *
1924
+ * useEffect(() => {
1925
+ * iframeRef.current = resolveIframe(playerElRef.current);
1926
+ * }, [iframeRef]);
1927
+ * ```
1928
+ */
1929
+ declare function resolveIframe(el: Element | null): HTMLIFrameElement | null;
1930
+
1931
+ interface UseTimelinePlayerOptions {
1932
+ /** Runs right after a reloaded preview becomes the live iframe. */
1933
+ onShadowPromoted?: () => void;
1934
+ /** A reload was abandoned (cause in the message); the previous preview is still showing. */
1935
+ onPreviewReloadFailed?: (message: string) => void;
1936
+ }
1937
+ declare function useTimelinePlayer({ onShadowPromoted, onPreviewReloadFailed, }?: UseTimelinePlayerOptions): {
1938
+ iframeRef: react.RefObject<HTMLIFrameElement | null>;
1939
+ play: () => void;
1940
+ pause: () => void;
1941
+ togglePlay: () => void;
1942
+ seek: (time: number, options?: {
1943
+ keepPlaying?: boolean;
1944
+ follow?: boolean;
1945
+ }) => boolean;
1946
+ onIframeLoad: (context?: number) => void;
1947
+ refreshPlayer: () => void;
1948
+ saveSeekPosition: () => boolean;
1949
+ resetPlayer: () => void;
1950
+ previewSlots: PreviewIframeSlot[];
1951
+ onShadowIframeLoad: (context?: number) => void;
1952
+ onShadowReadyChange: (gen: number, ready: boolean) => void;
1953
+ onShadowError: (gen: number, cause: string) => void;
1954
+ setShadowIframeNode: (node: HTMLIFrameElement | null) => void;
1955
+ resetPreviewSlots: () => void;
1956
+ };
1957
+
1958
+ interface PlayerHandleElement {
1959
+ id: string;
1960
+ start: number;
1961
+ end: number;
1962
+ selector?: string;
1963
+ sourceFile?: string;
1964
+ compositionSrc?: string;
1965
+ }
1966
+ type PlayerHandleListener = () => void;
1967
+ type PlayerHandleTimeListener = (time: number) => void;
1968
+ interface PlayerHandle {
1969
+ ready: boolean;
1970
+ playing: boolean;
1971
+ seek: (seconds: number) => boolean;
1972
+ play: () => void;
1973
+ pause: () => void;
1974
+ togglePlay: () => void;
1975
+ readonly currentTime: number;
1976
+ duration: number;
1977
+ elements: PlayerHandleElement[];
1978
+ subscribe: (listener: PlayerHandleListener) => () => void;
1979
+ subscribeTime: (listener: PlayerHandleTimeListener) => () => void;
1980
+ }
1981
+ /**
1982
+ * Reads and controls the shell player. Call this under EditorShell/NLEProvider;
1983
+ * the provider owns the mounted preview iframe and the single player instance.
1984
+ */
1985
+ declare function usePlayerHandle(): PlayerHandle;
1986
+
1987
+ declare function formatTime(time: number): string;
1988
+
1989
+ /** A host's verdict on one element: editable, or blocked with a reason to show. */
1990
+ type TimelineEditPermission = true | {
1991
+ blocked: true;
1992
+ reason: string;
1993
+ };
1994
+ type CanEditTimelineElement = (element: TimelineElement) => TimelineEditPermission;
1995
+ /** What an effect save did: landed, refused before writing, or failed while writing. */
1996
+ type TimelineEditOutcome = {
1997
+ status: "saved";
1998
+ } | {
1999
+ status: "refused" | "failed";
2000
+ reason: string;
2001
+ };
2002
+
2003
+ interface TimelineEditCallbackDeps {
2004
+ handleTimelineElementMove: (element: TimelineElement, updates: Pick<TimelineElement, "start" | "track">) => Promise<void> | void;
2005
+ handleTimelineElementsMove: (edits: Array<{
2006
+ element: TimelineElement;
2007
+ updates: Pick<TimelineElement, "start" | "track">;
2008
+ }>, coalesceKey?: string, operation?: TimelineMoveOperation) => Promise<void> | void;
2009
+ handleTimelineElementResize: (element: TimelineElement, updates: Pick<TimelineElement, "start" | "duration" | "playbackStart">) => Promise<void> | void;
2010
+ handleTimelineGroupResize: NonNullable<TimelineEditCallbacks["onResizeElements"]>;
2011
+ handleToggleTrackHidden: (track: number, hidden: boolean) => Promise<void> | void;
2012
+ setAudioGroupAttribute: {
2013
+ setLive: (groupId: string, attr: string, value: string | null) => void;
2014
+ revertLive?: (groupId: string, attr: string) => void;
2015
+ setQuiet: (groupId: string, attr: string, value: string | null, label: string) => Promise<TimelineEditOutcome | void>;
2016
+ };
2017
+ handleBlockedTimelineEdit: (element: TimelineElement, intent: BlockedTimelineEditIntent) => void;
2018
+ handleTimelineElementSplit: (element: TimelineElement, splitTime: number) => Promise<void> | void;
2019
+ handleRazorSplit: (element: TimelineElement, splitTime: number) => Promise<void> | void;
2020
+ handleRazorSplitAll: (splitTime: number) => Promise<void> | void;
2021
+ handleFreezeFrame?: (element: TimelineElement, time: number) => Promise<void> | void;
2022
+ handleLinkEdit?: TimelineEditCallbacks["onLinkEdit"];
2023
+ handleTimelineElementDeleteOnly?: TimelineEditCallbacks["onDeleteElementOnly"];
2024
+ /** C1's ungrouped-track FX pointer — same auto-grouping write B6's carve uses. */
2025
+ handleGroupClips?: (clipIds: readonly string[], groupId: string, groupLabel?: string) => Promise<void>;
2026
+ /** C1's single-clip FX write, addressed by the clip itself. */
2027
+ setElementFxAttribute?: {
2028
+ setLive: (element: TimelineElement, attr: string, value: string | null) => void;
2029
+ revertLive?: (element: TimelineElement, attr: string) => void;
2030
+ setQuiet: (element: TimelineElement, attr: string, value: string | null, label: string) => Promise<TimelineEditOutcome | void>;
2031
+ setMany?: TimelineEditCallbacks["onSetElementsAttributeQuiet"];
2032
+ };
2033
+ }
2034
+
2035
+ interface BlockPreviewInfo {
2036
+ videoUrl?: string;
2037
+ posterUrl?: string;
2038
+ title: string;
2039
+ }
2040
+
2041
+ type GestureRecordingState = "idle" | "recording" | "preview";
2042
+
2043
+ type RenderClipContent = (element: TimelineElement, style: {
2044
+ clip: string;
2045
+ label: string;
2046
+ }) => ReactNode;
2047
+ interface EditorShellProps extends TimelineEditCallbackDeps {
2048
+ /** Dock.Panel elements for every panel except the built-in preview and timeline. */
2049
+ panels: ReactNode;
2050
+ timelineToolbar: ReactNode;
2051
+ renderClipContent: RenderClipContent;
2052
+ handleTimelineElementDelete: (element: TimelineElement) => Promise<void> | void;
2053
+ handleTimelineAssetDrop: (assetPath: string, placement: TimelineDropPlacement) => Promise<void> | void;
2054
+ handleTimelineBlockDrop?: (blockName: string, placement: TimelineDropPlacement) => Promise<void> | void;
2055
+ handleTimelineCompositionDrop?: (sourcePath: string, placement: TimelineDropPlacement) => Promise<void> | void;
2056
+ handlePreviewBlockDrop?: (blockName: string, position: {
2057
+ left: number;
2058
+ top: number;
2059
+ }) => Promise<void> | void;
2060
+ handleTimelineFileDrop: (files: File[], placement?: TimelineDropPlacement) => Promise<void> | void;
2061
+ onCopyClip: () => boolean;
2062
+ onPasteClip: () => Promise<void>;
2063
+ onDuplicateClip: () => Promise<boolean>;
2064
+ canPasteClip: () => boolean;
2065
+ clipMenuItems?: TimelineProps["clipMenuItems"];
2066
+ splitShortcut?: TimelineProps["splitShortcut"];
2067
+ setCompIdToSrc: (map: Map<string, string>) => void;
2068
+ setCompositionLoading: (loading: boolean) => void;
2069
+ shouldShowMotionPath: boolean;
2070
+ shouldShowSelectedDomBounds: boolean;
2071
+ blockPreview?: BlockPreviewInfo | null;
2072
+ isGestureRecording?: boolean;
2073
+ recordingState?: GestureRecordingState;
2074
+ onToggleRecording?: () => void;
2075
+ /**
2076
+ * Host layer over the preview, positioned with `usePreviewCompositionRect`. Hidden in
2077
+ * fullscreen and during a block preview; below the selection overlay past z-index 10.
2078
+ */
2079
+ gestureOverlay?: ReactNode;
2080
+ /** Clicks still select and report; the preview cannot move, edit or delete anything. */
2081
+ readOnlyPreview?: boolean;
2082
+ /** Short text shown on disabled hand-edit controls while `readOnlyPreview` is set. */
2083
+ readOnlyPreviewReason?: string;
2084
+ }
2085
+ declare const EditorShell: react.NamedExoticComponent<EditorShellProps>;
2086
+
2087
+ interface PreviewCompositionSize {
2088
+ width: number;
2089
+ height: number;
2090
+ }
2091
+
2092
+ interface CompositionLevel {
2093
+ /** Unique id — "master" or composition file path */
2094
+ id: string;
2095
+ /** Display label — "Master" or filename without extension */
2096
+ label: string;
2097
+ /** Preview URL for this composition level */
2098
+ previewUrl: string;
2099
+ }
2100
+ interface CompositionBreadcrumbProps {
2101
+ stack: CompositionLevel[];
2102
+ onNavigate: (index: number) => void;
2103
+ }
2104
+ declare function CompositionBreadcrumb({ stack, onNavigate }: CompositionBreadcrumbProps): react_jsx_runtime.JSX.Element | null;
2105
+
2106
+ interface NLEContextValue {
2107
+ projectId: string;
2108
+ iframeRef: React.MutableRefObject<HTMLIFrameElement | null>;
2109
+ play: () => void;
2110
+ pause: () => void;
2111
+ togglePlay: () => void;
2112
+ seek: (time: number, options?: {
2113
+ keepPlaying?: boolean;
2114
+ follow?: boolean;
2115
+ }) => boolean;
2116
+ refreshPlayer: () => void;
2117
+ onIframeLoad: () => void;
2118
+ previewSlots: PreviewIframeSlot[];
2119
+ onShadowIframeLoad: (gen: number) => void;
2120
+ onShadowReadyChange: (gen: number, ready: boolean) => void;
2121
+ onShadowError: (gen: number, message: string) => void;
2122
+ setShadowIframeNode: (node: HTMLIFrameElement | null) => void;
2123
+ resetPreviewSlots: () => void;
2124
+ containerRef: React.MutableRefObject<HTMLDivElement | null>;
2125
+ compositionStack: CompositionLevel[];
2126
+ updateCompositionStack: React.Dispatch<React.SetStateAction<CompositionLevel[]>>;
2127
+ handleNavigateComposition: (index: number) => void;
2128
+ handleDrillDown: (element: TimelineElement) => void;
2129
+ compIdToSrc: Map<string, string>;
2130
+ compositionLoading: boolean;
2131
+ setCompositionLoading: (loading: boolean) => void;
2132
+ timelineDisabled: boolean;
2133
+ timelineSessionEpoch: number;
2134
+ hasLoadedOnceRef: React.MutableRefObject<boolean>;
2135
+ previewCompositionSize: {
2136
+ width: number;
2137
+ height: number;
2138
+ } | null;
2139
+ setPreviewCompositionSize: (size: {
2140
+ width: number;
2141
+ height: number;
2142
+ } | null) => void;
2143
+ }
2144
+
2145
+ interface NLEPreviewProps extends Pick<NLEContextValue, "projectId" | "onIframeLoad" | "previewSlots" | "onShadowIframeLoad" | "onShadowReadyChange" | "onShadowError" | "setShadowIframeNode" | "resetPreviewSlots"> {
2146
+ iframeRef: RefObject<HTMLIFrameElement | null>;
2147
+ onCompositionLoadingChange?: (loading: boolean) => void;
2148
+ portrait?: boolean;
2149
+ directUrl?: string;
2150
+ suppressLoadingOverlay?: boolean;
2151
+ onStageRef?: (ref: React.RefObject<HTMLDivElement | null>) => void;
2152
+ /** Reports the authored composition size measured from the loaded preview. */
2153
+ onCompositionSizeChange?: (size: PreviewCompositionSize | null) => void;
2154
+ /** Draws the picture edge to edge in this box, without Studio's inset band. */
2155
+ fillBox?: boolean;
2156
+ }
2157
+ declare const NLEPreview: react.NamedExoticComponent<NLEPreviewProps>;
2158
+
2159
+ interface ShortcutsButtonProps {
2160
+ sections?: readonly ShortcutSection[];
2161
+ disabled?: boolean;
2162
+ onSeek?: (time: number) => void;
2163
+ }
2164
+ declare function ShortcutsButton({ sections, disabled, onSeek }: ShortcutsButtonProps): react_jsx_runtime.JSX.Element;
2165
+
2166
+ interface LinkShortcutCallbacks {
2167
+ handleLinkEdit?: TimelineEditCallbacks["onLinkEdit"];
2168
+ handleTimelineElementDeleteOnly?: TimelineEditCallbacks["onDeleteElementOnly"];
2169
+ }
2170
+ /** ⌘L unlink/link, ⌥⇧D detach audio, ⌥⌫ delete one linked clip — the clip menu's shortcuts. */
2171
+ declare function dispatchLinkShortcut(event: KeyboardEvent, cb: LinkShortcutCallbacks): boolean;
2172
+
2173
+ interface UseCompositionStackOptions {
2174
+ projectId: string;
2175
+ activeCompositionPath?: string | null;
2176
+ onCompositionChange?: (compositionPath: string | null) => void;
2177
+ }
2178
+ interface UseCompositionStackResult {
2179
+ compositionStack: CompositionLevel[];
2180
+ updateCompositionStack: React.Dispatch<React.SetStateAction<CompositionLevel[]>>;
2181
+ handleNavigateComposition: (index: number) => void;
2182
+ handleDrillDown: (element: {
2183
+ id: string;
2184
+ compositionSrc?: string;
2185
+ }) => void;
2186
+ masterSeekRef: React.MutableRefObject<number>;
2187
+ compIdToSrc: Map<string, string>;
2188
+ setCompIdToSrc: React.Dispatch<React.SetStateAction<Map<string, string>>>;
2189
+ }
2190
+ declare function useCompositionStack({ projectId, activeCompositionPath, onCompositionChange, }: UseCompositionStackOptions): UseCompositionStackResult;
2191
+
2192
+ declare const PANEL_IDS: readonly ["preview", "timeline", "compositions", "assets", "code", "catalog", "design", "layers", "renders", "variables", "slideshow"];
2193
+ type PanelId = (typeof PANEL_IDS)[number];
2194
+ type PanelZone = "left" | "center" | "right";
2195
+
2196
+ declare function Root({ projectId, panels, storageKey, dockWidth, children, }: {
2197
+ projectId: string | null;
2198
+ panels?: readonly PanelId[];
2199
+ storageKey?: string;
2200
+ dockWidth?: () => number;
2201
+ children: ReactNode;
2202
+ }): react_jsx_runtime.JSX.Element;
2203
+ declare function Panel({ id, title, children }: {
2204
+ id: PanelId;
2205
+ title?: string;
2206
+ children: ReactNode;
2207
+ }): react.ReactPortal | null;
2208
+ declare function WindowMenu(): react_jsx_runtime.JSX.Element;
2209
+ declare const Dock: {
2210
+ Root: typeof Root;
2211
+ Panel: typeof Panel;
2212
+ WindowMenu: typeof WindowMenu;
2213
+ };
2214
+
2215
+ /** The narrow surface Dock.Root exposes; dockview types never leave the dock folder. */
2216
+ interface DockController {
2217
+ /** Adds the panel at its default place if it is closed; never moves focus. */
2218
+ open: (id: PanelId) => void;
2219
+ /** Focuses the panel, reopening it at its default place if it was closed. */
2220
+ activate: (id: PanelId) => void;
2221
+ setTitle: (id: PanelId, title: string) => void;
2222
+ close: (id: PanelId) => void;
2223
+ /** Hides or shows the panel's whole tab group without closing it. */
2224
+ setGroupVisible: (id: PanelId, visible: boolean) => void;
2225
+ reset: () => void;
2226
+ }
2227
+ interface DockSnapshot {
2228
+ openPanels: ReadonlySet<PanelId>;
2229
+ /** Open panels whose tab is showing and whose group is not hidden. */
2230
+ visiblePanels: ReadonlySet<PanelId>;
2231
+ activePanel: PanelId | null;
2232
+ /** The tab each group shows, so a restored layout still records what every side column last showed. */
2233
+ groupActivePanels?: readonly PanelId[];
2234
+ }
2235
+ type LastActive = Partial<Record<PanelZone, PanelId>>;
2236
+ interface DockLayoutState extends DockSnapshot {
2237
+ controller: DockController | null;
2238
+ panels: readonly PanelId[];
2239
+ lastActive: LastActive;
2240
+ /** An activation requested before the dock mounted; Dock.Root applies it on ready. */
2241
+ pendingActivation: PanelId | null;
2242
+ attach: (controller: DockController, panels?: readonly PanelId[]) => void;
2243
+ detach: () => void;
2244
+ sync: (snapshot: DockSnapshot) => void;
2245
+ takePendingActivation: () => PanelId | null;
2246
+ activatePanel: (id: PanelId) => void;
2247
+ closePanel: (id: PanelId) => void;
2248
+ togglePanel: (id: PanelId) => void;
2249
+ setZoneVisible: (zone: PanelZone, visible: boolean) => void;
2250
+ resetLayout: () => void;
2251
+ }
2252
+ declare const useDockLayoutStore: zustand.UseBoundStore<zustand.StoreApi<DockLayoutState>>;
2253
+
2254
+ interface PreviewIframeState {
2255
+ iframe: HTMLIFrameElement | null;
2256
+ setIframe: (iframe: HTMLIFrameElement | null) => void;
2257
+ }
2258
+ /** The one owner of "the live preview iframe element"; a promoted reload replaces it. */
2259
+ declare const usePreviewIframeStore: zustand.UseBoundStore<zustand.StoreApi<PreviewIframeState>>;
2260
+
2261
+ interface AudioGainDialogState {
2262
+ targetKeys: readonly string[] | null;
2263
+ open: (keys: readonly string[]) => void;
2264
+ close: () => void;
2265
+ }
2266
+ /** Which clips the Audio Gain dialog (G) is open for. */
2267
+ declare const useAudioGainDialogStore: zustand.UseBoundStore<zustand.StoreApi<AudioGainDialogState>>;
2268
+ /** Open Audio Gain for the selection (or the clicked clip); false when none of it has sound. */
2269
+ declare function openAudioGainDialog(clicked?: TimelineElement): boolean;
2270
+
2271
+ type FadeEdge = "in" | "out";
2272
+ /** The clip as drawn; `toolsLeft` is where its FX badge starts, null when it has none. */
2273
+ interface FadeHandleClipBox {
2274
+ width: number;
2275
+ height: number;
2276
+ radius: number;
2277
+ toolsLeft: number | null;
2278
+ }
2279
+ /** A fade handle's hit box in px from the clip's top left; `tabLeft` is its tab's centre within it. */
2280
+ interface FadeHandleBox {
2281
+ left: number;
2282
+ width: number;
2283
+ height: number;
2284
+ tabLeft: number;
2285
+ top: number;
2286
+ }
2287
+ /**
2288
+ * Where the fade handles sit on a clip `widthPx` wide: each centred on its fade's end, inside the
2289
+ * clip and left of its tools; two drawn handles that would overlap split at the midpoint.
2290
+ */
2291
+ declare function fadeHandleBoxes(input: {
2292
+ widthPx: number;
2293
+ inPx: number;
2294
+ outPx: number;
2295
+ clipBox: FadeHandleClipBox;
2296
+ drawn: Record<FadeEdge, boolean>;
2297
+ }): Record<FadeEdge, FadeHandleBox>;
2298
+
2299
+ interface AudioWaveformProps {
2300
+ audioUrl: string;
2301
+ waveformUrl?: string;
2302
+ label: string;
2303
+ labelColor: string;
2304
+ trimStartFraction?: number;
2305
+ trimEndFraction?: number;
2306
+ projectId: string;
2307
+ sessionEpoch: number;
2308
+ priority: ThumbnailPriority;
2309
+ /** `data-hidden` or a muted audio group. Greys the pill; the clip stays. */
2310
+ muted?: boolean;
2311
+ labelInset?: number;
2312
+ }
2313
+ /** Bounded waveform subscriber; cache, cancellation and dedupe live in one scheduler. */
2314
+ declare const AudioWaveform: react.NamedExoticComponent<AudioWaveformProps>;
2315
+
2316
+ interface ImageThumbnailProps {
2317
+ imageSrc: string;
2318
+ label: string;
2319
+ labelColor: string;
2320
+ projectId?: string;
2321
+ sessionEpoch?: number;
2322
+ priority?: ThumbnailPriority;
2323
+ rich?: boolean;
2324
+ }
2325
+ /** A scheduler-backed still-image strip. Mounting is the sole work trigger. */
2326
+ declare const ImageThumbnail: react.NamedExoticComponent<ImageThumbnailProps>;
2327
+
2328
+ interface UseRenderClipContentOptions {
2329
+ projectIdRef: {
2330
+ current: string | null;
2331
+ };
2332
+ compIdToSrc: Map<string, string>;
2333
+ activePreviewUrl: string | null;
2334
+ effectiveTimelineDuration: number;
2335
+ }
2336
+ declare function useRenderClipContent({ projectIdRef, compIdToSrc, activePreviewUrl, effectiveTimelineDuration, }: UseRenderClipContentOptions): (el: TimelineElement, style: {
2337
+ clip: string;
2338
+ label: string;
2339
+ }, context?: TimelineClipRenderContext) => ReactNode;
2340
+
2341
+ interface UseThumbnailStillOptions {
2342
+ sessionEpoch?: number;
2343
+ priority?: ThumbnailPriority;
2344
+ }
2345
+ type ThumbnailStill = {
2346
+ status: "loading";
2347
+ } | {
2348
+ status: "ready";
2349
+ url: string;
2350
+ } | {
2351
+ status: "failed";
2352
+ };
2353
+ /** A host picture's server still through the thumbnail scheduler, so it yields to a preview reload. */
2354
+ declare function useThumbnailStill(url: string | null, projectId: string, { sessionEpoch, priority }?: UseThumbnailStillOptions): ThumbnailStill;
2355
+
2356
+ interface DomEditCompositionRect {
2357
+ left: number;
2358
+ top: number;
2359
+ width: number;
2360
+ height: number;
2361
+ scaleX: number;
2362
+ scaleY: number;
2363
+ }
2364
+
2365
+ /**
2366
+ * Where the composition sits inside `overlayRef`, in overlay pixels, plus the scale from
2367
+ * composition units to pixels.
2368
+ */
2369
+ declare function usePreviewCompositionRect(overlayRef: RefObject<HTMLDivElement | null>, iframe: HTMLIFrameElement | null): DomEditCompositionRect;
2370
+
2371
+ interface PreviewSnapPreferences {
2372
+ snapEnabled: boolean;
2373
+ gridVisible: boolean;
2374
+ gridSpacing: number;
2375
+ snapToGrid: boolean;
2376
+ }
2377
+ interface PreviewOverlayContextValue {
2378
+ state: {
2379
+ snapPrefs: PreviewSnapPreferences;
2380
+ rulerVisible: boolean;
2381
+ safeMarginsVisible: boolean;
2382
+ iframeRef: RefObject<HTMLIFrameElement | null>;
2383
+ compositionRect: DomEditCompositionRect;
2384
+ };
2385
+ actions: {
2386
+ setSnapPrefs: (patch: Partial<PreviewSnapPreferences>) => void;
2387
+ toggleRulers: () => void;
2388
+ toggleSafeMargins: () => void;
2389
+ };
2390
+ }
2391
+ interface PreviewOverlayProviderProps {
2392
+ iframe?: HTMLIFrameElement | null;
2393
+ children: ReactNode;
2394
+ }
2395
+ declare function PreviewOverlayProvider({ iframe, children }: PreviewOverlayProviderProps): react_jsx_runtime.JSX.Element;
2396
+ declare function usePreviewOverlayContext(): PreviewOverlayContextValue;
2397
+
2398
+ /** Ruler and safe-margin boxes drawn over the preview pane, never inside the composition. */
2399
+ declare const PreviewGuides: react.NamedExoticComponent<object>;
2400
+
2401
+ declare const GridOverlay: react.NamedExoticComponent<object>;
2402
+
2403
+ declare const SnapToolbar: react.NamedExoticComponent<object>;
2404
+
2405
+ type GuideKey = "rulerVisible" | "safeMarginsVisible";
2406
+ interface PreviewGuidesState {
2407
+ rulerVisible: boolean;
2408
+ safeMarginsVisible: boolean;
2409
+ toggle: (key: GuideKey) => void;
2410
+ }
2411
+ declare const usePreviewGuidesStore: zustand.UseBoundStore<zustand.StoreApi<PreviewGuidesState>>;
2412
+
2413
+ interface SourceEditorProps {
2414
+ content: string;
2415
+ filePath?: string;
2416
+ language?: string;
2417
+ onChange?: (content: string) => void;
2418
+ readOnly?: boolean;
2419
+ revealOffset?: number | null;
2420
+ }
2421
+ declare const SourceEditor: react.NamedExoticComponent<SourceEditorProps>;
2422
+
2423
+ interface GeometryCommitResult {
2424
+ ok: true;
2425
+ changed: boolean;
2426
+ }
2427
+
2428
+ /**
2429
+ * Edit callbacks shared by GsapAnimationSection and each AnimationCard it
2430
+ * renders. Extracted so the two prop interfaces don't duplicate the (large)
2431
+ * signatures the section forwards straight through to the card.
2432
+ */
2433
+ interface GsapAnimationEditCallbacks {
2434
+ onUpdateProperty: (animationId: string, property: string, value: number | string) => void;
2435
+ onUpdateMeta: (animationId: string, updates: {
2436
+ duration?: number;
2437
+ ease?: string;
2438
+ position?: number;
2439
+ }) => void;
2440
+ onDeleteAnimation: (animationId: string) => void;
2441
+ onAddProperty: (animationId: string, property: string) => void;
2442
+ onRemoveProperty: (animationId: string, property: string) => void;
2443
+ onUpdateFromProperty?: (animationId: string, property: string, value: number | string) => void;
2444
+ onAddFromProperty?: (animationId: string, property: string) => void;
2445
+ onRemoveFromProperty?: (animationId: string, property: string) => void;
2446
+ onLivePreview?: (property: string, value: number | string) => void;
2447
+ onLivePreviewEnd?: () => void;
2448
+ onSetArcPath?: (animationId: string, config: {
2449
+ enabled: boolean;
2450
+ autoRotate?: boolean | number;
2451
+ segments?: ArcPathSegment[];
2452
+ }) => void;
2453
+ onUpdateArcSegment?: (animationId: string, segmentIndex: number, update: Partial<ArcPathSegment>) => void;
2454
+ onUpdateKeyframeEase?: (animationId: string, percentage: number, ease: string) => void;
2455
+ onUpdateSegmentEase?: (targets: AnimationKeyframeTarget[], ease: string) => void;
2456
+ /** Apply one ease to every keyframe segment at once (clears per-segment overrides). */
2457
+ onSetAllKeyframeEases?: (animationId: string, ease: string) => void;
2458
+ /** Unroll a computed (helper/loop) tween into literal tweens so it edits directly. */
2459
+ onUnroll?: (animationId: string) => void;
2460
+ }
2461
+
2462
+ interface BackgroundRemovalProgress {
2463
+ status: "processing" | "complete" | "failed";
2464
+ progress: number;
2465
+ stage?: string;
2466
+ outputPath?: string;
2467
+ backgroundOutputPath?: string;
2468
+ error?: string;
2469
+ provider?: string;
2470
+ }
2471
+ interface BackgroundRemovalResult {
2472
+ outputPath: string;
2473
+ backgroundOutputPath?: string;
2474
+ provider?: string;
2475
+ }
2476
+ interface MediaOverlayPlacement {
2477
+ start: number;
2478
+ duration?: number;
2479
+ track?: number;
2480
+ compositionPath?: string;
2481
+ }
2482
+ type AddMediaOverlayHandler = (blockName: string, placement: MediaOverlayPlacement) => Promise<void>;
2483
+ interface PropertyPanelProps {
2484
+ projectId: string;
2485
+ projectDir: string | null;
2486
+ assets: string[];
2487
+ element: DomEditSelection | null;
2488
+ multiSelectCount?: number;
2489
+ multiSelectedElements?: DomEditSelection[];
2490
+ onGroupSelection?: () => void;
2491
+ onHideAllSelected?: () => void;
2492
+ copiedAgentPrompt: boolean;
2493
+ onClearSelection: () => void;
2494
+ onUngroup?: () => void;
2495
+ onSetStyle: (prop: string, value: string) => void | Promise<unknown>;
2496
+ onPreviewStyle?: (prop: string, value: string) => void;
2497
+ onSetAttribute: (attr: string, value: string) => void | Promise<void>;
2498
+ /** Commits several data-* attributes on the SAME element in ONE atomic
2499
+ * persist call — e.g. a pinned timing range's start+duration together, so
2500
+ * a selection change or a partial failure mid-commit can't misdirect one
2501
+ * of the two writes or leave them half-applied. Falls back to sequential
2502
+ * `onSetAttribute` calls where omitted. */
2503
+ onSetAttributes?: (selection: DomEditSelection, attrs: Record<string, string>) => Promise<void>;
2504
+ onSetAttributeLive: (attr: string, value: string | null, onSettled?: (ok: boolean) => void) => void | Promise<void>;
2505
+ /** Persists without reloading the preview, but re-reads the selection after —
2506
+ * for attributes the runtime applies to the live graph itself, where a reload
2507
+ * would only interrupt playback, and where the panel still has to see the
2508
+ * value it just wrote to compute the next edit from. */
2509
+ onSetAttributeQuiet?: (attr: string, value: string | null) => void | Promise<void>;
2510
+ onApplyColorGradingScope?: (scope: "source-file" | "project", value: string | null) => Promise<{
2511
+ changedFiles: number;
2512
+ changedElements: number;
2513
+ }>;
2514
+ onSetHtmlAttribute: (attr: string, value: string | null) => void | Promise<void>;
2515
+ onSetAttributeBatch: CommitDomAttributeBatch;
2516
+ onRemoveBackground?: (inputPath: string, options: {
2517
+ createBackgroundPlate?: boolean;
2518
+ quality?: "fast" | "balanced" | "best";
2519
+ onProgress?: (progress: BackgroundRemovalProgress) => void;
2520
+ }) => Promise<BackgroundRemovalResult>;
2521
+ onSetManualOffset: (element: DomEditSelection, next: {
2522
+ x: number;
2523
+ y: number;
2524
+ }, route?: {
2525
+ plainTranslate: boolean;
2526
+ }) => void | Promise<void | GeometryCommitResult>;
2527
+ onSetManualSize: (element: DomEditSelection, next: {
2528
+ width: number;
2529
+ height: number;
2530
+ }) => void | Promise<void | GeometryCommitResult>;
2531
+ onSetManualRotation: (element: DomEditSelection, next: {
2532
+ angle: number;
2533
+ }) => void | Promise<void | GeometryCommitResult>;
2534
+ onSetText: (value: string, fieldKey?: string) => void;
2535
+ onSetTextFieldStyle: (fieldKey: string, property: string, value: string) => void;
2536
+ onPreviewTextFieldStyle?: (fieldKey: string, property: string, value: string) => void;
2537
+ onAddTextField: (afterFieldKey?: string) => string | Promise<string | null> | null;
2538
+ onRemoveTextField: (fieldKey: string) => void;
2539
+ onAskAgent: () => void;
2540
+ onToggleElementHidden?: (elementKey: string, hidden: boolean) => void | Promise<void>;
2541
+ /** B6: group two or more picked voice clips, atomically, one undo entry. */
2542
+ onAutoGroupCarveSources?: (clipIds: readonly string[], groupId: string) => Promise<void>;
2543
+ onImportAssets?: (files: FileList, dir?: string) => Promise<string[]>;
2544
+ onAddMediaOverlay?: AddMediaOverlayHandler;
2545
+ fontAssets?: ImportedFontAsset[];
2546
+ onImportFonts?: (files: FileList | File[]) => Promise<ImportedFontAsset[]>;
2547
+ previewIframeRef?: RefObject<HTMLIFrameElement | null>;
2548
+ gsapAnimations?: GsapAnimation$1[];
2549
+ gsapMultipleTimelines?: boolean;
2550
+ gsapUnsupportedTimelinePattern?: boolean;
2551
+ onUpdateGsapProperty?: (animId: string, prop: string, value: number | string) => void;
2552
+ onUpdateGsapMeta?: (animId: string, updates: {
2553
+ duration?: number;
2554
+ ease?: string;
2555
+ position?: number;
2556
+ }) => void;
2557
+ onDeleteGsapAnimation?: (animId: string) => void;
2558
+ onAddGsapProperty?: (animId: string, prop: string) => void;
2559
+ onRemoveGsapProperty?: (animId: string, prop: string) => void;
2560
+ onUpdateGsapFromProperty?: (animId: string, prop: string, value: number | string) => void;
2561
+ onAddGsapFromProperty?: (animId: string, prop: string) => void;
2562
+ onRemoveGsapFromProperty?: (animId: string, prop: string) => void;
2563
+ onAddGsapAnimation?: (method: "to" | "from" | "set" | "fromTo") => void;
2564
+ onSetArcPath?: (animId: string, config: {
2565
+ enabled: boolean;
2566
+ autoRotate?: boolean | number;
2567
+ segments?: ArcPathSegment[];
2568
+ }) => void;
2569
+ onUpdateArcSegment?: (animId: string, segmentIndex: number, update: Partial<ArcPathSegment>) => void;
2570
+ onUnroll?: (animationId: string) => void;
2571
+ onAddKeyframe?: (animationId: string, percentage: number, property: string, value: number | string) => void;
2572
+ onRemoveKeyframe?: (animationId: string, percentage: number) => void;
2573
+ onUpdateKeyframeEase?: (animationId: string, percentage: number, ease: string) => void;
2574
+ onUpdateSegmentEase?: NonNullable<GsapAnimationEditCallbacks["onUpdateSegmentEase"]>;
2575
+ onSetAllKeyframeEases?: (animationId: string, ease: string) => void;
2576
+ onConvertToKeyframes?: (animationId: string, duration?: number) => void;
2577
+ onCommitAnimatedProperty?: (selection: DomEditSelection, property: string, value: number | string) => Promise<void>;
2578
+ onCommitAnimatedProperties?: (selection: DomEditSelection, props: Record<string, number | string>) => Promise<void>;
2579
+ onSeekToTime?: (time: number) => void;
2580
+ recordingState?: "idle" | "recording" | "preview";
2581
+ recordingDuration?: number;
2582
+ onToggleRecording?: () => void;
2583
+ }
2584
+
2585
+ interface LocalFontData {
2586
+ family: string;
2587
+ fullName?: string;
2588
+ postscriptName?: string;
2589
+ style?: string;
2590
+ blob?: () => Promise<Blob>;
2591
+ }
2592
+ declare global {
2593
+ interface Window {
2594
+ queryLocalFonts?: () => Promise<LocalFontData[]>;
2595
+ }
2596
+ }
2597
+
2598
+ declare const PropertyPanel: react.NamedExoticComponent<PropertyPanelProps>;
2599
+
2600
+ interface FileTreeProps {
2601
+ files: string[];
2602
+ activeFile: string | null;
2603
+ onSelectFile: (path: string) => void;
2604
+ onCreateFile?: (path: string) => void;
2605
+ onCreateFolder?: (path: string) => void;
2606
+ onDeleteFile?: (path: string) => void;
2607
+ onRenameFile?: (oldPath: string, newPath: string) => void;
2608
+ onDuplicateFile?: (path: string) => void;
2609
+ onMoveFile?: (oldPath: string, newPath: string) => void;
2610
+ onImportFiles?: (files: FileList, dir?: string) => void;
2611
+ lintFindingsByFile?: Map<string, {
2612
+ count: number;
2613
+ messages: string[];
2614
+ }>;
2615
+ }
2616
+ declare const FileTree: react.NamedExoticComponent<FileTreeProps>;
2617
+
2618
+ interface StudioAppProps {
2619
+ /** Clicks still select and report; the preview cannot move, edit or delete anything. */
2620
+ readOnlyPreview?: boolean;
2621
+ /** Short text shown on disabled hand-edit controls while `readOnlyPreview` is set. */
2622
+ readOnlyPreviewReason?: string;
2623
+ }
2624
+ declare function StudioApp({ readOnlyPreview, readOnlyPreviewReason }?: StudioAppProps): react_jsx_runtime.JSX.Element;
2625
+
2626
+ type RightPanelTab = "layers" | "design" | "renders" | "block-params" | "slideshow" | "variables";
2627
+ interface AgentModalAnchorPoint {
2628
+ x: number;
2629
+ y: number;
2630
+ }
2631
+
2632
+ interface AskAgentModalProps {
2633
+ selectionLabel: string;
2634
+ contextPreview?: string;
2635
+ anchorPoint?: AgentModalAnchorPoint | null;
2636
+ onSubmit: (instruction: string) => void;
2637
+ onClose: () => void;
2638
+ }
2639
+ declare function AskAgentModal({ selectionLabel, contextPreview, anchorPoint, onSubmit, onClose, }: AskAgentModalProps): react_jsx_runtime.JSX.Element;
2640
+
2641
+ /**
2642
+ * What the dev server knows about this machine's FFmpeg, as reported by
2643
+ * `GET /api/environment/ffmpeg`. Studio asks when the Render panel opens so a
2644
+ * missing encoder is a prompt with an install command, not a failed export an
2645
+ * hour into the work.
2646
+ */
2647
+ interface FfmpegStatus {
2648
+ ok: boolean;
2649
+ /** Short headline, e.g. "FFmpeg not found". Absent when ok. */
2650
+ title?: string;
2651
+ /** Why it cannot run, in the server's words. Absent when ok. */
2652
+ detail?: string;
2653
+ /** Prose remediation, including the manual route where one exists. */
2654
+ hint?: string;
2655
+ /** A single pasteable install command, when this platform has one. */
2656
+ command?: string;
2657
+ }
2658
+
2659
+ interface RenderJob {
2660
+ id: string;
2661
+ status: "rendering" | "complete" | "failed" | "cancelled";
2662
+ progress: number;
2663
+ stage?: string;
2664
+ error?: string;
2665
+ filename: string;
2666
+ createdAt: number;
2667
+ durationMs?: number;
2668
+ }
2669
+ type ResolutionPreset = CanvasResolution;
2670
+ interface StartRenderOptions {
2671
+ fps?: number;
2672
+ quality?: "draft" | "standard" | "high";
2673
+ format?: "mp4" | "webm" | "mov";
2674
+ /** `"auto"` (default) renders at the composition's authored dimensions. */
2675
+ resolution?: ResolutionPreset | "auto";
2676
+ /**
2677
+ * Render a specific composition file. Omit it to render the composition the
2678
+ * user currently has open — only the sidebar's per-composition Render button
2679
+ * names one, because it renders a card the user is not looking at.
2680
+ */
2681
+ composition?: string;
2682
+ /**
2683
+ * Composition-variable overrides ({variableId: value}), forwarded to the
2684
+ * render route and injected as window.__hfVariables — the same channel
2685
+ * `hyperframes render --variables` uses.
2686
+ */
2687
+ variables?: Record<string, unknown>;
2688
+ }
2689
+ declare function useRenderQueue(projectId: string | null, activeCompPathRef: {
2690
+ current: string | null;
2691
+ }): {
2692
+ jobs: RenderJob[];
2693
+ isRendering: boolean;
2694
+ loadError: string | null;
2695
+ actionError: string | null;
2696
+ dismissActionError: () => void;
2697
+ reloadRenders: () => Promise<void>;
2698
+ deleteRender: (jobId: string) => Promise<void>;
2699
+ cancelRender: (jobId: string) => Promise<void>;
2700
+ clearCompleted: () => void;
2701
+ startRender: (options: unknown) => Promise<void>;
2702
+ ffmpeg: FfmpegStatus | null;
2703
+ ffmpegMissing: boolean;
2704
+ ffmpegChecking: boolean;
2705
+ recheckFfmpeg: () => void;
2706
+ };
2707
+
2708
+ interface CompositionDimensions {
2709
+ width: number;
2710
+ height: number;
2711
+ }
2712
+ type StartRenderHandler = (format: "mp4" | "webm" | "mov", quality: "draft" | "standard" | "high", resolution: ResolutionPreset | "auto", fps: 24 | 30 | 60) => void | Promise<void>;
2713
+ interface RenderQueueProps {
2714
+ jobs: RenderJob[];
2715
+ projectId: string;
2716
+ onDelete: (jobId: string) => void;
2717
+ onCancel?: (jobId: string) => void;
2718
+ onClearCompleted: () => void;
2719
+ onStartRender: StartRenderHandler;
2720
+ isRendering: boolean;
2721
+ /** History fetch failure (null when the last load succeeded). */
2722
+ loadError?: string | null;
2723
+ /** Retry a failed history load. */
2724
+ onRetryLoad?: () => void;
2725
+ /** Failure of a delete/cancel action, shown inline until dismissed. */
2726
+ actionError?: string | null;
2727
+ onDismissActionError?: () => void;
2728
+ /**
2729
+ * Authored dimensions of the active composition. Used to pick the
2730
+ * matching preset (landscape / portrait / square) when the user selects
2731
+ * a 1080p or 4K scale. `null` falls back to landscape (legacy default).
2732
+ */
2733
+ compositionDimensions?: CompositionDimensions | null;
2734
+ /**
2735
+ * Encoder availability, owned by useRenderQueue so the panel's Export button
2736
+ * and the header's agree. `null` means "no answer", not "missing".
2737
+ */
2738
+ ffmpeg: FfmpegStatus | null;
2739
+ ffmpegChecking: boolean;
2740
+ onRecheckFfmpeg: () => void;
2741
+ }
2742
+ declare const RenderQueue: react.NamedExoticComponent<RenderQueueProps>;
2743
+
2744
+ interface PersistedRenderSettings {
2745
+ format: "mp4" | "webm" | "mov";
2746
+ quality: "draft" | "standard" | "high";
2747
+ fps: 24 | 30 | 60;
2748
+ }
2749
+ declare function getPersistedRenderSettings(): PersistedRenderSettings;
2750
+ declare function persistRenderSettings(format: PersistedRenderSettings["format"], quality: PersistedRenderSettings["quality"], fps: PersistedRenderSettings["fps"]): void;
2751
+
2752
+ interface PickedElement {
2753
+ id: string | null;
2754
+ tagName: string;
2755
+ selector: string;
2756
+ label: string;
2757
+ boundingBox: {
2758
+ x: number;
2759
+ y: number;
2760
+ width: number;
2761
+ height: number;
2762
+ };
2763
+ textContent: string | null;
2764
+ src: string | null;
2765
+ dataAttributes: Record<string, string>;
2766
+ computedStyles: Record<string, string>;
2767
+ }
2768
+ interface UseElementPickerReturn {
2769
+ isPickMode: boolean;
2770
+ pickedElement: PickedElement | null;
2771
+ enablePick: () => void;
2772
+ disablePick: () => void;
2773
+ clearPick: () => void;
2774
+ /** Update a CSS property on the picked element live + persist to source */
2775
+ setStyle: (prop: string, value: string) => void;
2776
+ /** Update a data attribute on the picked element + persist to source */
2777
+ setDataAttr: (attr: string, value: string) => void;
2778
+ /** Update the text content of the picked element + persist to source */
2779
+ setTextContent: (text: string) => void;
2780
+ /** Override the active iframe (for zoomed canvas view). Pass null to restore primary. */
2781
+ setActiveIframe: (el: HTMLIFrameElement | null) => void;
2782
+ /** Ref that always points to the active iframe (focused canvas frame or preview panel) */
2783
+ activeIframeRef: React.RefObject<HTMLIFrameElement | null>;
2784
+ }
2785
+ interface PickerOptions {
2786
+ /** Workspace files for source patching */
2787
+ workspaceFiles?: Record<string, string>;
2788
+ /** Callback to sync patched files to the project */
2789
+ onSyncFiles?: (files: Record<string, string>) => void;
2790
+ }
2791
+ /**
2792
+ * Hook for element picking via the HyperFrame runtime's picker API.
2793
+ * Communicates with the iframe via postMessage.
2794
+ */
2795
+ declare function useElementPicker(iframeRef: React.RefObject<HTMLIFrameElement | null>, options?: PickerOptions): UseElementPickerReturn;
2796
+
2797
+ /**
2798
+ * HTML Editor — Utility functions for parsing and manipulating HyperFrame HTML source.
2799
+ */
2800
+ /**
2801
+ * Parse a CSS inline style string into a key-value map.
2802
+ * e.g. "opacity: 0.5; transform: matrix(1,0,0,1,0,0)" →
2803
+ * { opacity: "0.5", transform: "matrix(1,0,0,1,0,0)" }
2804
+ */
2805
+ declare function parseStyleString(style: string): Record<string, string>;
2806
+ /**
2807
+ * Merge `newStyles` into an opening tag string's `style` attribute.
2808
+ * - New values win over existing ones.
2809
+ * - If no `style` attribute is present, one is added before the closing `>`.
2810
+ */
2811
+ declare function mergeStyleIntoTag(tag: string, newStyles: string): string;
2812
+ /**
2813
+ * Find the full element block (opening tag through closing tag) in the source.
2814
+ * Uses quote-aware scanning to handle attributes containing >.
2815
+ * Uses depth counting to handle nested same-name tags.
2816
+ */
2817
+ declare function findElementBlock(html: string, elementId: string): {
2818
+ start: number;
2819
+ end: number;
2820
+ openTag: string;
2821
+ tagName: string;
2822
+ indent: string;
2823
+ innerContent: string;
2824
+ isSelfClosing: boolean;
2825
+ } | null;
2826
+
2827
+ /** One file's restore from the edit-history store: before (live) / after (target) bytes. */
2828
+ interface UndoRestoreFile {
2829
+ previous: string;
2830
+ restored: string;
2831
+ }
2832
+ type RestoreFiles = Record<string, UndoRestoreFile>;
2833
+
2834
+ interface ApplyCallbacks {
2835
+ readFile: (path: string) => Promise<string>;
2836
+ serialize?: <T>(paths: readonly string[], task: () => Promise<T>) => Promise<T>;
2837
+ claimedAfter?: number;
2838
+ }
2839
+ interface UsePersistentEditHistoryOptions {
2840
+ projectId: string | null;
2841
+ }
2842
+ interface ApplyResult {
2843
+ ok: boolean;
2844
+ /** content-mismatch: `paths` changed after the step's entry. failed: `message` says why. */
2845
+ reason?: "empty" | "content-mismatch" | "failed";
2846
+ message?: string;
2847
+ label?: string;
2848
+ paths?: string[];
2849
+ undoes?: string;
2850
+ files?: RestoreFiles;
2851
+ }
2852
+ /** Studio's undo over the server's project history: an edit claims what it wrote; Cmd+Z steps the person's. */
2853
+ declare function usePersistentEditHistory({ projectId }: UsePersistentEditHistoryOptions): {
2854
+ loaded: boolean;
2855
+ canUndo: boolean;
2856
+ canRedo: boolean;
2857
+ undoLabel: string | undefined;
2858
+ redoLabel: string | undefined;
2859
+ undoPaths: string[];
2860
+ redoPaths: string[];
2861
+ state: {
2862
+ undo: {
2863
+ createdAt: number;
2864
+ }[];
2865
+ redo: {
2866
+ createdAt: number;
2867
+ }[];
2868
+ };
2869
+ recordEdit: ({ label, coalesceKey, coalesceMs, files, created }: RecordEditInput$5) => Promise<void>;
2870
+ claimKey: (key: string) => string;
2871
+ undo: (callbacks: ApplyCallbacks) => Promise<ApplyResult>;
2872
+ redo: (callbacks: ApplyCallbacks) => Promise<ApplyResult>;
2873
+ predict: (direction: "undo" | "redo") => {
2874
+ id: string;
2875
+ files: RestoreFiles;
2876
+ } | null;
2877
+ claims: () => number;
2878
+ noteOutsideChange: () => void;
2879
+ };
2880
+
2881
+ /** The files an undo or redo rewrote. */
2882
+ interface LiveLaneRestore {
2883
+ paths?: string[];
2884
+ files?: Record<string, {
2885
+ restored: string;
2886
+ }>;
2887
+ }
2888
+
2889
+ declare function useTimelineEditing({ projectId, activeCompPath, timelineElements, showToast, writeProjectFile, observeProjectFileVersion, recordEdit, reloadPreview, previewIframeRef, pendingTimelineEditPathRef, uploadProjectFiles, isRecordingRef, sdkSession, publishSdkSession, forceReloadSdkSession, invalidateGsapCache, handleDomZIndexReorderCommitRef, canEdit, }: UseTimelineEditingOptions): {
2890
+ handleTimelineElementMove: (element: TimelineElement, updates: TimelineMoveUpdates) => Promise<void>;
2891
+ handleTimelineElementResize: (element: TimelineElement, updates: Pick<TimelineElement, "start" | "duration" | "playbackStart">) => Promise<void>;
2892
+ handleToggleTrackHidden: (track: number, hidden: boolean, displayNumber?: number | null | undefined) => Promise<void>;
2893
+ handleToggleElementHidden: (elementKey: string | readonly string[], hidden: boolean) => Promise<void>;
2894
+ handleAutoGroupCarveSources: (clipIds: readonly string[], groupId: string, groupLabel?: string | undefined) => Promise<void>;
2895
+ setAudioGroupAttribute: {
2896
+ setQuiet: (groupId: string, attr: string, value: string | null, label: string) => Promise<TimelineEditOutcome>;
2897
+ setLive: (groupId: string, attr: string, value: string | null) => void;
2898
+ revertLive: (groupId: string, attr: string) => void;
2899
+ restoreLive: (restore: LiveLaneRestore) => void;
2900
+ };
2901
+ setElementFxAttribute: {
2902
+ setMany: (edits: readonly {
2903
+ element: TimelineElement;
2904
+ value: string | null;
2905
+ }[], attr: string, label: string) => Promise<TimelineEditOutcome>;
2906
+ setQuiet: (element: TimelineElement, attr: string, value: string | null, label: string) => Promise<TimelineEditOutcome>;
2907
+ setLive: (element: TimelineElement, attr: string, value: string | null) => void;
2908
+ revertLive: (element: TimelineElement, attr: string) => void;
2909
+ restoreLive: (restore: LiveLaneRestore) => void;
2910
+ };
2911
+ handleTimelineElementDelete: (element: TimelineElement) => Promise<void>;
2912
+ handleTimelineElementsDelete: (selection: TimelineElement[]) => Promise<void>;
2913
+ handleTimelineElementDeleteOnly: (element: TimelineElement) => Promise<void>;
2914
+ handleLinkEdit: (edit: TimelineLinkEdit) => Promise<void>;
2915
+ handleTimelineElementSplit: (element: TimelineElement, splitTime: number) => Promise<void>;
2916
+ handleRazorSplit: (element: TimelineElement, splitTime: number) => Promise<void>;
2917
+ handleFreezeFrame: (element: TimelineElement, playhead: number) => Promise<void>;
2918
+ handleRazorSplitAll: (splitTime: number) => Promise<void>;
2919
+ handleTimelineAssetDrop: (assetPath: string, placement: TimelineDropPlacement, durationOverride?: number | undefined) => Promise<void>;
2920
+ handleTimelineFileDrop: (files: File[], placement?: TimelineDropPlacement | undefined) => Promise<void>;
2921
+ handleTimelineCompositionDrop: (sourcePath: string, placement: Pick<TimelineElement, "track" | "start">) => Promise<void>;
2922
+ handleBlockedTimelineEdit: (element: TimelineElement) => void;
2923
+ handleTimelineGroupMove: (changes: TimelineGroupMoveChange[], options?: TimelineGroupCommitOptions | undefined) => Promise<void>;
2924
+ handleTimelineGroupResize: (changes: TimelineGroupResizeChange[], options?: TimelineGroupCommitOptions | undefined) => Promise<void>;
2925
+ restoreLiveLanes: (restore: Parameters<(restore: LiveLaneRestore) => void>[0]) => void;
2926
+ };
2927
+
2928
+ interface HistoryResult {
2929
+ ok: boolean;
2930
+ reason?: string;
2931
+ message?: string;
2932
+ label?: string;
2933
+ paths?: string[];
2934
+ undoes?: string;
2935
+ /** Per-file restored/previous content, used to soft-apply the preview. */
2936
+ files?: RestoreFiles;
2937
+ }
2938
+ interface HistoryFileCallbacks {
2939
+ readFile: (path: string) => Promise<string>;
2940
+ serialize?: <T>(paths: readonly string[], task: () => Promise<T>) => Promise<T>;
2941
+ claimedAfter?: number;
2942
+ }
2943
+ interface EditHistoryHandle {
2944
+ undo: (cb: HistoryFileCallbacks) => Promise<HistoryResult>;
2945
+ redo: (cb: HistoryFileCallbacks) => Promise<HistoryResult>;
2946
+ predict?: (direction: "undo" | "redo") => {
2947
+ id: string;
2948
+ files: RestoreFiles;
2949
+ } | null;
2950
+ claims?: () => number;
2951
+ state: {
2952
+ undo: ReadonlyArray<{
2953
+ createdAt: number;
2954
+ }>;
2955
+ redo: ReadonlyArray<{
2956
+ createdAt: number;
2957
+ }>;
2958
+ };
2959
+ }
2960
+ interface UseEditHistoryActionsOptions {
2961
+ editHistory: Pick<EditHistoryHandle, "undo" | "redo" | "predict" | "claims">;
2962
+ readOptionalProjectFile: (path: string) => Promise<string>;
2963
+ readProjectFile: (path: string) => Promise<string>;
2964
+ writeProjectFile: (path: string, content: string) => Promise<void>;
2965
+ showToast: (message: string, tone?: "error" | "info") => void;
2966
+ syncHistoryPreviewAfterApply: (restore: Pick<HistoryResult, "paths" | "files">) => Promise<void>;
2967
+ showHistoryRestoreNow?: (files: RestoreFiles) => (() => void) | null;
2968
+ waitForPendingDomEditSaves: () => Promise<void>;
2969
+ onAfterUndoRedo?: (restore: Pick<HistoryResult, "paths" | "files">) => void;
2970
+ /** Active composition path — decides whether undo/redo must resync the SDK session. */
2971
+ activeCompPath?: string | null;
2972
+ /** Reloads the SDK session after a revert of the active comp, past the self-write suppress window. */
2973
+ forceReloadSdkSession?: () => void;
2974
+ }
2975
+ /** Takes one step of the project's history: the single owner of undo/redo over project files. */
2976
+ declare function useEditHistoryActions({ editHistory, readOptionalProjectFile, readProjectFile, writeProjectFile, showToast, syncHistoryPreviewAfterApply, showHistoryRestoreNow, waitForPendingDomEditSaves, onAfterUndoRedo, activeCompPath, forceReloadSdkSession, }: UseEditHistoryActionsOptions): {
2977
+ undo: () => Promise<void>;
2978
+ redo: () => Promise<void>;
2979
+ };
2980
+
2981
+ interface UseProjectFileWriterOptions {
2982
+ projectId: string | null;
2983
+ }
2984
+ declare function useProjectFileWriter({ projectId }: UseProjectFileWriterOptions): {
2985
+ fileVersions: Map<string, string | null>;
2986
+ readProjectFile: (path: string) => Promise<string>;
2987
+ writeProjectFile: (path: string, content: string, expectedContent?: string) => Promise<void>;
2988
+ readOptionalProjectFile: (path: string) => Promise<string>;
2989
+ observeProjectFileVersion: (path: string, version: string | null) => void;
2990
+ };
2991
+
2992
+ type ExternalFileChangeBlockedState = {
2993
+ status: "conflict";
2994
+ generation: number;
2995
+ error: StudioFileConflictError;
2996
+ payload: unknown;
2997
+ } | {
2998
+ status: "failed";
2999
+ generation: number;
3000
+ path: string;
3001
+ error: unknown;
3002
+ payload: unknown;
3003
+ studioContent: string | null;
3004
+ recovered: boolean;
3005
+ };
3006
+ interface ExternalFileChangeCoordinatorHandle {
3007
+ blocked: ExternalFileChangeBlockedState | null;
3008
+ retry: () => Promise<void>;
3009
+ useExternalFile: () => Promise<void>;
3010
+ keepStudioFile: () => Promise<void>;
3011
+ }
3012
+
3013
+ declare function ExternalFileConflictBanner({ coordinator, }: {
3014
+ coordinator: ExternalFileChangeCoordinatorHandle;
3015
+ }): react_jsx_runtime.JSX.Element | null;
3016
+
3017
+ interface TimelinePaneProps {
3018
+ /** Slot rendered above the timeline tracks (toolbar with split, delete, zoom) */
3019
+ timelineToolbar?: ReactNode;
3020
+ /** Slot rendered below the timeline tracks */
3021
+ timelineFooter?: ReactNode;
3022
+ /** Slot for a host's own overlay spanning the whole timeline area (e.g. a draft/ghost
3023
+ * clip), positioned absolutely the same way PreviewPane's previewOverlay is. */
3024
+ timelineOverlay?: ReactNode;
3025
+ /** Custom clip content renderer for timeline (thumbnails, waveforms, etc.) */
3026
+ renderClipContent?: (element: TimelineElement, style: {
3027
+ clip: string;
3028
+ label: string;
3029
+ }) => ReactNode;
3030
+ onFileDrop?: (files: File[], placement?: Pick<TimelineElement, "start" | "track">) => Promise<void> | void;
3031
+ onDeleteElement?: (element: TimelineElement) => Promise<void> | void;
3032
+ onAssetDrop?: (assetPath: string, placement: Pick<TimelineElement, "start" | "track">) => Promise<void> | void;
3033
+ onBlockDrop?: (blockName: string, placement: Pick<TimelineElement, "start" | "track">) => Promise<void> | void;
3034
+ onCompositionDrop?: (sourcePath: string, placement: Pick<TimelineElement, "start" | "track">) => Promise<void> | void;
3035
+ onBlockedEditAttempt?: (element: TimelineElement, intent: BlockedTimelineEditIntent) => void;
3036
+ onSelectTimelineElement?: (element: TimelineElement | null) => void;
3037
+ onRangeSelect?: (range: TimelineTimeRange$1 | null) => void;
3038
+ /** Copy/paste/duplicate act on the store's own selection, not a passed
3039
+ * element, so unlike onDeleteElement they need no composition-basis wrapper. */
3040
+ onCopyClip?: () => boolean;
3041
+ onPasteClip?: () => Promise<void>;
3042
+ onDuplicateClip?: () => Promise<boolean>;
3043
+ canPasteClip?: () => boolean;
3044
+ clipMenuItems?: TimelineProps["clipMenuItems"];
3045
+ splitShortcut?: TimelineProps["splitShortcut"];
3046
+ }
3047
+ declare function TimelinePane({ timelineToolbar, timelineFooter, timelineOverlay, renderClipContent, onFileDrop, onDeleteElement, onAssetDrop, onBlockDrop, onCompositionDrop, onBlockedEditAttempt, onSelectTimelineElement, onRangeSelect, onCopyClip, onPasteClip, onDuplicateClip, canPasteClip, clipMenuItems, splitShortcut, }: TimelinePaneProps): react_jsx_runtime.JSX.Element;
3048
+
3049
+ declare function TimelineEditProvider({ value, children, }: {
3050
+ value: TimelineEditCallbacks;
3051
+ children: ReactNode;
3052
+ }): react_jsx_runtime.JSX.Element;
3053
+
3054
+ interface EnableKeyframesSession {
3055
+ domEditSelection: DomEditSelection | null;
3056
+ selectedGsapAnimations: GsapAnimation[];
3057
+ previewIframeRef?: React.RefObject<HTMLIFrameElement | null>;
3058
+ handleGsapAddAnimation: (method: "to" | "from" | "set" | "fromTo") => void;
3059
+ handleGsapConvertToKeyframes: (animId: string, resolvedFromValues?: Record<string, number | string>, duration?: number, commitOverrides?: Partial<CommitMutationOptions>) => void | Promise<void>;
3060
+ handleGsapRemoveKeyframe: (animId: string, pct: number) => void;
3061
+ handleGsapAddKeyframeBatch?: (animId: string, pct: number, properties: Record<string, number | string>, commitOverrides?: Partial<CommitMutationOptions>) => Promise<void>;
3062
+ commitMutation?: (mutation: Record<string, unknown>, options: CommitMutationOptions) => Promise<void>;
3063
+ }
3064
+
3065
+ interface TimelineHistoryButtonsProps {
3066
+ canUndo?: boolean;
3067
+ canRedo?: boolean;
3068
+ undoLabel?: string;
3069
+ redoLabel?: string;
3070
+ onUndo?: () => Promise<void> | void;
3071
+ onRedo?: () => Promise<void> | void;
3072
+ }
3073
+ /** Undo and Redo: a host's props win, else the shell's edit history. */
3074
+ declare function TimelineHistoryButtons(props: TimelineHistoryButtonsProps): react_jsx_runtime.JSX.Element;
3075
+
3076
+ interface DomEditSessionSlice extends EnableKeyframesSession {
3077
+ domEditSelection: DomEditSelection | null;
3078
+ selectedGsapAnimations: GsapAnimation[];
3079
+ }
3080
+ interface TimelineToolbarProps {
3081
+ domEditSession?: DomEditSessionSlice;
3082
+ onSplitElement?: (element: TimelineElement, splitTime: number) => void;
3083
+ splitShortcut?: TimelineProps["splitShortcut"];
3084
+ history?: TimelineHistoryButtonsProps;
3085
+ showHistory?: boolean;
3086
+ showSelectAroundPlayhead?: boolean;
3087
+ showAddBeat?: boolean;
3088
+ /** Hides Add keyframe and auto-record, and turns off auto-record and the K shortcut with them. */
3089
+ showKeyframes?: boolean;
3090
+ rightActions?: ReactNode;
3091
+ }
3092
+ declare const TimelineToolbar: react.NamedExoticComponent<TimelineToolbarProps>;
3093
+
3094
+ interface AudioMeterStripProps {
3095
+ /** Pass a stable ref (useRef): a new object each render restarts the meter loop. */
3096
+ previewIframeRef?: RefObject<HTMLIFrameElement | null>;
3097
+ }
3098
+ declare const AudioMeterStrip: react.NamedExoticComponent<AudioMeterStripProps>;
3099
+
3100
+ /** Whether the audio meter strip is shown; persisted, off unless the user showed it. */
3101
+ declare const useAudioMetersVisible: zustand.UseBoundStore<zustand.StoreApi<{
3102
+ visible: boolean;
3103
+ setVisible: (visible: boolean) => void;
3104
+ }>>;
3105
+
3106
+ type InPlace = {
3107
+ inPlace?: boolean;
3108
+ };
3109
+ interface RecordEditInput$3 {
3110
+ label: string;
3111
+ coalesceKey?: string;
3112
+ files: Record<string, {
3113
+ before: string;
3114
+ after: string;
3115
+ }>;
3116
+ }
3117
+ interface UseClipboardOptions {
3118
+ projectId: string | null;
3119
+ activeCompPath: string | null;
3120
+ domEditSelectionRef: React.MutableRefObject<DomEditSelection | null>;
3121
+ showToast: (message: string, tone?: "error" | "info") => void;
3122
+ writeProjectFile: (path: string, content: string) => Promise<void>;
3123
+ recordEdit: (input: RecordEditInput$3) => Promise<void>;
3124
+ reloadPreview: () => void;
3125
+ handleTimelineElementsDelete: (elements: TimelineElement[]) => Promise<void>;
3126
+ handleDomEditElementDelete: (selection: DomEditSelection) => Promise<void>;
3127
+ previewIframeRef: React.MutableRefObject<HTMLIFrameElement | null>;
3128
+ waitForPendingDomEditSaves: () => Promise<void>;
3129
+ }
3130
+ declare function useClipboard({ projectId, activeCompPath, domEditSelectionRef, showToast, writeProjectFile, recordEdit, reloadPreview, handleTimelineElementsDelete, handleDomEditElementDelete, previewIframeRef, waitForPendingDomEditSaves, }: UseClipboardOptions): {
3131
+ handleCopy: () => boolean;
3132
+ handlePaste: (options?: InPlace) => Promise<void>;
3133
+ handleCut: () => Promise<boolean>;
3134
+ handleDuplicate: (options?: InPlace) => Promise<boolean>;
3135
+ canPaste: () => boolean;
3136
+ };
3137
+
3138
+ /** The live markup to persist and the session snapshot to restore on failure. */
3139
+ interface InlineTextEditCommit {
3140
+ /** The exact preview node that owned the edit; a reload must not retarget it. */
3141
+ element: HTMLElement;
3142
+ html: string;
3143
+ previousHtml: string;
3144
+ }
3145
+
3146
+ /** Where a plain rotate draws its turn, read once at press: the element's own `rotate`, or, when its
3147
+ * transform translates it (often the translate(-50%, -50%) centring), a rotate() right after that
3148
+ * translate, so the box turns in place in screen space. `share` is what the rest already turns. */
3149
+ interface CssRotationTarget {
3150
+ property: "rotate" | "transform";
3151
+ before: string;
3152
+ after: string;
3153
+ share: number;
3154
+ /** -1 when a mirroring `scale` property flips a turn made inside the transform. */
3155
+ sign: number;
3156
+ /** An inline box does not transform, so the turn makes it inline-block. */
3157
+ inline: boolean;
3158
+ }
3159
+ type PressChoseGsap = null;
3160
+ type RotationCommit = {
3161
+ angle: number;
3162
+ plain?: CssRotationTarget | PressChoseGsap;
3163
+ };
3164
+
3165
+ declare const SNAP_THRESHOLD_PX = 6;
3166
+ /** Whether a move of this size has travelled far enough for snapping to apply. */
3167
+ declare function snapEngagedForTravel(dx: number, dy: number): boolean;
3168
+ interface SnapEdge {
3169
+ position: number;
3170
+ source: "grid";
3171
+ id: string;
3172
+ }
3173
+ interface SnapTarget {
3174
+ left: number;
3175
+ top: number;
3176
+ right: number;
3177
+ bottom: number;
3178
+ centerX: number;
3179
+ centerY: number;
3180
+ id: string;
3181
+ }
3182
+ interface SnapGuide {
3183
+ axis: "x" | "y";
3184
+ position: number;
3185
+ /** Extent of the guide line (min of involved elements). */
3186
+ from: number;
3187
+ /** Extent of the guide line (max of involved elements). */
3188
+ to: number;
3189
+ }
3190
+ interface SpacingGuide {
3191
+ axis: "x" | "y";
3192
+ /** Position of the gap (start of gap). */
3193
+ position: number;
3194
+ /** Size of the gap in pixels. */
3195
+ size: number;
3196
+ /** Extent for rendering the indicator. */
3197
+ from: number;
3198
+ /** Extent for rendering the indicator. */
3199
+ to: number;
3200
+ }
3201
+ interface SnapResult {
3202
+ dx: number;
3203
+ dy: number;
3204
+ guides: SnapGuide[];
3205
+ spacingGuides: SpacingGuide[];
3206
+ }
3207
+ interface Rect {
3208
+ left: number;
3209
+ top: number;
3210
+ width: number;
3211
+ height: number;
3212
+ }
3213
+ /**
3214
+ * Convert overlay rects to snap targets with precomputed edges & centers.
3215
+ */
3216
+ declare function extractSnapTargets(entries: Array<{
3217
+ rect: Rect;
3218
+ id: string;
3219
+ }>): SnapTarget[];
3220
+ /**
3221
+ * Create a snap target from the composition/overlay boundary.
3222
+ */
3223
+ declare function buildCompositionSnapTarget(rect: Rect): SnapTarget;
3224
+ /**
3225
+ * Generate grid-line snap edges.
3226
+ * `gridSpacing` is in composition pixels; `scale` converts to overlay pixels.
3227
+ * X edges are vertical grid lines; Y edges are horizontal grid lines.
3228
+ */
3229
+ declare function buildGridSnapEdges(compositionRect: Rect, gridSpacing: number, scale: number): {
3230
+ x: SnapEdge[];
3231
+ y: SnapEdge[];
3232
+ };
3233
+ declare function resolveSnapAdjustment(input: {
3234
+ movingRect: Rect;
3235
+ proposedDx: number;
3236
+ proposedDy: number;
3237
+ targets: SnapTarget[];
3238
+ gridEdges?: {
3239
+ x: SnapEdge[];
3240
+ y: SnapEdge[];
3241
+ };
3242
+ threshold: number;
3243
+ disabled: boolean;
3244
+ /** Set when the gesture has not travelled far enough for snapping yet. */
3245
+ disabledForTravel?: boolean;
3246
+ lockedAxis?: "x" | "y";
3247
+ }): SnapResult;
3248
+ /**
3249
+ * Full-length guide line spanning the composition: a vertical line (axis "x")
3250
+ * runs the composition's height at the snapped x position; a horizontal line
3251
+ * (axis "y") runs the composition's width. `composition` is the composition
3252
+ * rect in overlay space — guide positions are already overlay-space, so the
3253
+ * line must be offset by the composition's left/top (the canvas is usually
3254
+ * letterboxed inside the overlay).
3255
+ */
3256
+ declare function resolveGuideLineRect(guide: SnapGuide, composition: Rect): Rect;
3257
+ declare function resolveEquidistanceGuides(input: {
3258
+ movingRect: Rect;
3259
+ targets: SnapTarget[];
3260
+ threshold: number;
3261
+ }): SpacingGuide[];
3262
+
3263
+ interface SnapContext {
3264
+ targets: SnapTarget[];
3265
+ compositionTarget: SnapTarget | null;
3266
+ gridEdges: {
3267
+ x: SnapEdge[];
3268
+ y: SnapEdge[];
3269
+ } | null;
3270
+ snapEnabled: boolean;
3271
+ }
3272
+ declare function collectSnapContext(input: {
3273
+ overlayEl: HTMLDivElement;
3274
+ iframe: HTMLIFrameElement;
3275
+ excludeElements: Set<HTMLElement>;
3276
+ }): SnapContext;
3277
+
3278
+ interface SnapGuidesState {
3279
+ guides: SnapGuide[];
3280
+ spacingGuides: SpacingGuide[];
3281
+ }
3282
+ interface SnapGuideOverlayProps {
3283
+ snapGuidesRef: RefObject<SnapGuidesState | null>;
3284
+ /** Composition rect in overlay space — guide lines span exactly this rect. */
3285
+ compositionLeft: number;
3286
+ compositionTop: number;
3287
+ compositionWidth: number;
3288
+ compositionHeight: number;
3289
+ }
3290
+ declare const SnapGuideOverlay: react.NamedExoticComponent<SnapGuideOverlayProps>;
3291
+
3292
+ interface DomSelectionResult {
3293
+ changed: boolean;
3294
+ count: number;
3295
+ }
3296
+ interface ApplyDomSelectionOptions {
3297
+ revealPanel?: boolean;
3298
+ additive?: boolean;
3299
+ preserveGroup?: boolean;
3300
+ announce?: boolean;
3301
+ }
3302
+ interface ResolveDomSelectionOptions {
3303
+ preferClipAncestor?: boolean;
3304
+ skipSourceProbe?: boolean;
3305
+ activeGroupElement?: HTMLElement | null;
3306
+ /** Resolve this node itself instead of applying human group-capture behavior. */
3307
+ exactTarget?: boolean;
3308
+ previous?: DomEditSelection | null;
3309
+ }
3310
+ interface DomEditTimelineParams {
3311
+ projectId: string | null;
3312
+ activeCompPath: string | null;
3313
+ compIdToSrc: Map<string, string>;
3314
+ captionEditMode: boolean;
3315
+ previewIframeRef: MutableRefObject<HTMLIFrameElement | null>;
3316
+ timelineElements: TimelineElement[];
3317
+ getTimelineSelectionSet: () => ReadonlySet<string>;
3318
+ setSelectedTimelineElementId: (id: string | null, options?: SelectElementOptions) => void;
3319
+ /** Publishes a whole multi-selection to the timeline; the anchor is set separately. */
3320
+ setTimelineSelectionSet: (ids: Set<string>) => void;
3321
+ setRightCollapsed: (collapsed: boolean) => void;
3322
+ setRightPanelTab: (tab: RightPanelTab) => void;
3323
+ }
3324
+
3325
+ interface PreviewMouseDownOptions {
3326
+ preferClipAncestor?: boolean;
3327
+ hoverSelection?: DomEditSelection | null;
3328
+ }
3329
+
3330
+ interface MoveCommitOptions {
3331
+ altKey?: boolean;
3332
+ plainTranslate?: boolean;
3333
+ }
3334
+ interface DomEditGroupPathOffsetCommit {
3335
+ selection: DomEditSelection;
3336
+ next: {
3337
+ x: number;
3338
+ y: number;
3339
+ };
3340
+ plainTranslate?: boolean;
3341
+ }
3342
+
3343
+ /**
3344
+ * Why a DOM edit commit did not change the file.
3345
+ *
3346
+ * `runDomEditCommit` resolves on persist failure by design (see its contract
3347
+ * above), so a caller cannot learn whether the write landed by awaiting it — a
3348
+ * failed persist and a successful one are indistinguishable. Capture and apply
3349
+ * bugs still reject. The human path does not need to ask about handled persist
3350
+ * failures, because `onError` already put a toast on screen. A programmatic
3351
+ * caller has no screen, so it has to be told.
3352
+ */
3353
+ type DomEditCommitDeclineReason = "no-project" | "no-selection" | "geometry-property" | "styles-not-editable" | "not-text-editable" | "preview-stale" | "persist-failed";
3354
+ type DomEditCommitOutcome = {
3355
+ ok: true;
3356
+ persistence?: DomEditPersistOutcome;
3357
+ changed?: boolean;
3358
+ } | {
3359
+ ok: false;
3360
+ reason: DomEditCommitDeclineReason;
3361
+ };
3362
+
3363
+ /**
3364
+ * Which elements a delete acts on.
3365
+ *
3366
+ * Its own module so `useDomEditSession.ts` stays under the studio's 600-line
3367
+ * cap; it reads only its arguments.
3368
+ */
3369
+
3370
+ /** One entry in the studio's edit history, as `useDomEditSession`'s caller
3371
+ * supplies it. */
3372
+ interface RecordEditInput$2 {
3373
+ label: string;
3374
+ coalesceKey?: string;
3375
+ files: Record<string, {
3376
+ before: string;
3377
+ after: string;
3378
+ }>;
3379
+ }
3380
+
3381
+ interface DomGroupMove {
3382
+ selection: DomEditSelection;
3383
+ /** Composition px: the element's box moves by exactly this in the film. */
3384
+ delta: {
3385
+ x: number;
3386
+ y: number;
3387
+ };
3388
+ }
3389
+
3390
+ interface UseDomEditSessionParams extends DomEditTimelineParams {
3391
+ compositionLoading: boolean;
3392
+ showToast: (message: string, tone?: "error" | "info") => void;
3393
+ isRecordingRef?: React.RefObject<boolean>;
3394
+ refreshPreviewDocumentVersion: () => void;
3395
+ queueDomEditSave: <T>(save: () => Promise<T>) => Promise<T>;
3396
+ readProjectFile: (path: string) => Promise<string>;
3397
+ writeProjectFile: (path: string, content: string, expectedContent?: string) => Promise<void>;
3398
+ updateEditingFileContent: (path: string, content: string) => void;
3399
+ editHistory: {
3400
+ recordEdit: (entry: RecordEditInput$2) => Promise<void>;
3401
+ };
3402
+ fileTree: string[];
3403
+ importedFontAssetsRef: React.MutableRefObject<ImportedFontAsset[]>;
3404
+ projectDir: string | null;
3405
+ projectIdRef: React.MutableRefObject<string | null>;
3406
+ previewIframe: HTMLIFrameElement | null;
3407
+ refreshKey: number;
3408
+ previewDocumentVersion: number;
3409
+ rightPanelTab: RightPanelTab;
3410
+ applyStudioManualEditsToPreviewRef: React.MutableRefObject<(iframe: HTMLIFrameElement) => Promise<void>>;
3411
+ syncPreviewHotkeys: (iframe: HTMLIFrameElement | null) => void;
3412
+ reloadPreview: () => void;
3413
+ setRefreshKey: React.Dispatch<React.SetStateAction<number>>;
3414
+ openSourceForSelection?: (sourceFile: string, target: PatchTarget) => void;
3415
+ sdkSession?: Composition | null;
3416
+ publishSdkSession?: PublishSdkSession;
3417
+ forceReloadSdkSession?: () => void;
3418
+ /** The timeline context menu's delete op — a canvas selection that IS a
3419
+ * timeline row hands off here instead of the REST remove-elements path. */
3420
+ handleTimelineElementsDelete: (elements: TimelineElement[]) => Promise<void>;
3421
+ readOnlyPreview: boolean;
3422
+ }
3423
+ declare function useDomEditSession({ projectId, activeCompPath, compIdToSrc, captionEditMode, compositionLoading, previewIframeRef, timelineElements, getTimelineSelectionSet, setSelectedTimelineElementId, setTimelineSelectionSet, setRightCollapsed, setRightPanelTab, showToast, isRecordingRef, refreshPreviewDocumentVersion, queueDomEditSave, readProjectFile, writeProjectFile, updateEditingFileContent, editHistory, fileTree, importedFontAssetsRef, projectDir, projectIdRef, previewIframe: hostPreviewIframe, refreshKey, previewDocumentVersion, rightPanelTab, applyStudioManualEditsToPreviewRef, syncPreviewHotkeys, reloadPreview, openSourceForSelection, sdkSession, publishSdkSession, forceReloadSdkSession, handleTimelineElementsDelete, readOnlyPreview, }: UseDomEditSessionParams): {
3424
+ domEditSelection: DomEditSelection | null;
3425
+ domEditGroupSelections: DomEditSelection[];
3426
+ domEditHoverSelection: DomEditSelection | null;
3427
+ activeGroupElement: HTMLElement | null;
3428
+ agentModalOpen: boolean;
3429
+ agentModalAnchorPoint: AgentModalAnchorPoint | null;
3430
+ copiedAgentPrompt: boolean;
3431
+ agentPromptSelectionContext: string | undefined;
3432
+ domEditSelectionRef: react.MutableRefObject<DomEditSelection | null>;
3433
+ handleTimelineElementSelect: (element: TimelineElement | null) => Promise<void>;
3434
+ handlePreviewCanvasMouseDown: (e: React.MouseEvent<HTMLDivElement>, options?: PreviewMouseDownOptions) => Promise<void>;
3435
+ handlePreviewCanvasPointerMove: (e: React.PointerEvent<HTMLDivElement>, options?: {
3436
+ preferClipAncestor?: boolean;
3437
+ }) => Promise<DomEditSelection | null>;
3438
+ handlePreviewCanvasPointerLeave: () => void;
3439
+ applyDomSelection: (selection: DomEditSelection | null, options?: ApplyDomSelectionOptions) => void;
3440
+ clearDomSelection: () => void;
3441
+ refreshDomEditSelectionFromPreview: (selection: DomEditSelection) => Promise<void>;
3442
+ handleDomStyleCommit: (property: string, value: string) => Promise<DomEditCommitOutcome>;
3443
+ handleDomStyleCommitForSelection: (selection: DomEditSelection, propertyOrStylesAsOnePatch: string | Record<string, string>, value?: string) => Promise<DomEditCommitOutcome>;
3444
+ handleDomAttributeCommit: (attr: string, value: string) => Promise<void>;
3445
+ handleDomAttributeLiveCommit: (attr: string, value: string | null, onSettled?: (ok: boolean) => void, live?: {
3446
+ previewOnly?: boolean;
3447
+ }) => Promise<void>;
3448
+ handleDomAttributeQuietCommit: (attr: string, value: string | null) => Promise<void>;
3449
+ handleDomHtmlAttributeCommit: (attr: string, value: string | null) => Promise<void>;
3450
+ handleDomAttributesCommit: (selection: DomEditSelection, attrs: Record<string, string>) => Promise<void>;
3451
+ handleDomAttributeBatchCommit: CommitDomAttributeBatch;
3452
+ handleDomPathOffsetCommit: (selection: DomEditSelection, next: {
3453
+ x: number;
3454
+ y: number;
3455
+ }, modifiers?: MoveCommitOptions) => Promise<GeometryCommitResult | undefined>;
3456
+ handleDomGroupPathOffsetCommit: (updates: DomEditGroupPathOffsetCommit[], options?: {
3457
+ refusalToast?: boolean;
3458
+ }) => Promise<GeometryCommitResult>;
3459
+ handleDomGroupMoveBy: (moves: DomGroupMove[]) => Promise<void>;
3460
+ handleDomZIndexReorderCommit: (entries: Array<{
3461
+ element: HTMLElement;
3462
+ zIndex: number;
3463
+ id?: string;
3464
+ selector?: string;
3465
+ selectorIndex?: number;
3466
+ sourceFile: string;
3467
+ key?: string;
3468
+ }>, gestureCoalesceKey?: string, actionKind?: string) => Promise<void> | Promise<DomEditPatchBatchesResult>;
3469
+ handleDomBoxSizeCommit: (selection: DomEditSelection, next: {
3470
+ width: number;
3471
+ height: number;
3472
+ }, offset?: {
3473
+ x: number;
3474
+ y: number;
3475
+ }, restore?: () => void, route?: {
3476
+ plainTranslate: boolean;
3477
+ }) => Promise<GeometryCommitResult>;
3478
+ handleDomRotationCommit: (selection: DomEditSelection, next: RotationCommit) => Promise<GeometryCommitResult | undefined>;
3479
+ handleDomManualEditsReset: (selection: DomEditSelection) => Promise<DomEditPersistOutcome | undefined>;
3480
+ handleDomTextCommit: (value: string, fieldKey?: string) => Promise<DomEditCommitOutcome>;
3481
+ handleDomTextCommitForSelection: (selection: DomEditSelection, value: string, fieldKey?: string) => Promise<DomEditCommitOutcome>;
3482
+ handleDomRichTextCommit: ({ element, html, previousHtml }: InlineTextEditCommit) => Promise<void>;
3483
+ handleDomTextFieldStyleCommit: (fieldKey: string, property: string, value: string) => Promise<void>;
3484
+ handleDomAddTextField: (afterFieldKey?: string) => Promise<string | null>;
3485
+ handleDomRemoveTextField: (fieldKey: string) => Promise<void>;
3486
+ getGsapAnimationsForSelection: (selection: DomEditSelection) => _hyperframes_parsers.GsapAnimation[] | Promise<_hyperframes_parsers.GsapAnimation[]>;
3487
+ handleAskAgent: () => void;
3488
+ handleAgentModalSubmit: (userInstruction: string) => Promise<void>;
3489
+ handleBlockedDomMove: (selection: DomEditSelection, reason?: string) => void;
3490
+ handleDomManualDragStart: () => void;
3491
+ handleDomEditElementDelete: (selection: DomEditSelection, options?: {
3492
+ expandGroup?: boolean;
3493
+ }) => Promise<void>;
3494
+ handleGroupSelection: () => void;
3495
+ handleUngroupSelection: () => void;
3496
+ setActiveGroupElement: (el: HTMLElement | null) => void;
3497
+ buildDomSelectionFromTarget: (target: HTMLElement, options?: ResolveDomSelectionOptions) => Promise<DomEditSelection | null>;
3498
+ buildDomSelectionForTimelineElement: (element: TimelineElement) => Promise<DomEditSelection | null>;
3499
+ updateDomEditHoverSelection: (selection: DomEditSelection | null) => void;
3500
+ applyMarqueeSelection: (selections: DomEditSelection[], additive: boolean) => DomSelectionResult;
3501
+ resolveImportedFontAsset: (fontFamilyValue: string) => ImportedFontAsset | null;
3502
+ setAgentModalOpen: react.Dispatch<react.SetStateAction<boolean>>;
3503
+ setAgentPromptSelectionContext: react.Dispatch<react.SetStateAction<string | undefined>>;
3504
+ setAgentModalAnchorPoint: react.Dispatch<react.SetStateAction<AgentModalAnchorPoint | null>>;
3505
+ selectedGsapAnimations: _hyperframes_parsers.GsapAnimation[];
3506
+ gsapMultipleTimelines: boolean;
3507
+ gsapUnsupportedTimelinePattern: boolean;
3508
+ handleGsapUpdateProperty: (animId: string, prop: string, value: number | string) => void;
3509
+ handleGsapUpdateMeta: (animId: string, updates: {
3510
+ duration?: number;
3511
+ ease?: string;
3512
+ position?: number;
3513
+ }, selectionOverride?: DomEditSelection | null) => Promise<boolean>;
3514
+ handleGsapDeleteAnimation: (animId: string, selectionOverride?: DomEditSelection | null) => Promise<boolean>;
3515
+ handleGsapDeleteAllForElement: (targetSelector: string) => void;
3516
+ handleGsapAddAnimation: (method: "to" | "from" | "set" | "fromTo", selectionOverride?: DomEditSelection | null) => Promise<boolean>;
3517
+ handleGsapAddProperty: (animId: string, prop: string) => void;
3518
+ handleGsapRemoveProperty: (animId: string, prop: string) => void;
3519
+ handleGsapUpdateFromProperty: (animId: string, prop: string, value: number | string) => void;
3520
+ handleGsapAddFromProperty: (animId: string, prop: string) => void;
3521
+ handleGsapRemoveFromProperty: (animId: string, prop: string) => void;
3522
+ handleGsapAddKeyframe: (animId: string, percentage: number, property: string, value: number | string, selectionOverride?: DomEditSelection | null) => void;
3523
+ handleGsapAddKeyframeBatch: (animId: string, percentage: number, properties: Record<string, number | string>, commitOverrides?: Partial<CommitMutationOptions>, selectionOverride?: DomEditSelection | null) => Promise<void>;
3524
+ handleGsapRemoveKeyframe: (animId: string, percentage: number, commitOverrides?: Partial<CommitMutationOptions>, selectionOverride?: DomEditSelection | null) => void;
3525
+ handleGsapMoveKeyframeToPlayhead: (animId: string, fromPercentage: number, selectionOverride?: DomEditSelection | null, animationOverride?: _hyperframes_parsers.GsapAnimation) => void;
3526
+ handleGsapMoveKeyframe: (animId: string, fromPercentage: number, toPercentage: number, selectionOverride?: DomEditSelection | null) => Promise<boolean>;
3527
+ handleGsapResizeKeyframedTween: (animId: string, position: number, duration: number, pctRemap: Array<{
3528
+ from: number;
3529
+ to: number;
3530
+ }>, selectionOverride?: DomEditSelection | null) => Promise<boolean>;
3531
+ handleGsapConvertToKeyframes: (animId: string, resolvedFromValues?: Record<string, number | string>, duration?: number, commitOverrides?: Partial<CommitMutationOptions>, selectionOverride?: DomEditSelection | null) => Promise<void>;
3532
+ handleGsapRemoveAllKeyframes: (animId: string, selectionOverride?: DomEditSelection | null, telemetry?: boolean) => Promise<boolean>;
3533
+ handleResetSelectedElementKeyframes: () => boolean;
3534
+ handleUpdateKeyframeEase: (animationId: string, percentage: number, ease: string) => void;
3535
+ handleUpdateSegmentEase: (targets: AnimationKeyframeTarget[], ease: string) => void;
3536
+ handleSetAllKeyframeEases: (animationId: string, ease: string) => void;
3537
+ commitAnimatedProperty: (selection: DomEditSelection, property: string, value: number | string) => Promise<void>;
3538
+ commitAnimatedProperties: (selection: DomEditSelection, properties: Record<string, number | string>) => Promise<void>;
3539
+ handleSetArcPath: (animId: string, config: Parameters<(sel: DomEditSelection, animId: string, config: {
3540
+ enabled: boolean;
3541
+ autoRotate?: boolean | number;
3542
+ segments?: Array<{
3543
+ curviness: number;
3544
+ cp1?: {
3545
+ x: number;
3546
+ y: number;
3547
+ };
3548
+ cp2?: {
3549
+ x: number;
3550
+ y: number;
3551
+ };
3552
+ }>;
3553
+ }) => void>[2]) => void;
3554
+ handleUpdateArcSegment: (animId: string, segmentIndex: number, update: Parameters<(sel: DomEditSelection, animId: string, segmentIndex: number, update: {
3555
+ curviness?: number;
3556
+ cp1?: {
3557
+ x: number;
3558
+ y: number;
3559
+ };
3560
+ cp2?: {
3561
+ x: number;
3562
+ y: number;
3563
+ };
3564
+ }) => void>[3]) => void;
3565
+ handleUnroll: () => void;
3566
+ invalidateGsapCache: () => void;
3567
+ previewIframeRef: react.MutableRefObject<HTMLIFrameElement | null>;
3568
+ commitMutation: (mutation: Record<string, unknown>, options: CommitMutationOptions, selection?: DomEditSelection | null) => Promise<void>;
3569
+ };
3570
+
3571
+ /** The one source for which preview is on screen: the host's iframe, then each reload promoted in its place. */
3572
+ declare function useLivePreviewIframe(host: HTMLIFrameElement | null): HTMLIFrameElement | null;
3573
+
3574
+ type PreviewPromotion = {
3575
+ retired: HTMLIFrameElement | null;
3576
+ live: HTMLIFrameElement;
3577
+ };
3578
+
3579
+ interface DomEditSaveQueue {
3580
+ enqueue: <T>(save: () => Promise<T>) => Promise<T>;
3581
+ waitForIdle: () => Promise<DomEditSaveDrainResult>;
3582
+ isIdle: () => boolean;
3583
+ reset: () => void;
3584
+ destroy: () => void;
3585
+ }
3586
+ type DomEditSaveDrainResult = StudioSaveDrainResult;
3587
+
3588
+ /** The restore payload the undo/redo preview-sync consumes (from the history store). */
3589
+ interface HistoryPreviewRestore {
3590
+ paths?: string[];
3591
+ files?: RestoreFiles;
3592
+ }
3593
+ interface RecordEditInput$1 {
3594
+ label: string;
3595
+ coalesceKey?: string;
3596
+ files: Record<string, {
3597
+ before: string;
3598
+ after: string;
3599
+ }>;
3600
+ }
3601
+ interface UsePreviewPersistenceParams {
3602
+ showToast: (message: string, tone?: "error" | "info") => void;
3603
+ readOptionalProjectFile: (path: string) => Promise<string>;
3604
+ writeProjectFile: (path: string, content: string) => Promise<void>;
3605
+ recordEdit: (entry: RecordEditInput$1) => Promise<void>;
3606
+ previewIframeRef: React.MutableRefObject<HTMLIFrameElement | null>;
3607
+ activeCompPathRef: React.MutableRefObject<string | null>;
3608
+ /** Called to reload the preview after undo/redo or external file changes. */
3609
+ reloadPreview: () => void;
3610
+ }
3611
+ declare function usePreviewPersistence({ showToast, readOptionalProjectFile: _readOptionalProjectFile, writeProjectFile: _writeProjectFile, recordEdit: _recordEdit, previewIframeRef, activeCompPathRef, reloadPreview, }: UsePreviewPersistenceParams): {
3612
+ domTextCommitVersionRef: react.RefObject<number>;
3613
+ domEditSaveQueueRef: react.RefObject<DomEditSaveQueue | null>;
3614
+ applyStudioManualEditsToPreviewRef: react.RefObject<(iframe?: HTMLIFrameElement | null) => Promise<void>>;
3615
+ queueDomEditSave: <T>(save: () => Promise<T>) => Promise<T>;
3616
+ drainPendingDomEditSaves: () => Promise<{
3617
+ status: "clean";
3618
+ } | {
3619
+ status: "conflict";
3620
+ error: StudioFileConflictError;
3621
+ } | {
3622
+ status: "failed";
3623
+ error: unknown;
3624
+ }>;
3625
+ waitForPendingDomEditSaves: () => Promise<void>;
3626
+ settlePendingEdits: () => Promise<void>;
3627
+ domEditSaveQueuePaused: string | null;
3628
+ resetDomEditSaveQueueBreaker: () => void;
3629
+ applyCurrentStudioManualEditsToPreview: (iframe?: HTMLIFrameElement | null) => void;
3630
+ applyStudioManualEditsToPreview: (iframe?: HTMLIFrameElement | null) => Promise<void>;
3631
+ syncHistoryPreviewAfterApply: (restore: HistoryPreviewRestore) => Promise<void>;
3632
+ showHistoryRestoreNow: (files: RestoreFiles) => (() => void) | null;
3633
+ };
3634
+
3635
+ type DomEditValue = ReturnType<typeof useDomEditSession>;
3636
+ interface DomEditSelectionValue extends Pick<DomEditValue, "domEditSelection" | "domEditGroupSelections" | "domEditHoverSelection" | "activeGroupElement" | "domEditSelectionRef" | "selectedGsapAnimations" | "gsapMultipleTimelines" | "gsapUnsupportedTimelinePattern" | "agentModalOpen" | "agentModalAnchorPoint" | "copiedAgentPrompt" | "agentPromptSelectionContext"> {
3637
+ }
3638
+ declare function useDomEditSelectionContext(): DomEditSelectionValue;
3639
+ declare function DomEditProvider({ value: { domEditSelection, domEditGroupSelections, domEditHoverSelection, agentModalOpen, agentModalAnchorPoint, copiedAgentPrompt, agentPromptSelectionContext, domEditSelectionRef, handleTimelineElementSelect, handlePreviewCanvasMouseDown, handlePreviewCanvasPointerMove, handlePreviewCanvasPointerLeave, applyDomSelection, clearDomSelection, refreshDomEditSelectionFromPreview, handleDomStyleCommit, handleDomStyleCommitForSelection, handleDomAttributeCommit, handleDomAttributeLiveCommit, handleDomAttributeQuietCommit, handleDomHtmlAttributeCommit, handleDomAttributesCommit, handleDomAttributeBatchCommit, handleDomPathOffsetCommit, handleDomGroupPathOffsetCommit, handleDomGroupMoveBy, handleDomZIndexReorderCommit, handleDomBoxSizeCommit, handleDomRotationCommit, handleDomManualEditsReset, handleDomTextCommit, handleDomTextCommitForSelection, handleDomRichTextCommit, handleDomTextFieldStyleCommit, handleDomAddTextField, handleDomRemoveTextField, getGsapAnimationsForSelection, handleAskAgent, handleAgentModalSubmit, handleBlockedDomMove, handleDomManualDragStart, handleDomEditElementDelete, handleGroupSelection, handleUngroupSelection, setActiveGroupElement, activeGroupElement, buildDomSelectionFromTarget, buildDomSelectionForTimelineElement, updateDomEditHoverSelection, resolveImportedFontAsset, setAgentModalOpen, setAgentPromptSelectionContext, setAgentModalAnchorPoint, selectedGsapAnimations, gsapMultipleTimelines, gsapUnsupportedTimelinePattern, handleGsapUpdateProperty, handleGsapUpdateMeta, handleGsapDeleteAnimation, handleGsapDeleteAllForElement, handleGsapAddAnimation, handleGsapAddProperty, handleGsapRemoveProperty, handleGsapUpdateFromProperty, handleGsapAddFromProperty, handleGsapRemoveFromProperty, handleGsapAddKeyframe, handleGsapAddKeyframeBatch, handleGsapRemoveKeyframe, handleGsapMoveKeyframeToPlayhead, handleGsapMoveKeyframe, handleGsapResizeKeyframedTween, handleGsapConvertToKeyframes, handleGsapRemoveAllKeyframes, handleResetSelectedElementKeyframes, commitAnimatedProperty, commitAnimatedProperties, handleSetArcPath, handleUpdateArcSegment, handleUnroll, invalidateGsapCache, previewIframeRef, commitMutation, applyMarqueeSelection, handleUpdateKeyframeEase, handleUpdateSegmentEase, handleSetAllKeyframeEases, }, children, }: {
3640
+ value: DomEditValue;
3641
+ children: ReactNode;
3642
+ }): react_jsx_runtime.JSX.Element;
3643
+
3644
+ declare function PreviewReadOnlyProvider({ readOnly, reason, children, }: {
3645
+ readOnly: boolean;
3646
+ reason?: string;
3647
+ children: ReactNode;
3648
+ }): react_jsx_runtime.JSX.Element;
3649
+
3650
+ /**
3651
+ * Pure z-order helpers for the canvas right-click context menu.
3652
+ *
3653
+ * Layering strategy: z-index + CSS stacking context (position ≠ static).
3654
+ * All sibling z-index values are read from the live iframe DOM via
3655
+ * element.style.zIndex (inline style, set by the editor) falling back to
3656
+ * the computed value. Treat missing / "auto" as 0 for comparison purposes.
3657
+ *
3658
+ * "Overlapping siblings" = siblings whose bounding rects intersect the
3659
+ * target's bounding rect AND are actually visible at the current frame.
3660
+ * Forward/backward operate within that set; front/back operate across all
3661
+ * siblings (full painting family, visible or not — unchanged semantics).
3662
+ *
3663
+ * ── Visibility ───────────────────────────────────────────────────────────────
3664
+ * In HyperFrames compositions the nearest z-neighbor is often INVISIBLE at the
3665
+ * paused frame: the runtime hides time-inactive clips with inline
3666
+ * `visibility:hidden` / `display:none` (see core runtime
3667
+ * syncTimedElementVisibility), and GSAP timelines park elements at `opacity:0`.
3668
+ * Stepping "forward" over such a sibling looks like a silent no-op. The
3669
+ * forward/backward comparison set therefore keeps only siblings whose
3670
+ * element-level computed style is visible (display ≠ none, visibility ≠
3671
+ * hidden, opacity > 0.01) — all runtime hiding signals are inline styles, so
3672
+ * computed style covers them. Ancestor-chain checks are unnecessary here:
3673
+ * siblings share the target's ancestors. The probe is injectable
3674
+ * (ZOrderResolveOptions.isVisible) so the pure-module tests stay meaningful
3675
+ * without a real style engine, mirroring how tests stub rect reading.
3676
+ *
3677
+ * ── Tie-awareness ────────────────────────────────────────────────────────────
3678
+ * CSS paint order for elements that share a z-index is DOM document order:
3679
+ * the element that comes LATER in the DOM paints ON TOP. The old resolver
3680
+ * compared z-index alone, so a target tied with the element visually below it
3681
+ * (equal z, target later in DOM) had an empty "below" set and silently
3682
+ * no-op'd. This module computes true render order — sort by
3683
+ * (zIndex asc, DOM position asc), bottom→top — moves the target one step (or
3684
+ * to an end) in that order, then realizes the new order back into z values.
3685
+ *
3686
+ * The result is a MULTI-element patch: a single-element patch when a
3687
+ * strictly-between z value can express the new order given DOM-order
3688
+ * tie-breaking, otherwise a minimal renumber of the affected set (emitting
3689
+ * patches only for elements whose z actually changes). z is never negative
3690
+ * (project convention clamps z ≥ 0).
3691
+ */
3692
+ type ZOrderAction = "bring-forward" | "send-backward" | "bring-to-front" | "send-to-back";
3693
+ /** A resolved change: set `element`'s z-index to `zIndex`. */
3694
+ interface ZOrderPatch {
3695
+ element: HTMLElement;
3696
+ zIndex: number;
3697
+ }
3698
+
3699
+ interface DomEditOverlayProps {
3700
+ iframeRef: RefObject<HTMLIFrameElement | null>;
3701
+ activeCompositionPath: string | null;
3702
+ selection: DomEditSelection | null;
3703
+ groupSelections?: DomEditSelection[];
3704
+ hoverSelection: DomEditSelection | null;
3705
+ allowCanvasMovement?: boolean;
3706
+ allowBodyDrag?: boolean;
3707
+ /** "host": no hover, marquee, box re-select, or body drag if allowBodyDrag is false; Enter still opens text. */
3708
+ canvasInput?: "overlay" | "host";
3709
+ onTextEditingChange?: (editing: boolean) => void;
3710
+ /** A click on a single selection's box, in either mode; the event may be the pointerup. */
3711
+ onSelectionBoxClick?: (event: React.MouseEvent<HTMLDivElement>, selection: DomEditSelection) => void;
3712
+ onCanvasMouseDown: (event: React.MouseEvent<HTMLDivElement>, options?: PreviewMouseDownOptions) => void;
3713
+ onCanvasPointerMove: (event: React.PointerEvent<HTMLDivElement>, options?: {
3714
+ preferClipAncestor?: boolean;
3715
+ }) => Promise<DomEditSelection | null>;
3716
+ onCanvasPointerLeave: () => void;
3717
+ onSelectionChange: (selection: DomEditSelection, options?: {
3718
+ revealPanel?: boolean;
3719
+ additive?: boolean;
3720
+ }) => void;
3721
+ onBlockedMove: (selection: DomEditSelection, reason?: string) => void;
3722
+ onManualDragStart?: () => void;
3723
+ onPathOffsetCommit: (selection: DomEditSelection, next: {
3724
+ x: number;
3725
+ y: number;
3726
+ }, modifiers?: MoveCommitOptions) => Promise<unknown> | void;
3727
+ onGroupPathOffsetCommit: (updates: DomEditGroupPathOffsetCommit[]) => Promise<unknown> | void;
3728
+ onBoxSizeCommit: (selection: DomEditSelection, next: {
3729
+ width: number;
3730
+ height: number;
3731
+ }, offset?: {
3732
+ x: number;
3733
+ y: number;
3734
+ }, restore?: () => void, route?: {
3735
+ plainTranslate: boolean;
3736
+ }) => Promise<unknown> | void;
3737
+ onRotationCommit: (selection: DomEditSelection, next: RotationCommit) => Promise<unknown> | void;
3738
+ onStyleCommit?: (property: string, value: string) => Promise<unknown> | void;
3739
+ recordingState?: GestureRecordingState;
3740
+ onToggleRecording?: () => void;
3741
+ onMarqueeSelect?: (selections: DomEditSelection[], additive: boolean) => DomSelectionResult | void;
3742
+ /**
3743
+ * Delete the selected canvas element.
3744
+ * Wire to handleDomEditElementDelete from useDomEditActionsContext —
3745
+ * same handler the Delete/Backspace hotkey uses.
3746
+ */
3747
+ onDeleteSelection?: (selection: DomEditSelection) => void;
3748
+ /**
3749
+ * Called with the resolved z-order patch list and the menu action that
3750
+ * produced it (feeds the undo coalesce key). The patch list is tie-aware and
3751
+ * may include sibling elements (see canvasContextMenuZOrder); the live DOM is
3752
+ * NOT yet mutated. Wire to handleDomZIndexReorderCommit from
3753
+ * useDomEditActionsContext. See CanvasContextMenu.tsx module comment.
3754
+ */
3755
+ onApplyZIndex?: (selection: DomEditSelection, patches: ZOrderPatch[], action: ZOrderAction,
3756
+ /** Sibling a forward/backward step moved past (pre-mutation render order);
3757
+ * null for front/back. Feeds the timeline z-mirror's crossedKey. */
3758
+ crossed: HTMLElement | null) => void;
3759
+ }
3760
+ declare const DomEditOverlay: react.NamedExoticComponent<DomEditOverlayProps>;
3761
+
3762
+ type HostInputProps = Pick<ComponentProps<typeof DomEditOverlay>, "canvasInput" | "onSelectionBoxClick" | "allowBodyDrag">;
3763
+ interface ConnectedDomEditOverlayProps extends HostInputProps {
3764
+ activeCompositionPath: string | null;
3765
+ showHoverSelection: boolean;
3766
+ shouldShowSelectedDomBounds: boolean;
3767
+ isGestureRecording?: boolean;
3768
+ /** True when an in-place text edit opens its caret, false when it ends or unmounts. */
3769
+ onTextEditingChange?: (editing: boolean) => void;
3770
+ }
3771
+ declare function ConnectedDomEditOverlay({ activeCompositionPath, showHoverSelection, shouldShowSelectedDomBounds, isGestureRecording, canvasInput, allowBodyDrag, onTextEditingChange, onSelectionBoxClick, }: ConnectedDomEditOverlayProps): react_jsx_runtime.JSX.Element;
3772
+
3773
+ interface StudioShellValue {
3774
+ projectId: string;
3775
+ activeCompPath: string | null;
3776
+ setActiveCompPath: (path: string | null) => void;
3777
+ showToast: (message: string, tone?: "error" | "info") => void;
3778
+ previewIframeRef: React.MutableRefObject<HTMLIFrameElement | null>;
3779
+ editHistory: {
3780
+ canUndo: boolean;
3781
+ canRedo: boolean;
3782
+ undoLabel: string | undefined;
3783
+ redoLabel: string | undefined;
3784
+ };
3785
+ /**
3786
+ * Why a composition write would be refused right now, or null when writes
3787
+ * are possible. Derived from the paused save queue and the external-file
3788
+ * conflict state, both of which are otherwise banners with no lock behind
3789
+ * them. One field rather than two, so there is one owner of the question.
3790
+ */
3791
+ writeBlockedReason: string | null;
3792
+ handleUndo: () => Promise<void>;
3793
+ handleRedo: () => Promise<void>;
3794
+ renderQueue: {
3795
+ jobs: unknown[];
3796
+ isRendering: boolean;
3797
+ loadError: string | null;
3798
+ actionError: string | null;
3799
+ dismissActionError: () => void;
3800
+ reloadRenders: () => void;
3801
+ deleteRender: (jobId: string) => void;
3802
+ cancelRender: (jobId: string) => void;
3803
+ clearCompleted: () => void;
3804
+ startRender: (options: unknown) => Promise<void>;
3805
+ /** Encoder availability. `null` means "no answer", not "missing". */
3806
+ ffmpeg: FfmpegStatus | null;
3807
+ /** True only when the server positively reported no usable FFmpeg. */
3808
+ ffmpegMissing: boolean;
3809
+ ffmpegChecking: boolean;
3810
+ recheckFfmpeg: () => void;
3811
+ };
3812
+ compositionDimensions: CompositionDimensions | null;
3813
+ waitForPendingDomEditSaves: () => Promise<void>;
3814
+ handlePreviewIframeRef: (iframe: HTMLIFrameElement | null) => void;
3815
+ }
3816
+ interface StudioPlaybackValue {
3817
+ captionEditMode: boolean;
3818
+ compositionLoading: boolean;
3819
+ refreshKey: number;
3820
+ setRefreshKey: React.Dispatch<React.SetStateAction<number>>;
3821
+ timelineElements: TimelineElement[];
3822
+ isPlaying: boolean;
3823
+ refreshPreviewDocumentVersion: () => void;
3824
+ }
3825
+
3826
+ /** Studio state the panel reads; passed by hosts outside Studio's providers. Keep previewIframeRef stable,
3827
+ * and bump refreshKey when the preview document is rebuilt without an iframe load. */
3828
+ type LayersPanelHost = Pick<StudioShellValue, "previewIframeRef" | "activeCompPath" | "showToast"> & Pick<StudioPlaybackValue, "timelineElements" | "isPlaying"> & Partial<Pick<StudioPlaybackValue, "refreshKey" | "compositionLoading">>;
3829
+ declare const LayersPanel: react.NamedExoticComponent<{
3830
+ host?: LayersPanelHost;
3831
+ }>;
3832
+
3833
+ interface DomEditZOrder {
3834
+ /** False in a read-only preview, for an element no longer in the live preview, or at that end of its stacking set. */
3835
+ enabled: (sel: DomEditSelection, action: ZOrderAction) => boolean;
3836
+ /** Resolve and commit one step; false when nothing is sent to be saved. */
3837
+ apply: (sel: DomEditSelection, action: ZOrderAction) => boolean;
3838
+ /** Commit patches already resolved (the canvas menu resolves its own); false when none could be sent to be saved. */
3839
+ commit: (sel: DomEditSelection, patches: ReadonlyArray<ZOrderPatch>, action: ZOrderAction, crossed: HTMLElement | null) => boolean;
3840
+ }
3841
+ declare function useDomEditZOrder(): DomEditZOrder;
3842
+
3843
+ interface RecordEditInput {
3844
+ label: string;
3845
+ coalesceKey?: string;
3846
+ coalesceMs?: number;
3847
+ files: Record<string, {
3848
+ before: string;
3849
+ after: string;
3850
+ }>;
3851
+ }
3852
+
3853
+ interface UseDomStyleCommitOptions {
3854
+ projectId: string | null;
3855
+ /** The preview the host already runs: the style applies there live, and it reseeks after a save. */
3856
+ iframeRef: React.MutableRefObject<HTMLIFrameElement | null>;
3857
+ /** The same function objects the host gives the timeline, so there is one writer and one undo list. */
3858
+ writeProjectFile: (path: string, content: string, expectedContent?: string) => Promise<void>;
3859
+ recordEdit: (entry: RecordEditInput) => Promise<void>;
3860
+ activeCompPath?: string | null;
3861
+ showToast?: (message: string, tone?: "error" | "info") => void;
3862
+ }
3863
+ /** Saves style edits on a selection through Studio's own style commit, for a host without the editor. */
3864
+ declare function useDomStyleCommit({ projectId, iframeRef, writeProjectFile, recordEdit, activeCompPath, showToast, }: UseDomStyleCommitOptions): {
3865
+ commitStyle: (selection: DomEditSelection, styles: Record<string, string>) => Promise<DomEditCommitOutcome>;
3866
+ waitForPendingSaves: () => Promise<DomEditSaveDrainResult>;
3867
+ };
3868
+
3869
+ declare function ColorField({ label, value, disabled, onReset, flat, mixed, onPreview, onCommit, }: {
3870
+ label: string;
3871
+ value: string;
3872
+ disabled?: boolean;
3873
+ onReset?: () => void;
3874
+ flat?: boolean;
3875
+ mixed?: boolean;
3876
+ onPreview?: (nextValue: string) => void;
3877
+ onCommit: (nextValue: string) => void;
3878
+ }): react_jsx_runtime.JSX.Element;
3879
+
3880
+ declare function GradientField({ value, fallbackColor, disabled, onCommit, }: {
3881
+ value: string;
3882
+ fallbackColor: string | undefined;
3883
+ disabled?: boolean;
3884
+ onCommit: (nextValue: string) => void;
3885
+ }): react_jsx_runtime.JSX.Element;
3886
+
3887
+ /**
3888
+ * Studio's `Player` must show the project, with `beginTimelineSession(projectId)` run before it
3889
+ * mounts; drain `waitForPendingSaves` before switching projects.
3890
+ */
3891
+ interface UseDomGeometryCommitOptions extends UseDomStyleCommitOptions {
3892
+ /** Reloads the host's preview when a save cannot patch it in place. */
3893
+ reloadPreview: () => void;
3894
+ }
3895
+ interface DomGeometryCommits {
3896
+ commitPathOffset: (selection: DomEditSelection, next: {
3897
+ x: number;
3898
+ y: number;
3899
+ }, modifiers?: MoveCommitOptions) => Promise<DomEditCommitOutcome>;
3900
+ commitGroupPathOffset: (updates: DomEditGroupPathOffsetCommit[]) => Promise<DomEditCommitOutcome>;
3901
+ commitBoxSize: (selection: DomEditSelection, next: {
3902
+ width: number;
3903
+ height: number;
3904
+ }, offset?: {
3905
+ x: number;
3906
+ y: number;
3907
+ }, restore?: () => void, route?: {
3908
+ plainTranslate: boolean;
3909
+ }) => Promise<DomEditCommitOutcome>;
3910
+ commitRotation: (selection: DomEditSelection, next: RotationCommit) => Promise<DomEditCommitOutcome>;
3911
+ waitForPendingSaves: () => Promise<void>;
3912
+ }
3913
+ /**
3914
+ * Saves canvas moves, resizes and rotations through Studio's own GSAP-aware commits, for a host
3915
+ * without the editor. A failed save rejects, so DomEditOverlay undoes the live gesture.
3916
+ */
3917
+ declare function useDomGeometryCommit({ projectId, iframeRef, writeProjectFile, recordEdit, activeCompPath, showToast, reloadPreview, }: UseDomGeometryCommitOptions): DomGeometryCommits;
3918
+
3919
+ interface MarqueeGesturesDeps<T = DomEditSelection> {
3920
+ iframeRef: React.RefObject<HTMLIFrameElement | null>;
3921
+ overlayRef: React.RefObject<HTMLDivElement | null>;
3922
+ activeCompositionPathRef: React.RefObject<string | null>;
3923
+ onMarqueeSelectRef: React.RefObject<((selections: T[], additive: boolean) => DomSelectionResult | void) | undefined>;
3924
+ /** Turns the elements a drag touched into picks; without it, Studio's edit selections. */
3925
+ resolveHits?: (elements: HTMLElement[]) => T[] | Promise<T[]>;
3926
+ selectionRef?: React.RefObject<DomEditSelection | null>;
3927
+ /** Studio's pointer handling, for the events that are not part of a marquee. */
3928
+ gestures?: {
3929
+ onPointerMove: (event: React.PointerEvent<HTMLDivElement>) => void;
3930
+ onPointerUp: (event: React.PointerEvent<HTMLDivElement>) => void;
3931
+ clearPointerState: (ref: React.RefObject<DomEditSelection | null>) => void;
3932
+ };
3933
+ }
3934
+ interface MarqueeGestures {
3935
+ marqueeRect: Rect$1 | null;
3936
+ candidateRects: Rect$1[];
3937
+ /** Starts a marquee at this press; the host has decided it landed on empty canvas. */
3938
+ begin: (event: React.PointerEvent<HTMLElement>) => void;
3939
+ /** Drops an active marquee without selecting anything. */
3940
+ cancel: () => void;
3941
+ onPointerMove: (event: React.PointerEvent<HTMLDivElement>) => void;
3942
+ onPointerUp: (event: React.PointerEvent<HTMLDivElement>) => void;
3943
+ onPointerCancel: () => void;
3944
+ }
3945
+ declare function useMarqueeGestures(deps: MarqueeGesturesDeps): MarqueeGestures;
3946
+ declare function useMarqueeGestures<T>(deps: MarqueeGesturesDeps<T> & Required<Pick<MarqueeGesturesDeps<T>, "resolveHits">>): MarqueeGestures;
3947
+
3948
+ interface MarqueeOverlayProps {
3949
+ /** Elements the marquee currently intersects — outlined live before mouse-up. */
3950
+ candidateRects: Rect$1[];
3951
+ /** The marquee drag rectangle itself, or null when not marquee-selecting. */
3952
+ marqueeRect: Rect$1 | null;
3953
+ }
3954
+ /**
3955
+ * The marquee selection visuals: a live "candidate" outline on each element the
3956
+ * box currently touches, plus the dashed drag rectangle. Extracted from
3957
+ * DomEditOverlay to keep that file under the 600-line cap.
3958
+ */
3959
+ declare function MarqueeOverlay({ candidateRects, marqueeRect }: MarqueeOverlayProps): react_jsx_runtime.JSX.Element;
3960
+
3961
+ /**
3962
+ * The slice of the WebMCP browser API that Studio uses.
3963
+ *
3964
+ * Mirrors the WebIDL in the W3C spec (`webmachinelearning/webmcp`, `index.bs`)
3965
+ * as of 2026-08-26. Two things worth knowing before editing this file:
3966
+ *
3967
+ * - The API hangs off `document`, NOT `navigator`. `navigator.modelContext` is
3968
+ * a polyfill compatibility shim, not a spec member, so feature-detecting it
3969
+ * is wrong even where an article's sample "works".
3970
+ * - The spec is pre-stable (Origin Trial). This file and `registrar.ts` are the
3971
+ * only places that touch the API, so a spec change is a two-file edit. Re-read
3972
+ * `index.bs` rather than trusting this transcription.
3973
+ *
3974
+ * Only the surface Studio registers against is declared. `getTools` and
3975
+ * `executeTool` are the consumer side; Studio registers, it does not call.
3976
+ *
3977
+ * These stay hand-written rather than imported from `@mcp-b/webmcp-types`,
3978
+ * which the polyfill pulls in. That package's `registerTool` is overloaded to
3979
+ * infer argument types from a literal `inputSchema`, which is useful when you
3980
+ * register one tool inline and actively hostile when you register a uniform
3981
+ * list of them, as `registerStudioTools` does. Narrower is the safe operation
3982
+ * here. It does mean this file can drift from the spec, hence the note above.
3983
+ */
3984
+ interface ModelContextToolAnnotations {
3985
+ /** The tool does not change state. Lets an agent decide when calling is free. */
3986
+ readOnlyHint?: boolean;
3987
+ /** The tool's output contains data the page's author does not vouch for. */
3988
+ untrustedContentHint?: boolean;
3989
+ }
3990
+ interface ToolExecuteCallbackOptions {
3991
+ /**
3992
+ * Aborted when the caller cancels. Studio's commit path is not cancellable
3993
+ * once dispatched, so tools check this BEFORE dispatching and document that a
3994
+ * late abort does not unwind a write.
3995
+ */
3996
+ signal: AbortSignal;
3997
+ }
3998
+ interface ModelContextTool {
3999
+ /**
4000
+ * Max 128 characters, ASCII alphanumeric plus `_`, `-`, `.`. Registering a
4001
+ * name that already exists REJECTS with InvalidStateError; it does not
4002
+ * replace.
4003
+ */
4004
+ name: string;
4005
+ title?: string;
4006
+ /** Required and non-empty; an empty string rejects with InvalidStateError. */
4007
+ description: string;
4008
+ /** JSON Schema. Nothing in the platform validates input against it. */
4009
+ inputSchema?: object;
4010
+ /**
4011
+ * The user agent JSON-serializes whatever this resolves with, so it must
4012
+ * return an object. Returning `undefined` fails the serialization.
4013
+ *
4014
+ * A rejection is NOT a usable error channel: the spec discards the reason and
4015
+ * rejects the caller with a bare UnknownError. Resolve with a tagged failure
4016
+ * instead. See `toolResult.ts`.
4017
+ *
4018
+ * `options` is optional here although the spec always passes it: the
4019
+ * `@mcp-b/global` polyfill (through 5.1.0) calls `execute(input)` with no
4020
+ * second argument, so a Studio handler must not depend on receiving one.
4021
+ */
4022
+ execute: (input: object, options?: ToolExecuteCallbackOptions) => Promise<unknown>;
4023
+ annotations?: ModelContextToolAnnotations;
4024
+ }
4025
+
4026
+ /**
4027
+ * The shape every Studio tool resolves with.
4028
+ *
4029
+ * Tools resolve, they never reject. That is forced by the spec, not a style
4030
+ * choice: a rejected `execute` has its reason DISCARDED and the caller is
4031
+ * rejected with a bare `UnknownError` (`index.bs`, the execute-tool completion
4032
+ * steps). Rejecting would therefore guarantee the agent cannot see why the edit
4033
+ * failed, which is the one thing it needs most.
4034
+ *
4035
+ * There is no `outputSchema` in the platform yet, so this discriminant is
4036
+ * invisible to the agent's schema layer. Every tool's `description` has to say
4037
+ * that it returns `ok`.
4038
+ */
4039
+ type ToolFailureKind =
4040
+ /** A real state the agent can route around: save queue paused, capability off. */
4041
+ "blocked"
4042
+ /** The agent's fault: unknown handle, bad enum, out of range. */
4043
+ | "invalid"
4044
+ /** Exogenous: the server said no, the patch target could not be resolved. */
4045
+ | "failed"
4046
+ /** Our bug. Reported AND re-thrown, so it is findable instead of plausible. */
4047
+ | "internal";
4048
+ interface ToolFailure {
4049
+ ok: false;
4050
+ kind: ToolFailureKind;
4051
+ reason: string;
4052
+ /** What to try instead. This is what turns a failure into a next action. */
4053
+ hint?: string;
4054
+ }
4055
+ type ToolResult<T> = ({
4056
+ ok: true;
4057
+ } & T) | ToolFailure;
4058
+
4059
+ /**
4060
+ * `studio_look`: the one call that orients an agent.
4061
+ *
4062
+ * Deliberately fat. Every field here is one the agent would otherwise have to
4063
+ * spend a round trip discovering.
4064
+ *
4065
+ * The building is a pure function over a snapshot so it can be tested with
4066
+ * values. Gathering the snapshot is the React layer's job.
4067
+ */
4068
+
4069
+ type StudioLookSceneSnapshot = {
4070
+ status: "loading";
4071
+ } | {
4072
+ status: "ready";
4073
+ items: readonly DomEditLayerItem[];
4074
+ drillInItem: DomEditLayerItem | null;
4075
+ };
4076
+ interface StudioLookSnapshot {
4077
+ projectId: string | null;
4078
+ compositionPath: string | null;
4079
+ currentTime: number;
4080
+ duration: number;
4081
+ isPlaying: boolean;
4082
+ elements: readonly TimelineElement[];
4083
+ scene: StudioLookSceneSnapshot;
4084
+ selection: DomEditSelection | null;
4085
+ /** Live animations for the current selection arrive outside DomEditSelection. */
4086
+ selectionAnimationCount: number;
4087
+ /**
4088
+ * The undo stack as Studio's shell actually exposes it.
4089
+ *
4090
+ * This is a weaker signal than a revision counter, and deliberately not
4091
+ * dressed up as one: the depth lives in component-local state and is not
4092
+ * reachable here without plumbing it through the shell context. What an agent
4093
+ * CAN do is checkpoint `undoLabel` before a batch and notice it change to
4094
+ * something it did not do, which means a human pressed undo and its earlier
4095
+ * edits are gone.
4096
+ */
4097
+ history: {
4098
+ canUndo: boolean;
4099
+ canRedo: boolean;
4100
+ undoLabel: string | null;
4101
+ redoLabel: string | null;
4102
+ };
4103
+ }
4104
+ /** Gather the live scene once per tool call. The response never retains DOM nodes. */
4105
+ declare function collectStudioLookScene(doc: Document | null, activeCompositionPath: string | null, activeGroupElement: HTMLElement | null): StudioLookSceneSnapshot;
4106
+
4107
+ /**
4108
+ * `studio_select` and `studio_seek`: pointing the human and the agent at the
4109
+ * same thing.
4110
+ *
4111
+ * Selection is shared human-visible state. Element writes do not infer their
4112
+ * target from it: they resolve an explicit source-safe handle per call. Keeping
4113
+ * these contracts separate means a human click cannot redirect an agent write.
4114
+ */
4115
+
4116
+ interface SelectionToolDeps {
4117
+ /** The preview iframe's document, or null before it mounts. */
4118
+ getPreviewDocument: () => Document | null;
4119
+ getCompositionPath: () => string | null;
4120
+ getProjectId: () => string | null;
4121
+ buildSelection: (element: HTMLElement) => Promise<DomEditSelection | null>;
4122
+ applySelection: (selection: DomEditSelection) => void;
4123
+ /** Out-of-loop seek. `requestSeek`, not `setCurrentTime`. */
4124
+ requestSeek: (time: number) => void;
4125
+ readPlayhead: () => {
4126
+ currentTime: number;
4127
+ duration: number;
4128
+ isPlaying: boolean;
4129
+ };
4130
+ }
4131
+
4132
+ /**
4133
+ * `studio_frame`: the eyes.
4134
+ *
4135
+ * Without this the tool set is a remote control. With it an agent can author a
4136
+ * change, look at the instant it affects, judge it, and adjust. That loop is the
4137
+ * one thing source alone cannot support, because "what does this look like at
4138
+ * 2.4 seconds" is not a question a file can answer.
4139
+ *
4140
+ * Reuses Studio's existing capture endpoint (`utils/frameCapture`) rather than
4141
+ * inventing a second one. The server renders the composition with Puppeteer, so
4142
+ * the frame reflects the file on disk, not the live preview DOM.
4143
+ */
4144
+
4145
+ interface FrameToolDeps {
4146
+ getProjectId: () => string | null;
4147
+ getCompositionPath: () => string | null;
4148
+ readPlayhead: () => {
4149
+ currentTime: number;
4150
+ duration: number;
4151
+ isPlaying: boolean;
4152
+ };
4153
+ requestSeek: (time: number) => void;
4154
+ /** Confirms the URL renders. Injected so tests need no network. */
4155
+ probeFrame: (url: string) => Promise<{
4156
+ ok: boolean;
4157
+ status: number;
4158
+ }>;
4159
+ wait: (ms: number) => Promise<void>;
4160
+ }
4161
+
4162
+ /**
4163
+ * `studio_inspect`: everything about one element, in one call.
4164
+ *
4165
+ * The point is to prevent a failed write. Every field here either tells the
4166
+ * agent what it can change (`can`, with `reasonIfDisabled` verbatim) or what it
4167
+ * would be changing (the resolved styles, the text fields, the animations).
4168
+ * An agent that reads this first should never attempt an edit the element will
4169
+ * refuse.
4170
+ *
4171
+ * The GSAP diagnostics are here for the same reason: `multipleTimelines` and
4172
+ * `unsupportedTimelinePattern` are states where animation editing is off, and
4173
+ * learning that from a read is cheaper than learning it from a failed write.
4174
+ */
4175
+
4176
+ interface InspectToolDeps extends SelectionToolDeps {
4177
+ /** What the human currently has selected, used when no handle is given. */
4178
+ getCurrentSelection: () => DomEditSelection | null;
4179
+ getGsapDiagnostics: () => {
4180
+ animations: readonly GsapAnimation$1[];
4181
+ multipleTimelines: boolean;
4182
+ unsupportedTimelinePattern: boolean;
4183
+ };
4184
+ }
4185
+
4186
+ interface TargetedWriteDeps {
4187
+ getPreviewDocument: () => Document | null;
4188
+ getProjectId: () => string | null;
4189
+ getWriteBlockedReason: () => string | null;
4190
+ buildSelection: (element: HTMLElement) => Promise<DomEditSelection | null>;
4191
+ applySelection: (selection: DomEditSelection) => void;
4192
+ }
4193
+
4194
+ /**
4195
+ * `studio_set_text` and `studio_set_style`: the first tools that change the file.
4196
+ *
4197
+ * The explicit source-safe handle is resolved to one selection per invocation.
4198
+ * That captured selection is passed into Studio's existing commit actor; visible
4199
+ * selection is presentation only and cannot redirect the write.
4200
+ */
4201
+
4202
+ interface ContentToolDeps extends TargetedWriteDeps {
4203
+ setText: (selection: DomEditSelection, value: string, fieldKey?: string) => Promise<DomEditCommitOutcome>;
4204
+ setStyle: (selection: DomEditSelection, property: string, value: string) => Promise<DomEditCommitOutcome>;
4205
+ }
4206
+
4207
+ /**
4208
+ * `studio_transform`: move, resize and rotate, as a drag would.
4209
+ *
4210
+ * This tool reads the element's box back after every write and reports what
4211
+ * ACTUALLY changed. That is not belt-and-braces, it is the only thing standing
4212
+ * between an agent and a silent lie, because two of the three handlers can do
4213
+ * nothing and resolve:
4214
+ *
4215
+ * - The handlers exposed on `DomEditActionsValue` are the GSAP-AWARE wrappers
4216
+ * (`useDomEditSession.ts` aliases them), not the CSS ones in
4217
+ * `useDomGeometryCommits.ts`.
4218
+ * - `handleGsapAwarePathOffsetCommit` and `handleGsapAwareRotationCommit` are
4219
+ * `if (gsapCommitMutation) { ...intercept... }` with NO else branch. In a
4220
+ * composition with no GSAP they return having done nothing. The adjacent
4221
+ * comments confirm that is deliberate: there is no CSS fallback to write to.
4222
+ * - `handleGsapAwareBoxSizeCommit` is different. It runs through
4223
+ * `runGestureTransaction` with a scale route and a width/height route, so
4224
+ * resize works more generally than the other two.
4225
+ *
4226
+ * Read back, do not assume.
4227
+ */
4228
+
4229
+ interface ElementBox {
4230
+ x: number;
4231
+ y: number;
4232
+ width: number;
4233
+ height: number;
4234
+ }
4235
+ interface TransformToolDeps extends TargetedWriteDeps {
4236
+ /** The element's box as it renders right now. */
4237
+ readBox: (selection: DomEditSelection) => ElementBox;
4238
+ moveTo: (selection: DomEditSelection, next: {
4239
+ x: number;
4240
+ y: number;
4241
+ }) => Promise<DomEditCommitOutcome | void>;
4242
+ resizeTo: (selection: DomEditSelection, next: {
4243
+ width: number;
4244
+ height: number;
4245
+ }) => Promise<DomEditCommitOutcome | void>;
4246
+ rotateTo: (selection: DomEditSelection, next: {
4247
+ angle: number;
4248
+ }) => Promise<DomEditCommitOutcome | void>;
4249
+ }
4250
+
4251
+ /**
4252
+ * `studio_animate`: author motion.
4253
+ *
4254
+ * Add, update, and delete await the shared GSAP commit pipeline. Its promise is
4255
+ * the single settlement boundary for persistence and live-preview sync, so a
4256
+ * successful tool response never races ahead of the pixels the user sees.
4257
+ * Keyframe writes still report dispatch because their existing actor catches
4258
+ * its own failure instead of returning a landed signal.
4259
+ */
4260
+
4261
+ type GsapMethod = "to" | "from" | "set" | "fromTo";
4262
+ interface AnimationToolDeps extends TargetedWriteDeps {
4263
+ getAnimationsForSelection: (selection: DomEditSelection) => Promise<readonly {
4264
+ id: string;
4265
+ }[]>;
4266
+ readPlayhead: () => {
4267
+ currentTime: number;
4268
+ duration: number;
4269
+ isPlaying: boolean;
4270
+ };
4271
+ addAnimation: (selection: DomEditSelection, method: GsapMethod) => Promise<boolean>;
4272
+ updateAnimation: (selection: DomEditSelection, animationId: string, updates: {
4273
+ duration?: number;
4274
+ ease?: string;
4275
+ position?: number;
4276
+ }) => Promise<boolean>;
4277
+ addKeyframe: (selection: DomEditSelection, animationId: string, percent: number, properties: Record<string, number | string>) => Promise<void>;
4278
+ deleteAnimation: (selection: DomEditSelection, animationId: string) => Promise<boolean>;
4279
+ }
4280
+
4281
+ interface StudioAgentToolsDeps extends SelectionToolDeps, FrameToolDeps, InspectToolDeps, ContentToolDeps, TransformToolDeps, AnimationToolDeps {
4282
+ /** Read Studio's current state. Called per tool invocation, never cached. */
4283
+ getSnapshot: () => StudioLookSnapshot;
4284
+ }
4285
+ /**
4286
+ * Build the tool list once.
4287
+ *
4288
+ * Every `execute` reads `depsRef.current` at CALL time rather than closing over
4289
+ * a snapshot, which is what lets the list be built once and still see live
4290
+ * state. That is the whole point of the ref: see the registration note below.
4291
+ */
4292
+ declare function buildStudioTools(depsRef: {
4293
+ readonly current: StudioAgentToolsDeps;
4294
+ }): ModelContextTool[];
4295
+
4296
+ export { type AgentModalAnchorPoint, type AgentPromptElementInfo, AskAgentModal, type AskAgentModalProps, AudioMeterStrip, type AudioMeterStripProps, AudioWaveform, type AudioWaveformProps, type BlockedTimelineEditIntent, type CanEditTimelineElement, ColorField, CompositionBreadcrumb, type CompositionDimensions, type CompositionLevel, CompositionThumbnail, ConnectedDomEditOverlay, type ConnectedDomEditOverlayProps, DEFAULT_SHORTCUT_SECTIONS, Dock, type DockController, type DomEditCapabilities, type DomEditCommitDeclineReason, type DomEditCommitOutcome, type DomEditGroupPathOffsetCommit, DomEditOverlay, type DomEditOverlayProps, DomEditProvider, type DomEditSelection, type DomEditZOrder, type DomGeometryCommits, type EditHistoryHandle, EditorShell, type EditorShellProps, type ExternalFileChangeBlockedState, type ExternalFileChangeCoordinatorHandle, ExternalFileConflictBanner, type FadeEdge, type FadeHandleBox, type FadeHandleClipBox, type FfmpegStatus, FileTree, GradientField, GridOverlay, ImageThumbnail, type ImageThumbnailProps, LayersPanel, type LayersPanelHost, type LinkShortcutCallbacks, type MarqueeGestures, type MarqueeGesturesDeps, MarqueeOverlay, type MarqueeOverlayProps, type Rect$1 as MarqueeRect, type ModelContextTool, NLEPreview, type PanelId, type PatchOperation, type PersistedRenderSettings, type PickedElement, PlayerControls, type PlayerHandle, type PlayerHandleElement, type PlayerHandleListener, type PlayerHandleTimeListener, type DomEditCompositionRect as PreviewCompositionRect, PreviewGuides, PreviewOverlayProvider, type PreviewOverlayProviderProps, type PreviewPromotion, PreviewReadOnlyProvider, type PreviewSnapPreferences, PropertyPanel, type RenderJob, RenderQueue, type RenderQueueProps, type ResolutionPreset, SNAP_THRESHOLD_PX, type ShortcutHint, type ShortcutSection, ShortcutsButton, type ShortcutsButtonProps, type SnapContext, type SnapEdge, type SnapGuide, SnapGuideOverlay, type SnapGuideOverlayProps, type SnapGuidesState, type Rect as SnapRect, type SnapResult, type SnapTarget, SnapToolbar, SourceEditor, type SpacingGuide, type StartRenderOptions, type StudioAgentToolsDeps, StudioApp, StudioFileConflictError, type StudioLookSnapshot, type StudioPendingEditsDrainResult, TRACK_H, type ThumbnailPriority, type ThumbnailStill, Timeline, TimelineClipMenu, type TimelineClipMenuItem, type TimelineClipRenderContext, type TimelineEditCallbacks, type TimelineEditOutcome, type TimelineEditPermission, TimelineEditPopover, TimelineEditProvider, type TimelineElement, TimelineEmptyStatePart, TimelineFrame, TimelineGapMenu, TimelineHistoryButtons, type TimelineHistoryButtonsProps, TimelineKeyframeMenu, TimelineLanes, TimelineOverlays, TimelinePane, type TimelinePaneProps, TimelinePlayhead, TimelineProvider, TimelineRazorGuide, TimelineRuler, TimelineShortcutHint, type TimelineTheme, type TimelineTimeRange$1 as TimelineTimeRange, TimelineToolbar, type TimelineToolbarProps, type TimelineTrackPadding, type TimelineZIndexReorderCommit, type ToolResult, type UseClipboardOptions, type UseDomEditSessionParams, type UseDomGeometryCommitOptions, type UseDomStyleCommitOptions, type UseEditHistoryActionsOptions, type UsePersistentEditHistoryOptions, type UsePreviewPersistenceParams, type UseProjectFileWriterOptions, type UseRenderClipContentOptions, type UseThumbnailStillOptions, type UseTimelineEditingOptions, VideoThumbnail, type ZOrderAction, applyPatch, buildCompositionSnapTarget, buildGridSnapEdges, buildPickerAgentContextPreview, buildPickerAgentPrompt, buildStudioTools, collectSnapContext, collectStudioLookScene, dispatchLinkShortcut, displayTrackOrder, extractSnapTargets, fadeHandleBoxes, findElementBlock, flushStudioPendingEdits, formatTime, getPersistedRenderSettings, liveTime, mergeStyleIntoTag, openAudioGainDialog, parseStyleString, persistRenderSettings, resolveDomEditSelection, resolveEquidistanceGuides, resolveGuideLineRect, resolveIframe, resolveSnapAdjustment, resolveSourceFile, revertNewestStudioPendingEdit, snapEngagedForTravel, useAudioGainDialogStore, useAudioMetersVisible, useClipboard, useCompositionStack, useDockLayoutStore, useDomEditSelectionContext, useDomEditSession, useDomEditZOrder, useDomGeometryCommit, useDomStyleCommit, useEditHistoryActions, useElementPicker, useLivePreviewIframe, useMarqueeGestures, usePersistentEditHistory, usePlayerHandle, usePlayerStore, usePreviewCompositionRect, usePreviewGuidesStore, usePreviewIframeStore, usePreviewOverlayContext, usePreviewPersistence, useProjectFileWriter, useRenderClipContent, useRenderQueue, useThumbnailStill, useTimelineContext, useTimelineEditing, useTimelinePlayer };