framefields 2.4.3 → 2.5.1
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/README.md +26 -1
- package/dist/audio/index.d.mts +4 -4
- package/dist/audio/index.mjs +13 -13
- package/dist/{audio-DJeVoE8b.mjs → audio-BluXgSeG.mjs} +1 -1
- package/dist/{audio-DJeVoE8b.mjs.map → audio-BluXgSeG.mjs.map} +1 -1
- package/dist/{audio-BymXfAvH.d.mts → audio-C1A4N3Wh.d.mts} +3 -3
- package/dist/{audio-BymXfAvH.d.mts.map → audio-C1A4N3Wh.d.mts.map} +1 -1
- package/dist/{audio-BzHHpImj.mjs → audio-CZwVENqB.mjs} +4 -4
- package/dist/{audio-BzHHpImj.mjs.map → audio-CZwVENqB.mjs.map} +1 -1
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +221 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/components/index.d.mts +12 -0
- package/dist/components/index.mjs +49 -0
- package/dist/{dist-Bo2_zeCn.mjs → dist-CQZ5_60A.mjs} +2 -2
- package/dist/{dist-Bo2_zeCn.mjs.map → dist-CQZ5_60A.mjs.map} +1 -1
- package/dist/{dist-0QGroRYZ.mjs → dist-C_SMBmHr.mjs} +1 -1
- package/dist/{dist-0QGroRYZ.mjs.map → dist-C_SMBmHr.mjs.map} +1 -1
- package/dist/{dist-hmWTJPik.mjs → dist-DBWkkSvJ.mjs} +113 -68
- package/dist/dist-DBWkkSvJ.mjs.map +1 -0
- package/dist/{dist-TrtLGPvc.mjs → dist-DFeF-ygz.mjs} +1 -1
- package/dist/{dist-TrtLGPvc.mjs.map → dist-DFeF-ygz.mjs.map} +1 -1
- package/dist/{dist-DMa2BbYs.mjs → dist-DHQVWaV2.mjs} +53 -21
- package/dist/dist-DHQVWaV2.mjs.map +1 -0
- package/dist/effects/index.d.mts +4 -4
- package/dist/effects/index.mjs +36 -36
- package/dist/{effects-CiZjSwIh.mjs → effects-DZvq-nWT.mjs} +3 -3
- package/dist/{effects-CiZjSwIh.mjs.map → effects-DZvq-nWT.mjs.map} +1 -1
- package/dist/fonts/index.d.mts +1 -1
- package/dist/fonts/index.mjs +3 -3
- package/dist/{fonts-Da1JDKpc.mjs → fonts-DcsxFpyU.mjs} +3 -2
- package/dist/fonts-DcsxFpyU.mjs.map +1 -0
- package/dist/{gpu-CHIgM_YH.mjs → gpu-Dq_uI_00.mjs} +2 -2
- package/dist/{gpu-CHIgM_YH.mjs.map → gpu-Dq_uI_00.mjs.map} +1 -1
- package/dist/{index-DIvWBm-q.d.mts → index-B-KVpJMb.d.mts} +2 -2
- package/dist/{index-DIvWBm-q.d.mts.map → index-B-KVpJMb.d.mts.map} +1 -1
- package/dist/{index-WMofVN02.d.mts → index-BpdVOlsV.d.mts} +3 -3
- package/dist/{index-WMofVN02.d.mts.map → index-BpdVOlsV.d.mts.map} +1 -1
- package/dist/index-C2f4Hm-p.d.mts +89 -0
- package/dist/index-C2f4Hm-p.d.mts.map +1 -0
- package/dist/{index-B-55dXDu.d.mts → index-CalU-mpZ.d.mts} +1 -1
- package/dist/{index-B-55dXDu.d.mts.map → index-CalU-mpZ.d.mts.map} +1 -1
- package/dist/{index-CJkihekp.d.mts → index-D6-lH1Mx.d.mts} +189 -189
- package/dist/index-D6-lH1Mx.d.mts.map +1 -0
- package/dist/index-DKssQ_wn.d.mts +5968 -0
- package/dist/index-DKssQ_wn.d.mts.map +1 -0
- package/dist/{index-Dwf76Qep.d.mts → index-DNKM3to5.d.mts} +3 -3
- package/dist/{index-Dwf76Qep.d.mts.map → index-DNKM3to5.d.mts.map} +1 -1
- package/dist/{index-DGe83M-p.d.mts → index-fymoeGNW.d.mts} +6 -1
- package/dist/index-fymoeGNW.d.mts.map +1 -0
- package/dist/index.d.mts +13 -4659
- package/dist/index.mjs +59 -6654
- package/dist/preview/index.d.mts +4 -90
- package/dist/preview/index.mjs +12 -12
- package/dist/{preview-5E4B96RD.mjs → preview-CYI4i4m3.mjs} +5 -4
- package/dist/preview-CYI4i4m3.mjs.map +1 -0
- package/dist/preview-engine/audio.mjs +1 -1
- package/dist/preview-engine/{chunk-TFFG5YFI.mjs → chunk-24H3QVYB.mjs} +1 -1
- package/dist/preview-engine/{chunk-7J4OK4VE.mjs → chunk-25T3M6MI.mjs} +1 -1
- package/dist/preview-engine/{chunk-O3NOB5IB.mjs → chunk-2QQQTZHS.mjs} +1 -1
- package/dist/preview-engine/{chunk-XTPEGKOZ.mjs → chunk-2RZ6S4SW.mjs} +1 -1
- package/dist/preview-engine/{chunk-37P2KIFE.mjs → chunk-3AYICEZ5.mjs} +1 -1
- package/dist/preview-engine/{chunk-JTUK7ZXK.mjs → chunk-3I6B3YPF.mjs} +1 -1
- package/dist/preview-engine/{chunk-LQBDZSQD.mjs → chunk-6GMEF2QB.mjs} +1 -1
- package/dist/preview-engine/{chunk-5CWQHYQP.mjs → chunk-7BUKVFWB.mjs} +1 -1
- package/dist/preview-engine/{chunk-AWX4YGC5.mjs → chunk-7JYMNGNK.mjs} +1 -1
- package/dist/preview-engine/chunk-AB5VITYM.mjs +1974 -0
- package/dist/preview-engine/{chunk-LSBCFJZM.mjs → chunk-BNO5JAEZ.mjs} +1 -1
- package/dist/preview-engine/{chunk-6WKWYUOM.mjs → chunk-CE6CG5BH.mjs} +1 -1
- package/dist/preview-engine/{chunk-LQENNFBA.mjs → chunk-CT2WFPYG.mjs} +11 -11
- package/dist/preview-engine/{chunk-5JSSXOBB.mjs → chunk-DUEY7AXY.mjs} +1 -1
- package/dist/preview-engine/{chunk-UDDK5QZF.mjs → chunk-DWHQSNSJ.mjs} +1 -1
- package/dist/preview-engine/{chunk-AY2ZIXST.mjs → chunk-ENS4KUJV.mjs} +1 -1
- package/dist/preview-engine/chunk-EU7CFSB5.mjs +1 -0
- package/dist/preview-engine/chunk-I6E3AKLS.mjs +1 -0
- package/dist/preview-engine/{chunk-7QE6II7R.mjs → chunk-JMOJKT5W.mjs} +1 -1
- package/dist/preview-engine/{chunk-NIRW77QA.mjs → chunk-KJGNTREI.mjs} +1 -1
- package/dist/preview-engine/{chunk-ILBZQLUF.mjs → chunk-KKBJ7X3T.mjs} +1 -1
- package/dist/preview-engine/{chunk-GQN35VLT.mjs → chunk-LNJYHSYX.mjs} +1 -1
- package/dist/preview-engine/{chunk-6TGNQ5FD.mjs → chunk-LQVACZDE.mjs} +1 -1
- package/dist/preview-engine/{chunk-YQYLBXOX.mjs → chunk-M6ZKK6ZU.mjs} +1 -1
- package/dist/preview-engine/{chunk-EEOUHDUD.mjs → chunk-MA4YVA2E.mjs} +1 -1
- package/dist/preview-engine/{chunk-JAJOZG5P.mjs → chunk-MBJXS3D7.mjs} +1 -1
- package/dist/preview-engine/{chunk-BIS3W4Z5.mjs → chunk-MCR7XMNQ.mjs} +1 -1
- package/dist/preview-engine/{chunk-C45ROXI6.mjs → chunk-NAISBHLR.mjs} +11 -11
- package/dist/preview-engine/{chunk-AKYUVDKM.mjs → chunk-NB55FW7D.mjs} +1 -1
- package/dist/preview-engine/{chunk-3SOD7OTO.mjs → chunk-NHQR76WL.mjs} +1 -1
- package/dist/preview-engine/{chunk-MJN3LOZ7.mjs → chunk-NKGXINCU.mjs} +1 -1
- package/dist/preview-engine/{chunk-FDNR4PRC.mjs → chunk-NXKXOSE6.mjs} +1 -1
- package/dist/preview-engine/{chunk-N3PRZLZJ.mjs → chunk-NYEDWUFS.mjs} +1 -1
- package/dist/preview-engine/{chunk-W3QGP5XF.mjs → chunk-P734GD7D.mjs} +1 -1
- package/dist/preview-engine/{chunk-YJ6GWVL4.mjs → chunk-PDM3TJ45.mjs} +1 -1
- package/dist/preview-engine/{chunk-KJ2DTA77.mjs → chunk-PXWCGXTF.mjs} +1 -1
- package/dist/preview-engine/{chunk-V6LCSK6Q.mjs → chunk-QCUGWPYP.mjs} +1 -1
- package/dist/preview-engine/{chunk-JJYNYYPA.mjs → chunk-QJYAIQYU.mjs} +1 -1
- package/dist/preview-engine/{chunk-VUFDQJ2B.mjs → chunk-QKQYHPBK.mjs} +1 -1
- package/dist/preview-engine/{chunk-NVTPJUNG.mjs → chunk-QVW5METG.mjs} +1 -1
- package/dist/preview-engine/{chunk-UMF7NNUA.mjs → chunk-QYIKOOFI.mjs} +1 -1
- package/dist/preview-engine/{chunk-FSAELHVT.mjs → chunk-RNFYEZLL.mjs} +1 -1
- package/dist/preview-engine/{chunk-CEIOI4HO.mjs → chunk-SIXIF5QZ.mjs} +1 -1
- package/dist/preview-engine/chunk-SNASF7OM.mjs +3 -0
- package/dist/preview-engine/{chunk-A2775RSO.mjs → chunk-T4VP45AP.mjs} +1 -1
- package/dist/preview-engine/{chunk-5EVEGKWT.mjs → chunk-TE2QAKKF.mjs} +1 -1
- package/dist/preview-engine/{chunk-6MBYREBG.mjs → chunk-UXCTWFKK.mjs} +1 -1
- package/dist/preview-engine/{chunk-V6DAD4S4.mjs → chunk-V3FODTPI.mjs} +2 -2
- package/dist/preview-engine/{chunk-JJA4G3OU.mjs → chunk-VH5V54RA.mjs} +1 -1
- package/dist/preview-engine/{chunk-GIH5QURF.mjs → chunk-VTE3IISK.mjs} +1 -1
- package/dist/preview-engine/chunk-W4HIVUUA.mjs +4 -0
- package/dist/preview-engine/{chunk-O5LA63CK.mjs → chunk-WUMVCQYI.mjs} +1 -1
- package/dist/preview-engine/{chunk-U4SQUTDV.mjs → chunk-X6BJLPW6.mjs} +1 -1
- package/dist/preview-engine/{chunk-54HE34HO.mjs → chunk-XJ4CQIZZ.mjs} +1 -1
- package/dist/preview-engine/{chunk-6AEU4DC7.mjs → chunk-XUPZBI3Y.mjs} +6 -6
- package/dist/preview-engine/{chunk-LMZHCWXP.mjs → chunk-XYRBFLFF.mjs} +1 -1
- package/dist/preview-engine/{chunk-S7NG26UG.mjs → chunk-YJ24W73B.mjs} +1 -1
- package/dist/preview-engine/{chunk-5SVJIGPK.mjs → chunk-Z4TKEI3I.mjs} +1 -1
- package/dist/preview-engine/{chunk-UVWGZUKZ.mjs → chunk-ZAIVXGSS.mjs} +1 -1
- package/dist/preview-engine/{chunk-OZDZQMTB.mjs → chunk-ZVUTFXDR.mjs} +1 -1
- package/dist/preview-engine/components.mjs +1 -0
- package/dist/preview-engine/effects.mjs +1 -1
- package/dist/preview-engine/fonts.mjs +1 -1
- package/dist/preview-engine/framefields.mjs +1 -1971
- package/dist/preview-engine/player.mjs +5 -5
- package/dist/preview-engine/renderers-2S5ZWL2J.mjs +1 -0
- package/dist/preview-engine/renderers-37CN7O4S.mjs +1 -0
- package/dist/preview-engine/renderers-3UGG2IMP.mjs +1 -0
- package/dist/preview-engine/{renderers-2A7YDJMJ.mjs → renderers-4RFB2LG2.mjs} +1 -1
- package/dist/preview-engine/renderers-6NFRKHNO.mjs +1 -0
- package/dist/preview-engine/{renderers-QJNGN722.mjs → renderers-6PVGRTXV.mjs} +1 -1
- package/dist/preview-engine/renderers-7MPBAHYA.mjs +1 -0
- package/dist/preview-engine/renderers-AFTYMS3H.mjs +1 -0
- package/dist/preview-engine/renderers-AKZAAGR7.mjs +1 -0
- package/dist/preview-engine/renderers-AYEWAW7F.mjs +1 -0
- package/dist/preview-engine/{renderers-5OGAF66H.mjs → renderers-BNXTSIXJ.mjs} +1 -1
- package/dist/preview-engine/{renderers-XPO2WQNF.mjs → renderers-BQLYS4TM.mjs} +1 -1
- package/dist/preview-engine/renderers-C7SJ3M6S.mjs +1 -0
- package/dist/preview-engine/{renderers-VD5GHHK6.mjs → renderers-CEJP6Q7F.mjs} +1 -1
- package/dist/preview-engine/{renderers-KW75FYFG.mjs → renderers-CLLR5MOQ.mjs} +1 -1
- package/dist/preview-engine/{renderers-PM4Q5QOW.mjs → renderers-DHKB5LI6.mjs} +1 -1
- package/dist/preview-engine/renderers-DUF2CTX6.mjs +1 -0
- package/dist/preview-engine/{renderers-XTRFEQO4.mjs → renderers-DZZFIYYA.mjs} +1 -1
- package/dist/preview-engine/renderers-EIJFIY6L.mjs +1 -0
- package/dist/preview-engine/renderers-EOMMSENQ.mjs +1 -0
- package/dist/preview-engine/{renderers-NJAKGI25.mjs → renderers-FOHW7RWH.mjs} +1 -1
- package/dist/preview-engine/{renderers-K23EAM2J.mjs → renderers-GF77N2KM.mjs} +1 -1
- package/dist/preview-engine/renderers-H3ZM2TOA.mjs +1 -0
- package/dist/preview-engine/{renderers-NPKRNXAT.mjs → renderers-HJ6NO5ZD.mjs} +1 -1
- package/dist/preview-engine/renderers-JXBZPQKP.mjs +1 -0
- package/dist/preview-engine/renderers-KSQM7EM5.mjs +1 -0
- package/dist/preview-engine/{renderers-WNMRLGZS.mjs → renderers-KV3TTCO6.mjs} +1 -1
- package/dist/preview-engine/{renderers-U2ZWRL25.mjs → renderers-L7EITUCD.mjs} +1 -1
- package/dist/preview-engine/renderers-LD3COS4X.mjs +1 -0
- package/dist/preview-engine/renderers-MCTBJEL7.mjs +1 -0
- package/dist/preview-engine/renderers-MKEXNBCW.mjs +1 -0
- package/dist/preview-engine/{renderers-ZRR7BLB7.mjs → renderers-MPCYLXXU.mjs} +1 -1
- package/dist/preview-engine/{renderers-DKOWLKDE.mjs → renderers-MS4HG3M4.mjs} +1 -1
- package/dist/preview-engine/{renderers-MHDLRY3S.mjs → renderers-N7T34SCI.mjs} +1 -1
- package/dist/preview-engine/{renderers-2GE5HE56.mjs → renderers-O56IOD7J.mjs} +1 -1
- package/dist/preview-engine/renderers-OZGEXW2X.mjs +1 -0
- package/dist/preview-engine/renderers-PSEDMUBV.mjs +1 -0
- package/dist/preview-engine/renderers-PVUROEGR.mjs +1 -0
- package/dist/preview-engine/renderers-QBVVTQV6.mjs +1 -0
- package/dist/preview-engine/{renderers-7M3YOI7E.mjs → renderers-QO2RHF7F.mjs} +1 -1
- package/dist/preview-engine/renderers-QPFZBLDI.mjs +1 -0
- package/dist/preview-engine/renderers-R4U2TK6P.mjs +1 -0
- package/dist/preview-engine/renderers-RBLNDAO4.mjs +1 -0
- package/dist/preview-engine/renderers-RM25AXWZ.mjs +1 -0
- package/dist/preview-engine/{renderers-DFJDEPCU.mjs → renderers-ROSSJ7Y2.mjs} +1 -1
- package/dist/preview-engine/{renderers-4H34AFW2.mjs → renderers-RRJ2DX2W.mjs} +1 -1
- package/dist/preview-engine/renderers-RYRFCEYT.mjs +1 -0
- package/dist/preview-engine/renderers-SIBP54WK.mjs +1 -0
- package/dist/preview-engine/renderers-SRU6QXLN.mjs +1 -0
- package/dist/preview-engine/{renderers-TFEDHXPY.mjs → renderers-T62TXGVO.mjs} +1 -1
- package/dist/preview-engine/{renderers-6GYRMHGQ.mjs → renderers-TAMDNTEQ.mjs} +1 -1
- package/dist/preview-engine/{renderers-LF6W5P2I.mjs → renderers-TASYN62K.mjs} +1 -1
- package/dist/preview-engine/renderers-TBP2EKJ4.mjs +1 -0
- package/dist/preview-engine/{renderers-FNPXT2EH.mjs → renderers-TWZHTKW7.mjs} +1 -1
- package/dist/preview-engine/renderers-UQHKFGDX.mjs +1 -0
- package/dist/preview-engine/{renderers-35G4KCQ2.mjs → renderers-UVABXXQF.mjs} +1 -1
- package/dist/preview-engine/{renderers-XTCBHTHC.mjs → renderers-VYK2BJID.mjs} +1 -1
- package/dist/preview-engine/{renderers-Q6AO5M54.mjs → renderers-W5CTR4B5.mjs} +1 -1
- package/dist/preview-engine/renderers-WDV7ENJA.mjs +1 -0
- package/dist/preview-engine/renderers-WNBDSSJ3.mjs +1 -0
- package/dist/preview-engine/{renderers-ATL5ARUV.mjs → renderers-WPBTAU2E.mjs} +1 -1
- package/dist/preview-engine/renderers-WTC2RNGU.mjs +1 -0
- package/dist/preview-engine/renderers-XLBHSQZJ.mjs +228 -0
- package/dist/preview-engine/{renderers-WOLTH5VI.mjs → renderers-XSPU2BIQ.mjs} +1 -1
- package/dist/preview-engine/renderers-XVUOO7B6.mjs +1 -0
- package/dist/preview-engine/renderers-YHOQUEHD.mjs +1 -0
- package/dist/preview-engine/renderers-YPFM5UJO.mjs +1 -0
- package/dist/preview-engine/renderers-YW3LBALW.mjs +1 -0
- package/dist/preview-engine/signals.mjs +1 -1
- package/dist/{program-KwDdbC0-.mjs → program-BdPDtfVv.mjs} +133 -30
- package/dist/program-BdPDtfVv.mjs.map +1 -0
- package/dist/registry/annotate.json +30 -0
- package/dist/registry/app-frame.json +38 -0
- package/dist/registry/backdrop.json +37 -0
- package/dist/registry/before-after.json +33 -0
- package/dist/registry/callout.json +30 -0
- package/dist/registry/captions.json +37 -0
- package/dist/registry/card-stack.json +30 -0
- package/dist/registry/chat-thread.json +32 -0
- package/dist/registry/code-block.json +45 -0
- package/dist/registry/confetti.json +29 -0
- package/dist/registry/counter.json +36 -0
- package/dist/registry/device-frame.json +36 -0
- package/dist/registry/focus-zoom.json +32 -0
- package/dist/registry/index.json +408 -0
- package/dist/registry/logo-reveal.json +37 -0
- package/dist/registry/lower-third.json +34 -0
- package/dist/registry/meter.json +35 -0
- package/dist/registry/mouse-pointer.json +44 -0
- package/dist/registry/selection.json +31 -0
- package/dist/registry/spotlight.json +28 -0
- package/dist/registry/terminal.json +40 -0
- package/dist/registry/text-reveal.json +39 -0
- package/dist/registry/title-card.json +34 -0
- package/dist/registry/toasts.json +28 -0
- package/dist/registry/touch-point.json +33 -0
- package/dist/registry/waveform.json +29 -0
- package/dist/registry/word-cycle.json +32 -0
- package/dist/renderer/index.d.mts +2 -2
- package/dist/renderer/index.mjs +3 -3
- package/dist/{renderer-Bhfl-WFX.mjs → renderer-0cHsK6xR.mjs} +5 -5
- package/dist/{renderer-Bhfl-WFX.mjs.map → renderer-0cHsK6xR.mjs.map} +1 -1
- package/dist/{renderer-D4No_jA4.mjs → renderer-1VKN5j2C.mjs} +4 -4
- package/dist/{renderer-D4No_jA4.mjs.map → renderer-1VKN5j2C.mjs.map} +1 -1
- package/dist/{renderer-qYhNf6iB.mjs → renderer-2bipMLqz.mjs} +3 -3
- package/dist/{renderer-qYhNf6iB.mjs.map → renderer-2bipMLqz.mjs.map} +1 -1
- package/dist/{renderer-DK9etIAz.mjs → renderer-7DyjqxEj.mjs} +5 -5
- package/dist/{renderer-DK9etIAz.mjs.map → renderer-7DyjqxEj.mjs.map} +1 -1
- package/dist/renderer-B-D_VZg3.mjs +5 -0
- package/dist/{renderer-Ci6YMa4u.mjs → renderer-B31zMDE8.mjs} +5 -5
- package/dist/{renderer-Ci6YMa4u.mjs.map → renderer-B31zMDE8.mjs.map} +1 -1
- package/dist/{renderer-DP_In2uT.mjs → renderer-B4blg067.mjs} +4 -4
- package/dist/{renderer-DP_In2uT.mjs.map → renderer-B4blg067.mjs.map} +1 -1
- package/dist/{renderer-kNjMhwiZ.mjs → renderer-B5YYBBDq.mjs} +3 -3
- package/dist/{renderer-kNjMhwiZ.mjs.map → renderer-B5YYBBDq.mjs.map} +1 -1
- package/dist/renderer-B64dhpDX.mjs +5 -0
- package/dist/{renderer-mqUBkx-a.mjs → renderer-B8LXXvHi.mjs} +4 -4
- package/dist/{renderer-mqUBkx-a.mjs.map → renderer-B8LXXvHi.mjs.map} +1 -1
- package/dist/renderer-BA2Ko4H1.mjs +3 -0
- package/dist/{renderer-B4ydDdo6.mjs → renderer-BAkPq8qo.mjs} +3 -3
- package/dist/{renderer-B4ydDdo6.mjs.map → renderer-BAkPq8qo.mjs.map} +1 -1
- package/dist/{renderer-OEpwc9Zk.mjs → renderer-BBTdHKH7.mjs} +5 -5
- package/dist/{renderer-OEpwc9Zk.mjs.map → renderer-BBTdHKH7.mjs.map} +1 -1
- package/dist/{renderer-DGT141pN.mjs → renderer-BBTkfhL8.mjs} +5 -5
- package/dist/{renderer-DGT141pN.mjs.map → renderer-BBTkfhL8.mjs.map} +1 -1
- package/dist/renderer-BDL4jyrb.mjs +5 -0
- package/dist/{renderer-BtWWpFvl.mjs → renderer-BGNdwdCR.mjs} +4 -4
- package/dist/{renderer-BtWWpFvl.mjs.map → renderer-BGNdwdCR.mjs.map} +1 -1
- package/dist/{renderer-DXSIstnn.mjs → renderer-BJwOM1Dq.mjs} +4 -4
- package/dist/{renderer-DXSIstnn.mjs.map → renderer-BJwOM1Dq.mjs.map} +1 -1
- package/dist/renderer-BKCZGKkl.mjs +5 -0
- package/dist/renderer-BKs3jI7-.mjs +5 -0
- package/dist/{renderer-C5WkQZGR.mjs → renderer-BN_n6O6P.mjs} +5 -5
- package/dist/{renderer-C5WkQZGR.mjs.map → renderer-BN_n6O6P.mjs.map} +1 -1
- package/dist/renderer-BW74Zf-u.mjs +5 -0
- package/dist/{renderer-C1U85w9f.mjs → renderer-BWa3CLK7.mjs} +3 -3
- package/dist/{renderer-C1U85w9f.mjs.map → renderer-BWa3CLK7.mjs.map} +1 -1
- package/dist/{renderer-plx7_lUQ.mjs → renderer-BWnFh7NO.mjs} +5 -5
- package/dist/{renderer-plx7_lUQ.mjs.map → renderer-BWnFh7NO.mjs.map} +1 -1
- package/dist/renderer-BXuQN61O.mjs +5 -0
- package/dist/renderer-BY1pPvzx.mjs +6 -0
- package/dist/{renderer-CwO8T8l8.mjs → renderer-BYJS2lhn.mjs} +4 -4
- package/dist/{renderer-CwO8T8l8.mjs.map → renderer-BYJS2lhn.mjs.map} +1 -1
- package/dist/renderer-Bahthqvq.mjs +5 -0
- package/dist/renderer-BbaiQG8h.mjs +5 -0
- package/dist/{renderer-gm0zoV4t.mjs → renderer-BfrzKmRh.mjs} +3 -3
- package/dist/{renderer-gm0zoV4t.mjs.map → renderer-BfrzKmRh.mjs.map} +1 -1
- package/dist/renderer-BhHF-08y.mjs +5 -0
- package/dist/{renderer-DQeUc1yY.mjs → renderer-BhhweLr_.mjs} +4 -4
- package/dist/{renderer-DQeUc1yY.mjs.map → renderer-BhhweLr_.mjs.map} +1 -1
- package/dist/{renderer-OsA-Lg4d.mjs → renderer-Bmj7AyJP.mjs} +3 -3
- package/dist/{renderer-OsA-Lg4d.mjs.map → renderer-Bmj7AyJP.mjs.map} +1 -1
- package/dist/{renderer-DZhIe8Gj.mjs → renderer-BmoQJUJO.mjs} +4 -4
- package/dist/{renderer-DZhIe8Gj.mjs.map → renderer-BmoQJUJO.mjs.map} +1 -1
- package/dist/renderer-BnrMcw6C.mjs +5 -0
- package/dist/{renderer-Blm4Dv_h.mjs → renderer-Bo1PY0zW.mjs} +3 -3
- package/dist/{renderer-DcOT5c0t.mjs → renderer-Bo_d7h86.mjs} +4 -4
- package/dist/{renderer-DcOT5c0t.mjs.map → renderer-Bo_d7h86.mjs.map} +1 -1
- package/dist/renderer-BsS61z5l.mjs +5 -0
- package/dist/renderer-Btuq2Eq8.mjs +5 -0
- package/dist/renderer-BvcqncI2.mjs +3 -0
- package/dist/{renderer-C4xvz_Ft.mjs → renderer-Bw5YP2Db.mjs} +4 -4
- package/dist/{renderer-C4xvz_Ft.mjs.map → renderer-Bw5YP2Db.mjs.map} +1 -1
- package/dist/renderer-BxmsEl2x.mjs +5 -0
- package/dist/{renderer-BSitV56h.mjs → renderer-C9r0-KY4.mjs} +10 -1
- package/dist/{renderer-BSitV56h.mjs.map → renderer-C9r0-KY4.mjs.map} +1 -1
- package/dist/{renderer-B4jxP8vF.mjs → renderer-CDX2f82b.mjs} +5 -5
- package/dist/{renderer-B4jxP8vF.mjs.map → renderer-CDX2f82b.mjs.map} +1 -1
- package/dist/renderer-CGOyHdKs.mjs +5 -0
- package/dist/renderer-CJjmpmpu.mjs +5 -0
- package/dist/{renderer-P4OPsD82.mjs → renderer-CJoa4H2G.mjs} +3 -3
- package/dist/{renderer-P4OPsD82.mjs.map → renderer-CJoa4H2G.mjs.map} +1 -1
- package/dist/{renderer-1P3yS8YM.mjs → renderer-CLO8QHWE.mjs} +4 -4
- package/dist/{renderer-1P3yS8YM.mjs.map → renderer-CLO8QHWE.mjs.map} +1 -1
- package/dist/{renderer-CjQAYeYz.mjs → renderer-CMEqUhrW.mjs} +5 -5
- package/dist/{renderer-CjQAYeYz.mjs.map → renderer-CMEqUhrW.mjs.map} +1 -1
- package/dist/{renderer-CzgDJcot.mjs → renderer-CNs1vBUy.mjs} +4 -4
- package/dist/{renderer-CzgDJcot.mjs.map → renderer-CNs1vBUy.mjs.map} +1 -1
- package/dist/{index-B0BZMhtw.d.mts → renderer-COXKPofU.d.mts} +13 -13
- package/dist/renderer-COXKPofU.d.mts.map +1 -0
- package/dist/{renderer-CrwYWVsV.mjs → renderer-COtZ315B.mjs} +3 -3
- package/dist/renderer-CQvDDAIu.mjs +5 -0
- package/dist/{renderer-DOvzHN60.mjs → renderer-CWSM0IGG.mjs} +4 -4
- package/dist/{renderer-DOvzHN60.mjs.map → renderer-CWSM0IGG.mjs.map} +1 -1
- package/dist/{renderer-DVFFVy9v.mjs → renderer-CXbXF7Dh.mjs} +5 -5
- package/dist/{renderer-DVFFVy9v.mjs.map → renderer-CXbXF7Dh.mjs.map} +1 -1
- package/dist/renderer-CYxigw7S.mjs +5 -0
- package/dist/{renderer-DOxmmN6Q.mjs → renderer-CdUf7ZDJ.mjs} +5 -5
- package/dist/{renderer-DOxmmN6Q.mjs.map → renderer-CdUf7ZDJ.mjs.map} +1 -1
- package/dist/renderer-CgDofO5z.mjs +5 -0
- package/dist/renderer-CgmQchab.mjs +5 -0
- package/dist/{renderer-CS8VMTp1.mjs → renderer-Ch7qwjH9.mjs} +5 -5
- package/dist/{renderer-CS8VMTp1.mjs.map → renderer-Ch7qwjH9.mjs.map} +1 -1
- package/dist/{renderer-PuN2_AL_.mjs → renderer-ChCUad83.mjs} +5 -5
- package/dist/{renderer-PuN2_AL_.mjs.map → renderer-ChCUad83.mjs.map} +1 -1
- package/dist/{renderer-BaJQx0Bp.mjs → renderer-ChjkppUz.mjs} +5 -5
- package/dist/{renderer-BaJQx0Bp.mjs.map → renderer-ChjkppUz.mjs.map} +1 -1
- package/dist/{renderer-CTYKUnDq.mjs → renderer-Cj1giMd0.mjs} +3 -3
- package/dist/{renderer-CTYKUnDq.mjs.map → renderer-Cj1giMd0.mjs.map} +1 -1
- package/dist/{renderer-DWG4Podv.mjs → renderer-Cjs1OeBu.mjs} +6 -6
- package/dist/{renderer-DWG4Podv.mjs.map → renderer-Cjs1OeBu.mjs.map} +1 -1
- package/dist/renderer-CjzrLwW_.mjs +5 -0
- package/dist/renderer-ClnYWADT.mjs +5 -0
- package/dist/{renderer-B9ssmkbx.mjs → renderer-CmKdr2nA.mjs} +5 -5
- package/dist/{renderer-B9ssmkbx.mjs.map → renderer-CmKdr2nA.mjs.map} +1 -1
- package/dist/renderer-CwAd71C6.mjs +5 -0
- package/dist/{renderer-BT0x6KPK.mjs → renderer-D0X7Eh-T.mjs} +4 -4
- package/dist/{renderer-BT0x6KPK.mjs.map → renderer-D0X7Eh-T.mjs.map} +1 -1
- package/dist/{renderer-DYbgd6Ye.mjs → renderer-D2ru2Afi.mjs} +4 -4
- package/dist/{renderer-DYbgd6Ye.mjs.map → renderer-D2ru2Afi.mjs.map} +1 -1
- package/dist/renderer-D3Z9t-xT.mjs +5 -0
- package/dist/{renderer-CLxQ4rU6.mjs → renderer-D5u3GVtD.mjs} +74 -74
- package/dist/{renderer-CLxQ4rU6.mjs.map → renderer-D5u3GVtD.mjs.map} +1 -1
- package/dist/{renderer-DCsTCvdo.mjs → renderer-D6p8b6ql.mjs} +4 -4
- package/dist/{renderer-DCsTCvdo.mjs.map → renderer-D6p8b6ql.mjs.map} +1 -1
- package/dist/{renderer-Bkq1PT0g.mjs → renderer-DBjV6C2u.mjs} +3 -3
- package/dist/{renderer-BAoKytKL.mjs → renderer-DHqicGgT.mjs} +4 -4
- package/dist/{renderer-BAoKytKL.mjs.map → renderer-DHqicGgT.mjs.map} +1 -1
- package/dist/{renderer-B_b8-ztW.mjs → renderer-DK34NH92.mjs} +5 -5
- package/dist/{renderer-B_b8-ztW.mjs.map → renderer-DK34NH92.mjs.map} +1 -1
- package/dist/renderer-DKH1oSlW.mjs +5 -0
- package/dist/{renderer-I3Wxk1tL.mjs → renderer-DP41Fokp.mjs} +4 -4
- package/dist/{renderer-I3Wxk1tL.mjs.map → renderer-DP41Fokp.mjs.map} +1 -1
- package/dist/{renderer-CPLfsRe1.mjs → renderer-DQuKNgIx.mjs} +6 -6
- package/dist/{renderer-CPLfsRe1.mjs.map → renderer-DQuKNgIx.mjs.map} +1 -1
- package/dist/renderer-DTkf_hwG.mjs +5 -0
- package/dist/renderer-DU0bmOS7.mjs +5 -0
- package/dist/{renderer-GapR_An3.mjs → renderer-DWaqF7-6.mjs} +4 -4
- package/dist/{renderer-GapR_An3.mjs.map → renderer-DWaqF7-6.mjs.map} +1 -1
- package/dist/renderer-D_vJHQt5.mjs +5 -0
- package/dist/{renderer-GbVNyv-E.mjs → renderer-Db_wphHH.mjs} +192 -27
- package/dist/renderer-Db_wphHH.mjs.map +1 -0
- package/dist/renderer-Dc5n0M6P.mjs +5 -0
- package/dist/renderer-Ddfn0Dha.mjs +5 -0
- package/dist/renderer-DeSoNQeG.mjs +5 -0
- package/dist/{renderer-C0ds-UfM.mjs → renderer-DkPDYtD3.mjs} +5 -5
- package/dist/{renderer-C0ds-UfM.mjs.map → renderer-DkPDYtD3.mjs.map} +1 -1
- package/dist/{renderer-BCLmYH4S.mjs → renderer-DqO9gBAi.mjs} +4 -4
- package/dist/{renderer-BCLmYH4S.mjs.map → renderer-DqO9gBAi.mjs.map} +1 -1
- package/dist/{renderer-BUwHWIf7.mjs → renderer-DuQMzR3v.mjs} +4 -4
- package/dist/{renderer-BUwHWIf7.mjs.map → renderer-DuQMzR3v.mjs.map} +1 -1
- package/dist/{renderer-DBtt-7wt.d.mts → renderer-Dx28wTi1.d.mts} +2 -2
- package/dist/{renderer-DBtt-7wt.d.mts.map → renderer-Dx28wTi1.d.mts.map} +1 -1
- package/dist/{renderer-f7A01ArI.mjs → renderer-DyMEAZIm.mjs} +5 -5
- package/dist/{renderer-f7A01ArI.mjs.map → renderer-DyMEAZIm.mjs.map} +1 -1
- package/dist/renderer-Dzca9Qba.mjs +5 -0
- package/dist/{renderer-DBKyuPl1.mjs → renderer-FCqOfN6n.mjs} +5 -5
- package/dist/{renderer-DBKyuPl1.mjs.map → renderer-FCqOfN6n.mjs.map} +1 -1
- package/dist/{renderer-D96Pu8yX.mjs → renderer-Fsdod0yZ.mjs} +5 -5
- package/dist/{renderer-D96Pu8yX.mjs.map → renderer-Fsdod0yZ.mjs.map} +1 -1
- package/dist/{renderer-Du8eOWWU.mjs → renderer-G3px5ODP.mjs} +4 -4
- package/dist/{renderer-Du8eOWWU.mjs.map → renderer-G3px5ODP.mjs.map} +1 -1
- package/dist/renderer-HRVvtc9c.mjs +5 -0
- package/dist/{renderer-CUPWHfEY.mjs → renderer-IMg0dK6K.mjs} +5 -5
- package/dist/{renderer-CUPWHfEY.mjs.map → renderer-IMg0dK6K.mjs.map} +1 -1
- package/dist/renderer-M3Qs4f1K.mjs +5 -0
- package/dist/renderer-NDHJt_Ae.mjs +5 -0
- package/dist/{renderer-y6k54AM6.mjs → renderer-PLoGrFGz.mjs} +4 -4
- package/dist/{renderer-y6k54AM6.mjs.map → renderer-PLoGrFGz.mjs.map} +1 -1
- package/dist/{renderer-DO5r7ZV-.mjs → renderer-PNIgmWft.mjs} +2 -2
- package/dist/{renderer-DO5r7ZV-.mjs.map → renderer-PNIgmWft.mjs.map} +1 -1
- package/dist/{renderer-CDky5Gva.mjs → renderer-VdTs-dqH.mjs} +4 -4
- package/dist/{renderer-CDky5Gva.mjs.map → renderer-VdTs-dqH.mjs.map} +1 -1
- package/dist/{renderer-QaN-aejD.mjs → renderer-VxVi_0c7.mjs} +3 -3
- package/dist/{renderer-QaN-aejD.mjs.map → renderer-VxVi_0c7.mjs.map} +1 -1
- package/dist/{renderer-BMLJgnbU.mjs → renderer-WVrUeiLZ.mjs} +3 -3
- package/dist/{renderer-BHLYKy8b.mjs → renderer-Z39F9QK5.mjs} +5 -5
- package/dist/{renderer-BHLYKy8b.mjs.map → renderer-Z39F9QK5.mjs.map} +1 -1
- package/dist/{renderer-DSbRWfgl.mjs → renderer-ZjSP5jw6.mjs} +3 -3
- package/dist/{renderer-DSbRWfgl.mjs.map → renderer-ZjSP5jw6.mjs.map} +1 -1
- package/dist/{renderer-CE83KHgr.mjs → renderer-fH9SCJC2.mjs} +3 -3
- package/dist/{renderer-CE83KHgr.mjs.map → renderer-fH9SCJC2.mjs.map} +1 -1
- package/dist/{renderer-Cy4a31rZ.mjs → renderer-gjT5v76-.mjs} +3 -3
- package/dist/{renderer-Cy4a31rZ.mjs.map → renderer-gjT5v76-.mjs.map} +1 -1
- package/dist/{renderer-C-z6bxj9.mjs → renderer-kP5Y282J.mjs} +5 -5
- package/dist/{renderer-C-z6bxj9.mjs.map → renderer-kP5Y282J.mjs.map} +1 -1
- package/dist/{renderer-BI8QhEj9.mjs → renderer-kkDfQ56G.mjs} +5 -5
- package/dist/{renderer-BI8QhEj9.mjs.map → renderer-kkDfQ56G.mjs.map} +1 -1
- package/dist/{renderer-DHUlVqST.mjs → renderer-l_U6kA8K.mjs} +3 -3
- package/dist/{renderer-DHUlVqST.mjs.map → renderer-l_U6kA8K.mjs.map} +1 -1
- package/dist/{renderer-BajIOuZH.mjs → renderer-nLPfvY3-.mjs} +2 -2
- package/dist/{renderer-BajIOuZH.mjs.map → renderer-nLPfvY3-.mjs.map} +1 -1
- package/dist/{renderer-C4vHq0X8.mjs → renderer-o_JK4YfO.mjs} +5 -5
- package/dist/{renderer-C4vHq0X8.mjs.map → renderer-o_JK4YfO.mjs.map} +1 -1
- package/dist/{renderer-CAi-lhR2.mjs → renderer-vwoyR8pW.mjs} +4 -4
- package/dist/{renderer-CAi-lhR2.mjs.map → renderer-vwoyR8pW.mjs.map} +1 -1
- package/dist/{renderers-CP8CFWDs-D1FHpA7I.mjs → renderers-CP8CFWDs-DiX2Y4Qp.mjs} +4 -4
- package/dist/{renderers-CP8CFWDs-D1FHpA7I.mjs.map → renderers-CP8CFWDs-DiX2Y4Qp.mjs.map} +1 -1
- package/dist/signals/index.d.mts +6 -6
- package/dist/signals/index.mjs +8 -8
- package/dist/{signals-BwdVfK3p.mjs → signals-Cf9mfNGE.mjs} +4 -4
- package/dist/{signals-BwdVfK3p.mjs.map → signals-Cf9mfNGE.mjs.map} +1 -1
- package/dist/src-Ds9IAk5S.mjs +8373 -0
- package/dist/src-Ds9IAk5S.mjs.map +1 -0
- package/package.json +68 -58
- package/dist/dist-DMa2BbYs.mjs.map +0 -1
- package/dist/dist-hmWTJPik.mjs.map +0 -1
- package/dist/fonts-Da1JDKpc.mjs.map +0 -1
- package/dist/index-B0BZMhtw.d.mts.map +0 -1
- package/dist/index-CJkihekp.d.mts.map +0 -1
- package/dist/index-DGe83M-p.d.mts.map +0 -1
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/preview/index.d.mts.map +0 -1
- package/dist/preview-5E4B96RD.mjs.map +0 -1
- package/dist/preview-engine/chunk-3T4LB4ZH.mjs +0 -3
- package/dist/preview-engine/chunk-E7DH7EPX.mjs +0 -1
- package/dist/preview-engine/chunk-PCWWKYFO.mjs +0 -1
- package/dist/preview-engine/chunk-RQLMW6MA.mjs +0 -4
- package/dist/preview-engine/chunk-XN56POGE.mjs +0 -1
- package/dist/preview-engine/renderers-2AD6AHAO.mjs +0 -1
- package/dist/preview-engine/renderers-37UYW266.mjs +0 -1
- package/dist/preview-engine/renderers-3YHETAPE.mjs +0 -1
- package/dist/preview-engine/renderers-43LBWRY2.mjs +0 -1
- package/dist/preview-engine/renderers-4I4UDLDR.mjs +0 -1
- package/dist/preview-engine/renderers-5EITT2FW.mjs +0 -1
- package/dist/preview-engine/renderers-7UKFQ75V.mjs +0 -1
- package/dist/preview-engine/renderers-AIRDDXRB.mjs +0 -1
- package/dist/preview-engine/renderers-BUOGMWAA.mjs +0 -1
- package/dist/preview-engine/renderers-C4XIAG3F.mjs +0 -1
- package/dist/preview-engine/renderers-ELARGDRC.mjs +0 -1
- package/dist/preview-engine/renderers-EU5VM2S2.mjs +0 -1
- package/dist/preview-engine/renderers-GEPP3YKK.mjs +0 -1
- package/dist/preview-engine/renderers-IQNZQWYU.mjs +0 -1
- package/dist/preview-engine/renderers-J6DEIWTU.mjs +0 -1
- package/dist/preview-engine/renderers-JQ7AI473.mjs +0 -228
- package/dist/preview-engine/renderers-JTVCE5PV.mjs +0 -1
- package/dist/preview-engine/renderers-KCNUETAD.mjs +0 -1
- package/dist/preview-engine/renderers-KKBHXAWS.mjs +0 -1
- package/dist/preview-engine/renderers-LER7SUT2.mjs +0 -1
- package/dist/preview-engine/renderers-MOERLDWF.mjs +0 -1
- package/dist/preview-engine/renderers-O57YIIAO.mjs +0 -1
- package/dist/preview-engine/renderers-OPUIAD7I.mjs +0 -1
- package/dist/preview-engine/renderers-PENUAXDD.mjs +0 -1
- package/dist/preview-engine/renderers-PFCI7ZFW.mjs +0 -1
- package/dist/preview-engine/renderers-Q4HDP2IE.mjs +0 -1
- package/dist/preview-engine/renderers-QMHUOKMM.mjs +0 -1
- package/dist/preview-engine/renderers-R26YPECG.mjs +0 -1
- package/dist/preview-engine/renderers-TAFDMFEA.mjs +0 -1
- package/dist/preview-engine/renderers-TMZLWQP2.mjs +0 -1
- package/dist/preview-engine/renderers-TP6ZMGU4.mjs +0 -1
- package/dist/preview-engine/renderers-TY63VTZB.mjs +0 -1
- package/dist/preview-engine/renderers-UBO4ZNE6.mjs +0 -1
- package/dist/preview-engine/renderers-UCNQ536S.mjs +0 -1
- package/dist/preview-engine/renderers-WOZQDE4A.mjs +0 -1
- package/dist/preview-engine/renderers-X2XGDF3R.mjs +0 -1
- package/dist/preview-engine/renderers-XG3BDROH.mjs +0 -1
- package/dist/preview-engine/renderers-XS4CFZWR.mjs +0 -1
- package/dist/preview-engine/renderers-ZQDMRWN7.mjs +0 -1
- package/dist/program-KwDdbC0-.mjs.map +0 -1
- package/dist/renderer-5C41E6gT.mjs +0 -5
- package/dist/renderer-6SXF9Ykm.mjs +0 -5
- package/dist/renderer-B2C2w3Wr.mjs +0 -5
- package/dist/renderer-B2QSfPYZ.mjs +0 -5
- package/dist/renderer-B5cQcMl1.mjs +0 -5
- package/dist/renderer-BDhD8Yab.mjs +0 -3
- package/dist/renderer-BSDdTHDh.mjs +0 -5
- package/dist/renderer-BTUjk8uY.mjs +0 -5
- package/dist/renderer-Bcey5Gvk.mjs +0 -5
- package/dist/renderer-Bd2MuOeJ.mjs +0 -5
- package/dist/renderer-Bd5A0zer.mjs +0 -5
- package/dist/renderer-CC-WlYa2.mjs +0 -5
- package/dist/renderer-Cb0qf1UG.mjs +0 -5
- package/dist/renderer-CfX13dgQ.mjs +0 -5
- package/dist/renderer-ChFkRLrv.mjs +0 -5
- package/dist/renderer-CjkfJj5R.mjs +0 -5
- package/dist/renderer-Ck7Lu6c9.mjs +0 -5
- package/dist/renderer-CuquqG_c.mjs +0 -5
- package/dist/renderer-Cwz2E4QD.mjs +0 -5
- package/dist/renderer-Czkt9YYp.mjs +0 -5
- package/dist/renderer-DFTIhSdJ.mjs +0 -5
- package/dist/renderer-DFaa-Ats.mjs +0 -5
- package/dist/renderer-DIHXKvPl.mjs +0 -5
- package/dist/renderer-DMzOqVM3.mjs +0 -5
- package/dist/renderer-DOId5U8x.mjs +0 -5
- package/dist/renderer-DQXFOup8.mjs +0 -5
- package/dist/renderer-DRt3BSTj.mjs +0 -5
- package/dist/renderer-Di_5vQ81.mjs +0 -6
- package/dist/renderer-DkmpsPIa.mjs +0 -5
- package/dist/renderer-Ds6wd9Gk.mjs +0 -5
- package/dist/renderer-DuuOlYIG.mjs +0 -3
- package/dist/renderer-Dv4p0lp9.mjs +0 -5
- package/dist/renderer-DzWoOlVc.mjs +0 -5
- package/dist/renderer-GbVNyv-E.mjs.map +0 -1
- package/dist/renderer-IOz63OWg.mjs +0 -5
- package/dist/renderer-JkSrsUa5.mjs +0 -5
- package/dist/renderer-Ocs1Djwu.mjs +0 -5
- package/dist/renderer-Wdn7m_uN.mjs +0 -5
- package/dist/renderer-mKpjaoE3.mjs +0 -5
- /package/dist/{chunk-GBe2k3y8.mjs → chunk-D7gtBK74.mjs} +0 -0
- /package/dist/preview-engine/{chunk-Q4Z54DQ7.mjs → chunk-LXHECDOB.mjs} +0 -0
- /package/dist/{renderer-B-BcgA6d.mjs → renderer-B7fX0C62.mjs} +0 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"name": "annotate",
|
|
4
|
+
"title": "Annotate",
|
|
5
|
+
"summary": "Marks that draw on to point at something: underline, circle, box, highlight, strike, cross, bracket, arrow or squiggle, clean or hand-drawn with a boil, with an optional label.",
|
|
6
|
+
"tags": [
|
|
7
|
+
"annotation",
|
|
8
|
+
"underline",
|
|
9
|
+
"highlight",
|
|
10
|
+
"arrow",
|
|
11
|
+
"hand-drawn",
|
|
12
|
+
"explainer"
|
|
13
|
+
],
|
|
14
|
+
"example": "Annotate({ target: { text: headline, match: \"faster\" }, mark: \"circle\" })",
|
|
15
|
+
"registryDependencies": []
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "app-frame",
|
|
19
|
+
"title": "AppFrame",
|
|
20
|
+
"summary": "Window chrome around any content — desktop window, browser with a typed URL, terminal, or bare frame — and the coordinate system for pointing into it.",
|
|
21
|
+
"tags": [
|
|
22
|
+
"window",
|
|
23
|
+
"browser",
|
|
24
|
+
"mockup",
|
|
25
|
+
"ui",
|
|
26
|
+
"screen recording",
|
|
27
|
+
"device"
|
|
28
|
+
],
|
|
29
|
+
"example": "AppFrame({ kind: \"browser\", url: \"acme.dev\", content: \"assets/recording.mp4\" })",
|
|
30
|
+
"registryDependencies": []
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "backdrop",
|
|
34
|
+
"title": "Backdrop",
|
|
35
|
+
"summary": "The surface behind a scene: a drifting mesh gradient, a grid or a dot field, with vignette and film grain, looping exactly.",
|
|
36
|
+
"tags": [
|
|
37
|
+
"background",
|
|
38
|
+
"backdrop",
|
|
39
|
+
"gradient",
|
|
40
|
+
"grid",
|
|
41
|
+
"dots",
|
|
42
|
+
"grain",
|
|
43
|
+
"loop"
|
|
44
|
+
],
|
|
45
|
+
"example": "Backdrop({ kind: \"mesh\" })",
|
|
46
|
+
"registryDependencies": []
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"name": "before-after",
|
|
50
|
+
"title": "BeforeAfter",
|
|
51
|
+
"summary": "Two versions of one picture split by a moving divider with a grip and labels: a clip with and without an effect, a redesign, a cleanup.",
|
|
52
|
+
"tags": [
|
|
53
|
+
"before after",
|
|
54
|
+
"comparison",
|
|
55
|
+
"split",
|
|
56
|
+
"wipe",
|
|
57
|
+
"slider",
|
|
58
|
+
"effects"
|
|
59
|
+
],
|
|
60
|
+
"example": "BeforeAfter({ before: \"assets/raw.mp4\", after: graded })",
|
|
61
|
+
"registryDependencies": []
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"name": "callout",
|
|
65
|
+
"title": "Callout",
|
|
66
|
+
"summary": "A label with a leader line pinned to a point, node, text or a moving tracked object; picks the open side and stays inside the frame.",
|
|
67
|
+
"tags": [
|
|
68
|
+
"callout",
|
|
69
|
+
"label",
|
|
70
|
+
"leader line",
|
|
71
|
+
"annotation",
|
|
72
|
+
"tracking",
|
|
73
|
+
"explainer"
|
|
74
|
+
],
|
|
75
|
+
"example": "Callout({ target: [820, 410], title: \"New\", text: \"Faster renderer\" })",
|
|
76
|
+
"registryDependencies": []
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"name": "captions",
|
|
80
|
+
"title": "Captions",
|
|
81
|
+
"summary": "Word-timed captions from words or a transcript (SRT, WebVTT, word JSON) in eight published styles, highlighting each word on its exact frame, optionally tucked behind the speaker.",
|
|
82
|
+
"tags": [
|
|
83
|
+
"captions",
|
|
84
|
+
"subtitles",
|
|
85
|
+
"social",
|
|
86
|
+
"talking head",
|
|
87
|
+
"transcript",
|
|
88
|
+
"karaoke"
|
|
89
|
+
],
|
|
90
|
+
"example": "Captions({ transcript: srt, style: \"karaoke\", emphasis: [\"faster\"] })",
|
|
91
|
+
"registryDependencies": []
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"name": "card-stack",
|
|
95
|
+
"title": "CardStack",
|
|
96
|
+
"summary": "Cards in a depth stack that shuffle: the front card flies off and returns to the back, or cards are dealt onto the pile.",
|
|
97
|
+
"tags": [
|
|
98
|
+
"cards",
|
|
99
|
+
"stack",
|
|
100
|
+
"deck",
|
|
101
|
+
"carousel",
|
|
102
|
+
"testimonials",
|
|
103
|
+
"features",
|
|
104
|
+
"3d"
|
|
105
|
+
],
|
|
106
|
+
"example": "CardStack({ cards: [{ title: \"Fast\" }, { title: \"Typed\" }, { title: \"Yours\" }] })",
|
|
107
|
+
"registryDependencies": []
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"name": "chat-thread",
|
|
111
|
+
"title": "ChatThread",
|
|
112
|
+
"summary": "A messaging conversation: bubbles that spring in from either side, typing dots before replies, names, timestamps, reactions, images and auto-scroll.",
|
|
113
|
+
"tags": [
|
|
114
|
+
"chat",
|
|
115
|
+
"messages",
|
|
116
|
+
"conversation",
|
|
117
|
+
"social",
|
|
118
|
+
"ui",
|
|
119
|
+
"demo"
|
|
120
|
+
],
|
|
121
|
+
"example": "ChatThread({ messages: [{ from: \"me\", text: \"Shipped?\" }, { from: \"sam\", text: \"Live!\", reaction: \"🎉\" }] })",
|
|
122
|
+
"registryDependencies": []
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"name": "code-block",
|
|
126
|
+
"title": "CodeBlock",
|
|
127
|
+
"summary": "Code that reads like an editor and moves like an explanation: syntax colours, typing, a focus band that walks the lines, and diffs where kept lines glide to their new places.",
|
|
128
|
+
"tags": [
|
|
129
|
+
"code",
|
|
130
|
+
"syntax",
|
|
131
|
+
"diff",
|
|
132
|
+
"developer",
|
|
133
|
+
"tutorial",
|
|
134
|
+
"typing"
|
|
135
|
+
],
|
|
136
|
+
"example": "CodeBlock({ code, lang: \"ts\", focus: [{ at: 60, lines: [3] }] })",
|
|
137
|
+
"registryDependencies": [
|
|
138
|
+
"app-frame"
|
|
139
|
+
]
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"name": "confetti",
|
|
143
|
+
"title": "Confetti",
|
|
144
|
+
"summary": "Celebration bursts of paper, ribbons and sparkles on the GPU that arc up, flutter down and can settle on a floor; bursts can follow cues.",
|
|
145
|
+
"tags": [
|
|
146
|
+
"confetti",
|
|
147
|
+
"celebration",
|
|
148
|
+
"particles",
|
|
149
|
+
"burst",
|
|
150
|
+
"success",
|
|
151
|
+
"party"
|
|
152
|
+
],
|
|
153
|
+
"example": "Confetti({ bursts: [{ at: 30, origin: [960, 900] }], floor: true })",
|
|
154
|
+
"registryDependencies": []
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"name": "counter",
|
|
158
|
+
"title": "Counter",
|
|
159
|
+
"summary": "A number that counts to its value on odometer reels (or stepping digits), with format-aware separators, affixes and multi-step values.",
|
|
160
|
+
"tags": [
|
|
161
|
+
"number",
|
|
162
|
+
"counter",
|
|
163
|
+
"stat",
|
|
164
|
+
"odometer",
|
|
165
|
+
"data",
|
|
166
|
+
"price"
|
|
167
|
+
],
|
|
168
|
+
"example": "Counter({ to: 12480, format: \",d\", prefix: \"$\" })",
|
|
169
|
+
"registryDependencies": []
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"name": "device-frame",
|
|
173
|
+
"title": "DeviceFrame",
|
|
174
|
+
"summary": "A phone, tablet or laptop around a screen; content is authored in device points and `at(x, y)` maps them for pointers and touches.",
|
|
175
|
+
"tags": [
|
|
176
|
+
"device",
|
|
177
|
+
"phone",
|
|
178
|
+
"mobile",
|
|
179
|
+
"tablet",
|
|
180
|
+
"laptop",
|
|
181
|
+
"mockup",
|
|
182
|
+
"screen",
|
|
183
|
+
"app"
|
|
184
|
+
],
|
|
185
|
+
"example": "DeviceFrame({ device: \"phone\", content: \"assets/app.mp4\" })",
|
|
186
|
+
"registryDependencies": []
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"name": "focus-zoom",
|
|
190
|
+
"title": "FocusZoom",
|
|
191
|
+
"summary": "A camera over 2D content that pushes in on each burst of pointer clicks (or on given shots) and eases back out, clamped to the content.",
|
|
192
|
+
"tags": [
|
|
193
|
+
"camera",
|
|
194
|
+
"zoom",
|
|
195
|
+
"auto-zoom",
|
|
196
|
+
"screen recording",
|
|
197
|
+
"demo",
|
|
198
|
+
"focus"
|
|
199
|
+
],
|
|
200
|
+
"example": "FocusZoom({ content: [frame, pointer], follow: pointer })",
|
|
201
|
+
"registryDependencies": []
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"name": "logo-reveal",
|
|
205
|
+
"title": "LogoReveal",
|
|
206
|
+
"summary": "The end-card lockup: a mark and a wordmark arriving as one move, drawn on, popped or wiped, with a glint across the name; names can be extruded in 3D.",
|
|
207
|
+
"tags": [
|
|
208
|
+
"logo",
|
|
209
|
+
"brand",
|
|
210
|
+
"lockup",
|
|
211
|
+
"end card",
|
|
212
|
+
"outro",
|
|
213
|
+
"wordmark",
|
|
214
|
+
"3d"
|
|
215
|
+
],
|
|
216
|
+
"example": "LogoReveal({ mark: \"assets/logo.svg\", name: \"framefields\", tagline: \"Motion in code\" })",
|
|
217
|
+
"registryDependencies": []
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"name": "lower-third",
|
|
221
|
+
"title": "LowerThird",
|
|
222
|
+
"summary": "The name-and-role bar of interviews and talks: measured plates in the safe area that slide in and leave on their own.",
|
|
223
|
+
"tags": [
|
|
224
|
+
"lower third",
|
|
225
|
+
"name",
|
|
226
|
+
"interview",
|
|
227
|
+
"talk",
|
|
228
|
+
"caption",
|
|
229
|
+
"broadcast"
|
|
230
|
+
],
|
|
231
|
+
"example": "LowerThird({ name: \"Ada Lovelace\", role: \"Engineer\" })",
|
|
232
|
+
"registryDependencies": []
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
"name": "meter",
|
|
236
|
+
"title": "Meter",
|
|
237
|
+
"summary": "Progress and scores as a ring, arc gauge, bar, lit segments or star rating, filling on the same timeline as its counter.",
|
|
238
|
+
"tags": [
|
|
239
|
+
"progress",
|
|
240
|
+
"gauge",
|
|
241
|
+
"score",
|
|
242
|
+
"rating",
|
|
243
|
+
"stat",
|
|
244
|
+
"data"
|
|
245
|
+
],
|
|
246
|
+
"example": "Meter({ value: 72, kind: \"ring\", label: \"Coverage\" })",
|
|
247
|
+
"registryDependencies": [
|
|
248
|
+
"counter"
|
|
249
|
+
]
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"name": "mouse-pointer",
|
|
253
|
+
"title": "MousePointer",
|
|
254
|
+
"summary": "An animated pointer that travels between targets, clicks, drags and changes shape, reporting every click as a cue.",
|
|
255
|
+
"tags": [
|
|
256
|
+
"pointer",
|
|
257
|
+
"cursor",
|
|
258
|
+
"demo",
|
|
259
|
+
"ui",
|
|
260
|
+
"interaction",
|
|
261
|
+
"screen recording"
|
|
262
|
+
],
|
|
263
|
+
"example": "MousePointer({ path: [{ to: [400, 300] }, { to: [900, 520], click: true }] })",
|
|
264
|
+
"registryDependencies": []
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"name": "selection",
|
|
268
|
+
"title": "Selection",
|
|
269
|
+
"summary": "A text selection or a marquee driven by a MousePointer drag: it follows the pointer glyph by glyph, and lights up covered items.",
|
|
270
|
+
"tags": [
|
|
271
|
+
"selection",
|
|
272
|
+
"highlight",
|
|
273
|
+
"marquee",
|
|
274
|
+
"drag",
|
|
275
|
+
"editor",
|
|
276
|
+
"ui",
|
|
277
|
+
"pointer"
|
|
278
|
+
],
|
|
279
|
+
"example": "Selection({ target: { text: paragraph, match: \"the key line\" }, pointer })",
|
|
280
|
+
"registryDependencies": []
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
"name": "spotlight",
|
|
284
|
+
"title": "Spotlight",
|
|
285
|
+
"summary": "Dims the frame except a region that glides between targets, as a crisp rounded rect or a soft pool of light.",
|
|
286
|
+
"tags": [
|
|
287
|
+
"spotlight",
|
|
288
|
+
"focus",
|
|
289
|
+
"dim",
|
|
290
|
+
"highlight",
|
|
291
|
+
"tutorial",
|
|
292
|
+
"ui"
|
|
293
|
+
],
|
|
294
|
+
"example": "Spotlight({ targets: [{ at: 0, target: button }, { at: 60, target: menu }] })",
|
|
295
|
+
"registryDependencies": []
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
"name": "terminal",
|
|
299
|
+
"title": "Terminal",
|
|
300
|
+
"summary": "A scripted shell session: commands typed with a human rhythm, streaming output, spinners that resolve to check marks, progress bars and scrolling, with a cue for every keystroke.",
|
|
301
|
+
"tags": [
|
|
302
|
+
"terminal",
|
|
303
|
+
"shell",
|
|
304
|
+
"cli",
|
|
305
|
+
"developer",
|
|
306
|
+
"demo",
|
|
307
|
+
"typing"
|
|
308
|
+
],
|
|
309
|
+
"example": "Terminal({ script: [{ cmd: \"pnpm add framefields\" }, { spinner: \"Installing\", for: 40, done: \"1 package added\" }] })",
|
|
310
|
+
"registryDependencies": [
|
|
311
|
+
"app-frame",
|
|
312
|
+
"counter"
|
|
313
|
+
]
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
"name": "text-reveal",
|
|
317
|
+
"title": "TextReveal",
|
|
318
|
+
"summary": "Headlines and body copy that animate in and out by character, word or line: rise, blur, track, mask, slam, scatter, scramble, type, stream, wipe and flip, each ending on exactly the static text.",
|
|
319
|
+
"tags": [
|
|
320
|
+
"text",
|
|
321
|
+
"typography",
|
|
322
|
+
"kinetic type",
|
|
323
|
+
"title",
|
|
324
|
+
"reveal",
|
|
325
|
+
"typewriter"
|
|
326
|
+
],
|
|
327
|
+
"example": "TextReveal({ text: \"Ship it faster\", style: \"rise\", emphasis: [\"faster\"] })",
|
|
328
|
+
"registryDependencies": []
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
"name": "title-card",
|
|
332
|
+
"title": "TitleCard",
|
|
333
|
+
"summary": "Kicker, headline, rule and sub-line in designed layouts (center, left, stack, split), the headline in any reveal style, on one timeline.",
|
|
334
|
+
"tags": [
|
|
335
|
+
"title",
|
|
336
|
+
"headline",
|
|
337
|
+
"typography",
|
|
338
|
+
"opener",
|
|
339
|
+
"chapter"
|
|
340
|
+
],
|
|
341
|
+
"example": "TitleCard({ kicker: \"Chapter one\", title: \"Ship it faster\", subtitle: \"What changed in 2.5\" })",
|
|
342
|
+
"registryDependencies": [
|
|
343
|
+
"text-reveal"
|
|
344
|
+
]
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
"name": "toasts",
|
|
348
|
+
"title": "Toasts",
|
|
349
|
+
"summary": "Notifications arriving into a corner stack that pushes older ones away and compresses as it grows; each slides out when dismissed.",
|
|
350
|
+
"tags": [
|
|
351
|
+
"toast",
|
|
352
|
+
"notification",
|
|
353
|
+
"alert",
|
|
354
|
+
"ui",
|
|
355
|
+
"stack",
|
|
356
|
+
"demo"
|
|
357
|
+
],
|
|
358
|
+
"example": "Toasts({ items: [{ at: 0, title: \"Deployed\", kind: \"success\" }, { at: 40, title: \"3 new comments\" }] })",
|
|
359
|
+
"registryDependencies": []
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
"name": "touch-point",
|
|
363
|
+
"title": "TouchPoint",
|
|
364
|
+
"summary": "Fingers on glass: taps, double taps, long presses and swipes as soft discs with ripples, for mobile demos in a DeviceFrame.",
|
|
365
|
+
"tags": [
|
|
366
|
+
"touch",
|
|
367
|
+
"tap",
|
|
368
|
+
"swipe",
|
|
369
|
+
"mobile",
|
|
370
|
+
"gesture",
|
|
371
|
+
"demo",
|
|
372
|
+
"phone"
|
|
373
|
+
],
|
|
374
|
+
"example": "TouchPoint({ touches: [{ to: phone.at(196, 700) }, { to: phone.at(196, 600), swipe: phone.at(196, 200) }] })",
|
|
375
|
+
"registryDependencies": []
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
"name": "waveform",
|
|
379
|
+
"title": "Waveform",
|
|
380
|
+
"summary": "An audiogram: bars, mirrored bars, dots or a ring that move with a track's spectrum, analysed offline and bound as signals.",
|
|
381
|
+
"tags": [
|
|
382
|
+
"audio",
|
|
383
|
+
"waveform",
|
|
384
|
+
"audiogram",
|
|
385
|
+
"spectrum",
|
|
386
|
+
"podcast",
|
|
387
|
+
"music",
|
|
388
|
+
"visualizer"
|
|
389
|
+
],
|
|
390
|
+
"example": "Waveform({ audio: await analyzeAudio(\"voice.wav\", { fps: 30 }), kind: \"mirror\" })",
|
|
391
|
+
"registryDependencies": []
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
"name": "word-cycle",
|
|
395
|
+
"title": "WordCycle",
|
|
396
|
+
"summary": "One slot in a line cycles through words: rolled, faded, slid or retyped, while the slot resizes to each word and the line glides to fit.",
|
|
397
|
+
"tags": [
|
|
398
|
+
"text",
|
|
399
|
+
"headline",
|
|
400
|
+
"rotating word",
|
|
401
|
+
"kinetic type",
|
|
402
|
+
"launch",
|
|
403
|
+
"typography"
|
|
404
|
+
],
|
|
405
|
+
"example": "WordCycle({ text: \"Make videos {}\", words: [\"faster\", \"together\", \"in code\"] })",
|
|
406
|
+
"registryDependencies": []
|
|
407
|
+
}
|
|
408
|
+
]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "logo-reveal",
|
|
3
|
+
"title": "LogoReveal",
|
|
4
|
+
"summary": "The end-card lockup: a mark and a wordmark arriving as one move, drawn on, popped or wiped, with a glint across the name; names can be extruded in 3D.",
|
|
5
|
+
"tags": [
|
|
6
|
+
"logo",
|
|
7
|
+
"brand",
|
|
8
|
+
"lockup",
|
|
9
|
+
"end card",
|
|
10
|
+
"outro",
|
|
11
|
+
"wordmark",
|
|
12
|
+
"3d"
|
|
13
|
+
],
|
|
14
|
+
"example": "LogoReveal({ mark: \"assets/logo.svg\", name: \"framefields\", tagline: \"Motion in code\" })",
|
|
15
|
+
"parts": [
|
|
16
|
+
"mark",
|
|
17
|
+
"mark-clip",
|
|
18
|
+
"mark-image",
|
|
19
|
+
"mark-fill",
|
|
20
|
+
"mark-outline",
|
|
21
|
+
"name",
|
|
22
|
+
"name-clip",
|
|
23
|
+
"tagline"
|
|
24
|
+
],
|
|
25
|
+
"cues": [
|
|
26
|
+
"hit",
|
|
27
|
+
"revealed",
|
|
28
|
+
"glint"
|
|
29
|
+
],
|
|
30
|
+
"registryDependencies": [],
|
|
31
|
+
"files": [
|
|
32
|
+
{
|
|
33
|
+
"path": "logo-reveal/index.ts",
|
|
34
|
+
"content": "/**\n * LogoReveal: the end-card lockup. A mark (image, SVG or path data) and a\n * wordmark arrive as one move, then a light sweeps across the name. Path\n * marks can draw themselves on; names can be extruded in 3D.\n */\nimport {\n\ttype KeyframeTuple,\n\tLayerAnimation,\n\ttype LayoutNode,\n} from \"framefields\";\nimport {\n\ttype Animatable,\n\tbindComponent,\n\tdefineComponent,\n\tdrawOnKeys,\n\tglyphAnimator,\n\trendererChars,\n\tscheduleExpression,\n\tspringKeys,\n\tthemeFrames,\n\ttransformPathData,\n\tz,\n} from \"framefields/components\";\n\nexport const LOGO_STYLES = [\"slide\", \"pop\", \"draw\", \"rise\"] as const;\nexport type LogoStyle = (typeof LOGO_STYLES)[number];\nexport const LOGO_LAYOUTS = [\"row\", \"stack\"] as const;\nexport type LogoLayout = (typeof LOGO_LAYOUTS)[number];\n\nexport interface LogoRevealCues {\n\t[name: string]: ReadonlyArray<{ frame: number }>;\n\t/** The mark lands. */\n\thit: ReadonlyArray<{ frame: number }>;\n\t/** The lockup is complete. */\n\trevealed: ReadonlyArray<{ frame: number }>;\n\t/** The glint starts (empty without `glint`). */\n\tglint: ReadonlyArray<{ frame: number }>;\n}\n\nconst POP = { stiffness: 260, damping: 14 };\nconst SWING = { stiffness: 120, damping: 14 };\n\nexport const logoReveal = /* @__PURE__ */ defineComponent({\n\tname: \"LogoReveal\",\n\tprops: () => ({\n\t\t/** An image / SVG file, or path data in its own viewBox. */\n\t\tmark: z\n\t\t\t.union([\n\t\t\t\tz.string().min(1),\n\t\t\t\tz\n\t\t\t\t\t.object({\n\t\t\t\t\t\td: z.string().min(1),\n\t\t\t\t\t\tviewBox: z.tuple([z.number().positive(), z.number().positive()]),\n\t\t\t\t\t\tcolor: z.string().optional(),\n\t\t\t\t\t})\n\t\t\t\t\t.strict(),\n\t\t\t])\n\t\t\t.optional(),\n\t\tname: z.string().min(1).optional(),\n\t\ttagline: z.string().min(1).optional(),\n\t\tlayout: z.enum(LOGO_LAYOUTS).default(\"row\"),\n\t\tstyle: z.enum(LOGO_STYLES).default(\"slide\"),\n\t\tglint: z.boolean().default(true),\n\t\t/** Above 0, the name is extruded text this deep (px). */\n\t\tdepth: z.number().min(0).default(0),\n\t\tmaterial: z.enum([\"lit\", \"chrome\", \"glass\"]).default(\"lit\"),\n\t\tmarkSize: z.number().positive().optional(),\n\t\tnameSize: z.number().positive().optional(),\n\t\tgap: z.number().min(0).optional(),\n\t\tcolor: z.string().optional(),\n\t\taccent: z.string().optional(),\n\t\tfontFamily: z.string().optional(),\n\t\tfontWeight: z.number().int().min(100).max(900).default(800),\n\t}),\n\tdefaults: { enter: false, exit: false, hold: 60 },\n\tbuild(ctx, props) {\n\t\tconst { host, theme, fps } = ctx;\n\t\tif (!props.mark && !props.name)\n\t\t\tthrow new Error(\"LogoReveal: give a `mark`, a `name`, or both.\");\n\t\tconst s = theme.scale;\n\t\tconst base = themeFrames(theme, \"base\", fps);\n\t\tconst ease = theme.motion.ease.move;\n\t\tconst accent = props.accent ?? theme.color.accent;\n\t\tconst ink = props.color ?? theme.color.ink;\n\t\tconst fontFamily = props.fontFamily ?? theme.font.display;\n\t\tconst ns = props.nameSize ?? 120 * s;\n\t\tconst m = props.mark ? (props.markSize ?? 150 * s) : 0;\n\t\tconst gap = props.mark && props.name ? (props.gap ?? ns * 0.32) : 0;\n\t\tconst stack = props.layout === \"stack\";\n\t\tconst solid = props.depth > 0;\n\t\tconst pathMark = typeof props.mark === \"object\" ? props.mark : null;\n\t\t// Image marks can't draw on: they pop.\n\t\tconst style: LogoStyle =\n\t\t\tprops.style === \"draw\" && !pathMark ? \"pop\" : props.style;\n\n\t\t// ── Geometry ─────────────────────────────────────────────────────\n\t\tconst nameM = props.name\n\t\t\t? host.measure(props.name, {\n\t\t\t\t\tfontFamily,\n\t\t\t\t\tfontSize: ns,\n\t\t\t\t\tfontWeight: props.fontWeight,\n\t\t\t\t})\n\t\t\t: { width: 0, height: 0 };\n\t\tconst tagSize = Math.max(18 * s, ns * 0.26);\n\t\tconst tagM = props.tagline\n\t\t\t? host.measure(props.tagline, {\n\t\t\t\t\tfontFamily: theme.font.body,\n\t\t\t\t\tfontSize: tagSize,\n\t\t\t\t})\n\t\t\t: { width: 0, height: 0 };\n\t\tconst tagGap = props.tagline ? ns * 0.12 : 0;\n\t\tconst textW = Math.max(nameM.width, tagM.width);\n\t\tconst textH = nameM.height + tagGap + tagM.height;\n\t\tconst W = stack ? Math.max(m, textW) : m + gap + textW;\n\t\tconst H = stack ? m + gap + textH : Math.max(m, textH);\n\t\tconst markAt = stack ? { x: (W - m) / 2, y: 0 } : { x: 0, y: (H - m) / 2 };\n\t\tconst nameAt = stack\n\t\t\t? { x: (W - nameM.width) / 2, y: m + gap }\n\t\t\t: { x: m + gap, y: (H - textH) / 2 };\n\t\tconst tagAt = stack\n\t\t\t? { x: (W - tagM.width) / 2, y: nameAt.y + nameM.height + tagGap }\n\t\t\t: { x: nameAt.x, y: nameAt.y + nameM.height + tagGap };\n\n\t\t// ── Timeline ─────────────────────────────────────────────────────\n\t\tconst drawFrames = Math.round(base * 2.2);\n\t\tconst glide = Math.round(base * 1.5);\n\t\tconst glideAt = style === \"slide\" ? Math.round(base * 1.1) : 0;\n\t\tconst hit = !props.mark\n\t\t\t? 0\n\t\t\t: style === \"draw\"\n\t\t\t\t? drawFrames\n\t\t\t\t: style === \"rise\"\n\t\t\t\t\t? base\n\t\t\t\t\t: Math.round(base * 0.75);\n\t\tconst nameStart = !props.mark\n\t\t\t? 0\n\t\t\t: style === \"slide\"\n\t\t\t\t? glideAt\n\t\t\t\t: style === \"draw\"\n\t\t\t\t\t? Math.round(drawFrames * 0.6)\n\t\t\t\t\t: style === \"rise\"\n\t\t\t\t\t\t? Math.round(base * 0.35)\n\t\t\t\t\t\t: Math.round(base * 0.55);\n\t\tconst chars = props.name?.length ?? 0;\n\t\tconst stagger = Math.max(1, Math.round(fps / 30) * 1.5);\n\t\tconst letters = style === \"pop\" || style === \"draw\";\n\t\tconst nameDone = !props.name\n\t\t\t? hit\n\t\t\t: solid\n\t\t\t\t? nameStart + base * 2\n\t\t\t\t: style === \"slide\"\n\t\t\t\t\t? glideAt + glide\n\t\t\t\t\t: letters\n\t\t\t\t\t\t? nameStart + Math.round(stagger * Math.max(0, chars - 1)) + base\n\t\t\t\t\t\t: nameStart + base;\n\t\tconst tagStart = Math.max(nameStart, nameDone - Math.round(base * 0.4));\n\t\tconst revealed = Math.max(\n\t\t\thit,\n\t\t\tnameDone,\n\t\t\tprops.tagline ? tagStart + base : 0,\n\t\t);\n\t\tconst glintAt = revealed + Math.round(base * 0.3);\n\t\tconst glintFrames = Math.round(base * 1.8);\n\t\tconst glints = props.glint && props.name && !solid;\n\t\tconst end = glints ? glintAt + glintFrames : revealed;\n\n\t\tconst parts: Record<string, Animatable<LayoutNode>> = {};\n\t\tconst children: LayoutNode[] = [];\n\t\t// Drawn last: the name wipes out from behind it.\n\t\tlet markNode: LayoutNode | undefined;\n\n\t\t// ── Mark ─────────────────────────────────────────────────────────\n\t\tif (props.mark) {\n\t\t\tconst markColor = pathMark?.color ?? accent;\n\t\t\tconst markKids: LayoutNode[] = [];\n\t\t\tif (pathMark) {\n\t\t\t\tconst [vw, vh] = pathMark.viewBox;\n\t\t\t\tconst k = m / Math.max(vw, vh);\n\t\t\t\tconst d = transformPathData(\n\t\t\t\t\tpathMark.d,\n\t\t\t\t\tk,\n\t\t\t\t\t(m - vw * k) / 2,\n\t\t\t\t\t(m - vh * k) / 2,\n\t\t\t\t);\n\t\t\t\tconst fill = host.shape(\"path\", {\n\t\t\t\t\tid: ctx.partId(\"mark-fill\"),\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\tx: 0,\n\t\t\t\t\ty: 0,\n\t\t\t\t\twidth: m,\n\t\t\t\t\theight: m,\n\t\t\t\t\td,\n\t\t\t\t\tfillType: \"solid\",\n\t\t\t\t\tfillColor: markColor,\n\t\t\t\t});\n\t\t\t\tparts[\"mark-fill\"] = fill;\n\t\t\t\tif (style === \"draw\") {\n\t\t\t\t\tconst outline = host.shape(\"path\", {\n\t\t\t\t\t\tid: ctx.partId(\"mark-outline\"),\n\t\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t\tx: 0,\n\t\t\t\t\t\ty: 0,\n\t\t\t\t\t\twidth: m,\n\t\t\t\t\t\theight: m,\n\t\t\t\t\t\td,\n\t\t\t\t\t\tfillType: \"none\",\n\t\t\t\t\t\tstrokeColor: markColor,\n\t\t\t\t\t\tstrokeWidth: Math.max(2, 3 * s),\n\t\t\t\t\t\tstrokeLineCap: \"round\",\n\t\t\t\t\t\tstrokeLineJoin: \"round\",\n\t\t\t\t\t});\n\t\t\t\t\toutline.animate(\n\t\t\t\t\t\tLayerAnimation.create()\n\t\t\t\t\t\t\t.keys(\"trimEnd\", drawOnKeys(0, drawFrames, \"power2.inOut\"))\n\t\t\t\t\t\t\t.keys(\"opacity\", [\n\t\t\t\t\t\t\t\t[drawFrames, 1],\n\t\t\t\t\t\t\t\t[drawFrames + base, 0, \"power2.out\"],\n\t\t\t\t\t\t\t]),\n\t\t\t\t\t);\n\t\t\t\t\tfill.animate(\n\t\t\t\t\t\tLayerAnimation.keys(\"opacity\", [\n\t\t\t\t\t\t\t[Math.round(drawFrames * 0.7), 0],\n\t\t\t\t\t\t\t[drawFrames, 1, \"power2.out\"],\n\t\t\t\t\t\t]),\n\t\t\t\t\t);\n\t\t\t\t\tmarkKids.push(fill, outline);\n\t\t\t\t\tparts[\"mark-outline\"] = outline;\n\t\t\t\t} else markKids.push(fill);\n\t\t\t} else {\n\t\t\t\tconst image = host.media(props.mark as string, {\n\t\t\t\t\tid: ctx.partId(\"mark-image\"),\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\tx: 0,\n\t\t\t\t\ty: 0,\n\t\t\t\t\twidth: m,\n\t\t\t\t\theight: m,\n\t\t\t\t\tfit: \"contain\",\n\t\t\t\t});\n\t\t\t\tmarkKids.push(image);\n\t\t\t\tparts[\"mark-image\"] = image;\n\t\t\t}\n\t\t\tconst centred = stack\n\t\t\t\t? { x: markAt.x, y: (H - m) / 2 }\n\t\t\t\t: { x: (W - m) / 2, y: markAt.y };\n\t\t\tconst slide = style === \"slide\" && !!props.name;\n\t\t\tconst mark = host.box({\n\t\t\t\tid: ctx.partId(\"mark\"),\n\t\t\t\tposition: \"absolute\",\n\t\t\t\tx: slide ? centred.x : markAt.x,\n\t\t\t\ty: slide ? centred.y : markAt.y,\n\t\t\t\twidth: m,\n\t\t\t\theight: m,\n\t\t\t\tchildren: markKids,\n\t\t\t});\n\t\t\tconst anim = LayerAnimation.create();\n\t\t\tconst scale: KeyframeTuple[] = [];\n\t\t\tif (style === \"slide\" || style === \"pop\")\n\t\t\t\tscale.push(...(springKeys(0, 0, 1, fps, POP) as KeyframeTuple[]));\n\t\t\tif (glints) {\n\t\t\t\t// A small bump as the light passes.\n\t\t\t\tif (scale.length === 0) scale.push([0, 1]);\n\t\t\t\tscale.push(\n\t\t\t\t\t[glintAt, 1],\n\t\t\t\t\t[glintAt + Math.round(base * 0.4), 1.06, \"power2.out\"],\n\t\t\t\t\t[glintAt + Math.round(base * 1.2), 1, \"power2.inOut\"],\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (scale.length > 0) anim.keys(\"scale\", scale);\n\t\t\tif (slide) {\n\t\t\t\tanim.keys(stack ? \"y\" : \"x\", [\n\t\t\t\t\t[glideAt, stack ? centred.y : centred.x],\n\t\t\t\t\t[glideAt + glide, stack ? markAt.y : markAt.x, ease],\n\t\t\t\t]);\n\t\t\t}\n\t\t\tif (style === \"rise\") {\n\t\t\t\tanim.keys(\"opacity\", [\n\t\t\t\t\t[0, 0],\n\t\t\t\t\t[Math.round(base * 0.6), 1, \"power2.out\"],\n\t\t\t\t]);\n\t\t\t}\n\t\t\tmark.animate(anim);\n\t\t\tparts.mark = mark;\n\t\t\tif (style === \"rise\") {\n\t\t\t\t// Rises through its own clip.\n\t\t\t\tmark.y = m;\n\t\t\t\tmark.x = 0;\n\t\t\t\tmark.animate(\n\t\t\t\t\tLayerAnimation.keys(\"y\", [\n\t\t\t\t\t\t[0, m],\n\t\t\t\t\t\t[base, 0, theme.motion.ease.enter],\n\t\t\t\t\t]),\n\t\t\t\t);\n\t\t\t\tconst clip = host.box({\n\t\t\t\t\tid: ctx.partId(\"mark-clip\"),\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\tx: markAt.x,\n\t\t\t\t\ty: markAt.y,\n\t\t\t\t\twidth: m,\n\t\t\t\t\theight: m,\n\t\t\t\t\toverflow: \"hidden\",\n\t\t\t\t\tchildren: [mark],\n\t\t\t\t});\n\t\t\t\tparts[\"mark-clip\"] = clip;\n\t\t\t\tmarkNode = clip;\n\t\t\t} else markNode = mark;\n\t\t}\n\n\t\t// ── Name ─────────────────────────────────────────────────────────\n\t\tif (props.name) {\n\t\t\tif (solid) {\n\t\t\t\tconst chrome = props.material === \"chrome\";\n\t\t\t\tconst name = host.extrudedText({\n\t\t\t\t\tid: ctx.partId(\"name\"),\n\t\t\t\t\ttext: props.name,\n\t\t\t\t\tx: nameAt.x + nameM.width / 2,\n\t\t\t\t\ty: nameAt.y + nameM.height / 2,\n\t\t\t\t\tdepth: props.depth,\n\t\t\t\t\tfontFamily,\n\t\t\t\t\tfontSize: ns,\n\t\t\t\t\tfontWeight: props.fontWeight,\n\t\t\t\t\tfill: chrome ? \"#e8ecf2\" : ink,\n\t\t\t\t\tbevelColor: chrome ? \"#9aa3ad\" : accent,\n\t\t\t\t\tmaterial: props.material === \"glass\" ? \"glass\" : \"lit\",\n\t\t\t\t\t...(chrome && { metallic: 1, roughness: 0.18, shininess: 96 }),\n\t\t\t\t});\n\t\t\t\tname.animate(\n\t\t\t\t\tLayerAnimation.create()\n\t\t\t\t\t\t.keys(\n\t\t\t\t\t\t\t\"rotateY\",\n\t\t\t\t\t\t\tspringKeys(nameStart, -70, 0, fps, SWING) as KeyframeTuple[],\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.keys(\"opacity\", [\n\t\t\t\t\t\t\t[nameStart, 0],\n\t\t\t\t\t\t\t[nameStart + Math.round(base * 0.5), 1, \"power2.out\"],\n\t\t\t\t\t\t]),\n\t\t\t\t);\n\t\t\t\tparts.name = name;\n\t\t\t\tchildren.push(name);\n\t\t\t} else {\n\t\t\t\tconst animators =\n\t\t\t\t\tletters || glints\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t...(letters\n\t\t\t\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\t\t\tglyphAnimator(\n\t\t\t\t\t\t\t\t\t\t\t\t\"rise\",\n\t\t\t\t\t\t\t\t\t\t\t\tscheduleExpression(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"char\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tstarts: rendererChars(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprops.name,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tArray.from({ length: chars }, (_, i) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tMath.round(i * stagger),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tduration: base,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tease: theme.motion.ease.enter,\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"enter\",\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t{ y: ns * 0.35, opacity: 0 },\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t: []),\n\t\t\t\t\t\t\t\t...(glints\n\t\t\t\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\t\t\tglyphAnimator(\n\t\t\t\t\t\t\t\t\t\t\t\t\"glint\",\n\t\t\t\t\t\t\t\t\t\t\t\tglintExpression(\n\t\t\t\t\t\t\t\t\t\t\t\t\tprops.name,\n\t\t\t\t\t\t\t\t\t\t\t\t\tglintAt - nameStart,\n\t\t\t\t\t\t\t\t\t\t\t\t\tglintFrames,\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t{ fillColor: \"#ffffff\" },\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t: []),\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: undefined;\n\t\t\t\tconst wipe = style === \"slide\" && !!props.mark;\n\t\t\t\tconst text = host.text(props.name, {\n\t\t\t\t\tid: ctx.partId(\"name\"),\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\tx: wipe ? (stack ? 0 : -nameM.width - gap) : 0,\n\t\t\t\t\ty: wipe && stack ? -nameM.height : 0,\n\t\t\t\t\tfontFamily,\n\t\t\t\t\tfontSize: ns,\n\t\t\t\t\tfontWeight: props.fontWeight,\n\t\t\t\t\tfill: ink,\n\t\t\t\t\t...(animators && { animators: animators as never }),\n\t\t\t\t\tstartFrame: nameStart,\n\t\t\t\t});\n\t\t\t\tif (wipe)\n\t\t\t\t\ttext.animate(\n\t\t\t\t\t\tLayerAnimation.keys(stack ? \"y\" : \"x\", [\n\t\t\t\t\t\t\t[0, stack ? -nameM.height : -nameM.width - gap],\n\t\t\t\t\t\t\t[glide, 0, ease],\n\t\t\t\t\t\t]),\n\t\t\t\t\t);\n\t\t\t\telse if (style === \"rise\" || (!props.mark && style === \"slide\"))\n\t\t\t\t\ttext.animate(\n\t\t\t\t\t\tLayerAnimation.keys(\"y\", [\n\t\t\t\t\t\t\t[0, nameM.height],\n\t\t\t\t\t\t\t[base, 0, theme.motion.ease.enter],\n\t\t\t\t\t\t]),\n\t\t\t\t\t);\n\t\t\t\t// The name sits in a clip: it wipes out from behind the mark or rises.\n\t\t\t\tconst clip = host.box({\n\t\t\t\t\tid: ctx.partId(\"name-clip\"),\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\tx: nameAt.x,\n\t\t\t\t\ty: nameAt.y,\n\t\t\t\t\twidth: nameM.width,\n\t\t\t\t\theight: nameM.height,\n\t\t\t\t\t...(!letters && { overflow: \"hidden\" as const }),\n\t\t\t\t\tchildren: [text],\n\t\t\t\t});\n\t\t\t\tparts.name = text;\n\t\t\t\tparts[\"name-clip\"] = clip;\n\t\t\t\tchildren.push(clip);\n\t\t\t}\n\t\t}\n\n\t\t// ── Tagline ──────────────────────────────────────────────────────\n\t\tif (props.tagline) {\n\t\t\tconst tag = host.text(props.tagline, {\n\t\t\t\tid: ctx.partId(\"tagline\"),\n\t\t\t\tposition: \"absolute\",\n\t\t\t\tx: tagAt.x,\n\t\t\t\ty: tagAt.y,\n\t\t\t\tfontFamily: theme.font.body,\n\t\t\t\tfontSize: tagSize,\n\t\t\t\tfill: theme.color.muted,\n\t\t\t});\n\t\t\ttag.animate(\n\t\t\t\tLayerAnimation.create()\n\t\t\t\t\t.keys(\"opacity\", [\n\t\t\t\t\t\t[tagStart, 0],\n\t\t\t\t\t\t[tagStart + base, 1, \"power2.out\"],\n\t\t\t\t\t])\n\t\t\t\t\t.keys(\"y\", [\n\t\t\t\t\t\t[tagStart, tagAt.y + 12 * s],\n\t\t\t\t\t\t[tagStart + base, tagAt.y, theme.motion.ease.enter],\n\t\t\t\t\t]),\n\t\t\t);\n\t\t\tparts.tagline = tag;\n\t\t\tchildren.push(tag);\n\t\t}\n\t\tif (markNode) children.push(markNode);\n\n\t\treturn {\n\t\t\tchildren,\n\t\t\twidth: W,\n\t\t\theight: H,\n\t\t\tduration: end,\n\t\t\topenEnded: true,\n\t\t\tcues: {\n\t\t\t\thit: props.mark ? [{ frame: hit }] : [],\n\t\t\t\trevealed: [{ frame: revealed }],\n\t\t\t\tglint: glints ? [{ frame: glintAt }] : [],\n\t\t\t} as LogoRevealCues,\n\t\t\tparts,\n\t\t};\n\t},\n});\n\n/**\n * A soft band of light crossing the name left to right: each character\n * peaks as the band passes its position (frame is the name's local frame).\n */\nfunction glintExpression(text: string, start: number, frames: number): string {\n\tconst n = Math.max(1, text.length - 1);\n\tconst peaks = rendererChars(\n\t\ttext,\n\t\tArray.from(\n\t\t\t{ length: text.length },\n\t\t\t(_, i) => Math.round((start + (i / n) * frames * 0.7) * 100) / 100,\n\t\t),\n\t);\n\tconst width = Math.max(2, frames * 0.18);\n\treturn `((P)=>{const d=abs(frame-(P[textIndex]??-999));return d<${width}?(1-d/${width})*0.85:0;})([${peaks.join(\",\")}])`;\n}\n\n/**\n * The end-card lockup: a mark and a wordmark arriving as one move, drawn on,\n * popped or wiped, with a glint across the name; names can be extruded in 3D.\n */\nexport const LogoReveal = /* @__PURE__ */ bindComponent(logoReveal);\n"
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "lower-third",
|
|
3
|
+
"title": "LowerThird",
|
|
4
|
+
"summary": "The name-and-role bar of interviews and talks: measured plates in the safe area that slide in and leave on their own.",
|
|
5
|
+
"tags": [
|
|
6
|
+
"lower third",
|
|
7
|
+
"name",
|
|
8
|
+
"interview",
|
|
9
|
+
"talk",
|
|
10
|
+
"caption",
|
|
11
|
+
"broadcast"
|
|
12
|
+
],
|
|
13
|
+
"example": "LowerThird({ name: \"Ada Lovelace\", role: \"Engineer\" })",
|
|
14
|
+
"parts": [
|
|
15
|
+
"plate",
|
|
16
|
+
"edge",
|
|
17
|
+
"name-plate",
|
|
18
|
+
"role-plate",
|
|
19
|
+
"tag",
|
|
20
|
+
"line",
|
|
21
|
+
"text"
|
|
22
|
+
],
|
|
23
|
+
"cues": [
|
|
24
|
+
"in",
|
|
25
|
+
"out"
|
|
26
|
+
],
|
|
27
|
+
"registryDependencies": [],
|
|
28
|
+
"files": [
|
|
29
|
+
{
|
|
30
|
+
"path": "lower-third/index.ts",
|
|
31
|
+
"content": "/**\n * LowerThird: the name-and-role bar of interviews and talks. Plates are\n * measured to their text, placed in the safe area's bottom corner, slide in\n * through their own box, and leave on their own after `hold`.\n *\n * Coordinates are the frame's: the root covers the video (default\n * 1920 × 1080 × theme scale, or the given width / height) from 0, 0.\n */\nimport {\n\ttype KeyframeTuple,\n\tLayerAnimation,\n\ttype LayoutNode,\n} from \"framefields\";\nimport {\n\ttype Animatable,\n\tbindComponent,\n\tdefineComponent,\n\ttype Rect,\n\tthemeFrames,\n\tz,\n} from \"framefields/components\";\n\nexport const LOWER_THIRD_LAYOUTS = [\"bar\", \"stacked\", \"tag\", \"line\"] as const;\nexport type LowerThirdLayout = (typeof LOWER_THIRD_LAYOUTS)[number];\n\nexport interface LowerThirdCues {\n\t[name: string]: ReadonlyArray<{ frame: number }>;\n\t/** Fully on screen. */\n\tin: ReadonlyArray<{ frame: number }>;\n\t/** Starts to leave (empty with `stay`). */\n\tout: ReadonlyArray<{ frame: number }>;\n}\n\nfunction safeArea(\n\tW: number,\n\tH: number,\n\tarea: \"portrait\" | \"landscape\" | Rect | undefined,\n): Rect {\n\tif (area && typeof area === \"object\") return area;\n\tconst portrait = area ? area === \"portrait\" : H > W;\n\treturn portrait\n\t\t? { x: W * 0.08, y: H * 0.1, width: W * 0.84, height: H * 0.66 }\n\t\t: { x: W * 0.06, y: H * 0.08, width: W * 0.88, height: H * 0.82 };\n}\n\nexport const lowerThird = /* @__PURE__ */ defineComponent({\n\tname: \"LowerThird\",\n\tprops: () => ({\n\t\tname: z.string().min(1),\n\t\trole: z.string().optional(),\n\t\tlayout: z.enum(LOWER_THIRD_LAYOUTS).default(\"bar\"),\n\t\tside: z.enum([\"left\", \"right\"]).default(\"left\"),\n\t\tsafeArea: z\n\t\t\t.union([\n\t\t\t\tz.enum([\"portrait\", \"landscape\"]),\n\t\t\t\tz.object({\n\t\t\t\t\tx: z.number(),\n\t\t\t\t\ty: z.number(),\n\t\t\t\t\twidth: z.number(),\n\t\t\t\t\theight: z.number(),\n\t\t\t\t}),\n\t\t\t])\n\t\t\t.optional(),\n\t\t/** Stay on screen instead of leaving after `hold`. */\n\t\tstay: z.boolean().default(false),\n\t\taccent: z.string().optional(),\n\t\tplate: z.string().optional(),\n\t\tnameSize: z.number().positive().optional(),\n\t\tfontFamily: z.string().optional(),\n\t}),\n\tdefaults: { enter: false, exit: false, hold: 90 },\n\tbuild(ctx, props) {\n\t\tconst { host, theme, fps } = ctx;\n\t\tconst s = theme.scale;\n\t\tconst W = ctx.requested.width ?? 1920 * s;\n\t\tconst H = ctx.requested.height ?? 1080 * s;\n\t\tconst safe = safeArea(W, H, props.safeArea);\n\t\tconst fontFamily = props.fontFamily ?? theme.font.display;\n\t\tconst nameSize = props.nameSize ?? 44 * s;\n\t\tconst roleSize = nameSize * 0.62;\n\t\tconst accent = props.accent ?? theme.color.accent;\n\t\tconst plateColor = props.plate ?? theme.color.surface;\n\t\tconst right = props.side === \"right\";\n\t\tconst base = themeFrames(theme, \"base\", fps);\n\t\tconst fast = themeFrames(theme, \"fast\", fps);\n\t\tconst enter = theme.motion.ease.enter;\n\n\t\tconst nameM = host.measure(props.name, {\n\t\t\tfontFamily,\n\t\t\tfontSize: nameSize,\n\t\t\tfontWeight: 700,\n\t\t});\n\t\tconst roleM = props.role\n\t\t\t? host.measure(props.role, {\n\t\t\t\t\tfontFamily,\n\t\t\t\t\tfontSize: roleSize,\n\t\t\t\t\tfontWeight: 500,\n\t\t\t\t})\n\t\t\t: null;\n\t\tconst padX = nameSize * 0.55;\n\t\tconst padY = nameSize * 0.36;\n\t\tconst children: LayoutNode[] = [];\n\t\tconst parts: Record<string, Animatable<LayoutNode>> = {};\n\t\t/** Keys per node and prop, merged into one track each at the end. */\n\t\tconst tracks = new Map<\n\t\t\tAnimatable<LayoutNode>,\n\t\t\tMap<string, KeyframeTuple[]>\n\t\t>();\n\t\tconst key = (\n\t\t\tnode: Animatable<LayoutNode>,\n\t\t\tprop: string,\n\t\t\tkeys: KeyframeTuple[],\n\t\t) => {\n\t\t\tconst byProp = tracks.get(node) ?? new Map<string, KeyframeTuple[]>();\n\t\t\ttracks.set(node, byProp);\n\t\t\tbyProp.set(prop, [...(byProp.get(prop) ?? []), ...keys]);\n\t\t};\n\n\t\tconst text = (\n\t\t\tid: string,\n\t\t\tcontent: string,\n\t\t\tsize: number,\n\t\t\tweight: number,\n\t\t\tfill: string,\n\t\t\tx: number,\n\t\t\ty: number,\n\t\t) =>\n\t\t\thost.text(content, {\n\t\t\t\tid: ctx.partId(id),\n\t\t\t\tposition: \"absolute\",\n\t\t\t\tx,\n\t\t\t\ty,\n\t\t\t\tfontFamily,\n\t\t\t\tfontSize: size,\n\t\t\t\tfontWeight: weight,\n\t\t\t\tfill,\n\t\t\t});\n\n\t\t/**\n\t\t * A plate that slides in through its own box: the background travels\n\t\t * in from the side, its text rises a beat later. Returns the timing.\n\t\t */\n\t\tconst plate = (\n\t\t\tid: string,\n\t\t\trect: Rect,\n\t\t\tbackground: string,\n\t\t\tradius: number,\n\t\t\tcontent: Array<Animatable<LayoutNode>>,\n\t\t\tat: number,\n\t\t) => {\n\t\t\tconst fill = host.box({\n\t\t\t\tid: ctx.partId(`${id}-fill`),\n\t\t\t\tposition: \"absolute\",\n\t\t\t\tx: 0,\n\t\t\t\ty: 0,\n\t\t\t\twidth: rect.width,\n\t\t\t\theight: rect.height,\n\t\t\t\tbackground,\n\t\t\t\tborderRadius: radius,\n\t\t\t});\n\t\t\tconst travel = rect.width * (right ? 1 : -1);\n\t\t\tconst slide = Math.round(base * 1.1);\n\t\t\tkey(fill, \"x\", [\n\t\t\t\t[at, travel],\n\t\t\t\t[at + slide, 0, enter],\n\t\t\t]);\n\t\t\tconst textAt = at + Math.round(fast * 0.7);\n\t\t\tfor (const node of content) {\n\t\t\t\tconst y0 = (node as unknown as { y: number }).y;\n\t\t\t\tkey(node, \"y\", [\n\t\t\t\t\t[textAt, y0 + rect.height * 0.5],\n\t\t\t\t\t[textAt + base, y0, enter],\n\t\t\t\t]);\n\t\t\t\tkey(node, \"opacity\", [\n\t\t\t\t\t[textAt, 0],\n\t\t\t\t\t[textAt + Math.round(base * 0.6), 1, \"power2.out\"],\n\t\t\t\t]);\n\t\t\t}\n\t\t\tconst clip = host.box({\n\t\t\t\tid: ctx.partId(id),\n\t\t\t\tposition: \"absolute\",\n\t\t\t\t...rect,\n\t\t\t\toverflow: \"hidden\",\n\t\t\t\tborderRadius: radius,\n\t\t\t\tchildren: [fill, ...content],\n\t\t\t});\n\t\t\tchildren.push(clip);\n\t\t\tparts[id] = clip;\n\t\t\treturn {\n\t\t\t\tclip,\n\t\t\t\tfill,\n\t\t\t\tcontent,\n\t\t\t\ttravel,\n\t\t\t\tsettled: Math.max(at + slide, textAt + base),\n\t\t\t};\n\t\t};\n\n\t\t// ── Layouts ───────────────────────────────────────────────────────\n\t\tconst bottom = safe.y + safe.height;\n\t\tconst xFor = (width: number) =>\n\t\t\tright ? safe.x + safe.width - width : safe.x;\n\t\tconst plates: Array<ReturnType<typeof plate>> = [];\n\t\tlet accentLine: Animatable<LayoutNode> | null = null;\n\t\tconst lineW = Math.max(3, nameSize * 0.09);\n\n\t\tswitch (props.layout) {\n\t\t\tcase \"bar\": {\n\t\t\t\tconst edge = Math.max(4, nameSize * 0.14);\n\t\t\t\tconst innerW = Math.max(nameM.width, roleM?.width ?? 0);\n\t\t\t\tconst h = padY * 2 + nameM.height + (roleM ? roleM.height * 0.95 : 0);\n\t\t\t\tconst w = innerW + padX * 2 + edge;\n\t\t\t\tconst rect = { x: xFor(w), y: bottom - h, width: w, height: h };\n\t\t\t\tconst tx = right ? padX : padX + edge;\n\t\t\t\tconst content = [\n\t\t\t\t\ttext(\"name\", props.name, nameSize, 700, theme.color.ink, tx, padY),\n\t\t\t\t];\n\t\t\t\tif (props.role && roleM)\n\t\t\t\t\tcontent.push(\n\t\t\t\t\t\ttext(\n\t\t\t\t\t\t\t\"role\",\n\t\t\t\t\t\t\tprops.role,\n\t\t\t\t\t\t\troleSize,\n\t\t\t\t\t\t\t500,\n\t\t\t\t\t\t\ttheme.color.muted,\n\t\t\t\t\t\t\ttx,\n\t\t\t\t\t\t\tpadY + nameM.height * 0.95,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\tconst p = plate(\"plate\", rect, plateColor, theme.radius.sm, content, 0);\n\t\t\t\tconst strip = host.box({\n\t\t\t\t\tid: ctx.partId(\"edge\"),\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\tx: right ? rect.x + rect.width - edge : rect.x,\n\t\t\t\t\ty: rect.y + rect.height,\n\t\t\t\t\twidth: edge,\n\t\t\t\t\theight: 0,\n\t\t\t\t\tbackground: accent,\n\t\t\t\t\tborderRadius: theme.radius.sm,\n\t\t\t\t});\n\t\t\t\tconst grow = Math.round(base * 0.8);\n\t\t\t\tkey(strip, \"height\", [\n\t\t\t\t\t[0, 0],\n\t\t\t\t\t[grow, rect.height, enter],\n\t\t\t\t]);\n\t\t\t\tkey(strip, \"y\", [\n\t\t\t\t\t[0, rect.y + rect.height],\n\t\t\t\t\t[grow, rect.y, enter],\n\t\t\t\t]);\n\t\t\t\tchildren.push(strip);\n\t\t\t\tparts.edge = strip;\n\t\t\t\tplates.push(p);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"stacked\": {\n\t\t\t\tconst nameW = nameM.width + padX * 2;\n\t\t\t\tconst nameH = nameM.height + padY * 2;\n\t\t\t\tconst roleH = roleM ? roleM.height + padY * 1.2 : 0;\n\t\t\t\tconst roleW = roleM ? roleM.width + padX * 1.6 : 0;\n\t\t\t\tconst inset = nameSize * 0.4;\n\t\t\t\tconst total = nameH + (roleM ? roleH * 0.9 : 0);\n\t\t\t\tconst top = bottom - total;\n\t\t\t\tplates.push(\n\t\t\t\t\tplate(\n\t\t\t\t\t\t\"name-plate\",\n\t\t\t\t\t\t{ x: xFor(nameW), y: top, width: nameW, height: nameH },\n\t\t\t\t\t\tplateColor,\n\t\t\t\t\t\ttheme.radius.sm,\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\ttext(\n\t\t\t\t\t\t\t\t\"name\",\n\t\t\t\t\t\t\t\tprops.name,\n\t\t\t\t\t\t\t\tnameSize,\n\t\t\t\t\t\t\t\t700,\n\t\t\t\t\t\t\t\ttheme.color.ink,\n\t\t\t\t\t\t\t\tpadX,\n\t\t\t\t\t\t\t\tpadY,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t],\n\t\t\t\t\t\t0,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tif (props.role && roleM)\n\t\t\t\t\tplates.push(\n\t\t\t\t\t\tplate(\n\t\t\t\t\t\t\t\"role-plate\",\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tx: right ? xFor(roleW) - inset : xFor(roleW) + inset,\n\t\t\t\t\t\t\t\ty: top + nameH - roleH * 0.1,\n\t\t\t\t\t\t\t\twidth: roleW,\n\t\t\t\t\t\t\t\theight: roleH,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\taccent,\n\t\t\t\t\t\t\ttheme.radius.sm,\n\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\ttext(\n\t\t\t\t\t\t\t\t\t\"role\",\n\t\t\t\t\t\t\t\t\tprops.role,\n\t\t\t\t\t\t\t\t\troleSize,\n\t\t\t\t\t\t\t\t\t600,\n\t\t\t\t\t\t\t\t\ttheme.color.bg,\n\t\t\t\t\t\t\t\t\tpadX * 0.8,\n\t\t\t\t\t\t\t\t\tpadY * 0.6,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tMath.round(fast * 0.8),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"tag\": {\n\t\t\t\t// One line, one node: bold name, a dot, the role a size down.\n\t\t\t\tconst sep = \" · \";\n\t\t\t\tconst sepW = props.role\n\t\t\t\t\t? host.measure(sep, { fontFamily, fontSize: roleSize }).width\n\t\t\t\t\t: 0;\n\t\t\t\tconst h = nameM.height + padY * 1.4;\n\t\t\t\tconst w = nameM.width + (roleM ? sepW + roleM.width : 0) + h;\n\t\t\t\tconst line = host.text(\n\t\t\t\t\tprops.role ? `${props.name}${sep}${props.role}` : props.name,\n\t\t\t\t\t{\n\t\t\t\t\t\tid: ctx.partId(\"name\"),\n\t\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t\tx: h / 2,\n\t\t\t\t\t\ty: padY * 0.7,\n\t\t\t\t\t\tfontFamily,\n\t\t\t\t\t\tfontSize: nameSize,\n\t\t\t\t\t\tfill: theme.color.ink,\n\t\t\t\t\t\tspans: [\n\t\t\t\t\t\t\t{ text: props.name, fontWeight: 700, fill: theme.color.ink },\n\t\t\t\t\t\t\t...(props.role\n\t\t\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\ttext: `${sep}${props.role}`,\n\t\t\t\t\t\t\t\t\t\t\tfontSize: roleSize,\n\t\t\t\t\t\t\t\t\t\t\tfontWeight: 500,\n\t\t\t\t\t\t\t\t\t\t\tfill: theme.color.muted,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t: []),\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tplates.push(\n\t\t\t\t\tplate(\n\t\t\t\t\t\t\"tag\",\n\t\t\t\t\t\t{ x: xFor(w), y: bottom - h, width: w, height: h },\n\t\t\t\t\t\tplateColor,\n\t\t\t\t\t\ttheme.radius.pill,\n\t\t\t\t\t\t[line],\n\t\t\t\t\t\t0,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"line\": {\n\t\t\t\tconst innerW = Math.max(nameM.width, roleM?.width ?? 0);\n\t\t\t\tconst h = nameM.height + (roleM ? roleM.height : 0);\n\t\t\t\tconst gap = nameSize * 0.4;\n\t\t\t\tconst w = innerW + gap + lineW;\n\t\t\t\tconst x = xFor(w);\n\t\t\t\tconst lineX = right ? x + w - lineW : x;\n\t\t\t\tconst tx = right ? 0 : lineW + gap;\n\t\t\t\taccentLine = host.box({\n\t\t\t\t\tid: ctx.partId(\"line\"),\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\tx: lineX,\n\t\t\t\t\ty: bottom,\n\t\t\t\t\twidth: lineW,\n\t\t\t\t\theight: 0,\n\t\t\t\t\tbackground: accent,\n\t\t\t\t\tborderRadius: lineW / 2,\n\t\t\t\t});\n\t\t\t\tconst grow = Math.round(base * 1.1);\n\t\t\t\tkey(accentLine, \"height\", [\n\t\t\t\t\t[0, 0],\n\t\t\t\t\t[grow, h, enter],\n\t\t\t\t]);\n\t\t\t\tkey(accentLine, \"y\", [\n\t\t\t\t\t[0, bottom],\n\t\t\t\t\t[grow, bottom - h, enter],\n\t\t\t\t]);\n\t\t\t\tchildren.push(accentLine);\n\t\t\t\tparts.line = accentLine;\n\t\t\t\tconst content = [\n\t\t\t\t\ttext(\"name\", props.name, nameSize, 700, theme.color.ink, tx, 0),\n\t\t\t\t];\n\t\t\t\tif (props.role && roleM)\n\t\t\t\t\tcontent.push(\n\t\t\t\t\t\ttext(\n\t\t\t\t\t\t\t\"role\",\n\t\t\t\t\t\t\tprops.role,\n\t\t\t\t\t\t\troleSize,\n\t\t\t\t\t\t\t500,\n\t\t\t\t\t\t\ttheme.color.muted,\n\t\t\t\t\t\t\ttx,\n\t\t\t\t\t\t\tnameM.height,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t// No plate: the text rises through a clear box.\n\t\t\t\tplates.push(\n\t\t\t\t\tplate(\n\t\t\t\t\t\t\"text\",\n\t\t\t\t\t\t{ x, y: bottom - h, width: w, height: h },\n\t\t\t\t\t\t\"rgba(0,0,0,0)\",\n\t\t\t\t\t\t0,\n\t\t\t\t\t\tcontent,\n\t\t\t\t\t\tMath.round(fast * 0.6),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tconst settled = Math.max(...plates.map((p) => p.settled));\n\t\t// ── Out: text first, then the plates slide back the way they came ──\n\t\tlet afterHold = 0;\n\t\tconst outAt = settled + ctx.hold;\n\t\tif (!props.stay) {\n\t\t\tconst fadeOut = Math.round(fast * 0.9);\n\t\t\tconst slide = Math.round(base * 0.9);\n\t\t\tplates.forEach((p, k) => {\n\t\t\t\tconst at = outAt + k * Math.round(fast * 0.4);\n\t\t\t\tfor (const node of p.content)\n\t\t\t\t\tkey(node, \"opacity\", [\n\t\t\t\t\t\t[at, 1],\n\t\t\t\t\t\t[at + fadeOut, 0, \"power2.in\"],\n\t\t\t\t\t]);\n\t\t\t\tkey(p.fill, \"x\", [\n\t\t\t\t\t[at + fadeOut - 2, 0],\n\t\t\t\t\t[at + fadeOut - 2 + slide, p.travel, theme.motion.ease.exit],\n\t\t\t\t]);\n\t\t\t\tafterHold = Math.max(afterHold, at + fadeOut - 2 + slide - outAt);\n\t\t\t});\n\t\t\tfor (const node of [accentLine, parts.edge])\n\t\t\t\tif (node)\n\t\t\t\t\tkey(node, \"opacity\", [\n\t\t\t\t\t\t[outAt, 1],\n\t\t\t\t\t\t[outAt + afterHold, 0, \"power2.in\"],\n\t\t\t\t\t]);\n\t\t}\n\t\tfor (const [node, byProp] of tracks) {\n\t\t\tconst a = LayerAnimation.create();\n\t\t\tfor (const [prop, keys] of byProp)\n\t\t\t\ta.keys(\n\t\t\t\t\tprop as \"x\",\n\t\t\t\t\t[...keys].sort((x, y) => x[0] - y[0]),\n\t\t\t\t);\n\t\t\tnode.animate(a);\n\t\t}\n\n\t\treturn {\n\t\t\tchildren,\n\t\t\twidth: W,\n\t\t\theight: H,\n\t\t\tduration: settled,\n\t\t\topenEnded: props.stay,\n\t\t\tafterHold,\n\t\t\torigin: [0, 0],\n\t\t\tcues: {\n\t\t\t\tin: [{ frame: settled }],\n\t\t\t\tout: props.stay ? [] : [{ frame: outAt }],\n\t\t\t} as LowerThirdCues,\n\t\t\tparts,\n\t\t};\n\t},\n});\n\n/**\n * The name-and-role bar of interviews and talks: measured plates in the safe\n * area that slide in and leave on their own.\n */\nexport const LowerThird = /* @__PURE__ */ bindComponent(lowerThird);\n"
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "meter",
|
|
3
|
+
"title": "Meter",
|
|
4
|
+
"summary": "Progress and scores as a ring, arc gauge, bar, lit segments or star rating, filling on the same timeline as its counter.",
|
|
5
|
+
"tags": [
|
|
6
|
+
"progress",
|
|
7
|
+
"gauge",
|
|
8
|
+
"score",
|
|
9
|
+
"rating",
|
|
10
|
+
"stat",
|
|
11
|
+
"data"
|
|
12
|
+
],
|
|
13
|
+
"example": "Meter({ value: 72, kind: \"ring\", label: \"Coverage\" })",
|
|
14
|
+
"parts": [
|
|
15
|
+
"track",
|
|
16
|
+
"fill",
|
|
17
|
+
"counter",
|
|
18
|
+
"label",
|
|
19
|
+
"cell-<n>",
|
|
20
|
+
"star-<n>"
|
|
21
|
+
],
|
|
22
|
+
"cues": [
|
|
23
|
+
"settled",
|
|
24
|
+
"crossings"
|
|
25
|
+
],
|
|
26
|
+
"registryDependencies": [
|
|
27
|
+
"counter"
|
|
28
|
+
],
|
|
29
|
+
"files": [
|
|
30
|
+
{
|
|
31
|
+
"path": "meter/index.ts",
|
|
32
|
+
"content": "/**\n * Meter: progress and scores as a ring, an arc gauge, a bar, lit segments or\n * a star rating, filling on the same value timeline as its `Counter`.\n */\nimport {\n\ttype KeyframeTuple,\n\tLayerAnimation,\n\ttype LayoutNode,\n} from \"framefields\";\nimport {\n\ttype Animatable,\n\tbakeSamples,\n\tbind,\n\tbindComponent,\n\tdefineComponent,\n\tthemeFrames,\n\ttoPathData,\n\ttype Vec2,\n\tz,\n} from \"framefields/components\";\nimport { counter } from \"../counter/index.js\";\nimport { type ValueKey, valueAt } from \"../counter/plan.js\";\n\nexport const METER_KINDS = [\"ring\", \"arc\", \"bar\", \"segments\", \"stars\"] as const;\nexport type MeterKind = (typeof METER_KINDS)[number];\n\nexport interface MeterCues {\n\t[name: string]: ReadonlyArray<{ frame: number }>;\n\t/** The fill (and counter) is at rest. */\n\tsettled: ReadonlyArray<{ frame: number }>;\n\t/** Each segment or star completing (fills only; empties are not cued). */\n\tcrossings: ReadonlyArray<{ frame: number; segment: number }>;\n}\n\n/** Points along a circular arc, angles in degrees (0 = right, clockwise). */\nfunction arcPoints(c: Vec2, r: number, from: number, to: number): Vec2[] {\n\tconst steps = Math.max(8, Math.ceil(Math.abs(to - from) / 6));\n\treturn Array.from({ length: steps + 1 }, (_, k) => {\n\t\tconst a = ((from + ((to - from) * k) / steps) * Math.PI) / 180;\n\t\treturn [c[0] + Math.cos(a) * r, c[1] + Math.sin(a) * r] as Vec2;\n\t});\n}\n\n/** A five-point star inside a `size` box. */\nfunction starPath(size: number): string {\n\tconst c = size / 2;\n\tconst pts: Vec2[] = Array.from({ length: 10 }, (_, k) => {\n\t\tconst r = k % 2 === 0 ? size * 0.5 : size * 0.21;\n\t\tconst a = -Math.PI / 2 + (k * Math.PI) / 5;\n\t\treturn [c + Math.cos(a) * r, c + Math.sin(a) * r * 1.02 + size * 0.03];\n\t});\n\treturn toPathData(pts, true);\n}\n\nexport const meter = /* @__PURE__ */ defineComponent({\n\tname: \"Meter\",\n\tprops: () => ({\n\t\tvalue: z.number().optional(),\n\t\t/** Multi-step values: `[frame, value, ease?]`, frames ascending. */\n\t\tvalues: z\n\t\t\t.array(\n\t\t\t\tz.union([\n\t\t\t\t\tz.tuple([z.number().int().min(0), z.number()]),\n\t\t\t\t\tz.tuple([z.number().int().min(0), z.number(), z.string()]),\n\t\t\t\t]),\n\t\t\t)\n\t\t\t.min(1)\n\t\t\t.optional(),\n\t\tfrom: z.number().default(0),\n\t\t/** Default 100 (5 for stars). */\n\t\tmax: z.number().optional(),\n\t\tkind: z.enum(METER_KINDS).default(\"ring\"),\n\t\t/** Cells for `segments` (default 10), stars for `stars` (default `max`). */\n\t\tsegments: z.number().int().positive().optional(),\n\t\t/** Width (bar, segments, stars) or diameter (ring, arc). */\n\t\tsize: z.number().positive().optional(),\n\t\tthickness: z.number().positive().optional(),\n\t\tcounter: z.boolean().optional(),\n\t\tformat: z.string().default(\",d\"),\n\t\tsuffix: z.string().optional(),\n\t\tlabel: z.string().optional(),\n\t\tcolor: z.string().optional(),\n\t\ttrack: z.string().optional(),\n\t\tcountDuration: z.number().int().positive().optional(),\n\t\tease: z.string().optional(),\n\t\tfontFamily: z.string().optional(),\n\t}),\n\tdefaults: { enter: false, exit: false },\n\tbuild(ctx, props) {\n\t\tconst { host, theme, fps } = ctx;\n\t\tconst s = theme.scale;\n\t\tconst kind = props.kind;\n\t\tconst max = props.max ?? (kind === \"stars\" ? 5 : 100);\n\t\tconst from = props.from;\n\t\tconst ease = props.ease ?? theme.motion.ease.move;\n\t\tconst color = props.color ?? theme.color.accent;\n\t\tconst trackColor = props.track ?? theme.color.line;\n\t\tconst fontFamily = props.fontFamily ?? theme.font.display;\n\t\tif (props.value === undefined && !props.values)\n\t\t\tthrow new Error(\"Meter: give `value` (or `values`).\");\n\t\tconst keys: ValueKey[] = props.values\n\t\t\t? props.values.map((v) => [...v] as unknown as ValueKey)\n\t\t\t: [\n\t\t\t\t\t[0, from],\n\t\t\t\t\t[\n\t\t\t\t\t\tprops.countDuration ?? themeFrames(theme, \"slow\", fps) * 2,\n\t\t\t\t\t\tprops.value as number,\n\t\t\t\t\t\tease,\n\t\t\t\t\t],\n\t\t\t\t];\n\t\tconst last = (keys[keys.length - 1] as ValueKey)[0];\n\t\tconst fraction = (v: number) =>\n\t\t\tMath.max(0, Math.min(1, (v - from) / (max - from || 1)));\n\t\t/** Keys of `f(fraction)`, on exactly the value's keyframes and eases. */\n\t\tconst fillKeys = (f: (x: number) => number): KeyframeTuple[] =>\n\t\t\tkeys.map((k, i) =>\n\t\t\t\ti === 0\n\t\t\t\t\t? [k[0], f(fraction(k[1]))]\n\t\t\t\t\t: [k[0], f(fraction(k[1])), k[2] ?? ease],\n\t\t\t);\n\t\tconst perFrame = Array.from({ length: last + 1 }, (_, t) =>\n\t\t\tvalueAt(keys, t, ease),\n\t\t);\n\n\t\tconst showCounter = props.counter ?? kind !== \"stars\";\n\t\tconst suffix = props.suffix ?? (max === 100 ? \"%\" : \"\");\n\t\tconst makeCounter = bind(host, counter);\n\t\tconst number = (size: number, align: \"start\" | \"center\" | \"end\") =>\n\t\t\tmakeCounter({\n\t\t\t\tid: ctx.partId(\"counter\"),\n\t\t\t\tvalues: keys.map((k) => [...k]) as never,\n\t\t\t\tformat: props.format,\n\t\t\t\tsuffix,\n\t\t\t\taffixScale: 0.6,\n\t\t\t\tdigitStagger: 0,\n\t\t\t\tease,\n\t\t\t\tfontFamily,\n\t\t\t\tfontSize: size,\n\t\t\t\tfontWeight: 700,\n\t\t\t\talign,\n\t\t\t\tx: 0,\n\t\t\t\ty: 0,\n\t\t\t\ttheme,\n\t\t\t\tfps,\n\t\t\t});\n\t\tconst label = (text: string, size: number) =>\n\t\t\thost.text(text, {\n\t\t\t\tid: ctx.partId(\"label\"),\n\t\t\t\tposition: \"absolute\",\n\t\t\t\tfontFamily,\n\t\t\t\tfontSize: size,\n\t\t\t\tfill: theme.color.muted,\n\t\t\t});\n\n\t\tconst children: LayoutNode[] = [];\n\t\tconst parts: Record<string, Animatable<LayoutNode>> = {};\n\t\tconst crossings: Array<{ frame: number; segment: number }> = [];\n\t\tlet W = 0;\n\t\tlet H = 0;\n\n\t\tconst stroke = (\n\t\t\tid: string,\n\t\t\td: string,\n\t\t\tw: number,\n\t\t\th: number,\n\t\t\tpaint: string,\n\t\t\tthickness: number,\n\t\t) =>\n\t\t\thost.shape(\"path\", {\n\t\t\t\tid: ctx.partId(id),\n\t\t\t\tposition: \"absolute\",\n\t\t\t\tx: 0,\n\t\t\t\ty: 0,\n\t\t\t\twidth: w,\n\t\t\t\theight: h,\n\t\t\t\td,\n\t\t\t\tfillType: \"none\",\n\t\t\t\tstrokeColor: paint,\n\t\t\t\tstrokeWidth: thickness,\n\t\t\t\tstrokeLineCap: \"round\",\n\t\t\t});\n\n\t\tswitch (kind) {\n\t\t\tcase \"ring\":\n\t\t\tcase \"arc\": {\n\t\t\t\tconst D = props.size ?? 260 * s;\n\t\t\t\tconst T = props.thickness ?? D * (kind === \"ring\" ? 0.085 : 0.1);\n\t\t\t\tconst r = (D - T) / 2;\n\t\t\t\tconst c: Vec2 = [D / 2, D / 2];\n\t\t\t\t// Ring: a full turn from the top. Arc: 240° from lower left, over the top.\n\t\t\t\tconst [a0, a1] = kind === \"ring\" ? [-90, 269.9] : [150, 390];\n\t\t\t\tconst path = toPathData(arcPoints(c, r, a0, a1));\n\t\t\t\tW = D;\n\t\t\t\tH = kind === \"ring\" ? D : D * 0.86;\n\t\t\t\tconst track = stroke(\"track\", path, W, H, trackColor, T);\n\t\t\t\tconst fill = stroke(\"fill\", path, W, H, color, T);\n\t\t\t\tfill.animate(\n\t\t\t\t\tLayerAnimation.keys(\n\t\t\t\t\t\t\"trimEnd\",\n\t\t\t\t\t\tfillKeys((x) => x),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tchildren.push(track, fill);\n\t\t\t\tparts.track = track;\n\t\t\t\tparts.fill = fill;\n\t\t\t\tif (showCounter) {\n\t\t\t\t\tconst n = number(D * (kind === \"ring\" ? 0.24 : 0.22), \"center\");\n\t\t\t\t\tconst nn = n as unknown as {\n\t\t\t\t\t\tx: number;\n\t\t\t\t\t\ty: number;\n\t\t\t\t\t\twidth: number;\n\t\t\t\t\t\theight: number;\n\t\t\t\t\t};\n\t\t\t\t\tnn.x = (W - nn.width) / 2;\n\t\t\t\t\tnn.y =\n\t\t\t\t\t\t(kind === \"ring\" ? D / 2 : D * 0.48) -\n\t\t\t\t\t\tnn.height / 2 -\n\t\t\t\t\t\t(props.label ? D * 0.04 : 0);\n\t\t\t\t\tchildren.push(n);\n\t\t\t\t\tparts.counter = n;\n\t\t\t\t\tif (props.label) {\n\t\t\t\t\t\tconst size = D * 0.075;\n\t\t\t\t\t\tconst m = host.measure(props.label, { fontFamily, fontSize: size });\n\t\t\t\t\t\tconst l = label(props.label, size);\n\t\t\t\t\t\tObject.assign(l, { x: (W - m.width) / 2, y: nn.y + nn.height });\n\t\t\t\t\t\tchildren.push(l);\n\t\t\t\t\t\tparts.label = l;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"bar\": {\n\t\t\t\tconst w = props.size ?? 640 * s;\n\t\t\t\tconst T = props.thickness ?? 16 * s;\n\t\t\t\tconst top = props.label ? 34 * s : 0;\n\t\t\t\tconst track = host.box({\n\t\t\t\t\tid: ctx.partId(\"track\"),\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\tx: 0,\n\t\t\t\t\ty: top,\n\t\t\t\t\twidth: w,\n\t\t\t\t\theight: T,\n\t\t\t\t\tbackground: trackColor,\n\t\t\t\t\tborderRadius: T / 2,\n\t\t\t\t});\n\t\t\t\tconst fill = host.box({\n\t\t\t\t\tid: ctx.partId(\"fill\"),\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\tx: 0,\n\t\t\t\t\ty: top,\n\t\t\t\t\twidth: 0,\n\t\t\t\t\theight: T,\n\t\t\t\t\tbackground: color,\n\t\t\t\t\tborderRadius: T / 2,\n\t\t\t\t});\n\t\t\t\tfill.animate(\n\t\t\t\t\tLayerAnimation.keys(\n\t\t\t\t\t\t\"width\",\n\t\t\t\t\t\tfillKeys((x) => x * w),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tchildren.push(track, fill);\n\t\t\t\tparts.track = track;\n\t\t\t\tparts.fill = fill;\n\t\t\t\tW = w;\n\t\t\t\tH = top + T;\n\t\t\t\tif (props.label) {\n\t\t\t\t\tconst l = label(props.label, 24 * s);\n\t\t\t\t\tObject.assign(l, { x: 0, y: 0 });\n\t\t\t\t\tchildren.push(l);\n\t\t\t\t\tparts.label = l;\n\t\t\t\t}\n\t\t\t\tif (showCounter) {\n\t\t\t\t\tconst n = number(Math.max(T * 2.2, 30 * s), \"end\");\n\t\t\t\t\tconst nn = n as unknown as {\n\t\t\t\t\t\tx: number;\n\t\t\t\t\t\ty: number;\n\t\t\t\t\t\twidth: number;\n\t\t\t\t\t\theight: number;\n\t\t\t\t\t};\n\t\t\t\t\tnn.x = w + 18 * s;\n\t\t\t\t\tnn.y = top + T / 2 - nn.height / 2;\n\t\t\t\t\tW = nn.x + nn.width;\n\t\t\t\t\tH = Math.max(H, nn.y + nn.height);\n\t\t\t\t\tchildren.push(n);\n\t\t\t\t\tparts.counter = n;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"segments\":\n\t\t\tcase \"stars\": {\n\t\t\t\tconst n = props.segments ?? (kind === \"stars\" ? Math.round(max) : 10);\n\t\t\t\tconst w = props.size ?? (kind === \"stars\" ? 300 : 640) * s;\n\t\t\t\tconst gap = kind === \"stars\" ? w * 0.03 : w * 0.012;\n\t\t\t\tconst cell = (w - gap * (n - 1)) / n;\n\t\t\t\tconst h = kind === \"stars\" ? cell : (props.thickness ?? 22 * s);\n\t\t\t\t// How full each cell is, per frame.\n\t\t\t\tconst fill = (k: number) =>\n\t\t\t\t\tperFrame.map((v) => Math.max(0, Math.min(1, fraction(v) * n - k)));\n\t\t\t\tfor (let k = 0; k < n; k++) {\n\t\t\t\t\tconst x = k * (cell + gap);\n\t\t\t\t\tconst amount = fill(k);\n\t\t\t\t\tconst full = amount.findIndex((a) => a >= 1);\n\t\t\t\t\tif (full >= 0) crossings.push({ frame: full, segment: k });\n\t\t\t\t\tif (kind === \"segments\") {\n\t\t\t\t\t\tconst base = host.box({\n\t\t\t\t\t\t\tid: ctx.partId(`cell-${k}`),\n\t\t\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t\t\tx,\n\t\t\t\t\t\t\ty: 0,\n\t\t\t\t\t\t\twidth: cell,\n\t\t\t\t\t\t\theight: h,\n\t\t\t\t\t\t\tbackground: trackColor,\n\t\t\t\t\t\t\tborderRadius: Math.min(h, cell) * 0.25,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst lit = host.box({\n\t\t\t\t\t\t\tid: ctx.partId(`lit-${k}`),\n\t\t\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t\t\tx,\n\t\t\t\t\t\t\ty: 0,\n\t\t\t\t\t\t\twidth: cell,\n\t\t\t\t\t\t\theight: h,\n\t\t\t\t\t\t\tbackground: color,\n\t\t\t\t\t\t\tborderRadius: Math.min(h, cell) * 0.25,\n\t\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\t});\n\t\t\t\t\t\t// Lights on the frame the value reaches the cell, with a small pop.\n\t\t\t\t\t\tconst on = amount.map((a) => (a >= 1 ? 1 : 0));\n\t\t\t\t\t\tconst opacity: KeyframeTuple[] = [[0, on[0] ?? 0]];\n\t\t\t\t\t\tconst scale: KeyframeTuple[] = [[0, 1]];\n\t\t\t\t\t\ton.forEach((v, t) => {\n\t\t\t\t\t\t\tif (t > 0 && v !== on[t - 1]) {\n\t\t\t\t\t\t\t\topacity.push([t, v, \"hold\"]);\n\t\t\t\t\t\t\t\tif (v === 1) scale.push([t, 1.18], [t + 6, 1, \"power2.out\"]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t\tlit.animate(\n\t\t\t\t\t\t\tLayerAnimation.create()\n\t\t\t\t\t\t\t\t.keys(\"opacity\", opacity)\n\t\t\t\t\t\t\t\t.keys(\"scale\", ascending(scale)),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tchildren.push(base, lit);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst d = starPath(cell);\n\t\t\t\t\t\tconst base = host.shape(\"path\", {\n\t\t\t\t\t\t\tid: ctx.partId(`star-${k}`),\n\t\t\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t\t\tx,\n\t\t\t\t\t\t\ty: 0,\n\t\t\t\t\t\t\twidth: cell,\n\t\t\t\t\t\t\theight: cell,\n\t\t\t\t\t\t\td,\n\t\t\t\t\t\t\tfillType: \"solid\",\n\t\t\t\t\t\t\tfillColor: trackColor,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst star = host.shape(\"path\", {\n\t\t\t\t\t\t\tid: ctx.partId(`star-${k}-fill`),\n\t\t\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t\t\tx: 0,\n\t\t\t\t\t\t\ty: 0,\n\t\t\t\t\t\t\twidth: cell,\n\t\t\t\t\t\t\theight: cell,\n\t\t\t\t\t\t\td,\n\t\t\t\t\t\t\tfillType: \"solid\",\n\t\t\t\t\t\t\tfillColor: color,\n\t\t\t\t\t\t});\n\t\t\t\t\t\t// Fractional ratings fill a star partway: a clip that widens.\n\t\t\t\t\t\tconst clip = host.box({\n\t\t\t\t\t\t\tid: ctx.partId(`star-${k}-clip`),\n\t\t\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t\t\tx,\n\t\t\t\t\t\t\ty: 0,\n\t\t\t\t\t\t\twidth: 0,\n\t\t\t\t\t\t\theight: cell,\n\t\t\t\t\t\t\toverflow: \"hidden\",\n\t\t\t\t\t\t\tchildren: [star],\n\t\t\t\t\t\t});\n\t\t\t\t\t\tclip.animate(\n\t\t\t\t\t\t\tLayerAnimation.keys(\n\t\t\t\t\t\t\t\t\"width\",\n\t\t\t\t\t\t\t\tbakeSamples(\n\t\t\t\t\t\t\t\t\tamount.map((a) => a * cell),\n\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t\t{ tolerance: 0.2 },\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tchildren.push(base, clip);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tW = w;\n\t\t\t\tH = h;\n\t\t\t\tif (showCounter) {\n\t\t\t\t\tconst c = number(Math.max(h * 1.4, 30 * s), \"end\");\n\t\t\t\t\tconst cc = c as unknown as {\n\t\t\t\t\t\tx: number;\n\t\t\t\t\t\ty: number;\n\t\t\t\t\t\twidth: number;\n\t\t\t\t\t\theight: number;\n\t\t\t\t\t};\n\t\t\t\t\tcc.x = w + 18 * s;\n\t\t\t\t\tcc.y = h / 2 - cc.height / 2;\n\t\t\t\t\tW = cc.x + cc.width;\n\t\t\t\t\tH = Math.max(H, cc.y + cc.height);\n\t\t\t\t\tchildren.push(c);\n\t\t\t\t\tparts.counter = c;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tconst settled = Math.max(\n\t\t\tlast,\n\t\t\t(\n\t\t\t\tparts.counter as unknown as {\n\t\t\t\t\tcues?: { settled: Array<{ frame: number }> };\n\t\t\t\t}\n\t\t\t)?.cues?.settled[0]?.frame ?? 0,\n\t\t);\n\t\treturn {\n\t\t\tchildren,\n\t\t\twidth: W,\n\t\t\theight: H,\n\t\t\tduration: settled + 1,\n\t\t\topenEnded: true,\n\t\t\tcues: { settled: [{ frame: settled }], crossings } as MeterCues,\n\t\t\tparts,\n\t\t};\n\t},\n});\n\nfunction ascending(keys: KeyframeTuple[]): KeyframeTuple[] {\n\tconst out: KeyframeTuple[] = [];\n\tfor (const k of [...keys].sort((a, b) => a[0] - b[0])) {\n\t\twhile (out.length > 0 && (out[out.length - 1] as KeyframeTuple)[0] >= k[0])\n\t\t\tout.pop();\n\t\tout.push(k);\n\t}\n\treturn out;\n}\n\n/**\n * Progress and scores as a ring, arc gauge, bar, lit segments or star rating,\n * filling on the same timeline as its counter.\n */\nexport const Meter = /* @__PURE__ */ bindComponent(meter);\n"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|