framefields 2.13.1 → 2.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (339) hide show
  1. package/NOTICE.md +5 -1
  2. package/dist/audio/index.d.mts +5 -5
  3. package/dist/audio/index.mjs +10 -10
  4. package/dist/{audio-DIvi6hTD.mjs → audio-6TfPlfl4.mjs} +3 -3
  5. package/dist/{audio-DIvi6hTD.mjs.map → audio-6TfPlfl4.mjs.map} +1 -1
  6. package/dist/{audio-C4B9p_yq.d.mts → audio-7oqTUi4G.d.mts} +3 -3
  7. package/dist/{audio-C4B9p_yq.d.mts.map → audio-7oqTUi4G.d.mts.map} +1 -1
  8. package/dist/cli/check-worker.mjs +44 -44
  9. package/dist/cli.mjs +1 -1
  10. package/dist/cloud/index.d.mts.map +1 -1
  11. package/dist/cloud/index.mjs +1 -1
  12. package/dist/{cloud-Cj1TIme8.mjs → cloud-jnk1hPYf.mjs} +2 -2
  13. package/dist/{cloud-Cj1TIme8.mjs.map → cloud-jnk1hPYf.mjs.map} +1 -1
  14. package/dist/components/index.d.mts +13 -13
  15. package/dist/components/index.mjs +43 -43
  16. package/dist/{dist-Kbf-JTry.mjs → dist-BtI6ukB5.mjs} +2 -2
  17. package/dist/{dist-Kbf-JTry.mjs.map → dist-BtI6ukB5.mjs.map} +1 -1
  18. package/dist/{dist-CCrYOkcc.mjs → dist-COOpgG9G.mjs} +4 -3
  19. package/dist/{dist-CCrYOkcc.mjs.map → dist-COOpgG9G.mjs.map} +1 -1
  20. package/dist/{dist-DtPPPsZV.mjs → dist-XqlFM2a8.mjs} +14063 -5308
  21. package/dist/dist-XqlFM2a8.mjs.map +1 -0
  22. package/dist/{dist-CiTgmfUw.mjs → dist-f1zkl69f.mjs} +4 -4
  23. package/dist/dist-f1zkl69f.mjs.map +1 -0
  24. package/dist/{dist-B_rSWeOz.mjs → dist-umQOWz0a.mjs} +1 -1
  25. package/dist/effects/index.d.mts +5 -5
  26. package/dist/effects/index.mjs +35 -35
  27. package/dist/{effects-B-L3rLs6.mjs → effects-DlRMovU5.mjs} +2 -2
  28. package/dist/{effects-B-L3rLs6.mjs.map → effects-DlRMovU5.mjs.map} +1 -1
  29. package/dist/fonts/index.d.mts +1 -1
  30. package/dist/fonts/index.mjs +2 -2
  31. package/dist/{fonts-k5ll8NTE.mjs → fonts-BWYcXjyK.mjs} +3 -3
  32. package/dist/fonts-BWYcXjyK.mjs.map +1 -0
  33. package/dist/{gpu-D2HT3KcE.mjs → gpu-CH1PdM4T.mjs} +2 -2
  34. package/dist/{gpu-D2HT3KcE.mjs.map → gpu-CH1PdM4T.mjs.map} +1 -1
  35. package/dist/{index-rtCXNxGO.d.mts → index-BHTycml5.d.mts} +2 -2
  36. package/dist/{index-rtCXNxGO.d.mts.map → index-BHTycml5.d.mts.map} +1 -1
  37. package/dist/{index-BFTtXosj.d.mts → index-BVd6nXd5.d.mts} +2 -2
  38. package/dist/{index-BFTtXosj.d.mts.map → index-BVd6nXd5.d.mts.map} +1 -1
  39. package/dist/{index-ByhlTwxh.d.mts → index-BcxxxwhV.d.mts} +5 -5
  40. package/dist/{index-ByhlTwxh.d.mts.map → index-BcxxxwhV.d.mts.map} +1 -1
  41. package/dist/{index-CnZhBlob.d.mts → index-BnB_Ou2y.d.mts} +2 -2
  42. package/dist/index-BnB_Ou2y.d.mts.map +1 -0
  43. package/dist/{index-a6JrbAK0.d.mts → index-C-V6CAhP.d.mts} +32 -2
  44. package/dist/index-C-V6CAhP.d.mts.map +1 -0
  45. package/dist/{index-DBh3WphX.d.mts → index-CMhkkc56.d.mts} +44 -12
  46. package/dist/index-CMhkkc56.d.mts.map +1 -0
  47. package/dist/{index-BGlaws7-.d.mts → index-CYVpYGM-.d.mts} +3 -3
  48. package/dist/{index-BGlaws7-.d.mts.map → index-CYVpYGM-.d.mts.map} +1 -1
  49. package/dist/{index-DQ1U3HC3.d.mts → index-DhL7ckvs.d.mts} +7 -7
  50. package/dist/index-DhL7ckvs.d.mts.map +1 -0
  51. package/dist/{index-CtKUQ2VG.d.mts → index-DkAjKnhW.d.mts} +1487 -533
  52. package/dist/index-DkAjKnhW.d.mts.map +1 -0
  53. package/dist/{index-B08eSpaI.d.mts → index-RILu3ULT.d.mts} +2 -2
  54. package/dist/{index-B08eSpaI.d.mts.map → index-RILu3ULT.d.mts.map} +1 -1
  55. package/dist/{index-C5sgRLlG.d.mts → index-TCtdSXd7.d.mts} +3 -1
  56. package/dist/index-TCtdSXd7.d.mts.map +1 -0
  57. package/dist/{index-C2yaponf.d.mts → index-s2qQ8ifZ.d.mts} +911 -57
  58. package/dist/index-s2qQ8ifZ.d.mts.map +1 -0
  59. package/dist/index.d.mts +15 -15
  60. package/dist/index.mjs +52 -52
  61. package/dist/preview/index.d.mts +5 -5
  62. package/dist/preview/index.mjs +10 -10
  63. package/dist/preview-BeGF1Bb1.mjs +1002 -0
  64. package/dist/preview-BeGF1Bb1.mjs.map +1 -0
  65. package/dist/preview-engine/audio.mjs +1 -1
  66. package/dist/preview-engine/{chunk-64L4GUOF.mjs → chunk-4F3DG6YB.mjs} +2 -2
  67. package/dist/preview-engine/chunk-A2OTOW3B.mjs +4694 -0
  68. package/dist/preview-engine/chunk-BR56TQBP.mjs +5 -0
  69. package/dist/preview-engine/{chunk-ADLIF544.mjs → chunk-H2XKXXAU.mjs} +1 -1
  70. package/dist/preview-engine/chunk-NDUODAY2.mjs +3 -0
  71. package/dist/preview-engine/{chunk-FZ4RD7HV.mjs → chunk-QAQJSWUT.mjs} +1 -1
  72. package/dist/preview-engine/chunk-SWRGQTVC.mjs +138 -0
  73. package/dist/preview-engine/{chunk-52X7SURQ.mjs → chunk-TEA3GVBJ.mjs} +1 -1
  74. package/dist/preview-engine/chunk-VM2ZBPLM.mjs +644 -0
  75. package/dist/preview-engine/{chunk-UBY2UYEL.mjs → chunk-XSHNQJ7L.mjs} +1 -1
  76. package/dist/preview-engine/components.mjs +1 -1
  77. package/dist/preview-engine/effects.mjs +1 -1
  78. package/dist/preview-engine/fonts.mjs +1 -1
  79. package/dist/preview-engine/framefields.mjs +1 -1
  80. package/dist/preview-engine/player.mjs +2 -2
  81. package/dist/preview-engine/{renderers-DU7KPFVV.mjs → renderers-6C7NWWDX.mjs} +1 -1
  82. package/dist/preview-engine/renderers-HHVGNMSJ.mjs +206 -0
  83. package/dist/preview-engine/{src-YXNX4MLK.mjs → src-RCNEKIRP.mjs} +1 -1
  84. package/dist/preview-page/index.html +19 -0
  85. package/dist/preview-page/main.css +1 -0
  86. package/dist/preview-page/main.js +327 -0
  87. package/dist/{program-BfiB9ttP.mjs → program-CMigyfso.mjs} +919 -58
  88. package/dist/program-CMigyfso.mjs.map +1 -0
  89. package/dist/renderer/index.d.mts +4 -4
  90. package/dist/renderer/index.mjs +2 -2
  91. package/dist/{renderer-CoC64eam.mjs → renderer-0GMEL_Zi.mjs} +3 -3
  92. package/dist/{renderer-CoC64eam.mjs.map → renderer-0GMEL_Zi.mjs.map} +1 -1
  93. package/dist/{renderer-CSu_vYPn.mjs → renderer-3Wv2ZBJG.mjs} +3 -3
  94. package/dist/{renderer-CSu_vYPn.mjs.map → renderer-3Wv2ZBJG.mjs.map} +1 -1
  95. package/dist/{renderer-Dv_iRIyx.mjs → renderer-4nXkaAWu.mjs} +1280 -285
  96. package/dist/renderer-4nXkaAWu.mjs.map +1 -0
  97. package/dist/{renderer-TfeohPxt.mjs → renderer-6SnfLXeg.mjs} +3 -3
  98. package/dist/{renderer-TfeohPxt.mjs.map → renderer-6SnfLXeg.mjs.map} +1 -1
  99. package/dist/{renderer-D0xM67cK.mjs → renderer-8gHw3O0P.mjs} +2 -2
  100. package/dist/{renderer-D0xM67cK.mjs.map → renderer-8gHw3O0P.mjs.map} +1 -1
  101. package/dist/{renderer-C64_B8It.mjs → renderer-AOBglZHC.mjs} +2 -2
  102. package/dist/{renderer-B10HDC13.mjs → renderer-B0bSARK3.mjs} +3 -3
  103. package/dist/{renderer-B10HDC13.mjs.map → renderer-B0bSARK3.mjs.map} +1 -1
  104. package/dist/{renderer-DWYmJSrl.mjs → renderer-B2_tuRfl.mjs} +2 -2
  105. package/dist/{renderer-DWYmJSrl.mjs.map → renderer-B2_tuRfl.mjs.map} +1 -1
  106. package/dist/{renderer-mDBoz0zT.mjs → renderer-B82FhkEr.mjs} +3 -3
  107. package/dist/{renderer-mDBoz0zT.mjs.map → renderer-B82FhkEr.mjs.map} +1 -1
  108. package/dist/{renderer-DYeNNc_G.mjs → renderer-B9lzA0PY.mjs} +3 -3
  109. package/dist/{renderer-DYeNNc_G.mjs.map → renderer-B9lzA0PY.mjs.map} +1 -1
  110. package/dist/{renderer-BGchUBW_.mjs → renderer-BBSIWSry.mjs} +2 -2
  111. package/dist/{renderer-BGchUBW_.mjs.map → renderer-BBSIWSry.mjs.map} +1 -1
  112. package/dist/{renderer-GIlQ9lZq.mjs → renderer-BEKDMxbi.mjs} +2 -2
  113. package/dist/{renderer-GIlQ9lZq.mjs.map → renderer-BEKDMxbi.mjs.map} +1 -1
  114. package/dist/renderer-BERGAxqA.mjs +5 -0
  115. package/dist/{renderer-Bw0O--gW.mjs → renderer-BF960HY8.mjs} +3 -3
  116. package/dist/{renderer-Bw0O--gW.mjs.map → renderer-BF960HY8.mjs.map} +1 -1
  117. package/dist/{renderer-BhcTYhaP.mjs → renderer-BFwyVxCu.mjs} +3 -3
  118. package/dist/{renderer-BhcTYhaP.mjs.map → renderer-BFwyVxCu.mjs.map} +1 -1
  119. package/dist/{renderer-DYlx7VHo.mjs → renderer-BNiwcI3-.mjs} +2 -2
  120. package/dist/{renderer-DYlx7VHo.mjs.map → renderer-BNiwcI3-.mjs.map} +1 -1
  121. package/dist/{renderer-B3_GddgJ.mjs → renderer-BPbVb2Q4.mjs} +2 -2
  122. package/dist/{renderer-B3_GddgJ.mjs.map → renderer-BPbVb2Q4.mjs.map} +1 -1
  123. package/dist/renderer-BQ_YkBMt.mjs +6 -0
  124. package/dist/{renderer-Y1kjtOto.mjs → renderer-BUWxlA8T.mjs} +3 -3
  125. package/dist/{renderer-Y1kjtOto.mjs.map → renderer-BUWxlA8T.mjs.map} +1 -1
  126. package/dist/renderer-BW0Tjsv9.mjs +5 -0
  127. package/dist/{renderer-DtFZbE1j.mjs → renderer-BX8liu-e.mjs} +2 -2
  128. package/dist/{renderer-BOlHW3Mi.mjs → renderer-BXIwDAr_.mjs} +2 -2
  129. package/dist/{renderer-BOlHW3Mi.mjs.map → renderer-BXIwDAr_.mjs.map} +1 -1
  130. package/dist/{renderer-DzON3wDZ.mjs → renderer-B_Hy1W-g.mjs} +3 -3
  131. package/dist/{renderer-DzON3wDZ.mjs.map → renderer-B_Hy1W-g.mjs.map} +1 -1
  132. package/dist/{renderer-BM19iK8v.mjs → renderer-Bb6cvSgh.mjs} +2 -2
  133. package/dist/{renderer-BM19iK8v.mjs.map → renderer-Bb6cvSgh.mjs.map} +1 -1
  134. package/dist/{renderer-D0h1hTOo.mjs → renderer-BdppwWC9.mjs} +2 -2
  135. package/dist/{renderer-D0h1hTOo.mjs.map → renderer-BdppwWC9.mjs.map} +1 -1
  136. package/dist/{renderer-BTwuM9u-.mjs → renderer-Bhc24HVe.mjs} +3 -3
  137. package/dist/{renderer-BTwuM9u-.mjs.map → renderer-Bhc24HVe.mjs.map} +1 -1
  138. package/dist/{renderer-BZX932Lj.mjs → renderer-BiNA2wF0.mjs} +2 -2
  139. package/dist/{renderer-BZX932Lj.mjs.map → renderer-BiNA2wF0.mjs.map} +1 -1
  140. package/dist/{renderer-CkTehyRX.mjs → renderer-BmoBgTp5.mjs} +3 -3
  141. package/dist/{renderer-CkTehyRX.mjs.map → renderer-BmoBgTp5.mjs.map} +1 -1
  142. package/dist/{renderer-B3un4Pdi.mjs → renderer-BmqFmCWS.mjs} +3 -3
  143. package/dist/{renderer-B3un4Pdi.mjs.map → renderer-BmqFmCWS.mjs.map} +1 -1
  144. package/dist/{renderer-CHCRcCKw.mjs → renderer-BnVwAObV.mjs} +2 -2
  145. package/dist/{renderer-CHCRcCKw.mjs.map → renderer-BnVwAObV.mjs.map} +1 -1
  146. package/dist/{renderer-Cv9CKKWG.mjs → renderer-BxttZHme.mjs} +2 -2
  147. package/dist/{renderer-Cv9CKKWG.mjs.map → renderer-BxttZHme.mjs.map} +1 -1
  148. package/dist/renderer-BzyPdUD1.mjs +5 -0
  149. package/dist/renderer-C0hM-mtY.mjs +5 -0
  150. package/dist/renderer-C6cyUTvk.mjs +5 -0
  151. package/dist/{renderer-B6bK9rXm.mjs → renderer-C8E4XsSg.mjs} +2 -2
  152. package/dist/{renderer-B6bK9rXm.mjs.map → renderer-C8E4XsSg.mjs.map} +1 -1
  153. package/dist/renderer-C8zY3pzk.mjs +5 -0
  154. package/dist/{renderer-4nsuReW2.mjs → renderer-C9U-LY50.mjs} +3 -3
  155. package/dist/{renderer-4nsuReW2.mjs.map → renderer-C9U-LY50.mjs.map} +1 -1
  156. package/dist/{renderer-BvBqTAtk.mjs → renderer-CB2JVu5x.mjs} +3 -3
  157. package/dist/{renderer-BvBqTAtk.mjs.map → renderer-CB2JVu5x.mjs.map} +1 -1
  158. package/dist/{renderer-CQ4h8n7p.mjs → renderer-CC4YBJ8Z.mjs} +3 -3
  159. package/dist/{renderer-CQ4h8n7p.mjs.map → renderer-CC4YBJ8Z.mjs.map} +1 -1
  160. package/dist/renderer-CEkSOyKu.mjs +5 -0
  161. package/dist/{renderer-zLi2qFGT.mjs → renderer-CIycc5O-.mjs} +2 -2
  162. package/dist/{renderer-zLi2qFGT.mjs.map → renderer-CIycc5O-.mjs.map} +1 -1
  163. package/dist/renderer-CJYtfa4x.mjs +5 -0
  164. package/dist/{renderer-yNWYqvvq.mjs → renderer-CJraQlV-.mjs} +2 -2
  165. package/dist/{renderer-yNWYqvvq.mjs.map → renderer-CJraQlV-.mjs.map} +1 -1
  166. package/dist/renderer-CKMtHGZh.mjs +5 -0
  167. package/dist/renderer-CLzicoiy.mjs +5 -0
  168. package/dist/renderer-CM2A4BHd.mjs +5 -0
  169. package/dist/{renderer-BrEeUw7T.mjs → renderer-COWGWtob.mjs} +2 -2
  170. package/dist/{renderer-BrEeUw7T.mjs.map → renderer-COWGWtob.mjs.map} +1 -1
  171. package/dist/{renderer-uER8kn7f.mjs → renderer-COxG2XGf.mjs} +2 -2
  172. package/dist/{renderer-uER8kn7f.mjs.map → renderer-COxG2XGf.mjs.map} +1 -1
  173. package/dist/{renderer-C4hd6Cqi.mjs → renderer-CQDCIsQm.mjs} +2 -2
  174. package/dist/{renderer-C4hd6Cqi.mjs.map → renderer-CQDCIsQm.mjs.map} +1 -1
  175. package/dist/{renderer-Cfx_FCSf.mjs → renderer-CRUeag8i.mjs} +3 -3
  176. package/dist/{renderer-Cfx_FCSf.mjs.map → renderer-CRUeag8i.mjs.map} +1 -1
  177. package/dist/{renderer-CXrnzihz.mjs → renderer-CWVput06.mjs} +3 -3
  178. package/dist/{renderer-CXrnzihz.mjs.map → renderer-CWVput06.mjs.map} +1 -1
  179. package/dist/renderer-CZlHjcxr.mjs +5 -0
  180. package/dist/{renderer-BmyFfvVA.mjs → renderer-CbbnBLOB.mjs} +3 -3
  181. package/dist/{renderer-BmyFfvVA.mjs.map → renderer-CbbnBLOB.mjs.map} +1 -1
  182. package/dist/renderer-CbimvSU8.mjs +5 -0
  183. package/dist/renderer-Ccvc63yd.mjs +5 -0
  184. package/dist/renderer-Cdp-SGfq.mjs +5 -0
  185. package/dist/renderer-CeTcSs3e.mjs +5 -0
  186. package/dist/{renderer-_J9JcCMR.mjs → renderer-CfLZein2.mjs} +3 -3
  187. package/dist/{renderer-_J9JcCMR.mjs.map → renderer-CfLZein2.mjs.map} +1 -1
  188. package/dist/{renderer-D-mX1EVA.mjs → renderer-Ch-q1O-q.mjs} +3 -3
  189. package/dist/{renderer-D-mX1EVA.mjs.map → renderer-Ch-q1O-q.mjs.map} +1 -1
  190. package/dist/{renderer-uzU6dsdR.mjs → renderer-Ch5JvJWl.mjs} +2 -2
  191. package/dist/{renderer-uzU6dsdR.mjs.map → renderer-Ch5JvJWl.mjs.map} +1 -1
  192. package/dist/{renderer-BZMh2io2.mjs → renderer-ChtEzq-R.mjs} +2 -2
  193. package/dist/{renderer-BZMh2io2.mjs.map → renderer-ChtEzq-R.mjs.map} +1 -1
  194. package/dist/{renderer-B2IUPjhw.mjs → renderer-Cj9nTC5l.mjs} +3 -3
  195. package/dist/{renderer-B2IUPjhw.mjs.map → renderer-Cj9nTC5l.mjs.map} +1 -1
  196. package/dist/{renderer-CdXBRdFf.mjs → renderer-CqT8HsSS.mjs} +2 -2
  197. package/dist/{renderer-CdXBRdFf.mjs.map → renderer-CqT8HsSS.mjs.map} +1 -1
  198. package/dist/{renderer-CldjJmRR.mjs → renderer-CuQjMhdV.mjs} +2 -2
  199. package/dist/renderer-CvNuu52U.mjs +5 -0
  200. package/dist/renderer-CwciC0oI.mjs +5 -0
  201. package/dist/renderer-CysLUbIr.mjs +5 -0
  202. package/dist/{renderer-BsrKj6Td.mjs → renderer-Cz30EVws.mjs} +2 -2
  203. package/dist/{renderer-BsrKj6Td.mjs.map → renderer-Cz30EVws.mjs.map} +1 -1
  204. package/dist/renderer-D3A22Vxb.mjs +5 -0
  205. package/dist/renderer-D5SY9EmA.mjs +5 -0
  206. package/dist/renderer-D8h3ZvaE.mjs +5 -0
  207. package/dist/renderer-DE-B6N9n.mjs +5 -0
  208. package/dist/renderer-DETZTI7t.mjs +5 -0
  209. package/dist/{renderer-CC22Djgi.mjs → renderer-DHoX-5U_.mjs} +3 -3
  210. package/dist/{renderer-CC22Djgi.mjs.map → renderer-DHoX-5U_.mjs.map} +1 -1
  211. package/dist/{renderer-HKv5cBdp.mjs → renderer-DOkm0Ycd.mjs} +2 -2
  212. package/dist/{renderer-HKv5cBdp.mjs.map → renderer-DOkm0Ycd.mjs.map} +1 -1
  213. package/dist/{renderer-fG8Jy8Rx.d.mts → renderer-DU3f6ZrS.d.mts} +2 -2
  214. package/dist/{renderer-fG8Jy8Rx.d.mts.map → renderer-DU3f6ZrS.d.mts.map} +1 -1
  215. package/dist/{renderer-C98XwEIr.mjs → renderer-DUzv-shq.mjs} +2 -2
  216. package/dist/{renderer-C98XwEIr.mjs.map → renderer-DUzv-shq.mjs.map} +1 -1
  217. package/dist/renderer-DWnDj0IM.mjs +5 -0
  218. package/dist/renderer-DcGUIbQF.mjs +5 -0
  219. package/dist/renderer-Dfq6FoNO.mjs +5 -0
  220. package/dist/renderer-DhasXW6S.mjs +3 -0
  221. package/dist/{renderer-BEuXJY-C.mjs → renderer-DhnOWnEA.mjs} +3 -3
  222. package/dist/{renderer-BEuXJY-C.mjs.map → renderer-DhnOWnEA.mjs.map} +1 -1
  223. package/dist/{renderer-BIKkxw_Z.mjs → renderer-Dhy1XHzz.mjs} +3 -3
  224. package/dist/{renderer-BIKkxw_Z.mjs.map → renderer-Dhy1XHzz.mjs.map} +1 -1
  225. package/dist/renderer-DjCvpsV_.mjs +5 -0
  226. package/dist/{renderer-pn52dzZz.mjs → renderer-DjJshz9Y.mjs} +2 -2
  227. package/dist/{renderer-pn52dzZz.mjs.map → renderer-DjJshz9Y.mjs.map} +1 -1
  228. package/dist/{renderer-DhGZ41hQ.mjs → renderer-DmTUIdus.mjs} +3 -3
  229. package/dist/{renderer-DhGZ41hQ.mjs.map → renderer-DmTUIdus.mjs.map} +1 -1
  230. package/dist/{renderer-D_m6Qbsi.mjs → renderer-Dq7AioJa.mjs} +2 -2
  231. package/dist/{renderer-D_m6Qbsi.mjs.map → renderer-Dq7AioJa.mjs.map} +1 -1
  232. package/dist/renderer-DrAaM6JD.mjs +5 -0
  233. package/dist/{renderer-D-GWBoVT.mjs → renderer-Dt4sqNEu.mjs} +2 -2
  234. package/dist/{renderer-D-GWBoVT.mjs.map → renderer-Dt4sqNEu.mjs.map} +1 -1
  235. package/dist/{renderer-DCrKEVjb.mjs → renderer-Dtcs4idV.mjs} +3 -3
  236. package/dist/{renderer-DCrKEVjb.mjs.map → renderer-Dtcs4idV.mjs.map} +1 -1
  237. package/dist/renderer-Dxlv8LYm.mjs +5 -0
  238. package/dist/{renderer-CO9vE3sd.mjs → renderer-Gj8SrE2W.mjs} +2 -2
  239. package/dist/{renderer-CO9vE3sd.mjs.map → renderer-Gj8SrE2W.mjs.map} +1 -1
  240. package/dist/{renderer-DvHi_wXE.mjs → renderer-KfnXDJS0.mjs} +3 -3
  241. package/dist/{renderer-DvHi_wXE.mjs.map → renderer-KfnXDJS0.mjs.map} +1 -1
  242. package/dist/{renderer-7xQmXXMH.mjs → renderer-MXVlg4p5.mjs} +3 -3
  243. package/dist/{renderer-7xQmXXMH.mjs.map → renderer-MXVlg4p5.mjs.map} +1 -1
  244. package/dist/{renderer-YONlI6W-.mjs → renderer-N2b6QZ1E.mjs} +3 -3
  245. package/dist/{renderer-YONlI6W-.mjs.map → renderer-N2b6QZ1E.mjs.map} +1 -1
  246. package/dist/renderer-Pb43OO2t.mjs +5 -0
  247. package/dist/{renderer-DNynPM6X.mjs → renderer-Q7gDzm8c.mjs} +2 -2
  248. package/dist/{renderer-DNynPM6X.mjs.map → renderer-Q7gDzm8c.mjs.map} +1 -1
  249. package/dist/{renderer-BEhZiOT4.mjs → renderer-RCiANtRV.mjs} +2 -2
  250. package/dist/{renderer-BEhZiOT4.mjs.map → renderer-RCiANtRV.mjs.map} +1 -1
  251. package/dist/{renderer-Dm57W73p.mjs → renderer-Sig9nZcI.mjs} +2 -2
  252. package/dist/renderer-VQbm-cGr.mjs +5 -0
  253. package/dist/{renderer-DiZkZ0Pr.mjs → renderer-fabBgwQX.mjs} +3 -3
  254. package/dist/{renderer-DiZkZ0Pr.mjs.map → renderer-fabBgwQX.mjs.map} +1 -1
  255. package/dist/{renderer-Bw-_GZVw.mjs → renderer-g-0PCNoo.mjs} +3 -3
  256. package/dist/{renderer-Bw-_GZVw.mjs.map → renderer-g-0PCNoo.mjs.map} +1 -1
  257. package/dist/{renderer-QbSrnPZU.mjs → renderer-gmHKIbKI.mjs} +3 -3
  258. package/dist/{renderer-QbSrnPZU.mjs.map → renderer-gmHKIbKI.mjs.map} +1 -1
  259. package/dist/{renderer-CU6WT5jW.mjs → renderer-kVZwiRoK.mjs} +3 -3
  260. package/dist/{renderer-CU6WT5jW.mjs.map → renderer-kVZwiRoK.mjs.map} +1 -1
  261. package/dist/renderer-oPMypDM1.mjs +5 -0
  262. package/dist/{renderer-CRhEGqW4.mjs → renderer-p7tgxP-A.mjs} +3 -3
  263. package/dist/{renderer-CRhEGqW4.mjs.map → renderer-p7tgxP-A.mjs.map} +1 -1
  264. package/dist/{renderer-CO4NGvAh.mjs → renderer-tvYj306A.mjs} +81 -78
  265. package/dist/renderer-tvYj306A.mjs.map +1 -0
  266. package/dist/renderer-xvWGpVyp.mjs +5 -0
  267. package/dist/renderer-zafZbD6Q.mjs +5 -0
  268. package/dist/{renderers-CP8CFWDs-BufiCyn7.mjs → renderers-CP8CFWDs-DLjtjrwx.mjs} +2 -2
  269. package/dist/{renderers-CP8CFWDs-BufiCyn7.mjs.map → renderers-CP8CFWDs-DLjtjrwx.mjs.map} +1 -1
  270. package/dist/sam/index.d.mts +3 -3
  271. package/dist/sam/index.mjs +1 -1
  272. package/dist/signals/index.d.mts +5 -5
  273. package/dist/signals/index.mjs +4 -4
  274. package/dist/{src-BU6vm9sP-DdTHmCr4.mjs → src-B23p_eh7-Cj6-lvV6.mjs} +293 -6
  275. package/dist/src-B23p_eh7-Cj6-lvV6.mjs.map +1 -0
  276. package/dist/{src-DrP7fGJX.mjs → src-CoHAjviq.mjs} +1355 -178
  277. package/dist/src-CoHAjviq.mjs.map +1 -0
  278. package/dist/storage/index.mjs +1 -1
  279. package/package.json +63 -60
  280. package/dist/dist-CiTgmfUw.mjs.map +0 -1
  281. package/dist/dist-DtPPPsZV.mjs.map +0 -1
  282. package/dist/fonts-k5ll8NTE.mjs.map +0 -1
  283. package/dist/index-C2yaponf.d.mts.map +0 -1
  284. package/dist/index-C5sgRLlG.d.mts.map +0 -1
  285. package/dist/index-CnZhBlob.d.mts.map +0 -1
  286. package/dist/index-CtKUQ2VG.d.mts.map +0 -1
  287. package/dist/index-DBh3WphX.d.mts.map +0 -1
  288. package/dist/index-DQ1U3HC3.d.mts.map +0 -1
  289. package/dist/index-a6JrbAK0.d.mts.map +0 -1
  290. package/dist/preview-engine/chunk-5ZS46EFB.mjs +0 -5
  291. package/dist/preview-engine/chunk-N3XTDAL6.mjs +0 -2227
  292. package/dist/preview-engine/chunk-NCQHOGZK.mjs +0 -3
  293. package/dist/preview-engine/chunk-PH3UUX6A.mjs +0 -138
  294. package/dist/preview-engine/chunk-XCPRRMMW.mjs +0 -2462
  295. package/dist/preview-engine/renderers-ZMMQ7S2A.mjs +0 -228
  296. package/dist/preview-lHH8Tv4j.mjs +0 -2446
  297. package/dist/preview-lHH8Tv4j.mjs.map +0 -1
  298. package/dist/program-BfiB9ttP.mjs.map +0 -1
  299. package/dist/renderer-0rLmztAv.mjs +0 -5
  300. package/dist/renderer-B0pjOXFY.mjs +0 -5
  301. package/dist/renderer-B7J13reL.mjs +0 -5
  302. package/dist/renderer-BPGIKGgl.mjs +0 -5
  303. package/dist/renderer-Bv-Artj1.mjs +0 -5
  304. package/dist/renderer-BvLjbhcL.mjs +0 -5
  305. package/dist/renderer-By6awWaf.mjs +0 -5
  306. package/dist/renderer-C0rvsz7m.mjs +0 -5
  307. package/dist/renderer-CDgud_HB.mjs +0 -5
  308. package/dist/renderer-CDiRF3bG.mjs +0 -6
  309. package/dist/renderer-CIIEQd4B.mjs +0 -5
  310. package/dist/renderer-CJblwOA9.mjs +0 -5
  311. package/dist/renderer-CNMOXtXE.mjs +0 -5
  312. package/dist/renderer-CO4NGvAh.mjs.map +0 -1
  313. package/dist/renderer-COeSeNGg.mjs +0 -5
  314. package/dist/renderer-CUfElmtZ.mjs +0 -5
  315. package/dist/renderer-CYh2lFoJ.mjs +0 -5
  316. package/dist/renderer-CYtVZYMH.mjs +0 -5
  317. package/dist/renderer-CjxZlkjb.mjs +0 -5
  318. package/dist/renderer-Cpd6TvTC.mjs +0 -5
  319. package/dist/renderer-D3ziOPhX.mjs +0 -5
  320. package/dist/renderer-D5yp74NL.mjs +0 -3
  321. package/dist/renderer-DL-phtL5.mjs +0 -5
  322. package/dist/renderer-DSnmYnHg.mjs +0 -5
  323. package/dist/renderer-DUGfsT-E.mjs +0 -5
  324. package/dist/renderer-DW5af9x1.mjs +0 -5
  325. package/dist/renderer-DYMrol1t.mjs +0 -5
  326. package/dist/renderer-DekeUHaz.mjs +0 -5
  327. package/dist/renderer-Dt5uyJdZ.mjs +0 -5
  328. package/dist/renderer-Dv_iRIyx.mjs.map +0 -1
  329. package/dist/renderer-DwLQAnaK.mjs +0 -5
  330. package/dist/renderer-IXQP2CWM.mjs +0 -5
  331. package/dist/renderer-K-Pkw63O.mjs +0 -5
  332. package/dist/renderer-MPw2KH9P.mjs +0 -5
  333. package/dist/renderer-RPu8RMav.mjs +0 -5
  334. package/dist/renderer-dCqxd5N2.mjs +0 -5
  335. package/dist/renderer-lhjmE-Fp.mjs +0 -5
  336. package/dist/renderer-u9cmBuvM.mjs +0 -5
  337. package/dist/renderer-vH12jcpz.mjs +0 -5
  338. package/dist/src-BU6vm9sP-DdTHmCr4.mjs.map +0 -1
  339. package/dist/src-DrP7fGJX.mjs.map +0 -1
@@ -1,12 +1,12 @@
1
1
  import { G as ProgrammaticSignal, K as Signal, Mt as frameArraySignal, N as MediaSignalRecorder, St as createVirtualMedia, pt as appendOperation, rn as mediaSourceTime, tn as mediaSourceRange, y as Effect$1, yn as resolveFrameRequest } from "./dist-C8XSqfTx.mjs";
2
- import { F as getPrimitiveGeometry, K as mediaDecoderCache, N as generateExtrudedTextGeometry, Q as parseSvgPathToSegments, _ as buildShapeSvgPath, bt as Path3D, p as SlugFontCache, q as parseColor$1, z as inputStore } from "./dist-DtPPPsZV.mjs";
3
- import { n as decodeAudioSource, o as preflightMediaTime } from "./dist-CCrYOkcc.mjs";
4
- import { t as FontManager } from "./fonts-k5ll8NTE.mjs";
2
+ import { B as fractureModel, C as buildShapeSvgPath, D as createTerrainSampler, Lt as Matrix4Math, Rt as Path3D, U as getPrimitiveGeometry, Ut as createRandom, V as generateExtrudedTextGeometry, et as mediaDecoderCache, ht as scatterOnSurface, m as SlugFontCache, ot as parseSvgPathToSegments, q as inputStore, tt as parseColor$1, xt as terrainSegments } from "./dist-XqlFM2a8.mjs";
3
+ import { n as decodeAudioSource, o as preflightMediaTime } from "./dist-COOpgG9G.mjs";
4
+ import { t as FontManager } from "./fonts-BWYcXjyK.mjs";
5
5
  import { s as TensorPipeline } from "./dist-DgZpN6IK.mjs";
6
- import { E as pinNodeToObject, S as maskObject, T as pinNodeToLandmark, d as VisionNode, f as VisionRunner, i as COCO17_KEYPOINT_NAMES, l as VisionBundle, p as analyzeSequence, t as CLIP_SUBJECT, w as mergeSubjectMask } from "./src-BU6vm9sP-DdTHmCr4.mjs";
7
- import { G as mediaSignalSampler, K as mergeAnimationTracks, N as collectNodeOps, P as compositorToProgram, W as lintComposition, f as LayerAnimation, q as sampleMediaTimeSignal } from "./program-BfiB9ttP.mjs";
8
- import { C as effectFactories, H as Dither, I as ColorBalance, K as Iridescence, L as ColorKey, M as CRT, R as Contour, S as Vision, T as Ascii, Y as LayerStyle, _ as SelectiveColor, a as CustomEffect, at as Posterize, b as TileOffset, c as GradientMap, d as Levels, et as OpArt, f as Modulate, g as SSAO, h as Relight3D, ht as Vignette, i as Curves, it as Pixelate, l as HalftoneScreen, m as PBRGlass, nt as Painterly, o as DepthOfField, ot as ProceduralVFX, p as MotionBlur, pt as Toon, q as Kaleidoscope, r as Crop, s as FilmGrain, st as RGBSplit, t as ApplyLUT, u as HighPass, v as ShadowsHighlights, w as Blur, x as UnsharpMask, y as TemporalDeflicker } from "./effects-B-L3rLs6.mjs";
9
- import { n as renderFrameGrid, s as HeadlessMediaRenderer } from "./renderer-CO4NGvAh.mjs";
6
+ import { C as maskObject, D as pinNodeToObject, E as pinNodeToLandmark, T as mergeSubjectMask, d as VisionNode, f as VisionRunner, g as defaultMatteBand, i as COCO17_KEYPOINT_NAMES, l as VisionBundle, p as analyzeSequence, t as CLIP_SUBJECT } from "./src-B23p_eh7-Cj6-lvV6.mjs";
7
+ import { $ as mergeAnimationTracks, Q as mediaSignalSampler, V as compositorToProgram, X as lintComposition, _ as LayerAnimation, et as numberAt, nt as sampleMediaTimeSignal, tt as sampleLayerProp, z as collectLayersOnClock } from "./program-CMigyfso.mjs";
8
+ import { C as effectFactories, H as Dither, I as ColorBalance, K as Iridescence, L as ColorKey, M as CRT, R as Contour, S as Vision, T as Ascii, Y as LayerStyle, _ as SelectiveColor, a as CustomEffect, at as Posterize, b as TileOffset, c as GradientMap, d as Levels, et as OpArt, f as Modulate, g as SSAO, h as Relight3D, ht as Vignette, i as Curves, it as Pixelate, l as HalftoneScreen, m as PBRGlass, nt as Painterly, o as DepthOfField, ot as ProceduralVFX, p as MotionBlur, pt as Toon, q as Kaleidoscope, r as Crop, s as FilmGrain, st as RGBSplit, t as ApplyLUT, u as HighPass, v as ShadowsHighlights, w as Blur, x as UnsharpMask, y as TemporalDeflicker } from "./effects-DlRMovU5.mjs";
9
+ import { n as renderFrameGrid, s as HeadlessMediaRenderer } from "./renderer-tvYj306A.mjs";
10
10
  import { z, z as z$2 } from "zod";
11
11
  import path from "node:path";
12
12
  import fs from "node:fs/promises";
@@ -223,7 +223,7 @@ const sleep = (ms, signal) => new Promise((resolve$1, reject) => {
223
223
  }, { once: true });
224
224
  });
225
225
  /** Reads (status, result) are free and idempotent, so transient failures are retried. */
226
- async function read(run$1, signal) {
226
+ async function read$1(run$1, signal) {
227
227
  for (let attempt = 1;; attempt++) try {
228
228
  return await run$1();
229
229
  } catch (err) {
@@ -242,7 +242,7 @@ async function submit(model, { input, abortSignal }) {
242
242
  return data;
243
243
  }
244
244
  function status(model, { requestId, logs, abortSignal }) {
245
- return read(async () => {
245
+ return read$1(async () => {
246
246
  const { data } = await gatewayJson({
247
247
  service: "queue",
248
248
  path: requestPath(model, requestId, "/status"),
@@ -253,7 +253,7 @@ function status(model, { requestId, logs, abortSignal }) {
253
253
  }, abortSignal);
254
254
  }
255
255
  function result(model, { requestId, abortSignal }) {
256
- return read(async () => {
256
+ return read$1(async () => {
257
257
  const { data } = await gatewayJson({
258
258
  service: "queue",
259
259
  path: requestPath(model, requestId),
@@ -610,8 +610,8 @@ function parseMarkup(markup) {
610
610
  } else if (tagName === "accent") style.fill = "#6366f1";
611
611
  else if (tagName === "color") style.fill = attrs.value ?? attrs.hex ?? attrs.fill;
612
612
  else if (tagName === "size") {
613
- const num$4 = parseFloat(attrs.value ?? attrs.px ?? attrs.pt ?? "0");
614
- if (num$4 > 0) style.fontSize = num$4;
613
+ const num$5 = parseFloat(attrs.value ?? attrs.px ?? attrs.pt ?? "0");
614
+ if (num$5 > 0) style.fontSize = num$5;
615
615
  } else if (tagName === "mark") {
616
616
  style.mark = {
617
617
  background: attrs.bg ?? attrs.background ?? "#6366f133",
@@ -1332,12 +1332,170 @@ function translatePath(d, dx, dy) {
1332
1332
  return out.join("");
1333
1333
  }
1334
1334
 
1335
+ //#endregion
1336
+ //#region src/retarget.ts
1337
+ /**
1338
+ * Pose retargeting: a performer's 2D pose (vision keypoints, or any source
1339
+ * of named points) drives a 3D character's bones. Each bone is aimed along
1340
+ * its segment in the picture (shoulder → elbow, hip → knee, …), parents
1341
+ * first, so the character copies the performer's silhouette at its own
1342
+ * proportions. Aims run after clips and `pose`, before `lookAt` and `ik`,
1343
+ * so clips can carry what the camera can't see and IK can plant the feet.
1344
+ *
1345
+ * ```ts
1346
+ * const dancer = comp.vision("dance.mp4").person.place({ width: W, height: H });
1347
+ * Layer.glb("robot.glb", { aim: retargetPose(dancer, { rig: "mixamo" }) });
1348
+ * ```
1349
+ *
1350
+ * The picture has no depth: limbs swing in the plane facing the camera.
1351
+ */
1352
+ /** Joint names of common rigs. */
1353
+ const RIG_PRESETS = {
1354
+ mixamo: {
1355
+ spine: "Spine",
1356
+ neck: "Neck",
1357
+ leftUpperArm: "LeftArm",
1358
+ leftLowerArm: "LeftForeArm",
1359
+ rightUpperArm: "RightArm",
1360
+ rightLowerArm: "RightForeArm",
1361
+ leftUpperLeg: "LeftUpLeg",
1362
+ leftLowerLeg: "LeftLeg",
1363
+ rightUpperLeg: "RightUpLeg",
1364
+ rightLowerLeg: "RightLeg"
1365
+ },
1366
+ humanoid: {
1367
+ spine: "Spine",
1368
+ neck: "Neck",
1369
+ leftUpperArm: "LeftUpperArm",
1370
+ leftLowerArm: "LeftLowerArm",
1371
+ rightUpperArm: "RightUpperArm",
1372
+ rightLowerArm: "RightLowerArm",
1373
+ leftUpperLeg: "LeftUpperLeg",
1374
+ leftLowerLeg: "LeftLowerLeg",
1375
+ rightUpperLeg: "RightUpperLeg",
1376
+ rightLowerLeg: "RightLowerLeg"
1377
+ },
1378
+ rigify: {
1379
+ spine: "spine",
1380
+ neck: "neck",
1381
+ leftUpperArm: "upper_arm.L",
1382
+ leftLowerArm: "forearm.L",
1383
+ rightUpperArm: "upper_arm.R",
1384
+ rightLowerArm: "forearm.R",
1385
+ leftUpperLeg: "thigh.L",
1386
+ leftLowerLeg: "shin.L",
1387
+ rightUpperLeg: "thigh.R",
1388
+ rightLowerLeg: "shin.R"
1389
+ }
1390
+ };
1391
+ /** Each bone's segment in the picture, parents first. */
1392
+ const SEGMENTS = [
1393
+ [
1394
+ "spine",
1395
+ ["leftHip", "rightHip"],
1396
+ ["leftShoulder", "rightShoulder"]
1397
+ ],
1398
+ [
1399
+ "neck",
1400
+ ["leftShoulder", "rightShoulder"],
1401
+ "nose"
1402
+ ],
1403
+ [
1404
+ "leftUpperArm",
1405
+ "leftShoulder",
1406
+ "leftElbow"
1407
+ ],
1408
+ [
1409
+ "leftLowerArm",
1410
+ "leftElbow",
1411
+ "leftWrist"
1412
+ ],
1413
+ [
1414
+ "rightUpperArm",
1415
+ "rightShoulder",
1416
+ "rightElbow"
1417
+ ],
1418
+ [
1419
+ "rightLowerArm",
1420
+ "rightElbow",
1421
+ "rightWrist"
1422
+ ],
1423
+ [
1424
+ "leftUpperLeg",
1425
+ "leftHip",
1426
+ "leftKnee"
1427
+ ],
1428
+ [
1429
+ "leftLowerLeg",
1430
+ "leftKnee",
1431
+ "leftAnkle"
1432
+ ],
1433
+ [
1434
+ "rightUpperLeg",
1435
+ "rightHip",
1436
+ "rightKnee"
1437
+ ],
1438
+ [
1439
+ "rightLowerLeg",
1440
+ "rightKnee",
1441
+ "rightAnkle"
1442
+ ]
1443
+ ];
1444
+ const mirrored = (name) => name.startsWith("left") ? `right${name.slice(4)}` : name.startsWith("right") ? `left${name.slice(5)}` : name;
1445
+ /** A keypoint, or the midpoint of two, with the lesser visibility. */
1446
+ function read(source, p, frame, mirror) {
1447
+ const name = (n) => mirror ? mirrored(n) : n;
1448
+ if (typeof p === "string") return source.point(name(p), frame);
1449
+ const a = source.point(name(p[0]), frame);
1450
+ const b = source.point(name(p[1]), frame);
1451
+ return {
1452
+ x: (a.x + b.x) / 2,
1453
+ y: (a.y + b.y) / 2,
1454
+ visibility: Math.min(a.visibility, b.visibility)
1455
+ };
1456
+ }
1457
+ const smoothstep$1 = (lo, hi, v) => {
1458
+ const t = Math.min(1, Math.max(0, (v - lo) / (hi - lo)));
1459
+ return t * t * (3 - 2 * t);
1460
+ };
1461
+ /**
1462
+ * Aim constraints that make a character copy `source`'s pose: put them on
1463
+ * a glTF model's `aim`. Bones whose joints the rig map doesn't name, or
1464
+ * whose keypoints the vision isn't sure of, keep the animated pose.
1465
+ */
1466
+ function retargetPose(source, options = {}) {
1467
+ const rig$1 = typeof options.rig === "object" ? options.rig : RIG_PRESETS[options.rig ?? "mixamo"];
1468
+ const only = options.bones ? new Set(options.bones) : void 0;
1469
+ const mirror = options.mirror ?? false;
1470
+ const lo = options.minVisibility ?? .3;
1471
+ return SEGMENTS.filter(([bone]) => rig$1[bone] && (!only || only.has(bone))).map(([bone, from, to]) => ({
1472
+ joint: rig$1[bone],
1473
+ direction: (frame) => {
1474
+ const a = read(source, from, frame, mirror);
1475
+ const b = read(source, to, frame, mirror);
1476
+ return [
1477
+ b.x - a.x,
1478
+ b.y - a.y,
1479
+ 0
1480
+ ];
1481
+ },
1482
+ weight: { get: (ctx) => {
1483
+ const clock = ctx;
1484
+ const a = read(source, from, clock.frame, mirror);
1485
+ const b = read(source, to, clock.frame, mirror);
1486
+ return smoothstep$1(lo, lo + .2, Math.min(a.visibility, b.visibility)) * numberAt(options.weight, clock, 1);
1487
+ } }
1488
+ }));
1489
+ }
1490
+
1335
1491
  //#endregion
1336
1492
  //#region src/clip-vision.ts
1337
1493
  /** Frames looked back over to bridge a gap where the person is lost. */
1338
1494
  const HOLD = 24;
1339
1495
  const CACHE_VERSION = 1;
1340
1496
  const DEPTH_CACHE_VERSION = 1;
1497
+ const MATTE_CACHE_VERSION = 1;
1498
+ const MATTE_MODEL = "vitmatte-s";
1341
1499
  const DEPTH_MODEL = "depth-anything-v2-s";
1342
1500
  /** Depth frames held in memory when they also live on disk (each is about 1 MB). */
1343
1501
  const DEPTH_MEMORY = 48;
@@ -1345,7 +1503,7 @@ let visionSam;
1345
1503
  let clipVisionIds = 0;
1346
1504
  /** SAM ships in its own chunk, loaded only when a clip asks for `sam2` or `sam3`. */
1347
1505
  function loadVisionSam() {
1348
- visionSam ??= import("./dist-B_rSWeOz.mjs");
1506
+ visionSam ??= import("./dist-umQOWz0a.mjs");
1349
1507
  return visionSam;
1350
1508
  }
1351
1509
  /**
@@ -1402,6 +1560,10 @@ var ClipVision = class {
1402
1560
  subjects = /* @__PURE__ */ new Map();
1403
1561
  wantSubjects = false;
1404
1562
  subjectsLoaded;
1563
+ /** Soft alpha per source frame (`matting`); null when the frame holds no subject. */
1564
+ mattes = /* @__PURE__ */ new Map();
1565
+ mattesLoaded;
1566
+ unsavedMattes = 0;
1405
1567
  /** Depth per source frame; null when the frame did not decode. Bounded when on disk. */
1406
1568
  depths = /* @__PURE__ */ new Map();
1407
1569
  /** Source frames whose depth is on disk. */
@@ -1441,7 +1603,7 @@ var ClipVision = class {
1441
1603
  this.trimStartSec = options.trimStartSec ?? 0;
1442
1604
  this.smoothing = Math.max(0, Math.round(options.smoothing ?? (options.sam2 || options.sam3 ? 0 : 2)));
1443
1605
  this.cell = Math.max(1, Math.round(options.maskCell ?? 8));
1444
- if (options.sam2 || options.sam3) this.wantSubjects = true;
1606
+ if (options.sam2 || options.sam3 || this.tracksMatting) this.wantSubjects = true;
1445
1607
  }
1446
1608
  /** @internal Explicit selections must never fall back to another detected subject. */
1447
1609
  get exact() {
@@ -1538,9 +1700,11 @@ var ClipVision = class {
1538
1700
  if (s === null || !this.sourceWidth) return null;
1539
1701
  const width = this.sourceWidth;
1540
1702
  const height = this.sourceHeight;
1703
+ const mask = this.alpha(sourceFrame, s);
1704
+ if (!mask) return void 0;
1541
1705
  return {
1542
1706
  category: s.category,
1543
- mask: subjectAlpha(s, width * height),
1707
+ mask,
1544
1708
  width,
1545
1709
  height,
1546
1710
  area: s.area,
@@ -1582,6 +1746,34 @@ var ClipVision = class {
1582
1746
  get tracksMask() {
1583
1747
  return this.options.mask ?? !this.tracksDepth;
1584
1748
  }
1749
+ /** Whether subjects are matted to soft alpha. */
1750
+ get tracksMatting() {
1751
+ return this.options.matting !== void 0 && this.options.matting !== false;
1752
+ }
1753
+ get matteSettings() {
1754
+ const m = this.options.matting;
1755
+ if (!m) return void 0;
1756
+ const o = m === true ? {} : m;
1757
+ return {
1758
+ band: o.band ?? (this.sourceWidth ? defaultMatteBand(this.sourceWidth, this.sourceHeight) : 0),
1759
+ resolution: o.resolution ?? 1024
1760
+ };
1761
+ }
1762
+ /**
1763
+ * A stored subject's alpha at a source frame: the matte when the clip mattes
1764
+ * (undefined until matted), else the mask. With `id`, that track only.
1765
+ */
1766
+ alpha(c, stored, id) {
1767
+ const size$1 = this.sourceWidth * this.sourceHeight;
1768
+ if (!this.tracksMatting) return subjectAlpha(stored, size$1, id);
1769
+ const matte = this.mattes.get(c);
1770
+ if (!matte) return void 0;
1771
+ const alpha = decodeRuns(matte.alpha, size$1);
1772
+ if (id === void 0 || !matte.labels) return alpha;
1773
+ const labels = decodeRuns(matte.labels, size$1);
1774
+ for (let i = 0; i < size$1; i++) if (labels[i] !== id) alpha[i] = 0;
1775
+ return alpha;
1776
+ }
1585
1777
  /** Whether frames carry relative depth. */
1586
1778
  get tracksDepth() {
1587
1779
  return this.options.depth === true;
@@ -1636,7 +1828,7 @@ var ClipVision = class {
1636
1828
  return [Math.max(0, a - HOLD - this.smoothing), Math.max(0, b + this.smoothing)];
1637
1829
  }
1638
1830
  analysed(c) {
1639
- return this.analysedSubject(c) && (!this.tracksDepth || this.hasDepth(c));
1831
+ return this.analysedSubject(c) && (!this.tracksDepth || this.hasDepth(c)) && (!this.tracksMatting || this.mattes.has(c));
1640
1832
  }
1641
1833
  /** Everything but depth, which is a pass of its own. */
1642
1834
  analysedSubject(c) {
@@ -1660,6 +1852,11 @@ var ClipVision = class {
1660
1852
  await this.subjectsLoaded;
1661
1853
  }
1662
1854
  if (this.tracksDepth) await this.computeDepth(from, to);
1855
+ await this.computeSubjects(from, to);
1856
+ if (this.tracksMatting) await this.computeMattes(from, to);
1857
+ }
1858
+ /** Pose, silhouette and subject of every frame in `from…to` not analysed yet. */
1859
+ async computeSubjects(from, to) {
1663
1860
  let missing = false;
1664
1861
  for (let c = from; c <= to; c++) if (!this.analysedSubject(c)) missing = true;
1665
1862
  if (!missing) return;
@@ -1738,6 +1935,51 @@ var ClipVision = class {
1738
1935
  });
1739
1936
  return this.runner;
1740
1937
  }
1938
+ /**
1939
+ * The soft alpha of every subject in `from…to` not matted yet: one
1940
+ * ViTMatte pass per frame over every track's edge. Prompted label maps grow
1941
+ * into the soft edge, so each track keeps its own alpha.
1942
+ */
1943
+ async computeMattes(from, to) {
1944
+ if (!this.sourceWidth) return;
1945
+ this.mattesLoaded ??= this.loadMattes();
1946
+ await this.mattesLoaded;
1947
+ let decoder;
1948
+ for (let c = from; c <= to; c++) {
1949
+ if (this.mattes.has(c)) continue;
1950
+ const stored = this.subjects.get(c);
1951
+ if (stored === void 0) continue;
1952
+ if (stored === null) {
1953
+ this.mattes.set(c, null);
1954
+ continue;
1955
+ }
1956
+ decoder ??= this.decoder();
1957
+ const image = await decodedPixels(await decoder.getFrame(c / this.fps));
1958
+ if (!image) {
1959
+ this.mattes.set(c, null);
1960
+ continue;
1961
+ }
1962
+ const size$1 = image.width * image.height;
1963
+ const values = decodeRuns(stored, size$1);
1964
+ const hard = stored.scores ? values.map((label) => label ? 255 : 0) : values;
1965
+ const matte = await this.visionRunner().refineMatte(image, hard, this.matteSettings);
1966
+ let labels;
1967
+ if (stored.scores) {
1968
+ labels = new Uint8Array(size$1);
1969
+ for (let i = 0; i < size$1; i++) {
1970
+ const nearest = matte.nearest[i];
1971
+ if (matte.mask[i] && nearest >= 0) labels[i] = values[nearest];
1972
+ }
1973
+ }
1974
+ this.mattes.set(c, {
1975
+ alpha: encodeRuns(matte.mask),
1976
+ ...labels && { labels: encodeRuns(labels) }
1977
+ });
1978
+ this.signalMaskFrame = -1;
1979
+ if (++this.unsavedMattes >= 24) await this.saveMattes();
1980
+ }
1981
+ if (this.unsavedMattes > 0) await this.saveMattes();
1982
+ }
1741
1983
  /** Depth of every source frame in `from…to` not analysed yet, saved one file per frame. */
1742
1984
  async computeDepth(from, to) {
1743
1985
  const dir = await this.depthCacheDir();
@@ -1996,11 +2238,13 @@ var ClipVision = class {
1996
2238
  if (!this.results.has(c) || !this.sourceWidth) return void 0;
1997
2239
  const stored = this.subjects.get(c);
1998
2240
  const size$1 = this.sourceWidth * this.sourceHeight;
1999
- const data = stored ? subjectAlpha(stored, size$1, id) : new Uint8Array(size$1);
2241
+ const alpha = stored ? this.alpha(c, stored, id) : new Uint8Array(size$1);
2242
+ if (!alpha) return void 0;
2243
+ const data = alpha;
2000
2244
  let area$1 = stored?.area ?? 0;
2001
2245
  if (id !== void 0 && stored?.scores) {
2002
2246
  area$1 = 0;
2003
- for (const alpha of data) if (alpha) area$1++;
2247
+ for (const alpha$1 of data) if (alpha$1) area$1++;
2004
2248
  }
2005
2249
  const mask = {
2006
2250
  category: stored?.category ?? this.samCategory(),
@@ -2232,6 +2476,55 @@ var ClipVision = class {
2232
2476
  }
2233
2477
  } catch {}
2234
2478
  }
2479
+ /**
2480
+ * Mattes live beside the subjects they refine, keyed by the matting model
2481
+ * and settings, so toggling matting never recomputes the masks.
2482
+ */
2483
+ async mattesPath() {
2484
+ const file = await this.cachePath();
2485
+ const node = await nodeModules();
2486
+ const settings = this.matteSettings;
2487
+ if (!file || !node || !settings) return null;
2488
+ const hash = node.crypto.createHash("sha256").update(JSON.stringify([
2489
+ MATTE_CACHE_VERSION,
2490
+ MATTE_MODEL,
2491
+ settings.band,
2492
+ settings.resolution
2493
+ ])).digest("hex").slice(0, 12);
2494
+ return file.replace(/\.json$/, `.matte-${hash}.json`);
2495
+ }
2496
+ async loadMattes() {
2497
+ const file = await this.mattesPath();
2498
+ if (!file) return;
2499
+ try {
2500
+ const fs$1 = await import("node:fs");
2501
+ if (!fs$1.existsSync(file)) return;
2502
+ const json = JSON.parse(fs$1.readFileSync(file, "utf8"));
2503
+ if (json.width !== this.sourceWidth || json.height !== this.sourceHeight) return;
2504
+ for (const [c, m] of Object.entries(json.frames)) this.mattes.set(Number(c), m && {
2505
+ alpha: fromStoredRuns(m.alpha),
2506
+ ...m.labels && { labels: fromStoredRuns(m.labels) }
2507
+ });
2508
+ } catch {}
2509
+ }
2510
+ async saveMattes() {
2511
+ this.unsavedMattes = 0;
2512
+ const file = await this.mattesPath();
2513
+ if (!file || !this.sourceWidth) return;
2514
+ const frames = {};
2515
+ for (const [c, m] of this.mattes) frames[c] = m && {
2516
+ alpha: toStoredRuns(m.alpha),
2517
+ ...m.labels && { labels: toStoredRuns(m.labels) }
2518
+ };
2519
+ const fs$1 = await import("node:fs");
2520
+ const tmp = `${file}.${process.pid}.tmp`;
2521
+ fs$1.writeFileSync(tmp, JSON.stringify({
2522
+ width: this.sourceWidth,
2523
+ height: this.sourceHeight,
2524
+ frames
2525
+ }));
2526
+ fs$1.renameSync(tmp, file);
2527
+ }
2235
2528
  async saveSubjects() {
2236
2529
  this.unsavedSubjects = 0;
2237
2530
  const file = await this.subjectsPath();
@@ -2310,16 +2603,24 @@ var PersonTrack = class PersonTrack {
2310
2603
  visibility: a[2] + (b[2] - a[2]) * u
2311
2604
  };
2312
2605
  }
2606
+ /**
2607
+ * Aim constraints that make a 3D character copy this person's pose, for
2608
+ * a glTF model's `aim`: `Layer.glb(src, { aim: person.retarget({ rig: "mixamo" }) })`.
2609
+ * Place the person first (`place()`), so directions read in composition px.
2610
+ */
2611
+ retarget(options) {
2612
+ return retargetPose(this, options);
2613
+ }
2313
2614
  /** Signals for a keypoint, for `.signal("x", …)`; read while rendering. */
2314
2615
  signals(name) {
2315
- const read$1 = (axis) => Signal.builder({
2616
+ const read$2 = (axis) => Signal.builder({
2316
2617
  type: "custom",
2317
2618
  fn: (ctx) => this.point(name, ctx.frame)[axis]
2318
2619
  });
2319
2620
  return {
2320
- x: read$1("x"),
2321
- y: read$1("y"),
2322
- visibility: read$1("visibility")
2621
+ x: read$2("x"),
2622
+ y: read$2("y"),
2623
+ visibility: read$2("visibility")
2323
2624
  };
2324
2625
  }
2325
2626
  /**
@@ -2358,14 +2659,14 @@ var PersonTrack = class PersonTrack {
2358
2659
  const t = this.transform();
2359
2660
  const cx = (x - t.ox) / t.sx / cell - .5;
2360
2661
  const cy = (y - t.oy) / t.sy / cell - .5;
2361
- const read$1 = (gx, gy) => gx < 0 || gy < 0 || gx >= w || gy >= h ? 0 : grid[gy * w + gx];
2662
+ const read$2 = (gx, gy) => gx < 0 || gy < 0 || gx >= w || gy >= h ? 0 : grid[gy * w + gx];
2362
2663
  const bil = (px, py) => {
2363
2664
  const x0 = Math.floor(px);
2364
2665
  const y0 = Math.floor(py);
2365
2666
  const ux = px - x0;
2366
2667
  const uy = py - y0;
2367
- const a = read$1(x0, y0) + (read$1(x0 + 1, y0) - read$1(x0, y0)) * ux;
2368
- return a + (read$1(x0, y0 + 1) + (read$1(x0 + 1, y0 + 1) - read$1(x0, y0 + 1)) * ux - a) * uy;
2668
+ const a = read$2(x0, y0) + (read$2(x0 + 1, y0) - read$2(x0, y0)) * ux;
2669
+ return a + (read$2(x0, y0 + 1) + (read$2(x0 + 1, y0 + 1) - read$2(x0, y0 + 1)) * ux - a) * uy;
2369
2670
  };
2370
2671
  return {
2371
2672
  alpha: bil(cx, cy),
@@ -2465,6 +2766,19 @@ function downsampleMean(src, w, h, cell, dst, mw, mh) {
2465
2766
  dst[my * mw + mx] = n ? Math.round(sum / n) : 0;
2466
2767
  }
2467
2768
  }
2769
+ function toStoredRuns(runs) {
2770
+ return {
2771
+ values: Buffer.from(runs.values).toString("base64"),
2772
+ lengths: Buffer.from(runs.lengths.buffer, runs.lengths.byteOffset, runs.lengths.byteLength).toString("base64")
2773
+ };
2774
+ }
2775
+ function fromStoredRuns(stored) {
2776
+ const lengths = Buffer.from(stored.lengths, "base64");
2777
+ return {
2778
+ values: new Uint8Array(Buffer.from(stored.values, "base64")),
2779
+ lengths: new Uint32Array(lengths.buffer.slice(lengths.byteOffset, lengths.byteOffset + lengths.byteLength))
2780
+ };
2781
+ }
2468
2782
  /** A mask as (value, run length) pairs: long flat runs with soft edges. */
2469
2783
  function encodeRuns(mask) {
2470
2784
  let runs = 0;
@@ -2815,6 +3129,10 @@ var WorldCore = class {
2815
3129
  forces = [];
2816
3130
  impulses = [];
2817
3131
  fields = [];
3132
+ /** Run after each simulated frame with the pairs that started touching in it. */
3133
+ stepHooks = [];
3134
+ /** Run once the whole simulation has finished (not in live worlds). */
3135
+ simulatedHooks = [];
2818
3136
  worldRecording;
2819
3137
  allCollisions = [];
2820
3138
  /** No more bodies, joints or forces: the world has started (or finished). */
@@ -2869,6 +3187,7 @@ var WorldCore = class {
2869
3187
  */
2870
3188
  live(comp, options = {}) {
2871
3189
  if (this.locked) throw new Error("Physics: live() must come before simulate() or reading any body signal.");
3190
+ if (this.simulatedHooks.length) throw new Error("Physics: fracture() needs the whole run up front; use simulate() instead of live().");
2872
3191
  this.locked = true;
2873
3192
  this.liveMode = true;
2874
3193
  const prepare = async (frame) => {
@@ -2947,6 +3266,7 @@ var WorldCore = class {
2947
3266
  st.freed = true;
2948
3267
  this.sim.free();
2949
3268
  for (const body of this.bodies) this.bind(body);
3269
+ for (const hook of this.simulatedHooks) hook();
2950
3270
  }
2951
3271
  /** Records frame 0 and sets every channel to it, so frames not simulated yet hold the start pose. */
2952
3272
  begin() {
@@ -3085,6 +3405,7 @@ var WorldCore = class {
3085
3405
  if (level > loudest) loudest = level;
3086
3406
  }
3087
3407
  this.worldRecording.channel("impact")[frame] = loudest;
3408
+ for (const hook of this.stepHooks) hook(f, pairs);
3088
3409
  st.current = f;
3089
3410
  }
3090
3411
  bind(body) {
@@ -3184,15 +3505,15 @@ var Particles = class extends Effect$1 {
3184
3505
  }
3185
3506
  particleFrame(frame, fps) {
3186
3507
  const o = this.options;
3187
- const read$1 = (d, fallback) => d === void 0 ? fallback : sampleDriver(d, frame, fps);
3508
+ const read$2 = (d, fallback) => d === void 0 ? fallback : sampleDriver(d, frame, fps);
3188
3509
  const layerFrame = frame - (o.startFrame ?? 0);
3189
3510
  const burst = (o.emitter?.bursts ?? []).filter((b) => Math.round(b.frame) === layerFrame).reduce((n, b) => n + b.count, 0);
3190
3511
  const g = o.gravity;
3191
- const gravity = Array.isArray(g) ? [read$1(g[0], 0), read$1(g[1], 0)] : [0, read$1(g, 0)];
3512
+ const gravity = Array.isArray(g) ? [read$2(g[0], 0), read$2(g[1], 0)] : [0, read$2(g, 0)];
3192
3513
  let push = null;
3193
3514
  if (o.push) push = {
3194
- strength: read$1(o.push.strength, 6e3),
3195
- sweep: read$1(o.push.sweep, 6e4),
3515
+ strength: read$2(o.push.strength, 6e3),
3516
+ sweep: read$2(o.push.sweep, 6e4),
3196
3517
  mask: o.push.person.silhouetteGrid(frame),
3197
3518
  previous: o.push.person.silhouetteGrid(Math.max(0, frame - 1))
3198
3519
  };
@@ -3216,19 +3537,19 @@ var Particles = class extends Effect$1 {
3216
3537
  }
3217
3538
  return {
3218
3539
  ...emitter && { emitter },
3219
- rate: read$1(o.emitter?.rate, 1e3),
3540
+ rate: read$2(o.emitter?.rate, 1e3),
3220
3541
  burst,
3221
3542
  gravity,
3222
- drag: read$1(o.drag, .4),
3543
+ drag: read$2(o.drag, .4),
3223
3544
  noise: {
3224
- strength: read$1(o.noise?.strength, 0),
3545
+ strength: read$2(o.noise?.strength, 0),
3225
3546
  scale: o.noise?.scale ?? 300,
3226
3547
  speed: o.noise?.speed ?? .3
3227
3548
  },
3228
3549
  attractors: (o.attractors ?? []).map((a) => ({
3229
- x: read$1(a.x, 0),
3230
- y: read$1(a.y, 0),
3231
- strength: read$1(a.strength, 0),
3550
+ x: read$2(a.x, 0),
3551
+ y: read$2(a.y, 0),
3552
+ strength: read$2(a.strength, 0),
3232
3553
  radius: a.radius ?? 200
3233
3554
  })),
3234
3555
  push
@@ -3236,6 +3557,172 @@ var Particles = class extends Effect$1 {
3236
3557
  }
3237
3558
  };
3238
3559
 
3560
+ //#endregion
3561
+ //#region src/procedural3d.ts
3562
+ /** Where a model node's mesh sits: its static transform. */
3563
+ function staticMatrix(n) {
3564
+ const rad = Math.PI / 180;
3565
+ const s = n.scale ?? 1;
3566
+ let m = Matrix4Math.translate(n.x ?? 0, n.y ?? 0, n.z ?? 0);
3567
+ if (n.rotateZ) m = Matrix4Math.multiply(m, Matrix4Math.rotateZ(n.rotateZ * rad));
3568
+ if (n.rotateY) m = Matrix4Math.multiply(m, Matrix4Math.rotateY(n.rotateY * rad));
3569
+ if (n.rotateX) m = Matrix4Math.multiply(m, Matrix4Math.rotateX(n.rotateX * rad));
3570
+ return Matrix4Math.multiply(m, Matrix4Math.scale(s * (n.scaleX ?? 1), s * (n.scaleY ?? 1), s * (n.scaleZ ?? 1)));
3571
+ }
3572
+ function defineHidden(target$1, values) {
3573
+ for (const [key, value] of Object.entries(values)) Object.defineProperty(target$1, key, {
3574
+ value,
3575
+ enumerable: false,
3576
+ configurable: true
3577
+ });
3578
+ }
3579
+ function surfaceHelpers(sampler, o) {
3580
+ const s = o.scale ?? 1;
3581
+ const sx = s * (o.scaleX ?? 1);
3582
+ const sy = s * (o.scaleY ?? 1);
3583
+ const sz = s * (o.scaleZ ?? 1);
3584
+ const local = (x, z$3) => [(x - (o.x ?? 0)) / sx, (z$3 - (o.z ?? 0)) / sz];
3585
+ return {
3586
+ heightAt: (x, z$3) => (o.y ?? 0) + sampler.heightAt(...local(x, z$3)) * sy,
3587
+ elevationAt: (x, z$3) => sampler.elevationAt(...local(x, z$3)),
3588
+ normalAt(x, z$3) {
3589
+ const n = sampler.normalAt(...local(x, z$3));
3590
+ const m = [
3591
+ n[0] / sx,
3592
+ n[1] / sy,
3593
+ n[2] / sz
3594
+ ];
3595
+ const len = Math.hypot(m[0], m[1], m[2]) || 1;
3596
+ return [
3597
+ m[0] / len,
3598
+ m[1] / len,
3599
+ m[2] / len
3600
+ ];
3601
+ }
3602
+ };
3603
+ }
3604
+ /** Procedural terrain (see `Layer3D.terrain`). */
3605
+ function terrain3d(options) {
3606
+ const { heightFn, ...o } = options;
3607
+ const geometry = {
3608
+ type: "terrain",
3609
+ width: o.width,
3610
+ depth: o.depth,
3611
+ height: o.height,
3612
+ segments: o.segments,
3613
+ noise: o.noise,
3614
+ heights: o.heights,
3615
+ overhangWarp: o.overhangWarp,
3616
+ colorByElevation: o.colorByElevation,
3617
+ flatShaded: o.flatShaded,
3618
+ base: o.base
3619
+ };
3620
+ if (heightFn) {
3621
+ const [cols, rows] = terrainSegments(geometry);
3622
+ const heights = [];
3623
+ for (let j = 0; j <= rows; j++) for (let i = 0; i <= cols; i++) heights.push(heightFn(i / cols, j / rows));
3624
+ geometry.heights = heights;
3625
+ }
3626
+ const node = primitiveNode("terrain", geometry, o);
3627
+ defineHidden(node, surfaceHelpers(createTerrainSampler(geometry), options));
3628
+ return node;
3629
+ }
3630
+ /** A signed-distance sculpture (see `Layer3D.sdf`). */
3631
+ function sdf3d(options) {
3632
+ return primitiveNode("sdf", {
3633
+ type: "sdf",
3634
+ primitives: options.primitives,
3635
+ bounds: options.bounds,
3636
+ resolution: options.resolution,
3637
+ flatShaded: options.flatShaded
3638
+ }, options);
3639
+ }
3640
+ const SURFACE_KEYS = [
3641
+ "x",
3642
+ "y",
3643
+ "z",
3644
+ "rotateX",
3645
+ "rotateY",
3646
+ "rotateZ",
3647
+ "scale",
3648
+ "scaleX",
3649
+ "scaleY",
3650
+ "scaleZ",
3651
+ "primitive3d",
3652
+ "src",
3653
+ "modelFormat",
3654
+ "center",
3655
+ "normalizeSize"
3656
+ ];
3657
+ /** What the renderer rebuilds and places the surface from. */
3658
+ function surfaceSpec(surface) {
3659
+ const out = {};
3660
+ for (const k of SURFACE_KEYS) if (surface[k] !== void 0) out[k] = surface[k];
3661
+ if (!surface.primitive3d && !surface.src && surface.modelData) out.modelData = surface.modelData;
3662
+ return out;
3663
+ }
3664
+ /** The surface's mesh when it is already in memory (primitives, terrain, SDF). */
3665
+ function surfaceModel(surface) {
3666
+ const data = surface.modelData;
3667
+ if (data && "meshes" in data) return data;
3668
+ if (surface.primitive3d) return getPrimitiveGeometry(surface.primitive3d);
3669
+ }
3670
+ const SCATTER_KEYS = [
3671
+ "count",
3672
+ "minDistance",
3673
+ "seed",
3674
+ "slopeRange",
3675
+ "elevationRange",
3676
+ "alignToNormal",
3677
+ "scaleRange",
3678
+ "randomYaw",
3679
+ "exclude",
3680
+ "sink"
3681
+ ];
3682
+ /** Instances scattered on a surface (see `Layer3D.scatter`). */
3683
+ function scatter3d(options) {
3684
+ const { surface, wind, ...rest } = options;
3685
+ const spec$1 = { surface: surfaceSpec(surface) };
3686
+ const instanceOptions = { ...rest };
3687
+ for (const k of SCATTER_KEYS) {
3688
+ if (rest[k] !== void 0) spec$1[k] = rest[k];
3689
+ delete instanceOptions[k];
3690
+ }
3691
+ const node = Layer3D.instances(instanceOptions);
3692
+ const target$1 = node;
3693
+ target$1.scatter3d = spec$1;
3694
+ if (wind) target$1.wind = wind;
3695
+ defineHidden(node, { points: () => {
3696
+ const model = surfaceModel(surface);
3697
+ if (!model) return [];
3698
+ return scatterOnSurface({
3699
+ model,
3700
+ matrix: staticMatrix(surface)
3701
+ }, spec$1).points;
3702
+ } });
3703
+ return node;
3704
+ }
3705
+ /**
3706
+ * Share of a scatter's surface its slope / altitude filters keep (for
3707
+ * `lint`), or undefined when the surface is a file not loaded yet.
3708
+ */
3709
+ function scatterCoverage(spec$1) {
3710
+ const surface = spec$1.surface;
3711
+ const model = surfaceModel(surface);
3712
+ if (!model) return void 0;
3713
+ return scatterOnSurface({
3714
+ model,
3715
+ matrix: staticMatrix(surface)
3716
+ }, {
3717
+ ...spec$1,
3718
+ count: 0
3719
+ }).acceptedArea;
3720
+ }
3721
+ /** `texture` on a Layer3D mesh: an image path, or any layer drawn each frame. */
3722
+ function textureLayerOf(texture, image) {
3723
+ return { node: typeof texture === "string" ? image(texture) : texture };
3724
+ }
3725
+
3239
3726
  //#endregion
3240
3727
  //#region src/swarm3d.ts
3241
3728
  function createSwarm3D(options) {
@@ -3302,6 +3789,8 @@ function createSwarm3D(options) {
3302
3789
  //#endregion
3303
3790
  //#region src/shapes3d.ts
3304
3791
  const MATERIAL_KEYS = [
3792
+ "toon",
3793
+ "outline",
3305
3794
  "material",
3306
3795
  "shininess",
3307
3796
  "roughness",
@@ -3315,7 +3804,22 @@ const MATERIAL_KEYS = [
3315
3804
  "envIntensity",
3316
3805
  "emissive",
3317
3806
  "emissiveIntensity",
3318
- "castShadow"
3807
+ "castShadow",
3808
+ "clearcoat",
3809
+ "clearcoatRoughness",
3810
+ "anisotropy",
3811
+ "anisotropyRotation",
3812
+ "subsurface",
3813
+ "subsurfaceColor",
3814
+ "sheen",
3815
+ "sheenColor",
3816
+ "sheenRoughness",
3817
+ "iridescence",
3818
+ "iridescenceThickness",
3819
+ "iridescenceIor",
3820
+ "triplanar",
3821
+ "triplanarScale",
3822
+ "triplanarSharpness"
3319
3823
  ];
3320
3824
  /** The material and surface options that were actually given. */
3321
3825
  function materialProps(o) {
@@ -3332,6 +3836,7 @@ function normalizePathSpec(input) {
3332
3836
  if (input instanceof Path3D) return input.getPoints(96);
3333
3837
  return input;
3334
3838
  }
3839
+ /** A Layer3D mesh node built from a procedural geometry spec. */
3335
3840
  function primitiveNode(prefix, geometry, o) {
3336
3841
  const spec$1 = Object.fromEntries(Object.entries({
3337
3842
  ...geometry,
@@ -3349,9 +3854,9 @@ function primitiveNode(prefix, geometry, o) {
3349
3854
  x: o.x ?? 0,
3350
3855
  y: o.y ?? 0,
3351
3856
  z: o.z ?? 0,
3352
- rotateX: o.rotateX ?? 0,
3353
- rotateY: o.rotateY ?? 0,
3354
- rotateZ: o.rotateZ ?? 0,
3857
+ rotateX: o.rotateX ?? o.rotationX ?? 0,
3858
+ rotateY: o.rotateY ?? o.rotationY ?? 0,
3859
+ rotateZ: o.rotateZ ?? o.rotationZ ?? 0,
3355
3860
  scale: o.scale ?? 1,
3356
3861
  scaleX: o.scaleX ?? 1,
3357
3862
  scaleY: o.scaleY ?? 1,
@@ -3368,7 +3873,9 @@ function primitiveNode(prefix, geometry, o) {
3368
3873
  twoSided: o.twoSided ?? false,
3369
3874
  wireframe: o.wireframe,
3370
3875
  startFrame: o.startFrame,
3371
- durationFrames: o.durationFrames
3876
+ durationFrames: o.durationFrames,
3877
+ ...o.wind && { wind: o.wind },
3878
+ ...o.texture !== void 0 && { textureLayer: textureLayerOf(o.texture, (src) => Layer.image(src)) }
3372
3879
  });
3373
3880
  }
3374
3881
  /**
@@ -3426,7 +3933,10 @@ const Layer3D = {
3426
3933
  if (options.roughness !== void 0 && node.roughness === void 0) node.roughness = options.roughness;
3427
3934
  if (options.metallic !== void 0 && node.metallic === void 0) node.metallic = options.metallic;
3428
3935
  if (options.ambientIntensity !== void 0 && node.ambientIntensity === void 0) node.ambientIntensity = options.ambientIntensity;
3429
- Object.assign(node, faceProps);
3936
+ Object.assign(node, {
3937
+ ...materialProps(options),
3938
+ ...materialProps(node)
3939
+ }, faceProps);
3430
3940
  return node;
3431
3941
  }
3432
3942
  const cfg = typeof input === "string" ? { background: input } : input ?? { background: defaultColor };
@@ -3519,9 +4029,9 @@ const Layer3D = {
3519
4029
  height: h,
3520
4030
  is3D: true,
3521
4031
  transformStyle: "preserve-3d",
3522
- rotateX: options.rotateX ?? 0,
3523
- rotateY: options.rotateY ?? 0,
3524
- rotateZ: options.rotateZ ?? 0,
4032
+ rotateX: options.rotateX ?? options.rotationX ?? 0,
4033
+ rotateY: options.rotateY ?? options.rotationY ?? 0,
4034
+ rotateZ: options.rotateZ ?? options.rotationZ ?? 0,
3525
4035
  opacity: options.opacity ?? 1,
3526
4036
  background: "transparent",
3527
4037
  children: faces
@@ -3557,18 +4067,20 @@ const Layer3D = {
3557
4067
  height: options.itemHeight ?? 200,
3558
4068
  is3D: true,
3559
4069
  transformStyle: "preserve-3d",
3560
- rotateX: options.rotateX ?? 0,
3561
- rotateY: options.rotateY ?? 0,
3562
- rotateZ: options.rotateZ ?? 0,
4070
+ rotateX: options.rotateX ?? options.rotationX ?? 0,
4071
+ rotateY: options.rotateY ?? options.rotationY ?? 0,
4072
+ rotateZ: options.rotateZ ?? options.rotationZ ?? 0,
3563
4073
  opacity: options.opacity ?? 1,
3564
4074
  background: "transparent",
3565
4075
  children: transformedItems
3566
4076
  }), { items: transformedItems });
3567
4077
  },
3568
- prism(options) {
3569
- const n = Math.max(3, Math.round(options.sides));
4078
+ prism(options = {}) {
4079
+ const n = Math.max(3, Math.round(options.sides ?? 6));
4080
+ const radius = options.radius ?? 60;
4081
+ const height = options.height ?? 100;
3570
4082
  if (options.sideConfigs && options.sideConfigs.length > 0) {
3571
- const { radius, height, twoSided = true } = options;
4083
+ const { twoSided = true } = options;
3572
4084
  const sideWidth = 2 * radius * Math.tan(Math.PI / n);
3573
4085
  const angleStep = 360 / n;
3574
4086
  const panels = [];
@@ -3630,20 +4142,23 @@ const Layer3D = {
3630
4142
  height,
3631
4143
  is3D: true,
3632
4144
  transformStyle: "preserve-3d",
3633
- rotateX: options.rotateX ?? 0,
3634
- rotateY: options.rotateY ?? 0,
3635
- rotateZ: options.rotateZ ?? 0,
4145
+ rotateX: options.rotateX ?? options.rotationX ?? 0,
4146
+ rotateY: options.rotateY ?? options.rotationY ?? 0,
4147
+ rotateZ: options.rotateZ ?? options.rotationZ ?? 0,
3636
4148
  opacity: options.opacity ?? 1,
3637
4149
  background: "transparent",
3638
4150
  children: panels
3639
- }), { faces: panels });
4151
+ }), {
4152
+ faces: panels,
4153
+ items: panels
4154
+ });
3640
4155
  }
3641
4156
  const modelNode = primitiveNode("prism", {
3642
4157
  type: "cylinder",
3643
- radius: options.radius,
3644
- radiusTop: options.radiusTop ?? options.radius,
3645
- radiusBottom: options.radiusBottom ?? options.radius,
3646
- height: options.height,
4158
+ radius,
4159
+ radiusTop: options.radiusTop ?? options.topRadius ?? radius,
4160
+ radiusBottom: options.radiusBottom ?? options.bottomRadius ?? radius,
4161
+ height,
3647
4162
  segments: n,
3648
4163
  openEnded: options.openEnded ?? false,
3649
4164
  flatShaded: options.flatShaded ?? true
@@ -3657,14 +4172,14 @@ const Layer3D = {
3657
4172
  items: [modelNode]
3658
4173
  });
3659
4174
  },
3660
- pyramid(options) {
4175
+ pyramid(options = {}) {
3661
4176
  const n = Math.max(3, Math.round(options.sides ?? 4));
3662
4177
  return primitiveNode("pyramid", {
3663
4178
  type: "cylinder",
3664
4179
  radius: options.radius ?? 60,
3665
- radiusTop: options.radiusTop ?? 0,
4180
+ radiusTop: options.radiusTop ?? options.topRadius ?? 0,
3666
4181
  radiusBottom: options.radius ?? 60,
3667
- height: options.height,
4182
+ height: options.height ?? 100,
3668
4183
  segments: n,
3669
4184
  openEnded: options.openEnded ?? false,
3670
4185
  flatShaded: options.flatShaded ?? true
@@ -3685,9 +4200,9 @@ const Layer3D = {
3685
4200
  z: options.z ?? 0,
3686
4201
  is3D: true,
3687
4202
  twoSided: options.twoSided ?? true,
3688
- rotateX: options.rotateX ?? 0,
3689
- rotateY: options.rotateY ?? 0,
3690
- rotateZ: options.rotateZ ?? 0,
4203
+ rotateX: options.rotateX ?? options.rotationX ?? 0,
4204
+ rotateY: options.rotateY ?? options.rotationY ?? 0,
4205
+ rotateZ: options.rotateZ ?? options.rotationZ ?? 0,
3691
4206
  background: options.background ?? "#3b82f6",
3692
4207
  borderRadius: options.borderRadius ?? 0,
3693
4208
  opacity: options.opacity ?? 1,
@@ -3741,9 +4256,9 @@ const Layer3D = {
3741
4256
  z: options.z ?? 0,
3742
4257
  is3D: true,
3743
4258
  transformStyle: "preserve-3d",
3744
- rotateX: options.rotateX ?? 90,
3745
- rotateY: options.rotateY ?? 0,
3746
- rotateZ: options.rotateZ ?? 0,
4259
+ rotateX: options.rotateX ?? options.rotationX ?? 90,
4260
+ rotateY: options.rotateY ?? options.rotationY ?? 0,
4261
+ rotateZ: options.rotateZ ?? options.rotationZ ?? 0,
3747
4262
  background: "transparent",
3748
4263
  opacity: options.opacity ?? 1,
3749
4264
  children: lines
@@ -3762,9 +4277,9 @@ const Layer3D = {
3762
4277
  z: options.z ?? 0,
3763
4278
  is3D: true,
3764
4279
  twoSided: options.twoSided ?? true,
3765
- rotateX: options.rotateX ?? 0,
3766
- rotateY: options.rotateY ?? 0,
3767
- rotateZ: options.rotateZ ?? 0,
4280
+ rotateX: options.rotateX ?? options.rotationX ?? 0,
4281
+ rotateY: options.rotateY ?? options.rotationY ?? 0,
4282
+ rotateZ: options.rotateZ ?? options.rotationZ ?? 0,
3768
4283
  fontSize: options.fontSize ?? 48,
3769
4284
  fontFamily: options.fontFamily,
3770
4285
  fontWeight: options.fontWeight ?? "bold",
@@ -3820,9 +4335,9 @@ const Layer3D = {
3820
4335
  x: options.x ?? 0,
3821
4336
  y: options.y ?? 0,
3822
4337
  z: options.z ?? 0,
3823
- rotateX: options.rotateX ?? 0,
3824
- rotateY: options.rotateY ?? 0,
3825
- rotateZ: options.rotateZ ?? 0,
4338
+ rotateX: options.rotateX ?? options.rotationX ?? 0,
4339
+ rotateY: options.rotateY ?? options.rotationY ?? 0,
4340
+ rotateZ: options.rotateZ ?? options.rotationZ ?? 0,
3826
4341
  scale: options.scale ?? 1,
3827
4342
  scaleX: options.scaleX ?? 1,
3828
4343
  scaleY: options.scaleY ?? 1,
@@ -3852,7 +4367,7 @@ const Layer3D = {
3852
4367
  width: options.width,
3853
4368
  height: options.height,
3854
4369
  depth: options.depth,
3855
- radius: options.radius,
4370
+ radius: options.radius ?? options.cornerRadius ?? options.borderRadius,
3856
4371
  segments: options.segments,
3857
4372
  taper: options.taper
3858
4373
  }, options);
@@ -3868,8 +4383,8 @@ const Layer3D = {
3868
4383
  return primitiveNode("cylinder", {
3869
4384
  type: "cylinder",
3870
4385
  radius: options.radius,
3871
- radiusTop: options.radiusTop,
3872
- radiusBottom: options.radiusBottom,
4386
+ radiusTop: options.radiusTop ?? options.topRadius,
4387
+ radiusBottom: options.radiusBottom ?? options.bottomRadius,
3873
4388
  height: options.height,
3874
4389
  segments: options.segments,
3875
4390
  openEnded: options.openEnded,
@@ -3882,8 +4397,8 @@ const Layer3D = {
3882
4397
  torus(options = {}) {
3883
4398
  return primitiveNode("torus", {
3884
4399
  type: "torus",
3885
- radius: options.radius,
3886
- tube: options.tube,
4400
+ radius: options.radius ?? options.majorRadius,
4401
+ tube: options.tube ?? options.minorRadius ?? options.tubeRadius,
3887
4402
  radialSegments: options.radialSegments,
3888
4403
  tubularSegments: options.tubularSegments,
3889
4404
  arc: options.arc
@@ -4025,6 +4540,15 @@ const Layer3D = {
4025
4540
  irregularity: options.irregularity
4026
4541
  }, options);
4027
4542
  },
4543
+ terrain(options) {
4544
+ return terrain3d(options);
4545
+ },
4546
+ sdf(options) {
4547
+ return sdf3d(options);
4548
+ },
4549
+ scatter(options) {
4550
+ return scatter3d(options);
4551
+ },
4028
4552
  instances(options) {
4029
4553
  const primaryMesh = Array.isArray(options.mesh) ? options.mesh[0] : options.mesh;
4030
4554
  const node = {
@@ -4033,9 +4557,9 @@ const Layer3D = {
4033
4557
  x: options.x ?? 0,
4034
4558
  y: options.y ?? 0,
4035
4559
  z: options.z ?? 0,
4036
- rotateX: options.rotateX ?? 0,
4037
- rotateY: options.rotateY ?? 0,
4038
- rotateZ: options.rotateZ ?? 0,
4560
+ rotateX: options.rotateX ?? options.rotationX ?? 0,
4561
+ rotateY: options.rotateY ?? options.rotationY ?? 0,
4562
+ rotateZ: options.rotateZ ?? options.rotationZ ?? 0,
4039
4563
  scale: options.scale ?? 1,
4040
4564
  color: options.color,
4041
4565
  colorTint: options.colorTint,
@@ -4050,6 +4574,8 @@ const Layer3D = {
4050
4574
  startFrame: options.startFrame,
4051
4575
  durationFrames: options.durationFrames,
4052
4576
  instances3d: { ...options },
4577
+ ...options.wind && { wind: options.wind },
4578
+ ...options.crowd && { crowd: options.crowd },
4053
4579
  ...materialProps(options)
4054
4580
  };
4055
4581
  if (primaryMesh) {
@@ -4486,6 +5012,9 @@ function rig(name, options) {
4486
5012
  exposure: options.exposure,
4487
5013
  toneMapping: options.toneMapping,
4488
5014
  fog: options.fog,
5015
+ volumetricFog: options.volumetricFog,
5016
+ ssr: options.ssr,
5017
+ gi: options.gi,
4489
5018
  bloom: options.bloom
4490
5019
  }), Light.directional({
4491
5020
  id: `${id}-key`,
@@ -4597,6 +5126,20 @@ var RapierWorld2D = class {
4597
5126
  x,
4598
5127
  y
4599
5128
  }, true),
5129
+ setPose: ([x, y], angle) => {
5130
+ body.setTranslation({
5131
+ x,
5132
+ y
5133
+ }, true);
5134
+ body.setRotation(angle, true);
5135
+ },
5136
+ setVelocity: ([x, y], w) => {
5137
+ body.setLinvel({
5138
+ x,
5139
+ y
5140
+ }, true);
5141
+ body.setAngvel(w, true);
5142
+ },
4600
5143
  setKinematicTarget: ([x, y], angle) => {
4601
5144
  body.setNextKinematicTranslation({
4602
5145
  x,
@@ -4725,6 +5268,19 @@ var RapierWorld3D = class {
4725
5268
  mass: () => body.mass(),
4726
5269
  setEnabled: (on) => body.setEnabled(on),
4727
5270
  applyImpulse: (v) => body.applyImpulse(vec3(v), true),
5271
+ setPose: (p, [x, y, z$3, w]) => {
5272
+ body.setTranslation(vec3(p), true);
5273
+ body.setRotation({
5274
+ x,
5275
+ y,
5276
+ z: z$3,
5277
+ w
5278
+ }, true);
5279
+ },
5280
+ setVelocity: (v, w) => {
5281
+ body.setLinvel(vec3(v), true);
5282
+ body.setAngvel(vec3(w), true);
5283
+ },
4728
5284
  setKinematicTarget: (p, [x, y, z$3, w]) => {
4729
5285
  body.setNextKinematicTranslation(vec3(p));
4730
5286
  body.setNextKinematicRotation({
@@ -4832,6 +5388,7 @@ function shapeDesc3D(R, shape$1) {
4832
5388
  if (!desc) throw new Error("Physics: could not build a convex hull for this shape.");
4833
5389
  return desc;
4834
5390
  }
5391
+ case "trimesh": return R.ColliderDesc.trimesh(new Float32Array(shape$1.vertices), new Uint32Array(shape$1.indices));
4835
5392
  }
4836
5393
  }
4837
5394
 
@@ -5025,6 +5582,8 @@ var PhysicsWorld2D = class extends WorldCore {
5025
5582
  };
5026
5583
  const simBody = this.sim.addBody(spec$1);
5027
5584
  const body = new PhysicsBody2D(this, simBody, type, layer, geom, options, this.newRecording());
5585
+ const start = body.kinematicTarget(this.startFrame);
5586
+ if (start) simBody.setPose(start.position, start.rotation);
5028
5587
  return this.addBody(body);
5029
5588
  }
5030
5589
  /** A fixed, very wide floor whose top edge sits at `y`. */
@@ -5219,7 +5778,7 @@ function effectiveMass(a, b) {
5219
5778
  if (ma > 0 && mb > 0) return ma * mb / (ma + mb);
5220
5779
  return Math.max(ma, mb, .001);
5221
5780
  }
5222
- function num$3(v, fallback) {
5781
+ function num$4(v, fallback) {
5223
5782
  return typeof v === "number" && Number.isFinite(v) ? v : fallback;
5224
5783
  }
5225
5784
  function layerGeometry(layer, options) {
@@ -5230,31 +5789,31 @@ function layerGeometry(layer, options) {
5230
5789
  if ((width === void 0 || height === void 0) && layer.kind === "text") {
5231
5790
  const m = FontManager.measure(String(layer.text ?? ""), {
5232
5791
  fontFamily: String(layer.fontFamily ?? "Inter"),
5233
- fontSize: num$3(layer.fontSize, 48),
5792
+ fontSize: num$4(layer.fontSize, 48),
5234
5793
  fontWeight: layer.fontWeight,
5235
- letterSpacing: num$3(layer.letterSpacing, 0),
5794
+ letterSpacing: num$4(layer.letterSpacing, 0),
5236
5795
  lineHeight: typeof layer.lineHeight === "number" ? layer.lineHeight : void 0
5237
5796
  });
5238
5797
  width ??= m.width;
5239
5798
  height ??= m.height;
5240
5799
  }
5241
5800
  if (width === void 0 || height === void 0 || width <= 0 || height <= 0) throw new Error(`Physics: layer${id} needs a numeric \`width\` and \`height\` (or the \`size\` option) to become a body.`);
5242
- const scale = num$3(layer.scale, 1);
5801
+ const scale = num$4(layer.scale, 1);
5243
5802
  return {
5244
5803
  x: layer.x,
5245
5804
  y: layer.y,
5246
5805
  width,
5247
5806
  height,
5248
5807
  scale,
5249
- anchorX: num$3(layer.anchorX, .5),
5250
- anchorY: num$3(layer.anchorY, .5),
5251
- rotation: num$3(layer.rotation, 0),
5808
+ anchorX: num$4(layer.anchorX, .5),
5809
+ anchorY: num$4(layer.anchorY, .5),
5810
+ rotation: num$4(layer.rotation, 0),
5252
5811
  shape: scaleShape$1(colliderShape(layer, width, height, options.shape ?? "auto"), scale)
5253
5812
  };
5254
5813
  }
5255
5814
  function colliderShape(layer, w, h, mode) {
5256
5815
  const shapeType = layer.kind === "shape" ? String(layer.shapeType ?? "rect") : "rect";
5257
- const radius = num$3(layer.borderRadius, num$3(layer.cornerRadius, 0));
5816
+ const radius = num$4(layer.borderRadius, num$4(layer.cornerRadius, 0));
5258
5817
  const box = {
5259
5818
  kind: "box",
5260
5819
  hx: w / 2,
@@ -5282,7 +5841,7 @@ function outlinePoints(layer, shapeType, w, h) {
5282
5841
  shapeType,
5283
5842
  width: w,
5284
5843
  height: h,
5285
- cornerRadius: num$3(layer.cornerRadius, num$3(layer.borderRadius, 0)),
5844
+ cornerRadius: num$4(layer.cornerRadius, num$4(layer.borderRadius, 0)),
5286
5845
  polygonSides: layer.polygonSides,
5287
5846
  starPoints: layer.starPoints,
5288
5847
  starInnerRadiusRatio: layer.starInnerRadiusRatio,
@@ -5331,6 +5890,275 @@ function centerToLayer(cx, cy, rotationDeg, f) {
5331
5890
  return [cx - ox - f.anchorX * f.width, cy - oy - f.anchorY * f.height];
5332
5891
  }
5333
5892
 
5893
+ //#endregion
5894
+ //#region src/physics/fracture3d.ts
5895
+ /**
5896
+ * Voronoi destruction: a mesh layer stays whole (a fixed collider of its
5897
+ * own shape) until its fracture frame, or until a body hits it, then its
5898
+ * pieces wake as rigid bodies and fly apart. The pieces' recorded poses go
5899
+ * into the node (`fracture3d.track`), where the renderer turns them into
5900
+ * the joints of one rigidly skinned mesh.
5901
+ */
5902
+ /** A fractured layer: its pieces, and the collider that stands in for it while whole. */
5903
+ var Fracture3D = class {
5904
+ /** @internal */ brokeAt;
5905
+ /** @internal */
5906
+ constructor(node, pieces, intact, world) {
5907
+ this.node = node;
5908
+ this.pieces = pieces;
5909
+ this.intact = intact;
5910
+ this.world = world;
5911
+ }
5912
+ /** Composition frame it broke at (after simulating); undefined if it never did. */
5913
+ get frame() {
5914
+ return this.brokeAt === void 0 ? void 0 : this.world.startFrame + this.brokeAt;
5915
+ }
5916
+ };
5917
+ const NEVER = Number.MAX_SAFE_INTEGER;
5918
+ const num$3 = (v, fallback) => typeof v === "number" && Number.isFinite(v) ? v : fallback;
5919
+ /** The node's placement as the renderer builds it: T · Rz · Ry · Rx · S. */
5920
+ function nodePose(t) {
5921
+ const position = [
5922
+ num$3(t.x, 0),
5923
+ num$3(t.y, 0),
5924
+ num$3(t.z, 0)
5925
+ ];
5926
+ const rotation = [
5927
+ num$3(t.rotateX, 0),
5928
+ num$3(t.rotateY, 0),
5929
+ num$3(t.rotateZ, num$3(t.rotation, 0))
5930
+ ];
5931
+ const s = num$3(t.scale, 1);
5932
+ const scale = [
5933
+ s * num$3(t.scaleX, 1),
5934
+ s * num$3(t.scaleY, 1),
5935
+ s * num$3(t.scaleZ, 1)
5936
+ ];
5937
+ const rad = (d) => d * Math.PI / 180;
5938
+ let m = Matrix4Math.translate(...position);
5939
+ m = Matrix4Math.multiply(m, Matrix4Math.rotateZ(rad(rotation[2])));
5940
+ m = Matrix4Math.multiply(m, Matrix4Math.rotateY(rad(rotation[1])));
5941
+ m = Matrix4Math.multiply(m, Matrix4Math.rotateX(rad(rotation[0])));
5942
+ m = Matrix4Math.multiply(m, Matrix4Math.scale(...scale));
5943
+ return {
5944
+ position,
5945
+ rotation,
5946
+ scale,
5947
+ matrix: m
5948
+ };
5949
+ }
5950
+ const apply = (m, p) => [
5951
+ m[0] * p[0] + m[4] * p[1] + m[8] * p[2] + m[12],
5952
+ m[1] * p[0] + m[5] * p[1] + m[9] * p[2] + m[13],
5953
+ m[2] * p[0] + m[6] * p[1] + m[10] * p[2] + m[14]
5954
+ ];
5955
+ const SCALE_PROPS = [
5956
+ "scale",
5957
+ "scaleX",
5958
+ "scaleY",
5959
+ "scaleZ"
5960
+ ];
5961
+ /** The animated props among `props` (tracks on them). */
5962
+ function animatedProps(node, props) {
5963
+ const tracks = node.animation?.tracks ?? [];
5964
+ return props.filter((p) => tracks.some((t) => t.prop === p));
5965
+ }
5966
+ /** Rigid pieces cannot change size: a fractured layer's scale holds still. */
5967
+ function assertRigid(node) {
5968
+ const scaling = animatedProps(node, SCALE_PROPS);
5969
+ if (!scaling.length) return;
5970
+ const id = typeof node.id === "string" ? ` "${node.id}"` : "";
5971
+ throw new Error(`Physics.fracture: layer${id} animates ${scaling.join(", ")}; rigid pieces cannot change size. Keep a fractured layer's scale still (position and rotation may animate).`);
5972
+ }
5973
+ /**
5974
+ * The layer's animated position and rotation as kinematic drivers, sampled
5975
+ * as the compositor draws them (GSAP eases, stepped timing, signals), so the
5976
+ * stand-in collider is where the layer is; undefined when it holds still.
5977
+ * Read lazily: animation added after `fracture()` counts.
5978
+ */
5979
+ function followLayer(node, fps) {
5980
+ const layer = node;
5981
+ const at = (prop) => (frame) => sampleLayerProp(layer, prop, frame, fps);
5982
+ const rotateZ = (frame) => animatedProps(node, ["rotateZ"]).length || typeof node.rotateZ === "number" ? sampleLayerProp(layer, "rotateZ", frame, fps) : sampleLayerProp(layer, "rotation", frame, fps);
5983
+ return {
5984
+ x: at("x"),
5985
+ y: at("y"),
5986
+ z: at("z"),
5987
+ rotateX: at("rotateX"),
5988
+ rotateY: at("rotateY"),
5989
+ rotateZ
5990
+ };
5991
+ }
5992
+ const MOVING_PROPS = [
5993
+ "x",
5994
+ "y",
5995
+ "z",
5996
+ "rotateX",
5997
+ "rotateY",
5998
+ "rotateZ",
5999
+ "rotation"
6000
+ ];
6001
+ /** @internal */
6002
+ function createFracture(world, target$1, options) {
6003
+ const node = target$1;
6004
+ const model = node.modelData;
6005
+ if (!model?.meshes?.length) {
6006
+ const id = typeof node.id === "string" ? ` "${node.id}"` : "";
6007
+ throw new Error(`Physics.fracture: layer${id} has no mesh. Fracture a Layer3D primitive, extruded text, or a model node that carries modelData.`);
6008
+ }
6009
+ assertRigid(node);
6010
+ const pose = nodePose(node);
6011
+ const toObject = Matrix4Math.invert(pose.matrix) ?? Matrix4Math.identity();
6012
+ const spec$1 = {
6013
+ cells: Math.max(2, Math.min(256, Math.round(options.cells ?? 48))),
6014
+ seed: options.seed ?? 1,
6015
+ ...options.impactPoint && { impactPoint: apply(toObject, options.impactPoint) },
6016
+ ...options.interiorColor && { interiorColor: options.interiorColor },
6017
+ ...options.interiorRoughness !== void 0 && { interiorRoughness: options.interiorRoughness }
6018
+ };
6019
+ const { cells } = fractureModel(model, spec$1);
6020
+ node.fracture3d = spec$1;
6021
+ const moving = animatedProps(node, MOVING_PROPS).length > 0;
6022
+ const intact = world.body(target$1, moving ? {
6023
+ type: "kinematic",
6024
+ output: "none",
6025
+ follow: followLayer(node, world.fps)
6026
+ } : {
6027
+ type: "fixed",
6028
+ output: "none"
6029
+ });
6030
+ const pieces = cells.map((cell) => world.shapedBody(void 0, apply(pose.matrix, cell.centroid), pose.rotation, {
6031
+ kind: "hull",
6032
+ points: cell.hull.map((v, i) => v * pose.scale[i % 3] * .97)
6033
+ }, {
6034
+ type: "dynamic",
6035
+ startFrame: NEVER,
6036
+ output: "none",
6037
+ density: options.density,
6038
+ friction: options.friction,
6039
+ restitution: options.restitution ?? .2
6040
+ }));
6041
+ const fracture = new Fracture3D(target$1, pieces, intact, world);
6042
+ const radius = model.bounds.boundingSphereRadius * Math.max(...pose.scale);
6043
+ world.onStep((f, pairs) => {
6044
+ if (fracture.brokeAt !== void 0) return;
6045
+ const ff = options.fractureFrame ?? "onImpact";
6046
+ const hit = pairs.find(([a, b]) => a === intact && b.type === "dynamic" || b === intact && a.type === "dynamic");
6047
+ const hitter = hit ? hit[0] === intact ? hit[1] : hit[0] : void 0;
6048
+ if (!(ff === "onImpact" ? Boolean(hitter) : f >= ff - world.startFrame)) return;
6049
+ fracture.brokeAt = f;
6050
+ intact.sim.setEnabled(false);
6051
+ breakApart(world, pieces, options, radius, intact, pose, hitter, f);
6052
+ });
6053
+ world.onSimulated(() => {
6054
+ assertRigid(node);
6055
+ spec$1.track = recordTrack(pieces, world.startFrame + world.frames);
6056
+ });
6057
+ return fracture;
6058
+ }
6059
+ /** Where the stand-in is and how it moves (px, quaternion, px/s, rad/s). */
6060
+ function standInState(world, intact) {
6061
+ const ppm = world.pixelsPerMeter;
6062
+ return {
6063
+ position: intact.sim.position().map((v) => v * ppm),
6064
+ rotation: intact.sim.rotation(),
6065
+ velocity: intact.sim.velocity().map((v) => v * ppm),
6066
+ spin: intact.sim.angularVelocity()
6067
+ };
6068
+ }
6069
+ /**
6070
+ * Wakes every piece where the layer is now (the stand-in's pose, which
6071
+ * follows its animation), carrying the layer's own motion, plus a burst
6072
+ * outward from the impact and some of the hitter's momentum.
6073
+ */
6074
+ function breakApart(world, pieces, options, radius, intact, rest, hitter, frame) {
6075
+ const ppm = world.pixelsPerMeter;
6076
+ const layer = standInState(world, intact);
6077
+ const q0 = quatFromEuler(...rest.rotation);
6078
+ const undoRest = [
6079
+ -q0[0],
6080
+ -q0[1],
6081
+ -q0[2],
6082
+ q0[3]
6083
+ ];
6084
+ const hitAt = hitter?.sim.position().map((v) => v * ppm);
6085
+ const transfer = options.momentumTransfer ?? .35;
6086
+ const hitVel = [
6087
+ 0,
6088
+ 0,
6089
+ 0
6090
+ ];
6091
+ if (hitter) {
6092
+ const at = world.startFrame + frame - 1;
6093
+ const rec = hitter.recording;
6094
+ hitVel[0] = rec.channel("vx")[at] ?? 0;
6095
+ hitVel[1] = rec.channel("vy")[at] ?? 0;
6096
+ hitVel[2] = rec.channel("vz")[at] ?? 0;
6097
+ hitter.sim.setVelocity(hitVel.map((v) => v * (1 - transfer) / ppm), hitter.sim.angularVelocity());
6098
+ }
6099
+ const impact = options.impactPoint ?? hitAt ?? layer.position;
6100
+ const speed = options.explosionSpeed ?? 0;
6101
+ const spin = options.spin ?? speed / 3;
6102
+ const rand = createRandom((options.seed ?? 1) * 7717 + 3);
6103
+ for (const piece of pieces) {
6104
+ const c = piece.center();
6105
+ const arm = rotateByQuat(rotateByQuat([
6106
+ c[0] - rest.position[0],
6107
+ c[1] - rest.position[1],
6108
+ c[2] - rest.position[2]
6109
+ ], undoRest), layer.rotation);
6110
+ const p = [
6111
+ layer.position[0] + arm[0],
6112
+ layer.position[1] + arm[1],
6113
+ layer.position[2] + arm[2]
6114
+ ];
6115
+ const w0 = layer.spin;
6116
+ const carried = [
6117
+ layer.velocity[0] + w0[1] * arm[2] - w0[2] * arm[1],
6118
+ layer.velocity[1] + w0[2] * arm[0] - w0[0] * arm[2],
6119
+ layer.velocity[2] + w0[0] * arm[1] - w0[1] * arm[0]
6120
+ ];
6121
+ const d = [
6122
+ p[0] - impact[0],
6123
+ p[1] - impact[1],
6124
+ p[2] - impact[2]
6125
+ ];
6126
+ const dist$2 = Math.hypot(...d) || 1;
6127
+ const falloff = 1 / (1 + (dist$2 / Math.max(1, radius)) ** 2);
6128
+ const v = d.map((x, i) => carried[i] + x / dist$2 * speed * falloff + hitVel[i] * transfer * falloff);
6129
+ const axis = [
6130
+ rand() - .5,
6131
+ rand() - .5,
6132
+ rand() - .5
6133
+ ];
6134
+ const len = Math.hypot(...axis) || 1;
6135
+ const w = axis.map((a, i) => a / len * spin * (.5 + rand()) + w0[i] * 180 / Math.PI);
6136
+ piece.wake(frame, v, w, {
6137
+ position: p,
6138
+ rotation: layer.rotation
6139
+ });
6140
+ }
6141
+ }
6142
+ /** Every piece's pose per composition frame: [x, y, z, qx, qy, qz, qw] each. */
6143
+ function recordTrack(pieces, frames) {
6144
+ const channels = pieces.map((b) => [
6145
+ "x",
6146
+ "y",
6147
+ "z",
6148
+ "qx",
6149
+ "qy",
6150
+ "qz",
6151
+ "qw"
6152
+ ].map((c) => b.recording.channel(c)));
6153
+ const out = new Array(frames * pieces.length * 7);
6154
+ let k = 0;
6155
+ for (let f = 0; f < frames; f++) for (const ch of channels) for (let c = 0; c < 7; c++) {
6156
+ const v = ch[c][f] ?? 0;
6157
+ out[k++] = c < 3 ? Math.round(v * 1e5) / 1e5 : Math.round(v * 1e7) / 1e7;
6158
+ }
6159
+ return out;
6160
+ }
6161
+
5334
6162
  //#endregion
5335
6163
  //#region src/physics/world3d.ts
5336
6164
  const DEG = Math.PI / 180;
@@ -5356,6 +6184,7 @@ function quatFromEuler(rx, ry, rz) {
5356
6184
  Math.cos(half(rz))
5357
6185
  ], qy), qx);
5358
6186
  }
6187
+ /** @internal */
5359
6188
  function quatMul(a, b) {
5360
6189
  const [ax, ay, az, aw] = a;
5361
6190
  const [bx, by, bz, bw] = b;
@@ -5435,7 +6264,32 @@ var PhysicsBody3D = class {
5435
6264
  this.recording = recording;
5436
6265
  }
5437
6266
  get startFrame() {
5438
- return Math.max(0, Math.round(this.options.startFrame ?? 0));
6267
+ return this.wokeAt ?? Math.max(0, Math.round(this.options.startFrame ?? 0));
6268
+ }
6269
+ wokeAt;
6270
+ /**
6271
+ * @internal Starts the body now, mid-simulation (`frame` relative to the
6272
+ * world's start): it moves from the next frame, at this velocity (px/s,
6273
+ * degrees per second), from `pose` (px) when given.
6274
+ */
6275
+ wake(frame, velocity, angularVelocity, pose) {
6276
+ this.wokeAt = frame;
6277
+ const ppm = this.world.pixelsPerMeter;
6278
+ this.sim.setEnabled(true);
6279
+ if (pose) this.sim.setPose([
6280
+ pose.position[0] / ppm,
6281
+ pose.position[1] / ppm,
6282
+ pose.position[2] / ppm
6283
+ ], pose.rotation);
6284
+ this.sim.setVelocity([
6285
+ velocity[0] / ppm,
6286
+ velocity[1] / ppm,
6287
+ velocity[2] / ppm
6288
+ ], [
6289
+ angularVelocity[0] * DEG,
6290
+ angularVelocity[1] * DEG,
6291
+ angularVelocity[2] * DEG
6292
+ ]);
5439
6293
  }
5440
6294
  get gravityScale() {
5441
6295
  return this.options.gravityScale ?? 1;
@@ -5489,17 +6343,17 @@ var PhysicsBody3D = class {
5489
6343
  const follow = this.options.follow;
5490
6344
  if (this.type !== "kinematic" || !follow) return void 0;
5491
6345
  const fps = this.world.fps;
5492
- const read$1 = (d, fallback) => d === void 0 ? fallback : sampleDriver(d, frame, fps);
6346
+ const read$2 = (d, fallback) => d === void 0 ? fallback : sampleDriver(d, frame, fps);
5493
6347
  const p = this.start.position;
5494
6348
  const r = this.start.rotation;
5495
6349
  const ppm = this.world.pixelsPerMeter;
5496
6350
  return {
5497
6351
  position: [
5498
- read$1(follow.x, p[0]) / ppm,
5499
- read$1(follow.y, p[1]) / ppm,
5500
- read$1(follow.z, p[2]) / ppm
6352
+ read$2(follow.x, p[0]) / ppm,
6353
+ read$2(follow.y, p[1]) / ppm,
6354
+ read$2(follow.z, p[2]) / ppm
5501
6355
  ],
5502
- rotation: quatFromEuler(read$1(follow.rotateX, r[0]), read$1(follow.rotateY, r[1]), read$1(follow.rotateZ, r[2]))
6356
+ rotation: quatFromEuler(read$2(follow.rotateX, r[0]), read$2(follow.rotateY, r[1]), read$2(follow.rotateZ, r[2]))
5503
6357
  };
5504
6358
  }
5505
6359
  /** @internal */
@@ -5518,7 +6372,12 @@ var PhysicsBody3D = class {
5518
6372
  ry[previous],
5519
6373
  rz[previous]
5520
6374
  ];
5521
- const e = eulerFromQuat(this.sim.rotation(), prev);
6375
+ const q = this.sim.rotation();
6376
+ rec.channel("qx")[index] = q[0];
6377
+ rec.channel("qy")[index] = q[1];
6378
+ rec.channel("qz")[index] = q[2];
6379
+ rec.channel("qw")[index] = q[3];
6380
+ const e = eulerFromQuat(q, prev);
5522
6381
  rx[index] = e[0];
5523
6382
  ry[index] = e[1];
5524
6383
  rz[index] = e[2];
@@ -5571,6 +6430,7 @@ var PhysicsBody3D = class {
5571
6430
  ];
5572
6431
  }
5573
6432
  };
6433
+ /** @internal */
5574
6434
  function rotateByQuat(v, q) {
5575
6435
  const r = quatMul(quatMul(q, [
5576
6436
  v[0],
@@ -5626,6 +6486,11 @@ var PhysicsWorld3D = class extends WorldCore {
5626
6486
  num$2(options.rotateY ?? t.rotateY, 0),
5627
6487
  num$2(options.rotateZ ?? t.rotateZ, 0)
5628
6488
  ];
6489
+ return this.shapedBody(layer, position, rotation, colliderShape3D(t, options), options);
6490
+ }
6491
+ /** @internal A body with an explicit collider (px), at a pose in px and degrees. */
6492
+ shapedBody(layer, position, rotation, shape$1, options) {
6493
+ this.assertOpen();
5629
6494
  const ppm = this.pixelsPerMeter;
5630
6495
  const type = options.type ?? "dynamic";
5631
6496
  const v = options.velocity ?? [
@@ -5671,15 +6536,37 @@ var PhysicsWorld3D = class extends WorldCore {
5671
6536
  density: options.density ?? 1,
5672
6537
  friction: options.friction ?? .6,
5673
6538
  restitution: options.restitution ?? .3,
5674
- shape: scaleShape(colliderShape3D(t, options), 1 / ppm)
6539
+ shape: scaleShape(shape$1, 1 / ppm)
5675
6540
  };
5676
6541
  const simBody = this.sim.addBody(spec$1);
5677
6542
  const body = new PhysicsBody3D(this, simBody, type, layer, {
5678
6543
  position,
5679
6544
  rotation
5680
6545
  }, options, this.newRecording());
6546
+ const start = body.kinematicTarget(this.startFrame);
6547
+ if (start) simBody.setPose(start.position, start.rotation);
5681
6548
  return this.addBody(body);
5682
6549
  }
6550
+ /** @internal Runs after each simulated frame (frame relative to the world's start). */
6551
+ onStep(hook) {
6552
+ this.assertOpen();
6553
+ this.stepHooks.push(hook);
6554
+ }
6555
+ /** @internal Runs once the simulation has finished. */
6556
+ onSimulated(hook) {
6557
+ this.assertOpen();
6558
+ this.simulatedHooks.push(hook);
6559
+ }
6560
+ /**
6561
+ * Breaks a Layer3D primitive, extruded text or loaded model into Voronoi
6562
+ * pieces that stay together, looking intact, until the fracture frame (or
6563
+ * until something hits it), then fly apart as rigid bodies. The node is
6564
+ * changed in place: add it to the composition as usual. All pieces draw
6565
+ * in one call per material, the cut faces in `interiorColor`.
6566
+ */
6567
+ fracture(target$1, options = {}) {
6568
+ return createFracture(this, target$1, options);
6569
+ }
5683
6570
  /** A fixed, very large floor whose top face sits at `y`. */
5684
6571
  ground(options) {
5685
6572
  const t = 2e3;
@@ -5828,11 +6715,11 @@ var PhysicsWorld3D = class extends WorldCore {
5828
6715
  /** A steady push, px/s² (mass-independent). Drivers are read every frame. */
5829
6716
  force(body, accel) {
5830
6717
  const ppm = this.pixelsPerMeter;
5831
- const read$1 = (d, frame) => d === void 0 ? 0 : sampleDriver(d, frame, this.fps) / ppm;
6718
+ const read$2 = (d, frame) => d === void 0 ? 0 : sampleDriver(d, frame, this.fps) / ppm;
5832
6719
  this.addForce(body, (frame) => [
5833
- read$1(accel.x, frame),
5834
- read$1(accel.y, frame),
5835
- read$1(accel.z, frame)
6720
+ read$2(accel.x, frame),
6721
+ read$2(accel.y, frame),
6722
+ read$2(accel.z, frame)
5836
6723
  ]);
5837
6724
  return this;
5838
6725
  }
@@ -5937,6 +6824,10 @@ function colliderShape3D(t, options) {
5937
6824
  points: pts.map((v, i) => v * scale[i % 3])
5938
6825
  };
5939
6826
  };
6827
+ if (mode === "mesh" || mode === "auto" && (options.type ?? "dynamic") !== "dynamic" && (prim.type === "terrain" || prim.type === "sdf")) {
6828
+ const mesh = meshTriangles(t.modelData, scale);
6829
+ if (mesh) return mesh;
6830
+ }
5940
6831
  if (options.size || mode === "box") {
5941
6832
  const [w, h$1, d] = options.size ?? boxSize(t, prim) ?? [
5942
6833
  0,
@@ -6049,6 +6940,25 @@ function boxSize(t, prim) {
6049
6940
  t.depth
6050
6941
  ];
6051
6942
  }
6943
+ /** All of a model's triangles, scaled: an exact (non-convex) collider. */
6944
+ function meshTriangles(modelData, scale) {
6945
+ const meshes = modelData?.meshes;
6946
+ if (!meshes?.length) return void 0;
6947
+ const vertices = [];
6948
+ const indices = [];
6949
+ for (const m of meshes) {
6950
+ if (!m.positions || !m.indices) continue;
6951
+ if (m.topology && m.topology !== "triangle-list") continue;
6952
+ const base = vertices.length / 3;
6953
+ for (let i = 0; i < m.positions.length; i++) vertices.push(m.positions[i] * scale[i % 3]);
6954
+ for (let i = 0; i < m.indices.length; i++) indices.push(m.indices[i] + base);
6955
+ }
6956
+ return indices.length >= 3 ? {
6957
+ kind: "trimesh",
6958
+ vertices,
6959
+ indices
6960
+ } : void 0;
6961
+ }
6052
6962
  /** Every vertex of a model, flat xyz, at most ~4k points (the hull needs no more). */
6053
6963
  function meshPoints(modelData) {
6054
6964
  const meshes = modelData?.meshes;
@@ -6088,6 +6998,11 @@ function scaleShape(shape$1, s) {
6088
6998
  kind: "hull",
6089
6999
  points: shape$1.points.map((v) => v * s)
6090
7000
  };
7001
+ case "trimesh": return {
7002
+ kind: "trimesh",
7003
+ vertices: shape$1.vertices.map((v) => v * s),
7004
+ indices: shape$1.indices
7005
+ };
6091
7006
  }
6092
7007
  }
6093
7008
 
@@ -8662,7 +9577,7 @@ var Media = class Media {
8662
9577
  return this.virtualMedia;
8663
9578
  }
8664
9579
  /**
8665
- * Renders a single frame from this media pipeline to a PNG Buffer.
9580
+ * Renders a single frame from this media pipeline to an image or raw RGBA Buffer.
8666
9581
  * Can render either by timestamp in milliseconds (`atMs`) or by frame index (`frame`).
8667
9582
  */
8668
9583
  async renderFrame(options = {}) {
@@ -8775,7 +9690,11 @@ var Composition = class Composition {
8775
9690
  vision(sourceOrLayer, options = {}) {
8776
9691
  const source = typeof sourceOrLayer === "string" ? sourceOrLayer : sourceOrLayer.src ?? sourceOrLayer.inputHandleId;
8777
9692
  if (typeof sourceOrLayer !== "string") {
8778
- const layer = collectNodeOps(this.toVirtualMedia({ resolveMediaSignal: this.mediaSignalResolver(true) }).children).find((node) => node.operation.id === sourceOrLayer.id);
9693
+ const found = collectLayersOnClock(this.toVirtualMedia({ resolveMediaSignal: this.mediaSignalResolver(true) }).children).find(({ vm: node }) => node.operation.id === sourceOrLayer.id);
9694
+ const layer = found && { operation: {
9695
+ ...found.vm.operation,
9696
+ startFrame: found.startFrame
9697
+ } };
8779
9698
  if (!layer) throw new Error("Add the media layer to the composition before calling comp.vision(layer)");
8780
9699
  options = {
8781
9700
  startFrame: layer.operation.startFrame ?? sourceOrLayer.startFrame,
@@ -8818,9 +9737,12 @@ var Composition = class Composition {
8818
9737
  if (!node || typeof node !== "object") return;
8819
9738
  const n = node;
8820
9739
  if (n.kind === "media" && n.dataType === "Video" && typeof n.inputHandleId === "string" && n.vision instanceof Vision && !(CLIP_SUBJECT in n.vision)) {
8821
- layers ??= new Map(collectNodeOps(this.toVirtualMedia().children).map((node$1) => {
8822
- const op = node$1.operation;
8823
- return [op.id, op];
9740
+ layers ??= new Map(collectLayersOnClock(this.toVirtualMedia().children).map(({ vm, startFrame }) => {
9741
+ const op = vm.operation;
9742
+ return [op.id, {
9743
+ startFrame,
9744
+ timeRemap: op.timeRemap
9745
+ }];
8824
9746
  }));
8825
9747
  const layer = layers.get(n.id);
8826
9748
  const clip = this.clipForLayer(n.src ?? n.inputHandleId, n.vision, {
@@ -9373,10 +10295,11 @@ var Composition = class Composition {
9373
10295
  return vm;
9374
10296
  }
9375
10297
  /**
9376
- * Renders a single frame from the composition to a PNG Buffer.
10298
+ * Renders a single frame from the composition to an image or raw RGBA Buffer.
9377
10299
  * Can render either by timestamp in milliseconds (`atMs`) or by frame index (`frame`).
9378
10300
  */
9379
- async renderFrame(options = {}) {
10301
+ async renderFrame(frameOrOptions = {}) {
10302
+ const options = typeof frameOrOptions === "number" ? { frame: frameOrOptions } : frameOrOptions;
9380
10303
  const { frame } = resolveFrameRequest(options, this.fps);
9381
10304
  if (options.fps !== void 0 && options.fps !== this.fps) throw new Error(`Composition fps is ${this.fps}; cannot render at fps ${options.fps}.`);
9382
10305
  const vm = this.toVirtualMedia();
@@ -9394,7 +10317,9 @@ var Composition = class Composition {
9394
10317
  }
9395
10318
  return (options.renderer ?? new HeadlessMediaRenderer()).renderFrame(vm, {
9396
10319
  fps: this.fps,
9397
- frame
10320
+ frame,
10321
+ renderId: options.renderId,
10322
+ format: options.format
9398
10323
  });
9399
10324
  }
9400
10325
  /**
@@ -9437,11 +10362,27 @@ var Composition = class Composition {
9437
10362
  * never change. `renderVideo({ qa })` includes these automatically.
9438
10363
  */
9439
10364
  lint() {
9440
- return lintComposition(this.toSpec(), { emojiFont: FontManager.hasEmojiFont() });
10365
+ return lintComposition(this.toSpec(), {
10366
+ emojiFont: FontManager.hasEmojiFont(),
10367
+ scatterCoverage
10368
+ });
9441
10369
  }
9442
10370
  };
9443
10371
  function withAnimation(node) {
9444
10372
  const target$1 = node;
10373
+ const raw = target$1;
10374
+ if (raw.rotationX !== void 0) {
10375
+ if (raw.rotateX === void 0) raw.rotateX = raw.rotationX;
10376
+ delete raw.rotationX;
10377
+ }
10378
+ if (raw.rotationY !== void 0) {
10379
+ if (raw.rotateY === void 0) raw.rotateY = raw.rotationY;
10380
+ delete raw.rotationY;
10381
+ }
10382
+ if (raw.rotationZ !== void 0) {
10383
+ if (raw.rotateZ === void 0) raw.rotateZ = raw.rotationZ;
10384
+ delete raw.rotationZ;
10385
+ }
9445
10386
  if (target$1.animation instanceof LayerAnimation) target$1.animation = target$1.animation.toSpec();
9446
10387
  Object.defineProperty(target$1, "animate", {
9447
10388
  value: (...anims) => {
@@ -9628,8 +10569,89 @@ function withAnimation(node) {
9628
10569
  writable: true,
9629
10570
  configurable: true
9630
10571
  });
10572
+ bindMaterialSignals(target$1);
9631
10573
  return target$1;
9632
10574
  }
10575
+ /**
10576
+ * Numeric surface props a live `Signal` may drive directly (`clearcoat: sig`):
10577
+ * the value written to the node is the static fallback, the signal becomes a
10578
+ * draw-time signal track. `iridescence` counts only when it is the number form.
10579
+ */
10580
+ const MATERIAL_SIGNAL_PROPS = [
10581
+ {
10582
+ prop: "roughness",
10583
+ fallback: .5
10584
+ },
10585
+ {
10586
+ prop: "metallic",
10587
+ fallback: 0
10588
+ },
10589
+ {
10590
+ prop: "emissiveIntensity",
10591
+ fallback: 1
10592
+ },
10593
+ {
10594
+ prop: "clearcoat",
10595
+ fallback: 0
10596
+ },
10597
+ {
10598
+ prop: "clearcoatRoughness",
10599
+ fallback: .08
10600
+ },
10601
+ {
10602
+ prop: "anisotropy",
10603
+ fallback: 0
10604
+ },
10605
+ {
10606
+ prop: "anisotropyRotation",
10607
+ fallback: 0
10608
+ },
10609
+ {
10610
+ prop: "subsurface",
10611
+ fallback: 0
10612
+ },
10613
+ {
10614
+ prop: "sheen",
10615
+ fallback: 0
10616
+ },
10617
+ {
10618
+ prop: "sheenRoughness",
10619
+ fallback: .5
10620
+ },
10621
+ {
10622
+ prop: "iridescence",
10623
+ fallback: 0
10624
+ },
10625
+ {
10626
+ prop: "iridescenceThickness",
10627
+ fallback: 400
10628
+ },
10629
+ {
10630
+ prop: "iridescenceIor",
10631
+ fallback: 1.3
10632
+ },
10633
+ {
10634
+ prop: "triplanarScale",
10635
+ fallback: 1
10636
+ },
10637
+ {
10638
+ prop: "triplanarSharpness",
10639
+ fallback: 4
10640
+ }
10641
+ ];
10642
+ /** Moves signal-valued material props of a node onto signal tracks. */
10643
+ function bindMaterialSignals(target$1) {
10644
+ const raw = target$1;
10645
+ let anim;
10646
+ for (const { prop, fallback } of MATERIAL_SIGNAL_PROPS) {
10647
+ const val = raw[prop];
10648
+ if (!isSignalLike(val)) continue;
10649
+ anim ??= LayerAnimation.create();
10650
+ anim.signal(prop, val);
10651
+ raw[prop] = fallback;
10652
+ }
10653
+ if (anim) target$1.animate(anim);
10654
+ }
9633
10655
  const Layer = {
9634
10656
  video: (src, options = {}) => withAnimation({
9635
10657
  id: options.id ?? autoId("video"),
@@ -9907,29 +10929,42 @@ const Layer = {
9907
10929
  });
9908
10930
  },
9909
10931
  chart: (options, props = {}) => buildChart(options, props, FontManager.getAll()[0]?.family ?? "Inter"),
9910
- camera: (options = {}) => withAnimation({
9911
- id: options.id ?? autoId("camera"),
9912
- kind: "camera",
9913
- mode: options.mode ?? "lookAt",
9914
- pitch: options.pitch ?? 0,
9915
- yaw: options.yaw ?? 0,
9916
- roll: options.roll ?? 0,
9917
- ...options
9918
- }),
9919
- light: (options = {}) => withAnimation({
10932
+ camera: (options = {}) => {
10933
+ const { fov, focalLength, sensorWidth, near, far, zoom, lens: existingLens, ...rest } = options;
10934
+ const mergedLens = fov !== void 0 || focalLength !== void 0 || sensorWidth !== void 0 || near !== void 0 || far !== void 0 || zoom !== void 0 || existingLens !== void 0 ? {
10935
+ ...existingLens,
10936
+ ...fov !== void 0 && { fov },
10937
+ ...focalLength !== void 0 && { focalLength },
10938
+ ...sensorWidth !== void 0 && { sensorWidth },
10939
+ ...near !== void 0 && { near },
10940
+ ...far !== void 0 && { far },
10941
+ ...zoom !== void 0 && { zoom }
10942
+ } : void 0;
10943
+ return withAnimation({
10944
+ id: rest.id ?? autoId("camera"),
10945
+ kind: "camera",
10946
+ mode: rest.mode ?? "lookAt",
10947
+ pitch: rest.pitch ?? 0,
10948
+ yaw: rest.yaw ?? 0,
10949
+ roll: rest.roll ?? 0,
10950
+ ...rest,
10951
+ ...mergedLens !== void 0 && { lens: mergedLens }
10952
+ });
10953
+ },
10954
+ light: (options = {}) => buildLightNode({
9920
10955
  id: options.id ?? autoId("light"),
9921
10956
  kind: "light",
9922
10957
  lightType: options.lightType ?? "point",
9923
10958
  color: options.color ?? "#ffffff",
9924
- intensity: options.intensity ?? 1,
9925
- ...options
9926
- }),
10959
+ intensity: 1
10960
+ }, options),
9927
10961
  ambientLight: (color$1 = "#ffffff", intensity = .5, options = {}) => Light.ambient(color$1, intensity, options),
9928
10962
  sequence: (entries, options) => sequence(entries, options),
9929
10963
  environment: (presetOrOptions = "studio", options = {}) => Light.environment(presetOrOptions, options),
9930
10964
  directionalLight: (options = {}) => Light.directional(options),
9931
10965
  pointLight: (options = {}) => Light.point(options),
9932
10966
  spotLight: (options = {}) => Light.spot(options),
10967
+ rectLight: (options = {}) => Light.rect(options),
9933
10968
  cube: (options) => Layer3D.cube(options),
9934
10969
  carousel3d: (options) => Layer3D.carousel(options),
9935
10970
  plane3d: (options) => Layer3D.plane(options),
@@ -9993,78 +11028,220 @@ const Layer = {
9993
11028
  ...options
9994
11029
  })
9995
11030
  };
11031
+ function isHdriPath(value) {
11032
+ return /\.(hdr|exr)$/i.test(value);
11033
+ }
11034
+ const LIGHT_SIGNAL_PROPS = [
11035
+ {
11036
+ prop: "intensity",
11037
+ fallback: 1
11038
+ },
11039
+ {
11040
+ prop: "x",
11041
+ fallback: 0
11042
+ },
11043
+ {
11044
+ prop: "y",
11045
+ fallback: 0
11046
+ },
11047
+ {
11048
+ prop: "z",
11049
+ fallback: 0
11050
+ },
11051
+ {
11052
+ prop: "targetX",
11053
+ fallback: 0
11054
+ },
11055
+ {
11056
+ prop: "targetY",
11057
+ fallback: 0
11058
+ },
11059
+ {
11060
+ prop: "targetZ",
11061
+ fallback: 0
11062
+ },
11063
+ {
11064
+ prop: "radius",
11065
+ fallback: 1e3
11066
+ },
11067
+ {
11068
+ prop: "angle",
11069
+ fallback: 45
11070
+ },
11071
+ {
11072
+ prop: "penumbra",
11073
+ fallback: .2
11074
+ },
11075
+ {
11076
+ prop: "decay",
11077
+ fallback: 1
11078
+ },
11079
+ {
11080
+ prop: "width",
11081
+ fallback: 240
11082
+ },
11083
+ {
11084
+ prop: "height",
11085
+ fallback: 140
11086
+ },
11087
+ {
11088
+ prop: "rotation",
11089
+ fallback: 0
11090
+ },
11091
+ {
11092
+ prop: "exposure",
11093
+ fallback: 0
11094
+ },
11095
+ {
11096
+ prop: "volumetricFogDensity",
11097
+ fallback: .02
11098
+ },
11099
+ {
11100
+ prop: "volumetricFogAnisotropy",
11101
+ fallback: .55
11102
+ },
11103
+ {
11104
+ prop: "volumetricFogNoiseStrength",
11105
+ fallback: .45
11106
+ }
11107
+ ];
11108
+ function isSignalLike(val) {
11109
+ if (!val || typeof val !== "object") return false;
11110
+ const obj = val;
11111
+ return typeof obj.get === "function" || typeof obj.inputHandleId === "string" || typeof obj.gpuBinding === "object";
11112
+ }
11113
+ function buildLightNode(defaults, rawOpts) {
11114
+ const cleaned = {
11115
+ ...defaults,
11116
+ ...rawOpts
11117
+ };
11118
+ const signalBindings = [];
11119
+ for (const { prop, fallback } of LIGHT_SIGNAL_PROPS) {
11120
+ const val = cleaned[prop];
11121
+ if (isSignalLike(val)) {
11122
+ signalBindings.push([prop, val]);
11123
+ const defVal = defaults[prop];
11124
+ cleaned[prop] = typeof defVal === "number" ? defVal : fallback;
11125
+ }
11126
+ }
11127
+ const rawVf = cleaned.volumetricFog;
11128
+ if (rawVf && typeof rawVf === "object") {
11129
+ const vfCopy = { ...rawVf };
11130
+ if (isSignalLike(vfCopy.density)) {
11131
+ signalBindings.push(["volumetricFogDensity", vfCopy.density]);
11132
+ vfCopy.density = .02;
11133
+ }
11134
+ if (isSignalLike(vfCopy.anisotropy)) {
11135
+ signalBindings.push(["volumetricFogAnisotropy", vfCopy.anisotropy]);
11136
+ vfCopy.anisotropy = .55;
11137
+ }
11138
+ if (vfCopy.noise && typeof vfCopy.noise === "object") {
11139
+ const noiseCopy = { ...vfCopy.noise };
11140
+ if (isSignalLike(noiseCopy.strength)) {
11141
+ signalBindings.push(["volumetricFogNoiseStrength", noiseCopy.strength]);
11142
+ noiseCopy.strength = .45;
11143
+ }
11144
+ vfCopy.noise = noiseCopy;
11145
+ }
11146
+ cleaned.volumetricFog = vfCopy;
11147
+ }
11148
+ let node = withAnimation(cleaned);
11149
+ if (signalBindings.length > 0) {
11150
+ const anim = LayerAnimation.create();
11151
+ for (const [prop, sig] of signalBindings) anim.signal(prop, sig);
11152
+ node = node.animate(anim);
11153
+ }
11154
+ return node;
11155
+ }
9996
11156
  const Light = {
9997
11157
  environment: (presetOrOptions = "studio", options = {}) => {
9998
- const opts = typeof presetOrOptions === "string" ? {
9999
- preset: presetOrOptions,
10000
- ...options
10001
- } : {
10002
- ...presetOrOptions,
11158
+ const opts = {
11159
+ ...typeof presetOrOptions !== "string" ? presetOrOptions : isHdriPath(presetOrOptions) ? { hdri: presetOrOptions } : { preset: presetOrOptions },
10003
11160
  ...options
10004
11161
  };
10005
- return withAnimation({
11162
+ return buildLightNode({
11163
+ id: opts.id ?? autoId("environment"),
10006
11164
  kind: "light",
10007
11165
  lightType: "environment",
10008
11166
  preset: "studio",
10009
- intensity: 1,
10010
- ...opts,
10011
- id: opts.id ?? autoId("environment")
10012
- });
11167
+ intensity: 1
11168
+ }, opts);
10013
11169
  },
10014
- ambient: (color$1 = "#ffffff", intensity = .5, options = {}) => withAnimation({
10015
- id: options.id ?? autoId("light-ambient"),
10016
- kind: "light",
10017
- lightType: "ambient",
10018
- color: typeof color$1 === "string" ? color$1 : color$1.color ?? "#ffffff",
10019
- intensity,
10020
- ...typeof color$1 === "object" && color$1,
10021
- ...options
10022
- }),
10023
- directional: (options = {}) => withAnimation({
11170
+ ambient: (color$1 = "#ffffff", intensity = .5, options = {}) => {
11171
+ const merged = {
11172
+ color: typeof color$1 === "string" ? color$1 : color$1.color ?? "#ffffff",
11173
+ intensity,
11174
+ ...typeof color$1 === "object" && color$1,
11175
+ ...options
11176
+ };
11177
+ return buildLightNode({
11178
+ id: merged.id ?? autoId("light-ambient"),
11179
+ kind: "light",
11180
+ lightType: "ambient",
11181
+ color: "#ffffff",
11182
+ intensity: .5
11183
+ }, merged);
11184
+ },
11185
+ directional: (options = {}) => buildLightNode({
10024
11186
  id: options.id ?? autoId("light-directional"),
10025
11187
  kind: "light",
10026
11188
  lightType: "directional",
10027
11189
  color: options.color ?? "#ffffff",
10028
- intensity: options.intensity ?? 1,
10029
- x: options.x ?? 0,
10030
- y: options.y ?? -1e3,
10031
- z: options.z ?? -1e3,
10032
- targetX: options.targetX ?? 0,
10033
- targetY: options.targetY ?? 0,
10034
- targetZ: options.targetZ ?? 0,
10035
- ...options
10036
- }),
10037
- point: (options = {}) => withAnimation({
11190
+ intensity: 1,
11191
+ x: 0,
11192
+ y: -1e3,
11193
+ z: -1e3,
11194
+ targetX: 0,
11195
+ targetY: 0,
11196
+ targetZ: 0
11197
+ }, options),
11198
+ point: (options = {}) => buildLightNode({
10038
11199
  id: options.id ?? autoId("light-point"),
10039
11200
  kind: "light",
10040
11201
  lightType: "point",
10041
11202
  color: options.color ?? "#ffffff",
10042
- intensity: options.intensity ?? 1,
10043
- x: options.x ?? 0,
10044
- y: options.y ?? 0,
10045
- z: options.z ?? -500,
10046
- radius: options.radius ?? 1e3,
10047
- decay: options.decay ?? 1,
10048
- ...options
10049
- }),
10050
- spot: (options = {}) => withAnimation({
11203
+ intensity: 1,
11204
+ x: 0,
11205
+ y: 0,
11206
+ z: -500,
11207
+ radius: 1e3,
11208
+ decay: 1
11209
+ }, options),
11210
+ spot: (options = {}) => buildLightNode({
10051
11211
  id: options.id ?? autoId("light-spot"),
10052
11212
  kind: "light",
10053
11213
  lightType: "spot",
10054
11214
  color: options.color ?? "#ffffff",
10055
- intensity: options.intensity ?? 1,
10056
- x: options.x ?? 0,
10057
- y: options.y ?? -500,
10058
- z: options.z ?? -1e3,
10059
- targetX: options.targetX ?? 0,
10060
- targetY: options.targetY ?? 0,
10061
- targetZ: options.targetZ ?? 0,
10062
- angle: options.angle ?? 45,
10063
- penumbra: options.penumbra ?? .2,
10064
- radius: options.radius ?? 2e3,
10065
- decay: options.decay ?? 1,
10066
- ...options
10067
- })
11215
+ intensity: 1,
11216
+ x: 0,
11217
+ y: -500,
11218
+ z: -1e3,
11219
+ targetX: 0,
11220
+ targetY: 0,
11221
+ targetZ: 0,
11222
+ angle: 45,
11223
+ penumbra: .2,
11224
+ radius: 2e3,
11225
+ decay: 1
11226
+ }, options),
11227
+ rect: (options = {}) => buildLightNode({
11228
+ id: options.id ?? autoId("light-rect"),
11229
+ kind: "light",
11230
+ lightType: "rect",
11231
+ color: options.color ?? "#ffffff",
11232
+ intensity: 1,
11233
+ x: 0,
11234
+ y: -300,
11235
+ z: -800,
11236
+ targetX: 0,
11237
+ targetY: 0,
11238
+ targetZ: 0,
11239
+ width: 240,
11240
+ height: 140,
11241
+ twoSided: false,
11242
+ radius: 2e3,
11243
+ decay: 1.5
11244
+ }, options)
10068
11245
  };
10069
11246
  function section(source, targetOrOptions = {}, options = {}) {
10070
11247
  return Layer.section(source, targetOrOptions, options);
@@ -10105,5 +11282,5 @@ const Effect = Object.assign(Effect$1, effectFactories, {
10105
11282
  });
10106
11283
 
10107
11284
  //#endregion
10108
- export { glyphAnimator as $, wordRanges as $t, boilKeys as A, squigglePath as At, defineTheme as B, themes as Bt, audioLevelsSchema as C, span as Cn, scaleFrames as Ct, basePropsSchema as D, FRAMEFIELDS_AI_PROXY_URL as Dn, springKeys as Dt, bandEdges as E, ApiError as En, springAt as Et, constantExpression as F, surfaceFill as Ft, elevationStyle as G, transparent as Gt, drawOnKeys as H, toPathData as Ht, contrastRatio as I, targetPoint as It, evaluateEase as J, windowExpression as Jt, ellipsePath as K, typingFrames as Kt, cover as L, targetSchema as Lt, boxPath as M, staggerRanks as Mt, catmullRom as N, stepExpression as Nt, beats as O, ValidationError as On, springSettleFrames as Ot, chain as P, supersede as Pt, frameSpan as Q, wobblePoints as Qt, defineComponent as R, textLayout as Rt, ascending as S, size as Sn, safeArea as St, bakeSamples as T, sup as Tn, smoothRelease as Tt, ease as U, toSeconds as Ut, dist as V, toFrames as Vt, elevate as W, transformPathData as Wt, exitAnimation as X, withDefaults as Xt, evaluateGlyphExpression as Y, withAlpha as Yt, findRange as Z, within as Zt, after as _, italic as _n, resampleBands as _t, Media as a, PhysicsWorld2D as an, last as at, arcPath as b, parseMarkup as bn, rng as bt, section as c, Layer3D as cn, lineShift as ct, analyzeAudio as d, PersonTrack as dn, offsetCues as dt, Styles as en, hashRng as et, KeyBook as f, DEFAULT_CHART_COLORS as fn, parseColor as ft, UNIT_INDEX as g, color as gn, rendererChars as gt, Track as h, code as hn, rangeRects as ht, Light as i, PhysicsBody2D as in, isLight as it, boundsOf as j, staggerOffsets as jt, bind as k, ai as kn, springTrack as kt, bindComponent as l, Particles as ln, luminance as lt, SAFE_INSETS as m, bold as mn, quantize as mt, Effect as n, PhysicsBody3D as nn, holdFirstKeys as nt, blurRegion as o, Lighting as on, lerp2 as ot, MOTION_PRESETS as p, accent as pn, pulseKeys as pt, enterAnimation as q, valueAt as qt, Layer as r, PhysicsWorld3D as rn, inkOn as rt, editTrackedRegion as s, Transition as sn, linePath as st, Composition as t, Physics as tn, hashString as tt, z$2 as u, ClipVision as un, mix as ut, analyzeChannels as v, mark as vn, resolveMotion as vt, bakeFunction as w, sub as wn, scheduleExpression as wt, arrowPaths as x, rich as xn, round as xt, anchorPoint as y, normalizeTextSpans as yn, resolveTarget as yt, defineMeta as z, themeFrames as zt };
10109
- //# sourceMappingURL=src-DrP7fGJX.mjs.map
11285
+ export { glyphAnimator as $, wordRanges as $t, boilKeys as A, FRAMEFIELDS_AI_PROXY_URL as An, squigglePath as At, defineTheme as B, themes as Bt, audioLevelsSchema as C, parseMarkup as Cn, scaleFrames as Ct, basePropsSchema as D, sub as Dn, springKeys as Dt, bandEdges as E, span as En, springAt as Et, constantExpression as F, surfaceFill as Ft, elevationStyle as G, transparent as Gt, drawOnKeys as H, toPathData as Ht, contrastRatio as I, targetPoint as It, evaluateEase as J, windowExpression as Jt, ellipsePath as K, typingFrames as Kt, cover as L, targetSchema as Lt, boxPath as M, ai as Mn, staggerRanks as Mt, catmullRom as N, stepExpression as Nt, beats as O, sup as On, springSettleFrames as Ot, chain as P, supersede as Pt, frameSpan as Q, wobblePoints as Qt, defineComponent as R, textLayout as Rt, ascending as S, normalizeTextSpans as Sn, safeArea as St, bakeSamples as T, size as Tn, smoothRelease as Tt, ease as U, toSeconds as Ut, dist as V, toFrames as Vt, elevate as W, transformPathData as Wt, exitAnimation as X, withDefaults as Xt, evaluateGlyphExpression as Y, withAlpha as Yt, findRange as Z, within as Zt, after as _, bold as _n, resampleBands as _t, Media as a, PhysicsBody2D as an, last as at, arcPath as b, italic as bn, rng as bt, section as c, Transition as cn, lineShift as ct, analyzeAudio as d, ClipVision as dn, offsetCues as dt, Styles as en, hashRng as et, KeyBook as f, PersonTrack as fn, parseColor as ft, UNIT_INDEX as g, accent as gn, rendererChars as gt, Track as h, DEFAULT_CHART_COLORS as hn, rangeRects as ht, Light as i, Fracture3D as in, isLight as it, boundsOf as j, ValidationError as jn, staggerOffsets as jt, bind as k, ApiError as kn, springTrack as kt, bindComponent as l, Layer3D as ln, luminance as lt, SAFE_INSETS as m, retargetPose as mn, quantize as mt, Effect as n, PhysicsBody3D as nn, holdFirstKeys as nt, blurRegion as o, PhysicsWorld2D as on, lerp2 as ot, MOTION_PRESETS as p, RIG_PRESETS as pn, pulseKeys as pt, enterAnimation as q, valueAt as qt, Layer as r, PhysicsWorld3D as rn, inkOn as rt, editTrackedRegion as s, Lighting as sn, linePath as st, Composition as t, Physics as tn, hashString as tt, z$2 as u, Particles as un, mix as ut, analyzeChannels as v, code as vn, resolveMotion as vt, bakeFunction as w, rich as wn, scheduleExpression as wt, arrowPaths as x, mark as xn, round as xt, anchorPoint as y, color as yn, resolveTarget as yt, defineMeta as z, themeFrames as zt };
11286
+ //# sourceMappingURL=src-CoHAjviq.mjs.map