framefields 2.14.0 → 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 (334) hide show
  1. package/NOTICE.md +5 -1
  2. package/dist/audio/index.d.mts +3 -3
  3. package/dist/audio/index.mjs +10 -10
  4. package/dist/{audio-DFwRbID_.mjs → audio-6TfPlfl4.mjs} +3 -3
  5. package/dist/{audio-DFwRbID_.mjs.map → audio-6TfPlfl4.mjs.map} +1 -1
  6. package/dist/{audio-CdCuGK5d.d.mts → audio-7oqTUi4G.d.mts} +2 -2
  7. package/dist/{audio-CdCuGK5d.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 +11 -11
  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-B8Nby2CU.mjs → dist-COOpgG9G.mjs} +4 -3
  19. package/dist/{dist-B8Nby2CU.mjs.map → dist-COOpgG9G.mjs.map} +1 -1
  20. package/dist/{dist--Uu5bQ_6.mjs → dist-XqlFM2a8.mjs} +13733 -5323
  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 +4 -4
  26. package/dist/effects/index.mjs +35 -35
  27. package/dist/{effects-WMgv8ZaD.mjs → effects-DlRMovU5.mjs} +2 -2
  28. package/dist/{effects-WMgv8ZaD.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-OW3yAfO5.mjs → fonts-BWYcXjyK.mjs} +3 -3
  32. package/dist/fonts-BWYcXjyK.mjs.map +1 -0
  33. package/dist/{gpu-R4T2Tndu.mjs → gpu-CH1PdM4T.mjs} +2 -2
  34. package/dist/{gpu-R4T2Tndu.mjs.map → gpu-CH1PdM4T.mjs.map} +1 -1
  35. package/dist/{index-CEKxvGY-.d.mts → index-BHTycml5.d.mts} +2 -2
  36. package/dist/{index-CEKxvGY-.d.mts.map → index-BHTycml5.d.mts.map} +1 -1
  37. package/dist/{index-DoP6EiHj.d.mts → index-BcxxxwhV.d.mts} +4 -4
  38. package/dist/{index-DoP6EiHj.d.mts.map → index-BcxxxwhV.d.mts.map} +1 -1
  39. package/dist/{index-Bv7gxGK1.d.mts → index-BnB_Ou2y.d.mts} +2 -2
  40. package/dist/index-BnB_Ou2y.d.mts.map +1 -0
  41. package/dist/index-C-V6CAhP.d.mts.map +1 -1
  42. package/dist/{index-D1FqV1eu.d.mts → index-CMhkkc56.d.mts} +43 -11
  43. package/dist/index-CMhkkc56.d.mts.map +1 -0
  44. package/dist/{index-B0Vq8Bwf.d.mts → index-CYVpYGM-.d.mts} +2 -2
  45. package/dist/{index-B0Vq8Bwf.d.mts.map → index-CYVpYGM-.d.mts.map} +1 -1
  46. package/dist/{index-C7-p9zwU.d.mts → index-DhL7ckvs.d.mts} +5 -5
  47. package/dist/index-DhL7ckvs.d.mts.map +1 -0
  48. package/dist/{index-9xte4JgL.d.mts → index-DkAjKnhW.d.mts} +1464 -559
  49. package/dist/index-DkAjKnhW.d.mts.map +1 -0
  50. package/dist/{index-GA9_Z8Fn.d.mts → index-RILu3ULT.d.mts} +2 -2
  51. package/dist/{index-GA9_Z8Fn.d.mts.map → index-RILu3ULT.d.mts.map} +1 -1
  52. package/dist/{index-C5sgRLlG.d.mts → index-TCtdSXd7.d.mts} +3 -1
  53. package/dist/index-TCtdSXd7.d.mts.map +1 -0
  54. package/dist/{index-CRaydvLi.d.mts → index-s2qQ8ifZ.d.mts} +886 -51
  55. package/dist/index-s2qQ8ifZ.d.mts.map +1 -0
  56. package/dist/index.d.mts +13 -13
  57. package/dist/index.mjs +52 -52
  58. package/dist/preview/index.d.mts +3 -3
  59. package/dist/preview/index.mjs +10 -10
  60. package/dist/preview-BeGF1Bb1.mjs +1002 -0
  61. package/dist/preview-BeGF1Bb1.mjs.map +1 -0
  62. package/dist/preview-engine/audio.mjs +1 -1
  63. package/dist/preview-engine/{chunk-64L4GUOF.mjs → chunk-4F3DG6YB.mjs} +2 -2
  64. package/dist/preview-engine/chunk-A2OTOW3B.mjs +4694 -0
  65. package/dist/preview-engine/{chunk-GNDE3OXQ.mjs → chunk-BR56TQBP.mjs} +1 -1
  66. package/dist/preview-engine/{chunk-ADLIF544.mjs → chunk-H2XKXXAU.mjs} +1 -1
  67. package/dist/preview-engine/chunk-NDUODAY2.mjs +3 -0
  68. package/dist/preview-engine/{chunk-FZ4RD7HV.mjs → chunk-QAQJSWUT.mjs} +1 -1
  69. package/dist/preview-engine/chunk-SWRGQTVC.mjs +138 -0
  70. package/dist/preview-engine/{chunk-52X7SURQ.mjs → chunk-TEA3GVBJ.mjs} +1 -1
  71. package/dist/preview-engine/chunk-VM2ZBPLM.mjs +644 -0
  72. package/dist/preview-engine/{chunk-UBY2UYEL.mjs → chunk-XSHNQJ7L.mjs} +1 -1
  73. package/dist/preview-engine/components.mjs +1 -1
  74. package/dist/preview-engine/effects.mjs +1 -1
  75. package/dist/preview-engine/fonts.mjs +1 -1
  76. package/dist/preview-engine/framefields.mjs +1 -1
  77. package/dist/preview-engine/player.mjs +2 -2
  78. package/dist/preview-engine/{renderers-DU7KPFVV.mjs → renderers-6C7NWWDX.mjs} +1 -1
  79. package/dist/preview-engine/renderers-HHVGNMSJ.mjs +206 -0
  80. package/dist/preview-engine/{src-YXNX4MLK.mjs → src-RCNEKIRP.mjs} +1 -1
  81. package/dist/preview-page/index.html +19 -0
  82. package/dist/preview-page/main.css +1 -0
  83. package/dist/preview-page/main.js +327 -0
  84. package/dist/{program-tFKCWU2j.mjs → program-CMigyfso.mjs} +829 -52
  85. package/dist/program-CMigyfso.mjs.map +1 -0
  86. package/dist/renderer/index.d.mts +2 -2
  87. package/dist/renderer/index.mjs +2 -2
  88. package/dist/{renderer-DkOuQi84.mjs → renderer-0GMEL_Zi.mjs} +3 -3
  89. package/dist/{renderer-DkOuQi84.mjs.map → renderer-0GMEL_Zi.mjs.map} +1 -1
  90. package/dist/{renderer-BGp0An5A.mjs → renderer-3Wv2ZBJG.mjs} +3 -3
  91. package/dist/{renderer-BGp0An5A.mjs.map → renderer-3Wv2ZBJG.mjs.map} +1 -1
  92. package/dist/{renderer-BVIXKfbC.mjs → renderer-4nXkaAWu.mjs} +1178 -199
  93. package/dist/renderer-4nXkaAWu.mjs.map +1 -0
  94. package/dist/{renderer-Cw6_NL2i.mjs → renderer-6SnfLXeg.mjs} +3 -3
  95. package/dist/{renderer-Cw6_NL2i.mjs.map → renderer-6SnfLXeg.mjs.map} +1 -1
  96. package/dist/{renderer-BVU22lBS.mjs → renderer-8gHw3O0P.mjs} +2 -2
  97. package/dist/{renderer-BVU22lBS.mjs.map → renderer-8gHw3O0P.mjs.map} +1 -1
  98. package/dist/{renderer-BjDddtw9.mjs → renderer-AOBglZHC.mjs} +2 -2
  99. package/dist/{renderer-D-KHHWQD.mjs → renderer-B0bSARK3.mjs} +3 -3
  100. package/dist/{renderer-D-KHHWQD.mjs.map → renderer-B0bSARK3.mjs.map} +1 -1
  101. package/dist/{renderer-CCxk-RJR.mjs → renderer-B2_tuRfl.mjs} +2 -2
  102. package/dist/{renderer-CCxk-RJR.mjs.map → renderer-B2_tuRfl.mjs.map} +1 -1
  103. package/dist/{renderer-k5d7JSbs.mjs → renderer-B82FhkEr.mjs} +3 -3
  104. package/dist/{renderer-k5d7JSbs.mjs.map → renderer-B82FhkEr.mjs.map} +1 -1
  105. package/dist/{renderer-I0Hh9cLK.mjs → renderer-B9lzA0PY.mjs} +3 -3
  106. package/dist/{renderer-I0Hh9cLK.mjs.map → renderer-B9lzA0PY.mjs.map} +1 -1
  107. package/dist/{renderer-Dwwnx7Dk.mjs → renderer-BBSIWSry.mjs} +2 -2
  108. package/dist/{renderer-Dwwnx7Dk.mjs.map → renderer-BBSIWSry.mjs.map} +1 -1
  109. package/dist/{renderer-_pC-jB9O.mjs → renderer-BEKDMxbi.mjs} +2 -2
  110. package/dist/{renderer-_pC-jB9O.mjs.map → renderer-BEKDMxbi.mjs.map} +1 -1
  111. package/dist/renderer-BERGAxqA.mjs +5 -0
  112. package/dist/{renderer-raxwsiGI.mjs → renderer-BF960HY8.mjs} +3 -3
  113. package/dist/{renderer-raxwsiGI.mjs.map → renderer-BF960HY8.mjs.map} +1 -1
  114. package/dist/{renderer-Dr0tXA4k.mjs → renderer-BFwyVxCu.mjs} +3 -3
  115. package/dist/{renderer-Dr0tXA4k.mjs.map → renderer-BFwyVxCu.mjs.map} +1 -1
  116. package/dist/{renderer-DEjo6dw_.mjs → renderer-BNiwcI3-.mjs} +2 -2
  117. package/dist/{renderer-DEjo6dw_.mjs.map → renderer-BNiwcI3-.mjs.map} +1 -1
  118. package/dist/{renderer-DIEeHiQA.mjs → renderer-BPbVb2Q4.mjs} +2 -2
  119. package/dist/{renderer-DIEeHiQA.mjs.map → renderer-BPbVb2Q4.mjs.map} +1 -1
  120. package/dist/renderer-BQ_YkBMt.mjs +6 -0
  121. package/dist/{renderer-BBMtmxks.mjs → renderer-BUWxlA8T.mjs} +3 -3
  122. package/dist/{renderer-BBMtmxks.mjs.map → renderer-BUWxlA8T.mjs.map} +1 -1
  123. package/dist/renderer-BW0Tjsv9.mjs +5 -0
  124. package/dist/{renderer-Dgj46uEU.mjs → renderer-BX8liu-e.mjs} +2 -2
  125. package/dist/{renderer-ZnrEfkYh.mjs → renderer-BXIwDAr_.mjs} +2 -2
  126. package/dist/{renderer-ZnrEfkYh.mjs.map → renderer-BXIwDAr_.mjs.map} +1 -1
  127. package/dist/{renderer-DA8YEo_d.mjs → renderer-B_Hy1W-g.mjs} +3 -3
  128. package/dist/{renderer-DA8YEo_d.mjs.map → renderer-B_Hy1W-g.mjs.map} +1 -1
  129. package/dist/{renderer-iMiYStcW.mjs → renderer-Bb6cvSgh.mjs} +2 -2
  130. package/dist/{renderer-iMiYStcW.mjs.map → renderer-Bb6cvSgh.mjs.map} +1 -1
  131. package/dist/{renderer-BacY4nh8.mjs → renderer-BdppwWC9.mjs} +2 -2
  132. package/dist/{renderer-BacY4nh8.mjs.map → renderer-BdppwWC9.mjs.map} +1 -1
  133. package/dist/{renderer-CrxwW6VQ.mjs → renderer-Bhc24HVe.mjs} +3 -3
  134. package/dist/{renderer-CrxwW6VQ.mjs.map → renderer-Bhc24HVe.mjs.map} +1 -1
  135. package/dist/{renderer-BH7UCMPQ.mjs → renderer-BiNA2wF0.mjs} +2 -2
  136. package/dist/{renderer-BH7UCMPQ.mjs.map → renderer-BiNA2wF0.mjs.map} +1 -1
  137. package/dist/{renderer-DVPgWHZw.mjs → renderer-BmoBgTp5.mjs} +3 -3
  138. package/dist/{renderer-DVPgWHZw.mjs.map → renderer-BmoBgTp5.mjs.map} +1 -1
  139. package/dist/{renderer-C20efMI0.mjs → renderer-BmqFmCWS.mjs} +3 -3
  140. package/dist/{renderer-C20efMI0.mjs.map → renderer-BmqFmCWS.mjs.map} +1 -1
  141. package/dist/{renderer-B0yVUOPP.mjs → renderer-BnVwAObV.mjs} +2 -2
  142. package/dist/{renderer-B0yVUOPP.mjs.map → renderer-BnVwAObV.mjs.map} +1 -1
  143. package/dist/{renderer-CP8wLzTU.mjs → renderer-BxttZHme.mjs} +2 -2
  144. package/dist/{renderer-CP8wLzTU.mjs.map → renderer-BxttZHme.mjs.map} +1 -1
  145. package/dist/renderer-BzyPdUD1.mjs +5 -0
  146. package/dist/renderer-C0hM-mtY.mjs +5 -0
  147. package/dist/renderer-C6cyUTvk.mjs +5 -0
  148. package/dist/{renderer-BOSZAdgF.mjs → renderer-C8E4XsSg.mjs} +2 -2
  149. package/dist/{renderer-BOSZAdgF.mjs.map → renderer-C8E4XsSg.mjs.map} +1 -1
  150. package/dist/renderer-C8zY3pzk.mjs +5 -0
  151. package/dist/{renderer-DWq9gYRw.mjs → renderer-C9U-LY50.mjs} +3 -3
  152. package/dist/{renderer-DWq9gYRw.mjs.map → renderer-C9U-LY50.mjs.map} +1 -1
  153. package/dist/{renderer-Dj2H5JPR.mjs → renderer-CB2JVu5x.mjs} +3 -3
  154. package/dist/{renderer-Dj2H5JPR.mjs.map → renderer-CB2JVu5x.mjs.map} +1 -1
  155. package/dist/{renderer-Bcu3UrI-.mjs → renderer-CC4YBJ8Z.mjs} +3 -3
  156. package/dist/{renderer-Bcu3UrI-.mjs.map → renderer-CC4YBJ8Z.mjs.map} +1 -1
  157. package/dist/renderer-CEkSOyKu.mjs +5 -0
  158. package/dist/{renderer-DzLrvCB2.mjs → renderer-CIycc5O-.mjs} +2 -2
  159. package/dist/{renderer-DzLrvCB2.mjs.map → renderer-CIycc5O-.mjs.map} +1 -1
  160. package/dist/renderer-CJYtfa4x.mjs +5 -0
  161. package/dist/{renderer-BeNl_6EG.mjs → renderer-CJraQlV-.mjs} +2 -2
  162. package/dist/{renderer-BeNl_6EG.mjs.map → renderer-CJraQlV-.mjs.map} +1 -1
  163. package/dist/renderer-CKMtHGZh.mjs +5 -0
  164. package/dist/renderer-CLzicoiy.mjs +5 -0
  165. package/dist/renderer-CM2A4BHd.mjs +5 -0
  166. package/dist/{renderer-DtMVitEF.mjs → renderer-COWGWtob.mjs} +2 -2
  167. package/dist/{renderer-DtMVitEF.mjs.map → renderer-COWGWtob.mjs.map} +1 -1
  168. package/dist/{renderer-CT3zkfbf.mjs → renderer-COxG2XGf.mjs} +2 -2
  169. package/dist/{renderer-CT3zkfbf.mjs.map → renderer-COxG2XGf.mjs.map} +1 -1
  170. package/dist/{renderer-DNxWOz8Q.mjs → renderer-CQDCIsQm.mjs} +2 -2
  171. package/dist/{renderer-DNxWOz8Q.mjs.map → renderer-CQDCIsQm.mjs.map} +1 -1
  172. package/dist/{renderer-C5AoaymD.mjs → renderer-CRUeag8i.mjs} +3 -3
  173. package/dist/{renderer-C5AoaymD.mjs.map → renderer-CRUeag8i.mjs.map} +1 -1
  174. package/dist/{renderer-ngmYIIob.mjs → renderer-CWVput06.mjs} +3 -3
  175. package/dist/{renderer-ngmYIIob.mjs.map → renderer-CWVput06.mjs.map} +1 -1
  176. package/dist/renderer-CZlHjcxr.mjs +5 -0
  177. package/dist/{renderer-0rveCDm-.mjs → renderer-CbbnBLOB.mjs} +3 -3
  178. package/dist/{renderer-0rveCDm-.mjs.map → renderer-CbbnBLOB.mjs.map} +1 -1
  179. package/dist/renderer-CbimvSU8.mjs +5 -0
  180. package/dist/renderer-Ccvc63yd.mjs +5 -0
  181. package/dist/renderer-Cdp-SGfq.mjs +5 -0
  182. package/dist/renderer-CeTcSs3e.mjs +5 -0
  183. package/dist/{renderer-Brmbl12Y.mjs → renderer-CfLZein2.mjs} +3 -3
  184. package/dist/{renderer-Brmbl12Y.mjs.map → renderer-CfLZein2.mjs.map} +1 -1
  185. package/dist/{renderer-BJ8ea92W.mjs → renderer-Ch-q1O-q.mjs} +3 -3
  186. package/dist/{renderer-BJ8ea92W.mjs.map → renderer-Ch-q1O-q.mjs.map} +1 -1
  187. package/dist/{renderer-CP108ABB.mjs → renderer-Ch5JvJWl.mjs} +2 -2
  188. package/dist/{renderer-CP108ABB.mjs.map → renderer-Ch5JvJWl.mjs.map} +1 -1
  189. package/dist/{renderer-47y12Z37.mjs → renderer-ChtEzq-R.mjs} +2 -2
  190. package/dist/{renderer-47y12Z37.mjs.map → renderer-ChtEzq-R.mjs.map} +1 -1
  191. package/dist/{renderer-DhyMfG1v.mjs → renderer-Cj9nTC5l.mjs} +3 -3
  192. package/dist/{renderer-DhyMfG1v.mjs.map → renderer-Cj9nTC5l.mjs.map} +1 -1
  193. package/dist/{renderer-BDzn1AKF.mjs → renderer-CqT8HsSS.mjs} +2 -2
  194. package/dist/{renderer-BDzn1AKF.mjs.map → renderer-CqT8HsSS.mjs.map} +1 -1
  195. package/dist/{renderer-B7G1KohJ.mjs → renderer-CuQjMhdV.mjs} +2 -2
  196. package/dist/renderer-CvNuu52U.mjs +5 -0
  197. package/dist/renderer-CwciC0oI.mjs +5 -0
  198. package/dist/renderer-CysLUbIr.mjs +5 -0
  199. package/dist/{renderer-Cm0tsbQH.mjs → renderer-Cz30EVws.mjs} +2 -2
  200. package/dist/{renderer-Cm0tsbQH.mjs.map → renderer-Cz30EVws.mjs.map} +1 -1
  201. package/dist/renderer-D3A22Vxb.mjs +5 -0
  202. package/dist/renderer-D5SY9EmA.mjs +5 -0
  203. package/dist/renderer-D8h3ZvaE.mjs +5 -0
  204. package/dist/renderer-DE-B6N9n.mjs +5 -0
  205. package/dist/renderer-DETZTI7t.mjs +5 -0
  206. package/dist/{renderer-nHS3Sius.mjs → renderer-DHoX-5U_.mjs} +3 -3
  207. package/dist/{renderer-nHS3Sius.mjs.map → renderer-DHoX-5U_.mjs.map} +1 -1
  208. package/dist/{renderer-BWSRryIA.mjs → renderer-DOkm0Ycd.mjs} +2 -2
  209. package/dist/{renderer-BWSRryIA.mjs.map → renderer-DOkm0Ycd.mjs.map} +1 -1
  210. package/dist/{renderer-BHYJlK6H.d.mts → renderer-DU3f6ZrS.d.mts} +2 -2
  211. package/dist/{renderer-BHYJlK6H.d.mts.map → renderer-DU3f6ZrS.d.mts.map} +1 -1
  212. package/dist/{renderer-BpVOk9ux.mjs → renderer-DUzv-shq.mjs} +2 -2
  213. package/dist/{renderer-BpVOk9ux.mjs.map → renderer-DUzv-shq.mjs.map} +1 -1
  214. package/dist/renderer-DWnDj0IM.mjs +5 -0
  215. package/dist/renderer-DcGUIbQF.mjs +5 -0
  216. package/dist/renderer-Dfq6FoNO.mjs +5 -0
  217. package/dist/renderer-DhasXW6S.mjs +3 -0
  218. package/dist/{renderer-NRMlYkX6.mjs → renderer-DhnOWnEA.mjs} +3 -3
  219. package/dist/{renderer-NRMlYkX6.mjs.map → renderer-DhnOWnEA.mjs.map} +1 -1
  220. package/dist/{renderer-COgwYqev.mjs → renderer-Dhy1XHzz.mjs} +3 -3
  221. package/dist/{renderer-COgwYqev.mjs.map → renderer-Dhy1XHzz.mjs.map} +1 -1
  222. package/dist/renderer-DjCvpsV_.mjs +5 -0
  223. package/dist/{renderer-BfZNIiSv.mjs → renderer-DjJshz9Y.mjs} +2 -2
  224. package/dist/{renderer-BfZNIiSv.mjs.map → renderer-DjJshz9Y.mjs.map} +1 -1
  225. package/dist/{renderer-CKo7VR8x.mjs → renderer-DmTUIdus.mjs} +3 -3
  226. package/dist/{renderer-CKo7VR8x.mjs.map → renderer-DmTUIdus.mjs.map} +1 -1
  227. package/dist/{renderer-Baw6Utxi.mjs → renderer-Dq7AioJa.mjs} +2 -2
  228. package/dist/{renderer-Baw6Utxi.mjs.map → renderer-Dq7AioJa.mjs.map} +1 -1
  229. package/dist/renderer-DrAaM6JD.mjs +5 -0
  230. package/dist/{renderer-D-GWBoVT.mjs → renderer-Dt4sqNEu.mjs} +2 -2
  231. package/dist/{renderer-D-GWBoVT.mjs.map → renderer-Dt4sqNEu.mjs.map} +1 -1
  232. package/dist/{renderer-FYOL5Za6.mjs → renderer-Dtcs4idV.mjs} +3 -3
  233. package/dist/{renderer-FYOL5Za6.mjs.map → renderer-Dtcs4idV.mjs.map} +1 -1
  234. package/dist/renderer-Dxlv8LYm.mjs +5 -0
  235. package/dist/{renderer-D-RhYvVl.mjs → renderer-Gj8SrE2W.mjs} +2 -2
  236. package/dist/{renderer-D-RhYvVl.mjs.map → renderer-Gj8SrE2W.mjs.map} +1 -1
  237. package/dist/{renderer-D_j1WKMD.mjs → renderer-KfnXDJS0.mjs} +3 -3
  238. package/dist/{renderer-D_j1WKMD.mjs.map → renderer-KfnXDJS0.mjs.map} +1 -1
  239. package/dist/{renderer-Bpm145BW.mjs → renderer-MXVlg4p5.mjs} +3 -3
  240. package/dist/{renderer-Bpm145BW.mjs.map → renderer-MXVlg4p5.mjs.map} +1 -1
  241. package/dist/{renderer-Nnmi8Gt6.mjs → renderer-N2b6QZ1E.mjs} +3 -3
  242. package/dist/{renderer-Nnmi8Gt6.mjs.map → renderer-N2b6QZ1E.mjs.map} +1 -1
  243. package/dist/renderer-Pb43OO2t.mjs +5 -0
  244. package/dist/{renderer-Ca1KjNCO.mjs → renderer-Q7gDzm8c.mjs} +2 -2
  245. package/dist/{renderer-Ca1KjNCO.mjs.map → renderer-Q7gDzm8c.mjs.map} +1 -1
  246. package/dist/{renderer-D2wNFNRf.mjs → renderer-RCiANtRV.mjs} +2 -2
  247. package/dist/{renderer-D2wNFNRf.mjs.map → renderer-RCiANtRV.mjs.map} +1 -1
  248. package/dist/{renderer-Cqb7PGrI.mjs → renderer-Sig9nZcI.mjs} +2 -2
  249. package/dist/renderer-VQbm-cGr.mjs +5 -0
  250. package/dist/{renderer-W1bVNVR6.mjs → renderer-fabBgwQX.mjs} +3 -3
  251. package/dist/{renderer-W1bVNVR6.mjs.map → renderer-fabBgwQX.mjs.map} +1 -1
  252. package/dist/{renderer-zRq0j6Xy.mjs → renderer-g-0PCNoo.mjs} +3 -3
  253. package/dist/{renderer-zRq0j6Xy.mjs.map → renderer-g-0PCNoo.mjs.map} +1 -1
  254. package/dist/{renderer-2PjR3w-q.mjs → renderer-gmHKIbKI.mjs} +3 -3
  255. package/dist/{renderer-2PjR3w-q.mjs.map → renderer-gmHKIbKI.mjs.map} +1 -1
  256. package/dist/{renderer-03mYJLgX.mjs → renderer-kVZwiRoK.mjs} +3 -3
  257. package/dist/{renderer-03mYJLgX.mjs.map → renderer-kVZwiRoK.mjs.map} +1 -1
  258. package/dist/renderer-oPMypDM1.mjs +5 -0
  259. package/dist/{renderer-DcAKDAnS.mjs → renderer-p7tgxP-A.mjs} +3 -3
  260. package/dist/{renderer-DcAKDAnS.mjs.map → renderer-p7tgxP-A.mjs.map} +1 -1
  261. package/dist/{renderer-jUKdkmG5.mjs → renderer-tvYj306A.mjs} +81 -78
  262. package/dist/renderer-tvYj306A.mjs.map +1 -0
  263. package/dist/renderer-xvWGpVyp.mjs +5 -0
  264. package/dist/renderer-zafZbD6Q.mjs +5 -0
  265. package/dist/{renderers-CP8CFWDs-CshljORp.mjs → renderers-CP8CFWDs-DLjtjrwx.mjs} +2 -2
  266. package/dist/{renderers-CP8CFWDs-CshljORp.mjs.map → renderers-CP8CFWDs-DLjtjrwx.mjs.map} +1 -1
  267. package/dist/sam/index.d.mts +2 -2
  268. package/dist/sam/index.mjs +1 -1
  269. package/dist/signals/index.d.mts +4 -4
  270. package/dist/signals/index.mjs +4 -4
  271. package/dist/{src-BU6vm9sP-DdTHmCr4.mjs → src-B23p_eh7-Cj6-lvV6.mjs} +293 -6
  272. package/dist/src-B23p_eh7-Cj6-lvV6.mjs.map +1 -0
  273. package/dist/{src-Dy4gnc6w.mjs → src-CoHAjviq.mjs} +1349 -177
  274. package/dist/src-CoHAjviq.mjs.map +1 -0
  275. package/dist/storage/index.mjs +1 -1
  276. package/package.json +63 -60
  277. package/dist/dist--Uu5bQ_6.mjs.map +0 -1
  278. package/dist/dist-CiTgmfUw.mjs.map +0 -1
  279. package/dist/fonts-OW3yAfO5.mjs.map +0 -1
  280. package/dist/index-9xte4JgL.d.mts.map +0 -1
  281. package/dist/index-Bv7gxGK1.d.mts.map +0 -1
  282. package/dist/index-C5sgRLlG.d.mts.map +0 -1
  283. package/dist/index-C7-p9zwU.d.mts.map +0 -1
  284. package/dist/index-CRaydvLi.d.mts.map +0 -1
  285. package/dist/index-D1FqV1eu.d.mts.map +0 -1
  286. package/dist/preview-D7BGmE1E.mjs +0 -2446
  287. package/dist/preview-D7BGmE1E.mjs.map +0 -1
  288. package/dist/preview-engine/chunk-5DZTPUMH.mjs +0 -2568
  289. package/dist/preview-engine/chunk-NCQHOGZK.mjs +0 -3
  290. package/dist/preview-engine/chunk-PH3UUX6A.mjs +0 -138
  291. package/dist/preview-engine/chunk-UPZURPJY.mjs +0 -2227
  292. package/dist/preview-engine/renderers-DLJOA3BM.mjs +0 -228
  293. package/dist/program-tFKCWU2j.mjs.map +0 -1
  294. package/dist/renderer-6_bzbbXt.mjs +0 -5
  295. package/dist/renderer-8M-9G6F_.mjs +0 -5
  296. package/dist/renderer-B5OzKvF8.mjs +0 -5
  297. package/dist/renderer-BBCZ2qbE.mjs +0 -5
  298. package/dist/renderer-BChbxCux.mjs +0 -5
  299. package/dist/renderer-BGeMPr8C.mjs +0 -5
  300. package/dist/renderer-BPQ8Pkjb.mjs +0 -5
  301. package/dist/renderer-BTRpA3HD.mjs +0 -5
  302. package/dist/renderer-BVIXKfbC.mjs.map +0 -1
  303. package/dist/renderer-BVsECSn-.mjs +0 -5
  304. package/dist/renderer-Bgos68gc.mjs +0 -6
  305. package/dist/renderer-BjHOvoqO.mjs +0 -5
  306. package/dist/renderer-BjXMPPlV.mjs +0 -5
  307. package/dist/renderer-Byobxqkv.mjs +0 -5
  308. package/dist/renderer-CKrsg3EG.mjs +0 -5
  309. package/dist/renderer-Cj875NuH.mjs +0 -5
  310. package/dist/renderer-CnmzJoMv.mjs +0 -5
  311. package/dist/renderer-CtklDaMg.mjs +0 -5
  312. package/dist/renderer-D1tK3in_.mjs +0 -5
  313. package/dist/renderer-D2yc9P61.mjs +0 -5
  314. package/dist/renderer-D4v-JvSr.mjs +0 -5
  315. package/dist/renderer-D5yp74NL.mjs +0 -3
  316. package/dist/renderer-D7WRWDwB.mjs +0 -5
  317. package/dist/renderer-DGvA0tdB.mjs +0 -5
  318. package/dist/renderer-DO7v5Sdm.mjs +0 -5
  319. package/dist/renderer-DRVvt7-V.mjs +0 -5
  320. package/dist/renderer-DYMCd3jL.mjs +0 -5
  321. package/dist/renderer-DmHKw-MM.mjs +0 -5
  322. package/dist/renderer-DoDsuZ6G.mjs +0 -5
  323. package/dist/renderer-EpgclS70.mjs +0 -5
  324. package/dist/renderer-GroKiYyK.mjs +0 -5
  325. package/dist/renderer-MQ5K_xIS.mjs +0 -5
  326. package/dist/renderer-U43SflML.mjs +0 -5
  327. package/dist/renderer-UqOmBgCv.mjs +0 -5
  328. package/dist/renderer-XLULgJM0.mjs +0 -5
  329. package/dist/renderer-jUKdkmG5.mjs.map +0 -1
  330. package/dist/renderer-lNjxY1GG.mjs +0 -5
  331. package/dist/renderer-ukufL7pl.mjs +0 -5
  332. package/dist/renderer-wb0NCKdF.mjs +0 -5
  333. package/dist/src-BU6vm9sP-DdTHmCr4.mjs.map +0 -1
  334. package/dist/src-Dy4gnc6w.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--Uu5bQ_6.mjs";
3
- import { n as decodeAudioSource, o as preflightMediaTime } from "./dist-B8Nby2CU.mjs";
4
- import { t as FontManager } from "./fonts-OW3yAfO5.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 { F as collectNodeOps, I as compositorToProgram, J as mergeAnimationTracks, K as lintComposition, Y as sampleMediaTimeSignal, p as LayerAnimation, q as mediaSignalSampler } from "./program-tFKCWU2j.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-WMgv8ZaD.mjs";
9
- import { n as renderFrameGrid, s as HeadlessMediaRenderer } from "./renderer-jUKdkmG5.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) {
@@ -3317,7 +3804,22 @@ const MATERIAL_KEYS = [
3317
3804
  "envIntensity",
3318
3805
  "emissive",
3319
3806
  "emissiveIntensity",
3320
- "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"
3321
3823
  ];
3322
3824
  /** The material and surface options that were actually given. */
3323
3825
  function materialProps(o) {
@@ -3334,6 +3836,7 @@ function normalizePathSpec(input) {
3334
3836
  if (input instanceof Path3D) return input.getPoints(96);
3335
3837
  return input;
3336
3838
  }
3839
+ /** A Layer3D mesh node built from a procedural geometry spec. */
3337
3840
  function primitiveNode(prefix, geometry, o) {
3338
3841
  const spec$1 = Object.fromEntries(Object.entries({
3339
3842
  ...geometry,
@@ -3351,9 +3854,9 @@ function primitiveNode(prefix, geometry, o) {
3351
3854
  x: o.x ?? 0,
3352
3855
  y: o.y ?? 0,
3353
3856
  z: o.z ?? 0,
3354
- rotateX: o.rotateX ?? 0,
3355
- rotateY: o.rotateY ?? 0,
3356
- 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,
3357
3860
  scale: o.scale ?? 1,
3358
3861
  scaleX: o.scaleX ?? 1,
3359
3862
  scaleY: o.scaleY ?? 1,
@@ -3370,7 +3873,9 @@ function primitiveNode(prefix, geometry, o) {
3370
3873
  twoSided: o.twoSided ?? false,
3371
3874
  wireframe: o.wireframe,
3372
3875
  startFrame: o.startFrame,
3373
- 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)) }
3374
3879
  });
3375
3880
  }
3376
3881
  /**
@@ -3524,9 +4029,9 @@ const Layer3D = {
3524
4029
  height: h,
3525
4030
  is3D: true,
3526
4031
  transformStyle: "preserve-3d",
3527
- rotateX: options.rotateX ?? 0,
3528
- rotateY: options.rotateY ?? 0,
3529
- 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,
3530
4035
  opacity: options.opacity ?? 1,
3531
4036
  background: "transparent",
3532
4037
  children: faces
@@ -3562,18 +4067,20 @@ const Layer3D = {
3562
4067
  height: options.itemHeight ?? 200,
3563
4068
  is3D: true,
3564
4069
  transformStyle: "preserve-3d",
3565
- rotateX: options.rotateX ?? 0,
3566
- rotateY: options.rotateY ?? 0,
3567
- 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,
3568
4073
  opacity: options.opacity ?? 1,
3569
4074
  background: "transparent",
3570
4075
  children: transformedItems
3571
4076
  }), { items: transformedItems });
3572
4077
  },
3573
- prism(options) {
3574
- 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;
3575
4082
  if (options.sideConfigs && options.sideConfigs.length > 0) {
3576
- const { radius, height, twoSided = true } = options;
4083
+ const { twoSided = true } = options;
3577
4084
  const sideWidth = 2 * radius * Math.tan(Math.PI / n);
3578
4085
  const angleStep = 360 / n;
3579
4086
  const panels = [];
@@ -3635,20 +4142,23 @@ const Layer3D = {
3635
4142
  height,
3636
4143
  is3D: true,
3637
4144
  transformStyle: "preserve-3d",
3638
- rotateX: options.rotateX ?? 0,
3639
- rotateY: options.rotateY ?? 0,
3640
- 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,
3641
4148
  opacity: options.opacity ?? 1,
3642
4149
  background: "transparent",
3643
4150
  children: panels
3644
- }), { faces: panels });
4151
+ }), {
4152
+ faces: panels,
4153
+ items: panels
4154
+ });
3645
4155
  }
3646
4156
  const modelNode = primitiveNode("prism", {
3647
4157
  type: "cylinder",
3648
- radius: options.radius,
3649
- radiusTop: options.radiusTop ?? options.radius,
3650
- radiusBottom: options.radiusBottom ?? options.radius,
3651
- height: options.height,
4158
+ radius,
4159
+ radiusTop: options.radiusTop ?? options.topRadius ?? radius,
4160
+ radiusBottom: options.radiusBottom ?? options.bottomRadius ?? radius,
4161
+ height,
3652
4162
  segments: n,
3653
4163
  openEnded: options.openEnded ?? false,
3654
4164
  flatShaded: options.flatShaded ?? true
@@ -3662,14 +4172,14 @@ const Layer3D = {
3662
4172
  items: [modelNode]
3663
4173
  });
3664
4174
  },
3665
- pyramid(options) {
4175
+ pyramid(options = {}) {
3666
4176
  const n = Math.max(3, Math.round(options.sides ?? 4));
3667
4177
  return primitiveNode("pyramid", {
3668
4178
  type: "cylinder",
3669
4179
  radius: options.radius ?? 60,
3670
- radiusTop: options.radiusTop ?? 0,
4180
+ radiusTop: options.radiusTop ?? options.topRadius ?? 0,
3671
4181
  radiusBottom: options.radius ?? 60,
3672
- height: options.height,
4182
+ height: options.height ?? 100,
3673
4183
  segments: n,
3674
4184
  openEnded: options.openEnded ?? false,
3675
4185
  flatShaded: options.flatShaded ?? true
@@ -3690,9 +4200,9 @@ const Layer3D = {
3690
4200
  z: options.z ?? 0,
3691
4201
  is3D: true,
3692
4202
  twoSided: options.twoSided ?? true,
3693
- rotateX: options.rotateX ?? 0,
3694
- rotateY: options.rotateY ?? 0,
3695
- 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,
3696
4206
  background: options.background ?? "#3b82f6",
3697
4207
  borderRadius: options.borderRadius ?? 0,
3698
4208
  opacity: options.opacity ?? 1,
@@ -3746,9 +4256,9 @@ const Layer3D = {
3746
4256
  z: options.z ?? 0,
3747
4257
  is3D: true,
3748
4258
  transformStyle: "preserve-3d",
3749
- rotateX: options.rotateX ?? 90,
3750
- rotateY: options.rotateY ?? 0,
3751
- 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,
3752
4262
  background: "transparent",
3753
4263
  opacity: options.opacity ?? 1,
3754
4264
  children: lines
@@ -3767,9 +4277,9 @@ const Layer3D = {
3767
4277
  z: options.z ?? 0,
3768
4278
  is3D: true,
3769
4279
  twoSided: options.twoSided ?? true,
3770
- rotateX: options.rotateX ?? 0,
3771
- rotateY: options.rotateY ?? 0,
3772
- 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,
3773
4283
  fontSize: options.fontSize ?? 48,
3774
4284
  fontFamily: options.fontFamily,
3775
4285
  fontWeight: options.fontWeight ?? "bold",
@@ -3825,9 +4335,9 @@ const Layer3D = {
3825
4335
  x: options.x ?? 0,
3826
4336
  y: options.y ?? 0,
3827
4337
  z: options.z ?? 0,
3828
- rotateX: options.rotateX ?? 0,
3829
- rotateY: options.rotateY ?? 0,
3830
- 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,
3831
4341
  scale: options.scale ?? 1,
3832
4342
  scaleX: options.scaleX ?? 1,
3833
4343
  scaleY: options.scaleY ?? 1,
@@ -3857,7 +4367,7 @@ const Layer3D = {
3857
4367
  width: options.width,
3858
4368
  height: options.height,
3859
4369
  depth: options.depth,
3860
- radius: options.radius,
4370
+ radius: options.radius ?? options.cornerRadius ?? options.borderRadius,
3861
4371
  segments: options.segments,
3862
4372
  taper: options.taper
3863
4373
  }, options);
@@ -3873,8 +4383,8 @@ const Layer3D = {
3873
4383
  return primitiveNode("cylinder", {
3874
4384
  type: "cylinder",
3875
4385
  radius: options.radius,
3876
- radiusTop: options.radiusTop,
3877
- radiusBottom: options.radiusBottom,
4386
+ radiusTop: options.radiusTop ?? options.topRadius,
4387
+ radiusBottom: options.radiusBottom ?? options.bottomRadius,
3878
4388
  height: options.height,
3879
4389
  segments: options.segments,
3880
4390
  openEnded: options.openEnded,
@@ -3887,8 +4397,8 @@ const Layer3D = {
3887
4397
  torus(options = {}) {
3888
4398
  return primitiveNode("torus", {
3889
4399
  type: "torus",
3890
- radius: options.radius,
3891
- tube: options.tube,
4400
+ radius: options.radius ?? options.majorRadius,
4401
+ tube: options.tube ?? options.minorRadius ?? options.tubeRadius,
3892
4402
  radialSegments: options.radialSegments,
3893
4403
  tubularSegments: options.tubularSegments,
3894
4404
  arc: options.arc
@@ -4030,6 +4540,15 @@ const Layer3D = {
4030
4540
  irregularity: options.irregularity
4031
4541
  }, options);
4032
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
+ },
4033
4552
  instances(options) {
4034
4553
  const primaryMesh = Array.isArray(options.mesh) ? options.mesh[0] : options.mesh;
4035
4554
  const node = {
@@ -4038,9 +4557,9 @@ const Layer3D = {
4038
4557
  x: options.x ?? 0,
4039
4558
  y: options.y ?? 0,
4040
4559
  z: options.z ?? 0,
4041
- rotateX: options.rotateX ?? 0,
4042
- rotateY: options.rotateY ?? 0,
4043
- 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,
4044
4563
  scale: options.scale ?? 1,
4045
4564
  color: options.color,
4046
4565
  colorTint: options.colorTint,
@@ -4055,6 +4574,8 @@ const Layer3D = {
4055
4574
  startFrame: options.startFrame,
4056
4575
  durationFrames: options.durationFrames,
4057
4576
  instances3d: { ...options },
4577
+ ...options.wind && { wind: options.wind },
4578
+ ...options.crowd && { crowd: options.crowd },
4058
4579
  ...materialProps(options)
4059
4580
  };
4060
4581
  if (primaryMesh) {
@@ -4491,6 +5012,9 @@ function rig(name, options) {
4491
5012
  exposure: options.exposure,
4492
5013
  toneMapping: options.toneMapping,
4493
5014
  fog: options.fog,
5015
+ volumetricFog: options.volumetricFog,
5016
+ ssr: options.ssr,
5017
+ gi: options.gi,
4494
5018
  bloom: options.bloom
4495
5019
  }), Light.directional({
4496
5020
  id: `${id}-key`,
@@ -4602,6 +5126,20 @@ var RapierWorld2D = class {
4602
5126
  x,
4603
5127
  y
4604
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
+ },
4605
5143
  setKinematicTarget: ([x, y], angle) => {
4606
5144
  body.setNextKinematicTranslation({
4607
5145
  x,
@@ -4730,6 +5268,19 @@ var RapierWorld3D = class {
4730
5268
  mass: () => body.mass(),
4731
5269
  setEnabled: (on) => body.setEnabled(on),
4732
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
+ },
4733
5284
  setKinematicTarget: (p, [x, y, z$3, w]) => {
4734
5285
  body.setNextKinematicTranslation(vec3(p));
4735
5286
  body.setNextKinematicRotation({
@@ -4837,6 +5388,7 @@ function shapeDesc3D(R, shape$1) {
4837
5388
  if (!desc) throw new Error("Physics: could not build a convex hull for this shape.");
4838
5389
  return desc;
4839
5390
  }
5391
+ case "trimesh": return R.ColliderDesc.trimesh(new Float32Array(shape$1.vertices), new Uint32Array(shape$1.indices));
4840
5392
  }
4841
5393
  }
4842
5394
 
@@ -5030,6 +5582,8 @@ var PhysicsWorld2D = class extends WorldCore {
5030
5582
  };
5031
5583
  const simBody = this.sim.addBody(spec$1);
5032
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);
5033
5587
  return this.addBody(body);
5034
5588
  }
5035
5589
  /** A fixed, very wide floor whose top edge sits at `y`. */
@@ -5224,7 +5778,7 @@ function effectiveMass(a, b) {
5224
5778
  if (ma > 0 && mb > 0) return ma * mb / (ma + mb);
5225
5779
  return Math.max(ma, mb, .001);
5226
5780
  }
5227
- function num$3(v, fallback) {
5781
+ function num$4(v, fallback) {
5228
5782
  return typeof v === "number" && Number.isFinite(v) ? v : fallback;
5229
5783
  }
5230
5784
  function layerGeometry(layer, options) {
@@ -5235,31 +5789,31 @@ function layerGeometry(layer, options) {
5235
5789
  if ((width === void 0 || height === void 0) && layer.kind === "text") {
5236
5790
  const m = FontManager.measure(String(layer.text ?? ""), {
5237
5791
  fontFamily: String(layer.fontFamily ?? "Inter"),
5238
- fontSize: num$3(layer.fontSize, 48),
5792
+ fontSize: num$4(layer.fontSize, 48),
5239
5793
  fontWeight: layer.fontWeight,
5240
- letterSpacing: num$3(layer.letterSpacing, 0),
5794
+ letterSpacing: num$4(layer.letterSpacing, 0),
5241
5795
  lineHeight: typeof layer.lineHeight === "number" ? layer.lineHeight : void 0
5242
5796
  });
5243
5797
  width ??= m.width;
5244
5798
  height ??= m.height;
5245
5799
  }
5246
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.`);
5247
- const scale = num$3(layer.scale, 1);
5801
+ const scale = num$4(layer.scale, 1);
5248
5802
  return {
5249
5803
  x: layer.x,
5250
5804
  y: layer.y,
5251
5805
  width,
5252
5806
  height,
5253
5807
  scale,
5254
- anchorX: num$3(layer.anchorX, .5),
5255
- anchorY: num$3(layer.anchorY, .5),
5256
- 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),
5257
5811
  shape: scaleShape$1(colliderShape(layer, width, height, options.shape ?? "auto"), scale)
5258
5812
  };
5259
5813
  }
5260
5814
  function colliderShape(layer, w, h, mode) {
5261
5815
  const shapeType = layer.kind === "shape" ? String(layer.shapeType ?? "rect") : "rect";
5262
- const radius = num$3(layer.borderRadius, num$3(layer.cornerRadius, 0));
5816
+ const radius = num$4(layer.borderRadius, num$4(layer.cornerRadius, 0));
5263
5817
  const box = {
5264
5818
  kind: "box",
5265
5819
  hx: w / 2,
@@ -5287,7 +5841,7 @@ function outlinePoints(layer, shapeType, w, h) {
5287
5841
  shapeType,
5288
5842
  width: w,
5289
5843
  height: h,
5290
- cornerRadius: num$3(layer.cornerRadius, num$3(layer.borderRadius, 0)),
5844
+ cornerRadius: num$4(layer.cornerRadius, num$4(layer.borderRadius, 0)),
5291
5845
  polygonSides: layer.polygonSides,
5292
5846
  starPoints: layer.starPoints,
5293
5847
  starInnerRadiusRatio: layer.starInnerRadiusRatio,
@@ -5336,6 +5890,275 @@ function centerToLayer(cx, cy, rotationDeg, f) {
5336
5890
  return [cx - ox - f.anchorX * f.width, cy - oy - f.anchorY * f.height];
5337
5891
  }
5338
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
+
5339
6162
  //#endregion
5340
6163
  //#region src/physics/world3d.ts
5341
6164
  const DEG = Math.PI / 180;
@@ -5361,6 +6184,7 @@ function quatFromEuler(rx, ry, rz) {
5361
6184
  Math.cos(half(rz))
5362
6185
  ], qy), qx);
5363
6186
  }
6187
+ /** @internal */
5364
6188
  function quatMul(a, b) {
5365
6189
  const [ax, ay, az, aw] = a;
5366
6190
  const [bx, by, bz, bw] = b;
@@ -5440,7 +6264,32 @@ var PhysicsBody3D = class {
5440
6264
  this.recording = recording;
5441
6265
  }
5442
6266
  get startFrame() {
5443
- 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
+ ]);
5444
6293
  }
5445
6294
  get gravityScale() {
5446
6295
  return this.options.gravityScale ?? 1;
@@ -5494,17 +6343,17 @@ var PhysicsBody3D = class {
5494
6343
  const follow = this.options.follow;
5495
6344
  if (this.type !== "kinematic" || !follow) return void 0;
5496
6345
  const fps = this.world.fps;
5497
- 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);
5498
6347
  const p = this.start.position;
5499
6348
  const r = this.start.rotation;
5500
6349
  const ppm = this.world.pixelsPerMeter;
5501
6350
  return {
5502
6351
  position: [
5503
- read$1(follow.x, p[0]) / ppm,
5504
- read$1(follow.y, p[1]) / ppm,
5505
- 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
5506
6355
  ],
5507
- 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]))
5508
6357
  };
5509
6358
  }
5510
6359
  /** @internal */
@@ -5523,7 +6372,12 @@ var PhysicsBody3D = class {
5523
6372
  ry[previous],
5524
6373
  rz[previous]
5525
6374
  ];
5526
- 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);
5527
6381
  rx[index] = e[0];
5528
6382
  ry[index] = e[1];
5529
6383
  rz[index] = e[2];
@@ -5576,6 +6430,7 @@ var PhysicsBody3D = class {
5576
6430
  ];
5577
6431
  }
5578
6432
  };
6433
+ /** @internal */
5579
6434
  function rotateByQuat(v, q) {
5580
6435
  const r = quatMul(quatMul(q, [
5581
6436
  v[0],
@@ -5631,6 +6486,11 @@ var PhysicsWorld3D = class extends WorldCore {
5631
6486
  num$2(options.rotateY ?? t.rotateY, 0),
5632
6487
  num$2(options.rotateZ ?? t.rotateZ, 0)
5633
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();
5634
6494
  const ppm = this.pixelsPerMeter;
5635
6495
  const type = options.type ?? "dynamic";
5636
6496
  const v = options.velocity ?? [
@@ -5676,15 +6536,37 @@ var PhysicsWorld3D = class extends WorldCore {
5676
6536
  density: options.density ?? 1,
5677
6537
  friction: options.friction ?? .6,
5678
6538
  restitution: options.restitution ?? .3,
5679
- shape: scaleShape(colliderShape3D(t, options), 1 / ppm)
6539
+ shape: scaleShape(shape$1, 1 / ppm)
5680
6540
  };
5681
6541
  const simBody = this.sim.addBody(spec$1);
5682
6542
  const body = new PhysicsBody3D(this, simBody, type, layer, {
5683
6543
  position,
5684
6544
  rotation
5685
6545
  }, options, this.newRecording());
6546
+ const start = body.kinematicTarget(this.startFrame);
6547
+ if (start) simBody.setPose(start.position, start.rotation);
5686
6548
  return this.addBody(body);
5687
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
+ }
5688
6570
  /** A fixed, very large floor whose top face sits at `y`. */
5689
6571
  ground(options) {
5690
6572
  const t = 2e3;
@@ -5833,11 +6715,11 @@ var PhysicsWorld3D = class extends WorldCore {
5833
6715
  /** A steady push, px/s² (mass-independent). Drivers are read every frame. */
5834
6716
  force(body, accel) {
5835
6717
  const ppm = this.pixelsPerMeter;
5836
- 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;
5837
6719
  this.addForce(body, (frame) => [
5838
- read$1(accel.x, frame),
5839
- read$1(accel.y, frame),
5840
- read$1(accel.z, frame)
6720
+ read$2(accel.x, frame),
6721
+ read$2(accel.y, frame),
6722
+ read$2(accel.z, frame)
5841
6723
  ]);
5842
6724
  return this;
5843
6725
  }
@@ -5942,6 +6824,10 @@ function colliderShape3D(t, options) {
5942
6824
  points: pts.map((v, i) => v * scale[i % 3])
5943
6825
  };
5944
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
+ }
5945
6831
  if (options.size || mode === "box") {
5946
6832
  const [w, h$1, d] = options.size ?? boxSize(t, prim) ?? [
5947
6833
  0,
@@ -6054,6 +6940,25 @@ function boxSize(t, prim) {
6054
6940
  t.depth
6055
6941
  ];
6056
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
+ }
6057
6962
  /** Every vertex of a model, flat xyz, at most ~4k points (the hull needs no more). */
6058
6963
  function meshPoints(modelData) {
6059
6964
  const meshes = modelData?.meshes;
@@ -6093,6 +6998,11 @@ function scaleShape(shape$1, s) {
6093
6998
  kind: "hull",
6094
6999
  points: shape$1.points.map((v) => v * s)
6095
7000
  };
7001
+ case "trimesh": return {
7002
+ kind: "trimesh",
7003
+ vertices: shape$1.vertices.map((v) => v * s),
7004
+ indices: shape$1.indices
7005
+ };
6096
7006
  }
6097
7007
  }
6098
7008
 
@@ -8667,7 +9577,7 @@ var Media = class Media {
8667
9577
  return this.virtualMedia;
8668
9578
  }
8669
9579
  /**
8670
- * 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.
8671
9581
  * Can render either by timestamp in milliseconds (`atMs`) or by frame index (`frame`).
8672
9582
  */
8673
9583
  async renderFrame(options = {}) {
@@ -8780,7 +9690,11 @@ var Composition = class Composition {
8780
9690
  vision(sourceOrLayer, options = {}) {
8781
9691
  const source = typeof sourceOrLayer === "string" ? sourceOrLayer : sourceOrLayer.src ?? sourceOrLayer.inputHandleId;
8782
9692
  if (typeof sourceOrLayer !== "string") {
8783
- 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
+ } };
8784
9698
  if (!layer) throw new Error("Add the media layer to the composition before calling comp.vision(layer)");
8785
9699
  options = {
8786
9700
  startFrame: layer.operation.startFrame ?? sourceOrLayer.startFrame,
@@ -8823,9 +9737,12 @@ var Composition = class Composition {
8823
9737
  if (!node || typeof node !== "object") return;
8824
9738
  const n = node;
8825
9739
  if (n.kind === "media" && n.dataType === "Video" && typeof n.inputHandleId === "string" && n.vision instanceof Vision && !(CLIP_SUBJECT in n.vision)) {
8826
- layers ??= new Map(collectNodeOps(this.toVirtualMedia().children).map((node$1) => {
8827
- const op = node$1.operation;
8828
- 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
+ }];
8829
9746
  }));
8830
9747
  const layer = layers.get(n.id);
8831
9748
  const clip = this.clipForLayer(n.src ?? n.inputHandleId, n.vision, {
@@ -9378,10 +10295,11 @@ var Composition = class Composition {
9378
10295
  return vm;
9379
10296
  }
9380
10297
  /**
9381
- * 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.
9382
10299
  * Can render either by timestamp in milliseconds (`atMs`) or by frame index (`frame`).
9383
10300
  */
9384
- async renderFrame(options = {}) {
10301
+ async renderFrame(frameOrOptions = {}) {
10302
+ const options = typeof frameOrOptions === "number" ? { frame: frameOrOptions } : frameOrOptions;
9385
10303
  const { frame } = resolveFrameRequest(options, this.fps);
9386
10304
  if (options.fps !== void 0 && options.fps !== this.fps) throw new Error(`Composition fps is ${this.fps}; cannot render at fps ${options.fps}.`);
9387
10305
  const vm = this.toVirtualMedia();
@@ -9399,7 +10317,9 @@ var Composition = class Composition {
9399
10317
  }
9400
10318
  return (options.renderer ?? new HeadlessMediaRenderer()).renderFrame(vm, {
9401
10319
  fps: this.fps,
9402
- frame
10320
+ frame,
10321
+ renderId: options.renderId,
10322
+ format: options.format
9403
10323
  });
9404
10324
  }
9405
10325
  /**
@@ -9442,11 +10362,27 @@ var Composition = class Composition {
9442
10362
  * never change. `renderVideo({ qa })` includes these automatically.
9443
10363
  */
9444
10364
  lint() {
9445
- return lintComposition(this.toSpec(), { emojiFont: FontManager.hasEmojiFont() });
10365
+ return lintComposition(this.toSpec(), {
10366
+ emojiFont: FontManager.hasEmojiFont(),
10367
+ scatterCoverage
10368
+ });
9446
10369
  }
9447
10370
  };
9448
10371
  function withAnimation(node) {
9449
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
+ }
9450
10386
  if (target$1.animation instanceof LayerAnimation) target$1.animation = target$1.animation.toSpec();
9451
10387
  Object.defineProperty(target$1, "animate", {
9452
10388
  value: (...anims) => {
@@ -9633,8 +10569,89 @@ function withAnimation(node) {
9633
10569
  writable: true,
9634
10570
  configurable: true
9635
10571
  });
10572
+ bindMaterialSignals(target$1);
9636
10573
  return target$1;
9637
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
+ }
9638
10655
  const Layer = {
9639
10656
  video: (src, options = {}) => withAnimation({
9640
10657
  id: options.id ?? autoId("video"),
@@ -9912,29 +10929,42 @@ const Layer = {
9912
10929
  });
9913
10930
  },
9914
10931
  chart: (options, props = {}) => buildChart(options, props, FontManager.getAll()[0]?.family ?? "Inter"),
9915
- camera: (options = {}) => withAnimation({
9916
- id: options.id ?? autoId("camera"),
9917
- kind: "camera",
9918
- mode: options.mode ?? "lookAt",
9919
- pitch: options.pitch ?? 0,
9920
- yaw: options.yaw ?? 0,
9921
- roll: options.roll ?? 0,
9922
- ...options
9923
- }),
9924
- 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({
9925
10955
  id: options.id ?? autoId("light"),
9926
10956
  kind: "light",
9927
10957
  lightType: options.lightType ?? "point",
9928
10958
  color: options.color ?? "#ffffff",
9929
- intensity: options.intensity ?? 1,
9930
- ...options
9931
- }),
10959
+ intensity: 1
10960
+ }, options),
9932
10961
  ambientLight: (color$1 = "#ffffff", intensity = .5, options = {}) => Light.ambient(color$1, intensity, options),
9933
10962
  sequence: (entries, options) => sequence(entries, options),
9934
10963
  environment: (presetOrOptions = "studio", options = {}) => Light.environment(presetOrOptions, options),
9935
10964
  directionalLight: (options = {}) => Light.directional(options),
9936
10965
  pointLight: (options = {}) => Light.point(options),
9937
10966
  spotLight: (options = {}) => Light.spot(options),
10967
+ rectLight: (options = {}) => Light.rect(options),
9938
10968
  cube: (options) => Layer3D.cube(options),
9939
10969
  carousel3d: (options) => Layer3D.carousel(options),
9940
10970
  plane3d: (options) => Layer3D.plane(options),
@@ -9998,78 +11028,220 @@ const Layer = {
9998
11028
  ...options
9999
11029
  })
10000
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
+ }
10001
11156
  const Light = {
10002
11157
  environment: (presetOrOptions = "studio", options = {}) => {
10003
- const opts = typeof presetOrOptions === "string" ? {
10004
- preset: presetOrOptions,
10005
- ...options
10006
- } : {
10007
- ...presetOrOptions,
11158
+ const opts = {
11159
+ ...typeof presetOrOptions !== "string" ? presetOrOptions : isHdriPath(presetOrOptions) ? { hdri: presetOrOptions } : { preset: presetOrOptions },
10008
11160
  ...options
10009
11161
  };
10010
- return withAnimation({
11162
+ return buildLightNode({
11163
+ id: opts.id ?? autoId("environment"),
10011
11164
  kind: "light",
10012
11165
  lightType: "environment",
10013
11166
  preset: "studio",
10014
- intensity: 1,
10015
- ...opts,
10016
- id: opts.id ?? autoId("environment")
10017
- });
11167
+ intensity: 1
11168
+ }, opts);
10018
11169
  },
10019
- ambient: (color$1 = "#ffffff", intensity = .5, options = {}) => withAnimation({
10020
- id: options.id ?? autoId("light-ambient"),
10021
- kind: "light",
10022
- lightType: "ambient",
10023
- color: typeof color$1 === "string" ? color$1 : color$1.color ?? "#ffffff",
10024
- intensity,
10025
- ...typeof color$1 === "object" && color$1,
10026
- ...options
10027
- }),
10028
- 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({
10029
11186
  id: options.id ?? autoId("light-directional"),
10030
11187
  kind: "light",
10031
11188
  lightType: "directional",
10032
11189
  color: options.color ?? "#ffffff",
10033
- intensity: options.intensity ?? 1,
10034
- x: options.x ?? 0,
10035
- y: options.y ?? -1e3,
10036
- z: options.z ?? -1e3,
10037
- targetX: options.targetX ?? 0,
10038
- targetY: options.targetY ?? 0,
10039
- targetZ: options.targetZ ?? 0,
10040
- ...options
10041
- }),
10042
- 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({
10043
11199
  id: options.id ?? autoId("light-point"),
10044
11200
  kind: "light",
10045
11201
  lightType: "point",
10046
11202
  color: options.color ?? "#ffffff",
10047
- intensity: options.intensity ?? 1,
10048
- x: options.x ?? 0,
10049
- y: options.y ?? 0,
10050
- z: options.z ?? -500,
10051
- radius: options.radius ?? 1e3,
10052
- decay: options.decay ?? 1,
10053
- ...options
10054
- }),
10055
- 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({
10056
11211
  id: options.id ?? autoId("light-spot"),
10057
11212
  kind: "light",
10058
11213
  lightType: "spot",
10059
11214
  color: options.color ?? "#ffffff",
10060
- intensity: options.intensity ?? 1,
10061
- x: options.x ?? 0,
10062
- y: options.y ?? -500,
10063
- z: options.z ?? -1e3,
10064
- targetX: options.targetX ?? 0,
10065
- targetY: options.targetY ?? 0,
10066
- targetZ: options.targetZ ?? 0,
10067
- angle: options.angle ?? 45,
10068
- penumbra: options.penumbra ?? .2,
10069
- radius: options.radius ?? 2e3,
10070
- decay: options.decay ?? 1,
10071
- ...options
10072
- })
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)
10073
11245
  };
10074
11246
  function section(source, targetOrOptions = {}, options = {}) {
10075
11247
  return Layer.section(source, targetOrOptions, options);
@@ -10110,5 +11282,5 @@ const Effect = Object.assign(Effect$1, effectFactories, {
10110
11282
  });
10111
11283
 
10112
11284
  //#endregion
10113
- 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 };
10114
- //# sourceMappingURL=src-Dy4gnc6w.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