framefields 2.0.2

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 (408) hide show
  1. package/LICENCE +202 -0
  2. package/README.md +740 -0
  3. package/dist/audio/index.d.mts +5 -0
  4. package/dist/audio/index.mjs +14 -0
  5. package/dist/audio-Dvwwz8xU.d.mts +37 -0
  6. package/dist/audio-Dvwwz8xU.d.mts.map +1 -0
  7. package/dist/audio-TAvPwzLR.mjs +214 -0
  8. package/dist/audio-TAvPwzLR.mjs.map +1 -0
  9. package/dist/audio-x28ZgQBP.mjs +85 -0
  10. package/dist/audio-x28ZgQBP.mjs.map +1 -0
  11. package/dist/chunk-GMkBE123.mjs +47 -0
  12. package/dist/client-C74hb7fy.mjs +66 -0
  13. package/dist/client-C74hb7fy.mjs.map +1 -0
  14. package/dist/dist-1iUYuPct.mjs +1859 -0
  15. package/dist/dist-1iUYuPct.mjs.map +1 -0
  16. package/dist/dist-Bx6J0VcM.mjs +1859 -0
  17. package/dist/dist-Bx6J0VcM.mjs.map +1 -0
  18. package/dist/dist-C_hjvkdN.mjs +2220 -0
  19. package/dist/dist-C_hjvkdN.mjs.map +1 -0
  20. package/dist/dist-DKm2IyEJ.mjs +94 -0
  21. package/dist/dist-DKm2IyEJ.mjs.map +1 -0
  22. package/dist/dist-cjs-B5EVqDFp.mjs +85 -0
  23. package/dist/dist-cjs-B5EVqDFp.mjs.map +1 -0
  24. package/dist/dist-cjs-BGJkdexX.mjs +437 -0
  25. package/dist/dist-cjs-BGJkdexX.mjs.map +1 -0
  26. package/dist/dist-cjs-BKmGCgtm.mjs +9069 -0
  27. package/dist/dist-cjs-BKmGCgtm.mjs.map +1 -0
  28. package/dist/dist-cjs-BUc0_kg-.mjs +1091 -0
  29. package/dist/dist-cjs-BUc0_kg-.mjs.map +1 -0
  30. package/dist/dist-cjs-BUwe2XhR.mjs +153 -0
  31. package/dist/dist-cjs-BUwe2XhR.mjs.map +1 -0
  32. package/dist/dist-cjs-BWgoUCXJ.mjs +137 -0
  33. package/dist/dist-cjs-BWgoUCXJ.mjs.map +1 -0
  34. package/dist/dist-cjs-CmZEMtO6.mjs +6 -0
  35. package/dist/dist-cjs-D7kEM-Mj.mjs +181 -0
  36. package/dist/dist-cjs-D7kEM-Mj.mjs.map +1 -0
  37. package/dist/dist-cjs-DFUmy89O.mjs +48 -0
  38. package/dist/dist-cjs-DFUmy89O.mjs.map +1 -0
  39. package/dist/dist-cjs-Df7144zM.mjs +209 -0
  40. package/dist/dist-cjs-Df7144zM.mjs.map +1 -0
  41. package/dist/dist-cjs-DgxjcvBN.mjs +98 -0
  42. package/dist/dist-cjs-DgxjcvBN.mjs.map +1 -0
  43. package/dist/dist-cjs-DsMdld8l.mjs +5015 -0
  44. package/dist/dist-cjs-DsMdld8l.mjs.map +1 -0
  45. package/dist/dist-cjs-Dzs5P3K0.mjs +51 -0
  46. package/dist/dist-cjs-Dzs5P3K0.mjs.map +1 -0
  47. package/dist/dist-cjs-ECMuIF57.mjs +323 -0
  48. package/dist/dist-cjs-ECMuIF57.mjs.map +1 -0
  49. package/dist/dist-cjs-lYvO8aDo.mjs +64 -0
  50. package/dist/dist-cjs-lYvO8aDo.mjs.map +1 -0
  51. package/dist/dist-cjs-qEJrwjGk.mjs +66 -0
  52. package/dist/dist-cjs-qEJrwjGk.mjs.map +1 -0
  53. package/dist/dist-cjs-x5cwlqA5.mjs +43 -0
  54. package/dist/dist-cjs-x5cwlqA5.mjs.map +1 -0
  55. package/dist/dist-gjHmorxL.mjs +27479 -0
  56. package/dist/dist-gjHmorxL.mjs.map +1 -0
  57. package/dist/effects/index.d.mts +5 -0
  58. package/dist/effects/index.mjs +35 -0
  59. package/dist/effects-CHWORCYd.mjs +811 -0
  60. package/dist/effects-CHWORCYd.mjs.map +1 -0
  61. package/dist/event-streams-D-APZ7Ke.mjs +204 -0
  62. package/dist/event-streams-D-APZ7Ke.mjs.map +1 -0
  63. package/dist/fonts/index.d.mts +2 -0
  64. package/dist/fonts/index.mjs +3 -0
  65. package/dist/fonts-DrGTBJJk.mjs +188 -0
  66. package/dist/fonts-DrGTBJJk.mjs.map +1 -0
  67. package/dist/index-B0BNPEoH.d.mts +2117 -0
  68. package/dist/index-B0BNPEoH.d.mts.map +1 -0
  69. package/dist/index-BMVVmc4G.d.mts +72 -0
  70. package/dist/index-BMVVmc4G.d.mts.map +1 -0
  71. package/dist/index-D1ZsMpke.d.mts +264 -0
  72. package/dist/index-D1ZsMpke.d.mts.map +1 -0
  73. package/dist/index-D2jDC7O5.d.mts +3643 -0
  74. package/dist/index-D2jDC7O5.d.mts.map +1 -0
  75. package/dist/index-D2wJqSl5.d.mts +114 -0
  76. package/dist/index-D2wJqSl5.d.mts.map +1 -0
  77. package/dist/index-DKFGNyMB.d.mts +309 -0
  78. package/dist/index-DKFGNyMB.d.mts.map +1 -0
  79. package/dist/index-DiSKzDGR.d.mts +65 -0
  80. package/dist/index-DiSKzDGR.d.mts.map +1 -0
  81. package/dist/index.d.mts +4425 -0
  82. package/dist/index.d.mts.map +1 -0
  83. package/dist/index.mjs +2623 -0
  84. package/dist/index.mjs.map +1 -0
  85. package/dist/package-C58KmGKw.mjs +6 -0
  86. package/dist/package-C58KmGKw.mjs.map +1 -0
  87. package/dist/preview/index.d.mts +90 -0
  88. package/dist/preview/index.d.mts.map +1 -0
  89. package/dist/preview/index.mjs +15 -0
  90. package/dist/preview-engine/audio.mjs +1 -0
  91. package/dist/preview-engine/child_process-AIL2NBWS.mjs +1 -0
  92. package/dist/preview-engine/chunk-24P6DAB3.mjs +1 -0
  93. package/dist/preview-engine/chunk-37EFVZWT.mjs +1 -0
  94. package/dist/preview-engine/chunk-3O5OKR6D.mjs +223 -0
  95. package/dist/preview-engine/chunk-47VT677S.mjs +8 -0
  96. package/dist/preview-engine/chunk-4BEJJKEU.mjs +315 -0
  97. package/dist/preview-engine/chunk-4GEWSUX5.mjs +1 -0
  98. package/dist/preview-engine/chunk-55CCFPUX.mjs +237 -0
  99. package/dist/preview-engine/chunk-5JD65JSJ.mjs +110 -0
  100. package/dist/preview-engine/chunk-5UP7FSGT.mjs +294 -0
  101. package/dist/preview-engine/chunk-5XDHHOF2.mjs +367 -0
  102. package/dist/preview-engine/chunk-6YJP57MZ.mjs +729 -0
  103. package/dist/preview-engine/chunk-6ZOXGAYA.mjs +112 -0
  104. package/dist/preview-engine/chunk-AOLAHYVV.mjs +529 -0
  105. package/dist/preview-engine/chunk-B6PLCMBM.mjs +1 -0
  106. package/dist/preview-engine/chunk-BJKH76OM.mjs +264 -0
  107. package/dist/preview-engine/chunk-BUIQ5TUH.mjs +104 -0
  108. package/dist/preview-engine/chunk-BVF64D6H.mjs +1 -0
  109. package/dist/preview-engine/chunk-CA5N7JRZ.mjs +138 -0
  110. package/dist/preview-engine/chunk-CNSHAFEA.mjs +1 -0
  111. package/dist/preview-engine/chunk-CURR5X7D.mjs +1 -0
  112. package/dist/preview-engine/chunk-CVGM2U4J.mjs +47 -0
  113. package/dist/preview-engine/chunk-CYY366IE.mjs +1 -0
  114. package/dist/preview-engine/chunk-D5PHI6ET.mjs +109 -0
  115. package/dist/preview-engine/chunk-D7MZHP2Y.mjs +275 -0
  116. package/dist/preview-engine/chunk-DPPH3NK2.mjs +182 -0
  117. package/dist/preview-engine/chunk-DPST2XLC.mjs +418 -0
  118. package/dist/preview-engine/chunk-DRLEOHN5.mjs +1 -0
  119. package/dist/preview-engine/chunk-EDIZNO3P.mjs +1 -0
  120. package/dist/preview-engine/chunk-EHIIT4ZR.mjs +52 -0
  121. package/dist/preview-engine/chunk-FKZ4XXPE.mjs +1 -0
  122. package/dist/preview-engine/chunk-G3HW4VER.mjs +60 -0
  123. package/dist/preview-engine/chunk-G76HSKOS.mjs +184 -0
  124. package/dist/preview-engine/chunk-GYG2IIBR.mjs +1 -0
  125. package/dist/preview-engine/chunk-H2F5NVQ6.mjs +63 -0
  126. package/dist/preview-engine/chunk-H5BPCY7N.mjs +188 -0
  127. package/dist/preview-engine/chunk-HAXK42HG.mjs +997 -0
  128. package/dist/preview-engine/chunk-HXMDPMLB.mjs +1 -0
  129. package/dist/preview-engine/chunk-HYBAPT6I.mjs +1 -0
  130. package/dist/preview-engine/chunk-I4FH6HYU.mjs +73 -0
  131. package/dist/preview-engine/chunk-IYVN2QEL.mjs +1 -0
  132. package/dist/preview-engine/chunk-JPXQPP6J.mjs +1 -0
  133. package/dist/preview-engine/chunk-JWNHTRED.mjs +164 -0
  134. package/dist/preview-engine/chunk-KZOLCZIV.mjs +103 -0
  135. package/dist/preview-engine/chunk-L62MRHGZ.mjs +89 -0
  136. package/dist/preview-engine/chunk-LEEZXHQO.mjs +117 -0
  137. package/dist/preview-engine/chunk-LKYN3BM2.mjs +1 -0
  138. package/dist/preview-engine/chunk-LP3EP33S.mjs +610 -0
  139. package/dist/preview-engine/chunk-M2GRYRLM.mjs +111 -0
  140. package/dist/preview-engine/chunk-MC7TZZLD.mjs +134 -0
  141. package/dist/preview-engine/chunk-MT2DZQHO.mjs +1 -0
  142. package/dist/preview-engine/chunk-MTJHQATU.mjs +1 -0
  143. package/dist/preview-engine/chunk-N4LHIPHZ.mjs +340 -0
  144. package/dist/preview-engine/chunk-N4PWLBZ7.mjs +5 -0
  145. package/dist/preview-engine/chunk-NQZKBFC6.mjs +40 -0
  146. package/dist/preview-engine/chunk-NWRSVVTF.mjs +186 -0
  147. package/dist/preview-engine/chunk-P3HBP725.mjs +1 -0
  148. package/dist/preview-engine/chunk-PIAJWALT.mjs +1 -0
  149. package/dist/preview-engine/chunk-PJ3DVG45.mjs +1 -0
  150. package/dist/preview-engine/chunk-QP2NI4XD.mjs +82 -0
  151. package/dist/preview-engine/chunk-SA3JUR6D.mjs +52 -0
  152. package/dist/preview-engine/chunk-SRT2OCQW.mjs +1 -0
  153. package/dist/preview-engine/chunk-SWD76532.mjs +98 -0
  154. package/dist/preview-engine/chunk-SXX7HX34.mjs +191 -0
  155. package/dist/preview-engine/chunk-SZ7YRPKO.mjs +3 -0
  156. package/dist/preview-engine/chunk-TMRLZV5X.mjs +1 -0
  157. package/dist/preview-engine/chunk-U446SQP3.mjs +292 -0
  158. package/dist/preview-engine/chunk-UDNCEHUI.mjs +141 -0
  159. package/dist/preview-engine/chunk-V3H7WWOT.mjs +271 -0
  160. package/dist/preview-engine/chunk-V7ZVVUQU.mjs +108 -0
  161. package/dist/preview-engine/chunk-VJGK7MLJ.mjs +3 -0
  162. package/dist/preview-engine/chunk-VSSB73UU.mjs +58 -0
  163. package/dist/preview-engine/chunk-VXUJWPIK.mjs +1 -0
  164. package/dist/preview-engine/chunk-XD4GKD6H.mjs +5 -0
  165. package/dist/preview-engine/chunk-XKO4RYKN.mjs +3 -0
  166. package/dist/preview-engine/chunk-XOEEGC4Z.mjs +1 -0
  167. package/dist/preview-engine/chunk-YAQFFQPG.mjs +1 -0
  168. package/dist/preview-engine/chunk-YKMBRUAE.mjs +1 -0
  169. package/dist/preview-engine/chunk-YSTLMWCG.mjs +1 -0
  170. package/dist/preview-engine/chunk-Z4ERCLNF.mjs +1 -0
  171. package/dist/preview-engine/chunk-ZEYUXJIV.mjs +1 -0
  172. package/dist/preview-engine/chunk-ZX6APG6E.mjs +117 -0
  173. package/dist/preview-engine/effects.mjs +1 -0
  174. package/dist/preview-engine/esbuild-GWV7CM7D.mjs +1 -0
  175. package/dist/preview-engine/fonts.mjs +1 -0
  176. package/dist/preview-engine/framefields.mjs +1959 -0
  177. package/dist/preview-engine/onnxruntime-node-56GSZEH3.mjs +1 -0
  178. package/dist/preview-engine/player.mjs +155 -0
  179. package/dist/preview-engine/renderers-2AUSIYZN.mjs +1 -0
  180. package/dist/preview-engine/renderers-2QN6KZJP.mjs +1 -0
  181. package/dist/preview-engine/renderers-32SKW7ML.mjs +1 -0
  182. package/dist/preview-engine/renderers-5QYK6766.mjs +1 -0
  183. package/dist/preview-engine/renderers-6BJA6MSU.mjs +251 -0
  184. package/dist/preview-engine/renderers-6QAF3LQ2.mjs +1 -0
  185. package/dist/preview-engine/renderers-7AO5746S.mjs +296 -0
  186. package/dist/preview-engine/renderers-AFYKNM6N.mjs +1 -0
  187. package/dist/preview-engine/renderers-AGMH5CRH.mjs +1 -0
  188. package/dist/preview-engine/renderers-AHSGP6LY.mjs +126 -0
  189. package/dist/preview-engine/renderers-ASTBICLA.mjs +1 -0
  190. package/dist/preview-engine/renderers-BHVPLYNN.mjs +1 -0
  191. package/dist/preview-engine/renderers-D7PVQFVU.mjs +1 -0
  192. package/dist/preview-engine/renderers-DB4ABTNA.mjs +1 -0
  193. package/dist/preview-engine/renderers-F2NFJI5L.mjs +1 -0
  194. package/dist/preview-engine/renderers-FI7YHNLY.mjs +1 -0
  195. package/dist/preview-engine/renderers-GBHULMPH.mjs +1 -0
  196. package/dist/preview-engine/renderers-GUKQUMGG.mjs +55 -0
  197. package/dist/preview-engine/renderers-HGT7QDY3.mjs +1 -0
  198. package/dist/preview-engine/renderers-HOYLA7ZK.mjs +1 -0
  199. package/dist/preview-engine/renderers-KKI2D3MZ.mjs +1 -0
  200. package/dist/preview-engine/renderers-KRAJNV4E.mjs +1 -0
  201. package/dist/preview-engine/renderers-KUGZKSVE.mjs +1 -0
  202. package/dist/preview-engine/renderers-L2EQQIOC.mjs +1 -0
  203. package/dist/preview-engine/renderers-LK3NRMGR.mjs +1 -0
  204. package/dist/preview-engine/renderers-LX654SZ3.mjs +1 -0
  205. package/dist/preview-engine/renderers-MCFQFYEL.mjs +1 -0
  206. package/dist/preview-engine/renderers-O6HOYIPS.mjs +1 -0
  207. package/dist/preview-engine/renderers-OEVXCGE2.mjs +1 -0
  208. package/dist/preview-engine/renderers-QVD6C4CS.mjs +1 -0
  209. package/dist/preview-engine/renderers-R3XEYD5V.mjs +248 -0
  210. package/dist/preview-engine/renderers-RBFWJWVM.mjs +1 -0
  211. package/dist/preview-engine/renderers-RX3VLVLO.mjs +1 -0
  212. package/dist/preview-engine/renderers-SM6JP64K.mjs +1 -0
  213. package/dist/preview-engine/renderers-TKMAATVS.mjs +1 -0
  214. package/dist/preview-engine/renderers-UGZUPONY.mjs +1 -0
  215. package/dist/preview-engine/renderers-UTFXZE3G.mjs +1 -0
  216. package/dist/preview-engine/renderers-UWPH7HBH.mjs +1 -0
  217. package/dist/preview-engine/renderers-UZGECFVO.mjs +1 -0
  218. package/dist/preview-engine/renderers-VGU3LNLT.mjs +1 -0
  219. package/dist/preview-engine/renderers-W3VVM5HB.mjs +1 -0
  220. package/dist/preview-engine/renderers-WJUTT5BB.mjs +1 -0
  221. package/dist/preview-engine/renderers-XA2M4YXK.mjs +1 -0
  222. package/dist/preview-engine/renderers-XIHRFEFQ.mjs +1 -0
  223. package/dist/preview-engine/renderers-XJTA5MFG.mjs +1 -0
  224. package/dist/preview-engine/renderers-XLTY5APF.mjs +1 -0
  225. package/dist/preview-engine/renderers-XZ3VXFGZ.mjs +1 -0
  226. package/dist/preview-engine/renderers-YKUQUCTO.mjs +124 -0
  227. package/dist/preview-engine/renderers-YVN3EIOP.mjs +1 -0
  228. package/dist/preview-engine/renderers-YWRP23SZ.mjs +125 -0
  229. package/dist/preview-engine/renderers-ZPWOUWZJ.mjs +120 -0
  230. package/dist/preview-engine/resvg-js-VMU4A77S.mjs +1 -0
  231. package/dist/preview-engine/server-utils-2FAIV45N.mjs +1 -0
  232. package/dist/preview-engine/sharp-V6ZTBNDW.mjs +1 -0
  233. package/dist/preview-engine/shims/fs-promises.mjs +1 -0
  234. package/dist/preview-engine/shims/fs.mjs +1 -0
  235. package/dist/preview-engine/shims/module.mjs +1 -0
  236. package/dist/preview-engine/shims/os.mjs +1 -0
  237. package/dist/preview-engine/shims/path.mjs +1 -0
  238. package/dist/preview-engine/shims/url.mjs +1 -0
  239. package/dist/preview-engine/signals.mjs +1 -0
  240. package/dist/preview-engine/webgpu-NSSANM4F.mjs +1 -0
  241. package/dist/preview-uQM210iy.mjs +2149 -0
  242. package/dist/preview-uQM210iy.mjs.map +1 -0
  243. package/dist/program-Dl510wmI.mjs +5183 -0
  244. package/dist/program-Dl510wmI.mjs.map +1 -0
  245. package/dist/renderer/index.d.mts +3 -0
  246. package/dist/renderer/index.mjs +6 -0
  247. package/dist/renderer-3BNskNuJ.mjs +3 -0
  248. package/dist/renderer-7DOcIxFG.mjs +288 -0
  249. package/dist/renderer-7DOcIxFG.mjs.map +1 -0
  250. package/dist/renderer-9dHlMQGX.mjs +3 -0
  251. package/dist/renderer-B1CvhW4p.mjs +677 -0
  252. package/dist/renderer-B1CvhW4p.mjs.map +1 -0
  253. package/dist/renderer-B2XzjK0z.mjs +3 -0
  254. package/dist/renderer-B80s47yo.mjs +166 -0
  255. package/dist/renderer-B80s47yo.mjs.map +1 -0
  256. package/dist/renderer-B9-QSJcG.mjs +479 -0
  257. package/dist/renderer-B9-QSJcG.mjs.map +1 -0
  258. package/dist/renderer-BAQmR0Zo.mjs +3 -0
  259. package/dist/renderer-BDLnExoP.mjs +127 -0
  260. package/dist/renderer-BDLnExoP.mjs.map +1 -0
  261. package/dist/renderer-BGXU6vcW.mjs +270 -0
  262. package/dist/renderer-BGXU6vcW.mjs.map +1 -0
  263. package/dist/renderer-BGvORwkQ.mjs +3 -0
  264. package/dist/renderer-BLikd6BK.mjs +3 -0
  265. package/dist/renderer-BMovYRoR.mjs +3 -0
  266. package/dist/renderer-BQHbp-Sp.mjs +243 -0
  267. package/dist/renderer-BQHbp-Sp.mjs.map +1 -0
  268. package/dist/renderer-BREIjsUU.mjs +252 -0
  269. package/dist/renderer-BREIjsUU.mjs.map +1 -0
  270. package/dist/renderer-BSbTJBWc.mjs +3 -0
  271. package/dist/renderer-BTu2EVhF.mjs +3 -0
  272. package/dist/renderer-BU1rwNRT.mjs +3 -0
  273. package/dist/renderer-BXMmISWG.mjs +499 -0
  274. package/dist/renderer-BXMmISWG.mjs.map +1 -0
  275. package/dist/renderer-BZJm3m4f.mjs +3 -0
  276. package/dist/renderer-B_NuVaIP.mjs +744 -0
  277. package/dist/renderer-B_NuVaIP.mjs.map +1 -0
  278. package/dist/renderer-BfJSUjPN.mjs +3 -0
  279. package/dist/renderer-BqyAgNt3.mjs +3 -0
  280. package/dist/renderer-BryTM2g7.mjs +3 -0
  281. package/dist/renderer-BsgIcBKH.mjs +391 -0
  282. package/dist/renderer-BsgIcBKH.mjs.map +1 -0
  283. package/dist/renderer-ByDhfrPE.mjs +422 -0
  284. package/dist/renderer-ByDhfrPE.mjs.map +1 -0
  285. package/dist/renderer-C-H680_l.mjs +3 -0
  286. package/dist/renderer-C17wL9QX.mjs +181 -0
  287. package/dist/renderer-C17wL9QX.mjs.map +1 -0
  288. package/dist/renderer-C2n-EHxg.mjs +1 -0
  289. package/dist/renderer-CB5aWAaf.mjs +343 -0
  290. package/dist/renderer-CB5aWAaf.mjs.map +1 -0
  291. package/dist/renderer-CB7lH5K8.mjs +3 -0
  292. package/dist/renderer-CDLrNgfo.mjs +3 -0
  293. package/dist/renderer-CDOUAN7X.mjs +454 -0
  294. package/dist/renderer-CDOUAN7X.mjs.map +1 -0
  295. package/dist/renderer-CH8sdfYX.mjs +387 -0
  296. package/dist/renderer-CH8sdfYX.mjs.map +1 -0
  297. package/dist/renderer-CIvaRnP_.mjs +261 -0
  298. package/dist/renderer-CIvaRnP_.mjs.map +1 -0
  299. package/dist/renderer-CMzEjdzi.mjs +369 -0
  300. package/dist/renderer-CMzEjdzi.mjs.map +1 -0
  301. package/dist/renderer-COkcU3db.mjs +3302 -0
  302. package/dist/renderer-COkcU3db.mjs.map +1 -0
  303. package/dist/renderer-CQCoggIa.mjs +3 -0
  304. package/dist/renderer-CQdVj2JS.mjs +3 -0
  305. package/dist/renderer-CQiTodg9.mjs +337 -0
  306. package/dist/renderer-CQiTodg9.mjs.map +1 -0
  307. package/dist/renderer-CV2m6k1V.mjs +3 -0
  308. package/dist/renderer-CYY-poLe.mjs +3 -0
  309. package/dist/renderer-CZgB5st8.mjs +3 -0
  310. package/dist/renderer-C_Ki91kc.mjs +3 -0
  311. package/dist/renderer-CclIvsLO.mjs +3 -0
  312. package/dist/renderer-Cj-whdVr.mjs +655 -0
  313. package/dist/renderer-Cj-whdVr.mjs.map +1 -0
  314. package/dist/renderer-CkykdR_D.mjs +3 -0
  315. package/dist/renderer-Cl1oUXMi.mjs +1143 -0
  316. package/dist/renderer-Cl1oUXMi.mjs.map +1 -0
  317. package/dist/renderer-CmApuKjS.mjs +3 -0
  318. package/dist/renderer-CpkiHRhh.mjs +269 -0
  319. package/dist/renderer-CpkiHRhh.mjs.map +1 -0
  320. package/dist/renderer-CszOjcRW.mjs +3 -0
  321. package/dist/renderer-CtVkU_GA.mjs +44 -0
  322. package/dist/renderer-CtVkU_GA.mjs.map +1 -0
  323. package/dist/renderer-Cu074POw.mjs +3 -0
  324. package/dist/renderer-CwQhzcUn.mjs +644 -0
  325. package/dist/renderer-CwQhzcUn.mjs.map +1 -0
  326. package/dist/renderer-CzPWB0Ss.mjs +273 -0
  327. package/dist/renderer-CzPWB0Ss.mjs.map +1 -0
  328. package/dist/renderer-D4qLmox-.mjs +3 -0
  329. package/dist/renderer-D6bWQtr-.mjs +3 -0
  330. package/dist/renderer-D6cJ6MSq.mjs +3 -0
  331. package/dist/renderer-D7EX8IjU.mjs +240 -0
  332. package/dist/renderer-D7EX8IjU.mjs.map +1 -0
  333. package/dist/renderer-DDp7_TUi.d.mts +10 -0
  334. package/dist/renderer-DDp7_TUi.d.mts.map +1 -0
  335. package/dist/renderer-DFKsLrUs.mjs +256 -0
  336. package/dist/renderer-DFKsLrUs.mjs.map +1 -0
  337. package/dist/renderer-DPSsf8-t.mjs +3 -0
  338. package/dist/renderer-DQLGnEFc.mjs +3 -0
  339. package/dist/renderer-DY2SVYUW.mjs +3 -0
  340. package/dist/renderer-DZGtBUCx.mjs +792 -0
  341. package/dist/renderer-DZGtBUCx.mjs.map +1 -0
  342. package/dist/renderer-DabG62XS.mjs +406 -0
  343. package/dist/renderer-DabG62XS.mjs.map +1 -0
  344. package/dist/renderer-DbaQLI4z.mjs +771 -0
  345. package/dist/renderer-DbaQLI4z.mjs.map +1 -0
  346. package/dist/renderer-DjI45OYC.mjs +71 -0
  347. package/dist/renderer-DjI45OYC.mjs.map +1 -0
  348. package/dist/renderer-Dm08-hAU.mjs +323 -0
  349. package/dist/renderer-Dm08-hAU.mjs.map +1 -0
  350. package/dist/renderer-DoAY5JbB.mjs +4 -0
  351. package/dist/renderer-Dp_FfvF-.mjs +401 -0
  352. package/dist/renderer-Dp_FfvF-.mjs.map +1 -0
  353. package/dist/renderer-Dt6fzgX5.mjs +756 -0
  354. package/dist/renderer-Dt6fzgX5.mjs.map +1 -0
  355. package/dist/renderer-DuplLRbp.mjs +3 -0
  356. package/dist/renderer-DvfUbZ31.mjs +3 -0
  357. package/dist/renderer-DxjVQV6f.mjs +311 -0
  358. package/dist/renderer-DxjVQV6f.mjs.map +1 -0
  359. package/dist/renderer-Fco4EmAu.mjs +23868 -0
  360. package/dist/renderer-Fco4EmAu.mjs.map +1 -0
  361. package/dist/renderer-HFfcJlmR.mjs +981 -0
  362. package/dist/renderer-HFfcJlmR.mjs.map +1 -0
  363. package/dist/renderer-I-Sw3JBB.mjs +145 -0
  364. package/dist/renderer-I-Sw3JBB.mjs.map +1 -0
  365. package/dist/renderer-OWQmmg4Z.mjs +697 -0
  366. package/dist/renderer-OWQmmg4Z.mjs.map +1 -0
  367. package/dist/renderer-Q_uUQipO.mjs +3 -0
  368. package/dist/renderer-Ryo2CEFD.mjs +586 -0
  369. package/dist/renderer-Ryo2CEFD.mjs.map +1 -0
  370. package/dist/renderer-Tp6OXWNZ.mjs +257 -0
  371. package/dist/renderer-Tp6OXWNZ.mjs.map +1 -0
  372. package/dist/renderer-UQFCgeNx.mjs +3 -0
  373. package/dist/renderer-WkVrkCVA.mjs +83 -0
  374. package/dist/renderer-WkVrkCVA.mjs.map +1 -0
  375. package/dist/renderer-XcmYTd6P.mjs +3818 -0
  376. package/dist/renderer-XcmYTd6P.mjs.map +1 -0
  377. package/dist/renderer-_uvdg48N.mjs +333 -0
  378. package/dist/renderer-_uvdg48N.mjs.map +1 -0
  379. package/dist/renderer-bZU_ndxf.mjs +8 -0
  380. package/dist/renderer-bZU_ndxf.mjs.map +1 -0
  381. package/dist/renderer-eMsnzJg9.mjs +3 -0
  382. package/dist/renderer-ho_jXJ0H.mjs +254 -0
  383. package/dist/renderer-ho_jXJ0H.mjs.map +1 -0
  384. package/dist/renderer-k2JL79kM.mjs +306 -0
  385. package/dist/renderer-k2JL79kM.mjs.map +1 -0
  386. package/dist/renderer-pHiz78e0.mjs +3 -0
  387. package/dist/renderer-pxXf9dvk.mjs +394 -0
  388. package/dist/renderer-pxXf9dvk.mjs.map +1 -0
  389. package/dist/renderer-vCFTm0oe.mjs +226 -0
  390. package/dist/renderer-vCFTm0oe.mjs.map +1 -0
  391. package/dist/renderer-vvpdx1vk.mjs +379 -0
  392. package/dist/renderer-vvpdx1vk.mjs.map +1 -0
  393. package/dist/renderer-x2s9LmVL.mjs +1121 -0
  394. package/dist/renderer-x2s9LmVL.mjs.map +1 -0
  395. package/dist/renderers-BWg16W-V-BXG_cjhM.mjs +49 -0
  396. package/dist/renderers-BWg16W-V-BXG_cjhM.mjs.map +1 -0
  397. package/dist/signals/index.d.mts +7 -0
  398. package/dist/signals/index.mjs +10 -0
  399. package/dist/signals-BwbdO3AN.mjs +224 -0
  400. package/dist/signals-BwbdO3AN.mjs.map +1 -0
  401. package/dist/signin-CZj4Oc5s.mjs +865 -0
  402. package/dist/signin-CZj4Oc5s.mjs.map +1 -0
  403. package/dist/sso-oidc-C0_31ThY.mjs +1051 -0
  404. package/dist/sso-oidc-C0_31ThY.mjs.map +1 -0
  405. package/dist/sts-DD4ggEXC.mjs +6 -0
  406. package/dist/sts-nXw8RDJI.mjs +1395 -0
  407. package/dist/sts-nXw8RDJI.mjs.map +1 -0
  408. package/package.json +173 -0
@@ -0,0 +1,3302 @@
1
+ import { Nt as reportRenderDiagnostic, bt as getActiveMediaMetadata, f as DEFAULT_DURATION_MS } from "./dist-Bx6J0VcM.mjs";
2
+ import { n as defineRenderer, t as audioRegistry } from "./renderer-CtVkU_GA.mjs";
3
+ import { I as generateExtrudedTextGeometry, J as parseColor, K as measureMaxCaptionHeight, Q as poseNodes, S as Vector3Math, V as jointMatrices, a as Camera3D, g as ScreenSpaceRelightPipeline, l as Matrix4Math, m as Renderer3D, n as AudioLatentTrackCache, nt as srtLoader, st as resolveMediaSourceUrl, y as SlugFontCache } from "./dist-gjHmorxL.mjs";
4
+ import { a as resolveLayerDuration, g as measureText, n as decodeAudioSource } from "./dist-1iUYuPct.mjs";
5
+ import { o as TemporalDeflickerPipeline } from "./dist-C_hjvkdN.mjs";
6
+ import { Gt as initLayout, Rt as evaluateTrackAtFrame, St as computeLayout, vt as collectNodeOps } from "./program-Dl510wmI.mjs";
7
+ import gsapModule from "gsap";
8
+
9
+ //#region ../../nodes/node-compositor/dist/renderers-DoYYCzgA.mjs
10
+ /**
11
+ * Solves a cubic bezier curve defined by control points (x1, y1) and (x2, y2)
12
+ * for a given progress parameter t in [0, 1].
13
+ */
14
+ function solveCubicBezier(x1, y1, x2, y2, t) {
15
+ if (t <= 0) return 0;
16
+ if (t >= 1) return 1;
17
+ if (x1 === y1 && x2 === y2) return t;
18
+ let u = t;
19
+ for (let i = 0; i < 8; i++) {
20
+ const oneMinusU$1 = 1 - u;
21
+ const oneMinusU2 = oneMinusU$1 * oneMinusU$1;
22
+ const u2 = u * u;
23
+ const diff = 3 * oneMinusU2 * u * x1 + 3 * oneMinusU$1 * u2 * x2 + u2 * u - t;
24
+ if (Math.abs(diff) < 1e-6) break;
25
+ const dx = 3 * oneMinusU2 * x1 + 6 * oneMinusU$1 * u * (x2 - x1) + 3 * u2 * (1 - x2);
26
+ if (Math.abs(dx) < 1e-6) break;
27
+ u -= diff / dx;
28
+ u = Math.max(0, Math.min(1, u));
29
+ }
30
+ const oneMinusU = 1 - u;
31
+ const checkX = 3 * oneMinusU * oneMinusU * u * x1 + 3 * oneMinusU * u * u * x2 + u * u * u;
32
+ if (Math.abs(checkX - t) > .001) {
33
+ let low = 0;
34
+ let high = 1;
35
+ u = t;
36
+ for (let i = 0; i < 16; i++) {
37
+ const mid = (low + high) * .5;
38
+ const oMid = 1 - mid;
39
+ const xMid = 3 * oMid * oMid * mid * x1 + 3 * oMid * mid * mid * x2 + mid * mid * mid;
40
+ if (Math.abs(xMid - t) < 1e-5) {
41
+ u = mid;
42
+ break;
43
+ }
44
+ if (xMid < t) low = mid;
45
+ else high = mid;
46
+ u = mid;
47
+ }
48
+ }
49
+ const oU = 1 - u;
50
+ return 3 * oU * oU * u * y1 + 3 * oU * u * u * y2 + u * u * u;
51
+ }
52
+ const gsap = gsapModule.timeline ? gsapModule : gsapModule.default || gsapModule;
53
+ const cache = /* @__PURE__ */ new Map();
54
+ const nodesHashMemo = /* @__PURE__ */ new WeakMap();
55
+ /** Entries untouched for this long are dropped (and their timeline killed). */
56
+ const CACHE_TTL_MS = 1e4;
57
+ /** Max compiled timelines retained per cache. */
58
+ const TIMELINE_CACHE_MAX = 50;
59
+ const LAYER_TIMELINE_CACHE_MAX = 50;
60
+ function fnv1a(str) {
61
+ let hash = 2166136261;
62
+ for (let i = 0; i < str.length; i++) {
63
+ hash ^= str.charCodeAt(i);
64
+ hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
65
+ }
66
+ return (hash >>> 0).toString(16);
67
+ }
68
+ const signalIds = /* @__PURE__ */ new WeakMap();
69
+ let nextSignalId = 0;
70
+ function signalsKey(signals) {
71
+ if (!signals || typeof signals !== "object") return stableStringify(signals);
72
+ return Object.keys(signals).sort().map((name) => {
73
+ const s = signals[name];
74
+ if (s && typeof s === "object" && typeof s.get === "function") {
75
+ let id = signalIds.get(s);
76
+ if (id === void 0) {
77
+ id = nextSignalId++;
78
+ signalIds.set(s, id);
79
+ }
80
+ return `${JSON.stringify(name)}:#${id}`;
81
+ }
82
+ return `${JSON.stringify(name)}:${stableStringify(s)}`;
83
+ }).join(",");
84
+ }
85
+ /**
86
+ * Paused gsap timelines stay attached to gsap's global timeline until killed,
87
+ * so anything dropped from a cache must be killed or it is never collected.
88
+ */
89
+ function release(value) {
90
+ value.tl.kill();
91
+ }
92
+ /**
93
+ * Make room for one insertion: drop and kill TTL-expired entries, then evict
94
+ * the least-recently-used entry if the cache is at capacity. Every dropped
95
+ * timeline MUST be killed — see `release`.
96
+ */
97
+ function evictForInsert(cache$1, maxSize) {
98
+ const now = Date.now();
99
+ for (const [key, entry] of cache$1.entries()) if (now - entry.cacheTime > CACHE_TTL_MS) {
100
+ cache$1.delete(key);
101
+ release(entry.value);
102
+ }
103
+ if (cache$1.size >= maxSize) {
104
+ const oldestKey = cache$1.keys().next().value;
105
+ if (oldestKey !== void 0) {
106
+ const oldest = cache$1.get(oldestKey);
107
+ cache$1.delete(oldestKey);
108
+ if (oldest) release(oldest.value);
109
+ }
110
+ }
111
+ }
112
+ function stableStringify(obj) {
113
+ if (obj === null) return "null";
114
+ if (obj === void 0) return "undefined";
115
+ if (typeof obj !== "object") return JSON.stringify(obj);
116
+ if (ArrayBuffer.isView(obj)) return `[TypedArray:${obj.byteLength}]`;
117
+ if (Array.isArray(obj)) return "[" + obj.map(stableStringify).join(",") + "]";
118
+ return "{" + Object.keys(obj).sort().map((key) => {
119
+ return `${JSON.stringify(key)}:${stableStringify(obj[key])}`;
120
+ }).join(",") + "}";
121
+ }
122
+ function getCachedTimeline(cacheKey) {
123
+ const entry = cache.get(cacheKey);
124
+ if (entry) {
125
+ if (Date.now() - entry.cacheTime > CACHE_TTL_MS) {
126
+ cache.delete(cacheKey);
127
+ release(entry.value);
128
+ return;
129
+ }
130
+ entry.cacheTime = Date.now();
131
+ cache.delete(cacheKey);
132
+ cache.set(cacheKey, entry);
133
+ return entry.value;
134
+ }
135
+ }
136
+ function setCachedTimeline(cacheKey, value) {
137
+ evictForInsert(cache, TIMELINE_CACHE_MAX);
138
+ cache.set(cacheKey, {
139
+ cacheTime: Date.now(),
140
+ value
141
+ });
142
+ }
143
+ function mappedEase(ease, durationFrames, fps = 24) {
144
+ if (!ease) return "none";
145
+ const { name, dir, params } = ease;
146
+ if (name === "none") return "none";
147
+ if (name === "spring") {
148
+ const damping = Math.max(.001, params?.[0] ?? 10);
149
+ const stiffness = Math.max(.001, params?.[1] ?? 100);
150
+ const mass = Math.max(.001, params?.[2] ?? 1);
151
+ return (p) => {
152
+ const t = p * (durationFrames && durationFrames > 0 ? durationFrames / (fps > 0 ? fps : 24) : 1);
153
+ const m = mass;
154
+ const k = stiffness;
155
+ const c = damping;
156
+ const w0 = Math.sqrt(k / m);
157
+ const zeta = c / (2 * Math.sqrt(k * m));
158
+ let x = 0;
159
+ if (zeta < 1) {
160
+ const wd = w0 * Math.sqrt(1 - zeta * zeta);
161
+ const A = -1;
162
+ const B = -zeta * w0 / wd;
163
+ x = Math.exp(-zeta * w0 * t) * (A * Math.cos(wd * t) + B * Math.sin(wd * t));
164
+ } else if (zeta === 1) {
165
+ const A = -1;
166
+ const B = -w0;
167
+ x = Math.exp(-w0 * t) * (A + B * t);
168
+ } else {
169
+ const r1 = -w0 * (zeta - Math.sqrt(zeta * zeta - 1));
170
+ const r2 = -w0 * (zeta + Math.sqrt(zeta * zeta - 1));
171
+ const C1 = -1 / (1 - r1 / r2);
172
+ const C2 = -1 - C1;
173
+ x = C1 * Math.exp(r1 * t) + C2 * Math.exp(r2 * t);
174
+ }
175
+ return 1 + x;
176
+ };
177
+ }
178
+ if (name === "cubic") {
179
+ const x1 = params?.[0] ?? .25;
180
+ const y1 = params?.[1] ?? .1;
181
+ const x2 = params?.[2] ?? .25;
182
+ const y2 = params?.[3] ?? 1;
183
+ return (p) => solveCubicBezier(x1, y1, x2, y2, p);
184
+ }
185
+ if (name === "hold") return (p) => p >= .9999 ? 1 : 0;
186
+ const easeName = name;
187
+ let suffix = "";
188
+ if (params && params.length > 0) suffix = `(${params.join(", ")})`;
189
+ else if (name === "back") suffix = "(1.7)";
190
+ else if (name === "elastic") suffix = "(1, 0.3)";
191
+ return `${easeName}.${dir}${suffix}`;
192
+ }
193
+ function compileTrackToTimeline(tl, stub, track, startFrame, fps, durationFrames, signals) {
194
+ const prop = track.prop;
195
+ if ((track.source ?? { type: "keyframe" }).type !== "keyframe") {
196
+ const endF = Number.isFinite(durationFrames) ? durationFrames : Math.round(fps * 5);
197
+ const frameStepSec = 1 / fps;
198
+ const kfList = [];
199
+ const firstVal = evaluateTrackAtFrame(track, startFrame, fps, {
200
+ startFrame,
201
+ baseValues: stub,
202
+ signals
203
+ });
204
+ stub[prop] = firstVal;
205
+ kfList.push({
206
+ [prop]: firstVal,
207
+ duration: 0
208
+ });
209
+ for (let f = 1; f <= endF; f++) {
210
+ const val = evaluateTrackAtFrame(track, startFrame + f, fps, {
211
+ startFrame,
212
+ baseValues: stub,
213
+ signals
214
+ });
215
+ kfList.push({
216
+ [prop]: val,
217
+ duration: frameStepSec,
218
+ ease: "none"
219
+ });
220
+ }
221
+ tl.to(stub, {
222
+ keyframes: kfList,
223
+ repeat: track.repeat ?? 0,
224
+ yoyo: !!track.yoyo,
225
+ lazy: false,
226
+ overwrite: false,
227
+ immediateRender: false
228
+ }, startFrame / fps);
229
+ return {
230
+ dropped: 0,
231
+ maxAuthoredFrame: 0
232
+ };
233
+ }
234
+ const sortedKeyframes = [...track.keyframes].sort((a, b) => a.frame - b.frame);
235
+ const validKeyframes = sortedKeyframes.filter((kf) => kf.frame >= 0 && kf.frame <= durationFrames);
236
+ const dropped = sortedKeyframes.length - validKeyframes.length;
237
+ const maxAuthoredFrame = dropped > 0 ? sortedKeyframes[sortedKeyframes.length - 1].frame : 0;
238
+ if (validKeyframes.length === 0) return {
239
+ dropped,
240
+ maxAuthoredFrame
241
+ };
242
+ if (prop === "hidden" || prop === "muted") for (const kf of validKeyframes) {
243
+ const absoluteSec = (startFrame + kf.frame) / fps;
244
+ tl.set(stub, {
245
+ [prop]: kf.value,
246
+ immediateRender: false
247
+ }, absoluteSec);
248
+ }
249
+ else {
250
+ const repeat = track.repeat ?? 0;
251
+ const yoyo = !!track.yoyo;
252
+ if (validKeyframes.length === 1) {
253
+ const kf0 = validKeyframes[0];
254
+ const absoluteSec = (startFrame + kf0.frame) / fps;
255
+ tl.set(stub, {
256
+ [prop]: kf0.value,
257
+ immediateRender: false
258
+ }, absoluteSec);
259
+ } else if (validKeyframes.length === 2) {
260
+ const kf0 = validKeyframes[0];
261
+ const kf1 = validKeyframes[1];
262
+ const val0 = kf0.value;
263
+ const val1 = kf1.value;
264
+ const startSec = (startFrame + kf0.frame) / fps;
265
+ const durSec = (kf1.frame - kf0.frame) / fps;
266
+ const trackDurationFrames = track.durationFrames ?? kf1.frame - kf0.frame;
267
+ const easeVal = mappedEase(kf1.ease ?? kf0.ease, trackDurationFrames, fps);
268
+ if (val0 === stub[prop]) tl.to(stub, {
269
+ [prop]: val1,
270
+ duration: durSec,
271
+ ease: easeVal,
272
+ repeat,
273
+ yoyo,
274
+ lazy: false,
275
+ overwrite: false,
276
+ immediateRender: false
277
+ }, startSec);
278
+ else tl.fromTo(stub, { [prop]: val0 }, {
279
+ [prop]: val1,
280
+ duration: durSec,
281
+ ease: easeVal,
282
+ repeat,
283
+ yoyo,
284
+ lazy: false,
285
+ overwrite: false,
286
+ immediateRender: false
287
+ }, startSec);
288
+ } else {
289
+ const kf0 = validKeyframes[0];
290
+ const startSec = (startFrame + kf0.frame) / fps;
291
+ const kfList = [];
292
+ kfList.push({
293
+ [prop]: kf0.value,
294
+ duration: 0
295
+ });
296
+ for (let i = 1; i < validKeyframes.length; i++) {
297
+ const prevKf = validKeyframes[i - 1];
298
+ const currKf = validKeyframes[i];
299
+ const deltaFrames = currKf.frame - prevKf.frame;
300
+ const durSec = deltaFrames / fps;
301
+ const easeVal = mappedEase(currKf.ease, deltaFrames, fps);
302
+ kfList.push({
303
+ [prop]: currKf.value,
304
+ duration: durSec,
305
+ ease: easeVal
306
+ });
307
+ }
308
+ tl.to(stub, {
309
+ keyframes: kfList,
310
+ repeat,
311
+ yoyo,
312
+ lazy: false,
313
+ overwrite: false,
314
+ immediateRender: false
315
+ }, startSec);
316
+ }
317
+ }
318
+ return {
319
+ dropped,
320
+ maxAuthoredFrame
321
+ };
322
+ }
323
+ /**
324
+ * Dedupe per compiled cache key — a fresh render of the same broken doc SHOULD
325
+ * re-warn. Single-frame renders are the exception: each `renderFrame` call has
326
+ * its own `img-` render id, so probing a doc frame by frame would repeat the
327
+ * warning on every frame; those dedupe per document instead.
328
+ */
329
+ const truncationWarnedKeys = /* @__PURE__ */ new Set();
330
+ const TRUNCATION_WARNED_CAP = 100;
331
+ function warnTruncationOnce(cacheKey, truncations) {
332
+ if (truncationWarnedKeys.has(cacheKey)) return;
333
+ if (truncationWarnedKeys.size >= TRUNCATION_WARNED_CAP) truncationWarnedKeys.clear();
334
+ truncationWarnedKeys.add(cacheKey);
335
+ const details = truncations.map((t) => `'${t.prop}' (track '${t.trackId}') on '${t.layerId}': ${t.dropped} keyframe(s) past the clip window (last authored frame ${t.maxAuthoredFrame})`).join("; ");
336
+ console.warn(`[compositor] ${truncations.length} track(s) truncated — animation tails will not play: ${details}. Extend durationFrames or move those keyframes.`);
337
+ }
338
+ function hashNodes(nodeOps, width, height, fps, durationSec) {
339
+ return fnv1a(stableStringify({
340
+ nodes: nodeOps.map((vm) => {
341
+ const lop = vm?.operation || {};
342
+ return {
343
+ id: lop.id,
344
+ animation: lop.animation,
345
+ startFrame: lop.startFrame,
346
+ durationFrames: lop.durationFrames,
347
+ x: lop.x,
348
+ y: lop.y,
349
+ scale: lop.scale,
350
+ rotation: lop.rotation,
351
+ opacity: lop.opacity,
352
+ volume: lop.volume,
353
+ width: lop.width,
354
+ height: lop.height,
355
+ hidden: lop.hidden,
356
+ muted: lop.muted,
357
+ backgroundColor: lop.backgroundColor,
358
+ fill: lop.fill,
359
+ borderColor: lop.borderColor,
360
+ textBackgroundColor: lop.textBackgroundColor,
361
+ rotateX: lop.rotateX,
362
+ rotateY: lop.rotateY,
363
+ rotateZ: lop.rotateZ,
364
+ perspective: lop.perspective,
365
+ perspectiveOriginX: lop.perspectiveOriginX,
366
+ perspectiveOriginY: lop.perspectiveOriginY,
367
+ translateZ: lop.translateZ,
368
+ backfaceVisibility: lop.backfaceVisibility,
369
+ transformStyle: lop.transformStyle,
370
+ is3D: lop.is3D,
371
+ z: lop.z,
372
+ scaleZ: lop.scaleZ,
373
+ twoSided: lop.twoSided,
374
+ cameraX: lop.cameraX,
375
+ cameraY: lop.cameraY,
376
+ cameraZ: lop.cameraZ,
377
+ targetX: lop.targetX,
378
+ targetY: lop.targetY,
379
+ targetZ: lop.targetZ,
380
+ cameraPitch: lop.cameraPitch,
381
+ cameraYaw: lop.cameraYaw,
382
+ cameraRoll: lop.cameraRoll,
383
+ cameraFov: lop.cameraFov,
384
+ cameraZoom: lop.cameraZoom,
385
+ focalLength: lop.focalLength,
386
+ focusDistance: lop.focusDistance,
387
+ fStop: lop.fStop,
388
+ maxBlurRadius: lop.maxBlurRadius,
389
+ shakeTranslation: lop.shakeTranslation,
390
+ shakeRotation: lop.shakeRotation,
391
+ orbitRadius: lop.orbitRadius,
392
+ orbitAzimuth: lop.orbitAzimuth,
393
+ orbitElevation: lop.orbitElevation,
394
+ material: lop.material,
395
+ shininess: lop.shininess,
396
+ roughness: lop.roughness,
397
+ specularIntensity: lop.specularIntensity,
398
+ ambientIntensity: lop.ambientIntensity,
399
+ metallic: lop.metallic,
400
+ lightType: lop.lightType,
401
+ intensity: lop.intensity,
402
+ radius: lop.radius,
403
+ angle: lop.angle,
404
+ penumbra: lop.penumbra,
405
+ animationProgress: lop.animationProgress,
406
+ animationTime: lop.animationTime,
407
+ animationSpeed: lop.animationSpeed,
408
+ wireframe: lop.wireframe,
409
+ scaleX: lop.scaleX,
410
+ scaleY: lop.scaleY,
411
+ fontSize: lop.fontSize,
412
+ text: lop.text
413
+ };
414
+ }),
415
+ width,
416
+ height,
417
+ fps,
418
+ durationSec
419
+ }));
420
+ }
421
+ function compileTimeline(renderId, virtualMedia, options) {
422
+ const fps = options.fps;
423
+ const durationSec = options.durationSec;
424
+ const width = virtualMedia?.metadata?.width ?? 1920;
425
+ const height = virtualMedia?.metadata?.height ?? 1080;
426
+ const nodeOps = collectNodeOps(virtualMedia?.children ?? []);
427
+ const memoKey = virtualMedia?.children;
428
+ const memo = memoKey ? nodesHashMemo.get(memoKey) : void 0;
429
+ let nodesHash;
430
+ if (memo && memo.width === width && memo.height === height && memo.fps === fps && memo.durationSec === durationSec) nodesHash = memo.hash;
431
+ else {
432
+ nodesHash = hashNodes(nodeOps, width, height, fps, durationSec);
433
+ if (memoKey) nodesHashMemo.set(memoKey, {
434
+ width,
435
+ height,
436
+ fps,
437
+ durationSec,
438
+ hash: nodesHash
439
+ });
440
+ }
441
+ const irHash = fnv1a(`${nodesHash}|${signalsKey(virtualMedia?.operation?.signals ?? virtualMedia?.signals)}`);
442
+ const cacheKey = `${renderId}_${irHash}`;
443
+ const cached = getCachedTimeline(cacheKey);
444
+ if (cached) return cached;
445
+ const tl = gsap.timeline({
446
+ paused: true,
447
+ smoothChildTiming: false
448
+ });
449
+ const targetsById = {};
450
+ const signals = virtualMedia?.operation?.signals ?? virtualMedia?.signals ?? {};
451
+ nodeOps.forEach((vm, index) => {
452
+ const lop = vm?.operation || {};
453
+ const layerId = lop.id || lop.inputHandleId || `layer_${index}`;
454
+ const stub = {
455
+ id: layerId,
456
+ inputHandleId: lop.inputHandleId || `layer_${index}`,
457
+ trackId: layerId,
458
+ x: lop.kind === "camera" || lop.kind === "light" ? lop.x ?? lop.cameraX : lop.x ?? 0,
459
+ y: lop.kind === "camera" || lop.kind === "light" ? lop.y ?? lop.cameraY : lop.y ?? 0,
460
+ scale: lop.scale ?? 1,
461
+ rotation: lop.rotation ?? 0,
462
+ opacity: lop.opacity ?? 1,
463
+ volume: lop.volume ?? 1,
464
+ width: lop.width,
465
+ height: lop.height,
466
+ hidden: !!lop.hidden,
467
+ muted: !!lop.muted,
468
+ rotateX: lop.rotateX ?? 0,
469
+ rotateY: lop.rotateY ?? 0,
470
+ rotateZ: lop.rotateZ ?? 0,
471
+ perspective: lop.perspective ?? 0,
472
+ perspectiveOriginX: lop.perspectiveOriginX ?? .5,
473
+ perspectiveOriginY: lop.perspectiveOriginY ?? .5,
474
+ translateZ: lop.translateZ ?? 0,
475
+ backfaceVisibility: lop.backfaceVisibility ?? "visible",
476
+ transformStyle: lop.transformStyle ?? "flat",
477
+ fontSize: lop.fontSize,
478
+ text: 1,
479
+ fill: lop.fill,
480
+ fillColor: lop.fillColor ?? lop.fill,
481
+ strokeColor: lop.strokeColor ?? lop.stroke,
482
+ strokeWidth: lop.strokeWidth,
483
+ letterSpacing: lop.letterSpacing,
484
+ firstMargin: lop.firstMargin ?? lop.pathOptions?.firstMargin,
485
+ lastMargin: lop.lastMargin ?? lop.pathOptions?.lastMargin,
486
+ baselineShift: lop.baselineShift ?? lop.pathOptions?.baselineShift,
487
+ offset: lop.offset,
488
+ rangeStart: lop.rangeStart,
489
+ rangeEnd: lop.rangeEnd,
490
+ animators: lop.animators,
491
+ pathOptions: lop.pathOptions,
492
+ typewriter: lop.typewriter,
493
+ marquee: lop.marquee,
494
+ is3D: lop.is3D ?? (lop.kind === "camera" || lop.kind === "light" || lop.kind === "model3d" ? true : false),
495
+ z: lop.z ?? (lop.kind === "camera" ? lop.z ?? -1500 : 0),
496
+ scaleZ: lop.scaleZ ?? 1,
497
+ twoSided: lop.twoSided ?? true,
498
+ material: lop.material,
499
+ shininess: lop.shininess,
500
+ roughness: lop.roughness,
501
+ specularIntensity: lop.specularIntensity,
502
+ ambientIntensity: lop.ambientIntensity,
503
+ metallic: lop.metallic,
504
+ animationProgress: lop.animationProgress ?? 0,
505
+ animationTime: lop.animationTime ?? 0,
506
+ animationSpeed: lop.animationSpeed ?? 1,
507
+ wireframe: lop.wireframe ?? false,
508
+ scaleX: lop.scaleX ?? 1,
509
+ scaleY: lop.scaleY ?? 1,
510
+ cameraX: lop.cameraX ?? (lop.kind === "camera" ? lop.x : void 0),
511
+ cameraY: lop.cameraY ?? (lop.kind === "camera" ? lop.y : void 0),
512
+ cameraZ: lop.cameraZ ?? (lop.kind === "camera" ? lop.z : void 0),
513
+ targetX: lop.targetX,
514
+ targetY: lop.targetY,
515
+ targetZ: lop.targetZ,
516
+ cameraPitch: lop.cameraPitch ?? lop.pitch ?? 0,
517
+ cameraYaw: lop.cameraYaw ?? lop.yaw ?? 0,
518
+ cameraRoll: lop.cameraRoll ?? lop.roll ?? 0,
519
+ cameraFov: lop.cameraFov ?? lop.lens?.fov ?? 50,
520
+ cameraZoom: lop.cameraZoom ?? lop.lens?.zoom ?? 1,
521
+ focalLength: lop.focalLength ?? lop.lens?.focalLength ?? 50,
522
+ focusDistance: lop.focusDistance ?? lop.dof?.focusDistance,
523
+ fStop: lop.fStop ?? lop.dof?.fStop ?? 2.8,
524
+ maxBlurRadius: lop.maxBlurRadius ?? lop.dof?.maxBlurRadius ?? 24,
525
+ shakeTranslation: lop.shakeTranslation ?? (lop.shake?.enabled ? lop.shake?.translationAmplitude ?? 0 : 0),
526
+ shakeRotation: lop.shakeRotation ?? (lop.shake?.enabled ? lop.shake?.rotationAmplitude ?? 0 : 0),
527
+ orbitRadius: lop.orbitRadius,
528
+ orbitAzimuth: lop.orbitAzimuth,
529
+ orbitElevation: lop.orbitElevation,
530
+ lightType: lop.lightType,
531
+ intensity: lop.intensity ?? (lop.kind === "light" ? 1 : void 0),
532
+ radius: lop.radius,
533
+ angle: lop.angle,
534
+ penumbra: lop.penumbra,
535
+ decay: lop.decay
536
+ };
537
+ for (const track of lop.animation?.tracks ?? []) if ((track.source ?? { type: "keyframe" }).type !== "keyframe") stub[track.prop] = evaluateTrackAtFrame(track, lop.startFrame ?? 0, fps, {
538
+ startFrame: lop.startFrame ?? 0,
539
+ baseValues: stub,
540
+ signals
541
+ });
542
+ else if (track.keyframes && track.keyframes.length > 0) {
543
+ const kf0 = track.keyframes[0];
544
+ const seeded = stub;
545
+ if (kf0.frame === 0) seeded[track.prop] = kf0.value;
546
+ else if (seeded[track.prop] === void 0) seeded[track.prop] = lop[track.prop] ?? kf0.value;
547
+ }
548
+ targetsById[layerId] = stub;
549
+ });
550
+ const truncations = [];
551
+ nodeOps.forEach((vm) => {
552
+ const lop = vm?.operation || {};
553
+ const layerId = lop.id || lop.inputHandleId;
554
+ const stub = layerId ? targetsById[layerId] : void 0;
555
+ if (!stub) return;
556
+ const startFrame = lop.startFrame ?? 0;
557
+ let durationFrames = lop.durationFrames;
558
+ if (durationFrames === void 0) {
559
+ const child = vm.children?.[0];
560
+ const childMeta = child ? getActiveMediaMetadata(child) : null;
561
+ const composeDuration = virtualMedia?.metadata?.durationMs ?? DEFAULT_DURATION_MS;
562
+ const layerType = lop.type ?? (lop.kind === "text" ? "Text" : lop.kind === "media" ? child ? child.operation?.dataType : void 0 : void 0);
563
+ const durationMs = resolveLayerDuration(void 0, childMeta?.durationMs ?? void 0, composeDuration, layerType);
564
+ durationFrames = Math.max(1, Math.round(durationMs / 1e3 * fps));
565
+ }
566
+ for (const track of lop.animation?.tracks ?? []) {
567
+ const { dropped, maxAuthoredFrame } = compileTrackToTimeline(tl, stub, track, startFrame, fps, durationFrames, signals);
568
+ if (dropped > 0) truncations.push({
569
+ layerId,
570
+ trackId: track.id,
571
+ prop: track.prop,
572
+ dropped,
573
+ maxAuthoredFrame
574
+ });
575
+ }
576
+ });
577
+ if (truncations.length > 0) {
578
+ warnTruncationOnce(renderId.startsWith("img-") ? `frame_${irHash}` : cacheKey, truncations);
579
+ for (const t of truncations) reportRenderDiagnostic(renderId, {
580
+ severity: "warning",
581
+ code: "animation_truncated",
582
+ layerId: t.layerId,
583
+ message: `'${t.prop}' on '${t.layerId}': ${t.dropped} keyframe(s) past the clip window (last authored frame ${t.maxAuthoredFrame}) never play`
584
+ });
585
+ }
586
+ tl.seek(1e-6);
587
+ tl.seek(0);
588
+ const compileResult = {
589
+ tl,
590
+ targetsById,
591
+ nodes: nodeOps
592
+ };
593
+ setCachedTimeline(cacheKey, compileResult);
594
+ return compileResult;
595
+ }
596
+ const layerTimelineCache = /* @__PURE__ */ new Map();
597
+ function compileLayerTimeline(layerId, animation, baseVolume, baseMuted, fps) {
598
+ const cacheKey = `layer_${layerId}_${fnv1a(stableStringify({
599
+ animation,
600
+ baseVolume,
601
+ baseMuted,
602
+ fps
603
+ }))}`;
604
+ const cached = layerTimelineCache.get(cacheKey);
605
+ if (cached) {
606
+ if (Date.now() - cached.cacheTime <= CACHE_TTL_MS) {
607
+ cached.cacheTime = Date.now();
608
+ return cached.value;
609
+ }
610
+ layerTimelineCache.delete(cacheKey);
611
+ release(cached.value);
612
+ }
613
+ const tl = gsap.timeline({
614
+ paused: true,
615
+ smoothChildTiming: false
616
+ });
617
+ const stub = {
618
+ volume: baseVolume,
619
+ muted: baseMuted
620
+ };
621
+ const tracks = animation?.tracks ?? [];
622
+ for (const track of tracks) {
623
+ const prop = track.prop;
624
+ if (prop !== "volume" && prop !== "muted") continue;
625
+ compileTrackToTimeline(tl, stub, track, 0, fps, Infinity);
626
+ }
627
+ tl.seek(1e-6);
628
+ tl.seek(0);
629
+ const result = {
630
+ tl,
631
+ stub
632
+ };
633
+ evictForInsert(layerTimelineCache, LAYER_TIMELINE_CACHE_MAX);
634
+ layerTimelineCache.set(cacheKey, {
635
+ cacheTime: Date.now(),
636
+ value: result
637
+ });
638
+ return result;
639
+ }
640
+ /**
641
+ * Which container kinds paint their own background.
642
+ *
643
+ * flex/block/box all accept an optional `background` in the program schema.
644
+ * The renderer must draw the rounded background pass for ALL of them (the old
645
+ * code only painted `box`, so flex/block backgrounds were silently dropped and
646
+ * their "transparent-optimized" fast path skipped the fill entirely).
647
+ */
648
+ function shouldPaintContainerBackground(kind, background) {
649
+ if (!background) return false;
650
+ return kind === "flex" || kind === "block" || kind === "box";
651
+ }
652
+ function translate(tx, ty) {
653
+ return {
654
+ a: 1,
655
+ b: 0,
656
+ c: 0,
657
+ d: 1,
658
+ e: tx,
659
+ f: ty
660
+ };
661
+ }
662
+ /** Rotation in degrees (screen convention: positive = clockwise, y-down). */
663
+ function rotate(degrees) {
664
+ const rad = degrees * Math.PI / 180;
665
+ const cos = Math.cos(rad);
666
+ const sin = Math.sin(rad);
667
+ return {
668
+ a: cos,
669
+ b: sin,
670
+ c: -sin,
671
+ d: cos,
672
+ e: 0,
673
+ f: 0
674
+ };
675
+ }
676
+ function scale(sx, sy = sx) {
677
+ return {
678
+ a: sx,
679
+ b: 0,
680
+ c: 0,
681
+ d: sy,
682
+ e: 0,
683
+ f: 0
684
+ };
685
+ }
686
+ /** m1 ∘ m2 (m2 applied first — matches DOMMatrix.multiply ordering). */
687
+ function multiply(m1, m2) {
688
+ return {
689
+ a: m1.a * m2.a + m1.c * m2.b,
690
+ b: m1.b * m2.a + m1.d * m2.b,
691
+ c: m1.a * m2.c + m1.c * m2.d,
692
+ d: m1.b * m2.c + m1.d * m2.d,
693
+ e: m1.a * m2.e + m1.c * m2.f + m1.e,
694
+ f: m1.b * m2.e + m1.d * m2.f + m1.f
695
+ };
696
+ }
697
+ /** Materialize into a DOMMatrix for the renderer's transform stack. */
698
+ function toDOMMatrix(m) {
699
+ return new DOMMatrix([
700
+ m.a,
701
+ m.b,
702
+ m.c,
703
+ m.d,
704
+ m.e,
705
+ m.f
706
+ ]);
707
+ }
708
+ /**
709
+ * Layer transform matrix with anchor-aware pivot semantics.
710
+ *
711
+ * The composition node box is drawn at (0, 0, width, height) in local space
712
+ * and positioned at `x`/`y`. `anchorX`/`anchorY` (0–1 fractions of the box)
713
+ * select the pivot point that scale/rotation are applied AROUND:
714
+ *
715
+ * position → pivot → rotate → scale → un-pivot
716
+ *
717
+ * With the default center anchor (0.5, 0.5) a `scale: 2` animation grows the
718
+ * node symmetrically from its middle instead of from its top-left corner.
719
+ * The pivot point itself is invariant under rotation and scale.
720
+ */
721
+ function buildLayerMatrix(params) {
722
+ const ax = params.anchorX ?? .5;
723
+ const ay = params.anchorY ?? .5;
724
+ const px = ax * params.width;
725
+ const py = ay * params.height;
726
+ return multiply(translate(params.x, params.y), multiply(translate(px, py), multiply(rotate(params.rotation), multiply(scale(params.scale), translate(-px, -py)))));
727
+ }
728
+ const Transform3DMath = {
729
+ identity() {
730
+ return [
731
+ 1,
732
+ 0,
733
+ 0,
734
+ 0,
735
+ 0,
736
+ 1,
737
+ 0,
738
+ 0,
739
+ 0,
740
+ 0,
741
+ 1,
742
+ 0,
743
+ 0,
744
+ 0,
745
+ 0,
746
+ 1
747
+ ];
748
+ },
749
+ multiply(a, b) {
750
+ const out = new Array(16);
751
+ for (let row = 0; row < 4; row++) for (let col = 0; col < 4; col++) out[col * 4 + row] = a[0 + row] * b[col * 4 + 0] + a[4 + row] * b[col * 4 + 1] + a[8 + row] * b[col * 4 + 2] + a[12 + row] * b[col * 4 + 3];
752
+ return out;
753
+ },
754
+ translate(tx, ty, tz = 0) {
755
+ return [
756
+ 1,
757
+ 0,
758
+ 0,
759
+ 0,
760
+ 0,
761
+ 1,
762
+ 0,
763
+ 0,
764
+ 0,
765
+ 0,
766
+ 1,
767
+ 0,
768
+ tx,
769
+ ty,
770
+ tz,
771
+ 1
772
+ ];
773
+ },
774
+ scale(sx, sy, sz = 1) {
775
+ return [
776
+ sx,
777
+ 0,
778
+ 0,
779
+ 0,
780
+ 0,
781
+ sy,
782
+ 0,
783
+ 0,
784
+ 0,
785
+ 0,
786
+ sz,
787
+ 0,
788
+ 0,
789
+ 0,
790
+ 0,
791
+ 1
792
+ ];
793
+ },
794
+ rotateX(rad) {
795
+ const c = Math.cos(rad);
796
+ const s = Math.sin(rad);
797
+ return [
798
+ 1,
799
+ 0,
800
+ 0,
801
+ 0,
802
+ 0,
803
+ c,
804
+ s,
805
+ 0,
806
+ 0,
807
+ -s,
808
+ c,
809
+ 0,
810
+ 0,
811
+ 0,
812
+ 0,
813
+ 1
814
+ ];
815
+ },
816
+ rotateY(rad) {
817
+ const c = Math.cos(rad);
818
+ const s = Math.sin(rad);
819
+ return [
820
+ c,
821
+ 0,
822
+ -s,
823
+ 0,
824
+ 0,
825
+ 1,
826
+ 0,
827
+ 0,
828
+ s,
829
+ 0,
830
+ c,
831
+ 0,
832
+ 0,
833
+ 0,
834
+ 0,
835
+ 1
836
+ ];
837
+ },
838
+ rotateZ(rad) {
839
+ const c = Math.cos(rad);
840
+ const s = Math.sin(rad);
841
+ return [
842
+ c,
843
+ s,
844
+ 0,
845
+ 0,
846
+ -s,
847
+ c,
848
+ 0,
849
+ 0,
850
+ 0,
851
+ 0,
852
+ 1,
853
+ 0,
854
+ 0,
855
+ 0,
856
+ 0,
857
+ 1
858
+ ];
859
+ },
860
+ perspective(d) {
861
+ if (d <= 0) return Transform3DMath.identity();
862
+ const m = Transform3DMath.identity();
863
+ m[11] = -1 / d;
864
+ return m;
865
+ },
866
+ buildLayer3DMatrix(config) {
867
+ const { x, y, width, height, rotateXDeg = 0, rotateYDeg = 0, rotateZDeg = 0, scaleX = 1, scaleY = 1, perspectivePx = 0, originXRatio = .5, originYRatio = .5, translateZPx = 0 } = config;
868
+ const pivotX = x + width * originXRatio;
869
+ const pivotY = y + height * originYRatio;
870
+ const rxRad = rotateXDeg * Math.PI / 180;
871
+ const ryRad = rotateYDeg * Math.PI / 180;
872
+ const rzRad = rotateZDeg * Math.PI / 180;
873
+ let m = Transform3DMath.identity();
874
+ m = Transform3DMath.multiply(m, Transform3DMath.translate(pivotX, pivotY, 0));
875
+ if (perspectivePx > 0) m = Transform3DMath.multiply(m, Transform3DMath.perspective(perspectivePx));
876
+ if (translateZPx !== 0) m = Transform3DMath.multiply(m, Transform3DMath.translate(0, 0, translateZPx));
877
+ if (rzRad !== 0) m = Transform3DMath.multiply(m, Transform3DMath.rotateZ(rzRad));
878
+ if (ryRad !== 0) m = Transform3DMath.multiply(m, Transform3DMath.rotateY(ryRad));
879
+ if (rxRad !== 0) m = Transform3DMath.multiply(m, Transform3DMath.rotateX(rxRad));
880
+ m = Transform3DMath.multiply(m, Transform3DMath.translate(-width * originXRatio, -height * originYRatio, 0));
881
+ if (scaleX !== 1 || scaleY !== 1) m = Transform3DMath.multiply(m, Transform3DMath.scale(scaleX, scaleY, 1));
882
+ return m;
883
+ },
884
+ projectPoint(m, p) {
885
+ const x = p.x;
886
+ const y = p.y;
887
+ const z = p.z;
888
+ const X = m[0] * x + m[4] * y + m[8] * z + m[12];
889
+ const Y = m[1] * x + m[5] * y + m[9] * z + m[13];
890
+ const W = m[3] * x + m[7] * y + m[11] * z + m[15];
891
+ const wInv = Math.abs(W) > 1e-6 ? 1 / W : 1;
892
+ return {
893
+ x: X * wInv,
894
+ y: Y * wInv
895
+ };
896
+ },
897
+ projectRectangleCorners(matrix, width, height) {
898
+ return {
899
+ topLeft: Transform3DMath.projectPoint(matrix, {
900
+ x: 0,
901
+ y: 0,
902
+ z: 0
903
+ }),
904
+ topRight: Transform3DMath.projectPoint(matrix, {
905
+ x: width,
906
+ y: 0,
907
+ z: 0
908
+ }),
909
+ bottomLeft: Transform3DMath.projectPoint(matrix, {
910
+ x: 0,
911
+ y: height,
912
+ z: 0
913
+ }),
914
+ bottomRight: Transform3DMath.projectPoint(matrix, {
915
+ x: width,
916
+ y: height,
917
+ z: 0
918
+ })
919
+ };
920
+ },
921
+ computeSignedArea(quad) {
922
+ const { topLeft: p0, topRight: p1, bottomRight: p2, bottomLeft: p3 } = quad;
923
+ return .5 * (p0.x * p1.y - p1.x * p0.y + (p1.x * p2.y - p2.x * p1.y) + (p2.x * p3.y - p3.x * p2.y) + (p3.x * p0.y - p0.x * p3.y));
924
+ }
925
+ };
926
+ /**
927
+ * Computes an 8-parameter 3x3 homography matrix mapping destination coordinates (quad)
928
+ * to normalized source coordinates (unit square [0, 1]^2).
929
+ *
930
+ * The homography H maps destination (x, y) to source (u, v):
931
+ * u = (h00*x + h01*y + h02) / (h20*x + h21*y + h22)
932
+ * v = (h10*x + h11*y + h12) / (h20*x + h21*y + h22)
933
+ *
934
+ * Resulting array: [h00, h01, h02, h10, h11, h12, h20, h21, 1.0]
935
+ */
936
+ function solveHomography(dstPoints, srcPoints = [
937
+ {
938
+ x: 0,
939
+ y: 0
940
+ },
941
+ {
942
+ x: 1,
943
+ y: 0
944
+ },
945
+ {
946
+ x: 0,
947
+ y: 1
948
+ },
949
+ {
950
+ x: 1,
951
+ y: 1
952
+ }
953
+ ]) {
954
+ const A = [];
955
+ const B = [];
956
+ for (let i = 0; i < 4; i++) {
957
+ const xi = dstPoints[i]?.x ?? 0;
958
+ const yi = dstPoints[i]?.y ?? 0;
959
+ const ui = srcPoints[i]?.x ?? 0;
960
+ const vi = srcPoints[i]?.y ?? 0;
961
+ A.push([
962
+ xi,
963
+ yi,
964
+ 1,
965
+ 0,
966
+ 0,
967
+ 0,
968
+ -xi * ui,
969
+ -yi * ui
970
+ ]);
971
+ B.push(ui);
972
+ A.push([
973
+ 0,
974
+ 0,
975
+ 0,
976
+ xi,
977
+ yi,
978
+ 1,
979
+ -xi * vi,
980
+ -yi * vi
981
+ ]);
982
+ B.push(vi);
983
+ }
984
+ const n = 8;
985
+ for (let i = 0; i < n; i++) {
986
+ let maxRow = i;
987
+ let maxVal = Math.abs(A[i][i]);
988
+ for (let k = i + 1; k < n; k++) if (Math.abs(A[k][i]) > maxVal) {
989
+ maxVal = Math.abs(A[k][i]);
990
+ maxRow = k;
991
+ }
992
+ const tempRow = A[i];
993
+ A[i] = A[maxRow];
994
+ A[maxRow] = tempRow;
995
+ const tempB = B[i];
996
+ B[i] = B[maxRow];
997
+ B[maxRow] = tempB;
998
+ const pivot = A[i][i];
999
+ if (Math.abs(pivot) < 1e-12) A[i][i] = pivot < 0 ? -1e-12 : 1e-12;
1000
+ for (let k = i + 1; k < n; k++) {
1001
+ const factor = A[k][i] / A[i][i];
1002
+ for (let j = i; j < n; j++) A[k][j] -= factor * A[i][j];
1003
+ B[k] -= factor * B[i];
1004
+ }
1005
+ }
1006
+ const h = new Array(8).fill(0);
1007
+ for (let i = n - 1; i >= 0; i--) {
1008
+ let sum = B[i];
1009
+ for (let j = i + 1; j < n; j++) sum -= A[i][j] * h[j];
1010
+ h[i] = sum / A[i][i];
1011
+ }
1012
+ return [
1013
+ h[0],
1014
+ h[1],
1015
+ h[2],
1016
+ h[3],
1017
+ h[4],
1018
+ h[5],
1019
+ h[6],
1020
+ h[7],
1021
+ 1
1022
+ ];
1023
+ }
1024
+ /**
1025
+ * Checks whether a layer operation or compiled stub activates the 3D perspective path.
1026
+ */
1027
+ function has3DTransform(target, lop) {
1028
+ const rx = target?.rotateX ?? lop?.rotateX ?? 0;
1029
+ const ry = target?.rotateY ?? lop?.rotateY ?? 0;
1030
+ const rz = target?.rotateZ ?? lop?.rotateZ ?? 0;
1031
+ const tz = target?.translateZ ?? lop?.translateZ ?? 0;
1032
+ const p = target?.perspective ?? lop?.perspective ?? 0;
1033
+ if (rx !== 0 || ry !== 0 || tz !== 0 || p > 0 && (rx !== 0 || ry !== 0 || tz !== 0 || rz !== 0)) return true;
1034
+ if (target?.rotateZ !== void 0 && target.rotateZ !== 0 || lop?.rotateZ !== void 0 && lop.rotateZ !== 0) return true;
1035
+ const tracks = lop?.animation?.tracks;
1036
+ if (tracks && tracks.length > 0) {
1037
+ for (const t of tracks) if (t.prop === "rotateX" || t.prop === "rotateY" || t.prop === "rotateZ" || t.prop === "translateZ" || t.prop === "perspective") return true;
1038
+ }
1039
+ return false;
1040
+ }
1041
+ const LAYOUT_PROPS = [
1042
+ "width",
1043
+ "height",
1044
+ "gap",
1045
+ "padding",
1046
+ "fontSize",
1047
+ "letterSpacing"
1048
+ ];
1049
+ const layoutMemo = /* @__PURE__ */ new WeakMap();
1050
+ function layoutKey(width, height, targetsById, mediaDims) {
1051
+ const parts = [width, height];
1052
+ for (const id in targetsById) {
1053
+ const t = targetsById[id];
1054
+ for (const k of LAYOUT_PROPS) if (t[k] !== void 0) parts.push(id, k, t[k]);
1055
+ }
1056
+ for (const [id, d] of mediaDims) parts.push(id, d.width, d.height);
1057
+ return JSON.stringify(parts);
1058
+ }
1059
+ const compositorHomographyWgsl = `
1060
+ struct HomographyUniforms {
1061
+ matrix_row0 : vec4<f32>,
1062
+ matrix_row1 : vec4<f32>,
1063
+ matrix_row2 : vec4<f32>,
1064
+ params : vec4<f32>, // params.x = opacity
1065
+ };
1066
+
1067
+ @group(0) @binding(0) var<uniform> u : HomographyUniforms;
1068
+ @group(1) @binding(0) var tex : texture_2d<f32>;
1069
+ @group(1) @binding(1) var samp : sampler;
1070
+
1071
+ struct VSOut {
1072
+ @builtin(position) pos : vec4<f32>,
1073
+ @location(0) uv : vec2<f32>,
1074
+ };
1075
+
1076
+ @vertex fn vs(@builtin(vertex_index) vi: u32) -> VSOut {
1077
+ var pos = array<vec2<f32>, 4>(
1078
+ vec2<f32>(-1.0, 1.0),
1079
+ vec2<f32>(1.0, 1.0),
1080
+ vec2<f32>(-1.0, -1.0),
1081
+ vec2<f32>(1.0, -1.0)
1082
+ );
1083
+ var uv = array<vec2<f32>, 4>(
1084
+ vec2<f32>(0.0, 0.0),
1085
+ vec2<f32>(1.0, 0.0),
1086
+ vec2<f32>(0.0, 1.0),
1087
+ vec2<f32>(1.0, 1.0)
1088
+ );
1089
+ return VSOut(vec4<f32>(pos[vi], 0.0, 1.0), uv[vi]);
1090
+ }
1091
+
1092
+ @fragment fn fs(in : VSOut) -> @location(0) vec4<f32> {
1093
+ let x = in.uv.x;
1094
+ let y = in.uv.y;
1095
+
1096
+ let d = u.matrix_row2.x * x + u.matrix_row2.y * y + u.matrix_row2.z;
1097
+ if (d <= 1e-6) {
1098
+ return vec4<f32>(0.0);
1099
+ }
1100
+
1101
+ let src_u = (u.matrix_row0.x * x + u.matrix_row0.y * y + u.matrix_row0.z) / d;
1102
+ let src_v = (u.matrix_row1.x * x + u.matrix_row1.y * y + u.matrix_row1.z) / d;
1103
+
1104
+ if (src_u < 0.0 || src_u > 1.0 || src_v < 0.0 || src_v > 1.0) {
1105
+ return vec4<f32>(0.0);
1106
+ }
1107
+
1108
+ let color = textureSampleLevel(tex, samp, vec2<f32>(src_u, src_v), 0.0);
1109
+ return color * u.params.x;
1110
+ }
1111
+ `;
1112
+ const deviceHomographyCache = /* @__PURE__ */ new WeakMap();
1113
+ function getHomographyResources(device, format) {
1114
+ let res = deviceHomographyCache.get(device);
1115
+ if (!res) {
1116
+ const uniformLayout = device.createBindGroupLayout({ entries: [{
1117
+ binding: 0,
1118
+ visibility: GPUShaderStage.FRAGMENT,
1119
+ buffer: { type: "uniform" }
1120
+ }] });
1121
+ const textureLayout = device.createBindGroupLayout({ entries: [{
1122
+ binding: 0,
1123
+ visibility: GPUShaderStage.FRAGMENT,
1124
+ texture: { sampleType: "float" }
1125
+ }, {
1126
+ binding: 1,
1127
+ visibility: GPUShaderStage.FRAGMENT,
1128
+ sampler: { type: "filtering" }
1129
+ }] });
1130
+ const module = device.createShaderModule({
1131
+ label: "compositor_homography.wgsl",
1132
+ code: compositorHomographyWgsl
1133
+ });
1134
+ res = {
1135
+ pipeline: device.createRenderPipeline({
1136
+ label: "CompositorHomographyPipeline",
1137
+ layout: device.createPipelineLayout({ bindGroupLayouts: [uniformLayout, textureLayout] }),
1138
+ vertex: {
1139
+ module,
1140
+ entryPoint: "vs"
1141
+ },
1142
+ fragment: {
1143
+ module,
1144
+ entryPoint: "fs",
1145
+ targets: [{
1146
+ format,
1147
+ blend: {
1148
+ color: {
1149
+ srcFactor: "one",
1150
+ dstFactor: "one-minus-src-alpha",
1151
+ operation: "add"
1152
+ },
1153
+ alpha: {
1154
+ srcFactor: "one",
1155
+ dstFactor: "one-minus-src-alpha",
1156
+ operation: "add"
1157
+ }
1158
+ }
1159
+ }]
1160
+ },
1161
+ primitive: { topology: "triangle-strip" }
1162
+ }),
1163
+ uniformLayout,
1164
+ textureLayout
1165
+ };
1166
+ deviceHomographyCache.set(device, res);
1167
+ }
1168
+ return res;
1169
+ }
1170
+ const audioTrackLatentCache = /* @__PURE__ */ new Map();
1171
+ const deviceRenderer3DCache = /* @__PURE__ */ new WeakMap();
1172
+ /** One Renderer3D per device, target format and MSAA sample count. */
1173
+ function getRenderer3D(device, format, sampleCount) {
1174
+ let byConfig = deviceRenderer3DCache.get(device);
1175
+ if (!byConfig) {
1176
+ byConfig = /* @__PURE__ */ new Map();
1177
+ deviceRenderer3DCache.set(device, byConfig);
1178
+ }
1179
+ const key = `${format}|${sampleCount}`;
1180
+ let r3d = byConfig.get(key);
1181
+ if (!r3d) {
1182
+ r3d = new Renderer3D(device, format, sampleCount);
1183
+ byConfig.set(key, r3d);
1184
+ }
1185
+ return r3d;
1186
+ }
1187
+ const deviceRelightPipelineCache = /* @__PURE__ */ new WeakMap();
1188
+ function getScreenSpaceRelightPipeline(device, format) {
1189
+ let relight = deviceRelightPipelineCache.get(device);
1190
+ if (!relight || relight.format !== format) {
1191
+ relight = new ScreenSpaceRelightPipeline(device, format);
1192
+ deviceRelightPipelineCache.set(device, relight);
1193
+ }
1194
+ return relight;
1195
+ }
1196
+ const deviceDeflickerPipelineCache = /* @__PURE__ */ new WeakMap();
1197
+ function getTemporalDeflickerPipeline(device, layerKey) {
1198
+ let map = deviceDeflickerPipelineCache.get(device);
1199
+ if (!map) {
1200
+ map = /* @__PURE__ */ new Map();
1201
+ deviceDeflickerPipelineCache.set(device, map);
1202
+ }
1203
+ let pipe = map.get(layerKey);
1204
+ if (!pipe) {
1205
+ pipe = new TemporalDeflickerPipeline(device);
1206
+ map.set(layerKey, pipe);
1207
+ }
1208
+ return pipe;
1209
+ }
1210
+ function resolveVal(val, fallback, frame, fps) {
1211
+ if (val === void 0 || val === null) return fallback;
1212
+ if (typeof val === "number") return Number.isFinite(val) ? val : fallback;
1213
+ if (typeof val === "object" && val !== null) {
1214
+ if ("get" in val && typeof val.get === "function") try {
1215
+ const res = val.get({
1216
+ frame,
1217
+ fps,
1218
+ time: fps > 0 ? frame / fps : 0,
1219
+ duration: 0,
1220
+ durationMs: 0,
1221
+ progress: 0,
1222
+ deltaTime: fps > 0 ? 1 / fps : 0
1223
+ });
1224
+ const n$1 = Number(res);
1225
+ if (Number.isFinite(n$1)) return n$1;
1226
+ } catch {}
1227
+ if ("value" in val) {
1228
+ const n$1 = Number(val.value);
1229
+ if (Number.isFinite(n$1)) return n$1;
1230
+ }
1231
+ }
1232
+ if (typeof val === "function") try {
1233
+ const n$1 = Number(val({
1234
+ frame,
1235
+ fps,
1236
+ time: fps > 0 ? frame / fps : 0
1237
+ }));
1238
+ if (Number.isFinite(n$1)) return n$1;
1239
+ } catch {}
1240
+ const n = Number(val);
1241
+ return Number.isFinite(n) ? n : fallback;
1242
+ }
1243
+ function synthesizeRelightLights(relightOpts, sceneLights, bounds, shiftedFrame, fps) {
1244
+ if (sceneLights.length > 0 || relightOpts.lightType === void 0 && relightOpts.intensity === void 0 && relightOpts.lightPosX === void 0) return sceneLights;
1245
+ const lightTypeStr = String(relightOpts.lightType ?? "point").toLowerCase();
1246
+ const lightKind = lightTypeStr === "directional" ? "directional" : lightTypeStr === "spot" ? "spot" : "point";
1247
+ const intensity = resolveVal(relightOpts.intensity ?? 1, 1, shiftedFrame, fps);
1248
+ const normX = resolveVal(relightOpts.lightPosX, .5, shiftedFrame, fps);
1249
+ const normY = resolveVal(relightOpts.lightPosY, .5, shiftedFrame, fps);
1250
+ const normZ = resolveVal(relightOpts.lightPosZ, .25, shiftedFrame, fps);
1251
+ const normRadius = resolveVal(relightOpts.lightRadius, .75, shiftedFrame, fps);
1252
+ const lightX = bounds.x + normX * bounds.width;
1253
+ const lightY = bounds.y + normY * bounds.height;
1254
+ const lightZ = normZ * Math.max(bounds.width, bounds.height);
1255
+ const lightRadius = normRadius * Math.max(bounds.width, bounds.height);
1256
+ const synthLight = {
1257
+ lightType: lightKind,
1258
+ color: relightOpts.lightColor ?? "#ffffff",
1259
+ intensity,
1260
+ x: lightX,
1261
+ y: lightY,
1262
+ z: lightZ,
1263
+ radius: lightRadius,
1264
+ decay: 1
1265
+ };
1266
+ const ambientInt = resolveVal(relightOpts.ambientIntensity, .15, shiftedFrame, fps);
1267
+ return [{
1268
+ lightType: "ambient",
1269
+ color: relightOpts.ambientColor ?? "#ffffff",
1270
+ intensity: ambientInt
1271
+ }, synthLight];
1272
+ }
1273
+ function drawProjectedQuad(ctx, encoder, destView, sourceTex, quad, destWidth, destHeight, opacity) {
1274
+ if (Math.abs(Transform3DMath.computeSignedArea(quad)) < 1e-4) return;
1275
+ const minX = Math.max(0, Math.min(destWidth, Math.floor(Math.min(quad.topLeft.x, quad.topRight.x, quad.bottomLeft.x, quad.bottomRight.x))));
1276
+ const minY = Math.max(0, Math.min(destHeight, Math.floor(Math.min(quad.topLeft.y, quad.topRight.y, quad.bottomLeft.y, quad.bottomRight.y))));
1277
+ const maxX = Math.max(0, Math.min(destWidth, Math.ceil(Math.max(quad.topLeft.x, quad.topRight.x, quad.bottomLeft.x, quad.bottomRight.x))));
1278
+ const maxY = Math.max(0, Math.min(destHeight, Math.ceil(Math.max(quad.topLeft.y, quad.topRight.y, quad.bottomLeft.y, quad.bottomRight.y))));
1279
+ const scissorW = maxX - minX;
1280
+ const scissorH = maxY - minY;
1281
+ if (scissorW <= 0 || scissorH <= 0) return;
1282
+ const h = solveHomography([
1283
+ {
1284
+ x: quad.topLeft.x / destWidth,
1285
+ y: quad.topLeft.y / destHeight
1286
+ },
1287
+ {
1288
+ x: quad.topRight.x / destWidth,
1289
+ y: quad.topRight.y / destHeight
1290
+ },
1291
+ {
1292
+ x: quad.bottomLeft.x / destWidth,
1293
+ y: quad.bottomLeft.y / destHeight
1294
+ },
1295
+ {
1296
+ x: quad.bottomRight.x / destWidth,
1297
+ y: quad.bottomRight.y / destHeight
1298
+ }
1299
+ ]);
1300
+ for (const val of h) if (!Number.isFinite(val)) return;
1301
+ const uniformData = new Float32Array(16);
1302
+ uniformData[0] = h[0];
1303
+ uniformData[1] = h[1];
1304
+ uniformData[2] = h[2];
1305
+ uniformData[3] = 0;
1306
+ uniformData[4] = h[3];
1307
+ uniformData[5] = h[4];
1308
+ uniformData[6] = h[5];
1309
+ uniformData[7] = 0;
1310
+ uniformData[8] = h[6];
1311
+ uniformData[9] = h[7];
1312
+ uniformData[10] = h[8];
1313
+ uniformData[11] = 0;
1314
+ uniformData[12] = opacity;
1315
+ uniformData[13] = 0;
1316
+ uniformData[14] = 0;
1317
+ uniformData[15] = 0;
1318
+ const { pipeline, uniformLayout, textureLayout } = getHomographyResources(ctx.device, ctx.renderer.format);
1319
+ const sampler = ctx.renderer.samplerCache.getSampler(ctx.device);
1320
+ const uniformBuffer = ctx.renderer.getTemporaryBuffer(uniformData);
1321
+ const uniformBindGroup = ctx.device.createBindGroup({
1322
+ layout: uniformLayout,
1323
+ entries: [{
1324
+ binding: 0,
1325
+ resource: { buffer: uniformBuffer }
1326
+ }]
1327
+ });
1328
+ const textureBindGroup = ctx.renderer.bindGroupCache.getBindGroup(ctx.device, textureLayout, sourceTex, sampler);
1329
+ const renderPass = encoder.beginRenderPass({ colorAttachments: [{
1330
+ view: destView,
1331
+ loadOp: "load",
1332
+ storeOp: "store"
1333
+ }] });
1334
+ renderPass.setPipeline(pipeline);
1335
+ renderPass.setScissorRect(minX, minY, scissorW, scissorH);
1336
+ renderPass.setBindGroup(0, uniformBindGroup);
1337
+ renderPass.setBindGroup(1, textureBindGroup);
1338
+ renderPass.draw(4);
1339
+ renderPass.end();
1340
+ }
1341
+ function computeContainerScissor(matrix, width, height) {
1342
+ const corners = [
1343
+ matrix.transformPoint(new DOMPoint(0, 0)),
1344
+ matrix.transformPoint(new DOMPoint(width, 0)),
1345
+ matrix.transformPoint(new DOMPoint(0, height)),
1346
+ matrix.transformPoint(new DOMPoint(width, height))
1347
+ ];
1348
+ const xs = corners.map((p) => p.x);
1349
+ const ys = corners.map((p) => p.y);
1350
+ const minX = Math.min(...xs);
1351
+ const minY = Math.min(...ys);
1352
+ const maxX = Math.max(...xs);
1353
+ const maxY = Math.max(...ys);
1354
+ return {
1355
+ x: Math.round(minX),
1356
+ y: Math.round(minY),
1357
+ width: Math.max(0, Math.round(maxX - minX)),
1358
+ height: Math.max(0, Math.round(maxY - minY))
1359
+ };
1360
+ }
1361
+ const CompositorWebGPURenderer = async (args) => {
1362
+ const { ctx, pass, targetView, targetTexture, targetWidth, targetHeight, encoder, props, drawChild } = args;
1363
+ const { virtualMedia, fps, frame } = props;
1364
+ const op = virtualMedia.operation;
1365
+ if (!op) return;
1366
+ pass.end();
1367
+ if (op.op === "CompositorLayer") {
1368
+ console.warn("CompositorWebGPURenderer called directly with legacy CompositorLayer operation. This is a bug.");
1369
+ args.pass = ctx.renderer.beginFrame(encoder, targetView, {
1370
+ r: 0,
1371
+ g: 0,
1372
+ b: 0,
1373
+ a: 0
1374
+ }, targetWidth, targetHeight, "load");
1375
+ return;
1376
+ }
1377
+ if (op.op === "Compositor") {
1378
+ const vop = op;
1379
+ const sampleCount3d = vop.antialias3d === false ? 1 : 4;
1380
+ const containerWidth = props.containerWidth ?? ctx.surface.width;
1381
+ const containerHeight = props.containerHeight ?? ctx.surface.height;
1382
+ const nativeWidth = vop.width ?? containerWidth;
1383
+ const nativeHeight = vop.height ?? containerHeight;
1384
+ const opacity = typeof vop.opacity === "number" ? vop.opacity : 1;
1385
+ const isVideoMode = props.isVideoMode ?? (vop.mode === "Video" || vop.dataType === "Video" || virtualMedia?.metadata?.durationMs != null);
1386
+ const inheritedSeekOffset = props.inheritedSeekOffset ?? 0;
1387
+ const shiftedFrame = Math.max(0, frame != null && fps != null ? frame + Math.round(inheritedSeekOffset * fps) : frame ?? 0);
1388
+ const compTex = ctx.renderer.getTemporaryTexture(nativeWidth, nativeHeight, [...props.excludeTextures || [], targetTexture]);
1389
+ const compView = compTex.createView();
1390
+ const composeDuration = virtualMedia?.metadata?.durationMs ?? DEFAULT_DURATION_MS;
1391
+ const durationSec = composeDuration / 1e3;
1392
+ const { tl, targetsById } = compileTimeline(props.renderId, virtualMedia, {
1393
+ fps: fps ?? 24,
1394
+ durationSec
1395
+ });
1396
+ tl.seek(shiftedFrame / (fps ?? 24));
1397
+ getRenderer3D(ctx.device, ctx.renderer.format ?? "rgba8unorm", sampleCount3d).resetPools();
1398
+ getScreenSpaceRelightPipeline(ctx.device, ctx.renderer.format ?? "rgba8unorm").resetPools();
1399
+ const clearColor = parseColor(vop.backgroundColor);
1400
+ ctx.renderer.beginFrame(encoder, compView, clearColor, nativeWidth, nativeHeight, "clear").end();
1401
+ let currentCompTex = compTex;
1402
+ ctx.renderer.pushScissor({
1403
+ x: 0,
1404
+ y: 0,
1405
+ width: nativeWidth,
1406
+ height: nativeHeight
1407
+ });
1408
+ ctx.renderer.pushIdentity();
1409
+ await initLayout();
1410
+ const mediaDims = /* @__PURE__ */ new Map();
1411
+ for (const vm of collectNodeOps(virtualMedia.children)) {
1412
+ const lop = vm.operation;
1413
+ if (lop.kind === "media") {
1414
+ const meta = getActiveMediaMetadata(vm.children?.[0]);
1415
+ if (meta?.width && meta?.height) mediaDims.set(lop.id, {
1416
+ width: meta.width,
1417
+ height: meta.height
1418
+ });
1419
+ else if (lop.dataType === "Caption" || (vm.children?.[0]?.operation)?.dataType === "Caption" || (vm.children?.[0]?.operation)?.srtText !== void 0) {
1420
+ const lopWidth = targetsById[lop.id]?.width ?? lop.width;
1421
+ const autoWidth = typeof lopWidth === "number" ? lopWidth : Math.round(nativeWidth * .8);
1422
+ const lopHeight = targetsById[lop.id]?.height ?? lop.height;
1423
+ let autoHeight = typeof lopHeight === "number" ? lopHeight : 160;
1424
+ const contentVM = vm.children?.[0];
1425
+ const src = resolveMediaSourceUrl(contentVM) ?? (contentVM?.operation)?.url ?? (contentVM?.operation)?.src ?? (contentVM?.operation)?.srtText ?? lop.src ?? lop.url;
1426
+ if (typeof lopHeight !== "number" && src) try {
1427
+ const captions = await srtLoader.load(src);
1428
+ if (captions && captions.length > 0) autoHeight = measureMaxCaptionHeight(captions, lop, autoWidth);
1429
+ } catch {}
1430
+ mediaDims.set(lop.id, {
1431
+ width: autoWidth,
1432
+ height: autoHeight
1433
+ });
1434
+ }
1435
+ }
1436
+ }
1437
+ const frameResolveNode = (vm) => {
1438
+ const lop = vm?.operation ?? {};
1439
+ const target = targetsById[lop.id];
1440
+ const pick = (k) => target && target[k] !== void 0 ? target[k] : lop[k];
1441
+ const node = {
1442
+ ...lop,
1443
+ width: pick("width"),
1444
+ height: pick("height"),
1445
+ gap: pick("gap"),
1446
+ padding: pick("padding"),
1447
+ fontSize: pick("fontSize"),
1448
+ letterSpacing: pick("letterSpacing")
1449
+ };
1450
+ node.children = (vm?.children ?? []).map(frameResolveNode);
1451
+ if (!node.children.length) node.children = void 0;
1452
+ return node;
1453
+ };
1454
+ const layoutRoots = () => (virtualMedia.children ?? []).map(frameResolveNode).filter((node) => node?.kind !== "camera" && node?.kind !== "light");
1455
+ const memoTree = virtualMedia.children;
1456
+ const memoKey = layoutKey(nativeWidth, nativeHeight, targetsById, mediaDims);
1457
+ const memo = memoTree ? layoutMemo.get(memoTree) : void 0;
1458
+ const { rects } = memo?.key === memoKey ? memo : await computeLayout({
1459
+ layout: layoutRoots(),
1460
+ viewport: {
1461
+ width: nativeWidth,
1462
+ height: nativeHeight
1463
+ },
1464
+ measure: (node, constraintWidth) => {
1465
+ if (node.kind === "text") {
1466
+ const textStyle = {
1467
+ fontSize: node.fontSize ?? 48,
1468
+ fontWeight: node.fontWeight,
1469
+ fontFamily: node.fontFamily,
1470
+ letterSpacing: node.letterSpacing,
1471
+ lineHeight: node.lineHeight,
1472
+ padding: node.padding
1473
+ };
1474
+ if (constraintWidth !== void 0) {
1475
+ const isAuto = typeof node.width !== "number";
1476
+ const wrapped$1 = measureText(node.text ?? "", {
1477
+ ...textStyle,
1478
+ width: isAuto ? void 0 : constraintWidth,
1479
+ keepNaturalWidth: true
1480
+ });
1481
+ return {
1482
+ width: isAuto ? Math.ceil(wrapped$1.width) : Math.min(constraintWidth, Math.ceil(wrapped$1.width)),
1483
+ height: Math.ceil(wrapped$1.height)
1484
+ };
1485
+ }
1486
+ const natural = measureText(node.text ?? "", textStyle);
1487
+ if (typeof node.width !== "number") return {
1488
+ width: Math.ceil(natural.width),
1489
+ height: Math.ceil(natural.height)
1490
+ };
1491
+ const wrapped = measureText(node.text ?? "", {
1492
+ ...textStyle,
1493
+ width: node.width
1494
+ });
1495
+ return {
1496
+ width: Math.ceil(wrapped.width),
1497
+ height: Math.ceil(wrapped.height)
1498
+ };
1499
+ }
1500
+ if (node.kind === "media") return mediaDims.get(node.id) ?? null;
1501
+ return null;
1502
+ }
1503
+ });
1504
+ if (memoTree && memo?.key !== memoKey) layoutMemo.set(memoTree, {
1505
+ key: memoKey,
1506
+ rects
1507
+ });
1508
+ const allNodeOps = collectNodeOps(virtualMedia.children ?? []);
1509
+ const cameraVMs = allNodeOps.filter((vm) => vm.operation?.kind === "camera");
1510
+ const cameraVM = isVideoMode ? cameraVMs.filter((vm) => {
1511
+ const op$1 = vm.operation;
1512
+ const start = op$1.startFrame ?? 0;
1513
+ const dur = op$1.durationFrames;
1514
+ return shiftedFrame >= start && (dur === void 0 || shiftedFrame < start + dur);
1515
+ }).sort((a, b) => (b.operation.startFrame ?? 0) - (a.operation.startFrame ?? 0))[0] : cameraVMs[0];
1516
+ const lightVMs = allNodeOps.filter((vm) => vm.operation?.kind === "light");
1517
+ const has3DLayer = allNodeOps.some((vm) => {
1518
+ const lop = vm.operation;
1519
+ const target = lop.id ? targetsById[lop.id] : void 0;
1520
+ return lop.kind !== "camera" && lop.kind !== "light" && (Boolean(target?.is3D ?? lop.is3D) || (target?.z ?? lop.z ?? 0) !== 0);
1521
+ });
1522
+ const is3DScene = Boolean(cameraVM || has3DLayer || lightVMs.length > 0);
1523
+ let camera = null;
1524
+ let dofEnabled = false;
1525
+ const sceneLights = [];
1526
+ if (is3DScene) {
1527
+ const camOp = cameraVM?.operation;
1528
+ const camStub = camOp?.id ? targetsById[camOp.id] : void 0;
1529
+ const fov = camStub?.cameraFov ?? camOp?.lens?.fov ?? 50;
1530
+ camera = Camera3D.createDefaultCamera(nativeWidth, nativeHeight, fov);
1531
+ camera.near = camOp?.lens?.near ?? 1;
1532
+ camera.far = camOp?.lens?.far ?? 5e4;
1533
+ camera.zoom = camStub?.cameraZoom ?? camOp?.lens?.zoom ?? 1;
1534
+ const defaultEye = camera.eye;
1535
+ const defaultTarget = camera.target;
1536
+ const eyeX = camStub?.cameraX ?? camStub?.x ?? camOp?.x ?? defaultEye[0];
1537
+ const eyeY = camStub?.cameraY ?? camStub?.y ?? camOp?.y ?? defaultEye[1];
1538
+ const eyeZ = camStub?.cameraZ ?? camStub?.z ?? camOp?.z ?? defaultEye[2];
1539
+ camera.eye = [
1540
+ eyeX,
1541
+ eyeY,
1542
+ eyeZ
1543
+ ];
1544
+ if (camStub?.targetX !== void 0 || camStub?.targetY !== void 0 || camStub?.targetZ !== void 0 || camOp?.targetX !== void 0 || camOp?.targetY !== void 0 || camOp?.targetZ !== void 0) camera.target = [
1545
+ camStub?.targetX ?? camOp?.targetX ?? defaultTarget[0],
1546
+ camStub?.targetY ?? camOp?.targetY ?? defaultTarget[1],
1547
+ camStub?.targetZ ?? camOp?.targetZ ?? defaultTarget[2]
1548
+ ];
1549
+ else camera.target = [
1550
+ eyeX,
1551
+ eyeY,
1552
+ 0
1553
+ ];
1554
+ const pitch = camStub?.cameraPitch ?? camOp?.pitch ?? 0;
1555
+ const yaw = camStub?.cameraYaw ?? camOp?.yaw ?? 0;
1556
+ const roll = camStub?.cameraRoll ?? camOp?.roll ?? 0;
1557
+ if (pitch !== 0 || yaw !== 0 || roll !== 0) camera = Camera3D.applyOrientation(camera, pitch, yaw, roll);
1558
+ const orbitAzimuth = camStub?.orbitAzimuth;
1559
+ const orbitElevation = camStub?.orbitElevation;
1560
+ const orbitRadius = camStub?.orbitRadius;
1561
+ if (orbitAzimuth !== void 0 || orbitElevation !== void 0 || orbitRadius !== void 0) {
1562
+ const radius = orbitRadius ?? Vector3Math.distance(camera.eye, camera.target);
1563
+ camera.eye = Camera3D.orbit(camera.target, radius, orbitAzimuth ?? 0, orbitElevation ?? 0);
1564
+ }
1565
+ const shakeTrans = camStub?.shakeTranslation ?? (camOp?.shake?.enabled ? camOp?.shake?.translationAmplitude : 0) ?? 0;
1566
+ const shakeRot = camStub?.shakeRotation ?? (camOp?.shake?.enabled ? camOp?.shake?.rotationAmplitude : 0) ?? 0;
1567
+ if (shakeTrans > 0 || shakeRot > 0) {
1568
+ const t = shiftedFrame / (fps ?? 24);
1569
+ camera = Camera3D.applyCameraShake(camera, t, {
1570
+ translationAmplitude: shakeTrans,
1571
+ rotationAmplitude: shakeRot,
1572
+ frequency: camOp?.shake?.frequency ?? 1.5,
1573
+ octaves: camOp?.shake?.octaves ?? 3,
1574
+ seed: camOp?.shake?.seed ?? 42
1575
+ });
1576
+ }
1577
+ dofEnabled = Boolean(camOp?.dof?.enabled || camStub?.focusDistance !== void 0);
1578
+ if (dofEnabled) {
1579
+ camera.focusDistance = camStub?.focusDistance ?? camOp?.dof?.focusDistance ?? Vector3Math.distance(camera.eye, camera.target);
1580
+ camera.fStop = camStub?.fStop ?? camOp?.dof?.fStop ?? 2.8;
1581
+ camera.maxBlurRadius = camStub?.maxBlurRadius ?? camOp?.dof?.maxBlurRadius ?? 24;
1582
+ }
1583
+ for (const lvm of lightVMs) {
1584
+ const lop = lvm.operation;
1585
+ const targetId = lop.id || lop.inputHandleId;
1586
+ const target = targetId ? targetsById[targetId] : void 0;
1587
+ if (target?.hidden || lop.hidden) continue;
1588
+ if (isVideoMode) {
1589
+ const startFrame = lop.startFrame ?? 0;
1590
+ const durationFrames = lop.durationFrames;
1591
+ if (shiftedFrame < startFrame) continue;
1592
+ if (durationFrames !== void 0 && shiftedFrame >= startFrame + durationFrames) continue;
1593
+ }
1594
+ const lightType = target?.lightType ?? lop.lightType ?? "point";
1595
+ const color = parseColor(target?.color ?? lop.color ?? "#ffffff");
1596
+ const intensity = target?.intensity ?? lop.intensity ?? 1;
1597
+ const x = target?.x ?? lop.x ?? 0;
1598
+ const y = target?.y ?? lop.y ?? 0;
1599
+ const z = target?.z ?? lop.z ?? 0;
1600
+ const targetX = target?.targetX ?? lop.targetX ?? 0;
1601
+ const targetY = target?.targetY ?? lop.targetY ?? 0;
1602
+ const targetZ = target?.targetZ ?? lop.targetZ ?? 0;
1603
+ const radius = target?.radius ?? lop.radius ?? 1e3;
1604
+ const angle = target?.angle ?? lop.angle ?? 45;
1605
+ const penumbra = target?.penumbra ?? lop.penumbra ?? .2;
1606
+ const decay = target?.decay ?? lop.decay ?? 1;
1607
+ sceneLights.push({
1608
+ type: lightType,
1609
+ color,
1610
+ intensity,
1611
+ position: [
1612
+ x,
1613
+ y,
1614
+ z
1615
+ ],
1616
+ target: [
1617
+ targetX,
1618
+ targetY,
1619
+ targetZ
1620
+ ],
1621
+ radius,
1622
+ angle,
1623
+ penumbra,
1624
+ decay
1625
+ });
1626
+ }
1627
+ }
1628
+ const pending3DItems = [];
1629
+ const flush3DPass = (curTex, curView, curExcludes) => {
1630
+ if (pending3DItems.length === 0 || !camera) return {
1631
+ finalTex: curTex,
1632
+ finalView: curView
1633
+ };
1634
+ const r3d = getRenderer3D(ctx.device, ctx.renderer.format ?? "rgba8unorm", sampleCount3d);
1635
+ for (const item of pending3DItems) if (item.kind === "mesh" && item.opts.audioDeform) item.meshBuffers = r3d.deformMesh(encoder, item.mesh, item.opts.audioDeform);
1636
+ const itemTextures = pending3DItems.map((q) => q.kind === "quad" ? q.texture : q.texture).filter((t) => Boolean(t));
1637
+ const scene3dTex = ctx.renderer.getTemporaryTexture(nativeWidth, nativeHeight, [
1638
+ curTex,
1639
+ targetTexture,
1640
+ ...curExcludes,
1641
+ ...itemTextures
1642
+ ]);
1643
+ const scene3dView = scene3dTex.createView();
1644
+ let linearDepthTex;
1645
+ let linearDepthView;
1646
+ if (dofEnabled) {
1647
+ linearDepthTex = r3d.getOrCreateLinearDepthTexture(nativeWidth, nativeHeight);
1648
+ linearDepthView = linearDepthTex.createView();
1649
+ }
1650
+ const { pass: pass3d, cameraBindGroup, cameraBuffer, lightsBindGroup } = r3d.beginPass(encoder, scene3dView, nativeWidth, nativeHeight, camera, "clear", {
1651
+ r: 0,
1652
+ g: 0,
1653
+ b: 0,
1654
+ a: 0
1655
+ }, linearDepthView, sceneLights);
1656
+ for (const item of pending3DItems) if (item.kind === "quad") r3d.drawTextureQuad(pass3d, cameraBindGroup, lightsBindGroup, item.texture, item.opts, dofEnabled);
1657
+ else if (item.kind === "slug") r3d.drawSlugText(pass3d, cameraBindGroup, lightsBindGroup, item.batches, item.opts, item.stackBase, dofEnabled);
1658
+ else if (item.kind === "mesh") r3d.drawMesh3D(pass3d, cameraBindGroup, lightsBindGroup, item.meshBuffers ?? item.mesh, item.texture, item.opts, dofEnabled);
1659
+ pass3d.end();
1660
+ let final3dTex = scene3dTex;
1661
+ if (dofEnabled && linearDepthTex) {
1662
+ const dofResultTex = ctx.renderer.getTemporaryTexture(nativeWidth, nativeHeight, [
1663
+ curTex,
1664
+ targetTexture,
1665
+ scene3dTex,
1666
+ ...curExcludes
1667
+ ]);
1668
+ r3d.applyDepthOfField(encoder, scene3dTex, linearDepthTex, dofResultTex.createView(), cameraBuffer);
1669
+ final3dTex = dofResultTex;
1670
+ }
1671
+ const nextTex = ctx.renderer.composite(encoder, curTex, final3dTex, "normal", [targetTexture, ...curExcludes]);
1672
+ pending3DItems.length = 0;
1673
+ return {
1674
+ finalTex: nextTex,
1675
+ finalView: nextTex.createView()
1676
+ };
1677
+ };
1678
+ let nodeIndex = 0;
1679
+ const renderNodeTree = async (vms, initialTex, initialView, excludes, accumulatedOpacity = 1, parentMatrix = new DOMMatrix(), parentRect = null, targetW = nativeWidth, targetH = nativeHeight, parent3DMatrix = null, isRootScene = false) => {
1680
+ const sorted = [...vms].sort((a, b) => {
1681
+ return (a.operation?.zIndex ?? 0) - (b.operation?.zIndex ?? 0);
1682
+ });
1683
+ let activeTex = initialTex;
1684
+ let activeView = initialView;
1685
+ let activeExcludes = excludes;
1686
+ for (const child of sorted) {
1687
+ const lop = child.operation;
1688
+ if (lop.kind === "camera" || lop.kind === "light") continue;
1689
+ const targetId = lop.id || lop.inputHandleId;
1690
+ const target = targetId ? targetsById[targetId] : void 0;
1691
+ const isChild3D = Boolean(target?.is3D ?? lop.is3D) || Boolean(camera && ((target?.z ?? lop.z ?? 0) !== 0 || lop.is3D)) || Boolean(parent3DMatrix);
1692
+ if (isRootScene && !isChild3D && pending3DItems.length > 0) {
1693
+ const flushed = flush3DPass(activeTex, activeView, activeExcludes);
1694
+ if (flushed.finalTex !== activeTex) activeExcludes = [...activeExcludes, flushed.finalTex];
1695
+ activeTex = flushed.finalTex;
1696
+ activeView = flushed.finalView;
1697
+ }
1698
+ if (lop.op !== "CompositorLayer") {
1699
+ await drawChild(child, {
1700
+ containerWidth: targetW,
1701
+ containerHeight: targetH,
1702
+ renderId: `${props.renderId}-c${nodeIndex}-${lop.op}`,
1703
+ fps,
1704
+ isVideoMode,
1705
+ frame: shiftedFrame,
1706
+ excludeTextures: [targetTexture, ...activeExcludes]
1707
+ }, activeView, activeTex, targetW, targetH);
1708
+ continue;
1709
+ }
1710
+ nodeIndex += 1;
1711
+ const res = await renderLayerVM(child, nodeIndex, activeTex, activeView, activeExcludes, accumulatedOpacity, parentMatrix, parentRect, targetW, targetH, parent3DMatrix, isRootScene);
1712
+ if (res) {
1713
+ if (res.finalTex !== activeTex) activeExcludes = [...activeExcludes, res.finalTex];
1714
+ activeTex = res.finalTex;
1715
+ activeView = res.finalView;
1716
+ }
1717
+ }
1718
+ if (isRootScene && pending3DItems.length > 0) {
1719
+ const flushed = flush3DPass(activeTex, activeView, activeExcludes);
1720
+ if (flushed.finalTex !== activeTex) activeExcludes = [...activeExcludes, flushed.finalTex];
1721
+ activeTex = flushed.finalTex;
1722
+ activeView = flushed.finalView;
1723
+ }
1724
+ return {
1725
+ finalTex: activeTex,
1726
+ finalView: activeView
1727
+ };
1728
+ };
1729
+ const renderLayerVM = async (nodeVM, i, destTex, destView, baseExcludes, accumulatedOpacity, parentMatrix, parentRect, targetW = nativeWidth, targetH = nativeHeight, parent3DMatrix = null, isRootScene = false) => {
1730
+ const excludes = [...baseExcludes, ...pending3DItems.map((q) => q.texture).filter((t) => Boolean(t))];
1731
+ const lop = nodeVM.operation;
1732
+ if (lop.kind === "camera" || lop.kind === "light") return;
1733
+ const targetId = lop.id || lop.inputHandleId;
1734
+ const target = targetId ? targetsById[targetId] : void 0;
1735
+ if (target?.hidden || lop.hidden) return;
1736
+ const kind = lop.kind;
1737
+ const isContainer = kind === "flex" || kind === "block" || kind === "box";
1738
+ if (isVideoMode) {
1739
+ const startFrame = lop.startFrame ?? 0;
1740
+ const durationFrames = lop.durationFrames;
1741
+ if (shiftedFrame < startFrame) return;
1742
+ if (durationFrames !== void 0 && shiftedFrame >= startFrame + durationFrames) return;
1743
+ }
1744
+ if (kind === "model3d") {
1745
+ const r3d = getRenderer3D(ctx.device, ctx.renderer.format ?? "rgba8unorm", sampleCount3d);
1746
+ let modelSrc = lop.modelData ?? lop.src;
1747
+ if (!modelSrc && lop.text3dOptions) {
1748
+ const tOpts = lop.text3dOptions;
1749
+ const font = (tOpts.fontFamily ? SlugFontCache.getParsed(tOpts.fontFamily) : null) ?? SlugFontCache.getParsed("Inter") ?? SlugFontCache.getParsed("Unbounded") ?? SlugFontCache.getFirstParsed();
1750
+ if (font) {
1751
+ modelSrc = generateExtrudedTextGeometry({
1752
+ ...tOpts,
1753
+ font
1754
+ }).modelData;
1755
+ lop.modelData = modelSrc;
1756
+ }
1757
+ }
1758
+ if (!modelSrc) return;
1759
+ let model;
1760
+ try {
1761
+ model = typeof modelSrc === "object" && modelSrc !== null && "meshes" in modelSrc ? modelSrc : r3d.loadModel(modelSrc, lop.modelFormat ?? "auto", {
1762
+ center: lop.center,
1763
+ normalizeSize: lop.normalizeSize
1764
+ });
1765
+ } catch (err) {
1766
+ console.error("Failed to load 3D model:", err);
1767
+ return;
1768
+ }
1769
+ if (!model || model.meshes.length === 0) return;
1770
+ const posX = target?.x ?? lop.x ?? 0;
1771
+ const posY = target?.y ?? lop.y ?? 0;
1772
+ const posZ = target?.z ?? lop.z ?? 0;
1773
+ const rotX = target?.rotateX ?? lop.rotateX ?? 0;
1774
+ const rotY = target?.rotateY ?? lop.rotateY ?? 0;
1775
+ const rotZ = (target?.rotateZ ?? lop.rotateZ ?? 0) !== 0 ? target?.rotateZ ?? lop.rotateZ ?? 0 : target?.rotation ?? lop.rotation ?? 0;
1776
+ const sc = target?.scale ?? lop.scale ?? 1;
1777
+ const scX = (target?.scaleX ?? lop.scaleX ?? 1) * sc;
1778
+ const scY = (target?.scaleY ?? lop.scaleY ?? 1) * sc;
1779
+ const scZ = (target?.scaleZ ?? lop.scaleZ ?? 1) * sc;
1780
+ let localM = Matrix4Math.identity();
1781
+ localM = Matrix4Math.multiply(localM, Matrix4Math.translate(posX, posY, posZ));
1782
+ const rxRad = rotX * Math.PI / 180;
1783
+ const ryRad = rotY * Math.PI / 180;
1784
+ const rzRad = rotZ * Math.PI / 180;
1785
+ if (rzRad !== 0) localM = Matrix4Math.multiply(localM, Matrix4Math.rotateZ(rzRad));
1786
+ if (ryRad !== 0) localM = Matrix4Math.multiply(localM, Matrix4Math.rotateY(ryRad));
1787
+ if (rxRad !== 0) localM = Matrix4Math.multiply(localM, Matrix4Math.rotateX(rxRad));
1788
+ localM = Matrix4Math.multiply(localM, Matrix4Math.scale(scX, scY, scZ));
1789
+ const finalModelMatrix = parent3DMatrix ? Matrix4Math.multiply(parent3DMatrix, localM) : localM;
1790
+ const colorParsed = target?.colorTint || target?.color || lop.colorTint || lop.color ? parseColor(target?.colorTint ?? target?.color ?? lop.colorTint ?? lop.color) : void 0;
1791
+ const colorTint = colorParsed ? [
1792
+ colorParsed.r,
1793
+ colorParsed.g,
1794
+ colorParsed.b,
1795
+ colorParsed.a
1796
+ ] : [
1797
+ 1,
1798
+ 1,
1799
+ 1,
1800
+ 1
1801
+ ];
1802
+ const modelOpacity = (target?.opacity ?? lop.opacity ?? 1) * accumulatedOpacity;
1803
+ let skinningMatrices;
1804
+ const animProgress = target?.animationProgress ?? lop.animationProgress ?? 0;
1805
+ const animTime = target?.animationTime ?? lop.animationTime ?? 0;
1806
+ const animSpeed = target?.animationSpeed ?? lop.animationSpeed ?? 1;
1807
+ const clip = (lop.animationName ? model.animations.find((a) => a.name === lop.animationName) : void 0) ?? model.animations[0];
1808
+ let clipSec = 0;
1809
+ if (clip && clip.duration > 0) {
1810
+ clipSec = animProgress > 0 ? animProgress * clip.duration : animTime + (shiftedFrame ?? 0) / (fps || 30) * animSpeed;
1811
+ if (lop.loop ?? true) clipSec %= clip.duration;
1812
+ }
1813
+ const sceneRoot = Matrix4Math.multiply(finalModelMatrix, model.rootTransform ?? Matrix4Math.identity());
1814
+ const posed = model.nodes ? poseNodes(model, clip, clipSec) : void 0;
1815
+ const skinCache = /* @__PURE__ */ new Map();
1816
+ const placeMesh = (mesh) => {
1817
+ if (!posed) return { matrix: sceneRoot };
1818
+ if (mesh.skin !== void 0) {
1819
+ let joints = skinCache.get(mesh.skin);
1820
+ if (!joints) {
1821
+ joints = jointMatrices(model, mesh.skin, posed);
1822
+ skinCache.set(mesh.skin, joints);
1823
+ }
1824
+ return {
1825
+ matrix: sceneRoot,
1826
+ joints
1827
+ };
1828
+ }
1829
+ if (mesh.node !== void 0) return { matrix: Matrix4Math.multiply(sceneRoot, posed[mesh.node]) };
1830
+ return { matrix: sceneRoot };
1831
+ };
1832
+ if (!posed && clip && clip.duration > 0) {
1833
+ const currentSec = clipSec;
1834
+ if (model.skeleton && model.skeleton.bones.length > 0) {
1835
+ const numBones = Math.min(128, model.skeleton.bones.length);
1836
+ skinningMatrices = new Float32Array(2048);
1837
+ for (let b = 0; b < 128; b++) {
1838
+ skinningMatrices[b * 16] = 1;
1839
+ skinningMatrices[b * 16 + 5] = 1;
1840
+ skinningMatrices[b * 16 + 10] = 1;
1841
+ skinningMatrices[b * 16 + 15] = 1;
1842
+ }
1843
+ for (const track of clip.tracks) {
1844
+ const boneIdx = model.skeleton.boneIndicesByName[track.nodeName];
1845
+ if (boneIdx !== void 0 && boneIdx < numBones) {
1846
+ const times = track.times;
1847
+ let sampleIdx = 0;
1848
+ for (let k = 0; k < times.length - 1; k++) if (currentSec >= times[k] && currentSec <= times[k + 1]) {
1849
+ sampleIdx = k;
1850
+ break;
1851
+ }
1852
+ const t0 = times[sampleIdx] ?? 0;
1853
+ const t1 = times[sampleIdx + 1] ?? t0;
1854
+ const alpha = t1 > t0 ? (currentSec - t0) / (t1 - t0) : 0;
1855
+ if (track.translations) {
1856
+ const x0 = track.translations[sampleIdx * 3] ?? 0;
1857
+ const y0 = track.translations[sampleIdx * 3 + 1] ?? 0;
1858
+ const z0 = track.translations[sampleIdx * 3 + 2] ?? 0;
1859
+ const x1 = track.translations[(sampleIdx + 1) * 3] ?? x0;
1860
+ const y1 = track.translations[(sampleIdx + 1) * 3 + 1] ?? y0;
1861
+ const z1 = track.translations[(sampleIdx + 1) * 3 + 2] ?? z0;
1862
+ const curX = x0 + (x1 - x0) * alpha;
1863
+ const curY = y0 + (y1 - y0) * alpha;
1864
+ const curZ = z0 + (z1 - z0) * alpha;
1865
+ const boneMat = Matrix4Math.translate(curX, curY, curZ);
1866
+ const bone = model.skeleton.bones[boneIdx];
1867
+ const skinMat = bone ? Matrix4Math.multiply(boneMat, bone.inverseBindMatrix) : boneMat;
1868
+ skinningMatrices.set(skinMat, boneIdx * 16);
1869
+ }
1870
+ }
1871
+ }
1872
+ }
1873
+ }
1874
+ const isBlend = (m) => m.materialName ? model.materials[m.materialName]?.alphaMode === "blend" : false;
1875
+ const drawOrder = [...model.meshes].sort((a, b) => Number(isBlend(a)) - Number(isBlend(b)));
1876
+ for (const mesh of drawOrder) {
1877
+ const mat = mesh.materialName ? model.materials[mesh.materialName] : void 0;
1878
+ const placed = placeMesh(mesh);
1879
+ const meshSkin = placed.joints ?? skinningMatrices;
1880
+ let meshColorTint;
1881
+ if (colorParsed) if (mat?.diffuseColor) meshColorTint = [
1882
+ mat.diffuseColor[0] * colorTint[0],
1883
+ mat.diffuseColor[1] * colorTint[1],
1884
+ mat.diffuseColor[2] * colorTint[2],
1885
+ (mat.diffuseColor[3] ?? 1) * colorTint[3]
1886
+ ];
1887
+ else meshColorTint = colorTint;
1888
+ else if (mat?.diffuseColor) meshColorTint = mat.diffuseColor;
1889
+ else meshColorTint = [
1890
+ .8,
1891
+ .8,
1892
+ .85,
1893
+ 1
1894
+ ];
1895
+ const audioDeformConfig = target?.audioDeform ?? lop.audioDeform;
1896
+ let meshAudioDeform;
1897
+ if (audioDeformConfig) {
1898
+ const currentSec = (shiftedFrame ?? 0) / (fps || 30);
1899
+ const timeMs = currentSec * 1e3;
1900
+ let latentBuffer = audioDeformConfig.latentBuffer;
1901
+ if (!latentBuffer && audioDeformConfig.audioBuffer) latentBuffer = audioDeformConfig.audioBuffer;
1902
+ if (!latentBuffer) {
1903
+ const directAudio = audioDeformConfig.audioData;
1904
+ if (directAudio) {
1905
+ const cacheKey = (lop.id ?? "audio-mesh") + "-direct-audio";
1906
+ let trackCache = audioTrackLatentCache.get(cacheKey);
1907
+ if (!trackCache) {
1908
+ const chs = Array.isArray(directAudio) ? directAudio : directAudio.channels;
1909
+ const sRate = Array.isArray(directAudio) ? 48e3 : directAudio.sampleRate;
1910
+ const totalF = Math.max(10, Math.ceil((chs[0]?.length ?? 0) / sRate * (fps || 30)) + 10);
1911
+ trackCache = new AudioLatentTrackCache(chs, sRate, fps || 30, totalF);
1912
+ audioTrackLatentCache.set(cacheKey, trackCache);
1913
+ }
1914
+ latentBuffer = trackCache.getGpuBuffer(ctx.device, shiftedFrame ?? 0);
1915
+ }
1916
+ }
1917
+ if (!latentBuffer && audioDeformConfig.audioTrackId) {
1918
+ const trackId = audioDeformConfig.audioTrackId;
1919
+ let foundAudioUrl;
1920
+ const searchVms = (list) => {
1921
+ for (const v of list) {
1922
+ const op$1 = v.operation;
1923
+ if (op$1) {
1924
+ if (op$1.id === trackId || op$1.inputHandleId === trackId) {
1925
+ foundAudioUrl = op$1.inputHandleId || op$1.src || op$1.url;
1926
+ return;
1927
+ }
1928
+ if (v.children) searchVms(v.children);
1929
+ }
1930
+ }
1931
+ };
1932
+ if (virtualMedia.children) searchVms(virtualMedia.children);
1933
+ if (!foundAudioUrl && (trackId.endsWith(".mp3") || trackId.endsWith(".wav") || trackId.endsWith(".ogg"))) foundAudioUrl = trackId;
1934
+ if (foundAudioUrl) try {
1935
+ let trackCache = audioTrackLatentCache.get(foundAudioUrl);
1936
+ if (!trackCache) {
1937
+ const decoded = await decodeAudioSource(foundAudioUrl);
1938
+ if (decoded && decoded.channels.length > 0) {
1939
+ const sRate = decoded.sampleRate || 48e3;
1940
+ const ch0Len = decoded.channels[0]?.length ?? 0;
1941
+ const durationSec$1 = decoded.durationSec ?? ch0Len / sRate;
1942
+ const totalF = Math.max(10, Math.ceil(durationSec$1 * (fps || 30)) + 10);
1943
+ trackCache = new AudioLatentTrackCache(decoded.channels, sRate, fps || 30, totalF);
1944
+ audioTrackLatentCache.set(foundAudioUrl, trackCache);
1945
+ }
1946
+ }
1947
+ if (trackCache) latentBuffer = trackCache.getGpuBuffer(ctx.device, shiftedFrame ?? 0);
1948
+ } catch (err) {
1949
+ console.warn("[webgpu-renderer] Failed to decode audio for deformWithAudio:", err);
1950
+ }
1951
+ }
1952
+ if (latentBuffer) {
1953
+ let amplitudeMultiplier = audioDeformConfig.amplitudeMultiplier ?? 1;
1954
+ if (typeof amplitudeMultiplier !== "number" && typeof amplitudeMultiplier?.get === "function") {
1955
+ const frameCtx = {
1956
+ frame: shiftedFrame ?? 0,
1957
+ fps: fps || 30,
1958
+ time: currentSec,
1959
+ duration: 0,
1960
+ durationMs: 0,
1961
+ progress: 0,
1962
+ deltaTime: 1 / (fps || 30)
1963
+ };
1964
+ amplitudeMultiplier = Number(amplitudeMultiplier.get(frameCtx));
1965
+ } else if (typeof amplitudeMultiplier !== "number" && typeof amplitudeMultiplier?.value === "number") amplitudeMultiplier = amplitudeMultiplier.value;
1966
+ meshAudioDeform = {
1967
+ config: {
1968
+ ...audioDeformConfig,
1969
+ amplitudeMultiplier: Number.isFinite(amplitudeMultiplier) ? amplitudeMultiplier : 1
1970
+ },
1971
+ latentBuffer,
1972
+ timeMs,
1973
+ sampleRate: 48e3
1974
+ };
1975
+ }
1976
+ }
1977
+ const meshOpts = {
1978
+ modelMatrix: placed.matrix,
1979
+ opacity: modelOpacity * (mat?.opacity ?? 1),
1980
+ colorTint: meshColorTint,
1981
+ twoSided: target?.twoSided ?? lop.twoSided ?? mat?.twoSided ?? true,
1982
+ wireframe: Boolean(target?.wireframe ?? lop.wireframe),
1983
+ isSkinned: Boolean(meshSkin || mesh.jointIndices && mesh.jointWeights),
1984
+ skinningMatrices: meshSkin,
1985
+ material: target?.material ?? lop.material ?? mat?.shading ?? "lit",
1986
+ shadeColor: mat?.shadeColor,
1987
+ alphaCutoff: mat?.alphaCutoff,
1988
+ textureWrap: mat?.textureWrap,
1989
+ shininess: target?.shininess ?? lop.shininess ?? mat?.shininess ?? 32,
1990
+ roughness: target?.roughness ?? lop.roughness ?? mat?.roughness,
1991
+ specularIntensity: target?.specularIntensity ?? lop.specularIntensity ?? .5,
1992
+ ambientIntensity: target?.ambientIntensity ?? lop.ambientIntensity ?? 1,
1993
+ metallic: target?.metallic ?? lop.metallic ?? mat?.metallic,
1994
+ audioDeform: meshAudioDeform
1995
+ };
1996
+ pending3DItems.push({
1997
+ kind: "mesh",
1998
+ mesh,
1999
+ texture: mat ? await r3d.materialTexture(mat) : void 0,
2000
+ opts: meshOpts
2001
+ });
2002
+ }
2003
+ return {
2004
+ finalTex: destTex,
2005
+ finalView: destView
2006
+ };
2007
+ }
2008
+ const rect = rects[lop.id];
2009
+ if (!rect) {
2010
+ if (isContainer) return await renderNodeTree(nodeVM.children ?? [], destTex, destView, excludes, accumulatedOpacity, parentMatrix, parentRect, targetW, targetH, parent3DMatrix, isRootScene);
2011
+ return;
2012
+ }
2013
+ const baseX = lop.x ?? 0;
2014
+ const baseY = lop.y ?? 0;
2015
+ const sampledX = target?.x ?? baseX;
2016
+ const sampledY = target?.y ?? baseY;
2017
+ let localX = 0;
2018
+ let localY = 0;
2019
+ if (parentRect) {
2020
+ const localLayoutX = rect.x - parentRect.x;
2021
+ const localLayoutY = rect.y - parentRect.y;
2022
+ localX = localLayoutX + (sampledX - baseX);
2023
+ localY = localLayoutY + (sampledY - baseY);
2024
+ } else {
2025
+ localX = rect.x + (sampledX - baseX);
2026
+ localY = rect.y + (sampledY - baseY);
2027
+ }
2028
+ const scale$1 = target?.scale ?? lop.scale ?? 1;
2029
+ const rotation = target?.rotation ?? lop.rotation ?? 0;
2030
+ const layerOpacity = (target?.opacity ?? lop.opacity ?? 1) * accumulatedOpacity;
2031
+ const rawAnimators = target?.animators ?? lop.animators;
2032
+ const isPathText = kind === "text" && Boolean(lop.pathOptions || target?.pathOptions);
2033
+ const hasKineticAnimators = kind === "text" && Array.isArray(rawAnimators) && rawAnimators.length > 0;
2034
+ const hasFormation = kind === "text" && Array.isArray(rawAnimators) && rawAnimators.some((a) => {
2035
+ const anim = a;
2036
+ return anim?.props?.formation !== void 0 || anim?.formation !== void 0;
2037
+ });
2038
+ let padX = 0;
2039
+ let padY = 0;
2040
+ if (hasFormation) {
2041
+ let formationRadius = 0;
2042
+ let formationPitch = 0;
2043
+ for (const a of rawAnimators) {
2044
+ const anim = a;
2045
+ const f = anim?.props?.formation ?? anim?.formation;
2046
+ if (f) {
2047
+ if (typeof f.radius === "number") formationRadius = Math.max(formationRadius, f.radius);
2048
+ if (typeof f.pitch === "number") formationPitch = Math.max(formationPitch, f.pitch);
2049
+ }
2050
+ }
2051
+ padX = Math.max(160, Math.ceil(formationRadius + 100));
2052
+ padY = Math.max(100, Math.ceil(formationRadius + formationPitch * 15 + 100));
2053
+ } else if (!isPathText && hasKineticAnimators) {
2054
+ padX = Math.max(80, Math.ceil(rect.width * .2));
2055
+ padY = Math.max(50, Math.ceil(rect.height * .5));
2056
+ }
2057
+ const layerW = isPathText ? targetW : rect.width + padX * 2;
2058
+ const layerH = isPathText ? targetH : rect.height + padY * 2;
2059
+ if (!isPathText && hasKineticAnimators) {
2060
+ localX -= padX;
2061
+ localY -= padY;
2062
+ }
2063
+ const anchorX = lop.anchorX ?? .5;
2064
+ const anchorY = lop.anchorY ?? .5;
2065
+ const localMatrix = toDOMMatrix(buildLayerMatrix({
2066
+ x: localX,
2067
+ y: localY,
2068
+ width: layerW,
2069
+ height: layerH,
2070
+ rotation,
2071
+ scale: scale$1,
2072
+ anchorX: isPathText ? anchorX * rect.width / layerW : anchorX,
2073
+ anchorY: isPathText ? anchorY * rect.height / layerH : anchorY
2074
+ }));
2075
+ const layerMatrix = parentMatrix.multiply(localMatrix);
2076
+ const blendMode = lop.blendMode || "normal";
2077
+ let activeTex = destTex;
2078
+ let activeView = destView;
2079
+ const is3D = has3DTransform(target, lop);
2080
+ const rotateX = target?.rotateX ?? lop.rotateX ?? 0;
2081
+ const rotateY = target?.rotateY ?? lop.rotateY ?? 0;
2082
+ const rotateZ = target?.rotateZ ?? lop.rotateZ ?? 0;
2083
+ const translateZ = target?.translateZ ?? lop.translateZ ?? 0;
2084
+ const perspective = target?.perspective ?? lop.perspective ?? 0;
2085
+ const perspectiveOriginX = target?.perspectiveOriginX ?? lop.perspectiveOriginX ?? lop.anchorX ?? .5;
2086
+ const perspectiveOriginY = target?.perspectiveOriginY ?? lop.perspectiveOriginY ?? lop.anchorY ?? .5;
2087
+ const backfaceVisibility = target?.backfaceVisibility ?? lop.backfaceVisibility ?? "visible";
2088
+ let quad3D = null;
2089
+ if (is3D) {
2090
+ const m3d = Transform3DMath.buildLayer3DMatrix({
2091
+ x: localX,
2092
+ y: localY,
2093
+ width: layerW,
2094
+ height: layerH,
2095
+ rotateXDeg: rotateX,
2096
+ rotateYDeg: rotateY,
2097
+ rotateZDeg: rotateZ !== 0 ? rotateZ : rotation,
2098
+ scaleX: scale$1,
2099
+ scaleY: scale$1,
2100
+ perspectivePx: perspective,
2101
+ originXRatio: perspectiveOriginX,
2102
+ originYRatio: perspectiveOriginY,
2103
+ translateZPx: translateZ
2104
+ });
2105
+ let q = Transform3DMath.projectRectangleCorners(m3d, layerW, layerH);
2106
+ if (!parentMatrix.isIdentity) q = {
2107
+ topLeft: parentMatrix.transformPoint(new DOMPoint(q.topLeft.x, q.topLeft.y)),
2108
+ topRight: parentMatrix.transformPoint(new DOMPoint(q.topRight.x, q.topRight.y)),
2109
+ bottomLeft: parentMatrix.transformPoint(new DOMPoint(q.bottomLeft.x, q.bottomLeft.y)),
2110
+ bottomRight: parentMatrix.transformPoint(new DOMPoint(q.bottomRight.x, q.bottomRight.y))
2111
+ };
2112
+ if (backfaceVisibility === "hidden" && Transform3DMath.computeSignedArea(q) < 0) return;
2113
+ quad3D = q;
2114
+ }
2115
+ const isTrue3D = Boolean(target?.is3D ?? lop.is3D) || Boolean(camera && ((target?.z ?? lop.z ?? 0) !== 0 || lop.is3D));
2116
+ if (isContainer) {
2117
+ if (lop.transformStyle === "preserve-3d" && isTrue3D) {
2118
+ let current3DMatrix = Matrix4Math.identity();
2119
+ const containerX = parent3DMatrix !== null ? target?.x ?? lop.x ?? 0 : target?.x ?? lop.x ?? localX + layerW * .5;
2120
+ const containerY = parent3DMatrix !== null ? target?.y ?? lop.y ?? 0 : target?.y ?? lop.y ?? localY + layerH * .5;
2121
+ const containerZ = target?.z ?? lop.z ?? 0;
2122
+ current3DMatrix = Matrix4Math.multiply(current3DMatrix, Matrix4Math.translate(containerX, containerY, containerZ));
2123
+ const rxRad = (target?.rotateX ?? lop.rotateX ?? 0) * Math.PI / 180;
2124
+ const ryRad = (target?.rotateY ?? lop.rotateY ?? 0) * Math.PI / 180;
2125
+ const rzRad = ((target?.rotateZ ?? lop.rotateZ ?? 0) !== 0 ? target?.rotateZ ?? lop.rotateZ ?? 0 : rotation) * (Math.PI / 180);
2126
+ if (rzRad !== 0) current3DMatrix = Matrix4Math.multiply(current3DMatrix, Matrix4Math.rotateZ(rzRad));
2127
+ if (ryRad !== 0) current3DMatrix = Matrix4Math.multiply(current3DMatrix, Matrix4Math.rotateY(ryRad));
2128
+ if (rxRad !== 0) current3DMatrix = Matrix4Math.multiply(current3DMatrix, Matrix4Math.rotateX(rxRad));
2129
+ const csX = (target?.scaleX ?? lop.scaleX ?? 1) * scale$1;
2130
+ const csY = (target?.scaleY ?? lop.scaleY ?? 1) * scale$1;
2131
+ const csZ = (target?.scaleZ ?? lop.scaleZ ?? 1) * scale$1;
2132
+ if (csX !== 1 || csY !== 1 || csZ !== 1) current3DMatrix = Matrix4Math.multiply(current3DMatrix, Matrix4Math.scale(csX, csY, csZ));
2133
+ if (parent3DMatrix) current3DMatrix = Matrix4Math.multiply(parent3DMatrix, current3DMatrix);
2134
+ if (nodeVM.children && nodeVM.children.length > 0) {
2135
+ const res = await renderNodeTree(nodeVM.children, activeTex, activeView, excludes, layerOpacity, new DOMMatrix(), null, layerW, layerH, current3DMatrix, false);
2136
+ activeTex = res.finalTex;
2137
+ activeView = res.finalView;
2138
+ }
2139
+ return {
2140
+ finalTex: activeTex,
2141
+ finalView: activeView
2142
+ };
2143
+ }
2144
+ if (isTrue3D) {
2145
+ const texW$1 = Math.max(1, Math.ceil(layerW));
2146
+ const texH$1 = Math.max(1, Math.ceil(layerH));
2147
+ const groupExcludes$1 = [
2148
+ activeTex,
2149
+ targetTexture,
2150
+ ...excludes,
2151
+ ...pending3DItems.map((q) => q.texture).filter((t) => Boolean(t))
2152
+ ];
2153
+ const groupTex$1 = ctx.renderer.getTemporaryTexture(texW$1, texH$1, groupExcludes$1);
2154
+ const groupView$1 = groupTex$1.createView();
2155
+ ctx.renderer.beginFrame(encoder, groupView$1, {
2156
+ r: 0,
2157
+ g: 0,
2158
+ b: 0,
2159
+ a: 0
2160
+ }, texW$1, texH$1, "clear").end();
2161
+ const br$2 = Math.min(lop.borderRadius ?? lop.strokeRadius ?? 0, layerW / 2, layerH / 2);
2162
+ if (shouldPaintContainerBackground(kind, lop.background)) {
2163
+ const bgPass = ctx.renderer.beginFrame(encoder, groupView$1, {
2164
+ r: 0,
2165
+ g: 0,
2166
+ b: 0,
2167
+ a: 0
2168
+ }, texW$1, texH$1, "load");
2169
+ ctx.renderer.drawRect(bgPass, {
2170
+ x: 0,
2171
+ y: 0,
2172
+ width: layerW,
2173
+ height: layerH
2174
+ }, lop.background, 0, { opacity: 1 });
2175
+ bgPass.end();
2176
+ }
2177
+ let activeGroupTex$1 = groupTex$1;
2178
+ let activeGroupView$1 = groupView$1;
2179
+ if (nodeVM.children && nodeVM.children.length > 0) {
2180
+ const res = await renderNodeTree(nodeVM.children, groupTex$1, groupView$1, [groupTex$1, ...groupExcludes$1], 1, new DOMMatrix(), rect, texW$1, texH$1, null, false);
2181
+ activeGroupTex$1 = res.finalTex;
2182
+ activeGroupView$1 = res.finalView;
2183
+ }
2184
+ const borderResult$2 = !isTrue3D && lop.borderWidth !== void 0 && lop.borderColor ? createBorderTexture(ctx, encoder, layerW, layerH, br$2, lop.borderWidth, lop.borderColor, lop.strokeAlign ?? "inside", [activeGroupTex$1, ...groupExcludes$1]) : null;
2185
+ if (borderResult$2) {
2186
+ const borderPass = ctx.renderer.beginFrame(encoder, activeGroupView$1, {
2187
+ r: 0,
2188
+ g: 0,
2189
+ b: 0,
2190
+ a: 0
2191
+ }, texW$1, texH$1, "load");
2192
+ ctx.renderer.drawTexture(borderPass, borderResult$2.borderTex, {
2193
+ x: borderResult$2.ox,
2194
+ y: borderResult$2.oy,
2195
+ width: borderResult$2.ow,
2196
+ height: borderResult$2.oh
2197
+ }, { opacity: 1 });
2198
+ borderPass.end();
2199
+ }
2200
+ let modelMatrix;
2201
+ if (parent3DMatrix) {
2202
+ let localM = Matrix4Math.identity();
2203
+ const childX = target?.x ?? lop.x ?? 0;
2204
+ const childY = target?.y ?? lop.y ?? 0;
2205
+ const childZ = target?.z ?? lop.z ?? 0;
2206
+ localM = Matrix4Math.multiply(localM, Matrix4Math.translate(childX, childY, childZ));
2207
+ const rxRad = (target?.rotateX ?? lop.rotateX ?? 0) * Math.PI / 180;
2208
+ const ryRad = (target?.rotateY ?? lop.rotateY ?? 0) * Math.PI / 180;
2209
+ const rzRad = ((target?.rotateZ ?? lop.rotateZ ?? 0) !== 0 ? target?.rotateZ ?? lop.rotateZ ?? 0 : rotation) * (Math.PI / 180);
2210
+ if (rzRad !== 0) localM = Matrix4Math.multiply(localM, Matrix4Math.rotateZ(rzRad));
2211
+ if (ryRad !== 0) localM = Matrix4Math.multiply(localM, Matrix4Math.rotateY(ryRad));
2212
+ if (rxRad !== 0) localM = Matrix4Math.multiply(localM, Matrix4Math.rotateX(rxRad));
2213
+ const sx = layerW * scale$1;
2214
+ const sy = layerH * scale$1;
2215
+ const sz = target?.scaleZ ?? lop.scaleZ ?? 1;
2216
+ localM = Matrix4Math.multiply(localM, Matrix4Math.scale(sx, sy, sz));
2217
+ const ax = lop.anchorX ?? .5;
2218
+ const ay = lop.anchorY ?? .5;
2219
+ const pivotX = .5 - ax;
2220
+ const pivotY = .5 - ay;
2221
+ if (pivotX !== 0 || pivotY !== 0) localM = Matrix4Math.multiply(localM, Matrix4Math.translate(pivotX, pivotY, 0));
2222
+ modelMatrix = Matrix4Math.multiply(parent3DMatrix, localM);
2223
+ }
2224
+ const quadOpts = {
2225
+ position: [
2226
+ localX + layerW * .5,
2227
+ localY + layerH * .5,
2228
+ target?.z ?? lop.z ?? 0
2229
+ ],
2230
+ width: layerW,
2231
+ height: layerH,
2232
+ textureExtent: [layerW / activeGroupTex$1.width, layerH / activeGroupTex$1.height],
2233
+ rotation: [
2234
+ target?.rotateX ?? lop.rotateX ?? 0,
2235
+ target?.rotateY ?? lop.rotateY ?? 0,
2236
+ (target?.rotateZ ?? lop.rotateZ ?? 0) !== 0 ? target?.rotateZ ?? lop.rotateZ ?? 0 : rotation
2237
+ ],
2238
+ scale: [
2239
+ scale$1,
2240
+ scale$1,
2241
+ target?.scaleZ ?? lop.scaleZ ?? 1
2242
+ ],
2243
+ anchor: [lop.anchorX ?? .5, lop.anchorY ?? .5],
2244
+ borderRadius: br$2,
2245
+ borderWidth: lop.borderWidth,
2246
+ borderColor: lop.borderColor,
2247
+ opacity: layerOpacity,
2248
+ twoSided: target?.twoSided ?? lop.twoSided ?? true,
2249
+ material: target?.material ?? lop.material,
2250
+ shininess: target?.shininess ?? lop.shininess,
2251
+ roughness: target?.roughness ?? lop.roughness,
2252
+ specularIntensity: target?.specularIntensity ?? lop.specularIntensity,
2253
+ ambientIntensity: target?.ambientIntensity ?? lop.ambientIntensity,
2254
+ metallic: target?.metallic ?? lop.metallic,
2255
+ ...modelMatrix && { modelMatrix }
2256
+ };
2257
+ pending3DItems.push({
2258
+ kind: "quad",
2259
+ texture: activeGroupTex$1,
2260
+ opts: quadOpts
2261
+ });
2262
+ return {
2263
+ finalTex: activeTex,
2264
+ finalView: activeView
2265
+ };
2266
+ }
2267
+ if (is3D && quad3D) {
2268
+ const texW$1 = Math.max(1, Math.ceil(layerW));
2269
+ const texH$1 = Math.max(1, Math.ceil(layerH));
2270
+ const groupExcludes$1 = [
2271
+ activeTex,
2272
+ targetTexture,
2273
+ ...excludes
2274
+ ];
2275
+ const groupTex$1 = ctx.renderer.getTemporaryTexture(texW$1, texH$1, groupExcludes$1);
2276
+ const groupView$1 = groupTex$1.createView();
2277
+ ctx.renderer.beginFrame(encoder, groupView$1, {
2278
+ r: 0,
2279
+ g: 0,
2280
+ b: 0,
2281
+ a: 0
2282
+ }, texW$1, texH$1, "clear").end();
2283
+ const br$2 = Math.min(lop.borderRadius ?? lop.strokeRadius ?? 0, layerW / 2, layerH / 2);
2284
+ if (shouldPaintContainerBackground(kind, lop.background)) {
2285
+ const bgPass = ctx.renderer.beginFrame(encoder, groupView$1, {
2286
+ r: 0,
2287
+ g: 0,
2288
+ b: 0,
2289
+ a: 0
2290
+ }, texW$1, texH$1, "load");
2291
+ ctx.renderer.drawRect(bgPass, {
2292
+ x: 0,
2293
+ y: 0,
2294
+ width: layerW,
2295
+ height: layerH
2296
+ }, lop.background, br$2, { opacity: 1 });
2297
+ bgPass.end();
2298
+ }
2299
+ let activeGroupTex$1 = groupTex$1;
2300
+ let activeGroupView$1 = groupView$1;
2301
+ if (nodeVM.children && nodeVM.children.length > 0) {
2302
+ const res = await renderNodeTree(nodeVM.children, groupTex$1, groupView$1, [groupTex$1, ...groupExcludes$1], 1, new DOMMatrix(), rect, texW$1, texH$1, null, false);
2303
+ activeGroupTex$1 = res.finalTex;
2304
+ activeGroupView$1 = res.finalView;
2305
+ }
2306
+ const borderResult$2 = lop.borderWidth !== void 0 && lop.borderColor ? createBorderTexture(ctx, encoder, layerW, layerH, br$2, lop.borderWidth, lop.borderColor, lop.strokeAlign ?? "inside", [activeGroupTex$1, ...groupExcludes$1]) : null;
2307
+ if (borderResult$2) {
2308
+ const borderPass = ctx.renderer.beginFrame(encoder, activeGroupView$1, {
2309
+ r: 0,
2310
+ g: 0,
2311
+ b: 0,
2312
+ a: 0
2313
+ }, texW$1, texH$1, "load");
2314
+ ctx.renderer.drawTexture(borderPass, borderResult$2.borderTex, {
2315
+ x: borderResult$2.ox,
2316
+ y: borderResult$2.oy,
2317
+ width: borderResult$2.ow,
2318
+ height: borderResult$2.oh
2319
+ }, { opacity: 1 });
2320
+ borderPass.end();
2321
+ }
2322
+ const container3DShutter = target?.motionBlurShutter ?? lop.motionBlurShutter ?? 0;
2323
+ if (container3DShutter > 0 && fps && shiftedFrame !== void 0) {
2324
+ const currentT = shiftedFrame / fps;
2325
+ const prevT = (shiftedFrame - 1) / fps;
2326
+ tl.seek(prevT);
2327
+ const prevTarget = targetId ? targetsById[targetId] : void 0;
2328
+ const prevX = prevTarget?.x ?? baseX;
2329
+ const prevY = prevTarget?.y ?? baseY;
2330
+ tl.seek(currentT);
2331
+ const vx = sampledX - prevX;
2332
+ const vy = sampledY - prevY;
2333
+ if (Math.hypot(vx, vy) > .5) {
2334
+ activeGroupTex$1 = ctx.renderer.applyMotionBlur(encoder, activeGroupTex$1, vx, vy, container3DShutter, 16, [
2335
+ activeTex,
2336
+ targetTexture,
2337
+ ...excludes
2338
+ ]);
2339
+ activeGroupView$1 = activeGroupTex$1.createView();
2340
+ }
2341
+ }
2342
+ if (blendMode === "normal" || blendMode === "source-over") drawProjectedQuad(ctx, encoder, activeView, activeGroupTex$1, quad3D, targetW, targetH, layerOpacity);
2343
+ else {
2344
+ const compositeExcludes$1 = [
2345
+ activeTex,
2346
+ targetTexture,
2347
+ activeGroupTex$1,
2348
+ ...excludes
2349
+ ];
2350
+ if (borderResult$2) compositeExcludes$1.push(borderResult$2.borderTex);
2351
+ const layerTex = ctx.renderer.getTemporaryTexture(targetW, targetH, compositeExcludes$1);
2352
+ const layerView = layerTex.createView();
2353
+ ctx.renderer.beginFrame(encoder, layerView, {
2354
+ r: 0,
2355
+ g: 0,
2356
+ b: 0,
2357
+ a: 0
2358
+ }, targetW, targetH, "clear").end();
2359
+ drawProjectedQuad(ctx, encoder, layerView, activeGroupTex$1, quad3D, targetW, targetH, layerOpacity);
2360
+ activeTex = ctx.renderer.composite(encoder, activeTex, layerTex, blendMode, [targetTexture, ...excludes]);
2361
+ activeView = activeTex.createView();
2362
+ }
2363
+ return {
2364
+ finalTex: activeTex,
2365
+ finalView: activeView
2366
+ };
2367
+ }
2368
+ const shouldClip = lop.overflow !== "visible";
2369
+ const scissorRect = shouldClip ? computeContainerScissor(layerMatrix, layerW, layerH) : null;
2370
+ const clipRadius = shouldClip ? Math.min(target?.borderRadius ?? lop.borderRadius ?? 0, layerW / 2, layerH / 2) : 0;
2371
+ if ((kind === "flex" || kind === "block") && clipRadius <= 0 && !shouldPaintContainerBackground(kind, lop.background) && layerOpacity === 1 && blendMode === "normal" && !lop.borderWidth && !lop.borderColor && (typeof lop.relighting !== "object" || !lop.relighting) && (typeof lop.relight !== "object" || !lop.relight) && (typeof target?.relighting !== "object" || !target?.relighting) && (typeof target?.relight !== "object" || !target?.relight) && (typeof lop.deflicker !== "object" || !lop.deflicker) && (typeof target?.deflicker !== "object" || !target?.deflicker)) {
2372
+ if (scissorRect) ctx.renderer.pushScissor(scissorRect);
2373
+ const res = await renderNodeTree(nodeVM.children ?? [], activeTex, activeView, excludes, accumulatedOpacity, layerMatrix, rect, targetW, targetH, null, isRootScene);
2374
+ if (scissorRect) ctx.renderer.popScissor();
2375
+ return res;
2376
+ }
2377
+ const groupExcludes = [
2378
+ activeTex,
2379
+ targetTexture,
2380
+ ...excludes
2381
+ ];
2382
+ const groupTex = ctx.renderer.getTemporaryTexture(targetW, targetH, groupExcludes);
2383
+ const groupView = groupTex.createView();
2384
+ ctx.renderer.beginFrame(encoder, groupView, {
2385
+ r: 0,
2386
+ g: 0,
2387
+ b: 0,
2388
+ a: 0
2389
+ }, targetW, targetH, "clear").end();
2390
+ const br$1 = Math.min(target?.borderRadius ?? lop.borderRadius ?? lop.strokeRadius ?? 0, layerW / 2, layerH / 2);
2391
+ if (shouldPaintContainerBackground(kind, lop.background)) {
2392
+ const bgPass = ctx.renderer.beginFrame(encoder, groupView, {
2393
+ r: 0,
2394
+ g: 0,
2395
+ b: 0,
2396
+ a: 0
2397
+ }, targetW, targetH, "load");
2398
+ ctx.renderer.pushTransform(layerMatrix);
2399
+ ctx.renderer.drawRect(bgPass, {
2400
+ x: 0,
2401
+ y: 0,
2402
+ width: layerW,
2403
+ height: layerH
2404
+ }, lop.background, br$1, { opacity: layerOpacity });
2405
+ ctx.renderer.popTransform();
2406
+ bgPass.end();
2407
+ }
2408
+ let activeGroupTex = groupTex;
2409
+ let activeGroupView = groupView;
2410
+ if (nodeVM.children && nodeVM.children.length > 0) {
2411
+ if (scissorRect) ctx.renderer.pushScissor(scissorRect);
2412
+ const res = await renderNodeTree(nodeVM.children, groupTex, groupView, [groupTex, ...groupExcludes], layerOpacity, layerMatrix, rect, targetW, targetH, null, false);
2413
+ if (scissorRect) ctx.renderer.popScissor();
2414
+ activeGroupTex = res.finalTex;
2415
+ activeGroupView = res.finalView;
2416
+ }
2417
+ if (clipRadius > 0) {
2418
+ const maskTex = ctx.renderer.getTemporaryTexture(targetW, targetH, [activeGroupTex, ...groupExcludes]);
2419
+ const maskPass = ctx.renderer.beginFrame(encoder, maskTex.createView(), {
2420
+ r: 0,
2421
+ g: 0,
2422
+ b: 0,
2423
+ a: 0
2424
+ }, targetW, targetH, "clear");
2425
+ ctx.renderer.pushTransform(layerMatrix);
2426
+ ctx.renderer.drawRect(maskPass, {
2427
+ x: 0,
2428
+ y: 0,
2429
+ width: layerW,
2430
+ height: layerH
2431
+ }, "#ffffff", clipRadius);
2432
+ ctx.renderer.popTransform();
2433
+ maskPass.end();
2434
+ activeGroupTex = ctx.renderer.composite(encoder, activeGroupTex, maskTex, "mask-in", [
2435
+ activeGroupTex,
2436
+ maskTex,
2437
+ ...groupExcludes
2438
+ ]);
2439
+ activeGroupView = activeGroupTex.createView();
2440
+ }
2441
+ const borderResult$1 = lop.borderWidth !== void 0 && lop.borderColor ? createBorderTexture(ctx, encoder, layerW, layerH, br$1, lop.borderWidth, lop.borderColor, lop.strokeAlign ?? "inside", [activeGroupTex, ...groupExcludes]) : null;
2442
+ if (borderResult$1) {
2443
+ const borderPass = ctx.renderer.beginFrame(encoder, activeGroupView, {
2444
+ r: 0,
2445
+ g: 0,
2446
+ b: 0,
2447
+ a: 0
2448
+ }, targetW, targetH, "load");
2449
+ ctx.renderer.pushTransform(layerMatrix);
2450
+ ctx.renderer.drawTexture(borderPass, borderResult$1.borderTex, {
2451
+ x: borderResult$1.ox,
2452
+ y: borderResult$1.oy,
2453
+ width: borderResult$1.ow,
2454
+ height: borderResult$1.oh
2455
+ }, { opacity: layerOpacity });
2456
+ ctx.renderer.popTransform();
2457
+ borderPass.end();
2458
+ }
2459
+ const containerShutter = target?.motionBlurShutter ?? lop.motionBlurShutter ?? 0;
2460
+ if (containerShutter > 0 && fps && shiftedFrame !== void 0) {
2461
+ const currentT = shiftedFrame / fps;
2462
+ const prevT = (shiftedFrame - 1) / fps;
2463
+ tl.seek(prevT);
2464
+ const prevTarget = targetId ? targetsById[targetId] : void 0;
2465
+ const prevX = prevTarget?.x ?? baseX;
2466
+ const prevY = prevTarget?.y ?? baseY;
2467
+ tl.seek(currentT);
2468
+ const vx = sampledX - prevX;
2469
+ const vy = sampledY - prevY;
2470
+ if (Math.hypot(vx, vy) > .5) {
2471
+ activeGroupTex = ctx.renderer.applyMotionBlur(encoder, activeGroupTex, vx, vy, containerShutter, 16, [
2472
+ activeTex,
2473
+ targetTexture,
2474
+ ...excludes
2475
+ ]);
2476
+ activeGroupView = activeGroupTex.createView();
2477
+ }
2478
+ }
2479
+ const deflickerFromEffects = Array.isArray(lop.effects) ? lop.effects.find((e) => e?.op === "TemporalDeflicker" || e?.op === "Deflicker" || e?.constructor?.name === "TemporalDeflicker") : void 0;
2480
+ const rawDeflicker = target?.deflicker ?? lop.deflicker ?? deflickerFromEffects;
2481
+ const deflickerOpts$1 = typeof rawDeflicker === "object" && rawDeflicker !== null ? rawDeflicker : void 0;
2482
+ if (deflickerOpts$1) {
2483
+ const deflickerPipe = getTemporalDeflickerPipeline(ctx.device, lop.id || `layer_${i}`);
2484
+ if (shiftedFrame === 0) deflickerPipe.reset();
2485
+ activeGroupTex = deflickerPipe.execute(activeGroupTex, deflickerOpts$1, encoder);
2486
+ activeGroupView = activeGroupTex.createView();
2487
+ }
2488
+ const relightEffect = Array.isArray(lop.effects) ? lop.effects.find((e) => e?.op === "Relight3D" || e?.constructor?.name === "Relight3D") : void 0;
2489
+ const rawRelight = target?.relighting ?? lop.relighting ?? (typeof lop.relight === "object" ? lop.relight : void 0) ?? relightEffect;
2490
+ const relightOpts$1 = typeof rawRelight === "object" && rawRelight !== null ? rawRelight : void 0;
2491
+ if (relightOpts$1) {
2492
+ const relightPipeline = getScreenSpaceRelightPipeline(ctx.device, ctx.renderer.format ?? "rgba8unorm");
2493
+ const r3dInstance = getRenderer3D(ctx.device, ctx.renderer.format ?? "rgba8unorm", sampleCount3d);
2494
+ const activeLights = synthesizeRelightLights(relightOpts$1, sceneLights, rect, shiftedFrame, fps ?? 24);
2495
+ const lightsBuffer = r3dInstance.getOrCreateLightsBuffer(activeLights);
2496
+ const relitTex = ctx.renderer.getTemporaryTexture(targetW, targetH, [
2497
+ activeGroupTex,
2498
+ activeTex,
2499
+ targetTexture,
2500
+ ...excludes
2501
+ ]);
2502
+ const relitView = relitTex.createView();
2503
+ const normalTex = relightOpts$1.normalTexture ?? relightOpts$1.normalMap;
2504
+ relightPipeline.execute(encoder, relitView, activeGroupTex, normalTex, lightsBuffer, {
2505
+ viewportWidth: targetW,
2506
+ viewportHeight: targetH,
2507
+ layerX: 0,
2508
+ layerY: 0,
2509
+ roughness: resolveVal(target?.roughness ?? target?.relightRoughness ?? relightOpts$1.specularRoughness ?? relightOpts$1.roughness, .35, shiftedFrame, fps ?? 24),
2510
+ specularStrength: resolveVal(target?.specularStrength ?? target?.relightSpecularStrength ?? relightOpts$1.specularStrength, .7, shiftedFrame, fps ?? 24),
2511
+ metallic: resolveVal(target?.metallic ?? target?.relightMetallic ?? relightOpts$1.metallic, 0, shiftedFrame, fps ?? 24),
2512
+ ambientIntensity: resolveVal(target?.ambientIntensity ?? target?.relightAmbientIntensity ?? relightOpts$1.ambientIntensity, .15, shiftedFrame, fps ?? 24),
2513
+ depthScale: resolveVal(target?.depthScale ?? target?.relightDepthScale ?? relightOpts$1.depthScale, 1, shiftedFrame, fps ?? 24),
2514
+ opacity: 1
2515
+ }, "clear");
2516
+ activeGroupTex = relitTex;
2517
+ activeGroupView = relitView;
2518
+ }
2519
+ const compositeExcludes = [
2520
+ activeTex,
2521
+ targetTexture,
2522
+ ...excludes
2523
+ ];
2524
+ if (borderResult$1) compositeExcludes.push(borderResult$1.borderTex);
2525
+ activeTex = ctx.renderer.composite(encoder, activeTex, activeGroupTex, blendMode, compositeExcludes);
2526
+ activeView = activeTex.createView();
2527
+ return {
2528
+ finalTex: activeTex,
2529
+ finalView: activeView
2530
+ };
2531
+ }
2532
+ if (!(layerW > 0 && layerH > 0)) return {
2533
+ finalTex: activeTex,
2534
+ finalView: activeView
2535
+ };
2536
+ const br = Math.min(lop.borderRadius ?? lop.strokeRadius ?? 0, layerW / 2, layerH / 2);
2537
+ const texW = Math.ceil(layerW);
2538
+ const texH = Math.ceil(layerH);
2539
+ const savedScissors = ctx.renderer.suspendScissors?.() ?? [];
2540
+ const localTex = ctx.renderer.getTemporaryTexture(texW, texH, [
2541
+ activeTex,
2542
+ targetTexture,
2543
+ ...excludes
2544
+ ]);
2545
+ const localView = localTex.createView();
2546
+ ctx.renderer.beginFrame(encoder, localView, {
2547
+ r: 0,
2548
+ g: 0,
2549
+ b: 0,
2550
+ a: 0
2551
+ }, texW, texH, "clear").end();
2552
+ let content;
2553
+ let isCaption = false;
2554
+ if (kind === "media") {
2555
+ content = nodeVM.children?.[0];
2556
+ isCaption = content?.operation?.dataType === "Caption" || lop.dataType === "Caption" || (content?.operation)?.srtText !== void 0;
2557
+ } else if (kind === "text") {
2558
+ const fullText = lop.text ?? "";
2559
+ let displayText = fullText;
2560
+ let resolvedAnimators = rawAnimators;
2561
+ if (Array.isArray(rawAnimators) && rawAnimators.length > 0) resolvedAnimators = rawAnimators.map((animator, idx) => {
2562
+ const a = {
2563
+ ...animator,
2564
+ transform: { ...animator.transform ?? {} }
2565
+ };
2566
+ if (idx === 0) {
2567
+ const offsetVal = typeof target?.offset === "number" ? target.offset : typeof target?.animatorOffset === "number" ? target.animatorOffset : void 0;
2568
+ const rangeStartVal = typeof target?.rangeStart === "number" ? target.rangeStart : typeof target?.animatorRangeStart === "number" ? target.animatorRangeStart : void 0;
2569
+ const rangeEndVal = typeof target?.rangeEnd === "number" ? target.rangeEnd : typeof target?.animatorRangeEnd === "number" ? target.animatorRangeEnd : void 0;
2570
+ if (offsetVal !== void 0) a.offset = offsetVal;
2571
+ if (rangeStartVal !== void 0) a.rangeStart = rangeStartVal;
2572
+ if (rangeEndVal !== void 0) a.rangeEnd = rangeEndVal;
2573
+ if (Array.isArray(a.selectors)) a.selectors = a.selectors.map((s) => {
2574
+ if (s.type === "range") return {
2575
+ ...s,
2576
+ ...offsetVal !== void 0 ? { offset: offsetVal } : {},
2577
+ ...rangeStartVal !== void 0 ? { start: rangeStartVal } : {},
2578
+ ...rangeEndVal !== void 0 ? { end: rangeEndVal } : {}
2579
+ };
2580
+ return s;
2581
+ });
2582
+ }
2583
+ return a;
2584
+ });
2585
+ const hasKineticAnimators$1 = Array.isArray(resolvedAnimators) && resolvedAnimators.length > 0;
2586
+ const hasTypewriter = Boolean(lop.typewriter || target?.typewriter);
2587
+ const textTrack = lop.animation?.tracks?.find((t) => t.prop === "text");
2588
+ if (!hasKineticAnimators$1 && !hasTypewriter && (textTrack !== void 0 || typeof target?.text === "number") && fullText.length > 0) {
2589
+ const progress = typeof target?.text === "number" ? Math.max(0, Math.min(1, target.text)) : 1;
2590
+ if (progress >= 1) displayText = fullText;
2591
+ else if (progress <= 0) displayText = "";
2592
+ else {
2593
+ const presetType = textTrack?.keyframes?.find((k) => k.presetType)?.presetType ?? "typewriter";
2594
+ const textNumeric = typeof target?.text === "number" ? target.text : null;
2595
+ const isDirectCount = textNumeric !== null && textNumeric > 1.0001;
2596
+ if (presetType === "word-reveal" || presetType === "karaoke") {
2597
+ const tokens = fullText.split(/(\s+)/);
2598
+ const wordIndices = [];
2599
+ tokens.forEach((token, idx) => {
2600
+ if (token.trim().length > 0) wordIndices.push(idx);
2601
+ });
2602
+ const visibleWordCount = isDirectCount && textNumeric !== null ? Math.min(wordIndices.length, Math.round(textNumeric)) : Math.round(wordIndices.length * progress);
2603
+ if (visibleWordCount === 0) displayText = "";
2604
+ else {
2605
+ const lastTokenIdx = wordIndices[Math.min(wordIndices.length - 1, visibleWordCount - 1)];
2606
+ displayText = tokens.slice(0, lastTokenIdx + 1).join("");
2607
+ }
2608
+ } else if (presetType === "line-reveal") {
2609
+ const lines = fullText.split("\n");
2610
+ const visibleLineCount = isDirectCount && textNumeric !== null ? Math.min(lines.length, Math.round(textNumeric)) : Math.round(lines.length * progress);
2611
+ displayText = lines.slice(0, Math.max(0, visibleLineCount)).join("\n");
2612
+ } else {
2613
+ const visibleChars = isDirectCount && textNumeric !== null ? Math.min(fullText.length, Math.round(textNumeric)) : Math.round(fullText.length * progress);
2614
+ displayText = fullText.slice(0, visibleChars);
2615
+ }
2616
+ }
2617
+ }
2618
+ content = {
2619
+ metadata: {},
2620
+ operation: {
2621
+ op: "text",
2622
+ text: displayText,
2623
+ animators: resolvedAnimators,
2624
+ pathOptions: target?.pathOptions ?? lop.pathOptions,
2625
+ typewriter: target?.typewriter ?? lop.typewriter,
2626
+ marquee: target?.marquee ?? lop.marquee,
2627
+ textProgress: typeof target?.text === "number" ? target.text : void 0,
2628
+ firstMargin: target?.firstMargin ?? lop.firstMargin,
2629
+ lastMargin: target?.lastMargin ?? lop.lastMargin,
2630
+ baselineShift: target?.baselineShift ?? lop.baselineShift,
2631
+ signals: virtualMedia?.operation?.signals ?? virtualMedia?.signals,
2632
+ fontSize: target?.fontSize ?? lop.fontSize,
2633
+ fontFamily: lop.fontFamily,
2634
+ fontStyle: lop.fontStyle,
2635
+ fontWeight: lop.fontWeight,
2636
+ fill: target?.fill ?? target?.color ?? lop.fill,
2637
+ align: lop.align === "start" ? "left" : lop.align === "end" ? "right" : lop.align,
2638
+ verticalAlign: lop.verticalAlign,
2639
+ letterSpacing: target?.letterSpacing ?? lop.letterSpacing,
2640
+ lineHeight: lop.lineHeight,
2641
+ padding: lop.padding,
2642
+ textBackgroundColor: target?.textBackgroundColor ?? target?.background ?? lop.background,
2643
+ borderRadius: lop.borderRadius,
2644
+ stroke: target?.stroke ?? target?.strokeColor ?? lop.stroke,
2645
+ strokeWidth: target?.strokeWidth ?? lop.strokeWidth,
2646
+ strokeAlign: lop.strokeAlign,
2647
+ textShadow: lop.textShadow,
2648
+ shadows: lop.shadows,
2649
+ x: isPathText ? 0 : padX,
2650
+ y: isPathText ? 0 : padY,
2651
+ width: isPathText ? targetW : lop.width !== void 0 ? rect.width : void 0,
2652
+ height: isPathText ? targetH : lop.height !== void 0 ? rect.height : void 0
2653
+ },
2654
+ children: []
2655
+ };
2656
+ }
2657
+ let glyphBatches = null;
2658
+ let layerHasRaster = true;
2659
+ if (content) {
2660
+ const contentDurationMs = getActiveMediaMetadata(content)?.durationMs ?? composeDuration;
2661
+ const layerDurationInMS = Math.max(1, Math.round(contentDurationMs / 1e3 * (fps ?? 24))) / (fps ?? 24) * 1e3;
2662
+ const contentIsImageCompositor = content.operation?.op === "Compositor" && content.operation?.dataType === "Image";
2663
+ const captureGlyphs = isTrue3D && kind === "text";
2664
+ const rasterDrawsBefore = ctx.renderer.rasterDrawCount;
2665
+ if (captureGlyphs) ctx.renderer.slugPipeline.beginCapture();
2666
+ try {
2667
+ await drawChild(content, {
2668
+ containerWidth: layerW,
2669
+ containerHeight: layerH,
2670
+ renderId: `${props.renderId}-l${i}`,
2671
+ durationMs: layerDurationInMS,
2672
+ opacity: 1,
2673
+ fps,
2674
+ excludeTextures: [
2675
+ activeTex,
2676
+ targetTexture,
2677
+ ...excludes
2678
+ ],
2679
+ isVideoMode: isVideoMode && !contentIsImageCompositor,
2680
+ ...isVideoMode && { frame: Math.max(0, shiftedFrame - (lop.startFrame ?? 0)) + (lop.mediaStartFrame ?? lop.trimStartFrames ?? (lop.trimStartSec != null ? Math.round(lop.trimStartSec * (fps ?? 24)) : 0)) },
2681
+ ...isCaption && {
2682
+ fontFamily: lop.fontFamily,
2683
+ fontSize: target?.fontSize ?? lop.fontSize,
2684
+ fontWeight: lop.fontWeight,
2685
+ fontStyle: lop.fontStyle,
2686
+ fill: lop.fill,
2687
+ color: lop.fill,
2688
+ align: lop.align === "start" ? "left" : lop.align === "end" ? "right" : lop.align ?? "center",
2689
+ verticalAlign: lop.verticalAlign ?? lop.textAlignVertical,
2690
+ lineHeight: lop.lineHeight,
2691
+ letterSpacing: lop.letterSpacing,
2692
+ textBackgroundColor: lop.background ?? lop.textBackgroundColor,
2693
+ borderRadius: lop.borderRadius ?? lop.strokeRadius,
2694
+ strokeRadius: lop.strokeRadius ?? lop.borderRadius,
2695
+ stroke: lop.stroke,
2696
+ strokeWidth: lop.strokeWidth,
2697
+ shadows: lop.shadows,
2698
+ padding: lop.padding,
2699
+ maxWidth: lop.maxWidth ?? layerW
2700
+ }
2701
+ }, localView, localTex, texW, texH);
2702
+ } finally {
2703
+ if (captureGlyphs) glyphBatches = ctx.renderer.slugPipeline.endCapture();
2704
+ }
2705
+ layerHasRaster = ctx.renderer.rasterDrawCount !== rasterDrawsBefore;
2706
+ } else if (kind === "shape") {
2707
+ const shapePass = ctx.renderer.beginFrame(encoder, localView, {
2708
+ r: 0,
2709
+ g: 0,
2710
+ b: 0,
2711
+ a: 0
2712
+ }, texW, texH, "load");
2713
+ const shapeConfig = {
2714
+ shapeType: lop.shapeType ?? lop.shape ?? "rect",
2715
+ width: layerW,
2716
+ height: layerH,
2717
+ path: lop.d ?? lop.path,
2718
+ cornerRadius: target?.cornerRadius ?? lop.cornerRadius ?? lop.borderRadius ?? lop.radius ?? 0,
2719
+ starPoints: lop.starPoints ?? 5,
2720
+ starInnerRadiusRatio: target?.starInnerRadiusRatio ?? lop.starInnerRadiusRatio ?? .5,
2721
+ polygonSides: lop.polygonSides ?? 5
2722
+ };
2723
+ const fillType = lop.fillType ?? "solid";
2724
+ const fillColor = target?.fillColor ?? target?.fill ?? lop.fillColor ?? lop.fill ?? "#38bdf8";
2725
+ const color2 = target?.gradientEndColor ?? lop.gradientEndColor ?? lop.fillColor2 ?? "#9333ea";
2726
+ let startX = lop.fillStartX;
2727
+ let startY = lop.fillStartY;
2728
+ let endX = lop.fillEndX;
2729
+ let endY = lop.fillEndY;
2730
+ if (fillType === "linear" && startX === void 0 && lop.gradientAngle !== void 0) {
2731
+ const rad = lop.gradientAngle * Math.PI / 180;
2732
+ const cx = layerW / 2;
2733
+ const cy = layerH / 2;
2734
+ const half = (Math.abs(layerW * Math.cos(rad)) + Math.abs(layerH * Math.sin(rad))) / 2;
2735
+ startX = cx - Math.cos(rad) * half;
2736
+ startY = cy - Math.sin(rad) * half;
2737
+ endX = cx + Math.cos(rad) * half;
2738
+ endY = cy + Math.sin(rad) * half;
2739
+ }
2740
+ const fillConfig = {
2741
+ type: fillType,
2742
+ color: fillColor,
2743
+ color2,
2744
+ startX,
2745
+ startY,
2746
+ endX,
2747
+ endY,
2748
+ cx: lop.fillCx,
2749
+ cy: lop.fillCy,
2750
+ radius: lop.fillRadius
2751
+ };
2752
+ const strokeWidth = target?.strokeWidth ?? lop.strokeWidth ?? 0;
2753
+ const strokeColor = target?.strokeColor ?? lop.strokeColor ?? lop.stroke ?? "#ffffff";
2754
+ const strokeLineCap = lop.strokeLineCap ?? "round";
2755
+ const strokeDashArray = lop.strokeDashArray;
2756
+ const strokeDashOffset = target?.strokeDashOffset ?? lop.strokeDashOffset ?? 0;
2757
+ const trimStart = target?.trimStart ?? lop.trimStart ?? 0;
2758
+ const trimEnd = target?.trimEnd ?? lop.trimEnd ?? 1;
2759
+ const trimOffset = target?.trimOffset ?? lop.trimOffset ?? 0;
2760
+ ctx.renderer.drawShape(shapePass, shapeConfig, fillConfig, strokeWidth > 0 ? {
2761
+ color: strokeColor,
2762
+ width: strokeWidth,
2763
+ cap: strokeLineCap,
2764
+ trimStart,
2765
+ trimEnd,
2766
+ trimOffset,
2767
+ dashArray: strokeDashArray,
2768
+ dashOffset: strokeDashOffset
2769
+ } : void 0);
2770
+ shapePass.end();
2771
+ }
2772
+ const leafDeflickerEffect = Array.isArray(lop.effects) ? lop.effects.find((e) => e?.op === "TemporalDeflicker" || e?.constructor?.name === "TemporalDeflicker") : void 0;
2773
+ const deflickerOpts = target?.deflicker ?? lop.deflicker ?? leafDeflickerEffect;
2774
+ const leafRelightEffect = Array.isArray(lop.effects) ? lop.effects.find((e) => e?.op === "Relight3D" || e?.constructor?.name === "Relight3D") : void 0;
2775
+ const rawLeafRelight = target?.relighting ?? lop.relighting ?? (typeof lop.relight === "object" ? lop.relight : void 0) ?? leafRelightEffect;
2776
+ const relightOpts = typeof rawLeafRelight === "object" && rawLeafRelight !== null ? rawLeafRelight : void 0;
2777
+ const shutterAngle = target?.motionBlurShutter ?? lop.motionBlurShutter ?? 0;
2778
+ if (glyphBatches && glyphBatches.length > 0 && (deflickerOpts || relightOpts || shutterAngle > 0)) {
2779
+ const glyphPass = ctx.renderer.beginFrame(encoder, localView, {
2780
+ r: 0,
2781
+ g: 0,
2782
+ b: 0,
2783
+ a: 0
2784
+ }, texW, texH, "load");
2785
+ ctx.renderer.slugPipeline.drawBatches(glyphPass, glyphBatches, texW, texH);
2786
+ glyphPass.end();
2787
+ glyphBatches = null;
2788
+ layerHasRaster = true;
2789
+ }
2790
+ let finalTex = localTex;
2791
+ if (!isTrue3D && br > 0 && !isCaption && kind !== "shape") {
2792
+ const maskTex = ctx.renderer.getTemporaryTexture(texW, texH, [
2793
+ localTex,
2794
+ activeTex,
2795
+ targetTexture,
2796
+ ...excludes
2797
+ ]);
2798
+ const maskView = maskTex.createView();
2799
+ ctx.renderer.beginFrame(encoder, maskView, {
2800
+ r: 0,
2801
+ g: 0,
2802
+ b: 0,
2803
+ a: 0
2804
+ }, texW, texH, "clear").end();
2805
+ const maskPass = ctx.renderer.beginFrame(encoder, maskView, {
2806
+ r: 0,
2807
+ g: 0,
2808
+ b: 0,
2809
+ a: 0
2810
+ }, texW, texH, "load");
2811
+ ctx.renderer.drawRect(maskPass, {
2812
+ x: 0,
2813
+ y: 0,
2814
+ width: layerW,
2815
+ height: layerH
2816
+ }, {
2817
+ r: 1,
2818
+ g: 1,
2819
+ b: 1,
2820
+ a: 1
2821
+ }, br);
2822
+ maskPass.end();
2823
+ finalTex = ctx.renderer.composite(encoder, localTex, maskTex, "mask-in", [
2824
+ activeTex,
2825
+ targetTexture,
2826
+ ...excludes
2827
+ ]);
2828
+ }
2829
+ if (deflickerOpts) {
2830
+ const deflickerPipe = getTemporalDeflickerPipeline(ctx.device, lop.id || `layer_${i}`);
2831
+ if (shiftedFrame === 0) deflickerPipe.reset();
2832
+ finalTex = deflickerPipe.execute(finalTex, deflickerOpts, encoder);
2833
+ }
2834
+ if (relightOpts) {
2835
+ const relightPipeline = getScreenSpaceRelightPipeline(ctx.device, ctx.renderer.format ?? "rgba8unorm");
2836
+ const r3dInstance = getRenderer3D(ctx.device, ctx.renderer.format ?? "rgba8unorm", sampleCount3d);
2837
+ const activeLights = synthesizeRelightLights(relightOpts, sceneLights, {
2838
+ x: sampledX,
2839
+ y: sampledY,
2840
+ width: texW,
2841
+ height: texH
2842
+ }, shiftedFrame, fps ?? 24);
2843
+ const lightsBuffer = r3dInstance.getOrCreateLightsBuffer(activeLights);
2844
+ const relitTex = ctx.renderer.getTemporaryTexture(texW, texH, [
2845
+ finalTex,
2846
+ activeTex,
2847
+ targetTexture,
2848
+ ...excludes
2849
+ ]);
2850
+ const relitView = relitTex.createView();
2851
+ const normalTex = relightOpts.normalTexture ?? relightOpts.normalMap;
2852
+ relightPipeline.execute(encoder, relitView, finalTex, normalTex, lightsBuffer, {
2853
+ viewportWidth: texW,
2854
+ viewportHeight: texH,
2855
+ layerX: sampledX,
2856
+ layerY: sampledY,
2857
+ roughness: resolveVal(target?.roughness ?? target?.relightRoughness ?? relightOpts.specularRoughness ?? relightOpts.roughness, .35, shiftedFrame, fps ?? 24),
2858
+ specularStrength: resolveVal(target?.specularStrength ?? target?.relightSpecularStrength ?? relightOpts.specularStrength, .7, shiftedFrame, fps ?? 24),
2859
+ metallic: resolveVal(target?.metallic ?? target?.relightMetallic ?? relightOpts.metallic, 0, shiftedFrame, fps ?? 24),
2860
+ ambientIntensity: resolveVal(target?.ambientIntensity ?? target?.relightAmbientIntensity ?? relightOpts.ambientIntensity, .15, shiftedFrame, fps ?? 24),
2861
+ depthScale: resolveVal(target?.depthScale ?? target?.relightDepthScale ?? relightOpts.depthScale, 1, shiftedFrame, fps ?? 24),
2862
+ opacity: 1
2863
+ }, "clear");
2864
+ finalTex = relitTex;
2865
+ }
2866
+ let blurPadX = 0;
2867
+ let blurPadY = 0;
2868
+ if (shutterAngle > 0 && fps && shiftedFrame !== void 0) {
2869
+ const currentT = shiftedFrame / fps;
2870
+ const prevT = (shiftedFrame - 1) / fps;
2871
+ tl.seek(prevT);
2872
+ const prevTarget = targetId ? targetsById[targetId] : void 0;
2873
+ const prevX = prevTarget?.x ?? baseX;
2874
+ const prevY = prevTarget?.y ?? baseY;
2875
+ tl.seek(currentT);
2876
+ const vx = sampledX - prevX;
2877
+ const vy = sampledY - prevY;
2878
+ if (Math.hypot(vx, vy) > .5) {
2879
+ if (!isTrue3D && !(is3D && quad3D)) {
2880
+ const reach = shutterAngle / 360;
2881
+ blurPadX = Math.ceil(Math.abs(vx) * reach);
2882
+ blurPadY = Math.ceil(Math.abs(vy) * reach);
2883
+ const paddedTex = ctx.renderer.getTemporaryTexture(texW + blurPadX * 2, texH + blurPadY * 2, [
2884
+ finalTex,
2885
+ activeTex,
2886
+ targetTexture,
2887
+ ...excludes
2888
+ ]);
2889
+ const padPass = ctx.renderer.beginFrame(encoder, paddedTex.createView(), {
2890
+ r: 0,
2891
+ g: 0,
2892
+ b: 0,
2893
+ a: 0
2894
+ }, paddedTex.width, paddedTex.height, "clear");
2895
+ ctx.renderer.drawTexture(padPass, finalTex, {
2896
+ x: blurPadX,
2897
+ y: blurPadY,
2898
+ width: texW,
2899
+ height: texH
2900
+ }, { opacity: 1 });
2901
+ padPass.end();
2902
+ finalTex = paddedTex;
2903
+ }
2904
+ const streakPx = Math.hypot(vx, vy) * (shutterAngle / 360) * 2;
2905
+ const samples = Math.min(128, Math.max(16, Math.ceil(streakPx / 2)));
2906
+ finalTex = ctx.renderer.applyMotionBlur(encoder, finalTex, vx, vy, shutterAngle, samples, [
2907
+ activeTex,
2908
+ targetTexture,
2909
+ ...excludes
2910
+ ]);
2911
+ }
2912
+ }
2913
+ const borderExcludes = [
2914
+ localTex,
2915
+ finalTex,
2916
+ activeTex,
2917
+ targetTexture,
2918
+ ...excludes
2919
+ ];
2920
+ const borderResult = !isTrue3D && lop.borderWidth !== void 0 && lop.borderColor ? createBorderTexture(ctx, encoder, layerW, layerH, br, lop.borderWidth, lop.borderColor, lop.strokeAlign ?? "inside", borderExcludes) : null;
2921
+ if (savedScissors.length > 0) ctx.renderer.resumeScissors?.(savedScissors);
2922
+ if (isTrue3D) {
2923
+ const renderedTex = finalTex;
2924
+ if (borderResult) {
2925
+ const borderPass = ctx.renderer.beginFrame(encoder, renderedTex.createView(), {
2926
+ r: 0,
2927
+ g: 0,
2928
+ b: 0,
2929
+ a: 0
2930
+ }, texW, texH, "load");
2931
+ ctx.renderer.drawTexture(borderPass, borderResult.borderTex, {
2932
+ x: borderResult.ox,
2933
+ y: borderResult.oy,
2934
+ width: borderResult.ow,
2935
+ height: borderResult.oh
2936
+ }, { opacity: 1 });
2937
+ borderPass.end();
2938
+ }
2939
+ let modelMatrix;
2940
+ if (parent3DMatrix) {
2941
+ let localM = Matrix4Math.identity();
2942
+ const childX = target?.x ?? lop.x ?? 0;
2943
+ const childY = target?.y ?? lop.y ?? 0;
2944
+ const childZ = target?.z ?? lop.z ?? 0;
2945
+ localM = Matrix4Math.multiply(localM, Matrix4Math.translate(childX, childY, childZ));
2946
+ const rxRad = (target?.rotateX ?? lop.rotateX ?? 0) * Math.PI / 180;
2947
+ const ryRad = (target?.rotateY ?? lop.rotateY ?? 0) * Math.PI / 180;
2948
+ const rzRad = ((target?.rotateZ ?? lop.rotateZ ?? 0) !== 0 ? target?.rotateZ ?? lop.rotateZ ?? 0 : rotation) * (Math.PI / 180);
2949
+ if (rzRad !== 0) localM = Matrix4Math.multiply(localM, Matrix4Math.rotateZ(rzRad));
2950
+ if (ryRad !== 0) localM = Matrix4Math.multiply(localM, Matrix4Math.rotateY(ryRad));
2951
+ if (rxRad !== 0) localM = Matrix4Math.multiply(localM, Matrix4Math.rotateX(rxRad));
2952
+ const sx = layerW * scale$1;
2953
+ const sy = layerH * scale$1;
2954
+ const sz = target?.scaleZ ?? lop.scaleZ ?? 1;
2955
+ localM = Matrix4Math.multiply(localM, Matrix4Math.scale(sx, sy, sz));
2956
+ const ax = lop.anchorX ?? .5;
2957
+ const ay = lop.anchorY ?? .5;
2958
+ const pivotX = .5 - ax;
2959
+ const pivotY = .5 - ay;
2960
+ if (pivotX !== 0 || pivotY !== 0) localM = Matrix4Math.multiply(localM, Matrix4Math.translate(pivotX, pivotY, 0));
2961
+ modelMatrix = Matrix4Math.multiply(parent3DMatrix, localM);
2962
+ }
2963
+ const quadOpts = {
2964
+ position: [
2965
+ localX + layerW * .5,
2966
+ localY + layerH * .5,
2967
+ target?.z ?? lop.z ?? 0
2968
+ ],
2969
+ width: layerW,
2970
+ height: layerH,
2971
+ textureExtent: [layerW / texW, layerH / texH],
2972
+ rotation: [
2973
+ target?.rotateX ?? lop.rotateX ?? 0,
2974
+ target?.rotateY ?? lop.rotateY ?? 0,
2975
+ (target?.rotateZ ?? lop.rotateZ ?? 0) !== 0 ? target?.rotateZ ?? lop.rotateZ ?? 0 : rotation
2976
+ ],
2977
+ scale: [
2978
+ scale$1,
2979
+ scale$1,
2980
+ target?.scaleZ ?? lop.scaleZ ?? 1
2981
+ ],
2982
+ anchor: [lop.anchorX ?? .5, lop.anchorY ?? .5],
2983
+ borderRadius: br,
2984
+ borderWidth: lop.borderWidth,
2985
+ borderColor: lop.borderColor,
2986
+ opacity: layerOpacity,
2987
+ twoSided: target?.twoSided ?? lop.twoSided ?? true,
2988
+ material: target?.material ?? lop.material,
2989
+ shininess: target?.shininess ?? lop.shininess,
2990
+ roughness: target?.roughness ?? lop.roughness,
2991
+ specularIntensity: target?.specularIntensity ?? lop.specularIntensity,
2992
+ ambientIntensity: target?.ambientIntensity ?? lop.ambientIntensity,
2993
+ metallic: target?.metallic ?? lop.metallic,
2994
+ ...modelMatrix && { modelMatrix }
2995
+ };
2996
+ const quadHasContent = layerHasRaster || Boolean(quadOpts.borderWidth && quadOpts.borderWidth > 0 && quadOpts.borderColor);
2997
+ if (!glyphBatches || quadHasContent) pending3DItems.push({
2998
+ kind: "quad",
2999
+ texture: renderedTex,
3000
+ opts: quadOpts
3001
+ });
3002
+ if (glyphBatches && glyphBatches.length > 0) pending3DItems.push({
3003
+ kind: "slug",
3004
+ batches: glyphBatches,
3005
+ opts: quadOpts,
3006
+ stackBase: quadHasContent ? 1 : 0
3007
+ });
3008
+ return {
3009
+ finalTex: activeTex,
3010
+ finalView: activeView
3011
+ };
3012
+ }
3013
+ if (is3D && quad3D) {
3014
+ const renderedTex = finalTex;
3015
+ if (borderResult) {
3016
+ const borderPass = ctx.renderer.beginFrame(encoder, renderedTex.createView(), {
3017
+ r: 0,
3018
+ g: 0,
3019
+ b: 0,
3020
+ a: 0
3021
+ }, texW, texH, "load");
3022
+ ctx.renderer.drawTexture(borderPass, borderResult.borderTex, {
3023
+ x: borderResult.ox,
3024
+ y: borderResult.oy,
3025
+ width: borderResult.ow,
3026
+ height: borderResult.oh
3027
+ }, { opacity: 1 });
3028
+ borderPass.end();
3029
+ }
3030
+ if (blendMode === "normal" || blendMode === "source-over") drawProjectedQuad(ctx, encoder, activeView, renderedTex, quad3D, targetW, targetH, layerOpacity);
3031
+ else {
3032
+ const layerExcludes = [
3033
+ activeTex,
3034
+ targetTexture,
3035
+ renderedTex,
3036
+ ...excludes
3037
+ ];
3038
+ if (borderResult) layerExcludes.push(borderResult.borderTex);
3039
+ const layerTex = ctx.renderer.getTemporaryTexture(targetW, targetH, layerExcludes);
3040
+ const layerView = layerTex.createView();
3041
+ ctx.renderer.beginFrame(encoder, layerView, {
3042
+ r: 0,
3043
+ g: 0,
3044
+ b: 0,
3045
+ a: 0
3046
+ }, targetW, targetH, "clear").end();
3047
+ drawProjectedQuad(ctx, encoder, layerView, renderedTex, quad3D, targetW, targetH, layerOpacity);
3048
+ activeTex = ctx.renderer.composite(encoder, activeTex, layerTex, blendMode, [targetTexture, ...excludes]);
3049
+ activeView = activeTex.createView();
3050
+ }
3051
+ return {
3052
+ finalTex: activeTex,
3053
+ finalView: activeView
3054
+ };
3055
+ }
3056
+ if (blendMode === "normal" || blendMode === "source-over") {
3057
+ const drawPass = ctx.renderer.beginFrame(encoder, activeView, {
3058
+ r: 0,
3059
+ g: 0,
3060
+ b: 0,
3061
+ a: 0
3062
+ }, targetW, targetH, "load");
3063
+ ctx.renderer.pushTransform(layerMatrix);
3064
+ ctx.renderer.drawTexture(drawPass, finalTex, {
3065
+ x: -blurPadX,
3066
+ y: -blurPadY,
3067
+ width: layerW + blurPadX * 2,
3068
+ height: layerH + blurPadY * 2
3069
+ }, { opacity: layerOpacity });
3070
+ if (borderResult) ctx.renderer.drawTexture(drawPass, borderResult.borderTex, {
3071
+ x: borderResult.ox,
3072
+ y: borderResult.oy,
3073
+ width: borderResult.ow,
3074
+ height: borderResult.oh
3075
+ }, { opacity: layerOpacity });
3076
+ ctx.renderer.popTransform();
3077
+ drawPass.end();
3078
+ } else {
3079
+ const layerExcludes = [
3080
+ finalTex,
3081
+ activeTex,
3082
+ targetTexture,
3083
+ ...excludes
3084
+ ];
3085
+ if (borderResult) layerExcludes.push(borderResult.borderTex);
3086
+ const layerTex = ctx.renderer.getTemporaryTexture(targetW, targetH, layerExcludes);
3087
+ const layerView = layerTex.createView();
3088
+ ctx.renderer.beginFrame(encoder, layerView, {
3089
+ r: 0,
3090
+ g: 0,
3091
+ b: 0,
3092
+ a: 0
3093
+ }, targetW, targetH, "clear").end();
3094
+ const drawPass = ctx.renderer.beginFrame(encoder, layerView, {
3095
+ r: 0,
3096
+ g: 0,
3097
+ b: 0,
3098
+ a: 0
3099
+ }, targetW, targetH, "load");
3100
+ ctx.renderer.pushTransform(layerMatrix);
3101
+ ctx.renderer.drawTexture(drawPass, finalTex, {
3102
+ x: -blurPadX,
3103
+ y: -blurPadY,
3104
+ width: layerW + blurPadX * 2,
3105
+ height: layerH + blurPadY * 2
3106
+ }, { opacity: layerOpacity });
3107
+ if (borderResult) ctx.renderer.drawTexture(drawPass, borderResult.borderTex, {
3108
+ x: borderResult.ox,
3109
+ y: borderResult.oy,
3110
+ width: borderResult.ow,
3111
+ height: borderResult.oh
3112
+ }, { opacity: layerOpacity });
3113
+ ctx.renderer.popTransform();
3114
+ drawPass.end();
3115
+ activeTex = ctx.renderer.composite(encoder, activeTex, layerTex, blendMode, [targetTexture, ...excludes]);
3116
+ activeView = activeTex.createView();
3117
+ }
3118
+ return {
3119
+ finalTex: activeTex,
3120
+ finalView: activeView
3121
+ };
3122
+ };
3123
+ const initialExcludes = [
3124
+ compTex,
3125
+ targetTexture,
3126
+ ...props.excludeTextures || []
3127
+ ];
3128
+ currentCompTex = (await renderNodeTree(virtualMedia.children ?? [], compTex, compView, initialExcludes, 1, new DOMMatrix(), null, nativeWidth, nativeHeight, null, true)).finalTex;
3129
+ ctx.renderer.popTransform();
3130
+ ctx.renderer.popScissor();
3131
+ const finalPass = ctx.renderer.beginFrame(encoder, targetView, {
3132
+ r: 0,
3133
+ g: 0,
3134
+ b: 0,
3135
+ a: 0
3136
+ }, targetWidth, targetHeight, "load");
3137
+ ctx.renderer.drawTexture(finalPass, currentCompTex, {
3138
+ x: 0,
3139
+ y: 0,
3140
+ width: props.containerWidth ?? targetWidth,
3141
+ height: props.containerHeight ?? targetHeight
3142
+ }, { opacity });
3143
+ args.pass = finalPass;
3144
+ }
3145
+ };
3146
+ function createBorderTexture(ctx, encoder, w, h, br, borderWidth, borderColor, strokeAlign, excludeTextures) {
3147
+ if (w <= 0 || h <= 0 || !borderColor || !borderWidth || borderWidth <= 0) return null;
3148
+ let ox = 0;
3149
+ let oy = 0;
3150
+ let ow = w;
3151
+ let oh = h;
3152
+ let outerRadius = br;
3153
+ let innerRadius = br;
3154
+ if (strokeAlign === "inside") {
3155
+ ox = 0;
3156
+ oy = 0;
3157
+ ow = w;
3158
+ oh = h;
3159
+ outerRadius = br;
3160
+ innerRadius = Math.max(0, br - borderWidth);
3161
+ } else if (strokeAlign === "outside") {
3162
+ ox = -borderWidth;
3163
+ oy = -borderWidth;
3164
+ ow = w + 2 * borderWidth;
3165
+ oh = h + 2 * borderWidth;
3166
+ outerRadius = br + borderWidth;
3167
+ innerRadius = br;
3168
+ } else {
3169
+ ox = -borderWidth / 2;
3170
+ oy = -borderWidth / 2;
3171
+ ow = w + borderWidth;
3172
+ oh = h + borderWidth;
3173
+ outerRadius = br + borderWidth / 2;
3174
+ innerRadius = Math.max(0, br - borderWidth / 2);
3175
+ }
3176
+ if (br <= 0) {
3177
+ outerRadius = 0;
3178
+ innerRadius = 0;
3179
+ }
3180
+ if (ow <= 0 || oh <= 0) return null;
3181
+ const borderTexW = Math.ceil(ow);
3182
+ const borderTexH = Math.ceil(oh);
3183
+ const outerTex = ctx.renderer.getTemporaryTexture(borderTexW, borderTexH, excludeTextures);
3184
+ const outerView = outerTex.createView();
3185
+ ctx.renderer.beginFrame(encoder, outerView, {
3186
+ r: 0,
3187
+ g: 0,
3188
+ b: 0,
3189
+ a: 0
3190
+ }, borderTexW, borderTexH, "clear").end();
3191
+ const outerDrawPass = ctx.renderer.beginFrame(encoder, outerView, {
3192
+ r: 0,
3193
+ g: 0,
3194
+ b: 0,
3195
+ a: 0
3196
+ }, borderTexW, borderTexH, "load");
3197
+ ctx.renderer.drawRect(outerDrawPass, {
3198
+ x: 0,
3199
+ y: 0,
3200
+ width: ow,
3201
+ height: oh
3202
+ }, borderColor, outerRadius);
3203
+ outerDrawPass.end();
3204
+ const innerW = ow - 2 * borderWidth;
3205
+ const innerH = oh - 2 * borderWidth;
3206
+ if (innerW > 0 && innerH > 0) {
3207
+ const innerTex = ctx.renderer.getTemporaryTexture(borderTexW, borderTexH, [outerTex, ...excludeTextures]);
3208
+ const innerView = innerTex.createView();
3209
+ ctx.renderer.beginFrame(encoder, innerView, {
3210
+ r: 0,
3211
+ g: 0,
3212
+ b: 0,
3213
+ a: 0
3214
+ }, borderTexW, borderTexH, "clear").end();
3215
+ const innerDrawPass = ctx.renderer.beginFrame(encoder, innerView, {
3216
+ r: 0,
3217
+ g: 0,
3218
+ b: 0,
3219
+ a: 0
3220
+ }, borderTexW, borderTexH, "load");
3221
+ ctx.renderer.drawRect(innerDrawPass, {
3222
+ x: borderWidth,
3223
+ y: borderWidth,
3224
+ width: innerW,
3225
+ height: innerH
3226
+ }, {
3227
+ r: 1,
3228
+ g: 1,
3229
+ b: 1,
3230
+ a: 1
3231
+ }, innerRadius);
3232
+ innerDrawPass.end();
3233
+ return {
3234
+ borderTex: ctx.renderer.composite(encoder, outerTex, innerTex, "mask-out", excludeTextures),
3235
+ ox,
3236
+ oy,
3237
+ ow,
3238
+ oh
3239
+ };
3240
+ }
3241
+ return {
3242
+ borderTex: outerTex,
3243
+ ox,
3244
+ oy,
3245
+ ow,
3246
+ oh
3247
+ };
3248
+ }
3249
+ const compositorLayerAudioProcessor = async (channels, sampleRate, virtualMedia, ctx) => {
3250
+ const op = virtualMedia.operation;
3251
+ if (!op) return;
3252
+ const numChannels = channels.length;
3253
+ if (numChannels === 0) return;
3254
+ const numSamples = channels[0].length;
3255
+ if (numSamples === 0) return;
3256
+ if (op.op === "Compositor") {
3257
+ const master = typeof op.volume === "number" ? op.volume : 1;
3258
+ if (master === 1) return;
3259
+ for (let c = 0; c < numChannels; c++) {
3260
+ const ch = channels[c];
3261
+ for (let i = 0; i < ch.length; i++) ch[i] *= master;
3262
+ }
3263
+ return;
3264
+ }
3265
+ const volume = typeof op.volume === "number" ? op.volume : 1;
3266
+ const muted = !!op.muted;
3267
+ const animation = op.animation;
3268
+ const fps = ctx?.fps ?? 24;
3269
+ const tracks = animation?.tracks || [];
3270
+ const hasVolumeKeys = tracks.some((t) => t.prop === "volume" && t.keyframes && t.keyframes.length > 0);
3271
+ const hasMutedKeys = tracks.some((t) => t.prop === "muted" && t.keyframes && t.keyframes.length > 0);
3272
+ if (!hasVolumeKeys && !hasMutedKeys) return;
3273
+ const { tl, stub } = compileLayerTimeline(op.id || op.inputHandleId || "layer", animation, volume, muted, fps);
3274
+ const startTimeSec = (ctx?.elapsedMs ?? 0) / 1e3;
3275
+ const subChunkSize = 128;
3276
+ tl.seek(startTimeSec);
3277
+ let lastVol = stub.volume;
3278
+ let lastMuted = stub.muted;
3279
+ const baseGain = muted ? 0 : volume;
3280
+ for (let i = 0; i < numSamples; i += subChunkSize) {
3281
+ const nextI = Math.min(numSamples, i + subChunkSize);
3282
+ const tNext = startTimeSec + (nextI - i) / sampleRate;
3283
+ tl.seek(tNext);
3284
+ const nextVol = stub.volume;
3285
+ const nextMuted = stub.muted;
3286
+ for (let j = i; j < nextI; j++) {
3287
+ const p = (j - i) / (nextI - i);
3288
+ const currentVol = Math.min(1, Math.max(0, lastVol + (nextVol - lastVol) * p));
3289
+ const finalGain = (j - i < (nextI - i) / 2 ? lastMuted : nextMuted) ? 0 : currentVol;
3290
+ const relativeGain = baseGain === 0 ? 0 : finalGain / baseGain;
3291
+ if (relativeGain !== 1) for (let c = 0; c < numChannels; c++) channels[c][j] *= relativeGain;
3292
+ }
3293
+ lastVol = nextVol;
3294
+ lastMuted = nextMuted;
3295
+ }
3296
+ };
3297
+ audioRegistry.register("CompositorLayer", compositorLayerAudioProcessor);
3298
+ var renderers_default = defineRenderer({ WebGPURenderer: CompositorWebGPURenderer });
3299
+
3300
+ //#endregion
3301
+ export { Transform3DMath, renderers_default as default, has3DTransform, solveHomography };
3302
+ //# sourceMappingURL=renderer-COkcU3db.mjs.map