framefields 2.9.2 → 2.9.3
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.
- package/NOTICE.md +14 -0
- package/README.md +1 -5
- package/dist/audio/index.d.mts +5 -4
- package/dist/audio/index.mjs +13 -13
- package/dist/{audio-BfQg37MW.mjs → audio-B6RmYOPe.mjs} +4 -4
- package/dist/{audio-BfQg37MW.mjs.map → audio-B6RmYOPe.mjs.map} +1 -1
- package/dist/{audio-a0MFkK6J.mjs → audio-BlDbnteH.mjs} +1 -1
- package/dist/{audio-a0MFkK6J.mjs.map → audio-BlDbnteH.mjs.map} +1 -1
- package/dist/{audio-Ccpl9mjV.d.mts → audio-D6tBMbHh.d.mts} +4 -3
- package/dist/audio-D6tBMbHh.d.mts.map +1 -0
- package/dist/{check-result-C3jlgV2i.mjs → check-result-Bj7g62ka.mjs} +1 -1
- package/dist/{check-result-C3jlgV2i.mjs.map → check-result-Bj7g62ka.mjs.map} +1 -1
- package/dist/cli/check-worker.mjs +50 -50
- package/dist/cli.mjs +1 -1
- package/dist/components/index.d.mts +14 -11
- package/dist/components/index.mjs +47 -47
- package/dist/dist-BlulwErl.mjs +3 -0
- package/dist/{dist-BlIrsfcn.mjs → dist-ByxHoMQI.mjs} +1 -1
- package/dist/{dist-BlIrsfcn.mjs.map → dist-ByxHoMQI.mjs.map} +1 -1
- package/dist/{dist-Buaaj-Ul.mjs → dist-Cn8bDsQF.mjs} +1 -1
- package/dist/{dist-Buaaj-Ul.mjs.map → dist-Cn8bDsQF.mjs.map} +1 -1
- package/dist/{dist-C1cCW7Bt.mjs → dist-D12-a3-x.mjs} +3 -3
- package/dist/{dist-C1cCW7Bt.mjs.map → dist-D12-a3-x.mjs.map} +1 -1
- package/dist/{dist-C8Xq3zgx.mjs → dist-DEUU6sNe.mjs} +4 -4
- package/dist/{dist-C8Xq3zgx.mjs.map → dist-DEUU6sNe.mjs.map} +1 -1
- package/dist/{dist-DVMepKaO.mjs → dist-DL1GwJvs.mjs} +2 -2
- package/dist/{dist-DVMepKaO.mjs.map → dist-DL1GwJvs.mjs.map} +1 -1
- package/dist/dist-Dq5TkNDI.mjs +1434 -0
- package/dist/dist-Dq5TkNDI.mjs.map +1 -0
- package/dist/effects/index.d.mts +6 -4
- package/dist/effects/index.mjs +36 -36
- package/dist/{effects-CemgqEPv.mjs → effects-CViUoQSV.mjs} +3 -3
- package/dist/{effects-CemgqEPv.mjs.map → effects-CViUoQSV.mjs.map} +1 -1
- package/dist/fonts/index.d.mts +1 -1
- package/dist/fonts/index.mjs +3 -3
- package/dist/{fonts-BW0pPcvJ.mjs → fonts-B0U2KO5I.mjs} +2 -2
- package/dist/{fonts-BW0pPcvJ.mjs.map → fonts-B0U2KO5I.mjs.map} +1 -1
- package/dist/{gpu-CMaa63nz.mjs → gpu-zFNrvhV9.mjs} +2 -2
- package/dist/{gpu-CMaa63nz.mjs.map → gpu-zFNrvhV9.mjs.map} +1 -1
- package/dist/index-9_4X2ro1.d.mts +2402 -0
- package/dist/index-9_4X2ro1.d.mts.map +1 -0
- package/dist/{index-Bnh42ouE.d.mts → index-B9Lm1x8i.d.mts} +9 -8
- package/dist/index-B9Lm1x8i.d.mts.map +1 -0
- package/dist/{index-BfDFmIBE.d.mts → index-BuYtrhzL.d.mts} +1 -1
- package/dist/{index-BfDFmIBE.d.mts.map → index-BuYtrhzL.d.mts.map} +1 -1
- package/dist/{index-D5UDyVMb.d.mts → index-Bzo1uj8h.d.mts} +4 -2401
- package/dist/index-Bzo1uj8h.d.mts.map +1 -0
- package/dist/{index-CQ-bbZk3.d.mts → index-C6GcuYVA.d.mts} +6 -1164
- package/dist/index-C6GcuYVA.d.mts.map +1 -0
- package/dist/{index-BIjMAW1h.d.mts → index-CgGM31I9.d.mts} +2 -2
- package/dist/{index-BIjMAW1h.d.mts.map → index-CgGM31I9.d.mts.map} +1 -1
- package/dist/index-DBhswLMO.d.mts +330 -0
- package/dist/index-DBhswLMO.d.mts.map +1 -0
- package/dist/{index-CJL0JAU8.d.mts → index-V0ZQ4JN6.d.mts} +2 -2
- package/dist/{index-CJL0JAU8.d.mts.map → index-V0ZQ4JN6.d.mts.map} +1 -1
- package/dist/{index-7Z9_a_iB.d.mts → index-f4IF1vRH.d.mts} +3 -3
- package/dist/{index-7Z9_a_iB.d.mts.map → index-f4IF1vRH.d.mts.map} +1 -1
- package/dist/index-svAgwTY_.d.mts +1163 -0
- package/dist/index-svAgwTY_.d.mts.map +1 -0
- package/dist/{index-CFoAmh7q.d.mts → index-w28KUM9A.d.mts} +3 -3
- package/dist/{index-CFoAmh7q.d.mts.map → index-w28KUM9A.d.mts.map} +1 -1
- package/dist/index.d.mts +15 -12
- package/dist/index.mjs +58 -57
- package/dist/preview/index.d.mts +4 -3
- package/dist/preview/index.mjs +12 -12
- package/dist/{preview-DvP8AZuV.mjs → preview-ZKJ_zTmd.mjs} +3 -3
- package/dist/{preview-DvP8AZuV.mjs.map → preview-ZKJ_zTmd.mjs.map} +1 -1
- package/dist/preview-engine/{chunk-KXLXP66K.mjs → chunk-Q62GPWGD.mjs} +23 -23
- package/dist/preview-engine/components.mjs +1 -1
- package/dist/preview-engine/framefields.mjs +1 -1
- package/dist/{program-CKpKkllV.mjs → program-xjIwjKb6.mjs} +4 -4
- package/dist/{program-CKpKkllV.mjs.map → program-xjIwjKb6.mjs.map} +1 -1
- package/dist/renderer/index.d.mts +3 -2
- package/dist/renderer/index.mjs +3 -3
- package/dist/renderer-129U3pc9.mjs +5 -0
- package/dist/renderer-2phFTFxQ.mjs +5 -0
- package/dist/{renderer-Bfk6A7UO.mjs → renderer-5qJPGvVL.mjs} +5 -5
- package/dist/{renderer-Bfk6A7UO.mjs.map → renderer-5qJPGvVL.mjs.map} +1 -1
- package/dist/renderer-9muKpDeE.mjs +5 -0
- package/dist/{renderer-B522Dkdk.mjs → renderer-AUK_ZS3p.mjs} +4 -4
- package/dist/{renderer-B522Dkdk.mjs.map → renderer-AUK_ZS3p.mjs.map} +1 -1
- package/dist/{renderer-DKgPVOLL.d.mts → renderer-B-inTgyb.d.mts} +2 -2
- package/dist/{renderer-DKgPVOLL.d.mts.map → renderer-B-inTgyb.d.mts.map} +1 -1
- package/dist/{renderer-BF0hx_iJ.mjs → renderer-B3IRvukr.mjs} +5 -5
- package/dist/{renderer-BF0hx_iJ.mjs.map → renderer-B3IRvukr.mjs.map} +1 -1
- package/dist/renderer-B5Dhv6j9.mjs +5 -0
- package/dist/{renderer-DO-KbpYZ.mjs → renderer-B6TjJi1g.mjs} +5 -5
- package/dist/{renderer-DO-KbpYZ.mjs.map → renderer-B6TjJi1g.mjs.map} +1 -1
- package/dist/{renderer-D61B9bXF.mjs → renderer-B78W9uad.mjs} +4 -4
- package/dist/{renderer-D61B9bXF.mjs.map → renderer-B78W9uad.mjs.map} +1 -1
- package/dist/{renderer-BPWDsufX.mjs → renderer-B7kOF_Az.mjs} +3 -3
- package/dist/{renderer-BPWDsufX.mjs.map → renderer-B7kOF_Az.mjs.map} +1 -1
- package/dist/renderer-BBUgCS3C.mjs +5 -0
- package/dist/{renderer-C7eFJf0_.mjs → renderer-BG6bkKtY.mjs} +5 -5
- package/dist/{renderer-C7eFJf0_.mjs.map → renderer-BG6bkKtY.mjs.map} +1 -1
- package/dist/{renderer-B39I6CQw.mjs → renderer-BJKzZwyn.mjs} +4 -4
- package/dist/{renderer-B39I6CQw.mjs.map → renderer-BJKzZwyn.mjs.map} +1 -1
- package/dist/{renderer-DqvoMLca.mjs → renderer-BJQt0RiZ.mjs} +5 -5
- package/dist/{renderer-DqvoMLca.mjs.map → renderer-BJQt0RiZ.mjs.map} +1 -1
- package/dist/renderer-BKXM28Mx.mjs +5 -0
- package/dist/renderer-BKqm6xdf.mjs +5 -0
- package/dist/{renderer-DiY70S8S.mjs → renderer-BMP_lYMk.mjs} +4 -4
- package/dist/{renderer-DiY70S8S.mjs.map → renderer-BMP_lYMk.mjs.map} +1 -1
- package/dist/renderer-BMfMMf0R.mjs +5 -0
- package/dist/{renderer-DkRSZg5g.mjs → renderer-BNbMi9CI.mjs} +5 -5
- package/dist/{renderer-DkRSZg5g.mjs.map → renderer-BNbMi9CI.mjs.map} +1 -1
- package/dist/{renderer-D7Al3_-5.mjs → renderer-BPYIqtNg.mjs} +5 -5
- package/dist/{renderer-D7Al3_-5.mjs.map → renderer-BPYIqtNg.mjs.map} +1 -1
- package/dist/renderer-BPsjEnnl.mjs +5 -0
- package/dist/{renderer-DDEkFbVI.mjs → renderer-BQOeeXTr.mjs} +5 -5
- package/dist/{renderer-DDEkFbVI.mjs.map → renderer-BQOeeXTr.mjs.map} +1 -1
- package/dist/{renderer-GBmWjBvy.mjs → renderer-BRWjLiHX.mjs} +3 -3
- package/dist/{renderer-GBmWjBvy.mjs.map → renderer-BRWjLiHX.mjs.map} +1 -1
- package/dist/{renderer-_iMAO698.mjs → renderer-BVql26Ay.mjs} +2 -2
- package/dist/{renderer-_iMAO698.mjs.map → renderer-BVql26Ay.mjs.map} +1 -1
- package/dist/{renderer-CHr7MiYW.mjs → renderer-BWMzjSgf.mjs} +5 -5
- package/dist/{renderer-CHr7MiYW.mjs.map → renderer-BWMzjSgf.mjs.map} +1 -1
- package/dist/{renderer-pHWEHDnM.mjs → renderer-BYqrtBvd.mjs} +5 -5
- package/dist/{renderer-pHWEHDnM.mjs.map → renderer-BYqrtBvd.mjs.map} +1 -1
- package/dist/{renderer-CwFqqpWY.mjs → renderer-BZmmekE8.mjs} +4 -4
- package/dist/{renderer-CwFqqpWY.mjs.map → renderer-BZmmekE8.mjs.map} +1 -1
- package/dist/{renderer-D47AEJE_.mjs → renderer-BcO7LUla.mjs} +3 -3
- package/dist/{renderer-D47AEJE_.mjs.map → renderer-BcO7LUla.mjs.map} +1 -1
- package/dist/{renderer-BlvGcyAN.mjs → renderer-BdbI_u9w.mjs} +3 -3
- package/dist/{renderer-BlvGcyAN.mjs.map → renderer-BdbI_u9w.mjs.map} +1 -1
- package/dist/{renderer-DPAD6fL1.mjs → renderer-Be5hfwSd.mjs} +74 -74
- package/dist/{renderer-DPAD6fL1.mjs.map → renderer-Be5hfwSd.mjs.map} +1 -1
- package/dist/{renderer-BAYTI6jj.mjs → renderer-BfbSvElt.mjs} +4 -4
- package/dist/{renderer-BAYTI6jj.mjs.map → renderer-BfbSvElt.mjs.map} +1 -1
- package/dist/{renderer-BpIF1QIE.mjs → renderer-BgDLCCuq.mjs} +5 -5
- package/dist/{renderer-BpIF1QIE.mjs.map → renderer-BgDLCCuq.mjs.map} +1 -1
- package/dist/renderer-Bofr6f88.mjs +6 -0
- package/dist/renderer-BqoGcujR.mjs +5 -0
- package/dist/renderer-BvuBt2aH.mjs +5 -0
- package/dist/renderer-BxTgXHu1.mjs +5 -0
- package/dist/renderer-Bz2Rrz60.mjs +5 -0
- package/dist/{renderer-g_vrrAQU.mjs → renderer-C06U4c9k.mjs} +3 -3
- package/dist/{renderer-g_vrrAQU.mjs.map → renderer-C06U4c9k.mjs.map} +1 -1
- package/dist/{renderer-D7r6onRT.mjs → renderer-C3Iev6zu.mjs} +4 -4
- package/dist/{renderer-D7r6onRT.mjs.map → renderer-C3Iev6zu.mjs.map} +1 -1
- package/dist/{renderer-CpUJBOfb.mjs → renderer-C3tVrzyT.mjs} +3 -3
- package/dist/{renderer-SWr3vbrV.mjs → renderer-C4yKI8MT.mjs} +3 -3
- package/dist/{renderer-SWr3vbrV.mjs.map → renderer-C4yKI8MT.mjs.map} +1 -1
- package/dist/{renderer-Xv6GfNUI.mjs → renderer-C6st34I6.mjs} +3 -3
- package/dist/{renderer-Xv6GfNUI.mjs.map → renderer-C6st34I6.mjs.map} +1 -1
- package/dist/{renderer-sCovEubT.mjs → renderer-C7MAqpIS.mjs} +4 -4
- package/dist/{renderer-sCovEubT.mjs.map → renderer-C7MAqpIS.mjs.map} +1 -1
- package/dist/renderer-CBjG8rjE.mjs +5 -0
- package/dist/{renderer-BAusZ6Vu.mjs → renderer-CCFHnafT.mjs} +4 -4
- package/dist/{renderer-BAusZ6Vu.mjs.map → renderer-CCFHnafT.mjs.map} +1 -1
- package/dist/{renderer-DVCJjVn7.mjs → renderer-CDVb4OfJ.mjs} +5 -5
- package/dist/{renderer-DVCJjVn7.mjs.map → renderer-CDVb4OfJ.mjs.map} +1 -1
- package/dist/{renderer-DpruWmZU.mjs → renderer-CEfVvcw-.mjs} +4 -4
- package/dist/{renderer-DpruWmZU.mjs.map → renderer-CEfVvcw-.mjs.map} +1 -1
- package/dist/{renderer-DbRZe0Re.mjs → renderer-CIB5L_C4.mjs} +5 -5
- package/dist/{renderer-DbRZe0Re.mjs.map → renderer-CIB5L_C4.mjs.map} +1 -1
- package/dist/{renderer-ktWXVYka.mjs → renderer-CPTXJs0n.mjs} +6 -6
- package/dist/{renderer-ktWXVYka.mjs.map → renderer-CPTXJs0n.mjs.map} +1 -1
- package/dist/renderer-CS2zyPyZ.mjs +5 -0
- package/dist/{renderer-CcvvoKiZ.mjs → renderer-CUBDxuxh.mjs} +5 -5
- package/dist/{renderer-CcvvoKiZ.mjs.map → renderer-CUBDxuxh.mjs.map} +1 -1
- package/dist/renderer-CWLF6cAz.mjs +1008 -0
- package/dist/renderer-CWLF6cAz.mjs.map +1 -0
- package/dist/{renderer-EaLUCobW.mjs → renderer-CXLugAe8.mjs} +4 -4
- package/dist/{renderer-EaLUCobW.mjs.map → renderer-CXLugAe8.mjs.map} +1 -1
- package/dist/renderer-CXnbl_jR.mjs +5 -0
- package/dist/{renderer-C7L8Ceqr.mjs → renderer-CYX9vKZ-.mjs} +4 -4
- package/dist/{renderer-C7L8Ceqr.mjs.map → renderer-CYX9vKZ-.mjs.map} +1 -1
- package/dist/{renderer-8QIwXh7O.mjs → renderer-C_2UDMEG.mjs} +6 -6
- package/dist/{renderer-8QIwXh7O.mjs.map → renderer-C_2UDMEG.mjs.map} +1 -1
- package/dist/renderer-CaF9vod_.mjs +5 -0
- package/dist/renderer-CbSBH3lp.mjs +5 -0
- package/dist/{renderer-B2jjxsjO.mjs → renderer-CbhnJi_8.mjs} +4 -4
- package/dist/{renderer-B2jjxsjO.mjs.map → renderer-CbhnJi_8.mjs.map} +1 -1
- package/dist/{renderer-BdyopiLC.mjs → renderer-CcJyD9Q5.mjs} +4 -4
- package/dist/{renderer-BdyopiLC.mjs.map → renderer-CcJyD9Q5.mjs.map} +1 -1
- package/dist/renderer-CdjuGRbO.mjs +5 -0
- package/dist/{renderer-DF-yvIrV.mjs → renderer-Cl8r1LJe.mjs} +4 -4
- package/dist/{renderer-DF-yvIrV.mjs.map → renderer-Cl8r1LJe.mjs.map} +1 -1
- package/dist/renderer-CoLbxC13.mjs +5 -0
- package/dist/{renderer-BgO6BA_z.mjs → renderer-CpedZNEG.mjs} +3 -3
- package/dist/{renderer-BgO6BA_z.mjs.map → renderer-CpedZNEG.mjs.map} +1 -1
- package/dist/renderer-Cr9G0dXB.mjs +5 -0
- package/dist/{renderer-bAKUeHF3.mjs → renderer-CwVbHki6.mjs} +5 -5
- package/dist/{renderer-bAKUeHF3.mjs.map → renderer-CwVbHki6.mjs.map} +1 -1
- package/dist/{renderer-DTqDy2m9.mjs → renderer-CyCtm0UV.mjs} +3 -3
- package/dist/{renderer-DTqDy2m9.mjs.map → renderer-CyCtm0UV.mjs.map} +1 -1
- package/dist/{renderer-CYC32bDW.mjs → renderer-D1VsqFf4.mjs} +5 -5
- package/dist/{renderer-CYC32bDW.mjs.map → renderer-D1VsqFf4.mjs.map} +1 -1
- package/dist/{renderer-CCycwCEB.mjs → renderer-D2TTDcgh.mjs} +3 -3
- package/dist/{renderer-CCycwCEB.mjs.map → renderer-D2TTDcgh.mjs.map} +1 -1
- package/dist/renderer-D63l6_UC.mjs +5 -0
- package/dist/renderer-DCJqnzER.mjs +5 -0
- package/dist/{renderer-cod5Ona9.mjs → renderer-DEQeONTd.mjs} +3 -3
- package/dist/renderer-DFBOR5J3.mjs +5 -0
- package/dist/renderer-DGAZSzw6.mjs +5 -0
- package/dist/{renderer-oKRF4A0M.mjs → renderer-DH7l5WFr.mjs} +4 -4
- package/dist/{renderer-oKRF4A0M.mjs.map → renderer-DH7l5WFr.mjs.map} +1 -1
- package/dist/{renderer-DNQvOrkY.mjs → renderer-DIEmK57T.mjs} +5 -5
- package/dist/{renderer-DNQvOrkY.mjs.map → renderer-DIEmK57T.mjs.map} +1 -1
- package/dist/{renderer-DEmYyaqj.mjs → renderer-DIqkhsLI.mjs} +4 -4
- package/dist/{renderer-DEmYyaqj.mjs.map → renderer-DIqkhsLI.mjs.map} +1 -1
- package/dist/{renderer-DX41niRU.mjs → renderer-DOKHd37M.mjs} +4 -4
- package/dist/{renderer-DX41niRU.mjs.map → renderer-DOKHd37M.mjs.map} +1 -1
- package/dist/renderer-DPLGk1Qk.mjs +5 -0
- package/dist/renderer-DTCUzByS.mjs +5 -0
- package/dist/{renderer-BXJXziIt.mjs → renderer-DW7hbluw.mjs} +3 -3
- package/dist/{renderer-BXJXziIt.mjs.map → renderer-DW7hbluw.mjs.map} +1 -1
- package/dist/{renderer--fkmiVjl.mjs → renderer-Dat8opUZ.mjs} +4 -4
- package/dist/{renderer--fkmiVjl.mjs.map → renderer-Dat8opUZ.mjs.map} +1 -1
- package/dist/renderer-DdGahYi1.mjs +5 -0
- package/dist/{renderer-DmkWrWAk.mjs → renderer-Dee8ksIV.mjs} +3 -3
- package/dist/{renderer-DmkWrWAk.mjs.map → renderer-Dee8ksIV.mjs.map} +1 -1
- package/dist/renderer-DhL4nNPk.mjs +5 -0
- package/dist/renderer-DkyTbiVz.mjs +3 -0
- package/dist/renderer-DnAZweRX.mjs +5 -0
- package/dist/{renderer-BX7jS14r.d.mts → renderer-DoPEPlbG.d.mts} +3 -2
- package/dist/{renderer-BX7jS14r.d.mts.map → renderer-DoPEPlbG.d.mts.map} +1 -1
- package/dist/renderer-DpisVnT2.mjs +5 -0
- package/dist/{renderer-mNSyac1V.mjs → renderer-DrWeb39d.mjs} +1 -1
- package/dist/{renderer-mNSyac1V.mjs.map → renderer-DrWeb39d.mjs.map} +1 -1
- package/dist/renderer-Ds7pAKnE.mjs +3 -0
- package/dist/{renderer-CiQhD8Gg.mjs → renderer-Dss7T71q.mjs} +5 -5
- package/dist/{renderer-CiQhD8Gg.mjs.map → renderer-Dss7T71q.mjs.map} +1 -1
- package/dist/{renderer-C41U1tK6.mjs → renderer-Du-GnKLb.mjs} +9 -9
- package/dist/{renderer-C41U1tK6.mjs.map → renderer-Du-GnKLb.mjs.map} +1 -1
- package/dist/renderer-DxZD5B54.mjs +5 -0
- package/dist/{renderer-WCZu2Rf5.mjs → renderer-ESkPj6pk.mjs} +4 -4
- package/dist/{renderer-WCZu2Rf5.mjs.map → renderer-ESkPj6pk.mjs.map} +1 -1
- package/dist/{renderer-DMvmf3T2.mjs → renderer-F1D9ZJ8I.mjs} +3 -3
- package/dist/{renderer-BlPqTEii.mjs → renderer-HnSiwSW8.mjs} +4 -4
- package/dist/{renderer-BlPqTEii.mjs.map → renderer-HnSiwSW8.mjs.map} +1 -1
- package/dist/{renderer-1r-Uq-Ae.mjs → renderer-IQ97z2rw.mjs} +3 -3
- package/dist/{renderer-1r-Uq-Ae.mjs.map → renderer-IQ97z2rw.mjs.map} +1 -1
- package/dist/{renderer-DFzI3yI_.mjs → renderer-NTCk1Srf.mjs} +3 -3
- package/dist/{renderer-DFzI3yI_.mjs.map → renderer-NTCk1Srf.mjs.map} +1 -1
- package/dist/{renderer-D8bBHrWC.mjs → renderer-OsQRvOle.mjs} +5 -5
- package/dist/{renderer-D8bBHrWC.mjs.map → renderer-OsQRvOle.mjs.map} +1 -1
- package/dist/renderer-PMHOnbnA.mjs +5 -0
- package/dist/renderer-STufNpMx.mjs +5 -0
- package/dist/renderer-SdrgfCxH.mjs +5 -0
- package/dist/{renderer-Lth37j17.mjs → renderer-US4GsamT.mjs} +3 -3
- package/dist/{renderer-zXPVLRlD.mjs → renderer-VhkubIx_.mjs} +5 -5
- package/dist/{renderer-zXPVLRlD.mjs.map → renderer-VhkubIx_.mjs.map} +1 -1
- package/dist/{renderer-DIw3UtEU.mjs → renderer-bbaMOD4I.mjs} +5 -5
- package/dist/{renderer-DIw3UtEU.mjs.map → renderer-bbaMOD4I.mjs.map} +1 -1
- package/dist/{renderer-hSCfnvaK.mjs → renderer-eT7Gp7FS.mjs} +5 -5
- package/dist/{renderer-hSCfnvaK.mjs.map → renderer-eT7Gp7FS.mjs.map} +1 -1
- package/dist/{renderer-CQvmbRQ5.mjs → renderer-g7fF2AYk.mjs} +5 -5
- package/dist/{renderer-CQvmbRQ5.mjs.map → renderer-g7fF2AYk.mjs.map} +1 -1
- package/dist/{renderer-B-ur0Ej8.mjs → renderer-mLlgfM7X.mjs} +4 -4
- package/dist/{renderer-B-ur0Ej8.mjs.map → renderer-mLlgfM7X.mjs.map} +1 -1
- package/dist/{renderer-SSBL4M1o.mjs → renderer-mQt-y49D.mjs} +5 -5
- package/dist/{renderer-SSBL4M1o.mjs.map → renderer-mQt-y49D.mjs.map} +1 -1
- package/dist/{renderer-BIGFP1cF.mjs → renderer-q4zMFfnY.mjs} +2 -2
- package/dist/{renderer-BIGFP1cF.mjs.map → renderer-q4zMFfnY.mjs.map} +1 -1
- package/dist/{renderer-DXEWbnRF.mjs → renderer-sPI7aY6c.mjs} +4 -4
- package/dist/{renderer-DXEWbnRF.mjs.map → renderer-sPI7aY6c.mjs.map} +1 -1
- package/dist/{renderer-sYSkIUfo.mjs → renderer-xDV2cCkX.mjs} +5 -5
- package/dist/{renderer-sYSkIUfo.mjs.map → renderer-xDV2cCkX.mjs.map} +1 -1
- package/dist/{renderers-CP8CFWDs-DH2oktaC.mjs → renderers-CP8CFWDs-BH1gUTYa.mjs} +4 -4
- package/dist/{renderers-CP8CFWDs-DH2oktaC.mjs.map → renderers-CP8CFWDs-BH1gUTYa.mjs.map} +1 -1
- package/dist/sam/index.d.mts +4 -0
- package/dist/sam/index.mjs +3 -0
- package/dist/signals/index.d.mts +7 -6
- package/dist/signals/index.mjs +8 -8
- package/dist/{signals-CXwgAUp-.mjs → signals-gOd0Ui9B.mjs} +4 -4
- package/dist/{signals-CXwgAUp-.mjs.map → signals-gOd0Ui9B.mjs.map} +1 -1
- package/dist/{src-DFEqficI.mjs → src-BU1VOWSk.mjs} +12 -18
- package/dist/src-BU1VOWSk.mjs.map +1 -0
- package/dist/{renderer-B2P1vgb7.mjs → src-Bnr8DUC--DzkRGA62.mjs} +8 -1008
- package/dist/src-Bnr8DUC--DzkRGA62.mjs.map +1 -0
- package/package.json +69 -69
- package/dist/audio-Ccpl9mjV.d.mts.map +0 -1
- package/dist/index-Bnh42ouE.d.mts.map +0 -1
- package/dist/index-CQ-bbZk3.d.mts.map +0 -1
- package/dist/index-D5UDyVMb.d.mts.map +0 -1
- package/dist/renderer--Ac-dg4A.mjs +0 -5
- package/dist/renderer--N7TMqzU.mjs +0 -5
- package/dist/renderer-2ecmdOae.mjs +0 -5
- package/dist/renderer-B2P1vgb7.mjs.map +0 -1
- package/dist/renderer-B5RJp5g-.mjs +0 -5
- package/dist/renderer-B7xyT1Vb.mjs +0 -5
- package/dist/renderer-BBeArN_x.mjs +0 -5
- package/dist/renderer-BCAZDu-r.mjs +0 -5
- package/dist/renderer-BJnhik7Y.mjs +0 -5
- package/dist/renderer-BxRW8MZO.mjs +0 -5
- package/dist/renderer-C-lfsEAN.mjs +0 -5
- package/dist/renderer-C6nOFN4-.mjs +0 -5
- package/dist/renderer-C84TSQmS.mjs +0 -5
- package/dist/renderer-C8_6YofT.mjs +0 -5
- package/dist/renderer-COb3tOPG.mjs +0 -5
- package/dist/renderer-CSCIzaLy.mjs +0 -5
- package/dist/renderer-CmI4c8MS.mjs +0 -5
- package/dist/renderer-CqVltdX9.mjs +0 -5
- package/dist/renderer-D-FpMzLY.mjs +0 -5
- package/dist/renderer-D-Oyn9mG.mjs +0 -5
- package/dist/renderer-D2QrkA8_.mjs +0 -5
- package/dist/renderer-D5bjOx83.mjs +0 -3
- package/dist/renderer-D64r4iN-.mjs +0 -5
- package/dist/renderer-DCq6YkgP.mjs +0 -5
- package/dist/renderer-DDHG3GdR.mjs +0 -5
- package/dist/renderer-DMdNfcud.mjs +0 -6
- package/dist/renderer-DZQXZ4lK.mjs +0 -5
- package/dist/renderer-DczJJLA1.mjs +0 -5
- package/dist/renderer-DfqJj9oe.mjs +0 -5
- package/dist/renderer-DgO9ihVJ.mjs +0 -5
- package/dist/renderer-DhgnQZYb.mjs +0 -5
- package/dist/renderer-DjxKjHMf.mjs +0 -5
- package/dist/renderer-DnRDW2Oz.mjs +0 -3
- package/dist/renderer-DqLA5cdR.mjs +0 -5
- package/dist/renderer-Dudp6ZlH.mjs +0 -5
- package/dist/renderer-_jC5KIT1.mjs +0 -5
- package/dist/renderer-cTgAuVmJ.mjs +0 -5
- package/dist/renderer-nVKDvDLO.mjs +0 -5
- package/dist/renderer-pZ6_pUo1.mjs +0 -5
- package/dist/src-DFEqficI.mjs.map +0 -1
- /package/dist/{chunk-BcJoO4Nm.mjs → chunk-D8S17ehY.mjs} +0 -0
- /package/dist/{renderer-COqFNSfV.mjs → renderer-Cputd36d.mjs} +0 -0
|
@@ -0,0 +1,1434 @@
|
|
|
1
|
+
import { F as registerVisionModel, M as varint, O as readVarint, P as VISION_MODELS, _ as fields, b as lengthDelimited, g as encoder, h as createDefaultSessionProvider, j as strings, k as sessionCompute, m as concat, u as VisionModelStore, v as firstString, y as imageToTensor } from "./src-Bnr8DUC--DzkRGA62.mjs";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { Tokenizer } from "@huggingface/tokenizers";
|
|
4
|
+
|
|
5
|
+
//#region ../vision-sam/dist/index.mjs
|
|
6
|
+
const SAM_LICENSE_TERMS_URL = "https://github.com/facebookresearch/sam3/blob/main/LICENSE";
|
|
7
|
+
/**
|
|
8
|
+
* Ensures that the user has explicitly accepted Meta's SAM License terms before
|
|
9
|
+
* downloading SAM 3 weights or performing inference. SAM 2.1's weights are Apache-2.0 and
|
|
10
|
+
* need no acceptance.
|
|
11
|
+
*/
|
|
12
|
+
function assertSamLicenseAccepted(context = "SAM 3", options) {
|
|
13
|
+
if (options?.acceptLicense) return;
|
|
14
|
+
if (typeof process !== "undefined" && process.env?.FRAMEFIELDS_ACCEPT_SAM_LICENSE === "1") return;
|
|
15
|
+
throw new Error(`Meta SAM License agreement required for ${context}:\nSAM 3's model weights are subject to Meta's SAM License.\nReview terms at: ${SAM_LICENSE_TERMS_URL}\nTo download and run SAM 3 in Framefields, you must explicitly accept the terms by:\n 1. Passing 'acceptLicense: true' (or 'acceptSamLicense: true' in ClipVision options), or\n 2. Setting the environment variable FRAMEFIELDS_ACCEPT_SAM_LICENSE=1.`);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Diffusion Studio's fp16 video exports of Meta SAM 2.1 (Apache-2.0). Tiny is built for
|
|
19
|
+
* speed at 512² (32×32 features); Small runs SAM 2's native 1024² (64×64), resolving small
|
|
20
|
+
* objects, thin structures and identity after cuts better at roughly 4× the encoder and
|
|
21
|
+
* 16× the memory-attention work.
|
|
22
|
+
*/
|
|
23
|
+
const SAM2_EXPORTS = {
|
|
24
|
+
tiny: {
|
|
25
|
+
repo: "diffusionstudio/sam2.1-tiny-video-onnx-fp16",
|
|
26
|
+
revision: "66673b5db39371b7dd7847f4d3bc0d4f4179b79e",
|
|
27
|
+
size: 512,
|
|
28
|
+
name: "Hiera Tiny"
|
|
29
|
+
},
|
|
30
|
+
small: {
|
|
31
|
+
repo: "diffusionstudio/sam2.1-small-video-onnx-fp16",
|
|
32
|
+
revision: "927ecec6e6ae2727d0af7720eefdb07f2efe4689",
|
|
33
|
+
size: 1024,
|
|
34
|
+
name: "Hiera Small"
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* The encoder precision each backend runs fastest. Measured on an M1 Pro (one 1008² frame):
|
|
39
|
+
* WebGPU fp16 3.65 s, q4f16 4.43 s, q4 6.63 s, int8 140 s (its ops fall back to the CPU);
|
|
40
|
+
* fp16 is also the closest to full precision. On WebGPU, 4-bit weights are dequantized
|
|
41
|
+
* before every matmul, so they only save memory. CUDA runs fp16 on tensor cores. CPUs have
|
|
42
|
+
* no fast fp16 path, so they get fp32-activation q4.
|
|
43
|
+
*/
|
|
44
|
+
const SAM3_ENCODER = {
|
|
45
|
+
webgpu: "fp16",
|
|
46
|
+
cuda: "fp16",
|
|
47
|
+
cpu: "q4"
|
|
48
|
+
};
|
|
49
|
+
const SAM_LICENSE = "Meta SAM License";
|
|
50
|
+
const hf = (repo, revision, path) => `https://huggingface.co/${repo}/resolve/${revision}/${path}`;
|
|
51
|
+
const sam2 = (model$1, graph, [path, bytes, sha256]) => {
|
|
52
|
+
const { repo, revision, size, name } = SAM2_EXPORTS[model$1];
|
|
53
|
+
const key = `sam2.1-${model$1}-${graph}`;
|
|
54
|
+
return {
|
|
55
|
+
key,
|
|
56
|
+
family: "sam2",
|
|
57
|
+
filename: `${key}${path.slice(path.lastIndexOf("."))}`,
|
|
58
|
+
url: hf(repo, revision, path),
|
|
59
|
+
bytes,
|
|
60
|
+
sha256,
|
|
61
|
+
input: [size, size],
|
|
62
|
+
source: `Meta SAM 2.1 ${name} (Apache-2.0), Diffusion Studio ${size}px fp16 video export`,
|
|
63
|
+
license: "Apache-2.0"
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
const sam3 = (repo, revision) => (key, filename, [path, bytes, sha256]) => ({
|
|
67
|
+
key,
|
|
68
|
+
family: "sam3",
|
|
69
|
+
filename,
|
|
70
|
+
url: hf(repo, revision, path),
|
|
71
|
+
bytes,
|
|
72
|
+
sha256,
|
|
73
|
+
input: [1008, 1008],
|
|
74
|
+
source: `Meta SAM 3 (${SAM_LICENSE}), pinned ${repo} ONNX export`,
|
|
75
|
+
license: SAM_LICENSE
|
|
76
|
+
});
|
|
77
|
+
const tracker = sam3("onnx-community/sam3-tracker-ONNX", "429305c8a5b3de597243d919a07e4e6bdcd00ef7");
|
|
78
|
+
/** The tracker encoder at `precision`: its graph and the weights file the graph names. */
|
|
79
|
+
function encoder$1(precision, [graphBytes, graphSha], [dataBytes, dataSha]) {
|
|
80
|
+
const { graph, data } = sam3EncoderFiles(precision);
|
|
81
|
+
return [tracker(`sam3-vision_encoder-${precision}`, `sam3-${graph}`, [
|
|
82
|
+
`onnx/${graph}`,
|
|
83
|
+
graphBytes,
|
|
84
|
+
graphSha
|
|
85
|
+
]), tracker(`sam3-vision_encoder-${precision}-data`, `sam3-${data}`, [
|
|
86
|
+
`onnx/${data}`,
|
|
87
|
+
dataBytes,
|
|
88
|
+
dataSha
|
|
89
|
+
])];
|
|
90
|
+
}
|
|
91
|
+
/** File names of the encoder at `precision`; the graph refers to its weights by `data`. */
|
|
92
|
+
function sam3EncoderFiles(precision) {
|
|
93
|
+
const graph = `vision_encoder_${precision}.onnx`;
|
|
94
|
+
return {
|
|
95
|
+
graph,
|
|
96
|
+
data: `${graph}_data`
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const video = sam3("jax-image-tools/sam3-video-onnx", "e942689a73d942f83c69b5965881cb3a0f6153ba");
|
|
100
|
+
const support = sam3("RamRom/sam3-onnx", "68ce2746e903966a88549cdd08ab554ff9162db0");
|
|
101
|
+
const text$1 = sam3("danilobukvic/sam3-text-onnx", "fe8f8e123bfa42d4e57d14fa2f4928a4c60f4665");
|
|
102
|
+
const SUPPORT_GRAPH = "bundles/sam3-base-video-tracking-ortcuda-v2/graphs/base_tracker_preview_single1.onnx";
|
|
103
|
+
const SAM_MODELS = [
|
|
104
|
+
sam2("tiny", "constants", [
|
|
105
|
+
"constants.json",
|
|
106
|
+
9781,
|
|
107
|
+
"67583810f4b80b762285377a5cc1066bbe19cdf8ef7fc87ff6aa78fc79830ef2"
|
|
108
|
+
]),
|
|
109
|
+
sam2("tiny", "vision_encoder", [
|
|
110
|
+
"onnx/vision_encoder.onnx",
|
|
111
|
+
58385353,
|
|
112
|
+
"24e9ccf5994be5c8dd93ebe771a4cc4f8bb122d0524555ac3ba4e7141710b133"
|
|
113
|
+
]),
|
|
114
|
+
sam2("tiny", "mask_decoder", [
|
|
115
|
+
"onnx/mask_decoder.onnx",
|
|
116
|
+
8898805,
|
|
117
|
+
"6bc158b0d028777ca2e25203ece0f27429c436de39a5c7fe301b3858d6059789"
|
|
118
|
+
]),
|
|
119
|
+
sam2("tiny", "memory_encoder", [
|
|
120
|
+
"onnx/memory_encoder.onnx",
|
|
121
|
+
2807753,
|
|
122
|
+
"8b2bb6810444cee684ef938b7464c5645653f236014f5497c3db3654818cc7ce"
|
|
123
|
+
]),
|
|
124
|
+
sam2("tiny", "memory_attention", [
|
|
125
|
+
"onnx/memory_attention.onnx",
|
|
126
|
+
13029470,
|
|
127
|
+
"67c4e4da01bc7f501b88294bb19a8200362915ece04e9d7e367a437658f342c9"
|
|
128
|
+
]),
|
|
129
|
+
sam2("tiny", "pointer_tpos", [
|
|
130
|
+
"onnx/pointer_tpos.onnx",
|
|
131
|
+
34228,
|
|
132
|
+
"3ab5bfce40ed01208301b2d8f596b9c9f7f493dcd7e09ef01ec22e5be3694bd7"
|
|
133
|
+
]),
|
|
134
|
+
sam2("small", "constants", [
|
|
135
|
+
"constants.json",
|
|
136
|
+
9820,
|
|
137
|
+
"09397f7251c159b64a2d581cc3ea0dbb3cf720c2e60777cb14e244405ed1c305"
|
|
138
|
+
]),
|
|
139
|
+
sam2("small", "vision_encoder", [
|
|
140
|
+
"onnx/vision_encoder.onnx",
|
|
141
|
+
83679474,
|
|
142
|
+
"fb570036f5afac59ef20848958b075c84da746e333efd863104d94604652efc4"
|
|
143
|
+
]),
|
|
144
|
+
sam2("small", "mask_decoder", [
|
|
145
|
+
"onnx/mask_decoder.onnx",
|
|
146
|
+
8910345,
|
|
147
|
+
"999b3b47bf2e924d522ed6cc011fa2c9b651754cc07895eb0da16a28a5ce7c4d"
|
|
148
|
+
]),
|
|
149
|
+
sam2("small", "memory_encoder", [
|
|
150
|
+
"onnx/memory_encoder.onnx",
|
|
151
|
+
2807884,
|
|
152
|
+
"f36324e383dbf21fcd549169aedf698db00c307fd9a49538c0e5f0aa168e4f99"
|
|
153
|
+
]),
|
|
154
|
+
sam2("small", "memory_attention", [
|
|
155
|
+
"onnx/memory_attention.onnx",
|
|
156
|
+
16175204,
|
|
157
|
+
"6666be8ca502b5c16e9a113d3d3934996d32f27e93bee5e66a8317fcceec9985"
|
|
158
|
+
]),
|
|
159
|
+
sam2("small", "pointer_tpos", [
|
|
160
|
+
"onnx/pointer_tpos.onnx",
|
|
161
|
+
34228,
|
|
162
|
+
"f9c1b36e0aa9dc6b7c05b02a8fdaa17cc671d967ffcacc14fcd3177e65ec25e9"
|
|
163
|
+
]),
|
|
164
|
+
...encoder$1("fp16", [1263005, "f8c52be6de99124bb17f25792054406abc482ce3502166f948d5c5849cd14d02"], [934729728, "4b021a4d3068c9e9153f2f2fcc9e6d280156228671c00ab6c2ddfa737da7f151"]),
|
|
165
|
+
...encoder$1("q4f16", [1307816, "4b96732adab3d7d70ac0964ce540a61fad097fbc10c9b27612f47d676877cefc"], [295622656, "d1d60808376dbd48e34cf89feaee708c13abed229f2398ab512149db34fdab07"]),
|
|
166
|
+
...encoder$1("q4", [1320396, "b80cb1cb6ab80efe646ad49ffa11d398af76e8912eb966971932ef2d8e7fe11b"], [368954368, "be632cacb4a82ef8be28285e49821b9dd7f96e3231cb90df631890f367110555"]),
|
|
167
|
+
video("sam3-mask_decoder", "sam3-mask_decoder.onnx", [
|
|
168
|
+
"mask_decoder.onnx",
|
|
169
|
+
17809322,
|
|
170
|
+
"4dff9a588828eeceba4285be85fb9c2a0306447ad642d02b1d8f6bfff1f19af9"
|
|
171
|
+
]),
|
|
172
|
+
video("sam3-memory_encoder", "sam3-memory_encoder.onnx", [
|
|
173
|
+
"memory_encoder.onnx",
|
|
174
|
+
5587704,
|
|
175
|
+
"78146118c2f91073489926bb587a81f129c391b2e0d1dba3aede6fbaa699498f"
|
|
176
|
+
]),
|
|
177
|
+
video("sam3-memory_attention", "sam3-memory_attention.onnx", [
|
|
178
|
+
"memory_attention.onnx",
|
|
179
|
+
34592488,
|
|
180
|
+
"8b24dc20acbb485b81f0e67ed0980b747aaa836707ccff4567a87e59c0ca1c24"
|
|
181
|
+
]),
|
|
182
|
+
support("sam3-support", "sam3-base_tracker_preview_single1.onnx", [
|
|
183
|
+
SUPPORT_GRAPH,
|
|
184
|
+
3064674,
|
|
185
|
+
"d80c1958175d5de6ca72f5b95d24d853dbdb511e0851d5918a4dcf7ed000f3ea"
|
|
186
|
+
]),
|
|
187
|
+
support("sam3-support-data", "sam3-base_tracker_preview_single1.onnx.data", [
|
|
188
|
+
`${SUPPORT_GRAPH}.data`,
|
|
189
|
+
63668224,
|
|
190
|
+
"618f62fbac368e863ee295526efd84ca768fb9914c7e1a5d9f1fb0f28837dda1"
|
|
191
|
+
]),
|
|
192
|
+
text$1("sam3-text-vision_encoder", "sam3-vision_encoder_int4_fp16attn.onnx", [
|
|
193
|
+
"vision_encoder_int4_fp16attn.onnx",
|
|
194
|
+
5216609,
|
|
195
|
+
"9d148134938a6a284a829733774d3b1356a706a3397bb1d4be240bf041e3ac0e"
|
|
196
|
+
]),
|
|
197
|
+
text$1("sam3-text-vision_encoder-data", "sam3-vision_encoder_int4_fp16attn.onnx.data", [
|
|
198
|
+
"vision_encoder_int4_fp16attn.onnx.data",
|
|
199
|
+
292836352,
|
|
200
|
+
"b89c9156064e926761f29be3f87b160fd34f4c93f1de46593295d155621829a2"
|
|
201
|
+
]),
|
|
202
|
+
text$1("sam3-text-encoder", "sam3-text_encoder_int8.onnx", [
|
|
203
|
+
"text_encoder_int8.onnx",
|
|
204
|
+
357021801,
|
|
205
|
+
"c0baf8a4165ecc4039bee9389903723e74a68d617d685a4f1dbfc21c58bb4121"
|
|
206
|
+
]),
|
|
207
|
+
text$1("sam3-text-decoder", "sam3-decoder_int8.onnx", [
|
|
208
|
+
"decoder_int8.onnx",
|
|
209
|
+
26804694,
|
|
210
|
+
"d721e7b643bb3ee2c48a59d520401c035c702cfbb13cb7f50fa103f0beb27af8"
|
|
211
|
+
]),
|
|
212
|
+
text$1("sam3-tokenizer", "sam3-tokenizer.json", [
|
|
213
|
+
"tokenizer.json",
|
|
214
|
+
3642073,
|
|
215
|
+
"6d9109cc838977f3ca94a379eec36aecc7c807e1785cd729660ca2fc0171fb35"
|
|
216
|
+
]),
|
|
217
|
+
text$1("sam3-tokenizer-config", "sam3-tokenizer_config.json", [
|
|
218
|
+
"tokenizer_config.json",
|
|
219
|
+
799,
|
|
220
|
+
"39670ad98457fe8f14ca59f6bb74591e9fc850974380a63993e5b8ffc865baa2"
|
|
221
|
+
])
|
|
222
|
+
];
|
|
223
|
+
/** Registers the SAM descriptors into the shared vision registry (idempotent). */
|
|
224
|
+
function ensureSamModelsRegistered() {
|
|
225
|
+
for (const descriptor of SAM_MODELS) if (!VISION_MODELS[descriptor.key]) registerVisionModel(descriptor);
|
|
226
|
+
}
|
|
227
|
+
var Sam2MemoryBank = class {
|
|
228
|
+
seed;
|
|
229
|
+
recent = [];
|
|
230
|
+
constructor(temporal) {
|
|
231
|
+
this.temporal = temporal;
|
|
232
|
+
}
|
|
233
|
+
remember(memory, prompted) {
|
|
234
|
+
if (prompted) {
|
|
235
|
+
this.seed = memory;
|
|
236
|
+
this.recent = [];
|
|
237
|
+
} else {
|
|
238
|
+
this.recent.push(memory);
|
|
239
|
+
if (this.recent.length > 15) this.recent.shift();
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
assemble(frame, frameCount = 16) {
|
|
243
|
+
if (!this.seed) throw new Error("SAM 2 must be prompted before propagation.");
|
|
244
|
+
const newest = [...this.recent].reverse();
|
|
245
|
+
const blocks = [this.seed, ...newest.slice(0, 6)];
|
|
246
|
+
while (blocks.length < 7) blocks.push(blocks[1] ?? this.seed);
|
|
247
|
+
const pointers = [this.seed, ...newest].slice(0, 16);
|
|
248
|
+
while (pointers.length < 16) pointers.push(pointers[pointers.length - 1]);
|
|
249
|
+
const length = this.seed.tokens.length;
|
|
250
|
+
const memory = new Float32Array(length * 7 + 16 * 256);
|
|
251
|
+
const positions = new Float32Array(memory.length);
|
|
252
|
+
for (const [slot, block] of blocks.entries()) {
|
|
253
|
+
memory.set(block.tokens, slot * length);
|
|
254
|
+
const available = Math.min(slot, this.recent.length);
|
|
255
|
+
const row = this.temporal[slot === 0 || available === 0 ? 6 : available - 1];
|
|
256
|
+
writePositions(positions, slot * length, block.positions, row);
|
|
257
|
+
}
|
|
258
|
+
const distances = new Float32Array(16);
|
|
259
|
+
for (const [i, entry] of pointers.entries()) {
|
|
260
|
+
memory.set(entry.pointer, length * 7 + i * 256);
|
|
261
|
+
distances[i] = Math.abs(frame - entry.frame) / Math.max(1, Math.min(frameCount, 16) - 1);
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
memory,
|
|
265
|
+
positions,
|
|
266
|
+
distances
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
/** NCHW features to the sequence-major layout consumed by memory attention. */
|
|
271
|
+
function sam2Tokens(data) {
|
|
272
|
+
const count = data.length / 256;
|
|
273
|
+
const result = new Float32Array(data.length);
|
|
274
|
+
for (let channel = 0; channel < 256; channel++) for (let token = 0; token < count; token++) result[token * 256 + channel] = data[channel * count + token] ?? 0;
|
|
275
|
+
return result;
|
|
276
|
+
}
|
|
277
|
+
function writePositions(target, offset, spatial, temporal) {
|
|
278
|
+
if (!temporal || temporal.length !== 64) throw new Error("Invalid SAM 2 temporal encoding.");
|
|
279
|
+
for (let i = 0; i < spatial.length; i++) target[offset + i] = (spatial[i] ?? 0) + (temporal[i % 64] ?? 0);
|
|
280
|
+
}
|
|
281
|
+
function validateSam2Prompts(prompts) {
|
|
282
|
+
if (prompts.length === 0) throw new Error("SAM 2 requires at least one prompt.");
|
|
283
|
+
let previous = -1;
|
|
284
|
+
for (const prompt of prompts) {
|
|
285
|
+
if (!Number.isSafeInteger(prompt.frame) || prompt.frame <= previous) throw new Error("SAM 2 prompt frames must be nonnegative, unique and increasing.");
|
|
286
|
+
previous = prompt.frame;
|
|
287
|
+
if (prompt.points.length === 0) throw new Error("SAM 2 prompts need points or a box.");
|
|
288
|
+
for (const point of prompt.points) validatePoint(point);
|
|
289
|
+
const corners = prompt.points.filter((point) => point.label >= 2);
|
|
290
|
+
if (corners.length && (corners.length !== 2 || corners[0]?.label !== 2 || corners[1]?.label !== 3 || corners[0].x >= corners[1].x || corners[0].y >= corners[1].y)) throw new Error("SAM 2 boxes need top-left (2) and bottom-right (3) corners.");
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
function validatePoint(point) {
|
|
294
|
+
if (![
|
|
295
|
+
0,
|
|
296
|
+
1,
|
|
297
|
+
2,
|
|
298
|
+
3
|
|
299
|
+
].includes(point.label) || !Number.isFinite(point.x) || !Number.isFinite(point.y) || point.x < 0 || point.x > 1 || point.y < 0 || point.y > 1) throw new Error("SAM 2 points require normalized coordinates and labels 0, 1, 2 or 3.");
|
|
300
|
+
}
|
|
301
|
+
const constantsSchema = z.object({
|
|
302
|
+
image_size: z.number().int().positive().multipleOf(16),
|
|
303
|
+
memory_frames: z.literal(7),
|
|
304
|
+
image_mean: z.tuple([
|
|
305
|
+
z.number(),
|
|
306
|
+
z.number(),
|
|
307
|
+
z.number()
|
|
308
|
+
]),
|
|
309
|
+
image_std: z.tuple([
|
|
310
|
+
z.number().positive(),
|
|
311
|
+
z.number().positive(),
|
|
312
|
+
z.number().positive()
|
|
313
|
+
]),
|
|
314
|
+
memory_temporal_positional_encoding: z.array(z.array(z.number()).length(64)).length(7)
|
|
315
|
+
});
|
|
316
|
+
const GRAPHS = [
|
|
317
|
+
"vision_encoder",
|
|
318
|
+
"mask_decoder",
|
|
319
|
+
"memory_encoder",
|
|
320
|
+
"memory_attention",
|
|
321
|
+
"pointer_tpos"
|
|
322
|
+
];
|
|
323
|
+
/** The pinned export revision of `model`: part of ClipVision's persistent cache identity. */
|
|
324
|
+
function sam2Revision(model$1 = "tiny") {
|
|
325
|
+
return `sam2.1-${model$1}-${SAM2_EXPORTS[model$1].revision}`;
|
|
326
|
+
}
|
|
327
|
+
function floats(outputs, name) {
|
|
328
|
+
const tensor$2 = outputs[name];
|
|
329
|
+
if (!tensor$2 || !(tensor$2.data instanceof Float32Array)) throw new Error(`Missing SAM 2 float output: ${name}`);
|
|
330
|
+
return tensor$2.data;
|
|
331
|
+
}
|
|
332
|
+
function input(name, tensor$2) {
|
|
333
|
+
if (tensor$2.data instanceof BigInt64Array) throw new Error(`Unsupported SAM 2 input type: ${name}`);
|
|
334
|
+
return {
|
|
335
|
+
name,
|
|
336
|
+
data: tensor$2.data,
|
|
337
|
+
dims: tensor$2.dims
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
function tensor$1(name, data, dims) {
|
|
341
|
+
return {
|
|
342
|
+
name,
|
|
343
|
+
data,
|
|
344
|
+
dims
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
/** Complete pinned SAM 2.1 video graph pipeline (Tiny or Small), one explicitly selected object. */
|
|
348
|
+
var Sam2Tracker = class Sam2Tracker$1 {
|
|
349
|
+
sessions = /* @__PURE__ */ new Map();
|
|
350
|
+
bank;
|
|
351
|
+
/** Model input side; image features are `size / 16` square, one memory token per cell. */
|
|
352
|
+
size;
|
|
353
|
+
tokens;
|
|
354
|
+
lastFrame = -1;
|
|
355
|
+
released = false;
|
|
356
|
+
constructor(constants, frameCount = 16) {
|
|
357
|
+
this.constants = constants;
|
|
358
|
+
this.frameCount = frameCount;
|
|
359
|
+
this.bank = new Sam2MemoryBank(constants.memory_temporal_positional_encoding);
|
|
360
|
+
this.size = constants.image_size;
|
|
361
|
+
this.tokens = (this.size / 16) ** 2;
|
|
362
|
+
}
|
|
363
|
+
static async create(options = {}) {
|
|
364
|
+
ensureSamModelsRegistered();
|
|
365
|
+
const store = options.store ?? new VisionModelStore(options);
|
|
366
|
+
const model$1 = options.model ?? "tiny";
|
|
367
|
+
if (!(model$1 in SAM2_EXPORTS)) throw new Error(`Unknown SAM 2.1 model "${model$1}"; use "tiny" or "small".`);
|
|
368
|
+
const bytes = await store.ensure(`sam2.1-${model$1}-constants`);
|
|
369
|
+
const constants = constantsSchema.parse(JSON.parse(new TextDecoder().decode(bytes)));
|
|
370
|
+
if (options.frameCount !== void 0 && (!Number.isSafeInteger(options.frameCount) || options.frameCount < 1)) throw new Error("SAM 2 frameCount must be a positive integer.");
|
|
371
|
+
const tracker$1 = new Sam2Tracker$1(constants, options.frameCount);
|
|
372
|
+
const provider = options.provider ?? createDefaultSessionProvider();
|
|
373
|
+
try {
|
|
374
|
+
for (const graph of GRAPHS) {
|
|
375
|
+
const session = await provider.createSession(await store.ensure(`sam2.1-${model$1}-${graph}`));
|
|
376
|
+
tracker$1.sessions.set(graph, session);
|
|
377
|
+
}
|
|
378
|
+
return tracker$1;
|
|
379
|
+
} catch (error) {
|
|
380
|
+
tracker$1.release();
|
|
381
|
+
throw error;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
run(graph, inputs) {
|
|
385
|
+
const session = this.sessions.get(graph);
|
|
386
|
+
if (!session) throw new Error("SAM 2 tracker has been released.");
|
|
387
|
+
if (session.runMany) return session.runMany(inputs);
|
|
388
|
+
if (inputs.length === 1 && inputs[0]) return session.run(inputs[0]);
|
|
389
|
+
throw new Error("SAM 2 requires a session provider with runMany support.");
|
|
390
|
+
}
|
|
391
|
+
async process(image, frame, points) {
|
|
392
|
+
if (this.released) throw new Error("SAM 2 tracker has been released.");
|
|
393
|
+
if (!Number.isSafeInteger(frame) || frame < 0 || this.lastFrame >= 0 && frame !== this.lastFrame + 1) throw new Error("SAM 2 propagation requires consecutive source frames.");
|
|
394
|
+
if (points) validateSam2Prompts([{
|
|
395
|
+
frame,
|
|
396
|
+
points
|
|
397
|
+
}]);
|
|
398
|
+
if (this.lastFrame < 0 && !points) throw new Error("SAM 2 needs a prompt on its first frame.");
|
|
399
|
+
const { tensor: pixels } = imageToTensor(image, {
|
|
400
|
+
width: this.size,
|
|
401
|
+
height: this.size,
|
|
402
|
+
fit: "stretch",
|
|
403
|
+
channels: "rgb",
|
|
404
|
+
padValue: 0,
|
|
405
|
+
mean: this.constants.image_mean.map((v) => v * 255),
|
|
406
|
+
std: this.constants.image_std.map((v) => v * 255)
|
|
407
|
+
});
|
|
408
|
+
const vision = await this.run("vision_encoder", [tensor$1("pixel_values", pixels, [
|
|
409
|
+
1,
|
|
410
|
+
3,
|
|
411
|
+
this.size,
|
|
412
|
+
this.size
|
|
413
|
+
])]);
|
|
414
|
+
const conditioned = points ? vision.feats2_no_mem : await this.condition(vision, frame);
|
|
415
|
+
if (!conditioned || !vision.feats0 || !vision.feats1) throw new Error("Invalid SAM 2 vision outputs.");
|
|
416
|
+
const prompt = points ?? [{
|
|
417
|
+
x: 0,
|
|
418
|
+
y: 0,
|
|
419
|
+
label: -1
|
|
420
|
+
}];
|
|
421
|
+
const decoded = await this.run("mask_decoder", [
|
|
422
|
+
input("feats0", vision.feats0),
|
|
423
|
+
input("feats1", vision.feats1),
|
|
424
|
+
input("feats2_cond", conditioned),
|
|
425
|
+
tensor$1("input_points", Float32Array.from(prompt.flatMap((p) => [p.x * this.size, p.y * this.size])), [
|
|
426
|
+
1,
|
|
427
|
+
1,
|
|
428
|
+
prompt.length,
|
|
429
|
+
2
|
|
430
|
+
]),
|
|
431
|
+
tensor$1("input_labels", Int32Array.from(prompt.map((p) => p.label)), [
|
|
432
|
+
1,
|
|
433
|
+
1,
|
|
434
|
+
prompt.length
|
|
435
|
+
])
|
|
436
|
+
]);
|
|
437
|
+
await this.remember(vision, decoded, frame, points !== void 0);
|
|
438
|
+
this.lastFrame = frame;
|
|
439
|
+
return decodeSam2Mask(floats(decoded, "high_res_mask"), image.width, image.height, floats(decoded, "object_score_logits")[0] ?? -Infinity, floats(decoded, "iou")[0] ?? 0);
|
|
440
|
+
}
|
|
441
|
+
async condition(vision, frame) {
|
|
442
|
+
const bank = this.bank.assemble(frame, this.frameCount);
|
|
443
|
+
const positions = floats(await this.run("pointer_tpos", [tensor$1("normalized_diffs", bank.distances, [16])]), "pointer_pos");
|
|
444
|
+
for (let i = 0; i < 16; i++) for (let token = 0; token < 4; token++) bank.positions.set(positions.subarray(i * 64, (i + 1) * 64), 7 * this.tokens * 64 + (i * 4 + token) * 64);
|
|
445
|
+
const memoryLength = 7 * this.tokens + 64;
|
|
446
|
+
const conditioned = (await this.run("memory_attention", [
|
|
447
|
+
tensor$1("current_vision_features", sam2Tokens(floats(vision, "feats2")), [
|
|
448
|
+
this.tokens,
|
|
449
|
+
1,
|
|
450
|
+
256
|
|
451
|
+
]),
|
|
452
|
+
tensor$1("current_vision_position_embeddings", sam2Tokens(floats(vision, "vision_pos_embed")), [
|
|
453
|
+
this.tokens,
|
|
454
|
+
1,
|
|
455
|
+
256
|
|
456
|
+
]),
|
|
457
|
+
tensor$1("memory", bank.memory, [
|
|
458
|
+
memoryLength,
|
|
459
|
+
1,
|
|
460
|
+
64
|
|
461
|
+
]),
|
|
462
|
+
tensor$1("memory_pos", bank.positions, [
|
|
463
|
+
memoryLength,
|
|
464
|
+
1,
|
|
465
|
+
64
|
|
466
|
+
])
|
|
467
|
+
])).conditioned_feats;
|
|
468
|
+
if (!conditioned) throw new Error("Missing SAM 2 conditioned features.");
|
|
469
|
+
return conditioned;
|
|
470
|
+
}
|
|
471
|
+
async remember(vision, decoded, frame, prompted) {
|
|
472
|
+
if (!vision.feats2 || !decoded.high_res_mask) throw new Error("Invalid SAM 2 memory inputs.");
|
|
473
|
+
const memory = await this.run("memory_encoder", [
|
|
474
|
+
input("feats2", vision.feats2),
|
|
475
|
+
input("high_res_mask", decoded.high_res_mask),
|
|
476
|
+
tensor$1("object_score_logits", floats(decoded, "object_score_logits"), [1, 1]),
|
|
477
|
+
tensor$1("binarize", new Float32Array([prompted ? 1 : 0]), [])
|
|
478
|
+
]);
|
|
479
|
+
this.bank.remember({
|
|
480
|
+
frame,
|
|
481
|
+
tokens: floats(memory, "memory_tokens").slice(),
|
|
482
|
+
positions: floats(memory, "memory_pos").slice(),
|
|
483
|
+
pointer: floats(decoded, "object_pointer").slice()
|
|
484
|
+
}, prompted);
|
|
485
|
+
}
|
|
486
|
+
release() {
|
|
487
|
+
for (const session of this.sessions.values()) session.release();
|
|
488
|
+
this.sessions.clear();
|
|
489
|
+
this.released = true;
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
/** Bilinear resize of square logits before thresholding, matching SAM's source-image mask contract. */
|
|
493
|
+
function decodeSam2Mask(logits, width, height, score, iou) {
|
|
494
|
+
const side = Math.round(Math.sqrt(logits.length));
|
|
495
|
+
if (side * side !== logits.length || side % 16 !== 0) throw new Error("Invalid SAM 2 mask shape.");
|
|
496
|
+
const last = side - 1;
|
|
497
|
+
const mask = new Uint8Array(width * height);
|
|
498
|
+
if (score > 0) for (let y = 0; y < height; y++) {
|
|
499
|
+
const sy = Math.max(0, Math.min(last, (y + .5) * side / height - .5));
|
|
500
|
+
const y0 = Math.floor(sy), y1 = Math.min(last, y0 + 1), fy = sy - y0;
|
|
501
|
+
for (let x = 0; x < width; x++) {
|
|
502
|
+
const sx = Math.max(0, Math.min(last, (x + .5) * side / width - .5));
|
|
503
|
+
const x0 = Math.floor(sx), x1 = Math.min(last, x0 + 1), fx = sx - x0;
|
|
504
|
+
const a = (logits[y0 * side + x0] ?? 0) * (1 - fx) + (logits[y0 * side + x1] ?? 0) * fx;
|
|
505
|
+
const b = (logits[y1 * side + x0] ?? 0) * (1 - fx) + (logits[y1 * side + x1] ?? 0) * fx;
|
|
506
|
+
mask[y * width + x] = a * (1 - fy) + b * fy > 0 ? 255 : 0;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return {
|
|
510
|
+
mask,
|
|
511
|
+
width,
|
|
512
|
+
height,
|
|
513
|
+
score,
|
|
514
|
+
iou
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
/** SAM 3's small prompt/position heads, assembled from the pinned upstream weights.
|
|
518
|
+
* The video export omits dense prompts and learned temporal constants. These heads
|
|
519
|
+
* restore the original operations, without approximating a semantic mask by clicks.
|
|
520
|
+
*/
|
|
521
|
+
function integer(field, value$1) {
|
|
522
|
+
return new Uint8Array([...varint(field * 8), ...varint(value$1)]);
|
|
523
|
+
}
|
|
524
|
+
function text(field, value$1) {
|
|
525
|
+
return lengthDelimited(field, encoder.encode(value$1));
|
|
526
|
+
}
|
|
527
|
+
function attribute(name, values) {
|
|
528
|
+
return lengthDelimited(5, concat([
|
|
529
|
+
text(1, name),
|
|
530
|
+
integer(20, 7),
|
|
531
|
+
lengthDelimited(8, new Uint8Array(values.flatMap(varint)))
|
|
532
|
+
]));
|
|
533
|
+
}
|
|
534
|
+
function intAttribute(name, value$1) {
|
|
535
|
+
return lengthDelimited(5, concat([
|
|
536
|
+
text(1, name),
|
|
537
|
+
integer(3, value$1),
|
|
538
|
+
integer(20, 2)
|
|
539
|
+
]));
|
|
540
|
+
}
|
|
541
|
+
function floatAttribute(name, value$1) {
|
|
542
|
+
const bytes = new Uint8Array(4);
|
|
543
|
+
new DataView(bytes.buffer).setFloat32(0, value$1, true);
|
|
544
|
+
return lengthDelimited(5, concat([
|
|
545
|
+
text(1, name),
|
|
546
|
+
new Uint8Array([21, ...bytes]),
|
|
547
|
+
integer(20, 1)
|
|
548
|
+
]));
|
|
549
|
+
}
|
|
550
|
+
function node(op, inputs, output, attrs = []) {
|
|
551
|
+
return lengthDelimited(1, concat([
|
|
552
|
+
...inputs.map((x) => text(1, x)),
|
|
553
|
+
text(2, output),
|
|
554
|
+
text(4, op),
|
|
555
|
+
...attrs
|
|
556
|
+
]));
|
|
557
|
+
}
|
|
558
|
+
function value(name, dims) {
|
|
559
|
+
const shape = concat(dims.map((d) => lengthDelimited(1, integer(1, d))));
|
|
560
|
+
return concat([text(1, name), lengthDelimited(2, lengthDelimited(1, concat([integer(1, 1), lengthDelimited(2, shape)])))]);
|
|
561
|
+
}
|
|
562
|
+
function scalar(name, amount) {
|
|
563
|
+
const data = new Float32Array([amount]);
|
|
564
|
+
return concat([
|
|
565
|
+
integer(2, 1),
|
|
566
|
+
text(8, name),
|
|
567
|
+
lengthDelimited(9, new Uint8Array(data.buffer))
|
|
568
|
+
]);
|
|
569
|
+
}
|
|
570
|
+
function model(nodes, inputs, outputs, weights) {
|
|
571
|
+
const graph = concat([
|
|
572
|
+
...nodes,
|
|
573
|
+
text(2, "framefields_sam3"),
|
|
574
|
+
...weights.map((w) => lengthDelimited(5, w)),
|
|
575
|
+
...inputs.map(([n, d]) => lengthDelimited(11, value(n, d))),
|
|
576
|
+
...outputs.map(([n, d]) => lengthDelimited(12, value(n, d)))
|
|
577
|
+
]);
|
|
578
|
+
return concat([
|
|
579
|
+
integer(1, 9),
|
|
580
|
+
lengthDelimited(7, graph),
|
|
581
|
+
lengthDelimited(8, integer(2, 18))
|
|
582
|
+
]);
|
|
583
|
+
}
|
|
584
|
+
function weightsFrom(modelBytes, external) {
|
|
585
|
+
const graph = fields(modelBytes).find((f) => f.number === 7);
|
|
586
|
+
if (!graph) throw new Error("SAM 3 constants graph is missing.");
|
|
587
|
+
const result = /* @__PURE__ */ new Map();
|
|
588
|
+
for (const entry of fields(graph.body).filter((f) => f.number === 5)) {
|
|
589
|
+
const fs = fields(entry.body), name = firstString(entry.body, 8);
|
|
590
|
+
if (!name || !/tracker\.(maskmem_tpos_enc|no_mem_embed|obj_ptr_tpos_proj|sam_prompt_encoder\.mask_downscaling)/.test(name)) continue;
|
|
591
|
+
const metadata = new Map(fs.filter((f) => f.number === 13).map((f) => [firstString(f.body, 1), firstString(f.body, 2)]));
|
|
592
|
+
const offset = Number(metadata.get("offset") ?? 0), length = Number(metadata.get("length") ?? 0);
|
|
593
|
+
const raw = fs.find((f) => f.number === 9)?.body ?? external.subarray(offset, offset + length);
|
|
594
|
+
const dataType = fs.find((f) => f.number === 2);
|
|
595
|
+
const dtype = dataType ? readVarint(dataType.raw, 1)[0] : 0;
|
|
596
|
+
if (![1, 10].includes(dtype)) throw new Error(`Unsupported SAM 3 weight type: ${name}`);
|
|
597
|
+
if (raw.length === 0 || raw.length % (dtype === 10 ? 2 : 4) !== 0) throw new Error(`Invalid SAM 3 weight: ${name}`);
|
|
598
|
+
const view = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
|
|
599
|
+
const data = Float32Array.from({ length: raw.length / (dtype === 10 ? 2 : 4) }, (_, i) => {
|
|
600
|
+
if (dtype === 1) return view.getFloat32(i * 4, true);
|
|
601
|
+
const bits = view.getUint16(i * 2, true), sign = bits & 32768 ? -1 : 1, exponent = bits >> 10 & 31, fraction = bits & 1023;
|
|
602
|
+
if (exponent === 31) throw new Error(`Non-finite SAM 3 weight ${name}`);
|
|
603
|
+
return sign * (exponent === 0 ? fraction * 2 ** -24 : (1 + fraction / 1024) * 2 ** (exponent - 15));
|
|
604
|
+
});
|
|
605
|
+
const copy = new Uint8Array(data.buffer);
|
|
606
|
+
result.set(name, {
|
|
607
|
+
proto: concat([
|
|
608
|
+
...fs.filter((f) => ![
|
|
609
|
+
2,
|
|
610
|
+
9,
|
|
611
|
+
13,
|
|
612
|
+
14
|
|
613
|
+
].includes(f.number)).map((f) => f.raw),
|
|
614
|
+
integer(2, 1),
|
|
615
|
+
lengthDelimited(9, copy)
|
|
616
|
+
]),
|
|
617
|
+
data: new Float32Array(copy.buffer)
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
return result;
|
|
621
|
+
}
|
|
622
|
+
function sam3SupportGraphs(reference, external) {
|
|
623
|
+
const weights = weightsFrom(reference, external);
|
|
624
|
+
const get = (name) => {
|
|
625
|
+
const item = weights.get(`tracker.${name}`);
|
|
626
|
+
if (!item) throw new Error(`Missing SAM 3 weight ${name}`);
|
|
627
|
+
return item;
|
|
628
|
+
};
|
|
629
|
+
const nodes = [], denseWeights = [
|
|
630
|
+
scalar("sqrt2", Math.SQRT2),
|
|
631
|
+
scalar("one", 1),
|
|
632
|
+
scalar("half", .5)
|
|
633
|
+
];
|
|
634
|
+
let previous = "mask";
|
|
635
|
+
for (const [index, layer] of [
|
|
636
|
+
0,
|
|
637
|
+
3,
|
|
638
|
+
6
|
|
639
|
+
].entries()) {
|
|
640
|
+
const base = `sam_prompt_encoder.mask_downscaling.${layer}`;
|
|
641
|
+
for (const suffix of ["weight", "bias"]) denseWeights.push(get(`${base}.${suffix}`).proto);
|
|
642
|
+
const output = `conv${index}`;
|
|
643
|
+
nodes.push(node("Conv", [
|
|
644
|
+
previous,
|
|
645
|
+
`tracker.${base}.weight`,
|
|
646
|
+
`tracker.${base}.bias`
|
|
647
|
+
], output, [attribute("kernel_shape", layer === 6 ? [1, 1] : [2, 2]), attribute("strides", layer === 6 ? [1, 1] : [2, 2])]));
|
|
648
|
+
previous = output;
|
|
649
|
+
if (layer === 6) continue;
|
|
650
|
+
const norm = `sam_prompt_encoder.mask_downscaling.${layer + 1}`;
|
|
651
|
+
for (const suffix of ["weight", "bias"]) denseWeights.push(get(`${norm}.${suffix}`).proto);
|
|
652
|
+
nodes.push(node("Transpose", [previous], `nhwc${index}`, [attribute("perm", [
|
|
653
|
+
0,
|
|
654
|
+
2,
|
|
655
|
+
3,
|
|
656
|
+
1
|
|
657
|
+
])]), node("LayerNormalization", [
|
|
658
|
+
`nhwc${index}`,
|
|
659
|
+
`tracker.${norm}.weight`,
|
|
660
|
+
`tracker.${norm}.bias`
|
|
661
|
+
], `norm${index}`, [intAttribute("axis", 3), floatAttribute("epsilon", 1e-6)]), node("Transpose", [`norm${index}`], `nchw${index}`, [attribute("perm", [
|
|
662
|
+
0,
|
|
663
|
+
3,
|
|
664
|
+
1,
|
|
665
|
+
2
|
|
666
|
+
])]), node("Div", [`nchw${index}`, "sqrt2"], `div${index}`), node("Erf", [`div${index}`], `erf${index}`), node("Add", [`erf${index}`, "one"], `add${index}`), node("Mul", [`add${index}`, `nchw${index}`], `mul${index}`), node("Mul", [`mul${index}`, "half"], `gelu${index}`));
|
|
667
|
+
previous = `gelu${index}`;
|
|
668
|
+
}
|
|
669
|
+
nodes.push(node("Identity", [previous], "dense_prompt"));
|
|
670
|
+
const pointerWeights = [get("obj_ptr_tpos_proj.weight").proto, get("obj_ptr_tpos_proj.bias").proto];
|
|
671
|
+
return {
|
|
672
|
+
densePrompt: model(nodes, [["mask", [
|
|
673
|
+
1,
|
|
674
|
+
1,
|
|
675
|
+
288,
|
|
676
|
+
288
|
|
677
|
+
]]], [["dense_prompt", [
|
|
678
|
+
1,
|
|
679
|
+
256,
|
|
680
|
+
72,
|
|
681
|
+
72
|
|
682
|
+
]]], denseWeights),
|
|
683
|
+
pointerPosition: model([node("Gemm", [
|
|
684
|
+
"encoding",
|
|
685
|
+
"tracker.obj_ptr_tpos_proj.weight",
|
|
686
|
+
"tracker.obj_ptr_tpos_proj.bias"
|
|
687
|
+
], "position", [intAttribute("transB", 1)])], [["encoding", [16, 256]]], [["position", [16, 64]]], pointerWeights),
|
|
688
|
+
temporal: get("maskmem_tpos_enc").data,
|
|
689
|
+
noMemory: get("no_mem_embed").data
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
/** Replace the no-mask embedding by the actual dense prompt head's output. */
|
|
693
|
+
function sam3DenseDecoder(modelBytes) {
|
|
694
|
+
const modelFields = fields(modelBytes), graph = modelFields.find((f) => f.number === 7);
|
|
695
|
+
if (!graph) throw new Error("Missing SAM 3 decoder graph.");
|
|
696
|
+
let replaced = false;
|
|
697
|
+
const graphParts = fields(graph.body).map((f) => {
|
|
698
|
+
if (f.number !== 1 || firstString(f.body, 3) !== "/mask_decoder/Add") return f.raw;
|
|
699
|
+
const inputs = strings(f.body, 1);
|
|
700
|
+
if (inputs[0] !== "feats2" || inputs[1] !== "/prompt_encoder/Expand_output_0") throw new Error("Unexpected SAM 3 dense prompt contract.");
|
|
701
|
+
replaced = true;
|
|
702
|
+
return lengthDelimited(1, concat(fields(f.body).filter((x) => x.number !== 1).map((x) => x.raw).concat([text(1, "feats2"), text(1, "dense_prompt")])));
|
|
703
|
+
});
|
|
704
|
+
if (!replaced) throw new Error("SAM 3 decoder has no prompt embedding input.");
|
|
705
|
+
graphParts.push(lengthDelimited(11, value("dense_prompt", [
|
|
706
|
+
1,
|
|
707
|
+
256,
|
|
708
|
+
72,
|
|
709
|
+
72
|
|
710
|
+
])));
|
|
711
|
+
return concat(modelFields.map((f) => f === graph ? lengthDelimited(7, concat(graphParts)) : f.raw));
|
|
712
|
+
}
|
|
713
|
+
/** Dynamic memory lengths: never duplicate unavailable early-frame memories. */
|
|
714
|
+
var Sam3MemoryBank = class {
|
|
715
|
+
seed;
|
|
716
|
+
recent = [];
|
|
717
|
+
constructor(temporal) {
|
|
718
|
+
this.temporal = temporal;
|
|
719
|
+
}
|
|
720
|
+
remember(memory, prompted) {
|
|
721
|
+
if (prompted) {
|
|
722
|
+
this.seed = memory;
|
|
723
|
+
this.recent = [];
|
|
724
|
+
} else {
|
|
725
|
+
this.recent.push(memory);
|
|
726
|
+
if (this.recent.length > 15) this.recent.shift();
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
assemble(frame, frameCount) {
|
|
730
|
+
if (!this.seed) throw new Error("SAM 3 needs a prompt before propagation.");
|
|
731
|
+
const blocks = [this.seed, ...this.recent.slice(-6)];
|
|
732
|
+
const spatial = new Float32Array(blocks.length * 5184 * 64), positions = new Float32Array(spatial.length);
|
|
733
|
+
for (const [i, block] of blocks.entries()) {
|
|
734
|
+
spatial.set(block.tokens, i * 5184 * 64);
|
|
735
|
+
const row = block === this.seed ? 6 : Math.min(5, frame - block.frame - 1);
|
|
736
|
+
for (let j = 0; j < block.positions.length; j++) positions[i * 5184 * 64 + j] = (block.positions[j] ?? 0) + (this.temporal[row * 64 + j % 64] ?? 0);
|
|
737
|
+
}
|
|
738
|
+
const entries = [this.seed, ...[...this.recent].reverse()].slice(0, 16);
|
|
739
|
+
const pointers = new Float32Array(entries.length * 256), encoding = new Float32Array(16 * 256);
|
|
740
|
+
for (const [i, entry] of entries.entries()) {
|
|
741
|
+
pointers.set(entry.pointer, i * 256);
|
|
742
|
+
const diff = (frame - entry.frame) / Math.max(1, Math.min(frameCount, 16) - 1);
|
|
743
|
+
for (let j = 0; j < 128; j++) {
|
|
744
|
+
const angle = diff / 1e4 ** (2 * Math.floor(j / 2) / 128);
|
|
745
|
+
encoding[i * 256 + j] = Math.sin(angle);
|
|
746
|
+
encoding[i * 256 + 128 + j] = Math.cos(angle);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
return {
|
|
750
|
+
spatial,
|
|
751
|
+
positions,
|
|
752
|
+
pointers,
|
|
753
|
+
encoding,
|
|
754
|
+
pointerCount: entries.length
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
/** SAM 3 PositionEmbeddingSine: y then x, normalized pixel centers at grid indices 1..72. */
|
|
759
|
+
function sam3Position() {
|
|
760
|
+
const out = new Float32Array(5184 * 256);
|
|
761
|
+
for (let y = 0; y < 72; y++) for (let x = 0; x < 72; x++) for (let j = 0; j < 128; j++) {
|
|
762
|
+
const divisor = 1e4 ** (2 * Math.floor(j / 2) / 128);
|
|
763
|
+
const yy = (y + 1) / 72.000001 * 2 * Math.PI / divisor, xx = (x + 1) / 72.000001 * 2 * Math.PI / divisor;
|
|
764
|
+
out[(y * 72 + x) * 256 + j] = j % 2 ? Math.cos(yy) : Math.sin(yy);
|
|
765
|
+
out[(y * 72 + x) * 256 + 128 + j] = j % 2 ? Math.cos(xx) : Math.sin(xx);
|
|
766
|
+
}
|
|
767
|
+
return out;
|
|
768
|
+
}
|
|
769
|
+
function sam3Floats(outputs, name) {
|
|
770
|
+
const value$1 = outputs[name];
|
|
771
|
+
if (!(value$1?.data instanceof Float32Array)) throw new Error(`Missing SAM 3 float output ${name}`);
|
|
772
|
+
return value$1.data;
|
|
773
|
+
}
|
|
774
|
+
async function sam3Run(session, inputs) {
|
|
775
|
+
if (!session.runMany) throw new Error("SAM 3 requires a session provider with runMany support.");
|
|
776
|
+
return session.runMany(inputs);
|
|
777
|
+
}
|
|
778
|
+
/** Semantic model is separate from the visual tracker and loads only for text prompts. */
|
|
779
|
+
var Sam3TextSelector = class Sam3TextSelector$1 {
|
|
780
|
+
sessions = [];
|
|
781
|
+
encoded;
|
|
782
|
+
constructor(tokenizer) {
|
|
783
|
+
this.tokenizer = tokenizer;
|
|
784
|
+
}
|
|
785
|
+
static async create(store, provider) {
|
|
786
|
+
const json = async (key) => JSON.parse(new TextDecoder().decode(await store.ensure(key)));
|
|
787
|
+
const selector = new Sam3TextSelector$1(new Tokenizer(await json("sam3-tokenizer"), await json("sam3-tokenizer-config")));
|
|
788
|
+
try {
|
|
789
|
+
selector.sessions.push(await provider.createSession(await store.ensure("sam3-text-vision_encoder"), { externalData: [{
|
|
790
|
+
path: "vision_encoder_int4_fp16attn.onnx.data",
|
|
791
|
+
data: await store.ensure("sam3-text-vision_encoder-data")
|
|
792
|
+
}] }));
|
|
793
|
+
for (const key of ["sam3-text-encoder", "sam3-text-decoder"]) selector.sessions.push(await provider.createSession(await store.ensure(key)));
|
|
794
|
+
return selector;
|
|
795
|
+
} catch (error) {
|
|
796
|
+
selector.release();
|
|
797
|
+
throw error;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Mask logits (288²) of the instances matching `text` with sigmoid score of at least
|
|
802
|
+
* `threshold`, best first and at most `max`. Queries that repeat an accepted instance
|
|
803
|
+
* (mask IoU above 0.5) are skipped. Throws when nothing matches unless `required` is false.
|
|
804
|
+
*/
|
|
805
|
+
async select(pixels, text$2, threshold, max = 1, required = true) {
|
|
806
|
+
const [visionSession, textSession, decoder] = this.sessions;
|
|
807
|
+
if (!visionSession || !textSession || !decoder) throw new Error("SAM 3 text selector has been released.");
|
|
808
|
+
const { features, mask } = await this.encodeText(textSession, text$2);
|
|
809
|
+
const vision = await sam3Run(visionSession, [{
|
|
810
|
+
name: "pixel_values",
|
|
811
|
+
data: pixels,
|
|
812
|
+
dims: [
|
|
813
|
+
1,
|
|
814
|
+
3,
|
|
815
|
+
1008,
|
|
816
|
+
1008
|
|
817
|
+
]
|
|
818
|
+
}]);
|
|
819
|
+
const inputs = [{
|
|
820
|
+
name: "text_features",
|
|
821
|
+
data: features,
|
|
822
|
+
dims: [
|
|
823
|
+
1,
|
|
824
|
+
32,
|
|
825
|
+
256
|
|
826
|
+
]
|
|
827
|
+
}, {
|
|
828
|
+
name: "attention_mask",
|
|
829
|
+
data: mask,
|
|
830
|
+
dims: [1, 32]
|
|
831
|
+
}];
|
|
832
|
+
for (const name of [
|
|
833
|
+
"fpn_hidden_state_0",
|
|
834
|
+
"fpn_hidden_state_1",
|
|
835
|
+
"fpn_hidden_state_2",
|
|
836
|
+
"fpn_position_encoding_2"
|
|
837
|
+
]) {
|
|
838
|
+
const value$1 = vision[name];
|
|
839
|
+
if (!value$1) throw new Error(`Missing SAM 3 concept feature ${name}`);
|
|
840
|
+
inputs.push({
|
|
841
|
+
name,
|
|
842
|
+
data: sam3Floats(vision, name),
|
|
843
|
+
dims: value$1.dims
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
const result = await sam3Run(decoder, inputs), scores = sam3Floats(result, "pred_logits"), masks = sam3Floats(result, "pred_masks");
|
|
847
|
+
if (masks.length !== scores.length * CELLS) throw new Error("Invalid SAM 3 concept mask shape.");
|
|
848
|
+
const ranked = [...scores.keys()].sort((a, b) => (scores[b] ?? -Infinity) - (scores[a] ?? -Infinity));
|
|
849
|
+
const best = 1 / (1 + Math.exp(-(scores[ranked[0] ?? 0] ?? -Infinity)));
|
|
850
|
+
if (best < threshold && !required) return [];
|
|
851
|
+
if (best < threshold) throw new Error(`SAM 3 found no confident instance for text ${JSON.stringify(text$2)} (score ${best.toFixed(3)}, threshold ${threshold}).`);
|
|
852
|
+
const logit = Math.log(threshold / (1 - threshold));
|
|
853
|
+
const selected = [];
|
|
854
|
+
for (const query of ranked) {
|
|
855
|
+
if (selected.length >= max || (scores[query] ?? -Infinity) < logit) break;
|
|
856
|
+
const candidate = masks.slice(query * CELLS, (query + 1) * CELLS);
|
|
857
|
+
if (selected.every((kept) => maskIou(kept, candidate) <= .5)) selected.push(candidate);
|
|
858
|
+
}
|
|
859
|
+
return selected;
|
|
860
|
+
}
|
|
861
|
+
/** Text features for a prompt; the last one is kept, since re-detection repeats it every few frames. */
|
|
862
|
+
async encodeText(session, text$2) {
|
|
863
|
+
if (this.encoded?.text === text$2) return this.encoded;
|
|
864
|
+
const tokens = this.tokenizer.encode(text$2).ids;
|
|
865
|
+
if (tokens.length > 32) throw new Error("SAM 3 text prompts must fit within 32 CLIP tokens.");
|
|
866
|
+
const ids = new BigInt64Array(32).fill(49407n), mask = new BigInt64Array(32);
|
|
867
|
+
tokens.forEach((id, i) => {
|
|
868
|
+
ids[i] = BigInt(id);
|
|
869
|
+
mask[i] = 1n;
|
|
870
|
+
});
|
|
871
|
+
this.encoded = {
|
|
872
|
+
text: text$2,
|
|
873
|
+
features: sam3Floats(await sam3Run(session, [{
|
|
874
|
+
name: "input_ids",
|
|
875
|
+
data: ids,
|
|
876
|
+
dims: [1, 32]
|
|
877
|
+
}, {
|
|
878
|
+
name: "attention_mask",
|
|
879
|
+
data: mask,
|
|
880
|
+
dims: [1, 32]
|
|
881
|
+
}]), "text_features").slice(),
|
|
882
|
+
mask
|
|
883
|
+
};
|
|
884
|
+
return this.encoded;
|
|
885
|
+
}
|
|
886
|
+
release() {
|
|
887
|
+
for (const session of this.sessions) session.release();
|
|
888
|
+
this.sessions.length = 0;
|
|
889
|
+
this.encoded = void 0;
|
|
890
|
+
}
|
|
891
|
+
};
|
|
892
|
+
const CELLS = 288 * 288;
|
|
893
|
+
function maskIou(a, b) {
|
|
894
|
+
let both = 0, either = 0;
|
|
895
|
+
for (let i = 0; i < a.length; i++) {
|
|
896
|
+
const x = (a[i] ?? 0) > 0, y = (b[i] ?? 0) > 0;
|
|
897
|
+
if (x && y) both++;
|
|
898
|
+
if (x || y) either++;
|
|
899
|
+
}
|
|
900
|
+
return either ? both / either : 0;
|
|
901
|
+
}
|
|
902
|
+
/** Frames kept: clips of one source ask for the same frame back to back. */
|
|
903
|
+
const RECENT = 2;
|
|
904
|
+
/**
|
|
905
|
+
* The encoder is most of SAM 3's per-frame cost (3.6 s at fp16 on an M1 Pro), and every
|
|
906
|
+
* clip of a source sees identical pixels. So trackers on one provider and precision share
|
|
907
|
+
* one session and the features of the last frames, keyed by pixel content.
|
|
908
|
+
*/
|
|
909
|
+
var SharedEncoder = class {
|
|
910
|
+
users = 0;
|
|
911
|
+
recent = [];
|
|
912
|
+
constructor(session, forget) {
|
|
913
|
+
this.session = session;
|
|
914
|
+
this.forget = forget;
|
|
915
|
+
}
|
|
916
|
+
hold() {
|
|
917
|
+
this.users++;
|
|
918
|
+
let held = true;
|
|
919
|
+
return {
|
|
920
|
+
encode: (image) => this.encode(image),
|
|
921
|
+
release: () => {
|
|
922
|
+
if (!held) return;
|
|
923
|
+
held = false;
|
|
924
|
+
if (--this.users > 0) return;
|
|
925
|
+
this.forget();
|
|
926
|
+
this.recent.length = 0;
|
|
927
|
+
this.session.release();
|
|
928
|
+
}
|
|
929
|
+
};
|
|
930
|
+
}
|
|
931
|
+
encode(image) {
|
|
932
|
+
const key = frameKey(image);
|
|
933
|
+
const hit = this.recent.find((entry$1) => entry$1.key === key);
|
|
934
|
+
if (hit) return hit.features;
|
|
935
|
+
const entry = {
|
|
936
|
+
key,
|
|
937
|
+
features: this.run(image)
|
|
938
|
+
};
|
|
939
|
+
this.recent.push(entry);
|
|
940
|
+
if (this.recent.length > RECENT) this.recent.shift();
|
|
941
|
+
entry.features.catch(() => {
|
|
942
|
+
const index = this.recent.indexOf(entry);
|
|
943
|
+
if (index >= 0) this.recent.splice(index, 1);
|
|
944
|
+
});
|
|
945
|
+
return entry.features;
|
|
946
|
+
}
|
|
947
|
+
async run(image) {
|
|
948
|
+
const { tensor: pixels } = imageToTensor(image, {
|
|
949
|
+
width: 1008,
|
|
950
|
+
height: 1008,
|
|
951
|
+
fit: "stretch",
|
|
952
|
+
channels: "rgb",
|
|
953
|
+
padValue: 0,
|
|
954
|
+
mean: [
|
|
955
|
+
127.5,
|
|
956
|
+
127.5,
|
|
957
|
+
127.5
|
|
958
|
+
],
|
|
959
|
+
std: [
|
|
960
|
+
127.5,
|
|
961
|
+
127.5,
|
|
962
|
+
127.5
|
|
963
|
+
]
|
|
964
|
+
});
|
|
965
|
+
const out = await sam3Run(this.session, [{
|
|
966
|
+
name: "pixel_values",
|
|
967
|
+
data: pixels,
|
|
968
|
+
dims: [
|
|
969
|
+
1,
|
|
970
|
+
3,
|
|
971
|
+
1008,
|
|
972
|
+
1008
|
|
973
|
+
]
|
|
974
|
+
}]);
|
|
975
|
+
return {
|
|
976
|
+
pixels,
|
|
977
|
+
feats0: sam3Floats(out, "image_embeddings.0"),
|
|
978
|
+
feats1: sam3Floats(out, "image_embeddings.1"),
|
|
979
|
+
raw: sam3Floats(out, "image_embeddings.2")
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
};
|
|
983
|
+
const shared = /* @__PURE__ */ new WeakMap();
|
|
984
|
+
/** Holds the process's SAM 3 encoder for `provider` at `precision`, creating it on first use. */
|
|
985
|
+
async function holdSam3Encoder(store, provider, precision) {
|
|
986
|
+
let byPrecision = shared.get(provider);
|
|
987
|
+
if (!byPrecision) {
|
|
988
|
+
byPrecision = /* @__PURE__ */ new Map();
|
|
989
|
+
shared.set(provider, byPrecision);
|
|
990
|
+
}
|
|
991
|
+
const encoders = byPrecision;
|
|
992
|
+
let encoder$2 = encoders.get(precision);
|
|
993
|
+
if (!encoder$2) {
|
|
994
|
+
encoder$2 = (async () => {
|
|
995
|
+
return new SharedEncoder(await provider.createSession(await store.ensure(`sam3-vision_encoder-${precision}`), { externalData: [{
|
|
996
|
+
path: sam3EncoderFiles(precision).data,
|
|
997
|
+
data: await store.ensure(`sam3-vision_encoder-${precision}-data`)
|
|
998
|
+
}] }), () => encoders.delete(precision));
|
|
999
|
+
})();
|
|
1000
|
+
encoders.set(precision, encoder$2);
|
|
1001
|
+
encoder$2.catch(() => encoders.delete(precision));
|
|
1002
|
+
}
|
|
1003
|
+
return (await encoder$2).hold();
|
|
1004
|
+
}
|
|
1005
|
+
/** Content key of a frame: size plus two 32-bit FNV-1a hashes over its bytes. */
|
|
1006
|
+
function frameKey(image) {
|
|
1007
|
+
const bytes = image.data;
|
|
1008
|
+
let a = 2166136261, b = 16777619 ^ bytes.length;
|
|
1009
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1010
|
+
const byte = bytes[i] ?? 0;
|
|
1011
|
+
a = Math.imul(a ^ byte, 16777619);
|
|
1012
|
+
b = Math.imul(b ^ byte, 1540483477) ^ b >>> 15;
|
|
1013
|
+
}
|
|
1014
|
+
return `${image.width}x${image.height}:${(a >>> 0).toString(36)}${(b >>> 0).toString(36)}`;
|
|
1015
|
+
}
|
|
1016
|
+
/**
|
|
1017
|
+
* Text-selected instances as one mask (`sam3.merge`): each pixel keeps its most confident
|
|
1018
|
+
* instance's logit, so the union is positive wherever any instance is.
|
|
1019
|
+
*/
|
|
1020
|
+
function mergeSelections(masks) {
|
|
1021
|
+
const merged = new Float32Array(masks[0]?.length ?? 0).fill(-Infinity);
|
|
1022
|
+
for (const mask of masks) for (let i = 0; i < merged.length; i++) merged[i] = Math.max(merged[i] ?? -Infinity, mask[i] ?? -Infinity);
|
|
1023
|
+
return merged;
|
|
1024
|
+
}
|
|
1025
|
+
/** Logit SAM uses for a given mask's pixels (and its object score): ±10. */
|
|
1026
|
+
const MASK_LOGIT = 10;
|
|
1027
|
+
/** A re-detected instance is new while tracked objects cover less than this share of it. */
|
|
1028
|
+
const NEW_OBJECT_COVERAGE = .5;
|
|
1029
|
+
/** Where any present tracked object is, on the 288² concept grid, as ±10 logits. */
|
|
1030
|
+
function coveredCells(tracked) {
|
|
1031
|
+
const covered = new Float32Array(288 * 288).fill(-MASK_LOGIT);
|
|
1032
|
+
for (const { logits, score } of tracked) {
|
|
1033
|
+
if (score <= 0) continue;
|
|
1034
|
+
for (let y = 0; y < 288; y++) {
|
|
1035
|
+
const row = Math.floor((y + .5) * 1008 / 288) * 1008;
|
|
1036
|
+
for (let x = 0; x < 288; x++) if ((logits[row + Math.floor((x + .5) * 1008 / 288)] ?? 0) > 0) covered[y * 288 + x] = MASK_LOGIT;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
return covered;
|
|
1040
|
+
}
|
|
1041
|
+
/** Re-detected 288² instances that the covered cells do not already hold. */
|
|
1042
|
+
function uncovered(found, covered) {
|
|
1043
|
+
return found.filter((instance) => {
|
|
1044
|
+
let inside = 0;
|
|
1045
|
+
let area = 0;
|
|
1046
|
+
for (let i = 0; i < instance.length; i++) {
|
|
1047
|
+
if ((instance[i] ?? 0) <= 0) continue;
|
|
1048
|
+
area++;
|
|
1049
|
+
if ((covered[i] ?? 0) > 0) inside++;
|
|
1050
|
+
}
|
|
1051
|
+
return area > 0 && inside / area < NEW_OBJECT_COVERAGE;
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
1054
|
+
/** 1008² seed logits that keep a present tracked mask at full resolution and add `added` to it. */
|
|
1055
|
+
function keepTracked(tracked, added) {
|
|
1056
|
+
if (!tracked || tracked.score <= 0) return added;
|
|
1057
|
+
return Float32Array.from(added, (value$1, i) => (tracked.logits[i] ?? 0) > 0 ? MASK_LOGIT : value$1);
|
|
1058
|
+
}
|
|
1059
|
+
function validateSam3Prompts(options) {
|
|
1060
|
+
const prompts = options.prompts ?? (options.text ? [{
|
|
1061
|
+
frame: 0,
|
|
1062
|
+
text: options.text
|
|
1063
|
+
}] : []);
|
|
1064
|
+
if (!prompts.length) throw new Error("SAM 3 requires at least one prompt or text description.");
|
|
1065
|
+
let previous = -1;
|
|
1066
|
+
for (const prompt of prompts) {
|
|
1067
|
+
if (!Number.isSafeInteger(prompt.frame) || prompt.frame <= previous) throw new Error("SAM 3 prompt frames must be nonnegative, unique and increasing.");
|
|
1068
|
+
previous = prompt.frame;
|
|
1069
|
+
if (prompt.points !== void 0 === (prompt.text !== void 0)) throw new Error("SAM 3 prompts need either points/a box or text.");
|
|
1070
|
+
if (prompt.points) validateSam2Prompts([{
|
|
1071
|
+
frame: prompt.frame,
|
|
1072
|
+
points: prompt.points
|
|
1073
|
+
}]);
|
|
1074
|
+
if (prompt.text !== void 0 && !prompt.text.trim()) throw new Error("SAM 3 text prompts must not be empty.");
|
|
1075
|
+
if (prompt.object !== void 0 && (prompt.text !== void 0 || !Number.isSafeInteger(prompt.object) || prompt.object < 1)) throw new Error("SAM 3 prompt objects are positive track IDs on points prompts.");
|
|
1076
|
+
}
|
|
1077
|
+
const maxObjects = options.maxObjects ?? 1;
|
|
1078
|
+
if (!Number.isSafeInteger(maxObjects) || maxObjects < 1) throw new Error("SAM 3 maxObjects must be a positive integer.");
|
|
1079
|
+
const redetect = options.redetect ?? 0;
|
|
1080
|
+
if (!Number.isSafeInteger(redetect) || redetect < 0) throw new Error("SAM 3 redetect must be a nonnegative integer frame interval.");
|
|
1081
|
+
const threshold = options.textThreshold ?? .5;
|
|
1082
|
+
if (!Number.isFinite(threshold) || threshold <= 0 || threshold >= 1) throw new Error("SAM 3 textThreshold must be between zero and one.");
|
|
1083
|
+
}
|
|
1084
|
+
/** Every graph and tokenizer revision, and the encoder precision: ClipVision's cache identity. */
|
|
1085
|
+
function sam3Revision(precision) {
|
|
1086
|
+
return `sam3-${precision}-429305c8-video-e942689a-support-68ce2746-text-fe8f8e12-v2`;
|
|
1087
|
+
}
|
|
1088
|
+
/** The encoder precision a tracker on `provider` uses: the override, else the backend's best. */
|
|
1089
|
+
async function sam3Precision(provider = createDefaultSessionProvider(), override) {
|
|
1090
|
+
return override ?? SAM3_ENCODER[await sessionCompute(provider)];
|
|
1091
|
+
}
|
|
1092
|
+
function tensor(name, data, dims) {
|
|
1093
|
+
return {
|
|
1094
|
+
name,
|
|
1095
|
+
data,
|
|
1096
|
+
dims
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
/**
|
|
1100
|
+
* Explicitly selected SAM 3 instances with full neural memory propagation on the provider.
|
|
1101
|
+
* The image encoder runs once per frame; each object keeps its own memory bank.
|
|
1102
|
+
*/
|
|
1103
|
+
var Sam3Tracker = class Sam3Tracker$1 {
|
|
1104
|
+
sessions = /* @__PURE__ */ new Map();
|
|
1105
|
+
encoder;
|
|
1106
|
+
position = sam3Position();
|
|
1107
|
+
banks = [];
|
|
1108
|
+
temporal;
|
|
1109
|
+
noMemory;
|
|
1110
|
+
selector;
|
|
1111
|
+
/** The last text prompt and its frame, which re-detection repeats. */
|
|
1112
|
+
text;
|
|
1113
|
+
lastFrame = -1;
|
|
1114
|
+
released = false;
|
|
1115
|
+
constructor(store, provider, options) {
|
|
1116
|
+
this.store = store;
|
|
1117
|
+
this.provider = provider;
|
|
1118
|
+
this.options = options;
|
|
1119
|
+
}
|
|
1120
|
+
static async create(options = {}) {
|
|
1121
|
+
assertSamLicenseAccepted("SAM 3", options);
|
|
1122
|
+
ensureSamModelsRegistered();
|
|
1123
|
+
if (options.frameCount !== void 0 && (!Number.isSafeInteger(options.frameCount) || options.frameCount < 1)) throw new Error("SAM 3 frameCount must be a positive integer.");
|
|
1124
|
+
if (options.textThreshold !== void 0 && (!Number.isFinite(options.textThreshold) || options.textThreshold <= 0 || options.textThreshold >= 1)) throw new Error("SAM 3 textThreshold must be between zero and one.");
|
|
1125
|
+
if (options.maxObjects !== void 0 && (!Number.isSafeInteger(options.maxObjects) || options.maxObjects < 1)) throw new Error("SAM 3 maxObjects must be a positive integer.");
|
|
1126
|
+
if (options.redetect !== void 0 && (!Number.isSafeInteger(options.redetect) || options.redetect < 0)) throw new Error("SAM 3 redetect must be a nonnegative integer frame interval.");
|
|
1127
|
+
const store = options.store ?? new VisionModelStore({
|
|
1128
|
+
...options,
|
|
1129
|
+
acceptLicense: options.acceptLicense ?? true
|
|
1130
|
+
});
|
|
1131
|
+
const provider = options.provider ?? createDefaultSessionProvider();
|
|
1132
|
+
const tracker$1 = new Sam3Tracker$1(store, provider, options);
|
|
1133
|
+
try {
|
|
1134
|
+
tracker$1.encoder = await holdSam3Encoder(store, provider, await sam3Precision(provider, options.precision));
|
|
1135
|
+
const support$1 = sam3SupportGraphs(await store.ensure("sam3-support"), await store.ensure("sam3-support-data"));
|
|
1136
|
+
tracker$1.temporal = support$1.temporal;
|
|
1137
|
+
tracker$1.noMemory = support$1.noMemory;
|
|
1138
|
+
tracker$1.sessions.set("dense_prompt", await provider.createSession(support$1.densePrompt));
|
|
1139
|
+
tracker$1.sessions.set("pointer_position", await provider.createSession(support$1.pointerPosition));
|
|
1140
|
+
const decoder = await store.ensure("sam3-mask_decoder");
|
|
1141
|
+
tracker$1.sessions.set("mask_decoder", await provider.createSession(decoder));
|
|
1142
|
+
tracker$1.sessions.set("dense_decoder", await provider.createSession(sam3DenseDecoder(decoder)));
|
|
1143
|
+
for (const graph of ["memory_encoder", "memory_attention"]) tracker$1.sessions.set(graph, await provider.createSession(await store.ensure(`sam3-${graph}`)));
|
|
1144
|
+
if (!options.store) store.clearMemoryCache();
|
|
1145
|
+
return tracker$1;
|
|
1146
|
+
} catch (error) {
|
|
1147
|
+
tracker$1.release();
|
|
1148
|
+
throw error;
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
run(graph, inputs) {
|
|
1152
|
+
const session = this.sessions.get(graph);
|
|
1153
|
+
if (!session) throw new Error("SAM 3 tracker has been released.");
|
|
1154
|
+
return sam3Run(session, inputs);
|
|
1155
|
+
}
|
|
1156
|
+
async process(image, frame, prompt) {
|
|
1157
|
+
if (this.released) throw new Error("SAM 3 tracker has been released.");
|
|
1158
|
+
if (!Number.isSafeInteger(frame) || frame < 0 || this.lastFrame >= 0 && frame !== this.lastFrame + 1) throw new Error("SAM 3 propagation requires consecutive source frames.");
|
|
1159
|
+
if (prompt) validateSam3Prompts({ prompts: [{
|
|
1160
|
+
...prompt,
|
|
1161
|
+
frame
|
|
1162
|
+
}] });
|
|
1163
|
+
if (this.lastFrame < 0 && !prompt) throw new Error("SAM 3 needs a prompt on its first frame.");
|
|
1164
|
+
if (!this.encoder) throw new Error("SAM 3 tracker has been released.");
|
|
1165
|
+
const { pixels, feats0, feats1, raw } = await this.encoder.encode(image);
|
|
1166
|
+
const shared$1 = [tensor("feats0", feats0, [
|
|
1167
|
+
1,
|
|
1168
|
+
32,
|
|
1169
|
+
288,
|
|
1170
|
+
288
|
|
1171
|
+
]), tensor("feats1", feats1, [
|
|
1172
|
+
1,
|
|
1173
|
+
64,
|
|
1174
|
+
144,
|
|
1175
|
+
144
|
|
1176
|
+
])];
|
|
1177
|
+
const seeds = await this.seeds(pixels, frame, prompt);
|
|
1178
|
+
const tracked = [];
|
|
1179
|
+
for (const [index, bank] of this.banks.entries()) {
|
|
1180
|
+
const seed = seeds.get(index);
|
|
1181
|
+
const features = seed ? this.initialFeatures(raw) : await this.condition(raw, frame, bank);
|
|
1182
|
+
tracked.push(this.track(seed, await this.decode(shared$1, features, seed)));
|
|
1183
|
+
}
|
|
1184
|
+
if (!prompt) await this.redetect(pixels, frame, tracked, shared$1, raw);
|
|
1185
|
+
const objects = [];
|
|
1186
|
+
for (const [index, bank] of this.banks.entries()) {
|
|
1187
|
+
const item = tracked[index];
|
|
1188
|
+
if (!item) continue;
|
|
1189
|
+
const { seed, decoded, logits, score } = item;
|
|
1190
|
+
await this.remember(bank, raw, decoded, frame, seed, logits, score);
|
|
1191
|
+
objects.push({
|
|
1192
|
+
id: index + 1,
|
|
1193
|
+
mask: sam3Mask(logits, image.width, image.height, score),
|
|
1194
|
+
score,
|
|
1195
|
+
iou: seed?.mask ? 1 : Math.max(...sam3Floats(decoded, "iou_scores"))
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1198
|
+
this.lastFrame = frame;
|
|
1199
|
+
return {
|
|
1200
|
+
width: image.width,
|
|
1201
|
+
height: image.height,
|
|
1202
|
+
objects
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
track(seed, decoded) {
|
|
1206
|
+
return {
|
|
1207
|
+
seed,
|
|
1208
|
+
decoded,
|
|
1209
|
+
logits: seed?.mask ?? sam3Floats(decoded, "high_res_masks"),
|
|
1210
|
+
score: seed?.mask ? MASK_LOGIT : sam3Floats(decoded, "object_score_logits")[0] ?? -Infinity
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
/**
|
|
1214
|
+
* On a `redetect` frame, runs the last text prompt again and seeds what no tracked object
|
|
1215
|
+
* covers: merged into the one object (keeping what it tracks), or as new objects.
|
|
1216
|
+
*/
|
|
1217
|
+
async redetect(pixels, frame, tracked, shared$1, raw) {
|
|
1218
|
+
const every = this.options.redetect ?? 0;
|
|
1219
|
+
if (!this.text || every <= 0 || (frame - this.text.frame) % every !== 0) return;
|
|
1220
|
+
const room = this.options.merge ? Infinity : (this.options.maxObjects ?? 1) - this.banks.length;
|
|
1221
|
+
if (room <= 0) return;
|
|
1222
|
+
const found = await (await this.textSelector()).select(pixels, this.text.value, this.options.textThreshold ?? .5, Infinity, false);
|
|
1223
|
+
const covered = coveredCells(tracked);
|
|
1224
|
+
const fresh = uncovered(found, covered).slice(0, room);
|
|
1225
|
+
if (!fresh.length) return;
|
|
1226
|
+
const seeded = async (seed) => this.track(seed, await this.decode(shared$1, this.initialFeatures(raw), seed));
|
|
1227
|
+
if (this.options.merge) {
|
|
1228
|
+
const added = mergeSelections(fresh);
|
|
1229
|
+
const kept = tracked[0];
|
|
1230
|
+
if (!kept) this.banks.push(this.newBank());
|
|
1231
|
+
tracked[0] = await seeded({
|
|
1232
|
+
dense: await this.densePrompt(mergeSelections([added, covered])),
|
|
1233
|
+
mask: keepTracked(kept, seedLogits(added))
|
|
1234
|
+
});
|
|
1235
|
+
return;
|
|
1236
|
+
}
|
|
1237
|
+
for (const logits of fresh) {
|
|
1238
|
+
this.banks.push(this.newBank());
|
|
1239
|
+
tracked.push(await seeded(await this.textSeed(logits)));
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
async textSelector() {
|
|
1243
|
+
this.selector ??= await Sam3TextSelector.create(this.store, this.provider);
|
|
1244
|
+
if (!this.options.store) this.store.clearMemoryCache();
|
|
1245
|
+
return this.selector;
|
|
1246
|
+
}
|
|
1247
|
+
/** A 288² concept mask as a seed that outputs (and remembers) that mask. */
|
|
1248
|
+
async textSeed(logits) {
|
|
1249
|
+
return {
|
|
1250
|
+
dense: await this.densePrompt(logits),
|
|
1251
|
+
mask: seedLogits(logits)
|
|
1252
|
+
};
|
|
1253
|
+
}
|
|
1254
|
+
async densePrompt(logits) {
|
|
1255
|
+
const binary = Float32Array.from(logits, (v) => v > 0 ? 1 : 0);
|
|
1256
|
+
return sam3Floats(await this.run("dense_prompt", [tensor("mask", binary, [
|
|
1257
|
+
1,
|
|
1258
|
+
1,
|
|
1259
|
+
288,
|
|
1260
|
+
288
|
|
1261
|
+
])]), "dense_prompt");
|
|
1262
|
+
}
|
|
1263
|
+
/** Objects a prompt (re)seeds, by index. Text re-selects every object; points address one. */
|
|
1264
|
+
async seeds(pixels, frame, prompt) {
|
|
1265
|
+
const seeds = /* @__PURE__ */ new Map();
|
|
1266
|
+
if (prompt?.points) {
|
|
1267
|
+
const index = (prompt.object ?? 1) - 1;
|
|
1268
|
+
if (index > this.banks.length) throw new Error(`SAM 3 prompt object ${index + 1} skips track IDs; the next new ID is ${this.banks.length + 1}.`);
|
|
1269
|
+
if (index === this.banks.length) this.banks.push(this.newBank());
|
|
1270
|
+
seeds.set(index, { points: prompt.points });
|
|
1271
|
+
}
|
|
1272
|
+
if (prompt?.text !== void 0) {
|
|
1273
|
+
const selected = await (await this.textSelector()).select(pixels, prompt.text, this.options.textThreshold ?? .5, this.options.maxObjects ?? (this.options.merge ? Infinity : 1));
|
|
1274
|
+
const masks = this.options.merge ? [mergeSelections(selected)] : selected;
|
|
1275
|
+
this.text = {
|
|
1276
|
+
value: prompt.text,
|
|
1277
|
+
frame
|
|
1278
|
+
};
|
|
1279
|
+
this.banks.length = 0;
|
|
1280
|
+
for (const [index, logits] of masks.entries()) {
|
|
1281
|
+
this.banks.push(this.newBank());
|
|
1282
|
+
seeds.set(index, await this.textSeed(logits));
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
return seeds;
|
|
1286
|
+
}
|
|
1287
|
+
newBank() {
|
|
1288
|
+
if (!this.temporal) throw new Error("SAM 3 tracker has been released.");
|
|
1289
|
+
return new Sam3MemoryBank(this.temporal);
|
|
1290
|
+
}
|
|
1291
|
+
decode(shared$1, features, seed) {
|
|
1292
|
+
const points = seed?.points ?? [{
|
|
1293
|
+
x: 0,
|
|
1294
|
+
y: 0,
|
|
1295
|
+
label: -1
|
|
1296
|
+
}];
|
|
1297
|
+
const inputs = [
|
|
1298
|
+
...shared$1,
|
|
1299
|
+
tensor("feats2", features, [
|
|
1300
|
+
1,
|
|
1301
|
+
256,
|
|
1302
|
+
72,
|
|
1303
|
+
72
|
|
1304
|
+
]),
|
|
1305
|
+
tensor("input_points", Float32Array.from(points.flatMap((p) => [p.x * 1008, p.y * 1008])), [
|
|
1306
|
+
1,
|
|
1307
|
+
1,
|
|
1308
|
+
points.length,
|
|
1309
|
+
2
|
|
1310
|
+
]),
|
|
1311
|
+
tensor("input_labels", Int32Array.from(points.map((p) => p.label)), [
|
|
1312
|
+
1,
|
|
1313
|
+
1,
|
|
1314
|
+
points.length
|
|
1315
|
+
])
|
|
1316
|
+
];
|
|
1317
|
+
if (!seed?.dense) return this.run("mask_decoder", inputs);
|
|
1318
|
+
return this.run("dense_decoder", [...inputs, tensor("dense_prompt", seed.dense, [
|
|
1319
|
+
1,
|
|
1320
|
+
256,
|
|
1321
|
+
72,
|
|
1322
|
+
72
|
|
1323
|
+
])]);
|
|
1324
|
+
}
|
|
1325
|
+
initialFeatures(raw) {
|
|
1326
|
+
if (!this.noMemory) throw new Error("Missing SAM 3 no-memory embedding.");
|
|
1327
|
+
return Float32Array.from(raw, (value$1, i) => value$1 + (this.noMemory?.[Math.floor(i / 5184)] ?? 0));
|
|
1328
|
+
}
|
|
1329
|
+
async condition(raw, frame, memory) {
|
|
1330
|
+
const bank = memory.assemble(frame, this.options.frameCount ?? 16);
|
|
1331
|
+
const positions = await this.run("pointer_position", [tensor("encoding", bank.encoding, [16, 256])]);
|
|
1332
|
+
const pointerPosition = new Float32Array(bank.pointerCount * 256), projected = sam3Floats(positions, "position");
|
|
1333
|
+
for (let i = 0; i < bank.pointerCount; i++) for (let token = 0; token < 4; token++) pointerPosition.set(projected.subarray(i * 64, (i + 1) * 64), (i * 4 + token) * 64);
|
|
1334
|
+
const tokens = sam3Floats(await this.run("memory_attention", [
|
|
1335
|
+
tensor("current_vision_features", sam2Tokens(raw), [
|
|
1336
|
+
5184,
|
|
1337
|
+
1,
|
|
1338
|
+
256
|
|
1339
|
+
]),
|
|
1340
|
+
tensor("current_vision_position_embeddings", this.position, [
|
|
1341
|
+
5184,
|
|
1342
|
+
1,
|
|
1343
|
+
256
|
|
1344
|
+
]),
|
|
1345
|
+
tensor("spatial_memory", bank.spatial, [
|
|
1346
|
+
bank.spatial.length / 64,
|
|
1347
|
+
1,
|
|
1348
|
+
64
|
|
1349
|
+
]),
|
|
1350
|
+
tensor("spatial_memory_position_embeddings", bank.positions, [
|
|
1351
|
+
bank.positions.length / 64,
|
|
1352
|
+
1,
|
|
1353
|
+
64
|
|
1354
|
+
]),
|
|
1355
|
+
tensor("pointer_memory", bank.pointers, [
|
|
1356
|
+
bank.pointerCount * 4,
|
|
1357
|
+
1,
|
|
1358
|
+
64
|
|
1359
|
+
]),
|
|
1360
|
+
tensor("pointer_memory_position_embeddings", pointerPosition, [
|
|
1361
|
+
bank.pointerCount * 4,
|
|
1362
|
+
1,
|
|
1363
|
+
64
|
|
1364
|
+
])
|
|
1365
|
+
]), "conditioned_features"), nchw = new Float32Array(tokens.length);
|
|
1366
|
+
for (let i = 0; i < 5184; i++) for (let channel = 0; channel < 256; channel++) nchw[channel * 5184 + i] = tokens[i * 256 + channel] ?? 0;
|
|
1367
|
+
return nchw;
|
|
1368
|
+
}
|
|
1369
|
+
async remember(bank, raw, decoded, frame, seed, logits, score) {
|
|
1370
|
+
const memory = await this.run("memory_encoder", [
|
|
1371
|
+
tensor("vision_features", raw, [
|
|
1372
|
+
1,
|
|
1373
|
+
256,
|
|
1374
|
+
72,
|
|
1375
|
+
72
|
|
1376
|
+
]),
|
|
1377
|
+
tensor("pred_masks_high_res", logits, [
|
|
1378
|
+
1,
|
|
1379
|
+
1,
|
|
1380
|
+
1008,
|
|
1381
|
+
1008
|
|
1382
|
+
]),
|
|
1383
|
+
tensor("object_score_logits", Float32Array.of(score), [1, 1]),
|
|
1384
|
+
tensor("is_mask_from_pts", new Uint8Array([seed ? 1 : 0]), [1])
|
|
1385
|
+
]);
|
|
1386
|
+
bank.remember({
|
|
1387
|
+
frame,
|
|
1388
|
+
tokens: sam3Floats(memory, "memory_tokens").slice(),
|
|
1389
|
+
positions: sam3Floats(memory, "memory_pos_enc").slice(),
|
|
1390
|
+
pointer: sam3Floats(decoded, "object_pointer").slice()
|
|
1391
|
+
}, seed !== void 0);
|
|
1392
|
+
}
|
|
1393
|
+
release() {
|
|
1394
|
+
for (const session of this.sessions.values()) session.release();
|
|
1395
|
+
this.sessions.clear();
|
|
1396
|
+
this.encoder?.release();
|
|
1397
|
+
this.encoder = void 0;
|
|
1398
|
+
this.selector?.release();
|
|
1399
|
+
this.banks.length = 0;
|
|
1400
|
+
this.temporal = void 0;
|
|
1401
|
+
this.noMemory = void 0;
|
|
1402
|
+
this.released = true;
|
|
1403
|
+
}
|
|
1404
|
+
};
|
|
1405
|
+
/** Resize logits before thresholding; source pixels are the public mask coordinate system. */
|
|
1406
|
+
function sam3Mask(logits, width, height, score) {
|
|
1407
|
+
if (logits.length !== 1008 * 1008) throw new Error("Invalid SAM 3 high-resolution mask shape.");
|
|
1408
|
+
const mask = new Uint8Array(width * height);
|
|
1409
|
+
if (score <= 0) return mask;
|
|
1410
|
+
for (let y = 0; y < height; y++) for (let x = 0; x < width; x++) {
|
|
1411
|
+
const sy = Math.max(0, Math.min(1007, (y + .5) * 1008 / height - .5)), sx = Math.max(0, Math.min(1007, (x + .5) * 1008 / width - .5));
|
|
1412
|
+
const y0 = Math.floor(sy), x0 = Math.floor(sx), fy = sy - y0, fx = sx - x0, y1 = Math.min(1007, y0 + 1), x1 = Math.min(1007, x0 + 1);
|
|
1413
|
+
const top = (logits[y0 * 1008 + x0] ?? 0) * (1 - fx) + (logits[y0 * 1008 + x1] ?? 0) * fx, bottom = (logits[y1 * 1008 + x0] ?? 0) * (1 - fx) + (logits[y1 * 1008 + x1] ?? 0) * fx;
|
|
1414
|
+
mask[y * width + x] = top * (1 - fy) + bottom * fy > 0 ? 255 : 0;
|
|
1415
|
+
}
|
|
1416
|
+
return mask;
|
|
1417
|
+
}
|
|
1418
|
+
/** A 288² concept mask's logits as SAM's 1008² seed logits: bilinear, then ±10. */
|
|
1419
|
+
function seedLogits(logits) {
|
|
1420
|
+
const out = new Float32Array(1008 * 1008);
|
|
1421
|
+
for (let y = 0; y < 1008; y++) {
|
|
1422
|
+
const sy = Math.max(0, Math.min(287, (y + .5) * 288 / 1008 - .5)), y0 = Math.floor(sy), y1 = Math.min(287, y0 + 1), fy = sy - y0;
|
|
1423
|
+
for (let x = 0; x < 1008; x++) {
|
|
1424
|
+
const sx = Math.max(0, Math.min(287, (x + .5) * 288 / 1008 - .5)), x0 = Math.floor(sx), x1 = Math.min(287, x0 + 1), fx = sx - x0;
|
|
1425
|
+
const top = (logits[y0 * 288 + x0] ?? 0) * (1 - fx) + (logits[y0 * 288 + x1] ?? 0) * fx, bottom = (logits[y1 * 288 + x0] ?? 0) * (1 - fx) + (logits[y1 * 288 + x1] ?? 0) * fx;
|
|
1426
|
+
out[y * 1008 + x] = top * (1 - fy) + bottom * fy > 0 ? MASK_LOGIT : -MASK_LOGIT;
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
return out;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
//#endregion
|
|
1433
|
+
export { sam3Run as C, validateSam3Prompts as E, sam3Revision as S, validateSam2Prompts as T, sam3EncoderFiles as _, SAM_MODELS as a, sam3Position as b, Sam3MemoryBank as c, assertSamLicenseAccepted as d, decodeSam2Mask as f, sam3DenseDecoder as g, sam2Tokens as h, SAM_LICENSE_TERMS_URL as i, Sam3TextSelector as l, sam2Revision as m, SAM3_ENCODER as n, Sam2MemoryBank as o, ensureSamModelsRegistered as p, SAM_LICENSE as r, Sam2Tracker as s, SAM2_EXPORTS as t, Sam3Tracker as u, sam3Floats as v, sam3SupportGraphs as w, sam3Precision as x, sam3Mask as y };
|
|
1434
|
+
//# sourceMappingURL=dist-Dq5TkNDI.mjs.map
|