@higgsfield/video-editor-mcp 1.0.7 → 1.1.1-dev.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 (189) hide show
  1. package/THIRD_PARTY_NOTICES.md +24 -24
  2. package/dist/cli.mjs +134 -125
  3. package/dist/index.html +136 -133
  4. package/dist/launcher.mjs +90 -90
  5. package/dist/server.mjs +1553 -1389
  6. package/node_modules/@higgsfield/higgsedit/README.md +181 -1
  7. package/node_modules/@higgsfield/higgsedit/dist/capture-page.js +902 -314
  8. package/node_modules/@higgsfield/higgsedit/dist/chunk-2JYLVSVV.mjs +1594 -0
  9. package/node_modules/@higgsfield/higgsedit/dist/chunk-2WKNH7OL.mjs +16 -0
  10. package/node_modules/@higgsfield/higgsedit/dist/{chunk-OMKZ5BXM.mjs → chunk-5LTTL3Q3.mjs} +1 -1
  11. package/node_modules/@higgsfield/higgsedit/dist/chunk-7PYXSJS7.mjs +717 -0
  12. package/node_modules/@higgsfield/higgsedit/dist/{chunk-MLJAIZGP.mjs → chunk-BH2QF635.mjs} +33 -326
  13. package/node_modules/@higgsfield/higgsedit/dist/{chunk-WZR5PZM7.mjs → chunk-BV5COOQZ.mjs} +250 -161
  14. package/node_modules/@higgsfield/higgsedit/dist/{chunk-HTCYVKFX.mjs → chunk-C3GSB3XZ.mjs} +8 -7
  15. package/node_modules/@higgsfield/higgsedit/dist/{chunk-CYH2EUQV.mjs → chunk-DVN4LUXV.mjs} +13 -4
  16. package/node_modules/@higgsfield/higgsedit/dist/chunk-F4CMIG5G.mjs +36 -0
  17. package/node_modules/@higgsfield/higgsedit/dist/chunk-IEPPEDEU.mjs +33 -0
  18. package/node_modules/@higgsfield/higgsedit/dist/{chunk-UVAZ6I6U.mjs → chunk-KIWGVAPJ.mjs} +16 -12
  19. package/node_modules/@higgsfield/higgsedit/dist/{chunk-L6QDNSL3.mjs → chunk-L5LWBA6A.mjs} +5 -5
  20. package/node_modules/@higgsfield/higgsedit/dist/chunk-LMQR3DHT.mjs +37 -0
  21. package/node_modules/@higgsfield/higgsedit/dist/chunk-LTKMGZ6T.mjs +58 -0
  22. package/node_modules/@higgsfield/higgsedit/dist/{chunk-VI6IV6JP.mjs → chunk-MV2JTTBQ.mjs} +65 -47
  23. package/node_modules/@higgsfield/higgsedit/dist/{chunk-4D6AXU4B.mjs → chunk-NARTAWRN.mjs} +50 -30
  24. package/node_modules/@higgsfield/higgsedit/dist/{chunk-27NBQ5FA.mjs → chunk-NUXTKQNM.mjs} +33 -21
  25. package/node_modules/@higgsfield/higgsedit/dist/chunk-OCIZ36XD.mjs +40 -0
  26. package/node_modules/@higgsfield/higgsedit/dist/{chunk-MK6PL7N4.mjs → chunk-OF6RMSM2.mjs} +19 -17
  27. package/node_modules/@higgsfield/higgsedit/dist/{chunk-6BETMESC.mjs → chunk-P2BGHTRR.mjs} +2 -2
  28. package/node_modules/@higgsfield/higgsedit/dist/{chunk-EKFC4S4M.mjs → chunk-PAHMD6SU.mjs} +5 -0
  29. package/node_modules/@higgsfield/higgsedit/dist/{chunk-QVLAEV3U.mjs → chunk-PFQYUJQL.mjs} +3 -4
  30. package/node_modules/@higgsfield/higgsedit/dist/chunk-QJTILFBS.mjs +335 -0
  31. package/node_modules/@higgsfield/higgsedit/dist/chunk-QQ3GGKDN.mjs +21 -0
  32. package/node_modules/@higgsfield/higgsedit/dist/chunk-TH7TK67K.mjs +23 -0
  33. package/node_modules/@higgsfield/higgsedit/dist/{chunk-SIMO6I3D.mjs → chunk-UDL5AHKO.mjs} +163 -158
  34. package/node_modules/@higgsfield/higgsedit/dist/chunk-UMWOUQN3.mjs +60 -0
  35. package/node_modules/@higgsfield/higgsedit/dist/{chunk-3AIM3THH.mjs → chunk-VLM5EOWJ.mjs} +4 -4
  36. package/node_modules/@higgsfield/higgsedit/dist/chunk-WENFTPXQ.mjs +403 -0
  37. package/node_modules/@higgsfield/higgsedit/dist/chunk-YLVXQIPX.mjs +464 -0
  38. package/node_modules/@higgsfield/higgsedit/dist/editor/.vite/manifest.json +559 -506
  39. package/node_modules/@higgsfield/higgsedit/dist/editor/assets/agent-corner-bottom-q4hZltI-.svg +431 -0
  40. package/node_modules/@higgsfield/higgsedit/dist/editor/assets/agent-corner-top-BJYI-I24.svg +431 -0
  41. package/node_modules/@higgsfield/higgsedit/dist/editor/assets/confirmation-BTnwl3LS.css +1 -0
  42. package/node_modules/@higgsfield/higgsedit/dist/editor/assets/drag-Bt_t4HZO.css +1 -0
  43. package/node_modules/@higgsfield/higgsedit/dist/editor/assets/local-B3OTAV_A.css +1 -0
  44. package/node_modules/@higgsfield/higgsedit/dist/editor/assets/menubar-2Y1Y2XJt.css +1 -0
  45. package/node_modules/@higgsfield/higgsedit/dist/editor/assets/model-DdE4hCgf.css +1 -0
  46. package/node_modules/@higgsfield/higgsedit/dist/editor/assets/{IconText1-CzbCrP7v.css → notifications-B08L1jSe.css} +1 -1
  47. package/node_modules/@higgsfield/higgsedit/dist/editor/assets/{panel-g852pZf_.css → panel-BRN_AbBM.css} +1 -1
  48. package/node_modules/@higgsfield/higgsedit/dist/editor/assets/panel-CYELNqrv.css +1 -0
  49. package/node_modules/@higgsfield/higgsedit/dist/editor/assets/panel-DYLpT6oA.css +1 -0
  50. package/node_modules/@higgsfield/higgsedit/dist/editor/assets/panel-v84HaGTZ.css +1 -0
  51. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/IconChainLink1-Bxb1Or0F.js +1 -0
  52. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/{IconCheckmark2Medium-daaES9uF.js → IconCheckmark2Medium-hegaz9mQ.js} +1 -1
  53. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/{IconChevronDownSmall-BhTBJk26.js → IconChevronDownSmall-DaruzJwU.js} +1 -1
  54. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/IconClosedCaptioning-BPqcqKsD.js +1 -0
  55. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/{IconCrossMedium-acfnCXOM.js → IconCrossMedium-BsPFJzc6.js} +1 -1
  56. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/IconOpenaiFilled-D1fzthmi.js +1 -0
  57. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/{IconPause-pTeVSvUe.js → IconPause-ClNg8pao.js} +1 -1
  58. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/{IconPlayFilled-CwdgIuDG.js → IconPlayFilled-CHb-7GSx.js} +1 -1
  59. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/IconSparklesSoftFilled-o7o33KRn.js +1 -0
  60. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/ai-composer-B9h-eaki.js +567 -0
  61. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/auto-layout-BO20Tg4B.js +1 -0
  62. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/{button-CjG6GcgF.js → button-Cg0U0zpV.js} +1 -1
  63. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/canvas-Bw4CVzfw.js +1 -0
  64. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/capabilities-BCd4-zPF.js +1 -0
  65. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/commands-QeSqAbCt.js +1 -0
  66. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/components-tXMtIZNL.js +51 -0
  67. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/confirmation-CO2PHR_z.js +1 -0
  68. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/dom-6aoQn29n.js +1 -0
  69. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/drag-Dw8b_vO2.js +1 -0
  70. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/{editing-CjWbiCxv.js → editing-Cy-SaOyB.js} +1 -1
  71. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/edits-CqLBqir0.js +1 -0
  72. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/export-dialog-BjBskOe3.js +2 -0
  73. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/factories-Bw_iQrUL.js +1 -0
  74. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/id3-CSR0NCRI.js +2 -0
  75. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/import-DP49i4ke.js +1 -0
  76. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/import-error-CMz9sLPe.js +1 -0
  77. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/ingest-DsmIc415.js +1 -0
  78. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/jsx-runtime-B5yqYJvp.js +1 -0
  79. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/{media-Bwjxu-0U.js → media-DQw6vU_T.js} +1 -1
  80. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/menubar-D31srALX.js +1 -0
  81. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/meters-D0nZVEJs.js +1 -0
  82. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/mode-DEG6doKF.js +1 -0
  83. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/model-Duf9fszJ.js +2 -0
  84. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/model-DyAkLA69.js +1 -0
  85. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/notifications-DqWZNIrK.js +9 -0
  86. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/palette-HT83gWgL.js +1 -0
  87. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-B5Mvm6dg.js +7 -0
  88. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-BC90wyvd.js +1 -0
  89. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-Bw_ZJ2JI.js +3 -0
  90. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-DNS060Nt.js +3 -0
  91. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-DSgxIrEq.js +2 -0
  92. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-DgBttE5O.js +1 -0
  93. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-assets-_T2bHsHW.js +771 -0
  94. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-inspector-DfHvAt5X.js +2 -0
  95. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-nBZvHlkA.js +1 -0
  96. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-timeline-DsCpJVSt.js +327 -0
  97. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-viewport-CEhZwZ67.js +280 -0
  98. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/projects-2_tW9Do7.js +1 -0
  99. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/react-dom-1uB7Vbbb.js +1 -0
  100. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/schemas-CddYAOcj.js +64 -0
  101. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/session-BpFeKAI2.js +1 -0
  102. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/src-BLG3tYBa.js +2 -0
  103. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/styles-e2n2A_JN.js +284 -0
  104. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/supercomputer-CuV0zYKd.js +24 -0
  105. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/tabs-XeAgs9cs.js +1 -0
  106. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/toggle-DbNEaSIl.js +1 -0
  107. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/transport-C8Ll3qFl.js +69 -0
  108. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/transport-bar-Dv1LPFbu.js +1 -0
  109. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/useOpenInteractionType-HWSfSsp2.js +1 -0
  110. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/useRenderElement-D4SOg3N_.js +1 -0
  111. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/value-EB7YmAdS.js +1 -0
  112. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/writeback-support-fj5rA9k3.js +1 -0
  113. package/node_modules/@higgsfield/higgsedit/dist/editor/editor-B-WAkLt7.js +372 -0
  114. package/node_modules/@higgsfield/higgsedit/dist/higgsedit.mjs +39 -24
  115. package/node_modules/@higgsfield/higgsedit/dist/jsx/hooks.d.ts +26 -0
  116. package/node_modules/@higgsfield/higgsedit/dist/jsx/index.d.ts +17 -0
  117. package/node_modules/@higgsfield/higgsedit/dist/jsx/inspect.d.ts +42 -0
  118. package/node_modules/@higgsfield/higgsedit/dist/jsx/jsx-runtime.d.ts +28 -0
  119. package/node_modules/@higgsfield/higgsedit/dist/jsx/svg.d.ts +9 -0
  120. package/node_modules/@higgsfield/higgsedit/dist/jsx/time.d.ts +6 -0
  121. package/node_modules/@higgsfield/higgsedit/dist/jsx/types.d.ts +420 -0
  122. package/node_modules/@higgsfield/higgsedit/package.json +28 -20
  123. package/package.json +4 -3
  124. package/plugin/.codex-plugin/plugin.json +1 -1
  125. package/plugin/plugin.json +1 -1
  126. package/plugin/skills/video-editing/references/caption-titling.md +1 -1
  127. package/plugin/skills/video-editing/references/local-setup.md +3 -3
  128. package/node_modules/@higgsfield/higgsedit/dist/chunk-C6SASQHE.mjs +0 -424
  129. package/node_modules/@higgsfield/higgsedit/dist/chunk-FZ5U36SQ.mjs +0 -83
  130. package/node_modules/@higgsfield/higgsedit/dist/chunk-QLPCYN6K.mjs +0 -292
  131. package/node_modules/@higgsfield/higgsedit/dist/editor/assets/edit-drag-D2EV5ddd.css +0 -1
  132. package/node_modules/@higgsfield/higgsedit/dist/editor/assets/editor-CuRHT75g.css +0 -1
  133. package/node_modules/@higgsfield/higgsedit/dist/editor/assets/panel-DnuQD7ja.css +0 -1
  134. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/FieldControl-B0fenhBJ.js +0 -2
  135. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/IconChainLink1-Cwv1X7hi.js +0 -1
  136. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/IconEyeOpen-BqTT9_VV.js +0 -1
  137. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/IconEyeSlash-Whv58c1m.js +0 -1
  138. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/IconPencil-Dr17k_7e.js +0 -1
  139. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/IconPlay-BroH3ziH.js +0 -1
  140. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/IconPlusSmall-43T9aE3d.js +0 -1
  141. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/IconText1-BaP_p9DW.js +0 -1
  142. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/IconTrashCan-DX2w2AIC.js +0 -1
  143. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/ai-composer-C-l0eIdP.js +0 -560
  144. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/captions-Cd-bDG3G.js +0 -1
  145. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/clip-highlight-DpAvcA4x.js +0 -1
  146. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/components-e3ZbUVns.js +0 -1
  147. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/disposables-CwUPjcuA.js +0 -1
  148. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/drag-HLBkto5o.js +0 -1
  149. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/dropdown-BJ04G_X3.js +0 -1
  150. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/edit-drag-Bg6LggKC.js +0 -1
  151. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/edits-a2IixhrN.js +0 -1
  152. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/export-dialog-4I4gqI5V.js +0 -2
  153. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/face-tracker-DzVfjVOO.js +0 -1
  154. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/fit-imported-media-CaCB0x0b.js +0 -1
  155. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/generation-queue-DuL2F4-_.js +0 -1
  156. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/import-error-CMARA0Hy.js +0 -1
  157. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/jsx-runtime-B-hcVAMW.js +0 -1
  158. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/menubar-Bs26OdwP.js +0 -1
  159. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/meters-YEr9OQjq.js +0 -1
  160. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/paints-DS2Msf91.js +0 -67
  161. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/palette-CcS9IcAC.js +0 -1
  162. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-7M3uQokX.js +0 -1
  163. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-BBK1NyG-.js +0 -1
  164. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-CHZTs7By.js +0 -4
  165. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-DaSOa3MP.js +0 -2
  166. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-DlK3RYVo.js +0 -1
  167. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-Dst5OKWu.js +0 -2
  168. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-H_ZoDiKK.js +0 -2
  169. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-Rn9Z7Eek.js +0 -3
  170. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-assets-FAghGFG3.js +0 -678
  171. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-inspector-DEqULBNF.js +0 -260
  172. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-timeline-0GYNz1uc.js +0 -333
  173. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/panel-viewport-DOWjJi5-.js +0 -317
  174. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/projects-BBJc7h5_.js +0 -2
  175. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/session-B9sZaFKC.js +0 -1
  176. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/supercomputer-CX-LCL6Y.js +0 -24
  177. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/tabs-CvKQ-eas.js +0 -1
  178. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/toggle-CrzrwiDZ.js +0 -1
  179. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/transport-BgRfk-Qq.js +0 -69
  180. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/transport-bar-C9nqAfE2.js +0 -1
  181. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/typography-C5-w9LOu-kD3uLKkf.js +0 -1
  182. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/useOpenInteractionType-DbrQ6Ehu.js +0 -1
  183. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/useRenderElement-bbxXdYq0.js +0 -1
  184. package/node_modules/@higgsfield/higgsedit/dist/editor/chunks/writeback-support-BZfNpkmB.js +0 -1
  185. package/node_modules/@higgsfield/higgsedit/dist/editor/editor-Csn2_T_e.js +0 -293
  186. package/node_modules/@higgsfield/higgsedit/dist/export-settings.mjs +0 -75
  187. package/node_modules/@higgsfield/higgsedit/dist/history.mjs +0 -295
  188. package/node_modules/@higgsfield/higgsedit/dist/media-upload.mjs +0 -381
  189. package/node_modules/@higgsfield/higgsedit/dist/proxy.mjs +0 -170
@@ -3016,11 +3016,11 @@ var OPUS_FRAME_DURATION_TABLE = [
3016
3016
  ];
3017
3017
  var parseOpusTocByte = (packet) => {
3018
3018
  const config = packet[0] >> 3;
3019
- const code = packet[0] & 3;
3019
+ const code2 = packet[0] & 3;
3020
3020
  let frameCount;
3021
- if (code === 0) {
3021
+ if (code2 === 0) {
3022
3022
  frameCount = 1;
3023
- } else if (code === 1 || code === 2) {
3023
+ } else if (code2 === 1 || code2 === 2) {
3024
3024
  frameCount = 2;
3025
3025
  } else {
3026
3026
  frameCount = packet[1] & 63;
@@ -5616,21 +5616,21 @@ var createAes128CbcDecryptStream = (reader, getInit, close2) => {
5616
5616
  }
5617
5617
  const bytesToRead = sliceLength === requestedLength ? sliceLength - BLOCK_SIZE : sliceLength;
5618
5618
  const input = readBytes(nextSlice, bytesToRead);
5619
- const output = new Uint8Array(bytesToRead);
5619
+ const output2 = new Uint8Array(bytesToRead);
5620
5620
  for (let i = 0; i < bytesToRead; i += 16) {
5621
5621
  aesContext.in.set(input.subarray(i, i + 16));
5622
5622
  aesContext.decrypt();
5623
- output.set(aesContext.out, i);
5623
+ output2.set(aesContext.out, i);
5624
5624
  }
5625
5625
  if (bytesToRead < sliceLength) {
5626
- controller.enqueue(output);
5626
+ controller.enqueue(output2);
5627
5627
  pos += bytesToRead;
5628
5628
  } else {
5629
- const paddingLength = output[bytesToRead - 1];
5629
+ const paddingLength = output2[bytesToRead - 1];
5630
5630
  if (paddingLength === 0 || paddingLength > 16) {
5631
5631
  throw new Error("Invalid PKCS#7 padding. Incorrect key or corrupted data.");
5632
5632
  }
5633
- const trimmedOutput = output.subarray(0, bytesToRead - paddingLength);
5633
+ const trimmedOutput = output2.subarray(0, bytesToRead - paddingLength);
5634
5634
  controller.enqueue(trimmedOutput);
5635
5635
  controller.close();
5636
5636
  close2();
@@ -8597,15 +8597,15 @@ var decryptCtr = async (key, encryptionInfo, sampleEncryption, data) => {
8597
8597
  }
8598
8598
  }
8599
8599
  const plain = await cryptApply(cryptBuffer);
8600
- const output = new Uint8Array(data);
8600
+ const output2 = new Uint8Array(data);
8601
8601
  let readPos = 0;
8602
8602
  for (const range of cryptRanges) {
8603
8603
  for (const seg of range.perSubsample) {
8604
- output.set(plain.subarray(readPos, readPos + seg.length), seg.offset);
8604
+ output2.set(plain.subarray(readPos, readPos + seg.length), seg.offset);
8605
8605
  readPos += seg.length;
8606
8606
  }
8607
8607
  }
8608
- return output;
8608
+ return output2;
8609
8609
  };
8610
8610
  var decryptCbcs = (key, encryptionInfo, sampleEncryption, data) => {
8611
8611
  const ctx = new Aes128CbcContext();
@@ -8614,20 +8614,20 @@ var decryptCbcs = (key, encryptionInfo, sampleEncryption, data) => {
8614
8614
  const skipByteBlock = encryptionInfo.defaultSkipByteBlock;
8615
8615
  assert(cryptByteBlock !== null && skipByteBlock !== null);
8616
8616
  if (!sampleEncryption.subsamples) {
8617
- const output2 = new Uint8Array(data);
8617
+ const output3 = new Uint8Array(data);
8618
8618
  const numBlocks = Math.floor(data.length / 16);
8619
8619
  for (let b = 0; b < numBlocks; b++) {
8620
8620
  const off = b * 16;
8621
8621
  ctx.in.set(data.subarray(off, off + 16));
8622
8622
  ctx.decrypt();
8623
- output2.set(ctx.out, off);
8623
+ output3.set(ctx.out, off);
8624
8624
  }
8625
- return output2;
8625
+ return output3;
8626
8626
  }
8627
8627
  if (cryptByteBlock === 0 && skipByteBlock === 0) {
8628
8628
  throw new Error("cbcs with subsamples requires pattern encryption.");
8629
8629
  }
8630
- const output = new Uint8Array(data);
8630
+ const output2 = new Uint8Array(data);
8631
8631
  const cryptRanges = collectCryptRanges(sampleEncryption.subsamples, cryptByteBlock, skipByteBlock);
8632
8632
  const ivView = new DataView(sampleEncryption.iv.buffer, sampleEncryption.iv.byteOffset, 16);
8633
8633
  for (const range of cryptRanges) {
@@ -8641,11 +8641,11 @@ var decryptCbcs = (key, encryptionInfo, sampleEncryption, data) => {
8641
8641
  const offset = seg.offset + b * 16;
8642
8642
  ctx.in.set(data.subarray(offset, offset + 16));
8643
8643
  ctx.decrypt();
8644
- output.set(ctx.out, offset);
8644
+ output2.set(ctx.out, offset);
8645
8645
  }
8646
8646
  }
8647
8647
  }
8648
- return output;
8648
+ return output2;
8649
8649
  };
8650
8650
  var collectCryptRanges = (subsamples, cryptByteBlock, skipByteBlock) => {
8651
8651
  const ranges = [];
@@ -18552,11 +18552,11 @@ var getMediaTagAutoselect = (attributes) => {
18552
18552
  }
18553
18553
  throw new Error(`Invalid M3U8 file; #EXT-X-MEDIA AUTOSELECT attribute must be YES or NO, got "${value}".`);
18554
18554
  };
18555
- var preprocessLanguageCode = (code) => {
18556
- if (code === null) {
18555
+ var preprocessLanguageCode = (code2) => {
18556
+ if (code2 === null) {
18557
18557
  return UNDETERMINED_LANGUAGE;
18558
18558
  }
18559
- const languageSubtag = code.split("-")[0];
18559
+ const languageSubtag = code2.split("-")[0];
18560
18560
  if (!languageSubtag) {
18561
18561
  return UNDETERMINED_LANGUAGE;
18562
18562
  }
@@ -22713,11 +22713,11 @@ var colorAlphaMergerWorkerCode = () => {
22713
22713
  const width = color.visibleRect?.width ?? color.codedWidth;
22714
22714
  const height = color.visibleRect?.height ?? color.codedHeight;
22715
22715
  const pixelCount = width * height;
22716
- const output = new Uint8Array(pixelCount * 4);
22717
- await color.copyTo(output);
22716
+ const output2 = new Uint8Array(pixelCount * 4);
22717
+ await color.copyTo(output2);
22718
22718
  const alphaY = await readAlpha(alpha, width, height, 1);
22719
22719
  for (let i = 0, j = 3; i < pixelCount; i++, j += 4) {
22720
- output[j] = alphaY[i];
22720
+ output2[j] = alphaY[i];
22721
22721
  }
22722
22722
  const outputFormat = format === "RGBX" || format === "RGBA" ? "RGBA" : "BGRA";
22723
22723
  const init = {
@@ -22726,9 +22726,9 @@ var colorAlphaMergerWorkerCode = () => {
22726
22726
  codedHeight: height,
22727
22727
  timestamp: color.timestamp,
22728
22728
  duration: color.duration ?? void 0,
22729
- transfer: [output.buffer]
22729
+ transfer: [output2.buffer]
22730
22730
  };
22731
- return new VideoFrame(output, init);
22731
+ return new VideoFrame(output2, init);
22732
22732
  };
22733
22733
  const mergePlanarYuv = async (color, alpha, format) => {
22734
22734
  const width = color.visibleRect?.width ?? color.codedWidth;
@@ -22754,11 +22754,11 @@ var colorAlphaMergerWorkerCode = () => {
22754
22754
  const uvBytes = uvSamples * bytesPerSample;
22755
22755
  const aBytes = ySamples * bytesPerSample;
22756
22756
  const outputBytes = yBytes + 2 * uvBytes + aBytes;
22757
- const output = new Uint8Array(outputBytes);
22758
- await color.copyTo(output);
22757
+ const output2 = new Uint8Array(outputBytes);
22758
+ await color.copyTo(output2);
22759
22759
  const alphaY = await readAlpha(alpha, width, height, bytesPerSample);
22760
22760
  const aOffset = yBytes + 2 * uvBytes;
22761
- output.set(alphaY, aOffset);
22761
+ output2.set(alphaY, aOffset);
22762
22762
  const outputFormat = format.slice(0, 4) + "A" + format.slice(4);
22763
22763
  const init = {
22764
22764
  format: outputFormat,
@@ -22766,9 +22766,9 @@ var colorAlphaMergerWorkerCode = () => {
22766
22766
  codedHeight: height,
22767
22767
  timestamp: color.timestamp,
22768
22768
  duration: color.duration ?? void 0,
22769
- transfer: [output.buffer]
22769
+ transfer: [output2.buffer]
22770
22770
  };
22771
- return new VideoFrame(output, init);
22771
+ return new VideoFrame(output2, init);
22772
22772
  };
22773
22773
  const mergeNv12 = async (color, alpha) => {
22774
22774
  const width = color.visibleRect?.width ?? color.codedWidth;
@@ -22782,26 +22782,26 @@ var colorAlphaMergerWorkerCode = () => {
22782
22782
  cpuColorBuffer = new Uint8Array(sourceSize);
22783
22783
  }
22784
22784
  await color.copyTo(cpuColorBuffer);
22785
- const output = new Uint8Array(ySize + 2 * uvSize + ySize);
22786
- output.set(cpuColorBuffer.subarray(0, ySize), 0);
22785
+ const output2 = new Uint8Array(ySize + 2 * uvSize + ySize);
22786
+ output2.set(cpuColorBuffer.subarray(0, ySize), 0);
22787
22787
  const uOffset = ySize;
22788
22788
  const vOffset = ySize + uvSize;
22789
22789
  const uvStart = ySize;
22790
22790
  for (let i = 0; i < uvSize; i++) {
22791
- output[uOffset + i] = cpuColorBuffer[uvStart + i * 2];
22792
- output[vOffset + i] = cpuColorBuffer[uvStart + i * 2 + 1];
22791
+ output2[uOffset + i] = cpuColorBuffer[uvStart + i * 2];
22792
+ output2[vOffset + i] = cpuColorBuffer[uvStart + i * 2 + 1];
22793
22793
  }
22794
22794
  const alphaY = await readAlpha(alpha, width, height, 1);
22795
- output.set(alphaY, ySize + 2 * uvSize);
22795
+ output2.set(alphaY, ySize + 2 * uvSize);
22796
22796
  const init = {
22797
22797
  format: "I420A",
22798
22798
  codedWidth: width,
22799
22799
  codedHeight: height,
22800
22800
  timestamp: color.timestamp,
22801
22801
  duration: color.duration ?? void 0,
22802
- transfer: [output.buffer]
22802
+ transfer: [output2.buffer]
22803
22803
  };
22804
- return new VideoFrame(output, init);
22804
+ return new VideoFrame(output2, init);
22805
22805
  };
22806
22806
  const readAlpha = async (alpha, width, height, bytesPerSample) => {
22807
22807
  const size = alpha.allocationSize();
@@ -25681,10 +25681,10 @@ var Id3V2Reader = class {
25681
25681
 
25682
25682
  // ../../node_modules/.pnpm/mediabunny@1.61.0/node_modules/mediabunny/dist/modules/src/muxer.js
25683
25683
  var Muxer = class {
25684
- constructor(output) {
25684
+ constructor(output2) {
25685
25685
  this.mutex = new AsyncMutex();
25686
25686
  this.trackTimestampInfo = /* @__PURE__ */ new WeakMap();
25687
- this.output = output;
25687
+ this.output = output2;
25688
25688
  }
25689
25689
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
25690
25690
  onTrackClose(track) {
@@ -27470,13 +27470,13 @@ var SUBTITLE_CODEC_TO_BOX_NAME = {
27470
27470
  var SUBTITLE_CODEC_TO_CONFIGURATION_BOX = {
27471
27471
  webvtt: vttC
27472
27472
  };
27473
- var getLanguageCodeInt = (code) => {
27474
- assert(code.length === 3);
27473
+ var getLanguageCodeInt = (code2) => {
27474
+ assert(code2.length === 3);
27475
27475
  ;
27476
27476
  let language = 0;
27477
27477
  for (let i = 0; i < 3; i++) {
27478
27478
  language <<= 5;
27479
- language += code.charCodeAt(i) - 96;
27479
+ language += code2.charCodeAt(i) - 96;
27480
27480
  }
27481
27481
  return language;
27482
27482
  };
@@ -27977,8 +27977,8 @@ var presentationSpan = (trackData) => {
27977
27977
  return maxEndTimestamp - minTimestamp;
27978
27978
  };
27979
27979
  var IsobmffMuxer = class extends Muxer {
27980
- constructor(output, format) {
27981
- super(output);
27980
+ constructor(output2, format) {
27981
+ super(output2);
27982
27982
  this.writer = null;
27983
27983
  this.boxWriter = null;
27984
27984
  this.initWriter = null;
@@ -30044,8 +30044,8 @@ var IsobmffOutputFormat = class extends OutputFormat {
30044
30044
  return "full";
30045
30045
  }
30046
30046
  /** @internal */
30047
- _createMuxer(output) {
30048
- return new IsobmffMuxer(output, this);
30047
+ _createMuxer(output2) {
30048
+ return new IsobmffMuxer(output2, this);
30049
30049
  }
30050
30050
  /** @internal */
30051
30051
  _isFragmentedIsobmff() {
@@ -30161,9 +30161,9 @@ var MovOutputFormat = class extends IsobmffOutputFormat {
30161
30161
  var ALL_TRACK_TYPES = ["video", "audio", "subtitle"];
30162
30162
  var OutputTrack = class _OutputTrack {
30163
30163
  /** @internal */
30164
- constructor(id, output, type, source, metadata) {
30164
+ constructor(id, output2, type, source, metadata) {
30165
30165
  this.id = id;
30166
- this.output = output;
30166
+ this.output = output2;
30167
30167
  this.type = type;
30168
30168
  this.source = source;
30169
30169
  this.metadata = metadata;
@@ -30208,20 +30208,20 @@ var OutputTrack = class _OutputTrack {
30208
30208
  };
30209
30209
  var OutputVideoTrack = class extends OutputTrack {
30210
30210
  /** @internal */
30211
- constructor(id, output, source, metadata) {
30212
- super(id, output, "video", source, metadata);
30211
+ constructor(id, output2, source, metadata) {
30212
+ super(id, output2, "video", source, metadata);
30213
30213
  }
30214
30214
  };
30215
30215
  var OutputAudioTrack = class extends OutputTrack {
30216
30216
  /** @internal */
30217
- constructor(id, output, source, metadata) {
30218
- super(id, output, "audio", source, metadata);
30217
+ constructor(id, output2, source, metadata) {
30218
+ super(id, output2, "audio", source, metadata);
30219
30219
  }
30220
30220
  };
30221
30221
  var OutputSubtitleTrack = class extends OutputTrack {
30222
30222
  /** @internal */
30223
- constructor(id, output, source, metadata) {
30224
- super(id, output, "subtitle", source, metadata);
30223
+ constructor(id, output2, source, metadata) {
30224
+ super(id, output2, "subtitle", source, metadata);
30225
30225
  }
30226
30226
  };
30227
30227
  var OutputTrackGroup = class _OutputTrackGroup {
@@ -30715,7 +30715,7 @@ async function createWebCodecsEncoder(canvas2, opts) {
30715
30715
  if (problem) throw new Error(problem);
30716
30716
  const { codec, full } = choose(opts.depth, opts.codec);
30717
30717
  const target2 = new StreamTarget(new WritableStream({ write: (chunk) => opts.write(chunk.position, chunk.data) }), { chunked: true, chunkSize: 4 << 20 });
30718
- const output = new Output({ format: new Mp4OutputFormat({ fastStart: false }), target: target2 });
30718
+ const output2 = new Output({ format: new Mp4OutputFormat({ fastStart: false }), target: target2 });
30719
30719
  let configured;
30720
30720
  const source = new CanvasSource(canvas2, {
30721
30721
  codec,
@@ -30726,16 +30726,16 @@ async function createWebCodecsEncoder(canvas2, opts) {
30726
30726
  configured = config.codec;
30727
30727
  }
30728
30728
  });
30729
- output.addVideoTrack(source, { frameRate: opts.fps });
30730
- await output.start();
30729
+ output2.addVideoTrack(source, { frameRate: opts.fps });
30730
+ await output2.start();
30731
30731
  const duration = 1 / opts.fps;
30732
30732
  return {
30733
30733
  get codec() {
30734
30734
  return configured;
30735
30735
  },
30736
30736
  add: (index) => source.add(index * duration, duration),
30737
- finish: () => output.finalize(),
30738
- cancel: () => output.cancel()
30737
+ finish: () => output2.finalize(),
30738
+ cancel: () => output2.cancel()
30739
30739
  };
30740
30740
  }
30741
30741
 
@@ -30880,7 +30880,7 @@ function captionBoxOrigin(look2, caption, box2, parent, x, y) {
30880
30880
  return { x: across + num(caption.offsetX, 0), y: down + num(caption.offsetY, 0) };
30881
30881
  }
30882
30882
 
30883
- // ../../node_modules/.pnpm/koota@0.6.6_@types+react@19.2.17_react@19.2.8/node_modules/koota/dist/chunk-ZWIGMIL4.js
30883
+ // ../../node_modules/.pnpm/koota@0.6.6_@types+react@19.2.18_react@19.2.8/node_modules/koota/dist/chunk-ZWIGMIL4.js
30884
30884
  var $internal = /* @__PURE__ */ Symbol.for("koota.internal");
30885
30885
  var WORLD_ID_BITS = 4;
30886
30886
  var GENERATION_BITS = 8;
@@ -33570,7 +33570,9 @@ var Node = trait(() => ({
33570
33570
  key: "",
33571
33571
  name: void 0,
33572
33572
  /** Props bound to accessors (`x={() => ...}`): code-driven at runtime. */
33573
- accessors: /* @__PURE__ */ new Set()
33573
+ accessors: /* @__PURE__ */ new Set(),
33574
+ /** Project module whose JSX created it (set by the project loader). */
33575
+ file: void 0
33574
33576
  }));
33575
33577
  var Hierarchy = trait(() => ({
33576
33578
  parent: null,
@@ -33602,7 +33604,11 @@ var Offset = trait(() => ({
33602
33604
  offsetY: void 0
33603
33605
  }));
33604
33606
  var Opacity = trait(() => ({ opacity: void 0 }));
33605
- var Visibility = trait(() => ({ hidden: void 0 }));
33607
+ var Visibility = trait(() => ({
33608
+ hidden: void 0,
33609
+ /** Editor preview from a cached render: `false` never, `true` always, unset when heavy (prerender.ts). */
33610
+ prerender: void 0
33611
+ }));
33606
33612
  var Fill = trait(() => ({ fill: void 0 }));
33607
33613
  var Shape = trait(() => ({ cornerRadius: void 0 }));
33608
33614
  var TextStyle = trait(() => ({
@@ -33705,6 +33711,7 @@ var PROP_TRAITS = {
33705
33711
  ...Object.fromEntries(TRANSFORM_PROPS.map((p) => [p, Transform])),
33706
33712
  opacity: Opacity,
33707
33713
  hidden: Visibility,
33714
+ prerender: Visibility,
33708
33715
  fill: Fill,
33709
33716
  cornerRadius: Shape,
33710
33717
  fontSize: TextStyle,
@@ -35963,6 +35970,19 @@ function findStage(world) {
35963
35970
  return world.query(Node, Hierarchy).find((e) => e.get(Node).tag === "stage" && parentOf(e) === null);
35964
35971
  }
35965
35972
  var PROP_OWNERS = [.../* @__PURE__ */ new Set([...Object.values(PROP_TRAITS), ...Object.values(SCENE_PROPS), ...Object.values(CAPTION_PROPS), ...Object.values(RANGE_PROPS)])];
35973
+ function readProps(entity) {
35974
+ const out = {};
35975
+ for (const t of PROP_OWNERS) {
35976
+ const v = entity.get(t);
35977
+ if (!v) continue;
35978
+ for (const [k, val] of Object.entries(v)) if (val !== void 0) out[k] = val;
35979
+ }
35980
+ const extra = entity.get(Extra);
35981
+ if (extra) Object.assign(out, extra.props);
35982
+ const text = entity.get(TextContent);
35983
+ if (text) out.text = text.text;
35984
+ return out;
35985
+ }
35966
35986
  function findByKey(world, key) {
35967
35987
  return world.query(Node).find((e) => e.get(Node).key === key);
35968
35988
  }
@@ -35986,13 +36006,14 @@ function definedOf(style) {
35986
36006
  for (const field of ["fontFamily", "fontWeight", "fontStyle"]) if (style?.[field] !== void 0) Object.assign(out, { [field]: style[field] });
35987
36007
  return out;
35988
36008
  }
35989
- function usedFonts(world) {
36009
+ function usedFonts(world, includes) {
35990
36010
  const out = /* @__PURE__ */ new Map();
35991
36011
  const add = (families, weight, style) => {
35992
36012
  if (!families) return;
35993
36013
  for (const family of familyNames(families)) out.set(`${family.toLowerCase()}|${weight}|${style}`, { family, weight, style });
35994
36014
  };
35995
36015
  for (const e of world.query(TextStyle)) {
36016
+ if (includes && !includes(e)) continue;
35996
36017
  const s = e.get(TextStyle);
35997
36018
  const tag2 = e.get(Node)?.tag;
35998
36019
  if (tag2 === "captions") {
@@ -36008,10 +36029,11 @@ function usedFonts(world) {
36008
36029
  }
36009
36030
  return [...out.values()];
36010
36031
  }
36011
- function htmlFonts(world) {
36032
+ function htmlFonts(world, includes) {
36012
36033
  if (typeof getComputedStyle === "undefined") return [];
36013
36034
  const out = /* @__PURE__ */ new Map();
36014
36035
  for (const e of world.query(Surface)) {
36036
+ if (includes && !includes(e)) continue;
36015
36037
  const root = e.get(Node)?.tag === "html" ? e.get(Surface).root : null;
36016
36038
  if (!root) continue;
36017
36039
  for (const el of [root, ...root.querySelectorAll("*")]) {
@@ -36238,6 +36260,39 @@ function estimateFps(timestamps) {
36238
36260
  return fps;
36239
36261
  }
36240
36262
 
36263
+ // ../../packages/runtime/src/media/luma-matte.ts
36264
+ var isMaskFile = (src) => /\.mask$/i.test(src);
36265
+ function lumaMatteIndex(facts, sourceTime, local) {
36266
+ const ts = facts?.timestamps;
36267
+ if (!facts || !ts || ts.length === 0) return -1;
36268
+ return frameIndexAt(ts, sourceTime ?? ts[0] + local, facts.fps);
36269
+ }
36270
+ var KEEP = 4;
36271
+ var converted = /* @__PURE__ */ new WeakMap();
36272
+ var scratch;
36273
+ function lumaToAlpha(handle, picture, width, height) {
36274
+ const list = converted.get(handle) ?? [];
36275
+ converted.set(handle, list);
36276
+ const hit = list.find((c) => c.picture === picture && c.alpha.width === width && c.alpha.height === height);
36277
+ if (hit) return hit.alpha;
36278
+ if (!scratch || scratch.canvas.width !== width || scratch.canvas.height !== height) {
36279
+ scratch = new OffscreenCanvas(width, height).getContext("2d", { willReadFrequently: true });
36280
+ }
36281
+ scratch.clearRect(0, 0, width, height);
36282
+ scratch.drawImage(picture, 0, 0, width, height);
36283
+ const image = scratch.getImageData(0, 0, width, height);
36284
+ const d = image.data;
36285
+ for (let i = 0; i < d.length; i += 4) {
36286
+ d[i + 3] = 54 * d[i] + 183 * d[i + 1] + 19 * d[i + 2] + 128 >> 8;
36287
+ d[i] = d[i + 1] = d[i + 2] = 255;
36288
+ }
36289
+ const alpha = new OffscreenCanvas(width, height);
36290
+ alpha.getContext("2d").putImageData(image, 0, 0);
36291
+ list.unshift({ picture, alpha });
36292
+ if (list.length > KEEP) list.length = KEEP;
36293
+ return alpha;
36294
+ }
36295
+
36241
36296
  // ../../packages/runtime/src/keyframes.ts
36242
36297
  function cubicBezier(x1, y1, x2, y2) {
36243
36298
  const cx = 3 * x1;
@@ -36523,6 +36578,9 @@ function watchFonts() {
36523
36578
  const fonts = globalThis.document?.fonts;
36524
36579
  fonts?.addEventListener("loadingdone", () => cache2.clear());
36525
36580
  }
36581
+ function fontsChanged() {
36582
+ cache2.clear();
36583
+ }
36526
36584
  var num2 = (v, fallback) => typeof v === "number" && Number.isFinite(v) ? v : fallback;
36527
36585
  var caseOf2 = (text, textCase) => textCase === "upper" ? text.toUpperCase() : textCase === "lower" ? text.toLowerCase() : text;
36528
36586
  function fontString(size, weight, style, family) {
@@ -36754,18 +36812,18 @@ function syncLinks(world) {
36754
36812
  }
36755
36813
  return out;
36756
36814
  }
36757
- function clockStart(world, parent, clock) {
36815
+ function clockStart(world, parent, clock2) {
36758
36816
  let t = 0;
36759
36817
  for (let e = parent; e; e = parentOf(e)) {
36760
36818
  const tag2 = e.get(Node).tag;
36761
- if (tag2 === "scene" || tag2 === "group") t += parseTime(e.get(Timing)?.start, clock.fpsUnder(world, parentOf(e))) ?? 0;
36819
+ if (tag2 === "scene" || tag2 === "group") t += parseTime(e.get(Timing)?.start, clock2.fpsUnder(world, parentOf(e))) ?? 0;
36762
36820
  }
36763
36821
  return t;
36764
36822
  }
36765
- function syncedSourceIn(world, entity, fps, clock) {
36766
- return syncedPlacement(world, entity, fps, clock)?.sourceIn ?? parseTime(entity.get(Timing)?.sourceIn, fps) ?? 0;
36823
+ function syncedSourceIn(world, entity, fps, clock2) {
36824
+ return syncedPlacement(world, entity, fps, clock2)?.sourceIn ?? parseTime(entity.get(Timing)?.sourceIn, fps) ?? 0;
36767
36825
  }
36768
- function syncedPlacement(world, entity, fps, clock) {
36826
+ function syncedPlacement(world, entity, fps, clock2) {
36769
36827
  const syncTo = entity.get(Sync)?.syncTo;
36770
36828
  if (!syncTo || !isSound(entity)) return void 0;
36771
36829
  const graph = syncGraph(world);
@@ -36776,15 +36834,15 @@ function syncedPlacement(world, entity, fps, clock) {
36776
36834
  const offset = info?.offsets.get(syncPair(src, target2.get(Media).src));
36777
36835
  if (offset === void 0) return void 0;
36778
36836
  const targetParent = parentOf(target2);
36779
- const targetFps = clock.fpsUnder(world, targetParent);
36780
- const targetSpan = clock.span(world, target2, targetFps);
36781
- const shift = clockStart(world, targetParent, clock);
36837
+ const targetFps = clock2.fpsUnder(world, targetParent);
36838
+ const targetSpan = clock2.span(world, target2, targetFps);
36839
+ const shift = clockStart(world, targetParent, clock2);
36782
36840
  const window2 = { from: shift + targetSpan.start, to: shift + targetSpan.end };
36783
- const zero = window2.from + (offset - syncedSourceIn(world, target2, targetFps, clock)) / clock.speed(target2);
36784
- const speed = clock.speed(entity);
36841
+ const zero = window2.from + (offset - syncedSourceIn(world, target2, targetFps, clock2)) / clock2.speed(target2);
36842
+ const speed = clock2.speed(entity);
36785
36843
  const duration = info?.durations.get(src);
36786
36844
  const recording = { from: zero, to: duration === void 0 ? Infinity : zero + duration / speed };
36787
- const own = clockStart(world, parentOf(entity), clock);
36845
+ const own = clockStart(world, parentOf(entity), clock2);
36788
36846
  const timing = entity.get(Timing);
36789
36847
  const authoredIn = parseTime(timing?.sourceIn, fps);
36790
36848
  const authoredEnd = parseTime(timing?.end, fps);
@@ -36814,17 +36872,18 @@ function invert(m) {
36814
36872
  return [m[3] * id, -m[1] * id, -m[2] * id, m[0] * id, (m[2] * m[5] - m[3] * m[4]) * id, (m[1] * m[4] - m[0] * m[5]) * id];
36815
36873
  }
36816
36874
  var sceneFps = (scene) => scene?.get(SceneConfig)?.fps ?? DEFAULT_FPS;
36817
- // Capture selection scopes composition and pixels, but root timing stays in the
36818
- // ordinary editor's stage clock, independent of the selected scene's own fps.
36819
- var captureSceneIds = new WeakMap();
36875
+ var captureScenes = /* @__PURE__ */ new WeakMap();
36876
+ function setCaptureScene(world, sceneId) {
36877
+ captureScenes.set(world, sceneId);
36878
+ }
36820
36879
  function stageFps(world) {
36821
36880
  const stage = findStage(world);
36822
- return sceneFps(stage ? childrenOf(stage).find((e) => e.get(Node).tag === "scene") : undefined);
36881
+ return sceneFps(stage ? childrenOf(stage).find((entity) => entity.get(Node).tag === "scene") : void 0);
36823
36882
  }
36824
36883
  function rootScenes(world) {
36825
36884
  const stage = findStage(world);
36826
- const sceneId = captureSceneIds.get(world);
36827
- return stage ? childrenOf(stage).filter((e) => e.get(Node).tag === "scene" && (sceneId === undefined || e.get(Node).key === sceneId || e.get(Node).id === sceneId)) : [];
36885
+ const selected = captureScenes.get(world);
36886
+ return stage ? childrenOf(stage).filter((e) => e.get(Node).tag === "scene" && (selected === void 0 || e.get(Node).key === selected || e.get(Node).id === selected)) : [];
36828
36887
  }
36829
36888
  function span(world, entity, fps) {
36830
36889
  const synced = syncedPlacement(world, entity, fps, SYNC_CLOCK);
@@ -36876,16 +36935,16 @@ function mediaSpeed(entity) {
36876
36935
  function localTime(world, entity, time) {
36877
36936
  const chain = [];
36878
36937
  for (let e = entity; e && e.get(Node).tag !== "stage"; e = parentOf(e)) chain.unshift(e);
36879
- let clock = time;
36938
+ let clock2 = time;
36880
36939
  let fps = stageFps(world);
36881
36940
  for (const e of chain) {
36882
36941
  const start = span(world, e, fps).start;
36883
36942
  const tag2 = e.get(Node).tag;
36884
- if (e === entity) return clock - start;
36943
+ if (e === entity) return clock2 - start;
36885
36944
  if (tag2 === "scene") fps = sceneFps(e);
36886
- if (tag2 === "scene" || tag2 === "group") clock -= start;
36945
+ if (tag2 === "scene" || tag2 === "group") clock2 -= start;
36887
36946
  }
36888
- return clock;
36947
+ return clock2;
36889
36948
  }
36890
36949
  function composition(world) {
36891
36950
  const scenes = rootScenes(world);
@@ -36893,8 +36952,7 @@ function composition(world) {
36893
36952
  const config = scene?.get(SceneConfig);
36894
36953
  const fps = sceneFps(scene);
36895
36954
  let duration = 0;
36896
- const rootFps = stageFps(world);
36897
- for (const s of scenes) duration = Math.max(duration, span(world, s, rootFps).end);
36955
+ for (const s of scenes) duration = Math.max(duration, span(world, s, stageFps(world)).end);
36898
36956
  return {
36899
36957
  scene,
36900
36958
  width: config?.width ?? DEFAULT_SCENE.width,
@@ -37049,14 +37107,11 @@ function textPivot(entity, text) {
37049
37107
  const fallback = text.x0 === 0 ? 0 : align === "center" ? 0.5 : 1;
37050
37108
  return [text.x0 + num3(resolved(entity, "anchorX"), fallback) * text.width, num3(resolved(entity, "anchorY"), 0) * text.height];
37051
37109
  }
37052
- function evaluate(world, time, onlyScene) {
37110
+ function evaluate(world, time) {
37053
37111
  const comp = composition(world);
37054
- const sceneConfig = onlyScene?.get(SceneConfig);
37055
- const sourceFps = stageFps(world);
37056
- const sourceEnd = onlyScene ? span(world, onlyScene, sourceFps).end : comp.duration;
37057
37112
  const stage = findStage(world);
37058
37113
  if (!stage) return comp;
37059
- const root = { time, length: sourceEnd, fps: sourceFps, matrix: [1, 0, 0, 1, 0, 0], opacity: 1, width: sceneConfig?.width ?? comp.width, height: sceneConfig?.height ?? comp.height, baseWidth: sceneConfig?.width ?? comp.width, baseHeight: sceneConfig?.height ?? comp.height, active: true };
37114
+ const root = { time, length: comp.duration, fps: stageFps(world), matrix: [1, 0, 0, 1, 0, 0], opacity: 1, width: comp.width, height: comp.height, baseWidth: comp.width, baseHeight: comp.height, active: true };
37060
37115
  const timeWalk = (entity, frame, held = false) => {
37061
37116
  const next = timeSystem(world, entity, frame, held);
37062
37117
  const crossings = entity.get(Crossings);
@@ -37067,29 +37122,47 @@ function evaluate(world, time, onlyScene) {
37067
37122
  }
37068
37123
  const crossing = new Set(crossings?.active.flatMap((c) => [c.left, c.right]));
37069
37124
  for (const child of childrenOf(entity)) {
37070
- if (entity === stage && onlyScene && child !== onlyScene) deactivate(child);
37125
+ if (entity === stage && captureScenes.has(world) && child !== comp.scene) deactivate(child);
37071
37126
  else timeWalk(child, next, crossing.has(child));
37072
37127
  }
37073
37128
  };
37074
37129
  timeWalk(stage, root);
37075
37130
  motionSystem(world);
37076
- const transformWalk = (entity, frame) => {
37077
- if (!entity.get(Computed).active) return;
37078
- const next = transformSystem(entity, frame);
37079
- const children2 = childrenOf(entity);
37080
- children2.forEach((child, i) => {
37081
- const matrix = layersAbove(entity, children2, i).reduce((m, layer) => multiply(m, localMatrix(layer, next).local), next.matrix);
37082
- transformWalk(child, { ...next, matrix });
37083
- });
37084
- };
37085
37131
  transformWalk(stage, root);
37086
37132
  return comp;
37087
37133
  }
37088
- function clips(world, onlyScene) {
37134
+ function transformWalk(entity, frame) {
37135
+ if (!entity.get(Computed).active) return;
37136
+ const next = transformSystem(entity, frame);
37137
+ const children2 = childrenOf(entity);
37138
+ children2.forEach((child, i) => {
37139
+ const matrix = layersAbove(entity, children2, i).reduce((m, layer) => multiply(m, localMatrix(layer, next).local), next.matrix);
37140
+ transformWalk(child, { ...next, matrix });
37141
+ });
37142
+ }
37143
+ function isolate(entity) {
37144
+ const parent = parentOf(entity);
37145
+ const pc = parent?.get(Computed);
37146
+ if (!parent || !pc) return;
37147
+ const scene = parent.get(Node).tag === "scene";
37148
+ const width = pc.width;
37149
+ const height = pc.height;
37150
+ transformWalk(entity, {
37151
+ time: 0,
37152
+ length: 0,
37153
+ fps: pc.fps,
37154
+ matrix: [1, 0, 0, 1, 0, 0],
37155
+ opacity: 1,
37156
+ width,
37157
+ height,
37158
+ baseWidth: scene ? width : authoredSize(parent, "width", width),
37159
+ baseHeight: scene ? height : authoredSize(parent, "height", height),
37160
+ active: true
37161
+ });
37162
+ }
37163
+ function clips(world) {
37089
37164
  const out = [];
37090
37165
  const comp = composition(world);
37091
- const rootFps = stageFps(world);
37092
- if (onlyScene) comp.duration = span(world, onlyScene, rootFps).end;
37093
37166
  const visit = (entity, origin, fps, depth3, scene) => {
37094
37167
  const node = entity.get(Node);
37095
37168
  if (node.tag === "textRange" || node.tag === "shaderPaint") return;
@@ -37098,21 +37171,20 @@ function clips(world, onlyScene) {
37098
37171
  const end = Number.isFinite(s.end) ? origin + s.end : origin + comp.duration;
37099
37172
  out.push({ key: node.key, id: node.id, tag: node.tag, start, end: Math.min(end, Math.max(start, comp.duration)), depth: depth3, scene });
37100
37173
  const isScene = node.tag === "scene";
37101
- const clock = isScene || node.tag === "group" ? start : origin;
37174
+ const clock2 = isScene || node.tag === "group" ? start : origin;
37102
37175
  for (const child of childrenOf(entity)) {
37103
- visit(child, clock, isScene ? sceneFps(entity) : fps, depth3 + 1, isScene ? node.key : scene);
37176
+ visit(child, clock2, isScene ? sceneFps(entity) : fps, depth3 + 1, isScene ? node.key : scene);
37104
37177
  }
37105
37178
  };
37106
- for (const scene of onlyScene ? [onlyScene] : rootScenes(world)) visit(scene, 0, rootFps, 0, void 0);
37179
+ for (const scene of rootScenes(world)) visit(scene, 0, stageFps(world), 0, void 0);
37107
37180
  return out;
37108
37181
  }
37109
37182
  function hiddenInTree(entity) {
37110
37183
  for (let e = entity; e; e = parentOf(e)) if (e.get(Visibility)?.hidden === true) return true;
37111
37184
  return false;
37112
37185
  }
37113
- function audioClips(world, onlyScene) {
37114
- const spans = new Map(clips(world, onlyScene).map((c) => [c.key, c]));
37115
- const fps = composition(world).fps;
37186
+ function audioClips(world) {
37187
+ const spans = new Map(clips(world).map((c) => [c.key, c]));
37116
37188
  const out = [];
37117
37189
  for (const e of world.query(Media, Node)) {
37118
37190
  const tag2 = e.get(Node).tag;
@@ -37125,7 +37197,7 @@ function audioClips(world, onlyScene) {
37125
37197
  src: media.src,
37126
37198
  start: clip.start,
37127
37199
  end: clip.end,
37128
- sourceIn: sourceInOf(world, e, onlyScene ? fpsUnder(world, e) : fps),
37200
+ sourceIn: sourceInOf(world, e, fpsUnder(world, parentOf(e))),
37129
37201
  volume: media.volume ?? 1,
37130
37202
  fadeIn: Math.max(0, media.fadeIn ?? 0),
37131
37203
  fadeOut: Math.max(0, media.fadeOut ?? 0),
@@ -37251,23 +37323,67 @@ async function htmlReady(entity) {
37251
37323
  }
37252
37324
  var repaintListeners = /* @__PURE__ */ new Set();
37253
37325
  var repaintPending = false;
37326
+ var pendingPaints = /* @__PURE__ */ new Set();
37327
+ var contentKeys = /* @__PURE__ */ new Set();
37328
+ var rootKeys = /* @__PURE__ */ new WeakMap();
37329
+ var pendingFonts = /* @__PURE__ */ new WeakMap();
37254
37330
  var watched = /* @__PURE__ */ new WeakSet();
37255
- function requestRepaint() {
37256
- if (repaintPending || repaintListeners.size === 0) return;
37331
+ function requestRepaint(root, content = false) {
37332
+ if (repaintListeners.size === 0) return;
37333
+ if (root) {
37334
+ pendingPaints.add(root);
37335
+ const key = content && rootKeys.get(root);
37336
+ if (key) contentKeys.add(key);
37337
+ }
37338
+ if (repaintPending) return;
37257
37339
  repaintPending = true;
37258
37340
  void afterPaint().then(() => {
37259
37341
  repaintPending = false;
37260
- for (const listener of repaintListeners) listener();
37342
+ pendingPaints.clear();
37343
+ const changed = [...contentKeys];
37344
+ contentKeys.clear();
37345
+ for (const listener of repaintListeners) listener(changed);
37261
37346
  });
37262
37347
  }
37263
37348
  var pins = /* @__PURE__ */ new WeakMap();
37349
+ function withHtmlClock(world, update) {
37350
+ const roots = world.query(Surface).map((entity) => entity.get(Surface).root).filter((root) => !!root && pins.has(root));
37351
+ const drain = (content) => {
37352
+ for (const root of roots) {
37353
+ const p = pins.get(root);
37354
+ if (!p.observer.takeRecords().length) continue;
37355
+ p.list = null;
37356
+ p.changed = true;
37357
+ if (content) {
37358
+ p.at = /* @__PURE__ */ new WeakMap();
37359
+ requestRepaint(root, true);
37360
+ }
37361
+ }
37362
+ };
37363
+ drain(true);
37364
+ try {
37365
+ return update();
37366
+ } finally {
37367
+ drain(false);
37368
+ }
37369
+ }
37264
37370
  function watch(root) {
37265
37371
  if (watched.has(root)) return;
37266
37372
  watched.add(root);
37267
- const observer = new MutationObserver(requestRepaint);
37373
+ const observer = new MutationObserver(() => {
37374
+ const p = pins.get(root);
37375
+ if (p) {
37376
+ p.list = null;
37377
+ p.at = /* @__PURE__ */ new WeakMap();
37378
+ p.changed = true;
37379
+ }
37380
+ requestRepaint(root, true);
37381
+ });
37382
+ root.addEventListener("load", () => requestRepaint(root), true);
37383
+ root.addEventListener("error", () => requestRepaint(root), true);
37268
37384
  observer.observe(root, { subtree: true, childList: true, attributes: true, characterData: true });
37269
- pins.set(root, { observer, list: null, at: /* @__PURE__ */ new WeakMap() });
37270
- requestRepaint();
37385
+ pins.set(root, { observer, list: null, at: /* @__PURE__ */ new WeakMap(), changed: false });
37386
+ requestRepaint(root);
37271
37387
  }
37272
37388
  function liveAnimations(root) {
37273
37389
  const p = pins.get(root);
@@ -37275,16 +37391,23 @@ function liveAnimations(root) {
37275
37391
  if (p.observer.takeRecords().length) {
37276
37392
  p.list = null;
37277
37393
  p.at = /* @__PURE__ */ new WeakMap();
37278
- requestRepaint();
37394
+ p.changed = true;
37395
+ requestRepaint(root, true);
37279
37396
  }
37280
37397
  return p.list ??= root.getAnimations({ subtree: true });
37281
37398
  }
37282
37399
  function pinLive(root, local) {
37283
37400
  const p = pins.get(root);
37284
- if (!p) return pinAnimations(root, local);
37401
+ if (!p) {
37402
+ const moved2 = pinAnimations(root, local);
37403
+ return { changed: moved2, moved: moved2 };
37404
+ }
37285
37405
  const at = local * 1e3;
37286
37406
  let moved = pinSmil(root, local);
37287
- for (const animation of liveAnimations(root)) {
37407
+ const list = liveAnimations(root);
37408
+ const changed = p.changed;
37409
+ p.changed = false;
37410
+ for (const animation of list) {
37288
37411
  const was = p.at.get(animation);
37289
37412
  if (was === at) continue;
37290
37413
  if (typeof CSSTransition !== "undefined" && animation instanceof CSSTransition) {
@@ -37298,7 +37421,7 @@ function pinLive(root, local) {
37298
37421
  p.at.set(animation, at);
37299
37422
  moved = true;
37300
37423
  }
37301
- return moved;
37424
+ return { changed: changed || moved, moved };
37302
37425
  }
37303
37426
  var KEYFRAME_META = /* @__PURE__ */ new Set(["offset", "computedOffset", "easing", "composite"]);
37304
37427
  var kebab = (p) => p.startsWith("--") ? p : p.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
@@ -37378,12 +37501,13 @@ function inlineImage(img) {
37378
37501
  const src = img.currentSrc || img.src;
37379
37502
  if (!src || src.startsWith("data:")) return null;
37380
37503
  if (inlined.has(src)) return src;
37381
- const entry = { lo: null, hi: null };
37504
+ const entry = { lo: null, hi: null, pending: true };
37382
37505
  inlined.set(src, entry);
37383
37506
  const [lo, hi] = [inlineSize(img, 1), inlineSize(img, density())];
37384
37507
  void encodeImage(img, src, hi === lo ? [lo] : [lo, hi]).then(([small, large]) => {
37385
37508
  entry.lo = small ?? null;
37386
37509
  entry.hi = large ?? entry.lo;
37510
+ entry.pending = false;
37387
37511
  requestRepaint();
37388
37512
  });
37389
37513
  return src;
@@ -37460,6 +37584,7 @@ function decode(sketch) {
37460
37584
  const image = new Image();
37461
37585
  const done = (ok) => {
37462
37586
  sketch.decoding = false;
37587
+ sketch.settledKey = job.key;
37463
37588
  if (ok) {
37464
37589
  const raster = sketch.shown ?? document.createElement("canvas");
37465
37590
  raster.width = job.width;
@@ -37476,12 +37601,13 @@ function decode(sketch) {
37476
37601
  image.addEventListener("error", () => done(false));
37477
37602
  image.src = job.url;
37478
37603
  }
37479
- function drawSketch(ctx, root, w, h, k) {
37480
- const { markup: frozen, images } = frozenMarkup(root);
37604
+ function drawSketch(ctx, root, w, h, k, changed) {
37605
+ let sketch = sketches.get(root);
37606
+ if (!sketch) sketches.set(root, sketch = { key: "", settledKey: "", base: "", settle: null, shown: null, frozen: null, decoding: false, next: null });
37607
+ if (changed || !sketch.frozen) sketch.frozen = frozenMarkup(root);
37608
+ const { markup: frozen, images } = sketch.frozen;
37481
37609
  const [pw, ph] = [Math.ceil(w * k), Math.ceil(h * k)];
37482
37610
  const base = `${pw}x${ph}:${frozen}`;
37483
- let sketch = sketches.get(root);
37484
- if (!sketch) sketches.set(root, sketch = { key: "", base: "", settle: null, shown: null, decoding: false, next: null });
37485
37611
  const still = sketch.base === base;
37486
37612
  sketch.base = base;
37487
37613
  const urls = images.map((src) => {
@@ -37503,17 +37629,37 @@ function drawSketch(ctx, root, w, h, k) {
37503
37629
  decode(sketch);
37504
37630
  }
37505
37631
  if (sketch.shown) ctx.drawImage(sketch.shown, 0, 0, w, h);
37632
+ return sketch.settledKey === sketch.key && !sketch.decoding && !sketch.next && !sketch.settle && !images.some((src) => inlined.get(src)?.pending);
37506
37633
  }
37507
37634
  function drawHtml(ctx, entity, k, mode) {
37508
37635
  const { canvas: host, root } = entity.get(Surface);
37509
37636
  const c = entity.get(Computed);
37510
- if (!(host instanceof HTMLCanvasElement) || !root || !(c.width > 0) || !(c.height > 0)) return;
37637
+ if (!(host instanceof HTMLCanvasElement) || !root || !(c.width > 0) || !(c.height > 0)) return true;
37511
37638
  const painter = htmlInCanvas();
37512
37639
  if (!painter && mode === "capture") throw new Error(MISSING);
37513
37640
  if (mode === "live") {
37641
+ rootKeys.set(root, entity.get(Node).key);
37514
37642
  watch(root);
37515
- if (fitBox(host, root, c.width, c.height) || pinLive(root, c.local)) requestRepaint();
37516
- if (!painter) return drawSketch(ctx, root, c.width, c.height, k);
37643
+ if (document.fonts.status === "loading" && pendingFonts.get(root) !== document.fonts.ready) {
37644
+ const ready = document.fonts.ready;
37645
+ pendingFonts.set(root, ready);
37646
+ void ready.then(() => {
37647
+ if (pendingFonts.get(root) === ready) pendingFonts.delete(root);
37648
+ requestRepaint(root);
37649
+ });
37650
+ }
37651
+ const sketch = painter ? void 0 : sketches.get(root);
37652
+ if (sketch?.decoding) {
37653
+ if (sketch.shown) ctx.drawImage(sketch.shown, 0, 0, c.width, c.height);
37654
+ return false;
37655
+ }
37656
+ const resized2 = fitBox(host, root, c.width, c.height);
37657
+ const { changed, moved } = pinLive(root, c.local);
37658
+ if (resized2 || moved) requestRepaint(root);
37659
+ if (!painter) {
37660
+ const ready = drawSketch(ctx, root, c.width, c.height, k, resized2 || changed);
37661
+ return ready && !pendingFonts.has(root);
37662
+ }
37517
37663
  }
37518
37664
  const bw = Math.max(1, Math.ceil(c.width * k));
37519
37665
  const bh = Math.max(1, Math.ceil(c.height * k));
@@ -37525,10 +37671,11 @@ function drawHtml(ctx, entity, k, mode) {
37525
37671
  hostCtx.drawElementImage(root, 0, 0, bw, bh);
37526
37672
  } catch (error) {
37527
37673
  if (mode === "capture") throw new Error(`${entity.get(Node).key}: <html> content was not painted before capture (${error.message})`, { cause: error });
37528
- requestRepaint();
37529
- return;
37674
+ requestRepaint(root);
37675
+ return false;
37530
37676
  }
37531
37677
  ctx.drawImage(host, 0, 0, c.width, c.height);
37678
+ return mode === "capture" || !pendingPaints.has(root) && !pendingFonts.has(root) && [...root.querySelectorAll("img")].every((image) => image.complete);
37532
37679
  }
37533
37680
 
37534
37681
  // ../../packages/runtime/src/errors.ts
@@ -37633,9 +37780,9 @@ var FLOATS = { f32: 1, vec2f: 2, vec3f: 3, vec4f: 4, "vec2<f32>": 2, "vec3<f32>"
37633
37780
  var UNIFORM_DECL = /((?:@\w+\s*\(\s*\d+\s*\)\s*)+)var\s*<\s*uniform\s*>\s*([A-Za-z_]\w*)\s*:\s*([^;=]+?)\s*;/g;
37634
37781
  var ATTRIBUTE = /@(\w+)\s*\(\s*(\d+)\s*\)/g;
37635
37782
  function uniformDecls(wgsl) {
37636
- const code = wgsl.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/[^\n]*/g, "");
37783
+ const code2 = wgsl.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/[^\n]*/g, "");
37637
37784
  const out = [];
37638
- for (const [, attrs, name, rawType] of code.matchAll(UNIFORM_DECL)) {
37785
+ for (const [, attrs, name, rawType] of code2.matchAll(UNIFORM_DECL)) {
37639
37786
  const numbers = Object.fromEntries([...attrs.matchAll(ATTRIBUTE)].map(([, key, n]) => [key, Number(n)]));
37640
37787
  if (numbers.group !== 1 || numbers.binding === void 0) continue;
37641
37788
  const type = rawType.replace(/\s+/g, "");
@@ -37776,14 +37923,12 @@ function targetFor(device) {
37776
37923
  sampler: device.createSampler({ magFilter: "linear", minFilter: "linear" }),
37777
37924
  layout: device.createBindGroupLayout(layoutDescriptors([])[0]),
37778
37925
  picture: void 0,
37926
+ stills: /* @__PURE__ */ new WeakMap(),
37779
37927
  crossing: void 0
37780
37928
  };
37781
37929
  return target;
37782
37930
  }
37783
- function pictureTexture(t, width, height) {
37784
- const current = t.picture?.texture;
37785
- if (current && current.width === width && current.height === height) return t.picture.group;
37786
- current?.destroy();
37931
+ function createUpload(t, width, height) {
37787
37932
  const texture = t.device.createTexture({
37788
37933
  size: [width, height],
37789
37934
  format: "rgba8unorm",
@@ -37797,8 +37942,14 @@ function pictureTexture(t, width, height) {
37797
37942
  { binding: 2, resource: t.sampler }
37798
37943
  ]
37799
37944
  });
37800
- t.picture = { texture, group };
37801
- return group;
37945
+ return { texture, group };
37946
+ }
37947
+ function pictureTexture(t, width, height) {
37948
+ const current = t.picture;
37949
+ if (current && current.texture.width === width && current.texture.height === height) return current;
37950
+ current?.texture.destroy();
37951
+ t.picture = { ...createUpload(t, width, height), holds: null };
37952
+ return t.picture;
37802
37953
  }
37803
37954
  var named = /* @__PURE__ */ new Map();
37804
37955
  var probe;
@@ -37827,6 +37978,12 @@ function packUniforms(decls, values) {
37827
37978
  });
37828
37979
  return data;
37829
37980
  }
37981
+ function pixelSize(image, width, height) {
37982
+ const i = image;
37983
+ const w = i.displayWidth ?? i.videoWidth ?? i.naturalWidth ?? i.width;
37984
+ const h = i.displayHeight ?? i.videoHeight ?? i.naturalHeight ?? i.height;
37985
+ return w && h ? [w, h] : [width, height];
37986
+ }
37830
37987
  function upload(t, gpu, draw, limit) {
37831
37988
  const { box: box2, picture } = draw;
37832
37989
  const queue = gpu.device.queue;
@@ -37836,11 +37993,31 @@ function upload(t, gpu, draw, limit) {
37836
37993
  queue.writeBuffer(t.globals, 0, new Float32Array([box2.width, box2.height, x * sx, y * sy, w * sx, h * sy, draw.time, 0]));
37837
37994
  queue.writeBuffer(gpu.uniforms, 0, packUniforms(gpu.decls, draw.uniforms));
37838
37995
  const size = (n) => Math.min(limit, Math.max(1, Math.round(n)));
37839
- const group = pictureTexture(t, picture ? size(picture.width) : 1, picture ? size(picture.height) : 1);
37840
- const texture = t.picture.texture;
37841
- if (!picture) queue.writeTexture({ texture }, new Uint8Array(4), { bytesPerRow: 4 }, [1, 1]);
37842
- else queue.copyExternalImageToTexture({ source: picture.image }, { texture, premultipliedAlpha: true }, [texture.width, texture.height]);
37843
- return group;
37996
+ if (!picture) {
37997
+ const blank = pictureTexture(t, 1, 1);
37998
+ queue.writeTexture({ texture: blank.texture }, new Uint8Array(4), { bytesPerRow: 4 }, [1, 1]);
37999
+ blank.holds = null;
38000
+ return blank.group;
38001
+ }
38002
+ const [pw, ph] = pixelSize(picture.image, picture.width, picture.height);
38003
+ const [tw, th] = [size(pw), size(ph)];
38004
+ const copy = (texture) => queue.copyExternalImageToTexture({ source: picture.image }, { texture, premultipliedAlpha: true }, [tw, th]);
38005
+ if (picture.still) {
38006
+ let kept = t.stills.get(picture.image);
38007
+ if (kept?.texture.width !== tw || kept.texture.height !== th) {
38008
+ kept?.texture.destroy();
38009
+ kept = createUpload(t, tw, th);
38010
+ copy(kept.texture);
38011
+ t.stills.set(picture.image, kept);
38012
+ }
38013
+ return kept.group;
38014
+ }
38015
+ const shared = pictureTexture(t, tw, th);
38016
+ if (shared.holds !== picture.image) {
38017
+ copy(shared.texture);
38018
+ shared.holds = picture.image;
38019
+ }
38020
+ return shared.group;
37844
38021
  }
37845
38022
  function render(t, gpu, inputs, width, height) {
37846
38023
  if (t.canvas.width !== width) t.canvas.width = width;
@@ -38046,8 +38223,8 @@ async function mediaReady(world, media) {
38046
38223
  for (const entity of world.query(Compositing, Computed)) {
38047
38224
  if (!entity.get(Computed).active) continue;
38048
38225
  const src = resolved(entity, "mask")?.src;
38049
- if (src) work.push(media.matte(src).ready);
38050
- for (const fx of liveEffects(entity)) if (fx.mask?.src) work.push(media.matte(fx.mask.src).ready);
38226
+ if (src) work.push(matteReady(entity, src, media));
38227
+ for (const fx of liveEffects(entity)) if (fx.mask?.src) work.push(matteReady(entity, fx.mask.src, media));
38051
38228
  }
38052
38229
  for (const entity of world.query(Captions, Computed)) {
38053
38230
  const src = entity.get(Captions).src;
@@ -38059,6 +38236,14 @@ async function mediaReady(world, media) {
38059
38236
  work.push(...shadersReady(world));
38060
38237
  await Promise.all(work);
38061
38238
  }
38239
+ var matteSourceTime = (entity) => entity.get(Node).tag === "video" ? entity.get(Computed).mediaTime : void 0;
38240
+ async function matteReady(entity, src, media) {
38241
+ if (isMaskFile(src)) return media.matte(src).ready;
38242
+ const handle = media.video(src);
38243
+ const facts = await handle.ready;
38244
+ const index = lumaMatteIndex(facts, matteSourceTime(entity), entity.get(Computed).local);
38245
+ if (index >= 0) await handle.request(index);
38246
+ }
38062
38247
  function roundRect(ctx, w, h, r) {
38063
38248
  ctx.beginPath();
38064
38249
  if (r > 0) ctx.roundRect(0, 0, w, h, Math.min(r, w / 2, h / 2));
@@ -38087,7 +38272,8 @@ function drawFitted(ctx, image, sw, sh, w, h, fit) {
38087
38272
  function drawPicture(ctx, entity, image, sw, sh, fit, opts) {
38088
38273
  const c = entity.get(Computed);
38089
38274
  const paint = pictureShader(entity);
38090
- if (paint && shadePicture(ctx, entity, paint, { image, width: sw, height: sh, placed: fitted(sw, sh, c.width, c.height, fit) }, opts.scale ?? 1)) return;
38275
+ const still = entity.get(Node).tag === "image";
38276
+ if (paint && shadePicture(ctx, entity, paint, { image, width: sw, height: sh, placed: fitted(sw, sh, c.width, c.height, fit), still }, opts.scale ?? 1)) return;
38091
38277
  drawFitted(ctx, image, sw, sh, c.width, c.height, fit);
38092
38278
  }
38093
38279
  function drawText(ctx, entity, c) {
@@ -38114,6 +38300,11 @@ function drawEntity(ctx, entity, media, opts, root) {
38114
38300
  function paintEntity(ctx, entity, media, opts, root) {
38115
38301
  const c = entity.get(Computed);
38116
38302
  if (!c.active) return;
38303
+ const picture = opts.mode === "live" ? opts.prerendered?.(entity) : void 0;
38304
+ if (picture) {
38305
+ drawPrerendered(ctx, entity, picture, opts);
38306
+ return;
38307
+ }
38117
38308
  const { tag: tag2 } = entity.get(Node);
38118
38309
  const device = deviceMatrix(c.matrix, opts);
38119
38310
  if (opts.visible && CULLABLE.has(tag2) && offscreen(device, c.bounds, opts.visible)) return;
@@ -38227,12 +38418,10 @@ function fitted(sw, sh, w, h, fit) {
38227
38418
  return [(w - sw * k) / 2, (h - sh * k) / 2, sw * k, sh * k];
38228
38419
  }
38229
38420
  function cutMatte(layer, entity, m, media, opts, device, k) {
38230
- const handle = media.matte(m.src);
38231
- const file = handle.file;
38232
- if (!file && opts.mode === "capture") throw new Error(`${m.src}: mask was not loaded before capture`);
38421
+ const matte = isMaskFile(m.src) ? maskFilePicture(entity, m.src, media, opts) : lumaPicture(entity, m.src, media, opts);
38422
+ const picture = matte?.picture;
38233
38423
  const c = entity.get(Computed);
38234
38424
  const { tag: tag2 } = entity.get(Node);
38235
- const picture = file ? handle.frame(file.indexAt(tag2 === "video" ? c.mediaTime : file.header.start + c.local)) : void 0;
38236
38425
  layer.save();
38237
38426
  if (!picture) {
38238
38427
  if (!m.invert) {
@@ -38243,7 +38432,7 @@ function cutMatte(layer, entity, m, media, opts, device, k) {
38243
38432
  return;
38244
38433
  }
38245
38434
  const fit = tag2 === "video" ? entity.get(Media).fit ?? "cover" : tag2 === "image" ? entity.get(Media).fit ?? "contain" : "fill";
38246
- const [sw, sh] = file.header.source;
38435
+ const [sw, sh] = matte.source;
38247
38436
  layer.setTransform(...device);
38248
38437
  layer.globalAlpha = 1;
38249
38438
  layer.globalCompositeOperation = m.invert ? "destination-out" : "destination-in";
@@ -38251,19 +38440,38 @@ function cutMatte(layer, entity, m, media, opts, device, k) {
38251
38440
  layer.drawImage(picture, ...fitted(sw, sh, c.width, c.height, fit));
38252
38441
  layer.restore();
38253
38442
  }
38443
+ function maskFilePicture(entity, src, media, opts) {
38444
+ const handle = media.matte(src);
38445
+ const file = handle.file;
38446
+ if (!file) opts.onPendingMedia?.(handle.src);
38447
+ if (!file && opts.mode === "capture") throw new Error(`${src}: mask was not loaded before capture`);
38448
+ if (!file) return void 0;
38449
+ const time = matteSourceTime(entity) ?? file.header.start + entity.get(Computed).local;
38450
+ return { picture: handle.frame(file.indexAt(time)), source: file.header.source };
38451
+ }
38452
+ function lumaPicture(entity, src, media, opts) {
38453
+ const handle = media.video(src);
38454
+ const facts = handle.facts;
38455
+ const index = lumaMatteIndex(facts, matteSourceTime(entity), entity.get(Computed).local);
38456
+ const frame = index < 0 ? void 0 : opts.mode === "capture" ? handle.exact(index) : handle.peek(index);
38457
+ if (!facts || index >= 0 && !handle.exact(index)) opts.onPendingMedia?.(handle.src);
38458
+ if (!frame && opts.mode === "capture") throw new Error(`${src}: matte frame ${index} was not decoded before capture`);
38459
+ if (!facts || !frame) return void 0;
38460
+ return { picture: lumaToAlpha(handle, frame, facts.width, facts.height), source: [facts.width, facts.height] };
38461
+ }
38254
38462
  function cut(layer, entity, mask, media, opts, device, k) {
38255
38463
  if (mask.shape === "matte") cutMatte(layer, entity, mask, media, opts, device, k);
38256
38464
  else cutMask(layer, mask, device, k);
38257
38465
  }
38258
38466
  function filterInPlace(layer, filter) {
38259
- const scratch = acquireLayer(layer);
38467
+ const scratch2 = acquireLayer(layer);
38260
38468
  try {
38261
- scratch.filter = filter;
38262
- scratch.drawImage(layer.canvas, 0, 0);
38469
+ scratch2.filter = filter;
38470
+ scratch2.drawImage(layer.canvas, 0, 0);
38263
38471
  layer.save();
38264
38472
  layer.setTransform(1, 0, 0, 1, 0, 0);
38265
38473
  layer.clearRect(0, 0, layer.canvas.width, layer.canvas.height);
38266
- layer.drawImage(scratch.canvas, 0, 0);
38474
+ layer.drawImage(scratch2.canvas, 0, 0);
38267
38475
  layer.restore();
38268
38476
  } finally {
38269
38477
  depth--;
@@ -38372,6 +38580,7 @@ function drawBody(ctx, entity, media, opts, root, clip) {
38372
38580
  case "image": {
38373
38581
  const src = entity.get(Media)?.src;
38374
38582
  const image = src ? media.image(src) : void 0;
38583
+ if (image && !image.bitmap) opts.onPendingMedia?.(image.src);
38375
38584
  if (image?.bitmap) rounded(ctx, entity, c, () => drawPicture(ctx, entity, image.bitmap, image.width, image.height, entity.get(Media).fit ?? "contain", opts));
38376
38585
  break;
38377
38586
  }
@@ -38382,12 +38591,16 @@ function drawBody(ctx, entity, media, opts, root, clip) {
38382
38591
  rounded(ctx, entity, c, () => drawSurface(ctx, entity.get(Surface).canvas, c.width, c.height));
38383
38592
  break;
38384
38593
  case "html":
38385
- rounded(ctx, entity, c, () => drawHtml(ctx, entity, (opts.scale ?? 1) * Math.hypot(c.matrix[0], c.matrix[1]), opts.mode));
38594
+ rounded(ctx, entity, c, () => {
38595
+ const ready = drawHtml(ctx, entity, (opts.scale ?? 1) * Math.hypot(c.matrix[0], c.matrix[1]), opts.mode);
38596
+ opts.onHtml?.(entity.get(Node).key, ready);
38597
+ });
38386
38598
  break;
38387
38599
  case "video": {
38388
38600
  const src = entity.get(Media)?.src;
38389
38601
  const handle = src ? media.video(src) : void 0;
38390
38602
  const facts = handle?.facts;
38603
+ if (handle && !facts) opts.onPendingMedia?.(handle.src);
38391
38604
  if (handle && facts) {
38392
38605
  const index = videoFrameIndex(entity, handle);
38393
38606
  const fit = entity.get(Media).fit ?? "cover";
@@ -38397,6 +38610,7 @@ function drawBody(ctx, entity, media, opts, root, clip) {
38397
38610
  handle.fit(box2 * k);
38398
38611
  }
38399
38612
  const frame = opts.mode === "capture" ? handle.exact(index) : handle.peek(index);
38613
+ if (index >= 0 && !handle.exact(index)) opts.onPendingMedia?.(handle.src);
38400
38614
  if (opts.mode === "capture" && !frame) throw new Error(`${src}: frame ${index} was not decoded before capture`);
38401
38615
  if (frame) rounded(ctx, entity, c, () => drawPicture(ctx, entity, frame, facts.width, facts.height, fit, opts));
38402
38616
  }
@@ -38404,7 +38618,9 @@ function drawBody(ctx, entity, media, opts, root, clip) {
38404
38618
  }
38405
38619
  case "captions": {
38406
38620
  const caps = entity.get(Captions);
38407
- const transcript = caps.src ? media.transcript(caps.src).transcript : void 0;
38621
+ const handle = caps.src ? media.transcript(caps.src) : void 0;
38622
+ const transcript = handle?.transcript;
38623
+ if (handle && !transcript) opts.onPendingMedia?.(handle.src);
38408
38624
  if (opts.mode === "capture" && caps.src && !transcript) throw new Error(`${caps.src}: transcript was not loaded before capture`);
38409
38625
  const k = (opts.scale ?? 1) * Math.hypot(c.matrix[0], c.matrix[1]);
38410
38626
  if (transcript) drawCaptions(ctx, transcript, c.mediaTime, captionStyle((p) => resolved(entity, p), caps.preset, caps.colors), c, k);
@@ -38577,6 +38793,15 @@ function drawShaderCrossing(ctx, box2, crossing, media, opts) {
38577
38793
  }
38578
38794
  }
38579
38795
  var WARM_LEAD = 0.6;
38796
+ function drawPrerendered(ctx, entity, picture, opts) {
38797
+ const parent = entity.get(Hierarchy).parent.get(Computed);
38798
+ const device = deviceMatrix(parent.matrix, opts);
38799
+ const box2 = [0, 0, picture.width, picture.height];
38800
+ if (opts.visible && offscreen(device, box2, opts.visible)) return;
38801
+ ctx.setTransform(...device);
38802
+ ctx.globalAlpha = parent.opacity;
38803
+ ctx.drawImage(picture.image, 0, 0, picture.width, picture.height);
38804
+ }
38580
38805
  var upcoming = (entity) => {
38581
38806
  const c = entity.get(Computed);
38582
38807
  return !c.active && c.local < 0 && c.local >= -WARM_LEAD && entity.get(Hierarchy)?.parent?.get(Computed)?.active === true;
@@ -38602,18 +38827,33 @@ function drawFrame(ctx, world, comp, media, opts) {
38602
38827
  ctx.clearRect(0, 0, opts.origin ? ctx.canvas.width : comp.width * s, opts.origin ? ctx.canvas.height : comp.height * s);
38603
38828
  const stage = findStage(world);
38604
38829
  if (!stage) return;
38605
- childrenOf(stage).filter((scene) => !opts.scene || scene === opts.scene).forEach((scene) => drawEntity(ctx, scene, media, opts, true));
38830
+ childrenOf(stage).forEach((scene) => drawEntity(ctx, scene, media, opts, true));
38831
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
38832
+ ctx.globalAlpha = 1;
38833
+ }
38834
+ function drawIsolated(ctx, entity, media, opts) {
38835
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
38836
+ ctx.globalAlpha = 1;
38837
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
38838
+ drawEntity(ctx, entity, media, opts, false);
38606
38839
  ctx.setTransform(1, 0, 0, 1, 0, 0);
38607
38840
  ctx.globalAlpha = 1;
38608
38841
  }
38609
38842
 
38610
38843
  // ../../packages/runtime/src/media/audio.ts
38844
+ var NoAudioTrackError = class extends Error {
38845
+ constructor(src) {
38846
+ super(`${src}: no audio track`);
38847
+ this.name = "NoAudioTrackError";
38848
+ }
38849
+ };
38611
38850
  var MediabunnyAudio = class {
38612
38851
  src;
38613
38852
  ready;
38614
38853
  facts;
38615
38854
  input;
38616
38855
  sink;
38856
+ disposed = false;
38617
38857
  constructor(src, url2) {
38618
38858
  this.src = src;
38619
38859
  this.ready = this.open(url2);
@@ -38624,24 +38864,55 @@ var MediabunnyAudio = class {
38624
38864
  const input = new Input({ source: new UrlSource(url2, { maxCacheSize: 32 * 1024 * 1024 }), formats: ALL_FORMATS });
38625
38865
  this.input = input;
38626
38866
  const track = await input.getPrimaryAudioTrack();
38627
- if (!track) throw new Error(`${this.src}: no audio track`);
38867
+ if (this.disposed) throw new DOMException("Audio source disposed", "AbortError");
38868
+ if (!track) throw new NoAudioTrackError(this.src);
38628
38869
  const duration = await track.computeDuration();
38870
+ if (this.disposed) throw new DOMException("Audio source disposed", "AbortError");
38629
38871
  this.sink = new AudioBufferSink(track);
38630
38872
  this.facts = { duration, sampleRate: track.sampleRate, channels: track.numberOfChannels };
38631
38873
  return this.facts;
38632
38874
  }
38633
- async *chunks(start, end) {
38634
- await this.ready;
38635
- if (!this.sink || end <= start) return;
38636
- for await (const b of this.sink.buffers(start, end)) yield { buffer: b.buffer, timestamp: b.timestamp };
38875
+ chunks(start, end) {
38876
+ let closed = false;
38877
+ let buffers;
38878
+ const close2 = async () => {
38879
+ if (!closed) {
38880
+ closed = true;
38881
+ await buffers?.return();
38882
+ }
38883
+ return { done: true, value: void 0 };
38884
+ };
38885
+ return {
38886
+ next: async () => {
38887
+ if (closed || this.disposed) return { done: true, value: void 0 };
38888
+ await this.ready;
38889
+ if (closed || this.disposed || !this.sink || end <= start) return { done: true, value: void 0 };
38890
+ buffers ??= this.sink.buffers(start, end);
38891
+ const result = await buffers.next();
38892
+ if (closed || this.disposed || result.done) return { done: true, value: void 0 };
38893
+ return { done: false, value: { buffer: result.value.buffer, timestamp: result.value.timestamp } };
38894
+ },
38895
+ return: close2,
38896
+ throw: async (error) => {
38897
+ await close2();
38898
+ throw error;
38899
+ },
38900
+ [Symbol.asyncIterator]() {
38901
+ return this;
38902
+ }
38903
+ // Asserted: under an ESNext lib AsyncGenerator also names Symbol.asyncDispose, which no consumer calls.
38904
+ };
38637
38905
  }
38638
38906
  dispose() {
38907
+ if (this.disposed) return;
38908
+ this.disposed = true;
38639
38909
  this.input?.dispose?.();
38640
38910
  this.sink = void 0;
38641
38911
  }
38642
38912
  };
38643
38913
 
38644
38914
  // ../../packages/runtime/src/media/fonts.ts
38915
+ var GOOGLE_ROUTE = "/__higgsedit/fonts/google";
38645
38916
  function axisRanges(fvar) {
38646
38917
  const out = /* @__PURE__ */ new Map();
38647
38918
  const first = fvar.getUint16(4);
@@ -38821,22 +39092,28 @@ var GoogleFonts = class {
38821
39092
  return;
38822
39093
  }
38823
39094
  if ("error" in answer) throw new Error(answer.error);
38824
- const href = new URL(answer.url, this.endpoint).href;
39095
+ const href = fileUrl(answer.url, this.endpoint);
38825
39096
  const faceKey = `${u.family}|${answer.weight}|${answer.style}`;
38826
39097
  let face = this.faces.get(faceKey);
38827
39098
  if (!face) {
38828
- const f = new FontFace(u.family, `url("${href}")`, { weight: String(answer.weight), style: answer.style });
38829
- set.add(f);
38830
- face = f.load().then(() => void 0);
38831
- face.catch(() => {
38832
- set.delete(f);
38833
- this.faces.delete(faceKey);
38834
- });
39099
+ face = (async () => {
39100
+ const file = await fetch(href);
39101
+ if (!file.ok) throw new Error(`${file.status} from ${href}`);
39102
+ const f = new FontFace(u.family, await file.arrayBuffer(), { weight: String(answer.weight), style: answer.style });
39103
+ await f.load();
39104
+ set.add(f);
39105
+ fontsChanged();
39106
+ })();
39107
+ face.catch(() => this.faces.delete(faceKey));
38835
39108
  this.faces.set(faceKey, face);
38836
39109
  }
38837
39110
  await face;
38838
39111
  }
38839
39112
  };
39113
+ function fileUrl(url2, endpoint) {
39114
+ const at = endpoint.indexOf(GOOGLE_ROUTE);
39115
+ return url2.startsWith("/") && at > 0 ? `${endpoint.slice(0, at)}${url2}` : new URL(url2, endpoint).href;
39116
+ }
38840
39117
  var fontSet = () => globalThis.document?.fonts ?? globalThis.fonts;
38841
39118
 
38842
39119
  // ../../packages/runtime/src/media/image.ts
@@ -38899,6 +39176,20 @@ var BrowserImage = class {
38899
39176
 
38900
39177
  // ../../packages/runtime/src/media/mask-file.ts
38901
39178
  var MAGIC = "RMSK";
39179
+ function decodeMaskRuns(bytes2, out, start = 0, end = bytes2.length) {
39180
+ out.fill(0);
39181
+ let at = start;
39182
+ let cell = 0;
39183
+ let value = 0;
39184
+ while (at < end) {
39185
+ const [run, next] = readVarint(bytes2, at);
39186
+ at = next;
39187
+ if (value) out.fill(1, cell, Math.min(out.length, cell + run));
39188
+ cell += run;
39189
+ value ^= 1;
39190
+ }
39191
+ return cell;
39192
+ }
38902
39193
  var MaskFile = class _MaskFile {
38903
39194
  header;
38904
39195
  bytes;
@@ -38933,20 +39224,10 @@ var MaskFile = class _MaskFile {
38933
39224
  }
38934
39225
  /** Fills `out` (grid-sized) with 1 inside the object, 0 outside; false when the frame was not tracked. */
38935
39226
  frame(index, out) {
38936
- out.fill(0);
38937
- let at = this.starts[index];
39227
+ const start = this.starts[index];
38938
39228
  const end = this.ends[index];
38939
- if (at >= end) return false;
38940
- let cell = 0;
38941
- let value = 0;
38942
- while (at < end) {
38943
- const [run, next] = readVarint(this.bytes, at);
38944
- at = next;
38945
- if (value) out.fill(1, cell, Math.min(out.length, cell + run));
38946
- cell += run;
38947
- value ^= 1;
38948
- }
38949
- return true;
39229
+ decodeMaskRuns(this.bytes, out, start, end);
39230
+ return start < end;
38950
39231
  }
38951
39232
  /** The frame shown at source seconds `t`: the nearest-frame rule video uses, clamped to the file. */
38952
39233
  indexAt(t) {
@@ -39203,32 +39484,40 @@ var MediabunnyVideo = class {
39203
39484
  };
39204
39485
  async function openVideo(src, url2) {
39205
39486
  const input = new Input({ source: new UrlSource(url2, { maxCacheSize: 128 * 1024 * 1024 }), formats: ALL_FORMATS });
39206
- const track = await input.getPrimaryVideoTrack();
39207
- if (!track) throw new Error(`${src}: no video track`);
39208
- if (!await track.canDecode()) throw new Error(`${src}: this browser cannot decode ${await track.getCodecParameterString()}`);
39209
- const packets = new EncodedPacketSink(track);
39210
- const stamps = [];
39211
- const keyStamps = [];
39212
- for await (const p of packets.packets(void 0, void 0, { metadataOnly: true })) {
39213
- stamps.push(p.timestamp);
39214
- if (p.type === "key") keyStamps.push(p.timestamp);
39215
- }
39216
- stamps.sort((a, b) => a - b);
39217
- const timestamps = Float64Array.from(stamps);
39218
- const fps = estimateFps(timestamps);
39219
- const keys = Int32Array.from(new Set(keyStamps.map((t) => indexOfTimestamp(timestamps, t)))).toSorted();
39220
- return {
39221
- input,
39222
- sink: new VideoSampleSink(track),
39223
- facts: {
39224
- width: track.displayWidth,
39225
- height: track.displayHeight,
39226
- fps,
39227
- timestamps,
39228
- duration: timestamps.length ? timestamps[timestamps.length - 1] - Math.max(0, timestamps[0]) + 1 / fps : 0
39229
- },
39230
- keys
39231
- };
39487
+ try {
39488
+ const track = await input.getPrimaryVideoTrack();
39489
+ if (!track) throw new Error(`${src}: no video track`);
39490
+ if (!await track.canDecode()) throw new Error(`${src}: this browser cannot decode ${await track.getCodecParameterString()}`);
39491
+ const packets = new EncodedPacketSink(track);
39492
+ const stamps = [];
39493
+ const keyStamps = [];
39494
+ for await (const p of packets.packets(void 0, void 0, { metadataOnly: true })) {
39495
+ stamps.push(p.timestamp);
39496
+ if (p.type === "key") keyStamps.push(p.timestamp);
39497
+ }
39498
+ stamps.sort((a, b) => a - b);
39499
+ const timestamps = Float64Array.from(stamps);
39500
+ const fps = estimateFps(timestamps);
39501
+ const keys = Int32Array.from(new Set(keyStamps.map((t) => indexOfTimestamp(timestamps, t)))).toSorted();
39502
+ return {
39503
+ input,
39504
+ sink: new VideoSampleSink(track),
39505
+ facts: {
39506
+ width: track.displayWidth,
39507
+ height: track.displayHeight,
39508
+ fps,
39509
+ timestamps,
39510
+ duration: timestamps.length ? timestamps[timestamps.length - 1] - Math.max(0, timestamps[0]) + 1 / fps : 0
39511
+ },
39512
+ keys
39513
+ };
39514
+ } catch (error) {
39515
+ try {
39516
+ input.dispose();
39517
+ } catch {
39518
+ }
39519
+ throw error;
39520
+ }
39232
39521
  }
39233
39522
  function indexOfTimestamp(timestamps, t) {
39234
39523
  let lo = 0;
@@ -39252,6 +39541,7 @@ var BrowserMediaHost = class {
39252
39541
  audios = /* @__PURE__ */ new Map();
39253
39542
  mattes = /* @__PURE__ */ new Map();
39254
39543
  transcripts = /* @__PURE__ */ new Map();
39544
+ readyListeners = /* @__PURE__ */ new Set();
39255
39545
  resolve;
39256
39546
  makeVideo;
39257
39547
  resolveVideo;
@@ -39261,6 +39551,17 @@ var BrowserMediaHost = class {
39261
39551
  this.makeVideo = makeVideo ?? ((src, url2) => new MediabunnyVideo(src, url2));
39262
39552
  this.resolveVideo = resolveVideo ?? resolve;
39263
39553
  }
39554
+ /** A lazily requested image, matte or metadata became available (or failed). */
39555
+ onReady(listener) {
39556
+ this.readyListeners.add(listener);
39557
+ return () => this.readyListeners.delete(listener);
39558
+ }
39559
+ watchReady(src, ready) {
39560
+ const settled = () => {
39561
+ for (const listener of this.readyListeners) listener(src);
39562
+ };
39563
+ void ready.then(settled, settled);
39564
+ }
39264
39565
  /** Drops the open video, matte or parsed transcript for `src`; the next use opens it again (its bytes changed). */
39265
39566
  forget(src) {
39266
39567
  const url2 = this.resolveVideo(src);
@@ -39275,6 +39576,7 @@ var BrowserMediaHost = class {
39275
39576
  if (!handle) {
39276
39577
  handle = new BrowserTranscript(src, url2);
39277
39578
  this.transcripts.set(url2, handle);
39579
+ this.watchReady(src, handle.ready);
39278
39580
  }
39279
39581
  return handle;
39280
39582
  }
@@ -39284,6 +39586,7 @@ var BrowserMediaHost = class {
39284
39586
  if (!handle) {
39285
39587
  handle = this.makeVideo(src, url2);
39286
39588
  this.videos.set(url2, handle);
39589
+ this.watchReady(src, handle.ready);
39287
39590
  }
39288
39591
  return handle;
39289
39592
  }
@@ -39293,6 +39596,7 @@ var BrowserMediaHost = class {
39293
39596
  if (!handle) {
39294
39597
  handle = new BrowserImage(src, url2);
39295
39598
  this.images.set(url2, handle);
39599
+ this.watchReady(src, handle.ready);
39296
39600
  }
39297
39601
  return handle;
39298
39602
  }
@@ -39311,10 +39615,12 @@ var BrowserMediaHost = class {
39311
39615
  if (!handle) {
39312
39616
  handle = new BrowserMatte(src, url2);
39313
39617
  this.mattes.set(url2, handle);
39618
+ this.watchReady(src, handle.ready);
39314
39619
  }
39315
39620
  return handle;
39316
39621
  }
39317
- dispose() {
39622
+ /** A full project resync invalidates every media source; listeners still belong to the live editor. */
39623
+ forgetAll() {
39318
39624
  for (const a of this.audios.values()) a.dispose();
39319
39625
  this.audios.clear();
39320
39626
  for (const v of this.videos.values()) v.dispose();
@@ -39323,6 +39629,10 @@ var BrowserMediaHost = class {
39323
39629
  this.mattes.clear();
39324
39630
  this.transcripts.clear();
39325
39631
  }
39632
+ dispose() {
39633
+ this.readyListeners.clear();
39634
+ this.forgetAll();
39635
+ }
39326
39636
  };
39327
39637
 
39328
39638
  // ../../packages/runtime/src/media/preview-video.ts
@@ -39404,8 +39714,90 @@ var HostFrameVideo = class {
39404
39714
  }
39405
39715
  };
39406
39716
 
39717
+ // ../../packages/runtime/src/prerender.ts
39718
+ var PRERENDER_MAX_SECONDS = 120;
39719
+ var EPS = 1e-6;
39720
+ var HEAVY_TAGS = /* @__PURE__ */ new Set(["html", "surface", "shaderPaint"]);
39721
+ var tagOf2 = (e) => e.get(Node).tag;
39722
+ var mark = (e) => e.get(Visibility)?.prerender;
39723
+ function isHeavy(entity) {
39724
+ if (mark(entity) === false) return false;
39725
+ if (HEAVY_TAGS.has(tagOf2(entity))) return true;
39726
+ const fx = entity.get(Effects);
39727
+ if (typeof fx?.blur === "number" && fx.blur > 0 || fx?.effects?.some((e) => e.type === "blur" && !e.hidden)) return true;
39728
+ if (entity.get(Keyframes)?.animate?.blur) return true;
39729
+ const presets = entity.get(Presets);
39730
+ return [...motionList(presets?.enter), ...motionList(presets?.exit)].some((m) => m.preset === "blur");
39731
+ }
39732
+ var clips2 = (e) => !!e && (tagOf2(e) === "scene" || tagOf2(e) === "group" && e.get(Effects)?.clip === true);
39733
+ var scopeOf = (e) => {
39734
+ const key = e.get(Node).key;
39735
+ return key.startsWith("~") ? void 0 : key.split("/").slice(0, -1).join("/");
39736
+ };
39737
+ function opensScope(e) {
39738
+ const own = scopeOf(e);
39739
+ const parent = parentOf(e);
39740
+ return !!own && !!parent && own !== scopeOf(parent);
39741
+ }
39742
+ function unitOf(entity) {
39743
+ const chain = [];
39744
+ for (let e = entity; e && tagOf2(e) !== "scene" && tagOf2(e) !== "stage"; e = parentOf(e)) chain.unshift(e);
39745
+ if (chain.some((e) => mark(e) === false)) return void 0;
39746
+ if (mark(entity) === true && clips2(parentOf(entity))) return entity;
39747
+ return chain.find((e) => opensScope(e) && clips2(parentOf(e))) ?? chain[0];
39748
+ }
39749
+ function anyIn(entity, test) {
39750
+ return test(entity) || childrenOf(entity).some((c) => anyIn(c, test));
39751
+ }
39752
+ function cacheable(entity) {
39753
+ const parent = parentOf(entity);
39754
+ if (!clips2(parent) || entity.get(Node).key.startsWith("~") || entity.get(Visibility)?.hidden) return false;
39755
+ const siblings = childrenOf(parent);
39756
+ const next = siblings[siblings.indexOf(entity) + 1];
39757
+ const layer = (e) => tagOf2(e) === "adjustmentLayer";
39758
+ if (next && (layer(next) || tagOf2(next) === "sequence" && anyIn(next, layer))) return false;
39759
+ return !anyIn(entity, layer);
39760
+ }
39761
+ function prerenderTargets(world) {
39762
+ const units = /* @__PURE__ */ new Set();
39763
+ for (const e of world.query(Node)) {
39764
+ if (!isHeavy(e) && mark(e) !== true) continue;
39765
+ const unit = unitOf(e);
39766
+ if (unit && cacheable(unit)) units.add(unit);
39767
+ }
39768
+ const inside = (e) => {
39769
+ for (let p = parentOf(e); p; p = parentOf(p)) if (units.has(p)) return true;
39770
+ return false;
39771
+ };
39772
+ return [...units].filter((e) => !inside(e));
39773
+ }
39774
+ function prerenderPlan(world, entity) {
39775
+ const parent = parentOf(entity);
39776
+ if (!parent) return void 0;
39777
+ const fps = composition(world).fps;
39778
+ const rootStart = -localTime(world, entity, 0);
39779
+ const firstFrame = Math.ceil(rootStart * fps - EPS);
39780
+ evaluate(world, firstFrame / fps);
39781
+ const c = entity.get(Computed);
39782
+ const pc = parent.get(Computed);
39783
+ if (!c.active || !(c.length > 0)) return void 0;
39784
+ const own = span(world, entity, c.fps);
39785
+ const length = Math.min(Number.isFinite(own.end) ? own.end - own.start : c.length, PRERENDER_MAX_SECONDS);
39786
+ const end = Math.ceil((rootStart + length) * fps - EPS);
39787
+ return {
39788
+ key: entity.get(Node).key,
39789
+ width: pc.width,
39790
+ height: pc.height,
39791
+ fps,
39792
+ firstFrame,
39793
+ frames: end - firstFrame,
39794
+ offset: firstFrame / fps - rootStart,
39795
+ rootStart
39796
+ };
39797
+ }
39798
+
39407
39799
  // ../../packages/reconciler/src/inspect.ts
39408
- var INSPECT_MODULE = "@higgsfield-ai/video-editor-next/jsx/inspect";
39800
+ var INSPECT_MODULE = "@higgsfield/higgsedit/jsx/inspect";
39409
39801
  var inspectKey = (file, name) => `${file}#${name}`;
39410
39802
  function createInspectHost(overrides = /* @__PURE__ */ new Map()) {
39411
39803
  const entries = [];
@@ -39440,20 +39832,20 @@ function findEntry(files) {
39440
39832
  const set = new Set(files);
39441
39833
  return ENTRY_CANDIDATES.find((c) => set.has(c));
39442
39834
  }
39443
- var isHostModule = (specifier) => /^(solid-js|@higgsfield-ai\/video-editor-next\/jsx)(\/|$)/.test(specifier);
39835
+ var isHostModule = (specifier) => /^(solid-js|@higgsfield\/higgsedit\/jsx)(\/|$)/.test(specifier);
39444
39836
  var packageName = (specifier) => specifier.split("/").slice(0, specifier.startsWith("@") ? 2 : 1).join("/");
39445
- function packageModules(code, externals) {
39446
- if (!code) return {};
39837
+ function packageModules(code2, externals) {
39838
+ if (!code2) return {};
39447
39839
  const module = { exports: {} };
39448
39840
  const require2 = (specifier) => {
39449
39841
  if (specifier in externals) return externals[specifier];
39450
39842
  throw new Error(`a package imports "${specifier}", which the host does not provide (available: ${Object.keys(externals).join(", ")})`);
39451
39843
  };
39452
- new Function("require", "module", "exports", `${code}
39844
+ new Function("require", "module", "exports", `${code2}
39453
39845
  //# sourceURL=higgsedit-project/node_modules.js`)(require2, module, module.exports);
39454
39846
  return module.exports;
39455
39847
  }
39456
- function evaluateProject(modules, externals, entry = findEntry(Object.keys(modules))) {
39848
+ function evaluateProject(modules, externals, entry = findEntry(Object.keys(modules)), options = {}) {
39457
39849
  if (!entry || !(entry in modules)) {
39458
39850
  throw new Error(`project has no entry file (expected one of ${ENTRY_CANDIDATES.join(", ")})`);
39459
39851
  }
@@ -39464,6 +39856,8 @@ function evaluateProject(modules, externals, entry = findEntry(Object.keys(modul
39464
39856
  const module = { exports: {} };
39465
39857
  cache3.set(file, module);
39466
39858
  const require2 = (specifier) => {
39859
+ const made = options.perFile?.[specifier];
39860
+ if (made) return made(file);
39467
39861
  if (specifier in externals) return externals[specifier];
39468
39862
  if (!specifier.startsWith(".")) {
39469
39863
  if (isHostModule(specifier)) throw new Error(`${file}: cannot import "${specifier}" (available: ${Object.keys(externals).join(", ")}, or relative files)`);
@@ -39472,6 +39866,11 @@ function evaluateProject(modules, externals, entry = findEntry(Object.keys(modul
39472
39866
  const base = normalize(`${dirname(file)}/${specifier}`);
39473
39867
  const target2 = EXTENSIONS.map((ext) => base + ext).find((candidate) => candidate in modules);
39474
39868
  if (!target2) throw new Error(`${file}: cannot resolve "${specifier}"`);
39869
+ if (options.imports) {
39870
+ const list = options.imports.get(file) ?? /* @__PURE__ */ new Set();
39871
+ list.add(target2);
39872
+ options.imports.set(file, list);
39873
+ }
39475
39874
  return load(target2);
39476
39875
  };
39477
39876
  const run = (0, eval)(`(function (require, module, exports) {${modules[file]}
@@ -40041,6 +40440,11 @@ var ProjectDocument = class {
40041
40440
  nodes = /* @__PURE__ */ new Map();
40042
40441
  keyCounts = /* @__PURE__ */ new Map();
40043
40442
  world;
40443
+ /** Scope paths whose clocks stand still: the editor shows them from a cached render (live mode only). */
40444
+ frozen;
40445
+ setFrozenScopes;
40446
+ /** Props of every component instance that opened a scope, by scope path ("a/b"). */
40447
+ scopes = /* @__PURE__ */ new Map();
40044
40448
  /** Scope of the component currently rendering, read when an element is created. */
40045
40449
  scopeOf = () => [];
40046
40450
  /** Where a relative `src` in HTML content (an `<img>`) points: the project's media URL. */
@@ -40054,6 +40458,17 @@ var ProjectDocument = class {
40054
40458
  });
40055
40459
  this.tick = tick;
40056
40460
  this.setTick = setTick;
40461
+ const [frozen, setFrozen] = createSignal(/* @__PURE__ */ new Set(), { equals: (a, b) => a.size === b.size && [...a].every((x) => b.has(x)) });
40462
+ this.frozen = frozen;
40463
+ this.setFrozenScopes = setFrozen;
40464
+ }
40465
+ /**
40466
+ * Stops the clocks (`useTicker`, `useLocalTime`) of components inside `scopes` (scope paths), so their effects
40467
+ * stop repainting what the editor draws from a cached render; thawing catches them up. Never in capture.
40468
+ */
40469
+ setFrozen(scopes) {
40470
+ if (this.mode === "capture") return;
40471
+ this.setFrozenScopes(new Set(scopes));
40057
40472
  }
40058
40473
  hold(work) {
40059
40474
  if (this.mode !== "capture") return;
@@ -40095,6 +40510,10 @@ var ProjectDocument = class {
40095
40510
  if (getOwner()) onCleanup(() => this.disposeElement(node));
40096
40511
  return node;
40097
40512
  }
40513
+ /** Records the project module whose JSX created `node`. */
40514
+ noteFile(node, file) {
40515
+ node.entity.get(Node).file = file;
40516
+ }
40098
40517
  createTextNode(value) {
40099
40518
  return { kind: "text", value, parent: null };
40100
40519
  }
@@ -40269,6 +40688,7 @@ var renderer_exports = {};
40269
40688
  __export(renderer_exports, {
40270
40689
  createComponent: () => createComponent2,
40271
40690
  createElement: () => createElement,
40691
+ createElementIn: () => createElementIn,
40272
40692
  createTextNode: () => createTextNode,
40273
40693
  currentScope: () => currentScope,
40274
40694
  effect: () => effect,
@@ -40482,11 +40902,11 @@ function createRenderer$1({
40482
40902
  return prevProps;
40483
40903
  }
40484
40904
  return {
40485
- render(code, element) {
40905
+ render(code2, element) {
40486
40906
  let disposer;
40487
40907
  createRoot((dispose2) => {
40488
40908
  disposer = dispose2;
40489
- insert2(element, code());
40909
+ insert2(element, code2());
40490
40910
  });
40491
40911
  return disposer;
40492
40912
  },
@@ -40540,6 +40960,11 @@ var renderer = createRenderer({
40540
40960
  getNextSibling: (node) => doc().getNextSibling(node)
40541
40961
  });
40542
40962
  var { render: render2, effect, memo: memo2, createElement, createTextNode, insertNode, insert, spread, setProp, mergeProps: mergeProps2, use } = renderer;
40963
+ function createElementIn(file, tag2) {
40964
+ const node = createElement(tag2);
40965
+ if ("entity" in node) doc().noteFile(node, file);
40966
+ return node;
40967
+ }
40543
40968
  var BUILTINS = /* @__PURE__ */ new Set();
40544
40969
  function registerBuiltins(components) {
40545
40970
  for (const c of components) BUILTINS.add(c);
@@ -40548,6 +40973,7 @@ function createComponent2(component, props) {
40548
40973
  const id = BUILTINS.has(component) ? void 0 : untrack(() => props.id);
40549
40974
  if (typeof id !== "string") return createComponent(component, props);
40550
40975
  const parent = useContext(ScopeContext);
40976
+ doc().scopes.set([...parent, id].join("/"), props);
40551
40977
  return createComponent(ScopeContext.Provider, {
40552
40978
  value: [...parent, id],
40553
40979
  get children() {
@@ -40558,20 +40984,34 @@ function createComponent2(component, props) {
40558
40984
  function currentScope() {
40559
40985
  return useContext(ScopeContext);
40560
40986
  }
40987
+ function frozenHere(document2) {
40988
+ const scope = useContext(ScopeContext).join("/");
40989
+ if (!scope) return () => false;
40990
+ return createMemo(() => {
40991
+ for (const s of document2.frozen()) if (scope === s || scope.startsWith(`${s}/`)) return true;
40992
+ return false;
40993
+ });
40994
+ }
40995
+ function clock(document2, frozen, read2) {
40996
+ return createMemo((prev) => prev !== void 0 && frozen() ? prev : read2(document2.tick()), void 0);
40997
+ }
40561
40998
  function useTicker2() {
40562
40999
  const document2 = doc();
40563
- const tick = document2.tick;
41000
+ const frozen = frozenHere(document2);
40564
41001
  return {
40565
- time: createMemo(() => tick().time),
40566
- frame: createMemo(() => tick().frame),
40567
- delta: createMemo(() => tick().delta),
40568
- playing: createMemo(() => tick().playing),
41002
+ time: clock(document2, frozen, (t) => t.time),
41003
+ frame: clock(document2, frozen, (t) => t.frame),
41004
+ delta: clock(document2, frozen, (t) => t.delta),
41005
+ playing: clock(document2, frozen, (t) => t.playing),
40569
41006
  hold: (work) => document2.hold(work)
40570
41007
  };
40571
41008
  }
40572
41009
  function useLocalTime2(id) {
40573
- const { world, tick } = doc();
40574
- return createMemo(() => {
41010
+ const document2 = doc();
41011
+ const { world, tick } = document2;
41012
+ const frozen = frozenHere(document2);
41013
+ return createMemo((prev) => {
41014
+ if (prev !== void 0 && frozen()) return prev;
40575
41015
  const time = tick().time;
40576
41016
  const entity = findByKey(world, id) ?? world.query(Node).find((e) => e.get(Node).id === id);
40577
41017
  if (!entity) throw new Error(`useLocalTime("${id}"): no element has id "${id}"`);
@@ -40610,10 +41050,13 @@ var JSX_MODULE = { ...src_exports, useTicker: useTicker2, useResolution: useReso
40610
41050
  var EXTERNALS = {
40611
41051
  "solid-js": solid_exports,
40612
41052
  "solid-js/store": store_exports,
40613
- "@higgsfield-ai/video-editor-next/jsx": JSX_MODULE,
40614
- "@higgsfield-ai/video-editor-next/jsx/renderer": renderer_exports,
41053
+ "@higgsfield/higgsedit/jsx": JSX_MODULE,
41054
+ "@higgsfield/higgsedit/jsx/renderer": renderer_exports,
40615
41055
  [INSPECT_MODULE]: SOURCE_VALUES
40616
41056
  };
41057
+ var PER_FILE = {
41058
+ "@higgsfield/higgsedit/jsx/renderer": (file) => ({ ...renderer_exports, createElement: (tag2) => createElementIn(file, tag2) })
41059
+ };
40617
41060
  function mountComponent(component, world, mode = "live", options = {}) {
40618
41061
  const document2 = new ProjectDocument(world, mode, options.resolveUrl);
40619
41062
  let disposeGraph;
@@ -40634,21 +41077,84 @@ function mountComponent(component, world, mode = "live", options = {}) {
40634
41077
  };
40635
41078
  }
40636
41079
 
40637
- // ../editor/src/session.ts
41080
+ // ../../packages/reconciler/src/prerender.ts
41081
+ var SKIP_PROPS = /* @__PURE__ */ new Set(["children", "ref"]);
41082
+ var MEDIA = /["'`]((?:\.\/)?(?:\$\{[^}]*\}|[^"'`\s<>])+?\.(?:mp4|mov|m4v|webm|mkv|png|jpe?g|webp|gif|avif|svg|mp3|wav|m4a|aac|ogg|flac|mask|json|ttf|otf|woff2?))["'`]/gi;
41083
+ var SOURCE_MAP = /\n?\/\/# sourceMappingURL=\S*\s*$/;
41084
+ var code = (sources, file) => (sources.modules[file] ?? "").replace(SOURCE_MAP, "");
41085
+ var isHostNode = (v) => "kind" in v && "entity" in v;
41086
+ function stable(v, seen) {
41087
+ if (v === void 0) return "u";
41088
+ if (v === null || typeof v === "number" || typeof v === "boolean" || typeof v === "string") return JSON.stringify(v);
41089
+ if (typeof v === "function") return `f${JSON.stringify(String(v))}`;
41090
+ if (typeof v !== "object") return JSON.stringify(String(v));
41091
+ if (seen.has(v)) return `"[cycle]"`;
41092
+ seen.add(v);
41093
+ if (Array.isArray(v)) return `[${v.map((x) => stable(x, seen)).join(",")}]`;
41094
+ if (v instanceof Set) return `s[${[...v].map((x) => stable(x, seen)).toSorted().join(",")}]`;
41095
+ if (v instanceof Map) return `m{${[...v].map(([k, x]) => `${stable(k, seen)}:${stable(x, seen)}`).toSorted().join(",")}}`;
41096
+ const proto = Object.getPrototypeOf(v);
41097
+ if (proto !== Object.prototype && proto !== null || isHostNode(v)) return JSON.stringify(`[${isHostNode(v) ? "node" : proto?.constructor?.name ?? "object"}]`);
41098
+ const record = v;
41099
+ return `{${Object.keys(record).filter((k) => !SKIP_PROPS.has(k)).toSorted().map((k) => `${JSON.stringify(k)}:${stable(record[k], seen)}`).join(",")}}`;
41100
+ }
41101
+ function prerenderSnapshot(document2, entity, sources) {
41102
+ const lines = [`E ${entity.get(Node).key}`];
41103
+ const files = /* @__PURE__ */ new Set();
41104
+ const scopes = /* @__PURE__ */ new Set();
41105
+ const parent = parentOf(entity);
41106
+ const outer = (parent && document2.nodes.get(parent)?.scope.length) ?? 0;
41107
+ let blend = false;
41108
+ const visit = (e, path) => {
41109
+ const node = e.get(Node);
41110
+ const props = readProps(e);
41111
+ for (const name of node.accessors) delete props[name];
41112
+ lines.push(`N ${path} ${node.tag} ${node.id ?? ""} ${[...node.accessors].toSorted().join(",")} ${untrack(() => stable(props, /* @__PURE__ */ new WeakSet()))}`);
41113
+ if (node.file) files.add(node.file);
41114
+ const scope = document2.nodes.get(e)?.scope ?? [];
41115
+ for (let i = outer + 1; i <= scope.length; i++) scopes.add(scope.slice(0, i).join("/"));
41116
+ const mode = e.get(Compositing)?.blend;
41117
+ if (mode && mode !== "normal") blend = true;
41118
+ childrenOf(e).forEach((c, i) => visit(c, `${path}/${i}`));
41119
+ };
41120
+ visit(entity, "");
41121
+ for (const s of [...scopes].toSorted()) lines.push(`S ${s} ${untrack(() => stable(document2.scopes.get(s), /* @__PURE__ */ new WeakSet()))}`);
41122
+ const queue = [...files];
41123
+ for (const f of queue) {
41124
+ for (const next of sources.imports.get(f) ?? []) {
41125
+ if (files.has(next)) continue;
41126
+ files.add(next);
41127
+ queue.push(next);
41128
+ }
41129
+ }
41130
+ const closure = [...files].toSorted();
41131
+ for (const f of closure) lines.push(`M ${f}
41132
+ ${code(sources, f)}`);
41133
+ if (sources.packages) lines.push(`P ${sources.packages}`);
41134
+ const text = lines.join("\n");
41135
+ const media = /* @__PURE__ */ new Set();
41136
+ for (const m of text.matchAll(MEDIA)) media.add(m[1].replace(/^\.\//, "").replace(/\$\{[^}]*\}/g, "*"));
41137
+ return { text, ticker: closure.some((f) => /\buseTicker\b/.test(code(sources, f))), blend, media: [...media].toSorted() };
41138
+ }
41139
+
41140
+ // ../../packages/editor-document/src/session.ts
40638
41141
  var HOLD_TIMEOUT_MS = 3e4;
40639
41142
  var relativeMedia = (src) => src.replace(/^\.\//, "");
40640
- var fontsInUse = (world) => [...usedFonts(world), ...htmlFonts(world)];
40641
- function captureMediaEntities(world, includes) {
40642
- const needed = new Set(world.query(Media).filter(includes));
40643
- const targets = new Map(syncLinks(world).filter((link) => !link.problem && link.target).map((link) => [link.entity, link.target]));
40644
- // Only load timing dependencies of the selected scene, not every sibling scene.
40645
- // Set iteration includes additions; cycles are bounded by the finite entity set.
40646
- for (const entity of needed) {
40647
- const target = targets.get(entity);
40648
- if (target) needed.add(target);
40649
- }
40650
- return needed;
41143
+ function fingerprint(text) {
41144
+ let a = 2166136261;
41145
+ let b = 16777619 ^ text.length;
41146
+ for (let i = 0; i < text.length; i++) {
41147
+ const c = text.charCodeAt(i);
41148
+ a = Math.imul(a ^ c, 16777619);
41149
+ b = Math.imul(b ^ c, 16777629);
41150
+ }
41151
+ return `${(a >>> 0).toString(16)}${(b >>> 0).toString(16)}:${text.length}`;
41152
+ }
41153
+ async function sha256(text) {
41154
+ const hash = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text));
41155
+ return [...new Uint8Array(hash)].map((b) => b.toString(16).padStart(2, "0")).join("");
40651
41156
  }
41157
+ var fontsInUse = (world, includes) => [...usedFonts(world, includes), ...htmlFonts(world, includes)];
40652
41158
  var Session = class {
40653
41159
  world = createProjectWorld();
40654
41160
  mount;
@@ -40658,35 +41164,33 @@ var Session = class {
40658
41164
  /** Families the project's font files register (lowercase): these never go to Google Fonts. */
40659
41165
  projectFamilies = /* @__PURE__ */ new Set();
40660
41166
  mediaUrl;
41167
+ server;
40661
41168
  options;
40662
41169
  comp;
40663
41170
  captureScene;
40664
- captureIncludes(entity) {
41171
+ captureIncludes = (entity) => {
40665
41172
  if (!this.captureScene) return true;
40666
41173
  for (let e = entity; e; e = parentOf(e)) if (e === this.captureScene) return true;
40667
41174
  return false;
40668
- }
40669
- captureFonts() {
40670
- return fontsInUse({ query: (...traits) => this.world.query(...traits).filter((entity) => this.captureIncludes(entity)) });
40671
- }
40672
- evaluateCapture(time) {
40673
- return evaluate(this.world, time, this.captureScene);
40674
- }
41175
+ };
40675
41176
  /** The `@inspect` consts the last load evaluated, with the values it used. */
40676
41177
  inspect = [];
41178
+ /** Elements the editor may play from a cached render, with what their picture depends on, read at mount. */
41179
+ prerender = /* @__PURE__ */ new Map();
40677
41180
  constructor(options) {
40678
41181
  this.options = options;
40679
41182
  const base = options.mediaBase.replace(/\/$/, "");
40680
41183
  this.mediaUrl = (src) => `${base}/${relativeMedia(src)}`;
40681
41184
  const videoBase = (options.videoBase ?? base).replace(/\/$/, "");
40682
41185
  this.media = new BrowserMediaHost(this.mediaUrl, options.makeVideo, (src) => `${videoBase}/${relativeMedia(src)}`);
40683
- this.googleFonts = new GoogleFonts(new URL("/__higgsedit/fonts/google", new URL(base, globalThis.location?.href)).href);
41186
+ this.server = options.origin ?? new URL(base, globalThis.location?.href).origin;
41187
+ this.googleFonts = new GoogleFonts(new URL(`${this.server}/__higgsedit/fonts/google`, globalThis.location?.href).href);
40684
41188
  }
40685
41189
  bundled;
40686
41190
  /** The project's npm packages, evaluated once per bundle so remounts keep the same module instances. */
40687
- packages(code, externals) {
40688
- if (!code) return {};
40689
- if (this.bundled?.code !== code) this.bundled = { code, modules: packageModules(code, externals) };
41191
+ packages(code2, externals) {
41192
+ if (!code2) return {};
41193
+ if (this.bundled?.code !== code2) this.bundled = { code: code2, modules: packageModules(code2, externals) };
40690
41194
  return this.bundled.modules;
40691
41195
  }
40692
41196
  /**
@@ -40699,27 +41203,34 @@ var Session = class {
40699
41203
  const t0 = performance.now();
40700
41204
  const inspect = createInspectHost(overrides);
40701
41205
  const externals = { ...EXTERNALS, [INSPECT_MODULE]: inspect.module };
40702
- const component = evaluateProject(modules, { ...externals, ...this.packages(packages, externals) });
41206
+ const imports = /* @__PURE__ */ new Map();
41207
+ const component = evaluateProject(modules, { ...externals, ...this.packages(packages, externals) }, void 0, { perFile: PER_FILE, imports });
40703
41208
  const t1 = performance.now();
40704
41209
  const world = createProjectWorld();
40705
- if (this.options.sceneId !== undefined) captureSceneIds.set(world, this.options.sceneId);
41210
+ if (this.options.captureSceneId !== void 0) setCaptureScene(world, this.options.captureSceneId);
40706
41211
  const mount = mountComponent(component, world, this.options.mode === "capture" ? "capture" : "live", { resolveUrl: this.mediaUrl });
41212
+ const captureScene = this.options.captureSceneId === void 0 ? void 0 : rootScenes(world)[0];
41213
+ if (this.options.captureSceneId !== void 0 && !captureScene) {
41214
+ mount.dispose();
41215
+ world.destroy();
41216
+ throw new Error(`unknown scene: ${this.options.captureSceneId}`);
41217
+ }
40707
41218
  const t2 = performance.now();
41219
+ const sources = { modules, imports, ...packages ? { packages: fingerprint(packages) } : {} };
41220
+ const prerender = new Map(prerenderTargets(world).map((e) => [e.get(Node).key, prerenderSnapshot(mount.document, e, sources)]));
40708
41221
  this.mount?.dispose();
40709
41222
  this.world.destroy();
40710
41223
  this.world = world;
40711
41224
  this.mount = mount;
40712
- if (this.options.sceneId !== undefined) {
40713
- this.captureScene = rootScenes(world).find((scene) => scene.get(Node).key === this.options.sceneId || scene.get(Node).id === this.options.sceneId);
40714
- if (!this.captureScene) throw new Error(`unknown scene: ${this.options.sceneId}`);
40715
- }
41225
+ this.captureScene = captureScene;
40716
41226
  this.inspect = inspect.entries;
41227
+ this.prerender = prerender;
40717
41228
  const faces = await fontsLoaded;
40718
41229
  this.projectFamilies = new Set(faces.flatMap((f) => f ? [f.family.replace(/^["']|["']$/g, "").toLowerCase()] : []));
40719
41230
  this.googleFonts.retryFailed();
40720
- await this.googleFonts.load(this.captureFonts(), this.projectFamilies);
41231
+ await this.googleFonts.load(fontsInUse(world, this.captureIncludes), this.projectFamilies);
40721
41232
  await this.resolveMedia(this.options.mode === "capture");
40722
- this.comp = this.evaluateCapture(0);
41233
+ this.comp = evaluate(world, 0);
40723
41234
  return {
40724
41235
  composition: { width: this.comp.width, height: this.comp.height, fps: this.comp.fps, duration: this.comp.duration, frames: this.comp.frames },
40725
41236
  clips: clips(world),
@@ -40731,7 +41242,12 @@ var Session = class {
40731
41242
  /** Opens every video and audio source to learn its duration; waits for them when `wait` (capture), else updates later. */
40732
41243
  async resolveMedia(wait2) {
40733
41244
  const durations = this.world.get(MediaInfo).durations;
40734
- const needed = captureMediaEntities(this.world, (entity) => this.captureIncludes(entity));
41245
+ const needed = new Set(this.world.query(Media).filter(this.captureIncludes));
41246
+ const targets = new Map(syncLinks(this.world).filter((link) => !link.problem && link.target).map((link) => [link.entity, link.target]));
41247
+ for (const entity of needed) {
41248
+ const target2 = targets.get(entity);
41249
+ if (target2) needed.add(target2);
41250
+ }
40735
41251
  const work = [...needed].filter((e) => (e.get(Node).tag === "video" || e.get(Node).tag === "audio") && e.get(Media).src).map((e) => {
40736
41252
  const src = e.get(Media).src;
40737
41253
  const handle = e.get(Node).tag === "audio" ? this.media.audio(src) : this.media.video(src);
@@ -40739,7 +41255,8 @@ var Session = class {
40739
41255
  durations.set(src, facts.duration);
40740
41256
  });
40741
41257
  });
40742
- for (const e of this.world.query(Captions).filter((entity) => this.captureIncludes(entity))) {
41258
+ for (const e of this.world.query(Captions)) {
41259
+ if (!this.captureIncludes(e)) continue;
40743
41260
  const src = e.get(Captions).src;
40744
41261
  if (src) work.push(this.media.transcript(src).ready.then((t) => void durations.set(src, transcriptLength(t))));
40745
41262
  }
@@ -40751,7 +41268,7 @@ var Session = class {
40751
41268
  async resolveSyncs(needed) {
40752
41269
  const world = this.world;
40753
41270
  const offsets = world.get(MediaInfo).offsets;
40754
- const url2 = this.options.syncUrl ?? `${new URL(this.options.mediaBase, globalThis.location?.href).origin}/__higgsedit/sync`;
41271
+ const url2 = this.options.syncUrl ?? `${this.server}/__higgsedit/sync`;
40755
41272
  await Promise.all(
40756
41273
  syncLinks(world).filter((link) => needed.has(link.entity)).map(async (link) => {
40757
41274
  if (link.problem || !link.src || !link.targetSrc) {
@@ -40787,8 +41304,12 @@ var Session = class {
40787
41304
  tick(frame, opts = {}) {
40788
41305
  const fps = stageFps(this.world);
40789
41306
  const time = opts.time ?? frame / fps;
40790
- batch(() => this.mount?.tick({ time, frame, delta: opts.delta ?? 1 / fps, playing: opts.playing ?? true }));
40791
- this.comp = this.evaluateCapture(time);
41307
+ const update = () => {
41308
+ batch(() => this.mount?.tick({ time, frame, delta: opts.delta ?? 1 / fps, playing: opts.playing ?? true }));
41309
+ this.comp = evaluate(this.world, time);
41310
+ };
41311
+ if (this.options.mode === "live") withHtmlClock(this.world, update);
41312
+ else update();
40792
41313
  return this.comp;
40793
41314
  }
40794
41315
  /**
@@ -40799,7 +41320,7 @@ var Session = class {
40799
41320
  const document2 = this.mount?.document;
40800
41321
  for (let round = 0; round < 50; round++) {
40801
41322
  const holds = document2 ? [...document2.holds] : [];
40802
- const work = Promise.all([...holds, mediaReady(this.world, this.media), this.googleFonts.load(this.captureFonts(), this.projectFamilies), globalThis.document?.fonts?.ready]);
41323
+ const work = Promise.all([...holds, mediaReady(this.world, this.media), this.googleFonts.load(fontsInUse(this.world, this.captureIncludes), this.projectFamilies), globalThis.document?.fonts?.ready]);
40803
41324
  let timer;
40804
41325
  const timeout = new Promise((_, reject) => {
40805
41326
  timer = setTimeout(() => reject(new Error(`frame ${frame}: hold() did not settle within ${HOLD_TIMEOUT_MS / 1e3} s`)), HOLD_TIMEOUT_MS);
@@ -40809,7 +41330,7 @@ var Session = class {
40809
41330
  } finally {
40810
41331
  clearTimeout(timer);
40811
41332
  }
40812
- this.comp = this.evaluateCapture(time);
41333
+ this.comp = evaluate(this.world, time);
40813
41334
  if (!document2 || document2.holds.size === 0) {
40814
41335
  await mediaReady(this.world, this.media);
40815
41336
  return;
@@ -40818,25 +41339,68 @@ var Session = class {
40818
41339
  throw new Error(`frame ${frame}: hold() kept registering new work`);
40819
41340
  }
40820
41341
  /** Capture mode: tick, barrier, draw. Pixels depend only on (source, media, frame). */
40821
- async renderFrame(ctx, frame, scale = 1) {
41342
+ async renderFrame(ctx, frame, scale = 1, options = {}) {
41343
+ try {
41344
+ this.tick(frame, { time: options.time });
41345
+ await this.settle(frame, options.time);
41346
+ drawFrame(ctx, this.world, this.comp, this.media, { mode: "capture", scale, origin: options.origin });
41347
+ } catch (error) {
41348
+ throw withFrame(error, frame, stageFps(this.world));
41349
+ }
41350
+ }
41351
+ /**
41352
+ * Every element that may play from a cached render, with its plan and source digest. Evaluates the world at other
41353
+ * times: the next tick puts it back.
41354
+ */
41355
+ async prerenderInputs() {
41356
+ const out = [];
41357
+ for (const [key, snap] of this.prerender) {
41358
+ const plan = this.prerenderPlan(key);
41359
+ if (!plan) continue;
41360
+ const geometry = `G ${plan.width}x${plan.height} ${plan.fps} ${plan.frames} ${Math.round(plan.offset * 1e6)}${snap.ticker ? ` ${plan.rootStart}` : ""}`;
41361
+ out.push({ ...plan, digest: await sha256(`${snap.text}
41362
+ ${geometry}`), media: snap.media, blend: snap.blend });
41363
+ }
41364
+ if (this.comp) this.comp = evaluate(this.world, 0);
41365
+ return out;
41366
+ }
41367
+ /** What a pre-rendered preview of element `key` covers (the editor's preview cache; renders never read it). */
41368
+ prerenderPlan(key) {
41369
+ const entity = findByKey(this.world, key);
41370
+ return entity ? prerenderPlan(this.world, entity) : void 0;
41371
+ }
41372
+ /** Capture mode, root frame `frame`, only element `key`: its parent's box at the canvas origin, `scale` px per parent px. */
41373
+ async renderIsolated(ctx, key, frame, scale) {
40822
41374
  try {
40823
41375
  this.tick(frame);
40824
41376
  await this.settle(frame);
40825
- drawFrame(ctx, this.world, this.comp, this.media, { mode: "capture", scale });
41377
+ const entity = findByKey(this.world, key);
41378
+ if (!entity) throw new Error(`no element ${key}`);
41379
+ isolate(entity);
41380
+ drawIsolated(ctx, entity, this.media, { mode: "capture", scale });
40826
41381
  } catch (error) {
40827
41382
  throw withFrame(error, frame, stageFps(this.world));
40828
41383
  }
40829
41384
  }
40830
41385
  /** Live mode: draw whatever media is ready now. */
40831
- drawLive(ctx, scale = 1, origin, visible) {
40832
- if (this.comp) drawFrame(ctx, this.world, this.comp, this.media, { mode: "live", scale, ...origin ? { origin } : {}, ...visible ? { visible } : {} });
41386
+ drawLive(ctx, scale = 1, origin, visible, prerendered) {
41387
+ const pending = /* @__PURE__ */ new Set();
41388
+ let pendingHtml = false;
41389
+ const htmlKeys = /* @__PURE__ */ new Set();
41390
+ if (this.comp) drawFrame(ctx, this.world, this.comp, this.media, { mode: "live", scale, ...origin ? { origin } : {}, ...visible ? { visible } : {}, ...prerendered ? { prerendered } : {}, onPendingMedia: (src) => {
41391
+ pending.add(src);
41392
+ }, onHtml: (key, ready) => {
41393
+ htmlKeys.add(key);
41394
+ if (!ready) pendingHtml = true;
41395
+ } });
41396
+ return { pendingMedia: [...pending], pendingHtml, htmlKeys: [...htmlKeys] };
40833
41397
  }
40834
41398
  entity(key) {
40835
41399
  return findByKey(this.world, key);
40836
41400
  }
40837
41401
  };
40838
41402
 
40839
- // ../editor/src/capture-page.ts
41403
+ // ../../packages/editor-document/src/capture-page.ts
40840
41404
  async function toBase64(blob) {
40841
41405
  const bytes2 = new Uint8Array(await blob.arrayBuffer());
40842
41406
  let binary = "";
@@ -40847,23 +41411,10 @@ var session;
40847
41411
  var canvas;
40848
41412
  var depth2 = 8;
40849
41413
  var encoder;
40850
- var outputComposition;
40851
- var outputOrigin = 0;
40852
- async function renderOutputFrame(ctx, frame) {
40853
- if (!outputComposition) return session.renderFrame(ctx, frame);
40854
- const time = outputOrigin + frame / outputComposition.fps;
40855
- const authoredFrame = Math.round(time * stageFps(session.world));
40856
- session.tick(authoredFrame, { time });
40857
- await session.settle(authoredFrame, time);
40858
- const source = session.captureScene?.get(SceneConfig) ?? session.comp;
40859
- const sourceWidth = source.width ?? session.comp.width;
40860
- const sourceHeight = source.height ?? session.comp.height;
40861
- const scale = Math.min(outputComposition.width / sourceWidth, outputComposition.height / sourceHeight);
40862
- const origin = { x: -(outputComposition.width / scale - sourceWidth) / 2, y: -(outputComposition.height / scale - sourceHeight) / 2 };
40863
- drawFrame(ctx, session.world, session.comp, session.media, { mode: "capture", scale, origin, scene: session.captureScene });
40864
- }
41414
+ var output;
41415
+ var sourceStart = 0;
40865
41416
  function context() {
40866
- const comp = outputComposition ?? session.comp;
41417
+ const comp = output;
40867
41418
  if (!canvas || canvas.width !== comp.width || canvas.height !== comp.height) {
40868
41419
  canvas = new OffscreenCanvas(comp.width, comp.height);
40869
41420
  }
@@ -40871,42 +41422,55 @@ function context() {
40871
41422
  if (!ctx) throw new Error("no 2d context");
40872
41423
  return ctx;
40873
41424
  }
41425
+ async function renderOutput(ctx, frame) {
41426
+ const authored = session.comp;
41427
+ const time = sourceStart + frame / output.fps;
41428
+ const scale = Math.min(output.width / authored.width, output.height / authored.height);
41429
+ const origin = { x: -(output.width / scale - authored.width) / 2, y: -(output.height / scale - authored.height) / 2 };
41430
+ await session.renderFrame(ctx, Math.round(time * stageFps(session.world)), scale, { time, origin });
41431
+ }
41432
+ var isolatedCanvas;
41433
+ function isolatedContext(key, height) {
41434
+ const plan = session.prerenderPlan(key);
41435
+ if (!plan) throw new Error(`${key}: nothing to pre-render`);
41436
+ const scale = height / plan.height;
41437
+ const width = Math.max(1, Math.round(plan.width * scale));
41438
+ if (!isolatedCanvas || isolatedCanvas.width !== width || isolatedCanvas.height !== height) isolatedCanvas = new OffscreenCanvas(width, height);
41439
+ const ctx = isolatedCanvas.getContext("2d", { willReadFrequently: true });
41440
+ return { ctx, scale };
41441
+ }
40874
41442
  function read(ctx) {
40875
41443
  const { width, height } = ctx.canvas;
40876
41444
  const image = depth2 === 10 ? ctx.getImageData(0, 0, width, height, { pixelFormat: "rgba-float16" }) : ctx.getImageData(0, 0, width, height);
40877
41445
  return image.data;
40878
41446
  }
40879
41447
  var api = {
40880
- async load({ modules, fonts, packages, mediaBase, depth: d, hostFrames, spec, sceneId }) {
41448
+ async load({ modules, fonts, packages, mediaBase, depth: d, hostFrames, sceneId, spec }) {
40881
41449
  depth2 = d;
41450
+ session?.mount?.dispose();
41451
+ session?.world.destroy();
40882
41452
  session = new Session({
40883
41453
  mediaBase,
40884
41454
  mode: "capture",
40885
- sceneId,
41455
+ captureSceneId: sceneId,
40886
41456
  ...hostFrames ? { makeVideo: (src) => new HostFrameVideo(src, hostFrames) } : {}
40887
41457
  });
40888
41458
  const info = await session.load(modules, fonts, void 0, packages);
40889
- outputComposition = undefined;
40890
- outputOrigin = 0;
40891
- if (spec || sceneId !== undefined) {
40892
- const scene = session.captureScene;
40893
- const timing = scene ? span(session.world, scene, stageFps(session.world)) : { start: 0, end: info.composition.duration };
40894
- const config = scene?.get(SceneConfig);
40895
- outputOrigin = timing.start;
40896
- const fps = spec?.video.fps ?? config?.fps ?? info.composition.fps;
40897
- const duration = timing.end - timing.start;
40898
- outputComposition = { width: spec?.video.width ?? config?.width ?? info.composition.width, height: spec?.video.height ?? config?.height ?? info.composition.height, fps, duration, frames: Math.max(1, Math.round(duration * fps)) };
40899
- return { ...info, composition: outputComposition, sourceFps: config?.fps ?? info.composition.fps };
40900
- }
40901
- return info;
41459
+ const authored = session.comp;
41460
+ const range = session.captureScene ? span(session.world, session.captureScene, stageFps(session.world)) : { start: 0, end: authored.duration };
41461
+ sourceStart = range.start;
41462
+ const duration = range.end - range.start;
41463
+ const fps = spec?.video.fps ?? authored.fps;
41464
+ output = { width: spec?.video.width ?? authored.width, height: spec?.video.height ?? authored.height, fps, duration, frames: Math.max(1, Math.round(duration * fps)) };
41465
+ return { ...info, composition: { ...output, sourceFps: authored.fps } };
40902
41466
  },
40903
41467
  async png(frame) {
40904
41468
  const ctx = context();
40905
- await renderOutputFrame(ctx, frame);
41469
+ await renderOutput(ctx, frame);
40906
41470
  return toBase64(await canvas.convertToBlob({ type: "image/png" }));
40907
41471
  },
40908
41472
  async sheet(frames, { columns, width }) {
40909
- const comp = outputComposition ?? session.comp;
41473
+ const comp = output;
40910
41474
  const thumbW = width;
40911
41475
  const thumbH = Math.round(width * comp.height / comp.width);
40912
41476
  const label = 28;
@@ -40917,7 +41481,7 @@ var api = {
40917
41481
  out.fillRect(0, 0, sheet.width, sheet.height);
40918
41482
  for (const [i, frame] of frames.entries()) {
40919
41483
  const ctx = context();
40920
- await renderOutputFrame(ctx, frame);
41484
+ await renderOutput(ctx, frame);
40921
41485
  const x = i % columns * thumbW;
40922
41486
  const y = Math.floor(i / columns) * (thumbH + label);
40923
41487
  out.drawImage(canvas, x, y, thumbW, thumbH);
@@ -40928,12 +41492,12 @@ var api = {
40928
41492
  }
40929
41493
  return toBase64(await sheet.convertToBlob({ type: "image/png" }));
40930
41494
  },
40931
- audio: () => audioClips(session.world, session.captureScene).map((clip) => ({ ...clip, start: clip.start - outputOrigin, end: clip.end - outputOrigin })),
41495
+ audio: () => audioClips(session.world).map((clip) => ({ ...clip, start: clip.start - sourceStart, end: clip.end - sourceStart })),
40932
41496
  fontMisses: () => session.fontMisses(),
40933
41497
  async raw(frame, url2) {
40934
41498
  const ctx = context();
40935
41499
  const t0 = performance.now();
40936
- await renderOutputFrame(ctx, frame);
41500
+ await renderOutput(ctx, frame);
40937
41501
  const t1 = performance.now();
40938
41502
  const data = read(ctx);
40939
41503
  const t2 = performance.now();
@@ -40943,17 +41507,17 @@ var api = {
40943
41507
  },
40944
41508
  async digest(frame) {
40945
41509
  const ctx = context();
40946
- await renderOutputFrame(ctx, frame);
41510
+ await renderOutput(ctx, frame);
40947
41511
  const data = read(ctx);
40948
41512
  const hash = await crypto.subtle.digest("SHA-256", data);
40949
41513
  return [...new Uint8Array(hash)].map((b) => b.toString(16).padStart(2, "0")).join("");
40950
41514
  },
40951
41515
  async encodeCheck({ codec, bitrate }) {
40952
- const comp = outputComposition ?? session.comp;
41516
+ const comp = output;
40953
41517
  return await encodeProblem({ depth: depth2, codec, width: comp.width, height: comp.height, fps: comp.fps, bitrate }) ?? null;
40954
41518
  },
40955
41519
  async encodeStart({ url: url2, codec, quantizer, bitrate }) {
40956
- const comp = outputComposition ?? session.comp;
41520
+ const comp = output;
40957
41521
  context();
40958
41522
  encoder = await createWebCodecsEncoder(canvas, {
40959
41523
  depth: depth2,
@@ -40972,7 +41536,7 @@ var api = {
40972
41536
  async encodeFrame(frame, index) {
40973
41537
  const ctx = context();
40974
41538
  const t0 = performance.now();
40975
- await renderOutputFrame(ctx, frame);
41539
+ await renderOutput(ctx, frame);
40976
41540
  const t1 = performance.now();
40977
41541
  await encoder.add(index);
40978
41542
  return { renderMs: t1 - t0, encodeMs: performance.now() - t1 };
@@ -40986,6 +41550,30 @@ var api = {
40986
41550
  async encodeCancel() {
40987
41551
  await encoder?.cancel();
40988
41552
  encoder = void 0;
41553
+ },
41554
+ prerenderPlan: (key) => session.prerenderPlan(key) ?? null,
41555
+ prerenderInputs: () => session.prerenderInputs(),
41556
+ async prerenderPng(key, frame, height) {
41557
+ const { ctx, scale } = isolatedContext(key, height);
41558
+ await session.renderIsolated(ctx, key, frame, scale);
41559
+ return toBase64(await isolatedCanvas.convertToBlob({ type: "image/png" }));
41560
+ },
41561
+ async prerenderRaw(key, frame, height, url2) {
41562
+ const { ctx, scale } = isolatedContext(key, height);
41563
+ const t0 = performance.now();
41564
+ await session.renderIsolated(ctx, key, frame, scale);
41565
+ const data = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height).data;
41566
+ let opaque2 = true;
41567
+ for (let i = 3; i < data.length; i += 4) {
41568
+ if (data[i] !== 255) {
41569
+ opaque2 = false;
41570
+ break;
41571
+ }
41572
+ }
41573
+ const t1 = performance.now();
41574
+ const r = await fetch(url2, { method: "POST", body: new Blob([data]) });
41575
+ if (!r.ok) throw new Error(`POST ${url2}: ${r.status}`);
41576
+ return { renderMs: t1 - t0, sendMs: performance.now() - t1, opaque: opaque2 };
40989
41577
  }
40990
41578
  };
40991
41579
  globalThis.higgsedit = api;