framefields 2.12.0 → 2.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audio/index.d.mts +6 -5
- package/dist/audio/index.mjs +13 -13
- package/dist/{audio-afTBdB3U.d.mts → audio-CHV33Od9.d.mts} +3 -4
- package/dist/audio-CHV33Od9.d.mts.map +1 -0
- package/dist/{audio-DHLoNcxD.mjs → audio-DHzLQ_RG.mjs} +4 -4
- package/dist/{audio-DHLoNcxD.mjs.map → audio-DHzLQ_RG.mjs.map} +1 -1
- package/dist/{audio-KHBadECb.mjs → audio-DS9Jg2ls.mjs} +1 -1
- package/dist/{audio-KHBadECb.mjs.map → audio-DS9Jg2ls.mjs.map} +1 -1
- package/dist/{check-result-Culfu7Nx.mjs → check-result-DZWx73V8.mjs} +1 -1
- package/dist/{check-result-Culfu7Nx.mjs.map → check-result-DZWx73V8.mjs.map} +1 -1
- package/dist/cli/check-worker.mjs +51 -51
- package/dist/cli/check-worker.mjs.map +1 -1
- package/dist/cli/local-worker.d.mts +28 -0
- package/dist/cli/local-worker.d.mts.map +1 -0
- package/dist/cli/local-worker.mjs +83 -0
- package/dist/cli/local-worker.mjs.map +1 -0
- package/dist/cli.mjs +229 -54
- package/dist/cli.mjs.map +1 -1
- package/dist/cloud/index.d.mts +2 -0
- package/dist/cloud/index.d.mts.map +1 -1
- package/dist/cloud/index.mjs +1 -1
- package/dist/{cloud-COid1Ipa.mjs → cloud-Cj1TIme8.mjs} +306 -7
- package/dist/cloud-Cj1TIme8.mjs.map +1 -0
- package/dist/components/index.d.mts +15 -14
- package/dist/components/index.mjs +47 -47
- package/dist/{dist-CySGkG54.mjs → dist-BSKAbyea.mjs} +2 -2
- package/dist/{dist-CySGkG54.mjs.map → dist-BSKAbyea.mjs.map} +1 -1
- package/dist/{dist-BwtxciN4.mjs → dist-B_rSWeOz.mjs} +1 -1
- package/dist/{dist-Bf2_efYP.mjs → dist-C8XSqfTx.mjs} +1 -1
- package/dist/{dist-Bf2_efYP.mjs.map → dist-C8XSqfTx.mjs.map} +1 -1
- package/dist/{dist-BSqeChht.mjs → dist-CUNvNDS3.mjs} +129 -82
- package/dist/dist-CUNvNDS3.mjs.map +1 -0
- package/dist/dist-CiTgmfUw.mjs +502 -0
- package/dist/dist-CiTgmfUw.mjs.map +1 -0
- package/dist/{dist-B-OPY7Cs.mjs → dist-D3BeAZ7X.mjs} +44 -10
- package/dist/dist-D3BeAZ7X.mjs.map +1 -0
- package/dist/{dist-BIE8fvlv.mjs → dist-DgZpN6IK.mjs} +1 -1
- package/dist/{dist-BIE8fvlv.mjs.map → dist-DgZpN6IK.mjs.map} +1 -1
- package/dist/{dist-2_lT3Dwc.mjs → dist-Kbf-JTry.mjs} +2 -2
- package/dist/{dist-2_lT3Dwc.mjs.map → dist-Kbf-JTry.mjs.map} +1 -1
- package/dist/effects/index.d.mts +6 -6
- package/dist/effects/index.mjs +36 -36
- package/dist/{effects-C8CL9cOq.mjs → effects-BiDgCK1L.mjs} +3 -3
- package/dist/{effects-C8CL9cOq.mjs.map → effects-BiDgCK1L.mjs.map} +1 -1
- package/dist/fonts/index.d.mts +1 -1
- package/dist/fonts/index.mjs +3 -3
- package/dist/{fonts-BQrDjnpV.mjs → fonts-DeDPWdvJ.mjs} +2 -2
- package/dist/{fonts-BQrDjnpV.mjs.map → fonts-DeDPWdvJ.mjs.map} +1 -1
- package/dist/{gpu-DHa-3Dou.mjs → gpu-CWjgql4C.mjs} +2 -2
- package/dist/{gpu-DHa-3Dou.mjs.map → gpu-CWjgql4C.mjs.map} +1 -1
- package/dist/index-BFTtXosj.d.mts +63 -0
- package/dist/index-BFTtXosj.d.mts.map +1 -0
- package/dist/{index-BW0Q1ygn.d.mts → index-C5sgRLlG.d.mts} +1 -1
- package/dist/{index-BW0Q1ygn.d.mts.map → index-C5sgRLlG.d.mts.map} +1 -1
- package/dist/{index-CdCrae-I.d.mts → index-CnZhBlob.d.mts} +2 -2
- package/dist/index-CnZhBlob.d.mts.map +1 -0
- package/dist/{index-CTv9ZieD.d.mts → index-D68eGFNE.d.mts} +3 -30
- package/dist/index-D68eGFNE.d.mts.map +1 -0
- package/dist/{index-WwuuX8ZJ.d.mts → index-DBh3WphX.d.mts} +2 -2
- package/dist/{index-WwuuX8ZJ.d.mts.map → index-DBh3WphX.d.mts.map} +1 -1
- package/dist/{index-gOVtTm-P.d.mts → index-DQ1U3HC3.d.mts} +14 -6
- package/dist/index-DQ1U3HC3.d.mts.map +1 -0
- package/dist/{index-CAuNuvIg.d.mts → index-Dibc_xpC.d.mts} +5 -5
- package/dist/{index-CAuNuvIg.d.mts.map → index-Dibc_xpC.d.mts.map} +1 -1
- package/dist/{index-BNClElng.d.mts → index-E2IXX0Cz.d.mts} +282 -284
- package/dist/index-E2IXX0Cz.d.mts.map +1 -0
- package/dist/{index-Fliv2Z-w.d.mts → index-X2u96TEo.d.mts} +131 -5
- package/dist/index-X2u96TEo.d.mts.map +1 -0
- package/dist/{index-Drk6HC2k.d.mts → index-YB9j9KUx.d.mts} +3 -3
- package/dist/{index-Drk6HC2k.d.mts.map → index-YB9j9KUx.d.mts.map} +1 -1
- package/dist/{index-COYNQ_mf.d.mts → index-a6JrbAK0.d.mts} +1 -1
- package/dist/{index-COYNQ_mf.d.mts.map → index-a6JrbAK0.d.mts.map} +1 -1
- package/dist/{index-DQa7mhzq.d.mts → index-rtCXNxGO.d.mts} +2 -2
- package/dist/{index-DQa7mhzq.d.mts.map → index-rtCXNxGO.d.mts.map} +1 -1
- package/dist/index.d.mts +16 -15
- package/dist/index.mjs +58 -58
- package/dist/preview/index.d.mts +5 -4
- package/dist/preview/index.mjs +12 -12
- package/dist/{preview-BUtt481A.mjs → preview-PDz7o2xg.mjs} +323 -35
- package/dist/preview-PDz7o2xg.mjs.map +1 -0
- package/dist/preview-engine/audio.mjs +1 -1
- package/dist/preview-engine/chunk-4P3MMJWD.mjs +1 -0
- package/dist/preview-engine/{chunk-4JNIEQS2.mjs → chunk-77WWW75O.mjs} +1 -1
- package/dist/preview-engine/{chunk-UKZVUYB6.mjs → chunk-7M5LE6EM.mjs} +1 -1
- package/dist/preview-engine/{chunk-KBCZKIIQ.mjs → chunk-CYM75INB.mjs} +1 -1
- package/dist/preview-engine/chunk-FRJPXWAG.mjs +1 -0
- package/dist/preview-engine/{chunk-FJTURGJV.mjs → chunk-IEEV5RB3.mjs} +1 -1
- package/dist/preview-engine/chunk-LZNHGH56.mjs +5 -0
- package/dist/preview-engine/{chunk-RGKS6YIA.mjs → chunk-N2VISDTG.mjs} +1 -1
- package/dist/preview-engine/{chunk-O75BFM4S.mjs → chunk-NVXFEDJS.mjs} +1 -1
- package/dist/preview-engine/{chunk-VUO4K52B.mjs → chunk-PD2HKW2S.mjs} +1 -1
- package/dist/preview-engine/{chunk-HTAHYSCW.mjs → chunk-R4H52Q7S.mjs} +1 -1
- package/dist/preview-engine/{chunk-6O7UDVNL.mjs → chunk-RYSV44B4.mjs} +1 -1
- package/dist/preview-engine/{chunk-JAUMCOOJ.mjs → chunk-SMHEMYCV.mjs} +1 -1
- package/dist/preview-engine/{chunk-TKXOSEIJ.mjs → chunk-SV3ZNZQU.mjs} +1 -1
- package/dist/preview-engine/{chunk-32WC4FRR.mjs → chunk-UE7Y65C3.mjs} +3 -3
- package/dist/preview-engine/chunk-UFPA36D2.mjs +2227 -0
- package/dist/preview-engine/{chunk-M4QVCQ3O.mjs → chunk-VMXJZ4KQ.mjs} +1 -1
- package/dist/preview-engine/{chunk-EYKN2VET.mjs → chunk-XYCR3STG.mjs} +1 -1
- package/dist/preview-engine/components.mjs +1 -1
- package/dist/preview-engine/effects.mjs +1 -1
- package/dist/preview-engine/framefields.mjs +1 -1
- package/dist/preview-engine/player.mjs +5 -5
- package/dist/preview-engine/{renderers-L6GFGHS6.mjs → renderers-AFTUFMQQ.mjs} +1 -1
- package/dist/preview-engine/renderers-DU7KPFVV.mjs +1 -1
- package/dist/preview-engine/{renderers-PREFONJG.mjs → renderers-EPSF5CSQ.mjs} +1 -1
- package/dist/preview-engine/{renderers-R22CDFO4.mjs → renderers-OJWWIVNW.mjs} +1 -1
- package/dist/preview-engine/{renderers-TS32FDV7.mjs → renderers-RHMRWX46.mjs} +1 -1
- package/dist/preview-engine/{renderers-PSBTV2DO.mjs → renderers-TTXTV4PC.mjs} +1 -1
- package/dist/preview-engine/renderers-VEHYARKY.mjs +1 -0
- package/dist/preview-engine/renderers-VRXAG3FR.mjs +1 -0
- package/dist/preview-engine/renderers-ZHSOWEMQ.mjs +1 -0
- package/dist/preview-engine/renderers-ZMDRNYSS.mjs +1 -0
- package/dist/preview-engine/signals.mjs +1 -1
- package/dist/preview-engine/{src-GPF7RIBU.mjs → src-YXNX4MLK.mjs} +1 -1
- package/dist/{program-Cvv_nb9T.mjs → program-Bn6ko_I4.mjs} +4 -4
- package/dist/{program-Cvv_nb9T.mjs.map → program-Bn6ko_I4.mjs.map} +1 -1
- package/dist/renderer/index.d.mts +4 -3
- package/dist/renderer/index.mjs +3 -3
- package/dist/{renderer-CZClDMgF.mjs → renderer--Q0pM9Vh.mjs} +5 -5
- package/dist/{renderer-CZClDMgF.mjs.map → renderer--Q0pM9Vh.mjs.map} +1 -1
- package/dist/renderer-1aSF5BmY.mjs +5 -0
- package/dist/{renderer-tRi3KNoG.mjs → renderer-45ifiDkn.mjs} +5 -5
- package/dist/{renderer-tRi3KNoG.mjs.map → renderer-45ifiDkn.mjs.map} +1 -1
- package/dist/{renderer-BTd6tFcS.mjs → renderer-549d94qG.mjs} +5 -5
- package/dist/{renderer-BTd6tFcS.mjs.map → renderer-549d94qG.mjs.map} +1 -1
- package/dist/{renderer-CMCmljb0.mjs → renderer-B-LUGB9h.mjs} +3 -3
- package/dist/{renderer-CMCmljb0.mjs.map → renderer-B-LUGB9h.mjs.map} +1 -1
- package/dist/renderer-B2e4Gr9u.mjs +5 -0
- package/dist/{renderer-sMFJtt_H.mjs → renderer-B5b-ehRb.mjs} +3 -3
- package/dist/{renderer-sMFJtt_H.mjs.map → renderer-B5b-ehRb.mjs.map} +1 -1
- package/dist/renderer-B6fz4j50.mjs +5 -0
- package/dist/{renderer-BJEexai1.mjs → renderer-BCTUqJG7.mjs} +5 -5
- package/dist/{renderer-BJEexai1.mjs.map → renderer-BCTUqJG7.mjs.map} +1 -1
- package/dist/renderer-BEftIYw-.mjs +5 -0
- package/dist/{renderer-smP1F57W.mjs → renderer-BHPgkoEL.mjs} +4 -4
- package/dist/{renderer-smP1F57W.mjs.map → renderer-BHPgkoEL.mjs.map} +1 -1
- package/dist/renderer-BHTnO-7e.mjs +5 -0
- package/dist/{renderer-LrAldCWN.mjs → renderer-BIieU9pY.mjs} +5 -5
- package/dist/{renderer-LrAldCWN.mjs.map → renderer-BIieU9pY.mjs.map} +1 -1
- package/dist/{renderer-snjhPaP-.mjs → renderer-BKi6jDi_.mjs} +4 -4
- package/dist/{renderer-snjhPaP-.mjs.map → renderer-BKi6jDi_.mjs.map} +1 -1
- package/dist/renderer-BMlnQqTO.mjs +5 -0
- package/dist/{renderer-C2kFIZ4r.mjs → renderer-BMpmmYOq.mjs} +4 -4
- package/dist/{renderer-C2kFIZ4r.mjs.map → renderer-BMpmmYOq.mjs.map} +1 -1
- package/dist/{renderer-_KIBvES8.mjs → renderer-BO_wuUKA.mjs} +5 -5
- package/dist/{renderer-_KIBvES8.mjs.map → renderer-BO_wuUKA.mjs.map} +1 -1
- package/dist/renderer-BOzcFezY.mjs +5 -0
- package/dist/{renderer-DLaUT6JZ.mjs → renderer-BPOh9x5X.mjs} +4 -4
- package/dist/{renderer-DLaUT6JZ.mjs.map → renderer-BPOh9x5X.mjs.map} +1 -1
- package/dist/{renderer-CNpq7rL-.mjs → renderer-BPiWsrC2.mjs} +3 -3
- package/dist/{renderer-CNpq7rL-.mjs.map → renderer-BPiWsrC2.mjs.map} +1 -1
- package/dist/{renderer-t1sXDiqm.mjs → renderer-BUj7jE6t.mjs} +3 -3
- package/dist/{renderer-t1sXDiqm.mjs.map → renderer-BUj7jE6t.mjs.map} +1 -1
- package/dist/renderer-BVbjJIKJ.mjs +5 -0
- package/dist/renderer-BXsHKf4k.mjs +5 -0
- package/dist/{renderer-rKw5_EjG.mjs → renderer-BZgJj8Cl.mjs} +4 -4
- package/dist/{renderer-rKw5_EjG.mjs.map → renderer-BZgJj8Cl.mjs.map} +1 -1
- package/dist/{renderer-5fGj_tqN.mjs → renderer-BgjPbgbn.mjs} +6 -6
- package/dist/{renderer-5fGj_tqN.mjs.map → renderer-BgjPbgbn.mjs.map} +1 -1
- package/dist/{renderer-D3QPNBEj.mjs → renderer-BjgFpwVK.mjs} +5 -5
- package/dist/{renderer-D3QPNBEj.mjs.map → renderer-BjgFpwVK.mjs.map} +1 -1
- package/dist/renderer-Bks49NVl.mjs +5 -0
- package/dist/{renderer-HhJPFidU.mjs → renderer-BlZgyBSo.mjs} +5 -5
- package/dist/{renderer-HhJPFidU.mjs.map → renderer-BlZgyBSo.mjs.map} +1 -1
- package/dist/{renderer-DO_zXwMJ.mjs → renderer-BqUAyzCZ.mjs} +5 -5
- package/dist/{renderer-DO_zXwMJ.mjs.map → renderer-BqUAyzCZ.mjs.map} +1 -1
- package/dist/{renderer-O4y02xkD.mjs → renderer-Br8km655.mjs} +4 -4
- package/dist/{renderer-O4y02xkD.mjs.map → renderer-Br8km655.mjs.map} +1 -1
- package/dist/{renderer-DEoerd-j.mjs → renderer-BsMZ5Iaq.mjs} +4 -4
- package/dist/{renderer-DEoerd-j.mjs.map → renderer-BsMZ5Iaq.mjs.map} +1 -1
- package/dist/{renderer-BBjkX0Vt.mjs → renderer-BtgqTg2K.mjs} +3 -3
- package/dist/{renderer-BOg8i8eF.mjs → renderer-BuvKGwk3.mjs} +1 -1
- package/dist/{renderer-BOg8i8eF.mjs.map → renderer-BuvKGwk3.mjs.map} +1 -1
- package/dist/{renderer-DsPLMzy1.mjs → renderer-C-3qhk5x.mjs} +2 -2
- package/dist/{renderer-DsPLMzy1.mjs.map → renderer-C-3qhk5x.mjs.map} +1 -1
- package/dist/{renderer-BwV-o_1b.mjs → renderer-C-GTxnfv.mjs} +4 -4
- package/dist/{renderer-BwV-o_1b.mjs.map → renderer-C-GTxnfv.mjs.map} +1 -1
- package/dist/renderer-C-t7qFKr.mjs +5 -0
- package/dist/{renderer-Bxiiar50.mjs → renderer-C1ctHdXl.mjs} +4 -4
- package/dist/{renderer-Bxiiar50.mjs.map → renderer-C1ctHdXl.mjs.map} +1 -1
- package/dist/renderer-C24n-6CX.mjs +6 -0
- package/dist/{renderer-xNOKSN3V.mjs → renderer-C7m7Yxgc.mjs} +5 -5
- package/dist/{renderer-xNOKSN3V.mjs.map → renderer-C7m7Yxgc.mjs.map} +1 -1
- package/dist/{renderer-4uZGSmUD.mjs → renderer-C9dqx3U7.mjs} +5 -5
- package/dist/{renderer-4uZGSmUD.mjs.map → renderer-C9dqx3U7.mjs.map} +1 -1
- package/dist/renderer-CCReX-7M.mjs +5 -0
- package/dist/{renderer-CtpEzVBn.mjs → renderer-CE4535aW.mjs} +3 -3
- package/dist/{renderer-CtpEzVBn.mjs.map → renderer-CE4535aW.mjs.map} +1 -1
- package/dist/renderer-CIxFQrAm.mjs +5 -0
- package/dist/{renderer-6g1ri445.mjs → renderer-CL-vyXgX.mjs} +5 -5
- package/dist/{renderer-6g1ri445.mjs.map → renderer-CL-vyXgX.mjs.map} +1 -1
- package/dist/renderer-CLHBMIqJ.mjs +5 -0
- package/dist/renderer-CMJKi-Ye.mjs +5 -0
- package/dist/{renderer-Bf7Z7WT5.mjs → renderer-CMnlgAGs.mjs} +4 -4
- package/dist/{renderer-Bf7Z7WT5.mjs.map → renderer-CMnlgAGs.mjs.map} +1 -1
- package/dist/{renderer-uA0UCxjA.mjs → renderer-CQFMyC_c.mjs} +4 -4
- package/dist/{renderer-uA0UCxjA.mjs.map → renderer-CQFMyC_c.mjs.map} +1 -1
- package/dist/{renderer-DKFaVaRJ.mjs → renderer-CYwVNbUh.mjs} +4 -4
- package/dist/{renderer-DKFaVaRJ.mjs.map → renderer-CYwVNbUh.mjs.map} +1 -1
- package/dist/{renderer-DZIxduEt.mjs → renderer-CZ5mwBW1.mjs} +3 -3
- package/dist/{renderer-DZIxduEt.mjs.map → renderer-CZ5mwBW1.mjs.map} +1 -1
- package/dist/{renderer-BSsKlcHk.mjs → renderer-C_1eqfI0.mjs} +5 -5
- package/dist/{renderer-BSsKlcHk.mjs.map → renderer-C_1eqfI0.mjs.map} +1 -1
- package/dist/renderer-C_H3mHZa.mjs +5 -0
- package/dist/{renderer-CGpi8CDT.mjs → renderer-CciiDHuU.mjs} +4 -4
- package/dist/{renderer-CGpi8CDT.mjs.map → renderer-CciiDHuU.mjs.map} +1 -1
- package/dist/renderer-CfkTdR5B.mjs +5 -0
- package/dist/{renderer-DGXqspB9.mjs → renderer-CgK7Q1G8.mjs} +3 -3
- package/dist/{renderer-B09I95bo.mjs → renderer-CnL8Cmmr.mjs} +3 -3
- package/dist/renderer-CnhkXJ0R.mjs +5 -0
- package/dist/{renderer-BwJ0nXXu.mjs → renderer-Cp_HOmp7.mjs} +5 -5
- package/dist/{renderer-BwJ0nXXu.mjs.map → renderer-Cp_HOmp7.mjs.map} +1 -1
- package/dist/renderer-CqpyVsq_.mjs +5 -0
- package/dist/renderer-CtWgIpTE.mjs +5 -0
- package/dist/{renderer-C3CGYjrC.mjs → renderer-Cu3iKMSJ.mjs} +5 -5
- package/dist/{renderer-C3CGYjrC.mjs.map → renderer-Cu3iKMSJ.mjs.map} +1 -1
- package/dist/{renderer-BzTj_CeK.mjs → renderer-CuPAQjDK.mjs} +4 -4
- package/dist/{renderer-BzTj_CeK.mjs.map → renderer-CuPAQjDK.mjs.map} +1 -1
- package/dist/{renderer-FvvywNvv.mjs → renderer-CwlY8Tb-.mjs} +3 -3
- package/dist/{renderer-FvvywNvv.mjs.map → renderer-CwlY8Tb-.mjs.map} +1 -1
- package/dist/{renderer-ByFPmHBC.mjs → renderer-CxSFvKd1.mjs} +4 -4
- package/dist/{renderer-ByFPmHBC.mjs.map → renderer-CxSFvKd1.mjs.map} +1 -1
- package/dist/{renderer-DL3o_lG1.mjs → renderer-CyUiXLRa.mjs} +5 -5
- package/dist/{renderer-DL3o_lG1.mjs.map → renderer-CyUiXLRa.mjs.map} +1 -1
- package/dist/renderer-CyuKr5ca.mjs +5 -0
- package/dist/renderer-CzgcZXKH.mjs +3 -0
- package/dist/{renderer-DCMoBppL.mjs → renderer-D-GWBoVT.mjs} +3 -3
- package/dist/{renderer-DCMoBppL.mjs.map → renderer-D-GWBoVT.mjs.map} +1 -1
- package/dist/{renderer-IAffbHXx.mjs → renderer-D-fzEZfX.mjs} +4 -4
- package/dist/{renderer-IAffbHXx.mjs.map → renderer-D-fzEZfX.mjs.map} +1 -1
- package/dist/renderer-D5yp74NL.mjs +3 -0
- package/dist/{renderer-BC_Nse6h.mjs → renderer-D8gN7aqk.mjs} +4 -4
- package/dist/{renderer-BC_Nse6h.mjs.map → renderer-D8gN7aqk.mjs.map} +1 -1
- package/dist/renderer-D9ON_1Hf.mjs +5 -0
- package/dist/renderer-DAnTgh4o.mjs +5 -0
- package/dist/{renderer-Dak_wVh9.mjs → renderer-DGOMfyh8.mjs} +2 -2
- package/dist/{renderer-Dak_wVh9.mjs.map → renderer-DGOMfyh8.mjs.map} +1 -1
- package/dist/{renderer-CInMMs5x.mjs → renderer-DGb_wgTW.mjs} +6 -6
- package/dist/{renderer-CInMMs5x.mjs.map → renderer-DGb_wgTW.mjs.map} +1 -1
- package/dist/{renderer-DO1SZ5xY.mjs → renderer-DJPZs_zV.mjs} +5 -5
- package/dist/{renderer-DO1SZ5xY.mjs.map → renderer-DJPZs_zV.mjs.map} +1 -1
- package/dist/renderer-DKJOon6y.d.mts +1 -0
- package/dist/{renderer-DQJHjU0L.mjs → renderer-DOZPZTxe.mjs} +5 -5
- package/dist/{renderer-DQJHjU0L.mjs.map → renderer-DOZPZTxe.mjs.map} +1 -1
- package/dist/{renderer-DaY04IyU.mjs → renderer-DRal7Goa.mjs} +5 -5
- package/dist/{renderer-DaY04IyU.mjs.map → renderer-DRal7Goa.mjs.map} +1 -1
- package/dist/renderer-DWgpivA3.mjs +5 -0
- package/dist/{renderer-qVJdxbXB.mjs → renderer-DXFJv_e6.mjs} +4 -4
- package/dist/{renderer-qVJdxbXB.mjs.map → renderer-DXFJv_e6.mjs.map} +1 -1
- package/dist/renderer-Dh_qNNwR.mjs +5 -0
- package/dist/renderer-DkCpXPMP.mjs +5 -0
- package/dist/{renderer-PnnkUWm-.mjs → renderer-Dp5ChuOs.mjs} +4 -4
- package/dist/{renderer-PnnkUWm-.mjs.map → renderer-Dp5ChuOs.mjs.map} +1 -1
- package/dist/{renderer-C_gR2H3R.mjs → renderer-DpZballM.mjs} +3 -3
- package/dist/{renderer-C_gR2H3R.mjs.map → renderer-DpZballM.mjs.map} +1 -1
- package/dist/renderer-Dre-6cDR.mjs +5 -0
- package/dist/renderer-Ds5z4_HX.mjs +5 -0
- package/dist/{renderer-b0H3oDae.mjs → renderer-DwGlDNOV.mjs} +3 -3
- package/dist/{renderer-b0H3oDae.mjs.map → renderer-DwGlDNOV.mjs.map} +1 -1
- package/dist/{renderer-oBgCEqaM.mjs → renderer-DxB_OfLs.mjs} +4 -4
- package/dist/{renderer-oBgCEqaM.mjs.map → renderer-DxB_OfLs.mjs.map} +1 -1
- package/dist/{renderer-BvRM3OZ6.mjs → renderer-Dz6P-rPI.mjs} +3 -3
- package/dist/{renderer-BvRM3OZ6.mjs.map → renderer-Dz6P-rPI.mjs.map} +1 -1
- package/dist/{renderer-DrL3J9ci.mjs → renderer-FPiLBwj5.mjs} +4 -4
- package/dist/{renderer-DrL3J9ci.mjs.map → renderer-FPiLBwj5.mjs.map} +1 -1
- package/dist/renderer-HGSCOMyP.mjs +5 -0
- package/dist/renderer-KMY8W-cJ.mjs +5 -0
- package/dist/{renderer-BXGuCnCJ.mjs → renderer-KgsVk9c6.mjs} +4 -4
- package/dist/{renderer-BXGuCnCJ.mjs.map → renderer-KgsVk9c6.mjs.map} +1 -1
- package/dist/{renderer-CLTRTtQ8.mjs → renderer-LXhEPCmy.mjs} +5 -5
- package/dist/{renderer-CLTRTtQ8.mjs.map → renderer-LXhEPCmy.mjs.map} +1 -1
- package/dist/{renderer-CN-mCIoI.mjs → renderer-NBMmvqWl.mjs} +5 -5
- package/dist/{renderer-CN-mCIoI.mjs.map → renderer-NBMmvqWl.mjs.map} +1 -1
- package/dist/{renderer-HXw4cJZx.mjs → renderer-Nnu32rqg.mjs} +3 -3
- package/dist/{renderer-HXw4cJZx.mjs.map → renderer-Nnu32rqg.mjs.map} +1 -1
- package/dist/renderer-R21YvXz3.mjs +5 -0
- package/dist/{renderer-Dj54y3h3.mjs → renderer-RAq3LnNy.mjs} +3 -3
- package/dist/{renderer-Dj54y3h3.mjs.map → renderer-RAq3LnNy.mjs.map} +1 -1
- package/dist/renderer-RtzCz37W.mjs +5 -0
- package/dist/{renderer-CiHVnhUk.mjs → renderer-RzkU_O1i.mjs} +5 -5
- package/dist/{renderer-CiHVnhUk.mjs.map → renderer-RzkU_O1i.mjs.map} +1 -1
- package/dist/{renderer-D3YbHjRG.mjs → renderer-S9tVGneU.mjs} +95 -80
- package/dist/renderer-S9tVGneU.mjs.map +1 -0
- package/dist/{renderer-DP9ScNM6.mjs → renderer-SJyp9-62.mjs} +3 -3
- package/dist/{renderer-DP9ScNM6.mjs.map → renderer-SJyp9-62.mjs.map} +1 -1
- package/dist/{renderer-TiaHrU5z.mjs → renderer-_54hiCq0.mjs} +5 -5
- package/dist/{renderer-TiaHrU5z.mjs.map → renderer-_54hiCq0.mjs.map} +1 -1
- package/dist/{renderer-CcmxR6Fy.d.mts → renderer-aRk849b3.d.mts} +2 -2
- package/dist/{renderer-CcmxR6Fy.d.mts.map → renderer-aRk849b3.d.mts.map} +1 -1
- package/dist/{renderer-Dy1xQOTu.mjs → renderer-dGEMVaZ3.mjs} +4 -4
- package/dist/{renderer-Dy1xQOTu.mjs.map → renderer-dGEMVaZ3.mjs.map} +1 -1
- package/dist/{renderer-Dp9FQKVP.mjs → renderer-dRXP2dJU.mjs} +5 -5
- package/dist/{renderer-Dp9FQKVP.mjs.map → renderer-dRXP2dJU.mjs.map} +1 -1
- package/dist/{renderer-DwH5e3hx.mjs → renderer-g9SstkTz.mjs} +3 -3
- package/dist/renderer-iMrqAjix.mjs +5 -0
- package/dist/{renderer-DX60Kr20.mjs → renderer-opVuiAQR.mjs} +3 -3
- package/dist/{renderer-DX60Kr20.mjs.map → renderer-opVuiAQR.mjs.map} +1 -1
- package/dist/{renderer-DrK6pyfz.mjs → renderer-puQhVfDS.mjs} +5 -5
- package/dist/{renderer-DrK6pyfz.mjs.map → renderer-puQhVfDS.mjs.map} +1 -1
- package/dist/renderer-sMed1u1O.mjs +5 -0
- package/dist/renderer-tsAuo46l.mjs +5 -0
- package/dist/{renderer-DaLy1dFA.mjs → renderer-vll8LX0I.mjs} +9 -9
- package/dist/{renderer-DaLy1dFA.mjs.map → renderer-vll8LX0I.mjs.map} +1 -1
- package/dist/{renderers-CP8CFWDs-DWRjjeUg.mjs → renderers-CP8CFWDs-BRQyvcut.mjs} +4 -4
- package/dist/{renderers-CP8CFWDs-DWRjjeUg.mjs.map → renderers-CP8CFWDs-BRQyvcut.mjs.map} +1 -1
- package/dist/sam/index.d.mts +3 -3
- package/dist/sam/index.mjs +1 -1
- package/dist/signals/index.d.mts +7 -7
- package/dist/signals/index.mjs +8 -8
- package/dist/{signals-BfJ1aqpT.mjs → signals-tiho_9fp.mjs} +4 -4
- package/dist/{signals-BfJ1aqpT.mjs.map → signals-tiho_9fp.mjs.map} +1 -1
- package/dist/{src-BU6vm9sP-DFJ3phW0.mjs → src-BU6vm9sP-DdTHmCr4.mjs} +3 -3
- package/dist/{src-BU6vm9sP-DFJ3phW0.mjs.map → src-BU6vm9sP-DdTHmCr4.mjs.map} +1 -1
- package/dist/{src-D7M8VTzv.mjs → src-BzFGotRc.mjs} +11 -11
- package/dist/{src-D7M8VTzv.mjs.map → src-BzFGotRc.mjs.map} +1 -1
- package/dist/storage/index.d.mts +206 -0
- package/dist/storage/index.d.mts.map +1 -0
- package/dist/storage/index.mjs +3 -0
- package/package.json +67 -59
- package/dist/audio-afTBdB3U.d.mts.map +0 -1
- package/dist/cloud-COid1Ipa.mjs.map +0 -1
- package/dist/dist-B-OPY7Cs.mjs.map +0 -1
- package/dist/dist-BSqeChht.mjs.map +0 -1
- package/dist/index-BNClElng.d.mts.map +0 -1
- package/dist/index-CTv9ZieD.d.mts.map +0 -1
- package/dist/index-CdCrae-I.d.mts.map +0 -1
- package/dist/index-Fliv2Z-w.d.mts.map +0 -1
- package/dist/index-gOVtTm-P.d.mts.map +0 -1
- package/dist/preview-BUtt481A.mjs.map +0 -1
- package/dist/preview-engine/chunk-5SLBE2FX.mjs +0 -1
- package/dist/preview-engine/chunk-74J4DJQA.mjs +0 -1
- package/dist/preview-engine/chunk-KIPXBOYG.mjs +0 -1974
- package/dist/preview-engine/chunk-P4Y3PMJF.mjs +0 -1
- package/dist/preview-engine/chunk-SE2C623Z.mjs +0 -5
- package/dist/preview-engine/renderers-TEKHQHCL.mjs +0 -1
- package/dist/preview-engine/renderers-U3RLYFCN.mjs +0 -1
- package/dist/preview-engine/renderers-V5HM6PZ2.mjs +0 -1
- package/dist/preview-engine/renderers-ZGX3A3QZ.mjs +0 -1
- package/dist/renderer--RJepuOy.mjs +0 -5
- package/dist/renderer-B1U6YRRV.d.mts +0 -117
- package/dist/renderer-B1U6YRRV.d.mts.map +0 -1
- package/dist/renderer-B4NFnaty.mjs +0 -5
- package/dist/renderer-B6g4ts0e.mjs +0 -5
- package/dist/renderer-BGoAr-tl.mjs +0 -5
- package/dist/renderer-BSOdBgdE.mjs +0 -5
- package/dist/renderer-BU6O0fpM.mjs +0 -5
- package/dist/renderer-BZ97iidG.mjs +0 -5
- package/dist/renderer-B_Klh1VT.mjs +0 -5
- package/dist/renderer-BaWQM1y-.mjs +0 -5
- package/dist/renderer-Bc0jvAj0.mjs +0 -5
- package/dist/renderer-Bd-NuU3M.mjs +0 -3
- package/dist/renderer-Bm077kZ6.mjs +0 -5
- package/dist/renderer-BtzE_e_Y.mjs +0 -5
- package/dist/renderer-C225eCAo.mjs +0 -5
- package/dist/renderer-CC4fhNup.mjs +0 -3
- package/dist/renderer-CLXdR4vz.mjs +0 -5
- package/dist/renderer-CszM8B3C.mjs +0 -5
- package/dist/renderer-Ctp8ZYfk.mjs +0 -5
- package/dist/renderer-CxQdSp8I.mjs +0 -5
- package/dist/renderer-D3YbHjRG.mjs.map +0 -1
- package/dist/renderer-D4GMRtDd.mjs +0 -6
- package/dist/renderer-DEsGIvTZ.mjs +0 -5
- package/dist/renderer-DIaUQ0EP.mjs +0 -5
- package/dist/renderer-DLjqcNzQ.mjs +0 -5
- package/dist/renderer-DMuQZa51.mjs +0 -5
- package/dist/renderer-DOgi2aF2.mjs +0 -5
- package/dist/renderer-DSh7cvi4.mjs +0 -5
- package/dist/renderer-DV1LVBBP.mjs +0 -5
- package/dist/renderer-Dhrj2bJz.mjs +0 -5
- package/dist/renderer-DoFUu1R4.mjs +0 -5
- package/dist/renderer-DsydX3cx.mjs +0 -5
- package/dist/renderer-DxVSoeYi.mjs +0 -5
- package/dist/renderer-Nc9bHb0n.mjs +0 -5
- package/dist/renderer-TFaSD2Db.mjs +0 -5
- package/dist/renderer-Z61ctppe.mjs +0 -5
- package/dist/renderer-awXf3sNS.mjs +0 -5
- package/dist/renderer-cHT28oYI.mjs +0 -5
- package/dist/renderer-g7Y3bFot.mjs +0 -5
- package/dist/renderer-qVv0OzVc.mjs +0 -5
- /package/dist/{chunk-W71TSjRM.mjs → chunk-DOL2i2sR.mjs} +0 -0
- /package/dist/{renderer-B6rZUBwE.mjs → renderer-Co2YqWX0.mjs} +0 -0
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":["path","fonts","path","path","config"],"sources":["../src/cli/fonts.ts","../src/cli/add.ts","../src/cli/templates.ts","../src/cli/init.ts","../src/cli/check.ts","../src/cli/cloud.ts","../src/cli/registry.ts","../src/cli.ts"],"sourcesContent":["/**\n * Fonts the CLI installs into a project: a catalog of pinned files (URL,\n * size, SHA-256, license), the installer `framefields add` and\n * `framefields fonts add` share, and the generated `fonts.ts` module that\n * registers whatever is installed.\n *\n * framefields ships no fonts in its package (a color emoji font alone is\n * ~10 MB); they're fetched when a project needs one, verified byte for byte,\n * and saved with their license next to them.\n */\nimport { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, posix, relative, resolve, sep } from \"node:path\";\nimport { readConfig, writeConfig } from \"./config.js\";\n\n/** A downloadable file, pinned by size and hash. */\ninterface PinnedFile {\n\turl: string;\n\tsha256: string;\n\tbytes: number;\n}\n\nexport interface FontSpec {\n\t/** What it's for, in a sentence: shown by `fonts list`. */\n\tlabel: string;\n\t/** File name it's saved under. */\n\tfile: string;\n\tfont: PinnedFile;\n\tlicense: PinnedFile & {\n\t\t/** SPDX id. */\n\t\tid: string;\n\t\t/** File name it's saved under, next to the font. */\n\t\tfile: string;\n\t};\n\t/**\n\t * How it registers: as the color emoji font, or as a text family under\n\t * this name (the name themes use: `Inter`, `JetBrains Mono`).\n\t */\n\tregister: { emoji: true } | { family: string };\n}\n\nconst NOTO_EMOJI =\n\t\"https://raw.githubusercontent.com/googlefonts/noto-emoji/v2.051\";\n/** google/fonts at one commit: Inter and JetBrains Mono. */\nconst GOOGLE_FONTS =\n\t\"https://raw.githubusercontent.com/google/fonts/e7db6ca603fd4862010383ff17ffd6cc4ffac1c0\";\n\n/** Installable fonts by role. */\nexport const FONTS: Record<string, FontSpec> = {\n\temoji: {\n\t\tlabel: \"Noto Color Emoji 2.051: color emoji in any text (🎉 ❤️ 👍)\",\n\t\tfile: \"NotoColorEmoji.ttf\",\n\t\tfont: {\n\t\t\turl: `${NOTO_EMOJI}/fonts/NotoColorEmoji.ttf`,\n\t\t\tsha256:\n\t\t\t\t\"72a635cb3d2f3524c51620cdde406b217204e8a6a06c6a096ff8ed4b5fd6e27b\",\n\t\t\tbytes: 10_673_480,\n\t\t},\n\t\tlicense: {\n\t\t\tid: \"OFL-1.1\",\n\t\t\tfile: \"NotoColorEmoji-OFL.txt\",\n\t\t\turl: `${NOTO_EMOJI}/fonts/LICENSE`,\n\t\t\tsha256:\n\t\t\t\t\"6a73f9541c2de74158c0e7cf6b0a58ef774f5a780bf191f2d7ec9cc53efe2bf2\",\n\t\t\tbytes: 4_301,\n\t\t},\n\t\tregister: { emoji: true },\n\t},\n\tsans: googleFont({\n\t\tlabel: \"Inter 4: the built-in themes' display and body face\",\n\t\tfile: \"Inter.ttf\",\n\t\tfamily: \"Inter\",\n\t\tpath: \"ofl/inter/Inter%5Bopsz,wght%5D.ttf\",\n\t\tsha256: \"29160a80ff49ddcab2c97711247e08b1fab27a484a329ce8b813d820dc559031\",\n\t\tbytes: 876_576,\n\t\tlicense: {\n\t\t\tpath: \"ofl/inter/OFL.txt\",\n\t\t\tsha256:\n\t\t\t\t\"5b9321a4298cfeb6b34354164a1c3afc3db114569984c502b9b35d988fd58c57\",\n\t\t\tbytes: 4_377,\n\t\t},\n\t}),\n\tmono: googleFont({\n\t\tlabel: \"JetBrains Mono 2: the built-in themes' code and terminal face\",\n\t\tfile: \"JetBrainsMono.ttf\",\n\t\tfamily: \"JetBrains Mono\",\n\t\tpath: \"ofl/jetbrainsmono/JetBrainsMono%5Bwght%5D.ttf\",\n\t\tsha256: \"48715a42ec242c21e9f02692891e147d022299a52e48d5e413e1a942193ffeda\",\n\t\tbytes: 187_208,\n\t\tlicense: {\n\t\t\tpath: \"ofl/jetbrainsmono/OFL.txt\",\n\t\t\tsha256:\n\t\t\t\t\"b2fe5e8987594e9ffd1d2ca52a2f5d73eb8335243893c5d6254b5ad69269591d\",\n\t\t\tbytes: 4_399,\n\t\t},\n\t}),\n};\n\n/** google/fonts, pinned to one commit. */\nfunction googleFont(o: {\n\tlabel: string;\n\tfile: string;\n\tfamily: string;\n\tpath: string;\n\tsha256: string;\n\tbytes: number;\n\tlicense: { path: string; sha256: string; bytes: number };\n}): FontSpec {\n\tconst at = (path: string) => `${GOOGLE_FONTS}/${path}`;\n\treturn {\n\t\tlabel: o.label,\n\t\tfile: o.file,\n\t\tfont: { url: at(o.path), sha256: o.sha256, bytes: o.bytes },\n\t\tlicense: {\n\t\t\turl: at(o.license.path),\n\t\t\tsha256: o.license.sha256,\n\t\t\tbytes: o.license.bytes,\n\t\t\tid: \"OFL-1.1\",\n\t\t\tfile: o.file.replace(/\\.ttf$/, \"-OFL.txt\"),\n\t\t},\n\t\tregister: { family: o.family },\n\t};\n}\n\n/** Where fonts go when `framefields.json` names no place: the setup skill's layout. */\nexport const DEFAULT_FONTS_DIR = \"assets/fonts\";\n\nexport type Fetch = (url: string) => Promise<{\n\tok: boolean;\n\tstatus: number;\n\tstatusText: string;\n\tarrayBuffer(): Promise<ArrayBuffer>;\n}>;\n\nexport interface FontInstallOptions {\n\tcwd: string;\n\t/** Folder for new font files, relative to `cwd`. Default `assets/fonts`. */\n\tdir?: string;\n\t/** Replace a different file already at the target path. */\n\toverwrite?: boolean;\n\t/** For tests; default the global `fetch`. */\n\tfetch?: Fetch;\n\t/** For tests; default {@link FONTS}. */\n\tcatalog?: Record<string, FontSpec>;\n\t/** Called before a download starts (for progress messages). */\n\tonDownload?: (spec: FontSpec) => void;\n}\n\nexport interface FontInstall {\n\trole: string;\n\t/** Relative to the project root. */\n\tpath: string;\n\t/**\n\t * `installed`: downloaded now. `present`: the pinned file was already\n\t * there. `configured`: `framefields.json` already names a font for the role.\n\t */\n\tstatus: \"installed\" | \"present\" | \"configured\";\n}\n\nconst sha256 = (bytes: Uint8Array) =>\n\tcreateHash(\"sha256\").update(bytes).digest(\"hex\");\n\n/** A project-relative path with forward slashes, as `framefields.json` keeps it. */\nconst projectPath = (cwd: string, path: string) =>\n\trelative(cwd, path).split(sep).join(posix.sep);\n\n/** Install the font for `role` into the project and record it in `framefields.json`. */\nexport async function installFont(\n\trole: string,\n\toptions: FontInstallOptions,\n): Promise<FontInstall> {\n\tconst catalog = options.catalog ?? FONTS;\n\tconst spec = catalog[role];\n\tif (!spec)\n\t\tthrow new Error(\n\t\t\t`Unknown font \"${role}\". Fonts framefields can install: ${Object.keys(catalog).join(\", \")}.`,\n\t\t);\n\tconst { cwd } = options;\n\tconst { config } = readConfig(cwd);\n\tconst configured = config.fonts?.[role];\n\tif (configured && existsSync(resolve(cwd, configured)))\n\t\treturn { role, path: configured, status: \"configured\" };\n\n\tconst target = resolve(cwd, options.dir ?? DEFAULT_FONTS_DIR, spec.file);\n\tconst path = projectPath(cwd, target);\n\tlet status: FontInstall[\"status\"] = \"present\";\n\tconst current = existsSync(target) ? readFileSync(target) : null;\n\tif (!current || sha256(current) !== spec.font.sha256) {\n\t\tif (current && !options.overwrite)\n\t\t\tthrow new Error(\n\t\t\t\t`${path} exists but isn't the pinned ${spec.file}. Pass --overwrite to replace it, or point \"fonts.${role}\" in framefields.json at it to keep using yours.`,\n\t\t\t);\n\t\toptions.onDownload?.(spec);\n\t\tconst get = options.fetch ?? (fetch as unknown as Fetch);\n\t\tconst [font, license] = await Promise.all([\n\t\t\tdownload(spec.font, get),\n\t\t\tdownload(spec.license, get),\n\t\t]);\n\t\tmkdirSync(dirname(target), { recursive: true });\n\t\twriteFileSync(target, font);\n\t\twriteFileSync(join(dirname(target), spec.license.file), license);\n\t\tstatus = \"installed\";\n\t}\n\twriteConfig(cwd, {\n\t\t...config,\n\t\tfonts: { ...config.fonts, [role]: path },\n\t});\n\treturn { role, path, status };\n}\n\nasync function download(file: PinnedFile, get: Fetch): Promise<Uint8Array> {\n\tlet res: Awaited<ReturnType<Fetch>>;\n\ttry {\n\t\tres = await get(file.url);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Couldn't download ${file.url} (${error instanceof Error ? error.message : String(error)}). Check the connection, or download it yourself and point framefields.json \"fonts\" at it.`,\n\t\t);\n\t}\n\tif (!res.ok) throw new Error(`${file.url}: ${res.status} ${res.statusText}`);\n\tconst bytes = new Uint8Array(await res.arrayBuffer());\n\tconst hash = sha256(bytes);\n\tif (bytes.length !== file.bytes || hash !== file.sha256)\n\t\tthrow new Error(\n\t\t\t`${file.url} isn't the pinned file (got ${bytes.length} bytes, sha256 ${hash}; expected ${file.bytes}, ${file.sha256}). Nothing was written.`,\n\t\t);\n\treturn bytes;\n}\n\n/** First line of the generated module: files without it are the user's and left alone. */\nexport const FONTS_MODULE_MARKER =\n\t\"// Generated by framefields from framefields.json.\";\n\nexport interface FontsModule {\n\t/** Relative to the project root. */\n\tpath: string;\n\t/** `skipped`: the file exists without the marker, so it's the user's. */\n\tstatus: \"written\" | \"unchanged\" | \"skipped\";\n\t/** The registration calls, one line each, for printing when `skipped`. */\n\tcalls: string[];\n}\n\n/**\n * Write `<components>/fonts.ts`, which registers every font in\n * `framefields.json`. Call it once before building or rendering:\n * `await registerFonts()`.\n */\nexport function writeFontsModule(\n\tcwd: string,\n\tcomponentsDir: string,\n\tcatalog: Record<string, FontSpec> = FONTS,\n): FontsModule {\n\tconst { config } = readConfig(cwd);\n\tconst target = join(componentsDir, \"fonts.ts\");\n\tconst path = projectPath(cwd, target);\n\tconst fonts = Object.entries(config.fonts ?? {})\n\t\t.filter(([role]) => catalog[role])\n\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t.map(([role, file]) => {\n\t\t\tconst from = relative(componentsDir, resolve(cwd, file as string))\n\t\t\t\t.split(sep)\n\t\t\t\t.join(posix.sep);\n\t\t\tconst url = from.startsWith(\".\") ? from : `./${from}`;\n\t\t\treturn { register: (catalog[role] as FontSpec).register, url };\n\t\t});\n\tconst call = (r: FontSpec[\"register\"], source: string) =>\n\t\t\"family\" in r\n\t\t\t? `register({ family: ${JSON.stringify(r.family)}, source: ${source} })`\n\t\t\t: `registerEmojiFont(${source})`;\n\tconst calls = fonts.map(\n\t\t(f) => `await FontManager.${call(f.register, `asset(\"${f.url}\")`)};`,\n\t);\n\tconst content = `${FONTS_MODULE_MARKER}\n// \\`framefields add\\` and \\`framefields fonts add\\` rewrite it when fonts\n// change; register any other fonts in your own code.\nimport { FontManager } from \"framefields\";\n\n/** A path next to this file as a URL: works in Node and in the browser preview. */\nconst asset = (path: string) => new URL(path, import.meta.url).href;\n\n/**\n * Register the fonts this project installed with framefields. Call it\n * once, before building any text or rendering:\n *\n * \\`\\`\\`ts\n * await registerFonts();\n * \\`\\`\\`\n */\nexport async function registerFonts(): Promise<void> {\n${fonts\n\t// Wrapped the way Biome / Prettier would at 80 columns.\n\t.map((f) =>\n\t\t\"family\" in f.register\n\t\t\t? `\\tawait FontManager.register({\\n\\t\\tfamily: ${JSON.stringify(f.register.family)},\\n\\t\\tsource: asset(\"${f.url}\"),\\n\\t});`\n\t\t\t: `\\tawait FontManager.registerEmojiFont(\\n\\t\\tasset(\"${f.url}\"),\\n\\t);`,\n\t)\n\t.join(\"\\n\")}\n}\n`;\n\tif (existsSync(target)) {\n\t\tconst current = readFileSync(target, \"utf8\");\n\t\tif (current === content) return { path, status: \"unchanged\", calls };\n\t\tif (!current.startsWith(FONTS_MODULE_MARKER))\n\t\t\treturn { path, status: \"skipped\", calls };\n\t}\n\tmkdirSync(componentsDir, { recursive: true });\n\twriteFileSync(target, content);\n\treturn { path, status: \"written\", calls };\n}\n\n/**\n * A hint when fonts land in a Git repo whose `.gitattributes` doesn't send\n * them to LFS (a 10 MB binary bloats every clone), or null.\n */\nexport function lfsHint(cwd: string, fontPath: string): string | null {\n\tif (!existsSync(join(cwd, \".git\"))) return null;\n\tconst attrs = join(cwd, \".gitattributes\");\n\tconst text = existsSync(attrs) ? readFileSync(attrs, \"utf8\") : \"\";\n\tif (/\\.ttf\\b[^\\n]*filter=lfs/.test(text)) return null;\n\tconst dir = posix.dirname(fontPath);\n\treturn `Fonts are large binaries: track them with Git LFS, e.g. \\`git lfs track \"${dir}/**/*.ttf\"\\`.`;\n}\n","/**\n * `framefields add`: copy components' source into a project, the way a\n * shadcn-style registry does. The code becomes the project's own; it\n * imports only `framefields` and `framefields/components` (the toolkit),\n * plus any component it builds on, which is installed alongside it.\n *\n * Where they go is remembered in `framefields.json` at the project root.\n * Components that draw with fonts beyond the theme's (emoji) get them\n * installed too, plus a generated `fonts.ts` that registers them.\n */\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, relative, resolve } from \"node:path\";\nimport { readConfig, writeConfig } from \"./config.js\";\nimport {\n\ttype Fetch,\n\ttype FontInstall,\n\ttype FontSpec,\n\ttype FontsModule,\n\tinstallFont,\n\twriteFontsModule,\n} from \"./fonts.js\";\nimport type { Registry, RegistryItem } from \"./registry.js\";\n\nexport { CONFIG_FILE, type ProjectConfig, readConfig } from \"./config.js\";\n\nexport interface AddOptions {\n\tcwd: string;\n\tregistry: Registry;\n\t/** Components directory; saved to `framefields.json` if there is none yet. */\n\tdir?: string;\n\t/** Replace files that differ from the registry's. */\n\toverwrite?: boolean;\n\t/** Install the fonts components ask for (default true). */\n\tfonts?: boolean;\n\t/** Folder for downloaded fonts. Default `assets/fonts`. */\n\tfontsDir?: string;\n\t/** For tests; default the global `fetch`. */\n\tfetch?: Fetch;\n\t/** For tests; default the built-in font catalog. */\n\tfontCatalog?: Record<string, FontSpec>;\n\t/** Called before a font download starts. */\n\tonDownload?: (spec: FontSpec) => void;\n}\n\nexport interface AddReport {\n\tdir: string;\n\t/** Components in install order (dependencies first). */\n\tcomponents: RegistryItem[];\n\twritten: string[];\n\tunchanged: string[];\n\t/** Files left alone because they differ and `overwrite` is off. */\n\tskipped: string[];\n\tconfigWritten: boolean;\n\t/** Fonts the components asked for, and what happened to each. */\n\tfonts: Array<FontInstall & { why: string; by: string }>;\n\t/** Fonts asked for but not installed (`fonts: false`), with why. */\n\tfontsSkipped: Array<{ role: string; why: string; by: string }>;\n\t/** The generated `fonts.ts`, when any font is installed. */\n\tfontsModule?: FontsModule;\n}\n\n/** Resolve `names` (and what they import) and write their files. */\nexport async function add(\n\tnames: string[],\n\toptions: AddOptions,\n): Promise<AddReport> {\n\tconst { cwd, registry } = options;\n\tconst index = await registry.index();\n\tconst known = new Set(index.map((e) => e.name));\n\tfor (const n of names)\n\t\tif (!known.has(n))\n\t\t\tthrow new Error(\n\t\t\t\t`Unknown component \"${n}\". Run \\`framefields list\\` to see them all.`,\n\t\t\t);\n\n\t// Depth-first, dependencies before dependants.\n\tconst order: RegistryItem[] = [];\n\tconst seen = new Set<string>();\n\tconst visit = async (name: string) => {\n\t\tif (seen.has(name)) return;\n\t\tseen.add(name);\n\t\tconst item = await registry.item(name);\n\t\tfor (const d of item.registryDependencies) await visit(d);\n\t\torder.push(item);\n\t};\n\tfor (const n of names) await visit(n);\n\n\tconst { config, saved } = readConfig(cwd);\n\tconst rel = options.dir ?? config.components;\n\tconst dir = resolve(cwd, rel);\n\tconst report: AddReport = {\n\t\tdir,\n\t\tcomponents: order,\n\t\twritten: [],\n\t\tunchanged: [],\n\t\tskipped: [],\n\t\tconfigWritten: false,\n\t\tfonts: [],\n\t\tfontsSkipped: [],\n\t};\n\tfor (const item of order) {\n\t\tfor (const file of item.files) {\n\t\t\tconst target = join(dir, file.path);\n\t\t\tconst shown = relative(cwd, target);\n\t\t\tif (existsSync(target)) {\n\t\t\t\tif (readFileSync(target, \"utf8\") === file.content) {\n\t\t\t\t\treport.unchanged.push(shown);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (!options.overwrite) {\n\t\t\t\t\treport.skipped.push(shown);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tmkdirSync(dirname(target), { recursive: true });\n\t\t\twriteFileSync(target, file.content);\n\t\t\treport.written.push(shown);\n\t\t}\n\t}\n\tif (!saved) {\n\t\twriteConfig(cwd, { ...config, components: relative(cwd, dir) || \".\" });\n\t\treport.configWritten = true;\n\t}\n\n\t// One install per font, credited to the first component that asks.\n\tconst needs = new Map<string, { why: string; by: string }>();\n\tfor (const item of order)\n\t\tfor (const f of item.fonts ?? [])\n\t\t\tif (!needs.has(f.font)) needs.set(f.font, { why: f.why, by: item.name });\n\tfor (const [role, need] of needs) {\n\t\tif (options.fonts === false) {\n\t\t\treport.fontsSkipped.push({ role, ...need });\n\t\t\tcontinue;\n\t\t}\n\t\tconst done = await installFont(role, {\n\t\t\tcwd,\n\t\t\tdir: options.fontsDir,\n\t\t\toverwrite: options.overwrite,\n\t\t\tfetch: options.fetch,\n\t\t\tcatalog: options.fontCatalog,\n\t\t\tonDownload: options.onDownload,\n\t\t});\n\t\treport.fonts.push({ ...done, ...need });\n\t}\n\tif (report.fonts.length > 0 || readConfig(cwd).config.fonts)\n\t\treport.fontsModule = writeFontsModule(cwd, dir, options.fontCatalog);\n\treturn report;\n}\n","/**\n * The files `framefields init` writes: the project layout the framefields\n * setup skill describes. `film.ts` only builds; `render.ts` renders frames,\n * a grid, the live preview or the video; `theme.ts` holds the numbers.\n */\nimport type { RenderSpec } from \"./config.js\";\n\n/**\n * Packages with install scripts. framefields needs exactly one (skia-canvas\n * downloads its native binary); the others work without theirs.\n */\nconst ALLOWED_SCRIPTS = [\"skia-canvas\"];\nconst DENIED_SCRIPTS = [\n\t\"sharp\",\n\t\"webgpu\",\n\t\"onnxruntime-node\",\n\t\"node-av\",\n\t\"esbuild\",\n\t\"protobufjs\",\n];\n\n/** Dev tools the scripts use, at versions the scaffold is tested with. */\nexport const DEV_DEPENDENCIES: Record<string, string> = {\n\t\"@types/node\": \"^24.1.0\",\n\ttsx: \"^4.20.3\",\n\ttypescript: \"^5.8.3\",\n};\n\nexport const SCRIPTS: Record<string, string> = {\n\ttypecheck: \"tsc --noEmit -p .\",\n\tcheck: \"tsc --noEmit -p . && framefields check film --json\",\n\t\"check:render\": \"tsc --noEmit -p . && framefields check film --render --json\",\n\tframes: \"tsx src/render.ts frames\",\n\tgrid: \"tsx src/render.ts grid\",\n\tpreview: \"tsx src/render.ts preview\",\n\trender: \"tsx src/render.ts\",\n\t\"render:cloud\": \"framefields render film --cloud\",\n};\n\n/** The named render `init` records in framefields.json. */\nexport function defaultRenders(name: string): Record<string, RenderSpec> {\n\treturn {\n\t\tfilm: {\n\t\t\ttitle: name,\n\t\t\tentry: \"src/film.ts\",\n\t\t\texport: \"buildFilm\",\n\t\t\tworkers: \"auto\",\n\t\t\toutput: \"output/film.mp4\",\n\t\t},\n\t};\n}\n\n/**\n * The `package.json` fields a framefields project needs. npm reads\n * `allowScripts`, pnpm its `pnpm` block, bun `trustedDependencies`.\n */\nexport function packageFields(o: {\n\tframefieldsVersion: string;\n\tpackageManager?: string;\n}) {\n\treturn {\n\t\ttype: \"module\",\n\t\t...(o.packageManager && { packageManager: o.packageManager }),\n\t\tscripts: SCRIPTS,\n\t\tdependencies: { framefields: `^${o.framefieldsVersion}` },\n\t\tdevDependencies: DEV_DEPENDENCIES,\n\t\tallowScripts: Object.fromEntries([\n\t\t\t...ALLOWED_SCRIPTS.map((p) => [p, true]),\n\t\t\t...DENIED_SCRIPTS.map((p) => [p, false]),\n\t\t]),\n\t\tpnpm: {\n\t\t\tonlyBuiltDependencies: ALLOWED_SCRIPTS,\n\t\t\tignoredBuiltDependencies: DENIED_SCRIPTS,\n\t\t},\n\t\ttrustedDependencies: ALLOWED_SCRIPTS,\n\t};\n}\n\nexport const TSCONFIG = `${JSON.stringify(\n\t{\n\t\tcompilerOptions: {\n\t\t\tmodule: \"NodeNext\",\n\t\t\tmoduleResolution: \"NodeNext\",\n\t\t\ttarget: \"ES2022\",\n\t\t\tstrict: true,\n\t\t\tskipLibCheck: true,\n\t\t\tnoEmit: true,\n\t\t\ttypes: [\"node\"],\n\t\t},\n\t\tinclude: [\"src/**/*\"],\n\t},\n\tnull,\n\t\"\\t\",\n)}\\n`;\n\n/** Lines `init` makes sure `.gitignore` has. */\nexport const GITIGNORE = [\n\t\"node_modules/\",\n\t\"output/\",\n\t\"scratch/\",\n\t\".DS_Store\",\n\t\".env\",\n];\n\n/** Where the AI gateway's keys come from. */\nexport const AI_DASHBOARD = \"https://framefields.dev/dashboard\";\n\n/** Optional settings; `render.ts` loads `.env` when there is one. Commit this, not `.env`. */\nexport const ENV_EXAMPLE = `# Copy to .env (git-ignored). Everything here is optional.\n\n# framefields AI gateway: generate images, video, music, voice and 3D from code.\n# Create a key at ${AI_DASHBOARD}\nFRAMEFIELDS_API_KEY=\n`;\n\n/** Media, LUTs and fonts go to Git LFS; renders stay out of Git. */\nexport const GITATTRIBUTES = [\n\t\"assets/**/*.mp4 filter=lfs diff=lfs merge=lfs -text\",\n\t\"assets/**/*.mov filter=lfs diff=lfs merge=lfs -text\",\n\t\"assets/**/*.webm filter=lfs diff=lfs merge=lfs -text\",\n\t\"assets/**/*.mp3 filter=lfs diff=lfs merge=lfs -text\",\n\t\"assets/**/*.wav filter=lfs diff=lfs merge=lfs -text\",\n\t\"assets/**/*.cube filter=lfs diff=lfs merge=lfs -text\",\n\t\"assets/**/*.lottie filter=lfs diff=lfs merge=lfs -text\",\n\t\"assets/fonts/**/*.ttf filter=lfs diff=lfs merge=lfs -text\",\n\t\"assets/fonts/**/*.otf filter=lfs diff=lfs merge=lfs -text\",\n];\n\nexport const THEME_TS = `import { registerFonts as registerInstalledFonts } from \"./components/fonts.js\";\n\nexport const W = 1920;\nexport const H = 1080;\nexport const FPS = 30;\nexport const INK = \"#0E0D0C\";\nexport const PAPER = \"#EEE9E0\";\n/** Installed by \\`framefields init\\` (assets/fonts), registered below. */\nexport const SANS = \"Inter\";\nexport const MONO = \"JetBrains Mono\";\n\n/**\n * Register the film's fonts. Fonts framefields installed\n * (\\`npx framefields fonts add <role>\\`) come from the generated\n * components/fonts.ts; register any others here with \\`FontManager.register\\`.\n */\nexport async function registerFonts(): Promise<void> {\n\tawait registerInstalledFonts();\n}\n`;\n\nexport const FILM_TS = `import { Composition, Layer, LayerAnimation } from \"framefields\";\nimport { FPS, H, INK, PAPER, registerFonts, SANS, W } from \"./theme.js\";\n\nconst DURATION = 3 * FPS; // frames\n\n/** Builds the film. Only builds: no rendering or writes, so tests, the preview and renders share it. */\nexport async function buildFilm(): Promise<Composition> {\n\t// Fonts must be registered before any text layer is built.\n\tawait registerFonts();\n\n\tconst film = new Composition({\n\t\twidth: W,\n\t\theight: H,\n\t\tfps: FPS,\n\t\tdurationMs: (DURATION / FPS) * 1000,\n\t\tbackgroundColor: INK,\n\t});\n\n\tfilm.add(\n\t\tLayer.text(\"Hello, framefields\", {\n\t\t\tid: \"title\",\n\t\t\tposition: \"absolute\",\n\t\t\tx: 0,\n\t\t\ty: H / 2 - 60,\n\t\t\twidth: W,\n\t\t\theight: 120,\n\t\t\tfontFamily: SANS,\n\t\t\tfontSize: 96,\n\t\t\tfontWeight: 700,\n\t\t\tfill: PAPER,\n\t\t\talign: \"center\",\n\t\t}).animate(\n\t\t\tLayerAnimation.create()\n\t\t\t\t.fadeIn(0, 20, \"power2.out\")\n\t\t\t\t.fromTo(\"y\", H / 2 - 20, H / 2 - 60, {\n\t\t\t\t\tstart: 0,\n\t\t\t\t\tend: 30,\n\t\t\t\t\tease: \"expo.out\",\n\t\t\t\t}),\n\t\t),\n\t);\n\n\treturn film;\n}\n`;\n\nexport const RENDER_TS = `import { existsSync } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { HeadlessMediaRenderer, frameCount, startPreview } from \"framefields\";\nimport { buildFilm } from \"./film.js\";\n\n// Optional settings such as FRAMEFIELDS_API_KEY (see .env.example).\nconst ENV = path.resolve(import.meta.dirname, \"../.env\");\nif (existsSync(ENV)) process.loadEnvFile(ENV);\n\nconst OUT = path.resolve(import.meta.dirname, \"../output\");\n// \\`npm run frames -- 0 30\\` needs the \\`--\\`; pnpm passes it through: drop it.\nconst [mode = \"video\", ...args] = process.argv\n\t.slice(2)\n\t.filter((a) => a !== \"--\");\n\nif (mode === \"preview\") {\n\t// The page runs film.ts itself and renders it with WebGPU in the browser.\n\tconst session = await startPreview({\n\t\tentry: new URL(\"./film.ts\", import.meta.url),\n\t\texport: \"buildFilm\",\n\t});\n\tconsole.log(\\`Preview at \\${session.url}\\`);\n\tawait session.closed; // until its tab closes or the next preview replaces it\n\tprocess.exit(0);\n}\n\nconst film = await buildFilm();\nawait fs.mkdir(OUT, { recursive: true });\n\nif (mode === \"frames\") {\n\tconst renderer = new HeadlessMediaRenderer();\n\tfor (const frame of (args.length ? args : [\"0\"]).map(Number)) {\n\t\tconst png = await film.renderFrame({ frame, renderer });\n\t\tconst file = path.join(OUT, \\`f\\${String(frame).padStart(4, \"0\")}.png\\`);\n\t\tawait fs.writeFile(file, png);\n\t\tconsole.log(\\`Wrote \\${path.relative(process.cwd(), file)}\\`);\n\t}\n} else if (mode === \"grid\") {\n\tconst png = await film.renderFrameGrid({\n\t\tframes: args.length ? args.map(Number) : [...new Set([0, Math.floor((frameCount(film.durationMs ?? await film.computeDuration(), film.fps) - 1) / 2), frameCount(film.durationMs ?? await film.computeDuration(), film.fps) - 1])],\n\t\tcolumns: 4,\n\t\tcellWidth: 480,\n\t\tshowLabels: true,\n\t});\n\tawait fs.writeFile(path.join(OUT, \"grid.png\"), png);\n\tconsole.log(\"Wrote output/grid.png\");\n} else {\n\tconst result = await film.renderVideo({\n\t\toutputPath: path.join(OUT, \"output.mp4\"),\n\t\tquality: \"high\",\n\t});\n\tawait result.cleanup?.();\n\tconsole.log(\\`Exported \\${result.filePath}\\`);\n}\n\n// Native GPU and encoder threads keep Node alive; always exit explicitly.\nprocess.exit(0);\n`;\n\nexport function readme(name: string, run: (script: string) => string): string {\n\treturn `# ${name}\n\nA film built with [framefields](https://www.npmjs.com/package/framefields).\n\n\\`\\`\\`bash\n${run(\"typecheck\")}\n${run(\"frames\")} -- 0 30 60 # PNGs in output/\n${run(\"grid\")} # a contact sheet of the motion\n${run(\"preview\")} # play it in the browser\n${run(\"render\")} # output/output.mp4\n${run(\"render:cloud\")} # on cloud GPUs, from the pushed commit\n\\`\\`\\`\n\n- \\`framefields.json\\` names the renders: \\`film\\` is \\`buildFilm\\` in \\`src/film.ts\\`. Add an\n entry under \\`renders\\` for each cut (a teaser, a vertical edit) and render or check it by\n name: \\`npx framefields render teaser --cloud\\`, \\`npx framefields check teaser\\`.\n- \\`src/film.ts\\` builds the composition, \\`src/theme.ts\\` holds sizes, colors and fonts,\n \\`src/render.ts\\` renders it.\n- \\`npx framefields list\\` shows ready-made components; \\`npx framefields add <name>\\` copies\n one into \\`src/components/\\`.\n- Optional: the AI gateway generates images, video, music, voice and 3D from code. Copy\n \\`.env.example\\` to \\`.env\\` and set \\`FRAMEFIELDS_API_KEY\\` (keys at ${AI_DASHBOARD}).\n- \\`render:cloud\\` renders on framefields' GPUs with the same key, and splits a long film\n across several (\\`-- --plan\\` shows workers, time and cost first). It renders the\n commit you pushed, not uncommitted changes.\n- Footage, audio and fonts live in \\`assets/\\` and are tracked with Git LFS\n (\\`git lfs install\\` once per machine, \\`git lfs pull\\` after cloning).\n`;\n}\n","/**\n * `framefields init [dir]`: a new framefields project, or framefields added\n * to an existing one. Writes the layout the setup skill describes\n * (`package.json` with the install-script approvals framefields needs,\n * `tsconfig.json`, `src/theme.ts` / `film.ts` / `render.ts`, `assets/`,\n * LFS `.gitattributes`, `.gitignore`), installs the default fonts\n * (Inter, JetBrains Mono, and Noto Color Emoji) and keeps them registered\n * in `src/components/fonts.ts`.\n *\n * It never overwrites: files that exist are left alone, and `package.json`,\n * `.gitignore` and `.gitattributes` gain only what they're missing.\n */\nimport { spawn } from \"node:child_process\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, dirname, join, relative, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { CONFIG_FILE, readConfig, writeConfig } from \"./config.js\";\nimport {\n\ttype Fetch,\n\ttype FontInstall,\n\ttype FontSpec,\n\ttype FontsModule,\n\tinstallFont,\n\twriteFontsModule,\n} from \"./fonts.js\";\nimport {\n\tdefaultRenders,\n\tENV_EXAMPLE,\n\tFILM_TS,\n\tGITATTRIBUTES,\n\tGITIGNORE,\n\tpackageFields,\n\tRENDER_TS,\n\treadme,\n\tTHEME_TS,\n\tTSCONFIG,\n} from \"./templates.js\";\n\nexport const PACKAGE_MANAGERS = [\"npm\", \"pnpm\", \"yarn\", \"bun\"] as const;\nexport type PackageManager = (typeof PACKAGE_MANAGERS)[number];\n\n/** Runs a command; resolves with its exit code (127 when it can't start). */\nexport type Runner = (\n\tcommand: string,\n\targs: string[],\n\toptions: { cwd: string; quiet?: boolean },\n) => Promise<number>;\n\nexport interface InitOptions {\n\t/** Where the command runs. */\n\tcwd: string;\n\t/** The project folder, relative to `cwd`. Default `.`. */\n\tdir?: string;\n\t/** Package name. Default: the folder's name, made npm-safe. */\n\tname?: string;\n\t/** Default: the one running the command (`npm_config_user_agent`), else npm. */\n\tpackageManager?: PackageManager;\n\t/** `npm_config_user_agent`, for detecting the package manager and its version. */\n\tuserAgent?: string;\n\t/** Install the default fonts: Inter, JetBrains Mono, and Noto Color Emoji (default true). */\n\tfonts?: boolean;\n\t/** Also install the color emoji font (default true when fonts is true). */\n\temoji?: boolean;\n\t/** `git init` when the folder isn't in a repository yet (default true). */\n\tgit?: boolean;\n\t/** Run the package manager's install afterwards (default false). */\n\tinstall?: boolean;\n\t/** framefields version for `dependencies`. Default: this package's. */\n\tframefieldsVersion?: string;\n\t/** For tests. */\n\trun?: Runner;\n\tfetch?: Fetch;\n\tfontCatalog?: Record<string, FontSpec>;\n\tonDownload?: (spec: FontSpec) => void;\n}\n\nexport interface InitReport {\n\t/** The project folder (absolute). */\n\troot: string;\n\tname: string;\n\tpackageManager: PackageManager;\n\t/** Paths relative to `root`. */\n\twritten: string[];\n\t/** Existing files that gained missing entries. */\n\tmerged: string[];\n\t/** Existing files left as they were. */\n\tunchanged: string[];\n\tfonts: FontInstall[];\n\tfontsModule: FontsModule;\n\tgit: \"initialized\" | \"existing\" | \"skipped\" | \"unavailable\";\n\t/** Whether `git lfs` is available (null when Git was skipped). */\n\tlfs: boolean | null;\n\tinstalled: boolean;\n\t/** `npm run frames` / `pnpm frames` …, for next-step messages. */\n\trunScript(script: string): string;\n}\n\n/** The package manager in `npm_config_user_agent` (`pnpm/10.13.1 npm/? node/v22 …`). */\nexport function detectPackageManager(\n\tuserAgent: string | undefined,\n): { name: PackageManager; version?: string } | null {\n\tconst m = userAgent?.match(/^(npm|pnpm|yarn|bun)\\/(\\d[\\w.+-]*)/);\n\tif (!m) return null;\n\treturn { name: m[1] as PackageManager, version: m[2] };\n}\n\nconst runScriptFor = (pm: PackageManager) => (script: string) =>\n\tpm === \"npm\" || pm === \"bun\" ? `${pm} run ${script}` : `${pm} ${script}`;\n\n/** `My Film!` → `my-film`. */\nexport function packageName(folder: string): string {\n\tconst name = folder\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9._~-]+/g, \"-\")\n\t\t.replace(/^[-._]+|[-._]+$/g, \"\");\n\treturn name || \"framefields-film\";\n}\n\nexport async function init(options: InitOptions): Promise<InitReport> {\n\tconst root = resolve(options.cwd, options.dir ?? \".\");\n\tmkdirSync(root, { recursive: true });\n\tconst detected = detectPackageManager(options.userAgent);\n\tconst pm = options.packageManager ?? detected?.name ?? \"npm\";\n\tconst pmVersion = detected?.name === pm ? detected.version : undefined;\n\tconst run = options.run ?? spawnRunner;\n\tconst report: InitReport = {\n\t\troot,\n\t\tname: \"\",\n\t\tpackageManager: pm,\n\t\twritten: [],\n\t\tmerged: [],\n\t\tunchanged: [],\n\t\tfonts: [],\n\t\tfontsModule: { path: \"\", status: \"unchanged\", calls: [] },\n\t\tgit: \"skipped\",\n\t\tlfs: null,\n\t\tinstalled: false,\n\t\trunScript: runScriptFor(pm),\n\t};\n\tconst fields = packageFields({\n\t\tframefieldsVersion: options.framefieldsVersion ?? ownVersion(),\n\t\t...(pmVersion && { packageManager: `${pm}@${pmVersion}` }),\n\t});\n\n\t// package.json: written whole, or merged without replacing anything.\n\tconst pkgPath = join(root, \"package.json\");\n\tif (existsSync(pkgPath)) {\n\t\tconst pkg = JSON.parse(readFileSync(pkgPath, \"utf8\")) as Record<\n\t\t\tstring,\n\t\t\tunknown\n\t\t>;\n\t\tif (pkg.type === \"commonjs\")\n\t\t\tthrow new Error(\n\t\t\t\t'package.json has \"type\": \"commonjs\". framefields projects are ES modules: set \"type\": \"module\" (and convert any require() files) first.',\n\t\t\t);\n\t\treport.name =\n\t\t\ttypeof pkg.name === \"string\" ? pkg.name : packageName(basename(root));\n\t\tconst merged = mergePackage(pkg, fields);\n\t\trecord(report, \"package.json\", writeIfChanged(pkgPath, merged, pkg));\n\t} else {\n\t\treport.name = options.name ?? packageName(basename(root));\n\t\twriteJson(pkgPath, {\n\t\t\tname: report.name,\n\t\t\tversion: \"0.0.0\",\n\t\t\tprivate: true,\n\t\t\t...fields,\n\t\t});\n\t\treport.written.push(\"package.json\");\n\t}\n\n\tconst files: Array<[string, string]> = [\n\t\t[\"tsconfig.json\", TSCONFIG],\n\t\t[\"src/theme.ts\", THEME_TS],\n\t\t[\"src/film.ts\", FILM_TS],\n\t\t[\"src/render.ts\", RENDER_TS],\n\t\t[\"assets/footage/.gitkeep\", \"\"],\n\t\t[\".env.example\", ENV_EXAMPLE],\n\t\t[\"README.md\", readme(report.name, report.runScript)],\n\t];\n\tfor (const [path, content] of files) {\n\t\tconst target = join(root, path);\n\t\tif (existsSync(target)) report.unchanged.push(path);\n\t\telse {\n\t\t\tmkdirSync(dirname(target), { recursive: true });\n\t\t\twriteFileSync(target, content);\n\t\t\treport.written.push(path);\n\t\t}\n\t}\n\tfor (const [path, lines] of [\n\t\t[\".gitignore\", GITIGNORE],\n\t\t[\".gitattributes\", GITATTRIBUTES],\n\t] as const)\n\t\trecord(report, path, appendLines(join(root, path), lines));\n\n\t// framefields.json (components folder, named renders), then fonts (recorded there) and their module.\n\tconst configExisted = existsSync(join(root, CONFIG_FILE));\n\tconst { config, saved } = readConfig(root);\n\tif (!saved || !config.renders) {\n\t\twriteConfig(root, {\n\t\t\t...config,\n\t\t\trenders: config.renders ?? defaultRenders(basename(root)),\n\t\t});\n\t\trecord(report, CONFIG_FILE, configExisted || \"written\");\n\t}\n\tconst installFonts = options.fonts !== false;\n\tconst installEmoji = options.emoji ?? installFonts;\n\tconst roles = [\n\t\t...(installFonts ? [\"sans\", \"mono\"] : []),\n\t\t...(installEmoji ? [\"emoji\"] : []),\n\t];\n\tfor (const role of roles)\n\t\treport.fonts.push(\n\t\t\tawait installFont(role, {\n\t\t\t\tcwd: root,\n\t\t\t\tfetch: options.fetch,\n\t\t\t\tcatalog: options.fontCatalog,\n\t\t\t\tonDownload: options.onDownload,\n\t\t\t}),\n\t\t);\n\t// theme.ts imports it, so it's written even with no fonts installed.\n\treport.fontsModule = writeFontsModule(\n\t\troot,\n\t\tresolve(root, readConfig(root).config.components),\n\t\toptions.fontCatalog,\n\t);\n\n\tif (options.git !== false) {\n\t\tconst inside = await run(\"git\", [\"rev-parse\", \"--is-inside-work-tree\"], {\n\t\t\tcwd: root,\n\t\t\tquiet: true,\n\t\t});\n\t\tif (inside === 0) report.git = \"existing\";\n\t\telse if (\n\t\t\t(await run(\"git\", [\"init\", \"-q\"], { cwd: root, quiet: true })) === 0\n\t\t)\n\t\t\treport.git = \"initialized\";\n\t\telse report.git = \"unavailable\";\n\t\tif (report.git !== \"unavailable\")\n\t\t\treport.lfs =\n\t\t\t\t(await run(\"git\", [\"lfs\", \"version\"], { cwd: root, quiet: true })) ===\n\t\t\t\t0;\n\t}\n\n\tif (options.install) {\n\t\tconst code = await run(pm, [\"install\"], { cwd: root });\n\t\tif (code !== 0)\n\t\t\tthrow new Error(\n\t\t\t\t`\\`${pm} install\\` failed (exit ${code}). The project files are written; fix the error and run it again.`,\n\t\t\t);\n\t\treport.installed = true;\n\t}\n\treturn report;\n}\n\n/** Add every field of `fields` the package lacks; existing values win. */\nfunction mergePackage(\n\tpkg: Record<string, unknown>,\n\tfields: ReturnType<typeof packageFields>,\n): Record<string, unknown> {\n\tconst out: Record<string, unknown> = { ...pkg };\n\tconst obj = (v: unknown) =>\n\t\tv && typeof v === \"object\" && !Array.isArray(v)\n\t\t\t? (v as Record<string, unknown>)\n\t\t\t: {};\n\tconst union = (a: unknown, b: readonly string[]) => [\n\t\t...new Set([...(Array.isArray(a) ? (a as string[]) : []), ...b]),\n\t];\n\tout.type ??= fields.type;\n\tif (fields.packageManager) out.packageManager ??= fields.packageManager;\n\tfor (const key of [\n\t\t\"scripts\",\n\t\t\"dependencies\",\n\t\t\"devDependencies\",\n\t\t\"allowScripts\",\n\t] as const) {\n\t\tconst theirs = obj(pkg[key]);\n\t\t// A dependency listed in either block counts as present.\n\t\tconst present =\n\t\t\tkey === \"dependencies\" || key === \"devDependencies\"\n\t\t\t\t? { ...obj(pkg.dependencies), ...obj(pkg.devDependencies) }\n\t\t\t\t: theirs;\n\t\tconst missing = Object.entries(fields[key]).filter(\n\t\t\t([k]) => !(k in present),\n\t\t);\n\t\tif (missing.length > 0)\n\t\t\tout[key] = { ...theirs, ...Object.fromEntries(missing) };\n\t}\n\tconst pnpm = obj(pkg.pnpm);\n\tout.pnpm = {\n\t\t...pnpm,\n\t\tonlyBuiltDependencies: union(\n\t\t\tpnpm.onlyBuiltDependencies,\n\t\t\tfields.pnpm.onlyBuiltDependencies,\n\t\t),\n\t\tignoredBuiltDependencies: union(\n\t\t\tpnpm.ignoredBuiltDependencies,\n\t\t\tfields.pnpm.ignoredBuiltDependencies,\n\t\t),\n\t};\n\tout.trustedDependencies = union(\n\t\tpkg.trustedDependencies,\n\t\tfields.trustedDependencies,\n\t);\n\treturn out;\n}\n\nfunction writeJson(path: string, value: unknown) {\n\twriteFileSync(path, `${JSON.stringify(value, null, \"\\t\")}\\n`);\n}\n\nfunction writeIfChanged(\n\tpath: string,\n\tnext: Record<string, unknown>,\n\tprev: Record<string, unknown>,\n): boolean {\n\tif (JSON.stringify(next) === JSON.stringify(prev)) return false;\n\twriteJson(path, next);\n\treturn true;\n}\n\n/** Create `path` with `lines` (\"written\"), or append the ones it lacks (true if any). */\nfunction appendLines(\n\tpath: string,\n\tlines: readonly string[],\n): \"written\" | boolean {\n\tif (!existsSync(path)) {\n\t\twriteFileSync(path, `${lines.join(\"\\n\")}\\n`);\n\t\treturn \"written\";\n\t}\n\tconst text = readFileSync(path, \"utf8\");\n\tconst have = new Set(text.split(/\\r?\\n/).map((l) => l.trim()));\n\tconst missing = lines.filter((l) => !have.has(l));\n\tif (missing.length === 0) return false;\n\twriteFileSync(\n\t\tpath,\n\t\t`${text}${text.endsWith(\"\\n\") || text === \"\" ? \"\" : \"\\n\"}${missing.join(\"\\n\")}\\n`,\n\t);\n\treturn true;\n}\n\n/** File it under written (new), merged (changed) or unchanged. */\nfunction record(report: InitReport, path: string, result: \"written\" | boolean) {\n\tif (result === \"written\") report.written.push(path);\n\telse if (result) report.merged.push(path);\n\telse report.unchanged.push(path);\n}\n\n/** This package's version, from the nearest `package.json` named framefields. */\nexport function ownVersion(): string {\n\tlet dir = dirname(fileURLToPath(import.meta.url));\n\tfor (;;) {\n\t\tconst file = join(dir, \"package.json\");\n\t\tif (existsSync(file)) {\n\t\t\tconst pkg = JSON.parse(readFileSync(file, \"utf8\")) as {\n\t\t\t\tname?: string;\n\t\t\t\tversion?: string;\n\t\t\t};\n\t\t\tif (pkg.name === \"framefields\" && pkg.version) return pkg.version;\n\t\t}\n\t\tconst up = dirname(dir);\n\t\tif (up === dir) throw new Error(\"Can't find framefields' own package.json\");\n\t\tdir = up;\n\t}\n}\n\nconst spawnRunner: Runner = (command, args, { cwd, quiet }) =>\n\tnew Promise((done) => {\n\t\tconst child = spawn(command, args, {\n\t\t\tcwd,\n\t\t\tstdio: quiet ? \"ignore\" : \"inherit\",\n\t\t\t// Windows needs a shell to find npm.cmd / pnpm.cmd.\n\t\t\tshell: process.platform === \"win32\",\n\t\t});\n\t\tchild.on(\"error\", () => done(127));\n\t\tchild.on(\"close\", (code) => done(code ?? 1));\n\t});\n\n/** Where the project is, as the user would `cd` to it. */\nexport function shownPath(cwd: string, root: string): string {\n\treturn relative(cwd, root) || \".\";\n}\n","import { spawn } from \"node:child_process\";\nimport { createRequire } from \"node:module\";\nimport { resolve } from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport { type CheckReport, failedCheck } from \"./check-result.js\";\nimport { ownVersion } from \"./init.js\";\n\nexport interface CheckOptions {\n\t/** Module path, resolved from the project working directory. */\n\tentry: string;\n\t/** Composition or builder export. Defaults to buildFilm. */\n\texportName?: string;\n\t/** Also probe the GPU and write a representative PNG and bounded grid. */\n\trender?: boolean;\n\t/** Artifact directory. Defaults to output/check, relative to the working directory. */\n\toutputDir?: string;\n\t/** Maximum worker lifetime in milliseconds. Defaults to 60000. */\n\ttimeoutMs?: number;\n\t/** Treat lint warnings as a failed check. Defaults to false. */\n\twarningsAsErrors?: boolean;\n}\n\n/** The worker's IPC result is separate from arbitrary builder stdout/stderr. */\nexport async function runCheck(options: CheckOptions): Promise<CheckReport> {\n\tconst entry = resolve(options.entry);\n\tconst exportName = options.exportName ?? \"buildFilm\";\n\tconst sdkVersion = ownVersion();\n\tconst timeout = options.timeoutMs ?? 60_000;\n\tif (!Number.isSafeInteger(timeout) || timeout <= 0)\n\t\tthrow new Error(\"--timeout must be a positive integer in milliseconds\");\n\tconst fail = (code: string, message: string) =>\n\t\tfailedCheck(entry, exportName, sdkVersion, code, message);\n\tconst source = import.meta.url.endsWith(\".ts\");\n\tconst args = source ? [\"--conditions=development\"] : [];\n\t// TypeScript belongs to the consumer project; it is already in init's scaffold.\n\tif (source || /\\.[cm]?tsx?$/.test(entry)) {\n\t\ttry {\n\t\t\tconst require = createRequire(resolve(\"package.json\"));\n\t\t\targs.push(\"--import\", pathToFileURL(require.resolve(\"tsx\")).href);\n\t\t} catch {\n\t\t\treturn fail(\n\t\t\t\t\"missing_ts_loader\",\n\t\t\t\t\"Install the project's tsx dev dependency to check a TypeScript entry.\",\n\t\t\t);\n\t\t}\n\t}\n\targs.push(\n\t\tfileURLToPath(\n\t\t\tnew URL(\n\t\t\t\tsource ? \"./check-worker.ts\" : \"./cli/check-worker.mjs\",\n\t\t\t\timport.meta.url,\n\t\t\t),\n\t\t),\n\t);\n\treturn new Promise((done) => {\n\t\tconst child = spawn(process.execPath, args, {\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\", \"ipc\"],\n\t\t});\n\t\tchild.stdout?.pipe(process.stderr);\n\t\tchild.stderr?.pipe(process.stderr);\n\t\tlet result: CheckReport | undefined;\n\t\tconst timer = setTimeout(() => {\n\t\t\tresult = fail(\n\t\t\t\t\"check_timeout\",\n\t\t\t\t`Check exceeded ${timeout}ms; worker terminated.`,\n\t\t\t);\n\t\t\tchild.kill(\"SIGKILL\");\n\t\t}, timeout);\n\t\tchild.on(\"message\", (message: unknown) => {\n\t\t\tif (isCheckReport(message)) result = message;\n\t\t});\n\t\tchild.on(\"error\", (error) => {\n\t\t\tclearTimeout(timer);\n\t\t\tdone(fail(\"worker_start_failed\", error.message));\n\t\t});\n\t\tchild.on(\"close\", (code, signal) => {\n\t\t\tclearTimeout(timer);\n\t\t\tdone(\n\t\t\t\tresult ??\n\t\t\t\t\tfail(\n\t\t\t\t\t\t\"worker_failed\",\n\t\t\t\t\t\t`Check worker exited without a result (code ${code}, signal ${signal}).`,\n\t\t\t\t\t),\n\t\t\t);\n\t\t});\n\t\tchild.send({\n\t\t\t...options,\n\t\t\tentry,\n\t\t\texportName,\n\t\t\tsdkVersion,\n\t\t\toutputDir: resolve(options.outputDir ?? \"output/check\"),\n\t\t});\n\t});\n}\n\nfunction isCheckReport(value: unknown): value is CheckReport {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"schemaVersion\" in value &&\n\t\tvalue.schemaVersion === 1 &&\n\t\t\"diagnostics\" in value &&\n\t\tArray.isArray(value.diagnostics)\n\t);\n}\n","/**\n * `framefields render <name|entry> --cloud`: renders the project on\n * api.framefields.dev and downloads the video. `name` is a render in\n * framefields.json; a module path renders without one. Prints one plain\n * line per phase, and a progress line at most every 10 seconds while\n * frames render.\n */\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport {\n\tCloudRenderError,\n\ttype CloudRenderOptions,\n\ttype CloudRenderStatus,\n\trenderCloud,\n} from \"../cloud/index.js\";\nimport { CONFIG_FILE, findRender, readConfig } from \"./config.js\";\n\nexport interface CloudCliOptions {\n\t/** A render named in framefields.json, or a module path. Optional when framefields.json has one render. */\n\tentry?: string;\n\texport?: string;\n\tselect?: string;\n\tworkers?: string;\n\tmaxWorkers?: string;\n\tcodec?: string;\n\tquality?: string;\n\toutput?: string;\n\tplan?: boolean;\n\tjson?: boolean;\n\t/** Project folder. Default `process.cwd()`. */\n\tcwd?: string;\n}\n\nconst PROGRESS_EVERY_MS = 10_000;\n\nexport async function runCloudRender(\n\to: CloudCliOptions,\n\tlog: (line: string) => void,\n\trender: (\n\t\toptions: CloudRenderOptions,\n\t) => Promise<CloudRenderStatus> = renderCloud,\n): Promise<number> {\n\tconst cwd = o.cwd ?? process.cwd();\n\tconst workers = parseWorkers(o.workers);\n\tif (workers === null) {\n\t\tlog(\n\t\t\t`--workers must be \"auto\" or a positive whole number, not \"${o.workers}\".`,\n\t\t);\n\t\treturn 2;\n\t}\n\tif (o.codec && o.codec !== \"h264\" && o.codec !== \"vp9\") {\n\t\tlog(`--codec must be h264 or vp9, not \"${o.codec}\".`);\n\t\treturn 2;\n\t}\n\tconst target = pickRender(o.entry, cwd);\n\tif (\"error\" in target) {\n\t\tlog(target.error);\n\t\treturn 2;\n\t}\n\tconst spec = target.name ? findRender(cwd, target.name) : undefined;\n\tconst codec = (o.codec ?? spec?.codec ?? \"h264\") as \"h264\" | \"vp9\";\n\tconst outputPath =\n\t\to.output ??\n\t\tspec?.output ??\n\t\tpath.join(\n\t\t\t\"output\",\n\t\t\t`${target.name ?? path.basename(target.entry ?? \"\").replace(/\\.[^.]+$/, \"\")}.${codec === \"vp9\" ? \"webm\" : \"mp4\"}`,\n\t\t);\n\t// A plan of a one-worker render would only ever say \"one worker\".\n\tconst planWorkers =\n\t\to.plan && (workers ?? spec?.workers ?? 1) === 1 ? \"auto\" : workers;\n\tconst controller = new AbortController();\n\tconst onSigint = () => {\n\t\tlog(\"Cancelling the cloud render…\");\n\t\tcontroller.abort(new Error(\"cancelled\"));\n\t};\n\tprocess.once(\"SIGINT\", onSigint);\n\tconst started = Date.now();\n\tconst narrate = narrator(o.json ? () => {} : log, Date.now);\n\ttry {\n\t\tconst result = await render({\n\t\t\tcwd,\n\t\t\trender: target.name,\n\t\t\tentry: target.entry,\n\t\t\texport: o.export,\n\t\t\tselect: o.select,\n\t\t\tworkers: planWorkers,\n\t\t\tmaxWorkers: o.maxWorkers ? Number(o.maxWorkers) : undefined,\n\t\t\tcodec: o.codec as \"h264\" | \"vp9\" | undefined,\n\t\t\tquality: o.quality,\n\t\t\tdryRun: o.plan,\n\t\t\toutputPath: o.plan ? undefined : outputPath,\n\t\t\tsignal: controller.signal,\n\t\t\tonProgress: narrate,\n\t\t\tonWarning: (m) => log(`warning: ${m}`),\n\t\t});\n\t\tif (o.json) {\n\t\t\tlog(JSON.stringify(result));\n\t\t\treturn 0;\n\t\t}\n\t\tif (result.status === \"planned\") {\n\t\t\tconst planned = planWorkers === \"auto\" && spec?.workers !== \"auto\";\n\t\t\tlog(\n\t\t\t\t`Render it: ${renderCommand({ ...o, entry: target.name ?? target.entry, workers: o.workers ?? (planned ? \"auto\" : undefined) })}`,\n\t\t\t);\n\t\t\treturn 0;\n\t\t}\n\t\tconst bytes = result.output?.bytes;\n\t\tlog(\n\t\t\t`Done in ${duration((Date.now() - started) / 1000)}: ${outputPath}${bytes ? ` (${(bytes / 1e6).toFixed(1)} MB)` : \"\"}, ${Math.round(result.gpuSeconds)} GPU seconds, ${usd(result.costUsd)}.`,\n\t\t);\n\t\treturn 0;\n\t} catch (err) {\n\t\tif (err instanceof CloudRenderError) {\n\t\t\tlog(err.message);\n\t\t\tif (err.status && err.status.costUsd > 0)\n\t\t\t\tlog(`Charged ${usd(err.status.costUsd)} for the GPU time used.`);\n\t\t\tif (err.code === \"insufficient_credits\")\n\t\t\t\tlog(\"Top up at https://framefields.dev/dashboard/billing\");\n\t\t\treturn 1;\n\t\t}\n\t\tthrow err;\n\t} finally {\n\t\tprocess.removeListener(\"SIGINT\", onSigint);\n\t}\n}\n\n/** The command that renders what `--plan` just planned: the same options, without `--plan`. */\nexport function renderCommand(o: CloudCliOptions): string {\n\tconst flags: [string, string | undefined][] = [\n\t\t[\"--export\", o.export],\n\t\t[\"--select\", o.select],\n\t\t[\"--workers\", o.workers],\n\t\t[\"--max-workers\", o.maxWorkers],\n\t\t[\"--codec\", o.codec],\n\t\t[\"--quality\", o.quality],\n\t\t[\"--output\", o.output],\n\t];\n\treturn [\n\t\t`framefields render ${o.entry ?? \"\"} --cloud`.replace(\" \", \" \"),\n\t\t...flags.filter(([, v]) => v !== undefined).map(([f, v]) => `${f} ${v}`),\n\t].join(\" \");\n}\n\n/**\n * What `framefields render [arg]` renders: a render named in framefields.json,\n * or a module path; with no argument, the project's only named render.\n */\nexport function pickRender(\n\targ: string | undefined,\n\tcwd: string,\n): { name?: string; entry?: string } | { error: string } {\n\tconst renders = readConfig(cwd).config.renders ?? {};\n\tconst names = Object.keys(renders);\n\tif (arg === undefined) {\n\t\tif (names.length === 1) return { name: names[0] };\n\t\treturn {\n\t\t\terror: names.length\n\t\t\t\t? `Name the render: ${names.join(\", \")}. \\`framefields renders\\` lists them.`\n\t\t\t\t: `Name a module, e.g. \\`framefields render src/film.ts --cloud\\`, or add \"renders\" to ${CONFIG_FILE}.`,\n\t\t};\n\t}\n\tif (renders[arg]) return { name: arg };\n\tif (existsSync(path.resolve(cwd, arg))) return { entry: arg };\n\treturn {\n\t\terror: names.length\n\t\t\t? `\"${arg}\" is neither a render in ${CONFIG_FILE} (${names.join(\", \")}) nor a file.`\n\t\t\t: `\"${arg}\" is not a file, and ${CONFIG_FILE} names no renders.`,\n\t};\n}\n\n/** --workers: undefined when not given, null when invalid. */\nfunction parseWorkers(\n\tvalue: string | undefined,\n): number | \"auto\" | undefined | null {\n\tif (value === undefined) return undefined;\n\tif (value === \"auto\") return \"auto\";\n\tconst n = Number(value);\n\treturn Number.isInteger(n) && n >= 1 ? n : null;\n}\n\n/** Turns status polls into log lines: one per phase, throttled frame progress. */\nexport function narrator(\n\tlog: (line: string) => void,\n\tnow: () => number,\n): (s: CloudRenderStatus) => void {\n\tlet phase: string | undefined;\n\tlet planned = false;\n\tlet lastProgress = 0;\n\treturn (s) => {\n\t\tif (!phase) log(`Cloud render ${s.id} started.`);\n\t\tif (s.plan && !planned) {\n\t\t\tplanned = true;\n\t\t\tlog(describePlan(s));\n\t\t}\n\t\tif (s.status !== phase) {\n\t\t\tphase = s.status;\n\t\t\tconst line = phaseLine(s);\n\t\t\tif (line) log(line);\n\t\t\tlastProgress = now();\n\t\t\treturn;\n\t\t}\n\t\tif (s.status === \"rendering\" && now() - lastProgress >= PROGRESS_EVERY_MS) {\n\t\t\tlastProgress = now();\n\t\t\tlog(progressLine(s));\n\t\t}\n\t};\n}\n\nexport function describePlan(s: CloudRenderStatus): string {\n\tconst plan = s.plan;\n\tif (!plan) return \"\";\n\tconst est =\n\t\ts.estimateUsd !== undefined ? `, estimated ${usd(s.estimateUsd)}` : \"\";\n\treturn `Plan: ${plan.workers} ${plan.workers === 1 ? \"worker\" : \"workers\"}, ${duration(plan.workSec)} of render work, ready in about ${duration(plan.etaSec)}${est}.`;\n}\n\nfunction phaseLine(s: CloudRenderStatus): string | undefined {\n\tswitch (s.status) {\n\t\tcase \"probing\":\n\t\t\treturn \"Measuring frame costs on one worker to plan the split…\";\n\t\tcase \"rendering\":\n\t\t\treturn s.workers > 1\n\t\t\t\t? `Rendering ${s.workers} chunks and the audio in parallel…`\n\t\t\t\t: \"Rendering on one worker…\";\n\t\tcase \"stitching\":\n\t\t\treturn `Joining ${s.workers} chunks…`;\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nexport function progressLine(s: CloudRenderStatus): string {\n\tconst { frames, totalFrames, etaSec } = s.progress;\n\tconst share = totalFrames\n\t\t? `${Math.floor((frames / totalFrames) * 100)}% (${frames}/${totalFrames} frames)`\n\t\t: `${frames} frames`;\n\tconst eta = etaSec ? `, about ${duration(etaSec)} left` : \"\";\n\treturn `Rendering ${share}${eta}, ${usd(s.costUsd)} so far.`;\n}\n\nexport function duration(sec: number): string {\n\tconst s = Math.max(0, Math.round(sec));\n\tif (s < 90) return `${s} s`;\n\tconst m = Math.round(s / 60);\n\tif (m < 90) return `${m} min`;\n\treturn `${Math.floor(m / 60)} h ${m % 60} min`;\n}\n\nexport function usd(value: number): string {\n\treturn value > 0 && value < 0.01 ? \"<$0.01\" : `$${value.toFixed(2)}`;\n}\n","/**\n * Reading a component registry: the one shipped in this package's dist, a\n * local folder, or one served over http(s). A registry is `index.json` (the\n * entries) plus `<name>.json` per component (entry, meta and files).\n */\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport interface RegistryEntry {\n\t/** What `framefields add` takes: `logo-reveal`. */\n\tname: string;\n\t/** The factory the component exports: `LogoReveal`. */\n\ttitle: string;\n\tsummary: string;\n\ttags: readonly string[];\n\texample: string;\n\t/** Other components it imports, installed with it. */\n\tregistryDependencies: string[];\n}\n\nexport interface RegistryItem extends RegistryEntry {\n\t/** Generated from the component schema and JSDoc. */\n\tprops?: ReadonlyArray<{\n\t\tname: string;\n\t\ttype: string;\n\t\trequired: boolean;\n\t\tdefault?: unknown;\n\t\tdescription?: string;\n\t}>;\n\tparts: readonly string[];\n\tcues: readonly string[];\n\t/** Fonts to install with it, by role (see `cli/fonts.ts`). */\n\tfonts?: ReadonlyArray<{ font: string; why: string }>;\n\t/** Paths relative to the components directory. */\n\tfiles: Array<{ path: string; content: string }>;\n}\n\nexport interface Registry {\n\t/** Where it was read from, for messages. */\n\tsource: string;\n\tindex(): Promise<RegistryEntry[]>;\n\titem(name: string): Promise<RegistryItem>;\n}\n\n/** The registry shipped next to this module in dist (`dist/registry`). */\nexport function bundledRegistryPath(): string {\n\treturn fileURLToPath(new URL(\"./registry/\", import.meta.url));\n}\n\n/** `source`: a folder or an http(s) URL. Default: the bundled registry. */\nexport function openRegistry(source?: string, cwd = process.cwd()): Registry {\n\tconst from =\n\t\tsource ?? process.env.FRAMEFIELDS_REGISTRY ?? bundledRegistryPath();\n\tif (/^https?:\\/\\//.test(from)) {\n\t\tconst base = from.endsWith(\"/\") ? from : `${from}/`;\n\t\tconst get = async <T>(file: string): Promise<T> => {\n\t\t\tconst res = await fetch(new URL(file, base));\n\t\t\tif (!res.ok)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${new URL(file, base)}: ${res.status} ${res.statusText}`,\n\t\t\t\t);\n\t\t\treturn (await res.json()) as T;\n\t\t};\n\t\treturn {\n\t\t\tsource: base,\n\t\t\tindex: () => get(\"index.json\"),\n\t\t\titem: (name) => get(`${name}.json`),\n\t\t};\n\t}\n\tconst dir = resolve(cwd, from);\n\tconst read = <T>(file: string): T => {\n\t\tconst path = join(dir, file);\n\t\tif (!existsSync(path)) throw new Error(`No ${file} in registry ${dir}`);\n\t\treturn JSON.parse(readFileSync(path, \"utf8\")) as T;\n\t};\n\treturn {\n\t\tsource: dir,\n\t\tindex: async () => read(\"index.json\"),\n\t\titem: async (name) => read(`${name}.json`),\n\t};\n}\n","#!/usr/bin/env node\n/**\n * The `framefields` command.\n *\n * npx framefields init [dir] start a project (or add framefields to one)\n * npx framefields add <name...> copy components into this project\n * npx framefields list the components you can add\n * npx framefields fonts add <role...> install fonts (emoji)\n * npx framefields fonts list the fonts you can install\n * npx framefields renders the renders named in framefields.json\n * npx framefields render <name> --cloud render on api.framefields.dev\n */\nimport { readFileSync } from \"node:fs\";\nimport { join, relative, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { parseArgs } from \"node:util\";\nimport { type AddReport, add } from \"./cli/add.js\";\nimport { runCheck } from \"./cli/check.js\";\nimport { runCloudRender } from \"./cli/cloud.js\";\nimport { readConfig } from \"./cli/config.js\";\nimport {\n\tFONTS,\n\ttype FontSpec,\n\tinstallFont,\n\tlfsHint,\n\twriteFontsModule,\n} from \"./cli/fonts.js\";\nimport {\n\ttype InitReport,\n\tinit,\n\townVersion,\n\tPACKAGE_MANAGERS,\n\ttype PackageManager,\n\tshownPath,\n} from \"./cli/init.js\";\nimport { openRegistry } from \"./cli/registry.js\";\nimport { AI_DASHBOARD } from \"./cli/templates.js\";\n\nconst HELP = `Usage: framefields <command> [options]\n\nCommands:\n api JSON reference generated from timing, grid and check types.\n check [name|entry]\n Build, validate and lint a composition; --render also writes a\n representative frame and grid. A render named in\n framefields.json, or a module (--export defaults to\n buildFilm); with neither, every named render.\n init [dir] Start a framefields project in dir (default: here), or add\n framefields to the project there: package.json, tsconfig,\n src/theme.ts, film.ts, render.ts, assets/, .gitignore,\n LFS .gitattributes, and the themes' fonts. Never\n overwrites; existing files only gain what they lack.\n add <name...> Copy components' source into this project (and the\n components they build on). The code is yours to edit.\n list List the components you can add.\n fonts add <role...>\n Install fonts (pinned, hash-checked, with their license)\n and register them in the generated <components>/fonts.ts.\n fonts list List the fonts you can install.\n renders List the renders named in framefields.json.\n render [name|entry] --cloud\n Render on api.framefields.dev from the pushed commit of\n this git repo, and download the video. Needs\n FRAMEFIELDS_API_KEY. A render named in framefields.json\n (its fields are the defaults; flags override them), or a\n module (--export defaults to buildFilm). Without either,\n the project's only named render.\n\nOptions for check:\n --export <name> Composition or builder export (default buildFilm).\n --render Also verify the GPU and render a small frame/grid.\n --output <dir> Inspection artifacts (default output/check).\n --timeout <ms> Worker timeout in milliseconds (default 60000).\n --warnings-as-errors Fail on lint warnings.\n --json Machine-readable check, component list, or font list result.\n\nOptions for render --cloud:\n --workers <n|auto> 1 (default) renders on one GPU. auto measures the film\n first and splits it across as many GPUs as stay\n efficient; a number splits it into that many.\n --max-workers <n> Upper bound for auto.\n --plan Measure and plan only: prints workers, time and the\n estimated cost, renders nothing.\n --output <file> Where the video goes (default output/<name>.mp4).\n --codec <codec> h264 (default) or vp9.\n --quality <q> very_low, low, high or very_high (default).\n --select <name> When the export returns several compositions.\n --json Print the final status as JSON.\n Ctrl-C cancels the render; GPU time already used is charged.\n\nOptions for init:\n --name <name> Package name (default: the folder's name).\n --pm <manager> npm, pnpm, yarn or bun (default: the one running this).\n --install Install dependencies afterwards.\n --no-fonts Skip fonts (Inter, JetBrains Mono, Noto Color Emoji).\n --no-emoji Skip the color emoji font.\n --no-git Don't run \\`git init\\`.\n\nOptions for add:\n --all Add every component.\n --dir <path> Components directory (default: from framefields.json,\n else src/components or components). Saved the first time.\n --overwrite Replace files you have changed.\n --no-fonts Don't install the fonts components ask for (emoji).\n\nOptions for add and fonts add:\n --fonts-dir <path> Where downloaded fonts go (default assets/fonts).\n\nOptions for add and list:\n --registry <src> A registry folder or http(s) URL instead of the one\n shipped with this version of framefields.\n -h, --help Show this help.\n\nExamples:\n npx framefields init my-film --install\n npx framefields add mouse-pointer focus-zoom\n npx framefields fonts add emoji\n npx framefields render film --cloud --plan\n`;\n\nasync function main(argv: string[]): Promise<number> {\n\tconst { values, positionals } = parseArgs({\n\t\targs: argv,\n\t\tallowPositionals: true,\n\t\toptions: {\n\t\t\tall: { type: \"boolean\" },\n\t\t\tdir: { type: \"string\" },\n\t\t\toverwrite: { type: \"boolean\" },\n\t\t\t\"no-fonts\": { type: \"boolean\" },\n\t\t\t\"no-emoji\": { type: \"boolean\" },\n\t\t\t\"fonts-dir\": { type: \"string\" },\n\t\t\tname: { type: \"string\" },\n\t\t\tpm: { type: \"string\" },\n\t\t\tinstall: { type: \"boolean\" },\n\t\t\temoji: { type: \"boolean\" },\n\t\t\t\"no-git\": { type: \"boolean\" },\n\t\t\tregistry: { type: \"string\" },\n\t\t\tjson: { type: \"boolean\" },\n\t\t\texport: { type: \"string\" },\n\t\t\trender: { type: \"boolean\" },\n\t\t\toutput: { type: \"string\" },\n\t\t\ttimeout: { type: \"string\" },\n\t\t\t\"warnings-as-errors\": { type: \"boolean\" },\n\t\t\tcloud: { type: \"boolean\" },\n\t\t\tworkers: { type: \"string\" },\n\t\t\t\"max-workers\": { type: \"string\" },\n\t\t\tplan: { type: \"boolean\" },\n\t\t\tcodec: { type: \"string\" },\n\t\t\tquality: { type: \"string\" },\n\t\t\tselect: { type: \"string\" },\n\t\t\thelp: { type: \"boolean\", short: \"h\" },\n\t\t},\n\t});\n\tconst [command, ...names] = positionals;\n\tif (values.help || !command) {\n\t\tprocess.stdout.write(HELP);\n\t\treturn command || values.help ? 0 : 1;\n\t}\n\tconst cwd = process.cwd();\n\tconst log = (line: string) => process.stdout.write(`${line}\\n`);\n\tif (command === \"api\") {\n\t\tconst catalog = JSON.parse(\n\t\t\treadFileSync(\n\t\t\t\tfileURLToPath(\n\t\t\t\t\tnew URL(\n\t\t\t\t\t\timport.meta.url.endsWith(\".ts\") ? \"../dist/api.json\" : \"./api.json\",\n\t\t\t\t\t\timport.meta.url,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\t\"utf8\",\n\t\t\t),\n\t\t) as object;\n\t\tlog(JSON.stringify({ ...catalog, sdkVersion: ownVersion() }));\n\t\treturn 0;\n\t}\n\tif (command === \"check\") return check(names, cwd, values, log);\n\tif (command === \"renders\") return listRenders(cwd, values.json, log);\n\tif (command === \"render\") {\n\t\tif (names.length > 1 || !values.cloud) {\n\t\t\tprocess.stderr.write(\n\t\t\t\t\"Usage: framefields render [name|entry] --cloud [--workers auto] [--plan]\\nLocal renders run your project's render script (`npm run render`).\\n\",\n\t\t\t);\n\t\t\treturn 2;\n\t\t}\n\t\treturn runCloudRender(\n\t\t\t{\n\t\t\t\tentry: names[0],\n\t\t\t\texport: values.export,\n\t\t\t\tselect: values.select,\n\t\t\t\tworkers: values.workers,\n\t\t\t\tmaxWorkers: values[\"max-workers\"],\n\t\t\t\tcodec: values.codec,\n\t\t\t\tquality: values.quality,\n\t\t\t\toutput: values.output,\n\t\t\t\tplan: values.plan,\n\t\t\t\tjson: values.json,\n\t\t\t},\n\t\t\tlog,\n\t\t);\n\t}\n\tif (command === \"fonts\") return fonts(names, cwd, values, log);\n\tif (command === \"init\") {\n\t\tif (names.length > 1) {\n\t\t\tprocess.stderr.write(\n\t\t\t\t\"init takes one folder: `framefields init my-film`.\\n\",\n\t\t\t);\n\t\t\treturn 1;\n\t\t}\n\t\tif (values.pm && !PACKAGE_MANAGERS.includes(values.pm as PackageManager)) {\n\t\t\tprocess.stderr.write(\n\t\t\t\t`--pm must be one of ${PACKAGE_MANAGERS.join(\", \")}.\\n`,\n\t\t\t);\n\t\t\treturn 1;\n\t\t}\n\t\tconst report = await init({\n\t\t\tcwd,\n\t\t\tdir: names[0],\n\t\t\tname: values.name,\n\t\t\tpackageManager: values.pm as PackageManager | undefined,\n\t\t\tuserAgent: process.env.npm_config_user_agent,\n\t\t\tfonts: !values[\"no-fonts\"],\n\t\t\temoji: values[\"no-emoji\"] ? false : values.emoji,\n\t\t\tgit: !values[\"no-git\"],\n\t\t\tinstall: values.install,\n\t\t\tonDownload,\n\t\t});\n\t\tlogInit(report, cwd, log);\n\t\treturn 0;\n\t}\n\tconst registry = openRegistry(values.registry, cwd);\n\n\tif (command === \"list\") {\n\t\tconst index = await registry.index();\n\t\tif (values.json) {\n\t\t\tlog(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tschemaVersion: 1,\n\t\t\t\t\tsdkVersion: ownVersion(),\n\t\t\t\t\tcomponents: await Promise.all(\n\t\t\t\t\t\tindex.map(async (entry) => {\n\t\t\t\t\t\t\tconst { files: _files, ...item } = await registry.item(\n\t\t\t\t\t\t\t\tentry.name,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn item;\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn 0;\n\t\t}\n\t\tconst width = Math.max(...index.map((e) => e.name.length));\n\t\tfor (const e of index)\n\t\t\tprocess.stdout.write(`${e.name.padEnd(width)} ${e.summary}\\n`);\n\t\treturn 0;\n\t}\n\tif (command !== \"add\") {\n\t\tprocess.stderr.write(`Unknown command \"${command}\".\\n\\n${HELP}`);\n\t\treturn 1;\n\t}\n\n\tconst wanted = values.all\n\t\t? (await registry.index()).map((e) => e.name)\n\t\t: names;\n\tif (wanted.length === 0) {\n\t\tprocess.stderr.write(\n\t\t\t\"Name the components to add, e.g. `framefields add mouse-pointer`.\\nRun `framefields list` to see them all.\\n\",\n\t\t);\n\t\treturn 1;\n\t}\n\tconst report = await add(wanted, {\n\t\tcwd,\n\t\tregistry,\n\t\tdir: values.dir,\n\t\toverwrite: values.overwrite,\n\t\tfonts: !values[\"no-fonts\"],\n\t\tfontsDir: values[\"fonts-dir\"],\n\t\tonDownload,\n\t});\n\tfor (const f of report.written) log(` wrote ${f}`);\n\tfor (const f of report.unchanged) log(` unchanged ${f}`);\n\tfor (const f of report.skipped)\n\t\tlog(` skipped ${f} (yours differs; --overwrite replaces it)`);\n\tif (report.configWritten) log(\" wrote framefields.json\");\n\tlogFonts(report, cwd, log);\n\tconst extra = report.components.filter((c) => !wanted.includes(c.name));\n\tif (extra.length > 0)\n\t\tlog(`\\nWith what they build on: ${extra.map((c) => c.name).join(\", \")}.`);\n\twarnIfMissingFramefields(cwd, log);\n\tconst first = report.components.find((c) => wanted.includes(c.name));\n\tif (first)\n\t\tlog(\n\t\t\t`\\nimport { ${first.title} } from \"./${first.name}/index.js\"; // from ${relative(cwd, report.dir) || \".\"}`,\n\t\t);\n\treturn 0;\n}\n\nconst onDownload = (spec: FontSpec) =>\n\tprocess.stdout.write(\n\t\t` fetching ${spec.file} (${(spec.font.bytes / 1e6).toFixed(1)} MB, ${spec.license.id})\\n`,\n\t);\n\n/** What `add` did about fonts, and how to use them. */\n/** `check [name|entry]`: a named render, a module, or every named render. */\nasync function check(\n\tnames: string[],\n\tcwd: string,\n\tvalues: {\n\t\texport?: string;\n\t\trender?: boolean;\n\t\toutput?: string;\n\t\ttimeout?: string;\n\t\t\"warnings-as-errors\"?: boolean;\n\t\tjson?: boolean;\n\t},\n\tlog: (s: string) => void,\n): Promise<number> {\n\tconst renders = readConfig(cwd).config.renders ?? {};\n\tconst usage = () => {\n\t\tprocess.stderr.write(\n\t\t\t\"Usage: framefields check [name|entry] [--export buildFilm] [--render] [--json]\\n\",\n\t\t);\n\t\treturn 2;\n\t};\n\tif (names.length > 1) return usage();\n\tconst targets: { name?: string; entry: string; exportName?: string }[] =\n\t\tnames.length === 0\n\t\t\t? Object.entries(renders).map(([name, spec]) => ({\n\t\t\t\t\tname,\n\t\t\t\t\tentry: spec.entry,\n\t\t\t\t\texportName: spec.export,\n\t\t\t\t}))\n\t\t\t: renders[names[0]]\n\t\t\t\t? [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tname: names[0],\n\t\t\t\t\t\t\tentry: renders[names[0]].entry,\n\t\t\t\t\t\t\texportName: values.export ?? renders[names[0]].export,\n\t\t\t\t\t\t},\n\t\t\t\t\t]\n\t\t\t\t: [{ entry: names[0], exportName: values.export }];\n\tif (targets.length === 0) return usage();\n\tconst reports = [];\n\tfor (const t of targets) {\n\t\tconst report = await runCheck({\n\t\t\tentry: t.entry,\n\t\t\texportName: t.exportName,\n\t\t\trender: values.render,\n\t\t\toutputDir:\n\t\t\t\tvalues.output ??\n\t\t\t\t(targets.length > 1\n\t\t\t\t\t? join(\"output\", \"check\", t.name ?? \"\")\n\t\t\t\t\t: undefined),\n\t\t\ttimeoutMs:\n\t\t\t\tvalues.timeout === undefined ? undefined : Number(values.timeout),\n\t\t\twarningsAsErrors: values[\"warnings-as-errors\"],\n\t\t});\n\t\treports.push({ ...(t.name && { name: t.name }), ...report });\n\t\tif (values.json) continue;\n\t\tlog(\n\t\t\t`Check ${report.status}: ${t.name ? `${t.name} (${t.entry}, ${report.exportName})` : `${report.entry} (${report.exportName})`}`,\n\t\t);\n\t\tfor (const d of report.diagnostics)\n\t\t\tlog(\n\t\t\t\t`${d.severity} ${d.code}${d.path ? ` at ${d.path}` : \"\"}: ${d.message}`,\n\t\t\t);\n\t\tfor (const file of report.artifacts) log(`Wrote ${file}`);\n\t}\n\tconst passed = reports.every((r) => r.status === \"passed\");\n\tif (values.json)\n\t\tlog(\n\t\t\tJSON.stringify(\n\t\t\t\tnames.length === 0\n\t\t\t\t\t? { status: passed ? \"passed\" : \"failed\", checks: reports }\n\t\t\t\t\t: reports[0],\n\t\t\t),\n\t\t);\n\treturn passed ? 0 : 1;\n}\n\n/** `renders`: what framefields.json names, as the dashboard shows it. */\nfunction listRenders(\n\tcwd: string,\n\tjson: boolean | undefined,\n\tlog: (s: string) => void,\n): number {\n\tconst renders = readConfig(cwd).config.renders ?? {};\n\tif (json) {\n\t\tlog(JSON.stringify({ schemaVersion: 1, renders }));\n\t\treturn 0;\n\t}\n\tconst entries = Object.entries(renders);\n\tif (entries.length === 0) {\n\t\tlog(\n\t\t\t'framefields.json names no renders. Add one: \"renders\": { \"film\": { \"entry\": \"src/film.ts\", \"export\": \"buildFilm\" } }',\n\t\t);\n\t\treturn 0;\n\t}\n\tfor (const [name, spec] of entries) {\n\t\tconst title = spec.title && spec.title !== name ? ` ${spec.title}` : \"\";\n\t\tconst opts = [\n\t\t\tspec.workers !== undefined && `workers ${spec.workers}`,\n\t\t\tspec.codec,\n\t\t].filter(Boolean);\n\t\tlog(\n\t\t\t`${name}${title}\\n ${spec.entry} · ${spec.export ?? \"buildFilm\"}${spec.select ? ` · ${spec.select}` : \"\"}${opts.length ? ` · ${opts.join(\", \")}` : \"\"}${spec.description ? `\\n ${spec.description}` : \"\"}`,\n\t\t);\n\t}\n\treturn 0;\n}\n\nfunction logFonts(report: AddReport, cwd: string, log: (s: string) => void) {\n\tfor (const f of report.fonts)\n\t\tlog(\n\t\t\t` ${f.status === \"installed\" ? \"font \" : \"font ok \"} ${f.path} (${f.role}, for ${f.by}: ${f.why})`,\n\t\t);\n\tfor (const f of report.fontsSkipped)\n\t\tlog(\n\t\t\t` no font ${f.role} for ${f.by} (--no-fonts): ${f.why} Install later with \\`framefields fonts add ${f.role}\\`.`,\n\t\t);\n\tif (report.fontsModule) logFontsModule(report.fontsModule, log);\n\tconst installed = report.fonts.find((f) => f.status === \"installed\");\n\tconst hint = installed && lfsHint(cwd, installed.path);\n\tif (hint) log(`\\n${hint}`);\n\tif (report.fonts.some((f) => f.status !== \"configured\") && report.fontsModule)\n\t\tlog(\n\t\t\t`\\nRegister them once before rendering: \\`await registerFonts()\\` from ${report.fontsModule.path.replace(/\\.ts$/, \".js\")}.`,\n\t\t);\n}\n\nfunction logFontsModule(\n\tm: NonNullable<AddReport[\"fontsModule\"]>,\n\tlog: (s: string) => void,\n) {\n\tif (m.status === \"written\") log(` wrote ${m.path}`);\n\telse if (m.status === \"unchanged\") log(` unchanged ${m.path}`);\n\telse\n\t\tlog(\n\t\t\t` skipped ${m.path} (not generated by framefields). Register the fonts yourself:\\n${m.calls.map((c) => ` ${c}`).join(\"\\n\")}`,\n\t\t);\n}\n\n/** `framefields fonts add <role...>` and `framefields fonts list`. */\nasync function fonts(\n\t[sub, ...roles]: string[],\n\tcwd: string,\n\tvalues: {\n\t\toverwrite?: boolean;\n\t\t\"fonts-dir\"?: string;\n\t\tdir?: string;\n\t\tjson?: boolean;\n\t},\n\tlog: (s: string) => void,\n): Promise<number> {\n\tif (sub === \"list\") {\n\t\tconst { config } = readConfig(cwd);\n\t\tif (values.json) {\n\t\t\tlog(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tschemaVersion: 1,\n\t\t\t\t\tsdkVersion: ownVersion(),\n\t\t\t\t\tfonts: Object.entries(FONTS).map(([role, spec]) => ({\n\t\t\t\t\t\trole,\n\t\t\t\t\t\t...spec,\n\t\t\t\t\t\tconfiguredPath: config.fonts?.[role],\n\t\t\t\t\t})),\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn 0;\n\t\t}\n\t\tfor (const [role, spec] of Object.entries(FONTS))\n\t\t\tlog(\n\t\t\t\t`${role.padEnd(6)} ${spec.label}${config.fonts?.[role] ? ` (installed: ${config.fonts[role]})` : \"\"}`,\n\t\t\t);\n\t\treturn 0;\n\t}\n\tif (sub !== \"add\" || roles.length === 0) {\n\t\tprocess.stderr.write(\n\t\t\t`Usage: framefields fonts add <role...> (roles: ${Object.keys(FONTS).join(\", \")})\\n framefields fonts list\\n`,\n\t\t);\n\t\treturn 1;\n\t}\n\tconst unknown = roles.filter((r) => !FONTS[r]);\n\tif (unknown.length > 0) {\n\t\tprocess.stderr.write(\n\t\t\t`Unknown font ${unknown.map((r) => `\"${r}\"`).join(\", \")}. Fonts framefields can install: ${Object.keys(FONTS).join(\", \")}.\\n`,\n\t\t);\n\t\treturn 1;\n\t}\n\tconst { config, saved } = readConfig(cwd);\n\tconst installs = [];\n\tfor (const role of roles)\n\t\tinstalls.push(\n\t\t\tawait installFont(role, {\n\t\t\t\tcwd,\n\t\t\t\tdir: values[\"fonts-dir\"],\n\t\t\t\toverwrite: values.overwrite,\n\t\t\t\tonDownload,\n\t\t\t}),\n\t\t);\n\tfor (const f of installs)\n\t\tlog(\n\t\t\t` ${f.status === \"installed\" ? \"font \" : \"font ok \"} ${f.path} (${f.role})`,\n\t\t);\n\tif (!saved) log(\" wrote framefields.json\");\n\tconst module = writeFontsModule(\n\t\tcwd,\n\t\tresolve(cwd, values.dir ?? config.components),\n\t);\n\tlogFontsModule(module, log);\n\tconst installed = installs.find((f) => f.status === \"installed\");\n\tconst hint = installed && lfsHint(cwd, installed.path);\n\tif (hint) log(`\\n${hint}`);\n\tlog(\n\t\t`\\nRegister them once before rendering: \\`await registerFonts()\\` from ${module.path.replace(/\\.ts$/, \".js\")}.`,\n\t);\n\treturn 0;\n}\n\nfunction logInit(report: InitReport, cwd: string, log: (s: string) => void) {\n\tconst at = shownPath(cwd, report.root);\n\tfor (const f of report.written) log(` wrote ${f}`);\n\tfor (const f of report.merged)\n\t\tlog(` merged ${f} (added what it lacked)`);\n\tfor (const f of report.unchanged) log(` unchanged ${f}`);\n\tfor (const f of report.fonts)\n\t\tlog(\n\t\t\t` ${f.status === \"installed\" ? \"font \" : \"font ok \"} ${f.path} (${f.role})`,\n\t\t);\n\tlogFontsModule(report.fontsModule, log);\n\tif (report.git === \"initialized\")\n\t\tlog(\" git initialized a repository\");\n\tif (report.git === \"unavailable\")\n\t\tlog(\" git not found: skipped `git init`\");\n\tif (report.lfs === false)\n\t\tlog(\n\t\t\t\"\\nGit LFS isn't installed. Footage and fonts are tracked with it: install it (https://git-lfs.com), then run `git lfs install` once.\",\n\t\t);\n\telse if (report.lfs)\n\t\tlog(\"\\nRun `git lfs install` once on this machine if you haven't yet.\");\n\tconst steps = [\n\t\t...(at === \".\" ? [] : [`cd ${/\\s/.test(at) ? JSON.stringify(at) : at}`]),\n\t\t...(report.installed ? [] : [`${report.packageManager} install`]),\n\t\t`${report.runScript(\"frames\")} -- 0 30 60`,\n\t];\n\tlog(\n\t\t`\\n${report.name} is ready. Next:\\n${steps.map((s) => ` ${s}`).join(\"\\n\")}`,\n\t);\n\tlog(\n\t\t\"\\nThen edit src/film.ts, and run `npx framefields list` for ready-made components.\",\n\t);\n\tlog(\n\t\t`\\nOptional: to generate images, video, music, voice and 3D with the framefields AI gateway, get a key at ${AI_DASHBOARD} and put it in .env as FRAMEFIELDS_API_KEY (see .env.example).`,\n\t);\n}\n\n/** Installed components import `framefields`; say so if the project lacks it. */\nfunction warnIfMissingFramefields(cwd: string, log: (s: string) => void) {\n\ttry {\n\t\tconst pkg = JSON.parse(readFileSync(`${cwd}/package.json`, \"utf8\")) as {\n\t\t\tdependencies?: Record<string, string>;\n\t\t\tdevDependencies?: Record<string, string>;\n\t\t};\n\t\tif (!pkg.dependencies?.framefields && !pkg.devDependencies?.framefields)\n\t\t\tlog(\n\t\t\t\t\"\\nThese components import `framefields`: add it with `npm i framefields`.\",\n\t\t\t);\n\t} catch {\n\t\t// No package.json: nothing to check.\n\t}\n}\n\nmain(process.argv.slice(2)).then(\n\t(code) => process.exit(code),\n\t(error: unknown) => {\n\t\tprocess.stderr.write(\n\t\t\t`framefields: ${error instanceof Error ? error.message : String(error)}\\n`,\n\t\t);\n\t\tprocess.exit(1);\n\t},\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":["path","fonts","path","path","config"],"sources":["../src/cli/fonts.ts","../src/cli/add.ts","../src/cli/templates.ts","../src/cli/init.ts","../src/cli/project-node.ts","../src/cli/check.ts","../src/cli/cloud.ts","../src/cli/local.ts","../src/cli/registry.ts","../src/cli.ts"],"sourcesContent":["/**\n * Fonts the CLI installs into a project: a catalog of pinned files (URL,\n * size, SHA-256, license), the installer `framefields add` and\n * `framefields fonts add` share, and the generated `fonts.ts` module that\n * registers whatever is installed.\n *\n * framefields ships no fonts in its package (a color emoji font alone is\n * ~10 MB); they're fetched when a project needs one, verified byte for byte,\n * and saved with their license next to them.\n */\nimport { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, posix, relative, resolve, sep } from \"node:path\";\nimport { readConfig, writeConfig } from \"./config.js\";\n\n/** A downloadable file, pinned by size and hash. */\ninterface PinnedFile {\n\turl: string;\n\tsha256: string;\n\tbytes: number;\n}\n\nexport interface FontSpec {\n\t/** What it's for, in a sentence: shown by `fonts list`. */\n\tlabel: string;\n\t/** File name it's saved under. */\n\tfile: string;\n\tfont: PinnedFile;\n\tlicense: PinnedFile & {\n\t\t/** SPDX id. */\n\t\tid: string;\n\t\t/** File name it's saved under, next to the font. */\n\t\tfile: string;\n\t};\n\t/**\n\t * How it registers: as the color emoji font, or as a text family under\n\t * this name (the name themes use: `Inter`, `JetBrains Mono`).\n\t */\n\tregister: { emoji: true } | { family: string };\n}\n\nconst NOTO_EMOJI =\n\t\"https://raw.githubusercontent.com/googlefonts/noto-emoji/v2.051\";\n/** google/fonts at one commit: Inter and JetBrains Mono. */\nconst GOOGLE_FONTS =\n\t\"https://raw.githubusercontent.com/google/fonts/e7db6ca603fd4862010383ff17ffd6cc4ffac1c0\";\n\n/** Installable fonts by role. */\nexport const FONTS: Record<string, FontSpec> = {\n\temoji: {\n\t\tlabel: \"Noto Color Emoji 2.051: color emoji in any text (🎉 ❤️ 👍)\",\n\t\tfile: \"NotoColorEmoji.ttf\",\n\t\tfont: {\n\t\t\turl: `${NOTO_EMOJI}/fonts/NotoColorEmoji.ttf`,\n\t\t\tsha256:\n\t\t\t\t\"72a635cb3d2f3524c51620cdde406b217204e8a6a06c6a096ff8ed4b5fd6e27b\",\n\t\t\tbytes: 10_673_480,\n\t\t},\n\t\tlicense: {\n\t\t\tid: \"OFL-1.1\",\n\t\t\tfile: \"NotoColorEmoji-OFL.txt\",\n\t\t\turl: `${NOTO_EMOJI}/fonts/LICENSE`,\n\t\t\tsha256:\n\t\t\t\t\"6a73f9541c2de74158c0e7cf6b0a58ef774f5a780bf191f2d7ec9cc53efe2bf2\",\n\t\t\tbytes: 4_301,\n\t\t},\n\t\tregister: { emoji: true },\n\t},\n\tsans: googleFont({\n\t\tlabel: \"Inter 4: the built-in themes' display and body face\",\n\t\tfile: \"Inter.ttf\",\n\t\tfamily: \"Inter\",\n\t\tpath: \"ofl/inter/Inter%5Bopsz,wght%5D.ttf\",\n\t\tsha256: \"29160a80ff49ddcab2c97711247e08b1fab27a484a329ce8b813d820dc559031\",\n\t\tbytes: 876_576,\n\t\tlicense: {\n\t\t\tpath: \"ofl/inter/OFL.txt\",\n\t\t\tsha256:\n\t\t\t\t\"5b9321a4298cfeb6b34354164a1c3afc3db114569984c502b9b35d988fd58c57\",\n\t\t\tbytes: 4_377,\n\t\t},\n\t}),\n\tmono: googleFont({\n\t\tlabel: \"JetBrains Mono 2: the built-in themes' code and terminal face\",\n\t\tfile: \"JetBrainsMono.ttf\",\n\t\tfamily: \"JetBrains Mono\",\n\t\tpath: \"ofl/jetbrainsmono/JetBrainsMono%5Bwght%5D.ttf\",\n\t\tsha256: \"48715a42ec242c21e9f02692891e147d022299a52e48d5e413e1a942193ffeda\",\n\t\tbytes: 187_208,\n\t\tlicense: {\n\t\t\tpath: \"ofl/jetbrainsmono/OFL.txt\",\n\t\t\tsha256:\n\t\t\t\t\"b2fe5e8987594e9ffd1d2ca52a2f5d73eb8335243893c5d6254b5ad69269591d\",\n\t\t\tbytes: 4_399,\n\t\t},\n\t}),\n};\n\n/** google/fonts, pinned to one commit. */\nfunction googleFont(o: {\n\tlabel: string;\n\tfile: string;\n\tfamily: string;\n\tpath: string;\n\tsha256: string;\n\tbytes: number;\n\tlicense: { path: string; sha256: string; bytes: number };\n}): FontSpec {\n\tconst at = (path: string) => `${GOOGLE_FONTS}/${path}`;\n\treturn {\n\t\tlabel: o.label,\n\t\tfile: o.file,\n\t\tfont: { url: at(o.path), sha256: o.sha256, bytes: o.bytes },\n\t\tlicense: {\n\t\t\turl: at(o.license.path),\n\t\t\tsha256: o.license.sha256,\n\t\t\tbytes: o.license.bytes,\n\t\t\tid: \"OFL-1.1\",\n\t\t\tfile: o.file.replace(/\\.ttf$/, \"-OFL.txt\"),\n\t\t},\n\t\tregister: { family: o.family },\n\t};\n}\n\n/** Where fonts go when `framefields.json` names no place: the setup skill's layout. */\nexport const DEFAULT_FONTS_DIR = \"assets/fonts\";\n\nexport type Fetch = (url: string) => Promise<{\n\tok: boolean;\n\tstatus: number;\n\tstatusText: string;\n\tarrayBuffer(): Promise<ArrayBuffer>;\n}>;\n\nexport interface FontInstallOptions {\n\tcwd: string;\n\t/** Folder for new font files, relative to `cwd`. Default `assets/fonts`. */\n\tdir?: string;\n\t/** Replace a different file already at the target path. */\n\toverwrite?: boolean;\n\t/** For tests; default the global `fetch`. */\n\tfetch?: Fetch;\n\t/** For tests; default {@link FONTS}. */\n\tcatalog?: Record<string, FontSpec>;\n\t/** Called before a download starts (for progress messages). */\n\tonDownload?: (spec: FontSpec) => void;\n}\n\nexport interface FontInstall {\n\trole: string;\n\t/** Relative to the project root. */\n\tpath: string;\n\t/**\n\t * `installed`: downloaded now. `present`: the pinned file was already\n\t * there. `configured`: `framefields.json` already names a font for the role.\n\t */\n\tstatus: \"installed\" | \"present\" | \"configured\";\n}\n\nconst sha256 = (bytes: Uint8Array) =>\n\tcreateHash(\"sha256\").update(bytes).digest(\"hex\");\n\n/** A project-relative path with forward slashes, as `framefields.json` keeps it. */\nconst projectPath = (cwd: string, path: string) =>\n\trelative(cwd, path).split(sep).join(posix.sep);\n\n/** Install the font for `role` into the project and record it in `framefields.json`. */\nexport async function installFont(\n\trole: string,\n\toptions: FontInstallOptions,\n): Promise<FontInstall> {\n\tconst catalog = options.catalog ?? FONTS;\n\tconst spec = catalog[role];\n\tif (!spec)\n\t\tthrow new Error(\n\t\t\t`Unknown font \"${role}\". Fonts framefields can install: ${Object.keys(catalog).join(\", \")}.`,\n\t\t);\n\tconst { cwd } = options;\n\tconst { config } = readConfig(cwd);\n\tconst configured = config.fonts?.[role];\n\tif (configured && existsSync(resolve(cwd, configured)))\n\t\treturn { role, path: configured, status: \"configured\" };\n\n\tconst target = resolve(cwd, options.dir ?? DEFAULT_FONTS_DIR, spec.file);\n\tconst path = projectPath(cwd, target);\n\tlet status: FontInstall[\"status\"] = \"present\";\n\tconst current = existsSync(target) ? readFileSync(target) : null;\n\tif (!current || sha256(current) !== spec.font.sha256) {\n\t\tif (current && !options.overwrite)\n\t\t\tthrow new Error(\n\t\t\t\t`${path} exists but isn't the pinned ${spec.file}. Pass --overwrite to replace it, or point \"fonts.${role}\" in framefields.json at it to keep using yours.`,\n\t\t\t);\n\t\toptions.onDownload?.(spec);\n\t\tconst get = options.fetch ?? (fetch as unknown as Fetch);\n\t\tconst [font, license] = await Promise.all([\n\t\t\tdownload(spec.font, get),\n\t\t\tdownload(spec.license, get),\n\t\t]);\n\t\tmkdirSync(dirname(target), { recursive: true });\n\t\twriteFileSync(target, font);\n\t\twriteFileSync(join(dirname(target), spec.license.file), license);\n\t\tstatus = \"installed\";\n\t}\n\twriteConfig(cwd, {\n\t\t...config,\n\t\tfonts: { ...config.fonts, [role]: path },\n\t});\n\treturn { role, path, status };\n}\n\nasync function download(file: PinnedFile, get: Fetch): Promise<Uint8Array> {\n\tlet res: Awaited<ReturnType<Fetch>>;\n\ttry {\n\t\tres = await get(file.url);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Couldn't download ${file.url} (${error instanceof Error ? error.message : String(error)}). Check the connection, or download it yourself and point framefields.json \"fonts\" at it.`,\n\t\t);\n\t}\n\tif (!res.ok) throw new Error(`${file.url}: ${res.status} ${res.statusText}`);\n\tconst bytes = new Uint8Array(await res.arrayBuffer());\n\tconst hash = sha256(bytes);\n\tif (bytes.length !== file.bytes || hash !== file.sha256)\n\t\tthrow new Error(\n\t\t\t`${file.url} isn't the pinned file (got ${bytes.length} bytes, sha256 ${hash}; expected ${file.bytes}, ${file.sha256}). Nothing was written.`,\n\t\t);\n\treturn bytes;\n}\n\n/** First line of the generated module: files without it are the user's and left alone. */\nexport const FONTS_MODULE_MARKER =\n\t\"// Generated by framefields from framefields.json.\";\n\nexport interface FontsModule {\n\t/** Relative to the project root. */\n\tpath: string;\n\t/** `skipped`: the file exists without the marker, so it's the user's. */\n\tstatus: \"written\" | \"unchanged\" | \"skipped\";\n\t/** The registration calls, one line each, for printing when `skipped`. */\n\tcalls: string[];\n}\n\n/**\n * Write `<components>/fonts.ts`, which registers every font in\n * `framefields.json`. Call it once before building or rendering:\n * `await registerFonts()`.\n */\nexport function writeFontsModule(\n\tcwd: string,\n\tcomponentsDir: string,\n\tcatalog: Record<string, FontSpec> = FONTS,\n): FontsModule {\n\tconst { config } = readConfig(cwd);\n\tconst target = join(componentsDir, \"fonts.ts\");\n\tconst path = projectPath(cwd, target);\n\tconst fonts = Object.entries(config.fonts ?? {})\n\t\t.filter(([role]) => catalog[role])\n\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t.map(([role, file]) => {\n\t\t\tconst from = relative(componentsDir, resolve(cwd, file as string))\n\t\t\t\t.split(sep)\n\t\t\t\t.join(posix.sep);\n\t\t\tconst url = from.startsWith(\".\") ? from : `./${from}`;\n\t\t\treturn { register: (catalog[role] as FontSpec).register, url };\n\t\t});\n\tconst call = (r: FontSpec[\"register\"], source: string) =>\n\t\t\"family\" in r\n\t\t\t? `register({ family: ${JSON.stringify(r.family)}, source: ${source} })`\n\t\t\t: `registerEmojiFont(${source})`;\n\tconst calls = fonts.map(\n\t\t(f) => `await FontManager.${call(f.register, `asset(\"${f.url}\")`)};`,\n\t);\n\tconst content = `${FONTS_MODULE_MARKER}\n// \\`framefields add\\` and \\`framefields fonts add\\` rewrite it when fonts\n// change; register any other fonts in your own code.\nimport { FontManager } from \"framefields\";\n\n/** A path next to this file as a URL: works in Node and in the browser preview. */\nconst asset = (path: string) => new URL(path, import.meta.url).href;\n\n/**\n * Register the fonts this project installed with framefields. Call it\n * once, before building any text or rendering:\n *\n * \\`\\`\\`ts\n * await registerFonts();\n * \\`\\`\\`\n */\nexport async function registerFonts(): Promise<void> {\n${fonts\n\t// Wrapped the way Biome / Prettier would at 80 columns.\n\t.map((f) =>\n\t\t\"family\" in f.register\n\t\t\t? `\\tawait FontManager.register({\\n\\t\\tfamily: ${JSON.stringify(f.register.family)},\\n\\t\\tsource: asset(\"${f.url}\"),\\n\\t});`\n\t\t\t: `\\tawait FontManager.registerEmojiFont(\\n\\t\\tasset(\"${f.url}\"),\\n\\t);`,\n\t)\n\t.join(\"\\n\")}\n}\n`;\n\tif (existsSync(target)) {\n\t\tconst current = readFileSync(target, \"utf8\");\n\t\tif (current === content) return { path, status: \"unchanged\", calls };\n\t\tif (!current.startsWith(FONTS_MODULE_MARKER))\n\t\t\treturn { path, status: \"skipped\", calls };\n\t}\n\tmkdirSync(componentsDir, { recursive: true });\n\twriteFileSync(target, content);\n\treturn { path, status: \"written\", calls };\n}\n\n/**\n * A hint when fonts land in a Git repo whose `.gitattributes` doesn't send\n * them to LFS (a 10 MB binary bloats every clone), or null.\n */\nexport function lfsHint(cwd: string, fontPath: string): string | null {\n\tif (!existsSync(join(cwd, \".git\"))) return null;\n\tconst attrs = join(cwd, \".gitattributes\");\n\tconst text = existsSync(attrs) ? readFileSync(attrs, \"utf8\") : \"\";\n\tif (/\\.ttf\\b[^\\n]*filter=lfs/.test(text)) return null;\n\tconst dir = posix.dirname(fontPath);\n\treturn `Fonts are large binaries: track them with Git LFS, e.g. \\`git lfs track \"${dir}/**/*.ttf\"\\`.`;\n}\n","/**\n * `framefields add`: copy components' source into a project, the way a\n * shadcn-style registry does. The code becomes the project's own; it\n * imports only `framefields` and `framefields/components` (the toolkit),\n * plus any component it builds on, which is installed alongside it.\n *\n * Where they go is remembered in `framefields.json` at the project root.\n * Components that draw with fonts beyond the theme's (emoji) get them\n * installed too, plus a generated `fonts.ts` that registers them.\n */\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, relative, resolve } from \"node:path\";\nimport { readConfig, writeConfig } from \"./config.js\";\nimport {\n\ttype Fetch,\n\ttype FontInstall,\n\ttype FontSpec,\n\ttype FontsModule,\n\tinstallFont,\n\twriteFontsModule,\n} from \"./fonts.js\";\nimport type { Registry, RegistryItem } from \"./registry.js\";\n\nexport { CONFIG_FILE, type ProjectConfig, readConfig } from \"./config.js\";\n\nexport interface AddOptions {\n\tcwd: string;\n\tregistry: Registry;\n\t/** Components directory; saved to `framefields.json` if there is none yet. */\n\tdir?: string;\n\t/** Replace files that differ from the registry's. */\n\toverwrite?: boolean;\n\t/** Install the fonts components ask for (default true). */\n\tfonts?: boolean;\n\t/** Folder for downloaded fonts. Default `assets/fonts`. */\n\tfontsDir?: string;\n\t/** For tests; default the global `fetch`. */\n\tfetch?: Fetch;\n\t/** For tests; default the built-in font catalog. */\n\tfontCatalog?: Record<string, FontSpec>;\n\t/** Called before a font download starts. */\n\tonDownload?: (spec: FontSpec) => void;\n}\n\nexport interface AddReport {\n\tdir: string;\n\t/** Components in install order (dependencies first). */\n\tcomponents: RegistryItem[];\n\twritten: string[];\n\tunchanged: string[];\n\t/** Files left alone because they differ and `overwrite` is off. */\n\tskipped: string[];\n\tconfigWritten: boolean;\n\t/** Fonts the components asked for, and what happened to each. */\n\tfonts: Array<FontInstall & { why: string; by: string }>;\n\t/** Fonts asked for but not installed (`fonts: false`), with why. */\n\tfontsSkipped: Array<{ role: string; why: string; by: string }>;\n\t/** The generated `fonts.ts`, when any font is installed. */\n\tfontsModule?: FontsModule;\n}\n\n/** Resolve `names` (and what they import) and write their files. */\nexport async function add(\n\tnames: string[],\n\toptions: AddOptions,\n): Promise<AddReport> {\n\tconst { cwd, registry } = options;\n\tconst index = await registry.index();\n\tconst known = new Set(index.map((e) => e.name));\n\tfor (const n of names)\n\t\tif (!known.has(n))\n\t\t\tthrow new Error(\n\t\t\t\t`Unknown component \"${n}\". Run \\`framefields list\\` to see them all.`,\n\t\t\t);\n\n\t// Depth-first, dependencies before dependants.\n\tconst order: RegistryItem[] = [];\n\tconst seen = new Set<string>();\n\tconst visit = async (name: string) => {\n\t\tif (seen.has(name)) return;\n\t\tseen.add(name);\n\t\tconst item = await registry.item(name);\n\t\tfor (const d of item.registryDependencies) await visit(d);\n\t\torder.push(item);\n\t};\n\tfor (const n of names) await visit(n);\n\n\tconst { config, saved } = readConfig(cwd);\n\tconst rel = options.dir ?? config.components;\n\tconst dir = resolve(cwd, rel);\n\tconst report: AddReport = {\n\t\tdir,\n\t\tcomponents: order,\n\t\twritten: [],\n\t\tunchanged: [],\n\t\tskipped: [],\n\t\tconfigWritten: false,\n\t\tfonts: [],\n\t\tfontsSkipped: [],\n\t};\n\tfor (const item of order) {\n\t\tfor (const file of item.files) {\n\t\t\tconst target = join(dir, file.path);\n\t\t\tconst shown = relative(cwd, target);\n\t\t\tif (existsSync(target)) {\n\t\t\t\tif (readFileSync(target, \"utf8\") === file.content) {\n\t\t\t\t\treport.unchanged.push(shown);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (!options.overwrite) {\n\t\t\t\t\treport.skipped.push(shown);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tmkdirSync(dirname(target), { recursive: true });\n\t\t\twriteFileSync(target, file.content);\n\t\t\treport.written.push(shown);\n\t\t}\n\t}\n\tif (!saved) {\n\t\twriteConfig(cwd, { ...config, components: relative(cwd, dir) || \".\" });\n\t\treport.configWritten = true;\n\t}\n\n\t// One install per font, credited to the first component that asks.\n\tconst needs = new Map<string, { why: string; by: string }>();\n\tfor (const item of order)\n\t\tfor (const f of item.fonts ?? [])\n\t\t\tif (!needs.has(f.font)) needs.set(f.font, { why: f.why, by: item.name });\n\tfor (const [role, need] of needs) {\n\t\tif (options.fonts === false) {\n\t\t\treport.fontsSkipped.push({ role, ...need });\n\t\t\tcontinue;\n\t\t}\n\t\tconst done = await installFont(role, {\n\t\t\tcwd,\n\t\t\tdir: options.fontsDir,\n\t\t\toverwrite: options.overwrite,\n\t\t\tfetch: options.fetch,\n\t\t\tcatalog: options.fontCatalog,\n\t\t\tonDownload: options.onDownload,\n\t\t});\n\t\treport.fonts.push({ ...done, ...need });\n\t}\n\tif (report.fonts.length > 0 || readConfig(cwd).config.fonts)\n\t\treport.fontsModule = writeFontsModule(cwd, dir, options.fontCatalog);\n\treturn report;\n}\n","/**\n * The files `framefields init` writes: the project layout the framefields\n * setup skill describes. `film.ts` only builds; `render.ts` renders frames,\n * a grid, the live preview or the video; `theme.ts` holds the numbers.\n */\nimport type { RenderSpec } from \"./config.js\";\n\n/**\n * Packages with install scripts. framefields needs exactly one (skia-canvas\n * downloads its native binary); the others work without theirs.\n */\nconst ALLOWED_SCRIPTS = [\"skia-canvas\"];\nconst DENIED_SCRIPTS = [\n\t\"sharp\",\n\t\"webgpu\",\n\t\"onnxruntime-node\",\n\t\"node-av\",\n\t\"esbuild\",\n\t\"protobufjs\",\n];\n\n/** Dev tools the scripts use, at versions the scaffold is tested with. */\nexport const DEV_DEPENDENCIES: Record<string, string> = {\n\t\"@types/node\": \"^24.1.0\",\n\ttsx: \"^4.20.3\",\n\ttypescript: \"^5.8.3\",\n};\n\nexport const SCRIPTS: Record<string, string> = {\n\ttypecheck: \"tsc --noEmit -p .\",\n\tcheck: \"tsc --noEmit -p . && framefields check film --json\",\n\t\"check:render\": \"tsc --noEmit -p . && framefields check film --render --json\",\n\tframes: \"tsx src/render.ts frames\",\n\tgrid: \"tsx src/render.ts grid\",\n\tpreview: \"framefields preview film\",\n\trender: \"framefields render film\",\n\t\"render:cloud\": \"framefields render film --cloud\",\n};\n\n/** The named render `init` records in framefields.json. */\nexport function defaultRenders(name: string): Record<string, RenderSpec> {\n\treturn {\n\t\tfilm: {\n\t\t\ttitle: name,\n\t\t\tentry: \"src/film.ts\",\n\t\t\texport: \"buildFilm\",\n\t\t\tworkers: \"auto\",\n\t\t\toutput: \"output/film.mp4\",\n\t\t},\n\t};\n}\n\n/**\n * The `package.json` fields a framefields project needs. npm reads\n * `allowScripts`, pnpm its `pnpm` block, bun `trustedDependencies`.\n */\nexport function packageFields(o: {\n\tframefieldsVersion: string;\n\tpackageManager?: string;\n}) {\n\treturn {\n\t\ttype: \"module\",\n\t\t...(o.packageManager && { packageManager: o.packageManager }),\n\t\tscripts: SCRIPTS,\n\t\tdependencies: { framefields: `^${o.framefieldsVersion}` },\n\t\tdevDependencies: DEV_DEPENDENCIES,\n\t\tallowScripts: Object.fromEntries([\n\t\t\t...ALLOWED_SCRIPTS.map((p) => [p, true]),\n\t\t\t...DENIED_SCRIPTS.map((p) => [p, false]),\n\t\t]),\n\t\tpnpm: {\n\t\t\tonlyBuiltDependencies: ALLOWED_SCRIPTS,\n\t\t\tignoredBuiltDependencies: DENIED_SCRIPTS,\n\t\t},\n\t\ttrustedDependencies: ALLOWED_SCRIPTS,\n\t};\n}\n\nexport const TSCONFIG = `${JSON.stringify(\n\t{\n\t\tcompilerOptions: {\n\t\t\tmodule: \"NodeNext\",\n\t\t\tmoduleResolution: \"NodeNext\",\n\t\t\ttarget: \"ES2022\",\n\t\t\tstrict: true,\n\t\t\tskipLibCheck: true,\n\t\t\tnoEmit: true,\n\t\t\ttypes: [\"node\"],\n\t\t},\n\t\tinclude: [\"src/**/*\"],\n\t},\n\tnull,\n\t\"\\t\",\n)}\\n`;\n\n/** Lines `init` makes sure `.gitignore` has. */\nexport const GITIGNORE = [\n\t\"node_modules/\",\n\t\"output/\",\n\t\"scratch/\",\n\t\".DS_Store\",\n\t\".env\",\n];\n\n/** Where the AI gateway's keys come from. */\nexport const AI_DASHBOARD = \"https://framefields.dev/dashboard\";\n\n/** Optional settings; `render.ts` loads `.env` when there is one. Commit this, not `.env`. */\nexport const ENV_EXAMPLE = `# Copy to .env (git-ignored). Everything here is optional.\n\n# framefields AI gateway: generate images, video, music, voice and 3D from code.\n# Create a key at ${AI_DASHBOARD}\nFRAMEFIELDS_API_KEY=\n`;\n\n/** Media, LUTs and fonts go to Git LFS; renders stay out of Git. */\nexport const GITATTRIBUTES = [\n\t\"assets/**/*.mp4 filter=lfs diff=lfs merge=lfs -text\",\n\t\"assets/**/*.mov filter=lfs diff=lfs merge=lfs -text\",\n\t\"assets/**/*.webm filter=lfs diff=lfs merge=lfs -text\",\n\t\"assets/**/*.mp3 filter=lfs diff=lfs merge=lfs -text\",\n\t\"assets/**/*.wav filter=lfs diff=lfs merge=lfs -text\",\n\t\"assets/**/*.cube filter=lfs diff=lfs merge=lfs -text\",\n\t\"assets/**/*.lottie filter=lfs diff=lfs merge=lfs -text\",\n\t\"assets/fonts/**/*.ttf filter=lfs diff=lfs merge=lfs -text\",\n\t\"assets/fonts/**/*.otf filter=lfs diff=lfs merge=lfs -text\",\n];\n\nexport const THEME_TS = `import { registerFonts as registerInstalledFonts } from \"./components/fonts.js\";\n\nexport const W = 1920;\nexport const H = 1080;\nexport const FPS = 30;\nexport const INK = \"#0E0D0C\";\nexport const PAPER = \"#EEE9E0\";\n/** Installed by \\`framefields init\\` (assets/fonts), registered below. */\nexport const SANS = \"Inter\";\nexport const MONO = \"JetBrains Mono\";\n\n/**\n * Register the film's fonts. Fonts framefields installed\n * (\\`npx framefields fonts add <role>\\`) come from the generated\n * components/fonts.ts; register any others here with \\`FontManager.register\\`.\n */\nexport async function registerFonts(): Promise<void> {\n\tawait registerInstalledFonts();\n}\n`;\n\nexport const FILM_TS = `import { Composition, Layer, LayerAnimation } from \"framefields\";\nimport { FPS, H, INK, PAPER, registerFonts, SANS, W } from \"./theme.js\";\n\nconst DURATION = 3 * FPS; // frames\n\n/** Builds the film. Only builds: no rendering or writes, so tests, the preview and renders share it. */\nexport async function buildFilm(): Promise<Composition> {\n\t// Fonts must be registered before any text layer is built.\n\tawait registerFonts();\n\n\tconst film = new Composition({\n\t\twidth: W,\n\t\theight: H,\n\t\tfps: FPS,\n\t\tdurationMs: (DURATION / FPS) * 1000,\n\t\tbackgroundColor: INK,\n\t});\n\n\tfilm.add(\n\t\tLayer.text(\"Hello, framefields\", {\n\t\t\tid: \"title\",\n\t\t\tposition: \"absolute\",\n\t\t\tx: 0,\n\t\t\ty: H / 2 - 60,\n\t\t\twidth: W,\n\t\t\theight: 120,\n\t\t\tfontFamily: SANS,\n\t\t\tfontSize: 96,\n\t\t\tfontWeight: 700,\n\t\t\tfill: PAPER,\n\t\t\talign: \"center\",\n\t\t}).animate(\n\t\t\tLayerAnimation.create()\n\t\t\t\t.fadeIn(0, 20, \"power2.out\")\n\t\t\t\t.fromTo(\"y\", H / 2 - 20, H / 2 - 60, {\n\t\t\t\t\tstart: 0,\n\t\t\t\t\tend: 30,\n\t\t\t\t\tease: \"expo.out\",\n\t\t\t\t}),\n\t\t),\n\t);\n\n\treturn film;\n}\n`;\n\nexport const RENDER_TS = `import { existsSync } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { HeadlessMediaRenderer, frameCount } from \"framefields\";\nimport { buildFilm } from \"./film.js\";\n\n// Quick looks at the film: \\`npm run frames -- 0 30 60\\` and \\`npm run grid\\`.\n// \\`npm run render\\` and \\`npm run preview\\` use the \"film\" render in\n// framefields.json instead (\\`framefields render film\\`, \\`framefields preview film\\`).\n\n// Optional settings such as FRAMEFIELDS_API_KEY (see .env.example).\nconst ENV = path.resolve(import.meta.dirname, \"../.env\");\nif (existsSync(ENV)) process.loadEnvFile(ENV);\n\nconst OUT = path.resolve(import.meta.dirname, \"../output\");\n// \\`npm run frames -- 0 30\\` needs the \\`--\\`; pnpm passes it through: drop it.\nconst [mode = \"frames\", ...args] = process.argv\n\t.slice(2)\n\t.filter((a) => a !== \"--\");\n\nconst film = await buildFilm();\nawait fs.mkdir(OUT, { recursive: true });\n\nif (mode === \"grid\") {\n\tconst last = frameCount(film.durationMs ?? (await film.computeDuration()), film.fps) - 1;\n\tconst png = await film.renderFrameGrid({\n\t\tframes: args.length ? args.map(Number) : [...new Set([0, Math.floor(last / 2), last])],\n\t\tcolumns: 4,\n\t\tcellWidth: 480,\n\t\tshowLabels: true,\n\t});\n\tawait fs.writeFile(path.join(OUT, \"grid.png\"), png);\n\tconsole.log(\"Wrote output/grid.png\");\n} else {\n\tconst renderer = new HeadlessMediaRenderer();\n\tfor (const frame of (args.length ? args : [\"0\"]).map(Number)) {\n\t\tconst png = await film.renderFrame({ frame, renderer });\n\t\tconst file = path.join(OUT, \\`f\\${String(frame).padStart(4, \"0\")}.png\\`);\n\t\tawait fs.writeFile(file, png);\n\t\tconsole.log(\\`Wrote \\${path.relative(process.cwd(), file)}\\`);\n\t}\n}\n\n// Native GPU and encoder threads keep Node alive; always exit explicitly.\nprocess.exit(0);\n`;\n\nexport function readme(name: string, run: (script: string) => string): string {\n\treturn `# ${name}\n\nA film built with [framefields](https://www.npmjs.com/package/framefields).\n\n\\`\\`\\`bash\n${run(\"typecheck\")}\n${run(\"frames\")} -- 0 30 60 # PNGs in output/\n${run(\"grid\")} # a contact sheet of the motion\n${run(\"preview\")} # play it in the browser\n${run(\"render\")} # output/film.mp4\n${run(\"render:cloud\")} # on cloud GPUs, from the pushed commit\n\\`\\`\\`\n\n- \\`framefields.json\\` names the renders: \\`film\\` is \\`buildFilm\\` in \\`src/film.ts\\`. Add an\n entry under \\`renders\\` for each cut (a teaser, a vertical edit) and render or check it by\n name: \\`npx framefields render teaser --cloud\\`, \\`npx framefields check teaser\\`.\n- \\`src/film.ts\\` builds the composition, \\`src/theme.ts\\` holds sizes, colors and fonts,\n \\`src/render.ts\\` renders it.\n- \\`npx framefields list\\` shows ready-made components; \\`npx framefields add <name>\\` copies\n one into \\`src/components/\\`.\n- Optional: the AI gateway generates images, video, music, voice and 3D from code. Copy\n \\`.env.example\\` to \\`.env\\` and set \\`FRAMEFIELDS_API_KEY\\` (keys at ${AI_DASHBOARD}).\n- \\`render:cloud\\` renders on framefields' GPUs with the same key, and splits a long film\n across several (\\`-- --plan\\` shows workers, time and cost first). It renders the\n commit you pushed, not uncommitted changes.\n- Footage, audio and fonts live in \\`assets/\\` and are tracked with Git LFS\n (\\`git lfs install\\` once per machine, \\`git lfs pull\\` after cloning).\n`;\n}\n","/**\n * `framefields init [dir]`: a new framefields project, or framefields added\n * to an existing one. Writes the layout the setup skill describes\n * (`package.json` with the install-script approvals framefields needs,\n * `tsconfig.json`, `src/theme.ts` / `film.ts` / `render.ts`, `assets/`,\n * LFS `.gitattributes`, `.gitignore`), installs the default fonts\n * (Inter, JetBrains Mono, and Noto Color Emoji) and keeps them registered\n * in `src/components/fonts.ts`.\n *\n * It never overwrites: files that exist are left alone, and `package.json`,\n * `.gitignore` and `.gitattributes` gain only what they're missing.\n */\nimport { spawn } from \"node:child_process\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, dirname, join, relative, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { CONFIG_FILE, readConfig, writeConfig } from \"./config.js\";\nimport {\n\ttype Fetch,\n\ttype FontInstall,\n\ttype FontSpec,\n\ttype FontsModule,\n\tinstallFont,\n\twriteFontsModule,\n} from \"./fonts.js\";\nimport {\n\tdefaultRenders,\n\tENV_EXAMPLE,\n\tFILM_TS,\n\tGITATTRIBUTES,\n\tGITIGNORE,\n\tpackageFields,\n\tRENDER_TS,\n\treadme,\n\tTHEME_TS,\n\tTSCONFIG,\n} from \"./templates.js\";\n\nexport const PACKAGE_MANAGERS = [\"npm\", \"pnpm\", \"yarn\", \"bun\"] as const;\nexport type PackageManager = (typeof PACKAGE_MANAGERS)[number];\n\n/** Runs a command; resolves with its exit code (127 when it can't start). */\nexport type Runner = (\n\tcommand: string,\n\targs: string[],\n\toptions: { cwd: string; quiet?: boolean },\n) => Promise<number>;\n\nexport interface InitOptions {\n\t/** Where the command runs. */\n\tcwd: string;\n\t/** The project folder, relative to `cwd`. Default `.`. */\n\tdir?: string;\n\t/** Package name. Default: the folder's name, made npm-safe. */\n\tname?: string;\n\t/** Default: the one running the command (`npm_config_user_agent`), else npm. */\n\tpackageManager?: PackageManager;\n\t/** `npm_config_user_agent`, for detecting the package manager and its version. */\n\tuserAgent?: string;\n\t/** Install the default fonts: Inter, JetBrains Mono, and Noto Color Emoji (default true). */\n\tfonts?: boolean;\n\t/** Also install the color emoji font (default true when fonts is true). */\n\temoji?: boolean;\n\t/** `git init` when the folder isn't in a repository yet (default true). */\n\tgit?: boolean;\n\t/** Run the package manager's install afterwards (default false). */\n\tinstall?: boolean;\n\t/** framefields version for `dependencies`. Default: this package's. */\n\tframefieldsVersion?: string;\n\t/** For tests. */\n\trun?: Runner;\n\tfetch?: Fetch;\n\tfontCatalog?: Record<string, FontSpec>;\n\tonDownload?: (spec: FontSpec) => void;\n}\n\nexport interface InitReport {\n\t/** The project folder (absolute). */\n\troot: string;\n\tname: string;\n\tpackageManager: PackageManager;\n\t/** Paths relative to `root`. */\n\twritten: string[];\n\t/** Existing files that gained missing entries. */\n\tmerged: string[];\n\t/** Existing files left as they were. */\n\tunchanged: string[];\n\tfonts: FontInstall[];\n\tfontsModule: FontsModule;\n\tgit: \"initialized\" | \"existing\" | \"skipped\" | \"unavailable\";\n\t/** Whether `git lfs` is available (null when Git was skipped). */\n\tlfs: boolean | null;\n\tinstalled: boolean;\n\t/** `npm run frames` / `pnpm frames` …, for next-step messages. */\n\trunScript(script: string): string;\n}\n\n/** The package manager in `npm_config_user_agent` (`pnpm/10.13.1 npm/? node/v22 …`). */\nexport function detectPackageManager(\n\tuserAgent: string | undefined,\n): { name: PackageManager; version?: string } | null {\n\tconst m = userAgent?.match(/^(npm|pnpm|yarn|bun)\\/(\\d[\\w.+-]*)/);\n\tif (!m) return null;\n\treturn { name: m[1] as PackageManager, version: m[2] };\n}\n\nconst runScriptFor = (pm: PackageManager) => (script: string) =>\n\tpm === \"npm\" || pm === \"bun\" ? `${pm} run ${script}` : `${pm} ${script}`;\n\n/** `My Film!` → `my-film`. */\nexport function packageName(folder: string): string {\n\tconst name = folder\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9._~-]+/g, \"-\")\n\t\t.replace(/^[-._]+|[-._]+$/g, \"\");\n\treturn name || \"framefields-film\";\n}\n\nexport async function init(options: InitOptions): Promise<InitReport> {\n\tconst root = resolve(options.cwd, options.dir ?? \".\");\n\tmkdirSync(root, { recursive: true });\n\tconst detected = detectPackageManager(options.userAgent);\n\tconst pm = options.packageManager ?? detected?.name ?? \"npm\";\n\tconst pmVersion = detected?.name === pm ? detected.version : undefined;\n\tconst run = options.run ?? spawnRunner;\n\tconst report: InitReport = {\n\t\troot,\n\t\tname: \"\",\n\t\tpackageManager: pm,\n\t\twritten: [],\n\t\tmerged: [],\n\t\tunchanged: [],\n\t\tfonts: [],\n\t\tfontsModule: { path: \"\", status: \"unchanged\", calls: [] },\n\t\tgit: \"skipped\",\n\t\tlfs: null,\n\t\tinstalled: false,\n\t\trunScript: runScriptFor(pm),\n\t};\n\tconst fields = packageFields({\n\t\tframefieldsVersion: options.framefieldsVersion ?? ownVersion(),\n\t\t...(pmVersion && { packageManager: `${pm}@${pmVersion}` }),\n\t});\n\n\t// package.json: written whole, or merged without replacing anything.\n\tconst pkgPath = join(root, \"package.json\");\n\tif (existsSync(pkgPath)) {\n\t\tconst pkg = JSON.parse(readFileSync(pkgPath, \"utf8\")) as Record<\n\t\t\tstring,\n\t\t\tunknown\n\t\t>;\n\t\tif (pkg.type === \"commonjs\")\n\t\t\tthrow new Error(\n\t\t\t\t'package.json has \"type\": \"commonjs\". framefields projects are ES modules: set \"type\": \"module\" (and convert any require() files) first.',\n\t\t\t);\n\t\treport.name =\n\t\t\ttypeof pkg.name === \"string\" ? pkg.name : packageName(basename(root));\n\t\tconst merged = mergePackage(pkg, fields);\n\t\trecord(report, \"package.json\", writeIfChanged(pkgPath, merged, pkg));\n\t} else {\n\t\treport.name = options.name ?? packageName(basename(root));\n\t\twriteJson(pkgPath, {\n\t\t\tname: report.name,\n\t\t\tversion: \"0.0.0\",\n\t\t\tprivate: true,\n\t\t\t...fields,\n\t\t});\n\t\treport.written.push(\"package.json\");\n\t}\n\n\tconst files: Array<[string, string]> = [\n\t\t[\"tsconfig.json\", TSCONFIG],\n\t\t[\"src/theme.ts\", THEME_TS],\n\t\t[\"src/film.ts\", FILM_TS],\n\t\t[\"src/render.ts\", RENDER_TS],\n\t\t[\"assets/footage/.gitkeep\", \"\"],\n\t\t[\".env.example\", ENV_EXAMPLE],\n\t\t[\"README.md\", readme(report.name, report.runScript)],\n\t];\n\tfor (const [path, content] of files) {\n\t\tconst target = join(root, path);\n\t\tif (existsSync(target)) report.unchanged.push(path);\n\t\telse {\n\t\t\tmkdirSync(dirname(target), { recursive: true });\n\t\t\twriteFileSync(target, content);\n\t\t\treport.written.push(path);\n\t\t}\n\t}\n\tfor (const [path, lines] of [\n\t\t[\".gitignore\", GITIGNORE],\n\t\t[\".gitattributes\", GITATTRIBUTES],\n\t] as const)\n\t\trecord(report, path, appendLines(join(root, path), lines));\n\n\t// framefields.json (components folder, named renders), then fonts (recorded there) and their module.\n\tconst configExisted = existsSync(join(root, CONFIG_FILE));\n\tconst { config, saved } = readConfig(root);\n\tif (!saved || !config.renders) {\n\t\twriteConfig(root, {\n\t\t\t...config,\n\t\t\trenders: config.renders ?? defaultRenders(basename(root)),\n\t\t});\n\t\trecord(report, CONFIG_FILE, configExisted || \"written\");\n\t}\n\tconst installFonts = options.fonts !== false;\n\tconst installEmoji = options.emoji ?? installFonts;\n\tconst roles = [\n\t\t...(installFonts ? [\"sans\", \"mono\"] : []),\n\t\t...(installEmoji ? [\"emoji\"] : []),\n\t];\n\tfor (const role of roles)\n\t\treport.fonts.push(\n\t\t\tawait installFont(role, {\n\t\t\t\tcwd: root,\n\t\t\t\tfetch: options.fetch,\n\t\t\t\tcatalog: options.fontCatalog,\n\t\t\t\tonDownload: options.onDownload,\n\t\t\t}),\n\t\t);\n\t// theme.ts imports it, so it's written even with no fonts installed.\n\treport.fontsModule = writeFontsModule(\n\t\troot,\n\t\tresolve(root, readConfig(root).config.components),\n\t\toptions.fontCatalog,\n\t);\n\n\tif (options.git !== false) {\n\t\tconst inside = await run(\"git\", [\"rev-parse\", \"--is-inside-work-tree\"], {\n\t\t\tcwd: root,\n\t\t\tquiet: true,\n\t\t});\n\t\tif (inside === 0) report.git = \"existing\";\n\t\telse if (\n\t\t\t(await run(\"git\", [\"init\", \"-q\"], { cwd: root, quiet: true })) === 0\n\t\t)\n\t\t\treport.git = \"initialized\";\n\t\telse report.git = \"unavailable\";\n\t\tif (report.git !== \"unavailable\")\n\t\t\treport.lfs =\n\t\t\t\t(await run(\"git\", [\"lfs\", \"version\"], { cwd: root, quiet: true })) ===\n\t\t\t\t0;\n\t}\n\n\tif (options.install) {\n\t\tconst code = await run(pm, [\"install\"], { cwd: root });\n\t\tif (code !== 0)\n\t\t\tthrow new Error(\n\t\t\t\t`\\`${pm} install\\` failed (exit ${code}). The project files are written; fix the error and run it again.`,\n\t\t\t);\n\t\treport.installed = true;\n\t}\n\treturn report;\n}\n\n/** Add every field of `fields` the package lacks; existing values win. */\nfunction mergePackage(\n\tpkg: Record<string, unknown>,\n\tfields: ReturnType<typeof packageFields>,\n): Record<string, unknown> {\n\tconst out: Record<string, unknown> = { ...pkg };\n\tconst obj = (v: unknown) =>\n\t\tv && typeof v === \"object\" && !Array.isArray(v)\n\t\t\t? (v as Record<string, unknown>)\n\t\t\t: {};\n\tconst union = (a: unknown, b: readonly string[]) => [\n\t\t...new Set([...(Array.isArray(a) ? (a as string[]) : []), ...b]),\n\t];\n\tout.type ??= fields.type;\n\tif (fields.packageManager) out.packageManager ??= fields.packageManager;\n\tfor (const key of [\n\t\t\"scripts\",\n\t\t\"dependencies\",\n\t\t\"devDependencies\",\n\t\t\"allowScripts\",\n\t] as const) {\n\t\tconst theirs = obj(pkg[key]);\n\t\t// A dependency listed in either block counts as present.\n\t\tconst present =\n\t\t\tkey === \"dependencies\" || key === \"devDependencies\"\n\t\t\t\t? { ...obj(pkg.dependencies), ...obj(pkg.devDependencies) }\n\t\t\t\t: theirs;\n\t\tconst missing = Object.entries(fields[key]).filter(\n\t\t\t([k]) => !(k in present),\n\t\t);\n\t\tif (missing.length > 0)\n\t\t\tout[key] = { ...theirs, ...Object.fromEntries(missing) };\n\t}\n\tconst pnpm = obj(pkg.pnpm);\n\tout.pnpm = {\n\t\t...pnpm,\n\t\tonlyBuiltDependencies: union(\n\t\t\tpnpm.onlyBuiltDependencies,\n\t\t\tfields.pnpm.onlyBuiltDependencies,\n\t\t),\n\t\tignoredBuiltDependencies: union(\n\t\t\tpnpm.ignoredBuiltDependencies,\n\t\t\tfields.pnpm.ignoredBuiltDependencies,\n\t\t),\n\t};\n\tout.trustedDependencies = union(\n\t\tpkg.trustedDependencies,\n\t\tfields.trustedDependencies,\n\t);\n\treturn out;\n}\n\nfunction writeJson(path: string, value: unknown) {\n\twriteFileSync(path, `${JSON.stringify(value, null, \"\\t\")}\\n`);\n}\n\nfunction writeIfChanged(\n\tpath: string,\n\tnext: Record<string, unknown>,\n\tprev: Record<string, unknown>,\n): boolean {\n\tif (JSON.stringify(next) === JSON.stringify(prev)) return false;\n\twriteJson(path, next);\n\treturn true;\n}\n\n/** Create `path` with `lines` (\"written\"), or append the ones it lacks (true if any). */\nfunction appendLines(\n\tpath: string,\n\tlines: readonly string[],\n): \"written\" | boolean {\n\tif (!existsSync(path)) {\n\t\twriteFileSync(path, `${lines.join(\"\\n\")}\\n`);\n\t\treturn \"written\";\n\t}\n\tconst text = readFileSync(path, \"utf8\");\n\tconst have = new Set(text.split(/\\r?\\n/).map((l) => l.trim()));\n\tconst missing = lines.filter((l) => !have.has(l));\n\tif (missing.length === 0) return false;\n\twriteFileSync(\n\t\tpath,\n\t\t`${text}${text.endsWith(\"\\n\") || text === \"\" ? \"\" : \"\\n\"}${missing.join(\"\\n\")}\\n`,\n\t);\n\treturn true;\n}\n\n/** File it under written (new), merged (changed) or unchanged. */\nfunction record(report: InitReport, path: string, result: \"written\" | boolean) {\n\tif (result === \"written\") report.written.push(path);\n\telse if (result) report.merged.push(path);\n\telse report.unchanged.push(path);\n}\n\n/** This package's version, from the nearest `package.json` named framefields. */\nexport function ownVersion(): string {\n\tlet dir = dirname(fileURLToPath(import.meta.url));\n\tfor (;;) {\n\t\tconst file = join(dir, \"package.json\");\n\t\tif (existsSync(file)) {\n\t\t\tconst pkg = JSON.parse(readFileSync(file, \"utf8\")) as {\n\t\t\t\tname?: string;\n\t\t\t\tversion?: string;\n\t\t\t};\n\t\t\tif (pkg.name === \"framefields\" && pkg.version) return pkg.version;\n\t\t}\n\t\tconst up = dirname(dir);\n\t\tif (up === dir) throw new Error(\"Can't find framefields' own package.json\");\n\t\tdir = up;\n\t}\n}\n\nconst spawnRunner: Runner = (command, args, { cwd, quiet }) =>\n\tnew Promise((done) => {\n\t\tconst child = spawn(command, args, {\n\t\t\tcwd,\n\t\t\tstdio: quiet ? \"ignore\" : \"inherit\",\n\t\t\t// Windows needs a shell to find npm.cmd / pnpm.cmd.\n\t\t\tshell: process.platform === \"win32\",\n\t\t});\n\t\tchild.on(\"error\", () => done(127));\n\t\tchild.on(\"close\", (code) => done(code ?? 1));\n\t});\n\n/** Where the project is, as the user would `cd` to it. */\nexport function shownPath(cwd: string, root: string): string {\n\treturn relative(cwd, root) || \".\";\n}\n","/**\n * Node arguments to run a CLI worker against the user's project: the\n * project's own tsx loader for a TypeScript entry (TypeScript belongs to the\n * consumer project; init's scaffold has it), and the worker script, from\n * source when the CLI runs from source.\n */\nimport { createRequire } from \"node:module\";\nimport { resolve } from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\n\nexport function projectNodeArgs(\n\tentry: string,\n\tworker: \"check-worker\" | \"local-worker\",\n): string[] | { error: string } {\n\tconst source = import.meta.url.endsWith(\".ts\");\n\tconst args = source ? [\"--conditions=development\"] : [];\n\tif (source || /\\.[cm]?tsx?$/.test(entry)) {\n\t\ttry {\n\t\t\tconst require = createRequire(resolve(\"package.json\"));\n\t\t\targs.push(\"--import\", pathToFileURL(require.resolve(\"tsx\")).href);\n\t\t} catch {\n\t\t\treturn {\n\t\t\t\terror:\n\t\t\t\t\t\"Install the project's tsx dev dependency to load a TypeScript entry.\",\n\t\t\t};\n\t\t}\n\t}\n\targs.push(\n\t\tfileURLToPath(\n\t\t\tnew URL(\n\t\t\t\tsource ? `./${worker}.ts` : `./cli/${worker}.mjs`,\n\t\t\t\timport.meta.url,\n\t\t\t),\n\t\t),\n\t);\n\treturn args;\n}\n","import { spawn } from \"node:child_process\";\nimport { resolve } from \"node:path\";\nimport { type CheckReport, failedCheck } from \"./check-result.js\";\nimport { ownVersion } from \"./init.js\";\nimport { projectNodeArgs } from \"./project-node.js\";\n\nexport interface CheckOptions {\n\t/** Module path, resolved from the project working directory. */\n\tentry: string;\n\t/** Composition or builder export. Defaults to buildFilm. */\n\texportName?: string;\n\t/** Also probe the GPU and write a representative PNG and bounded grid. */\n\trender?: boolean;\n\t/** Artifact directory. Defaults to output/check, relative to the working directory. */\n\toutputDir?: string;\n\t/** Maximum worker lifetime in milliseconds. Defaults to 60000. */\n\ttimeoutMs?: number;\n\t/** Treat lint warnings as a failed check. Defaults to false. */\n\twarningsAsErrors?: boolean;\n}\n\n/** The worker's IPC result is separate from arbitrary builder stdout/stderr. */\nexport async function runCheck(options: CheckOptions): Promise<CheckReport> {\n\tconst entry = resolve(options.entry);\n\tconst exportName = options.exportName ?? \"buildFilm\";\n\tconst sdkVersion = ownVersion();\n\tconst timeout = options.timeoutMs ?? 60_000;\n\tif (!Number.isSafeInteger(timeout) || timeout <= 0)\n\t\tthrow new Error(\"--timeout must be a positive integer in milliseconds\");\n\tconst fail = (code: string, message: string) =>\n\t\tfailedCheck(entry, exportName, sdkVersion, code, message);\n\tconst args = projectNodeArgs(entry, \"check-worker\");\n\tif (\"error\" in args) return fail(\"missing_ts_loader\", args.error);\n\treturn new Promise((done) => {\n\t\tconst child = spawn(process.execPath, args, {\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\", \"ipc\"],\n\t\t});\n\t\tchild.stdout?.pipe(process.stderr);\n\t\tchild.stderr?.pipe(process.stderr);\n\t\tlet result: CheckReport | undefined;\n\t\tconst timer = setTimeout(() => {\n\t\t\tresult = fail(\n\t\t\t\t\"check_timeout\",\n\t\t\t\t`Check exceeded ${timeout}ms; worker terminated.`,\n\t\t\t);\n\t\t\tchild.kill(\"SIGKILL\");\n\t\t}, timeout);\n\t\tchild.on(\"message\", (message: unknown) => {\n\t\t\tif (isCheckReport(message)) result = message;\n\t\t});\n\t\tchild.on(\"error\", (error) => {\n\t\t\tclearTimeout(timer);\n\t\t\tdone(fail(\"worker_start_failed\", error.message));\n\t\t});\n\t\tchild.on(\"close\", (code, signal) => {\n\t\t\tclearTimeout(timer);\n\t\t\tdone(\n\t\t\t\tresult ??\n\t\t\t\t\tfail(\n\t\t\t\t\t\t\"worker_failed\",\n\t\t\t\t\t\t`Check worker exited without a result (code ${code}, signal ${signal}).`,\n\t\t\t\t\t),\n\t\t\t);\n\t\t});\n\t\tchild.send({\n\t\t\t...options,\n\t\t\tentry,\n\t\t\texportName,\n\t\t\tsdkVersion,\n\t\t\toutputDir: resolve(options.outputDir ?? \"output/check\"),\n\t\t});\n\t});\n}\n\nfunction isCheckReport(value: unknown): value is CheckReport {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"schemaVersion\" in value &&\n\t\tvalue.schemaVersion === 1 &&\n\t\t\"diagnostics\" in value &&\n\t\tArray.isArray(value.diagnostics)\n\t);\n}\n","/**\n * `framefields render <name|entry> --cloud`: renders the project on\n * api.framefields.dev and downloads the video. `name` is a render in\n * framefields.json; a module path renders without one. Prints one plain\n * line per phase, and a progress line at most every 10 seconds while\n * frames render.\n */\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport {\n\tCloudRenderError,\n\ttype CloudRenderOptions,\n\ttype CloudRenderStatus,\n\trenderCloud,\n} from \"../cloud/index.js\";\nimport {\n\tCONFIG_FILE,\n\tfindRender,\n\ttype RenderSpec,\n\treadConfig,\n} from \"./config.js\";\n\nexport interface CloudCliOptions {\n\t/** A render named in framefields.json, or a module path. Optional when framefields.json has one render. */\n\tentry?: string;\n\texport?: string;\n\tselect?: string;\n\tworkers?: string;\n\tmaxWorkers?: string;\n\tcodec?: string;\n\tquality?: string;\n\toutput?: string;\n\tplan?: boolean;\n\tjson?: boolean;\n\t/** Project folder. Default `process.cwd()`. */\n\tcwd?: string;\n}\n\nconst PROGRESS_EVERY_MS = 10_000;\n\nexport async function runCloudRender(\n\to: CloudCliOptions,\n\tlog: (line: string) => void,\n\trender: (\n\t\toptions: CloudRenderOptions,\n\t) => Promise<CloudRenderStatus> = renderCloud,\n): Promise<number> {\n\tconst cwd = o.cwd ?? process.cwd();\n\tconst workers = parseWorkers(o.workers);\n\tif (workers === null) {\n\t\tlog(\n\t\t\t`--workers must be \"auto\" or a positive whole number, not \"${o.workers}\".`,\n\t\t);\n\t\treturn 2;\n\t}\n\tif (o.codec && o.codec !== \"h264\" && o.codec !== \"vp9\") {\n\t\tlog(`--codec must be h264 or vp9, not \"${o.codec}\".`);\n\t\treturn 2;\n\t}\n\tconst target = pickRender(o.entry, cwd);\n\tif (\"error\" in target) {\n\t\tlog(target.error);\n\t\treturn 2;\n\t}\n\tconst spec = target.name ? findRender(cwd, target.name) : undefined;\n\tconst codec = (o.codec ?? spec?.codec ?? \"h264\") as \"h264\" | \"vp9\";\n\tconst outputPath = renderOutput(target, spec, codec, o.output);\n\t// A plan of a one-worker render would only ever say \"one worker\".\n\tconst planWorkers =\n\t\to.plan && (workers ?? spec?.workers ?? 1) === 1 ? \"auto\" : workers;\n\tconst controller = new AbortController();\n\tconst onSigint = () => {\n\t\tlog(\"Cancelling the cloud render…\");\n\t\tcontroller.abort(new Error(\"cancelled\"));\n\t};\n\tprocess.once(\"SIGINT\", onSigint);\n\tconst started = Date.now();\n\tconst narrate = narrator(o.json ? () => {} : log, Date.now);\n\ttry {\n\t\tconst result = await render({\n\t\t\tcwd,\n\t\t\trender: target.name,\n\t\t\tentry: target.entry,\n\t\t\texport: o.export,\n\t\t\tselect: o.select,\n\t\t\tworkers: planWorkers,\n\t\t\tmaxWorkers: o.maxWorkers ? Number(o.maxWorkers) : undefined,\n\t\t\tcodec: o.codec as \"h264\" | \"vp9\" | undefined,\n\t\t\tquality: o.quality,\n\t\t\tdryRun: o.plan,\n\t\t\toutputPath: o.plan ? undefined : outputPath,\n\t\t\tsignal: controller.signal,\n\t\t\tonProgress: narrate,\n\t\t\tonWarning: (m) => log(`warning: ${m}`),\n\t\t\tonLog: log,\n\t\t});\n\t\tif (o.json) {\n\t\t\tlog(JSON.stringify(result));\n\t\t\treturn 0;\n\t\t}\n\t\tif (result.status === \"planned\") {\n\t\t\tconst planned = planWorkers === \"auto\" && spec?.workers !== \"auto\";\n\t\t\tlog(\n\t\t\t\t`Render it: ${renderCommand({ ...o, entry: target.name ?? target.entry, workers: o.workers ?? (planned ? \"auto\" : undefined) })}`,\n\t\t\t);\n\t\t\treturn 0;\n\t\t}\n\t\tconst bytes = result.output?.bytes;\n\t\tlog(\n\t\t\t`Done in ${duration((Date.now() - started) / 1000)}: ${outputPath}${bytes ? ` (${(bytes / 1e6).toFixed(1)} MB)` : \"\"}, ${Math.round(result.gpuSeconds)} GPU seconds, ${usd(result.costUsd)}.`,\n\t\t);\n\t\treturn 0;\n\t} catch (err) {\n\t\tif (err instanceof CloudRenderError) {\n\t\t\tlog(err.message);\n\t\t\tif (err.status && err.status.costUsd > 0)\n\t\t\t\tlog(`Charged ${usd(err.status.costUsd)} for the GPU time used.`);\n\t\t\tif (err.code === \"insufficient_credits\")\n\t\t\t\tlog(\"Top up at https://framefields.dev/dashboard/billing\");\n\t\t\treturn 1;\n\t\t}\n\t\tthrow err;\n\t} finally {\n\t\tprocess.removeListener(\"SIGINT\", onSigint);\n\t}\n}\n\n/** The command that renders what `--plan` just planned: the same options, without `--plan`. */\nexport function renderCommand(o: CloudCliOptions): string {\n\tconst flags: [string, string | undefined][] = [\n\t\t[\"--export\", o.export],\n\t\t[\"--select\", o.select],\n\t\t[\"--workers\", o.workers],\n\t\t[\"--max-workers\", o.maxWorkers],\n\t\t[\"--codec\", o.codec],\n\t\t[\"--quality\", o.quality],\n\t\t[\"--output\", o.output],\n\t];\n\treturn [\n\t\t`framefields render ${o.entry ?? \"\"} --cloud`.replace(\" \", \" \"),\n\t\t...flags.filter(([, v]) => v !== undefined).map(([f, v]) => `${f} ${v}`),\n\t].join(\" \");\n}\n\n/** What a render named `name` (or the module `entry`) produces, wherever it runs. */\nexport function renderOutput(\n\ttarget: { name?: string; entry?: string },\n\tspec: RenderSpec | undefined,\n\tcodec: string,\n\toutput?: string,\n): string {\n\tconst base =\n\t\ttarget.name ?? path.basename(target.entry ?? \"\").replace(/\\.[^.]+$/, \"\");\n\treturn (\n\t\toutput ??\n\t\tspec?.output ??\n\t\tpath.join(\"output\", `${base}.${codec === \"vp9\" ? \"webm\" : \"mp4\"}`)\n\t);\n}\n\n/**\n * What `framefields render [arg]` renders: a render named in framefields.json,\n * or a module path; with no argument, the project's only named render.\n */\nexport function pickRender(\n\targ: string | undefined,\n\tcwd: string,\n): { name?: string; entry?: string } | { error: string } {\n\tconst renders = readConfig(cwd).config.renders ?? {};\n\tconst names = Object.keys(renders);\n\tif (arg === undefined) {\n\t\tif (names.length === 1) return { name: names[0] };\n\t\treturn {\n\t\t\terror: names.length\n\t\t\t\t? `Name the render: ${names.join(\", \")}. \\`framefields renders\\` lists them.`\n\t\t\t\t: `Name a module, e.g. \\`framefields render src/film.ts\\`, or add \"renders\" to ${CONFIG_FILE}.`,\n\t\t};\n\t}\n\tif (renders[arg]) return { name: arg };\n\tif (existsSync(path.resolve(cwd, arg))) return { entry: arg };\n\treturn {\n\t\terror: names.length\n\t\t\t? `\"${arg}\" is neither a render in ${CONFIG_FILE} (${names.join(\", \")}) nor a file.`\n\t\t\t: `\"${arg}\" is not a file, and ${CONFIG_FILE} names no renders.`,\n\t};\n}\n\n/** --workers: undefined when not given, null when invalid. */\nfunction parseWorkers(\n\tvalue: string | undefined,\n): number | \"auto\" | undefined | null {\n\tif (value === undefined) return undefined;\n\tif (value === \"auto\") return \"auto\";\n\tconst n = Number(value);\n\treturn Number.isInteger(n) && n >= 1 ? n : null;\n}\n\n/** Turns status polls into log lines: one per phase, throttled frame progress. */\nexport function narrator(\n\tlog: (line: string) => void,\n\tnow: () => number,\n): (s: CloudRenderStatus) => void {\n\tlet phase: string | undefined;\n\tlet planned = false;\n\tlet lastProgress = 0;\n\treturn (s) => {\n\t\tif (!phase) log(`Cloud render ${s.id} started.`);\n\t\tif (s.plan && !planned) {\n\t\t\tplanned = true;\n\t\t\tlog(describePlan(s));\n\t\t}\n\t\tif (s.status !== phase) {\n\t\t\tphase = s.status;\n\t\t\tconst line = phaseLine(s);\n\t\t\tif (line) log(line);\n\t\t\tlastProgress = now();\n\t\t\treturn;\n\t\t}\n\t\tif (s.status === \"rendering\" && now() - lastProgress >= PROGRESS_EVERY_MS) {\n\t\t\tlastProgress = now();\n\t\t\tlog(progressLine(s));\n\t\t}\n\t};\n}\n\nexport function describePlan(s: CloudRenderStatus): string {\n\tconst plan = s.plan;\n\tif (!plan) return \"\";\n\tconst est =\n\t\ts.estimateUsd !== undefined ? `, estimated ${usd(s.estimateUsd)}` : \"\";\n\treturn `Plan: ${plan.workers} ${plan.workers === 1 ? \"worker\" : \"workers\"}, ${duration(plan.workSec)} of render work, ready in about ${duration(plan.etaSec)}${est}.`;\n}\n\nfunction phaseLine(s: CloudRenderStatus): string | undefined {\n\tswitch (s.status) {\n\t\tcase \"probing\":\n\t\t\treturn \"Measuring frame costs on one worker to plan the split…\";\n\t\tcase \"rendering\":\n\t\t\treturn s.workers > 1\n\t\t\t\t? `Rendering ${s.workers} chunks and the audio in parallel…`\n\t\t\t\t: \"Rendering on one worker…\";\n\t\tcase \"stitching\":\n\t\t\treturn `Joining ${s.workers} chunks…`;\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nexport function progressLine(s: CloudRenderStatus): string {\n\tconst { frames, totalFrames, etaSec } = s.progress;\n\tconst share = totalFrames\n\t\t? `${Math.floor((frames / totalFrames) * 100)}% (${frames}/${totalFrames} frames)`\n\t\t: `${frames} frames`;\n\tconst eta = etaSec ? `, about ${duration(etaSec)} left` : \"\";\n\treturn `Rendering ${share}${eta}, ${usd(s.costUsd)} so far.`;\n}\n\nexport function duration(sec: number): string {\n\tconst s = Math.max(0, Math.round(sec));\n\tif (s < 90) return `${s} s`;\n\tconst m = Math.round(s / 60);\n\tif (m < 90) return `${m} min`;\n\treturn `${Math.floor(m / 60)} h ${m % 60} min`;\n}\n\nexport function usd(value: number): string {\n\treturn value > 0 && value < 0.01 ? \"<$0.01\" : `$${value.toFixed(2)}`;\n}\n","/**\n * `framefields render [name|entry]` and `framefields preview [name|entry]`\n * on this machine. They read the same named renders in framefields.json as\n * `--cloud`, so a render goes to the same file wherever it runs.\n *\n * A local render first downloads pinned assets that are missing here; a\n * preview doesn't need to: the page streams them from their bucket.\n */\nimport { spawn } from \"node:child_process\";\nimport { createRequire } from \"node:module\";\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { AssetsError, megabytes, pullAssets } from \"./assets.js\";\nimport { pickRender, renderOutput } from \"./cloud.js\";\nimport { findRender, readConfig } from \"./config.js\";\nimport type { LocalJob, LocalResult } from \"./local-worker.js\";\nimport { projectNodeArgs } from \"./project-node.js\";\n\nexport interface LocalCliOptions {\n\t/** A render named in framefields.json, or a module path. */\n\tentry?: string;\n\texport?: string;\n\tselect?: string;\n\tcodec?: string;\n\tquality?: string;\n\toutput?: string;\n\t/** Project folder. Default `process.cwd()`. */\n\tcwd?: string;\n}\n\nexport async function runLocal(\n\tmode: LocalJob[\"mode\"],\n\to: LocalCliOptions,\n\tlog: (line: string) => void,\n): Promise<number> {\n\tconst cwd = o.cwd ?? process.cwd();\n\tconst target = pickRender(o.entry, cwd);\n\tif (\"error\" in target) {\n\t\tlog(target.error);\n\t\treturn 2;\n\t}\n\tconst spec = target.name ? findRender(cwd, target.name) : undefined;\n\tconst entry = path.resolve(cwd, spec?.entry ?? (target.entry as string));\n\tconst codec = o.codec ?? spec?.codec ?? \"h264\";\n\tif (codec !== \"h264\" && codec !== \"vp9\") {\n\t\tlog(`--codec must be h264 or vp9, not \"${codec}\".`);\n\t\treturn 2;\n\t}\n\tconst engine = projectEngine(entry);\n\tif (!engine) {\n\t\tlog(\"framefields isn't installed in this project: `npm i framefields`.\");\n\t\treturn 2;\n\t}\n\tconst job: LocalJob = {\n\t\tmode,\n\t\tentry,\n\t\tengine,\n\t\texport: o.export ?? spec?.export ?? \"buildFilm\",\n\t\targs: spec?.args,\n\t\tselect: o.select ?? spec?.select,\n\t\tcodec,\n\t\tquality: o.quality ?? spec?.quality,\n\t\toutputPath: path.resolve(cwd, renderOutput(target, spec, codec, o.output)),\n\t\ttitle: spec?.title ?? target.name,\n\t};\n\tif (mode === \"preview\" && (job.args !== undefined || job.select))\n\t\tlog(\n\t\t\t\"The preview calls the export without args or select; it shows what the export returns by default.\",\n\t\t);\n\tif (mode === \"render\" && !(await ensureAssets(cwd, log))) return 1;\n\tconst result = await runWorker(job, cwd);\n\tif (!result.ok) {\n\t\tlog(result.message);\n\t\treturn 1;\n\t}\n\tif (result.filePath)\n\t\tlog(`Rendered ${path.relative(cwd, result.filePath) || result.filePath}`);\n\t// The video is written either way; failed QA fails the command.\n\treturn result.qaPassed === false ? 1 : 0;\n}\n\n/** The framefields the film imports, resolved from its module. */\nfunction projectEngine(entry: string): string | undefined {\n\ttry {\n\t\treturn pathToFileURL(createRequire(entry).resolve(\"framefields\")).href;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/** Downloads pinned assets missing here; false (after saying why) when it can't. */\nasync function ensureAssets(\n\tcwd: string,\n\tlog: (line: string) => void,\n): Promise<boolean> {\n\tconst assets = readConfig(cwd).config.assets ?? {};\n\tif (Object.keys(assets).length === 0) return true;\n\ttry {\n\t\tconst { downloaded, changed } = await pullAssets({ cwd, log });\n\t\tif (downloaded.length) {\n\t\t\tconst bytes = downloaded.reduce((n, p) => n + (assets[p]?.size ?? 0), 0);\n\t\t\tlog(\n\t\t\t\t`Downloaded ${downloaded.length} pinned assets (${megabytes(bytes)}).`,\n\t\t\t);\n\t\t}\n\t\tif (changed.length)\n\t\t\tlog(\n\t\t\t\t`Rendering local edits of pinned assets: ${changed.join(\", \")}. \\`framefields assets add\\` pins them for the cloud.`,\n\t\t\t);\n\t\treturn true;\n\t} catch (err) {\n\t\tif (!(err instanceof AssetsError)) throw err;\n\t\tlog(err.message);\n\t\treturn false;\n\t}\n}\n\nfunction runWorker(job: LocalJob, cwd: string): Promise<LocalResult> {\n\tconst args = projectNodeArgs(job.entry, \"local-worker\");\n\tif (\"error\" in args)\n\t\treturn Promise.resolve({ ok: false, message: args.error });\n\treturn new Promise((done) => {\n\t\tconst child = spawn(process.execPath, args, {\n\t\t\tcwd,\n\t\t\tstdio: [\"inherit\", \"inherit\", \"inherit\", \"ipc\"],\n\t\t});\n\t\tlet result: LocalResult | undefined;\n\t\tchild.on(\"message\", (message: LocalResult) => {\n\t\t\tresult = message;\n\t\t});\n\t\tchild.on(\"error\", (error) => done({ ok: false, message: error.message }));\n\t\tchild.on(\"close\", (code, signal) =>\n\t\t\tdone(\n\t\t\t\tresult ??\n\t\t\t\t\t(signal === \"SIGINT\" || code === 130\n\t\t\t\t\t\t? { ok: false, message: \"Stopped.\" }\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\tok: false,\n\t\t\t\t\t\t\t\tmessage: `The ${job.mode} exited without a result (code ${code}, signal ${signal}).`,\n\t\t\t\t\t\t\t}),\n\t\t\t),\n\t\t);\n\t\tchild.send(job);\n\t});\n}\n","/**\n * Reading a component registry: the one shipped in this package's dist, a\n * local folder, or one served over http(s). A registry is `index.json` (the\n * entries) plus `<name>.json` per component (entry, meta and files).\n */\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport interface RegistryEntry {\n\t/** What `framefields add` takes: `logo-reveal`. */\n\tname: string;\n\t/** The factory the component exports: `LogoReveal`. */\n\ttitle: string;\n\tsummary: string;\n\ttags: readonly string[];\n\texample: string;\n\t/** Other components it imports, installed with it. */\n\tregistryDependencies: string[];\n}\n\nexport interface RegistryItem extends RegistryEntry {\n\t/** Generated from the component schema and JSDoc. */\n\tprops?: ReadonlyArray<{\n\t\tname: string;\n\t\ttype: string;\n\t\trequired: boolean;\n\t\tdefault?: unknown;\n\t\tdescription?: string;\n\t}>;\n\tparts: readonly string[];\n\tcues: readonly string[];\n\t/** Fonts to install with it, by role (see `cli/fonts.ts`). */\n\tfonts?: ReadonlyArray<{ font: string; why: string }>;\n\t/** Paths relative to the components directory. */\n\tfiles: Array<{ path: string; content: string }>;\n}\n\nexport interface Registry {\n\t/** Where it was read from, for messages. */\n\tsource: string;\n\tindex(): Promise<RegistryEntry[]>;\n\titem(name: string): Promise<RegistryItem>;\n}\n\n/** The registry shipped next to this module in dist (`dist/registry`). */\nexport function bundledRegistryPath(): string {\n\treturn fileURLToPath(new URL(\"./registry/\", import.meta.url));\n}\n\n/** `source`: a folder or an http(s) URL. Default: the bundled registry. */\nexport function openRegistry(source?: string, cwd = process.cwd()): Registry {\n\tconst from =\n\t\tsource ?? process.env.FRAMEFIELDS_REGISTRY ?? bundledRegistryPath();\n\tif (/^https?:\\/\\//.test(from)) {\n\t\tconst base = from.endsWith(\"/\") ? from : `${from}/`;\n\t\tconst get = async <T>(file: string): Promise<T> => {\n\t\t\tconst res = await fetch(new URL(file, base));\n\t\t\tif (!res.ok)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${new URL(file, base)}: ${res.status} ${res.statusText}`,\n\t\t\t\t);\n\t\t\treturn (await res.json()) as T;\n\t\t};\n\t\treturn {\n\t\t\tsource: base,\n\t\t\tindex: () => get(\"index.json\"),\n\t\t\titem: (name) => get(`${name}.json`),\n\t\t};\n\t}\n\tconst dir = resolve(cwd, from);\n\tconst read = <T>(file: string): T => {\n\t\tconst path = join(dir, file);\n\t\tif (!existsSync(path)) throw new Error(`No ${file} in registry ${dir}`);\n\t\treturn JSON.parse(readFileSync(path, \"utf8\")) as T;\n\t};\n\treturn {\n\t\tsource: dir,\n\t\tindex: async () => read(\"index.json\"),\n\t\titem: async (name) => read(`${name}.json`),\n\t};\n}\n","#!/usr/bin/env node\n/**\n * The `framefields` command.\n *\n * npx framefields init [dir] start a project (or add framefields to one)\n * npx framefields add <name...> copy components into this project\n * npx framefields list the components you can add\n * npx framefields fonts add <role...> install fonts (emoji)\n * npx framefields fonts list the fonts you can install\n * npx framefields assets add|push|pull|status media on your own bucket\n * npx framefields renders the renders named in framefields.json\n * npx framefields render <name> render on this machine's GPU\n * npx framefields render <name> --cloud render on api.framefields.dev\n * npx framefields preview <name> play it in the browser\n */\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join, relative, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { parseArgs } from \"node:util\";\nimport { type AddReport, add } from \"./cli/add.js\";\nimport { runAssets } from \"./cli/assets.js\";\nimport { runCheck } from \"./cli/check.js\";\nimport { runCloudRender } from \"./cli/cloud.js\";\nimport { readConfig } from \"./cli/config.js\";\nimport {\n\tFONTS,\n\ttype FontSpec,\n\tinstallFont,\n\tlfsHint,\n\twriteFontsModule,\n} from \"./cli/fonts.js\";\nimport {\n\ttype InitReport,\n\tinit,\n\townVersion,\n\tPACKAGE_MANAGERS,\n\ttype PackageManager,\n\tshownPath,\n} from \"./cli/init.js\";\nimport { runLocal } from \"./cli/local.js\";\nimport { openRegistry } from \"./cli/registry.js\";\nimport { AI_DASHBOARD } from \"./cli/templates.js\";\n\nconst HELP = `Usage: framefields <command> [options]\n\nCommands:\n api JSON reference generated from timing, grid and check types.\n check [name|entry]\n Build, validate and lint a composition; --render also writes a\n representative frame and grid. A render named in\n framefields.json, or a module (--export defaults to\n buildFilm); with neither, every named render.\n init [dir] Start a framefields project in dir (default: here), or add\n framefields to the project there: package.json, tsconfig,\n src/theme.ts, film.ts, render.ts, assets/, .gitignore,\n LFS .gitattributes, and the themes' fonts. Never\n overwrites; existing files only gain what they lack.\n add <name...> Copy components' source into this project (and the\n components they build on). The code is yours to edit.\n list List the components you can add.\n fonts add <role...>\n Install fonts (pinned, hash-checked, with their license)\n and register them in the generated <components>/fonts.ts.\n fonts list List the fonts you can install.\n assets add <path...>\n Keep media out of git: hash files (or every file in a\n folder), upload them to the project's bucket (R2, S3, any\n S3-compatible storage) and pin them in framefields.json.\n assets push Upload recorded assets the bucket lacks.\n assets pull Download missing assets, checked against their sha256.\n assets status Which assets are here, missing or changed.\n renders List the renders named in framefields.json.\n render [name|entry]\n Render on this machine: a render named in framefields.json\n (its fields are the defaults; flags override them), or a\n module (--export defaults to buildFilm). Without either,\n the project's only named render. Pinned assets missing\n here are downloaded first.\n render [name|entry] --cloud\n The same render on api.framefields.dev, from the pushed\n commit of this git repo, downloaded to the same file.\n Needs FRAMEFIELDS_API_KEY.\n preview [name|entry]\n Play it in the browser (localhost, WebGPU). Pinned assets\n that aren't here stream from their bucket.\n\nOptions for check:\n --export <name> Composition or builder export (default buildFilm).\n --render Also verify the GPU and render a small frame/grid.\n --output <dir> Inspection artifacts (default output/check).\n --timeout <ms> Worker timeout in milliseconds (default 60000).\n --warnings-as-errors Fail on lint warnings.\n --json Machine-readable check, component list, or font list result.\n\nOptions for render and preview:\n --export, --select, --codec, --quality and --output (render) override the\n named render's fields, locally and with --cloud.\n\nOptions for render --cloud:\n --workers <n|auto> 1 (default) renders on one GPU. auto measures the film\n first and splits it across as many GPUs as stay\n efficient; a number splits it into that many.\n --max-workers <n> Upper bound for auto.\n --plan Measure and plan only: prints workers, time and the\n estimated cost, renders nothing.\n --output <file> Where the video goes (default output/<name>.mp4).\n --codec <codec> h264 (default) or vp9.\n --quality <q> very_low, low, high or very_high (default).\n --select <name> When the export returns several compositions.\n --json Print the final status as JSON.\n Ctrl-C cancels the render; GPU time already used is charged.\n\nOptions for assets:\n --remote <name> The remote in framefields.json \"storage\" (default: its\n default, or its only one).\n --overwrite pull: replace files changed locally.\n Keys: FRAMEFIELDS_STORAGE_<REMOTE>_ACCESS_KEY_ID and _SECRET_ACCESS_KEY,\n or AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. Reads need none when the\n remote has a publicUrl (a custom domain or CDN in front of the bucket).\n\nOptions for init:\n --name <name> Package name (default: the folder's name).\n --pm <manager> npm, pnpm, yarn or bun (default: the one running this).\n --install Install dependencies afterwards.\n --no-fonts Skip fonts (Inter, JetBrains Mono, Noto Color Emoji).\n --no-emoji Skip the color emoji font.\n --no-git Don't run \\`git init\\`.\n\nOptions for add:\n --all Add every component.\n --dir <path> Components directory (default: from framefields.json,\n else src/components or components). Saved the first time.\n --overwrite Replace files you have changed.\n --no-fonts Don't install the fonts components ask for (emoji).\n\nOptions for add and fonts add:\n --fonts-dir <path> Where downloaded fonts go (default assets/fonts).\n\nOptions for add and list:\n --registry <src> A registry folder or http(s) URL instead of the one\n shipped with this version of framefields.\n -h, --help Show this help.\n\nExamples:\n npx framefields init my-film --install\n npx framefields add mouse-pointer focus-zoom\n npx framefields fonts add emoji\n npx framefields assets add assets/footage\n npx framefields preview film\n npx framefields render film\n npx framefields render film --cloud --plan\n`;\n\nasync function main(argv: string[]): Promise<number> {\n\tconst { values, positionals } = parseArgs({\n\t\targs: argv,\n\t\tallowPositionals: true,\n\t\toptions: {\n\t\t\tall: { type: \"boolean\" },\n\t\t\tdir: { type: \"string\" },\n\t\t\toverwrite: { type: \"boolean\" },\n\t\t\t\"no-fonts\": { type: \"boolean\" },\n\t\t\t\"no-emoji\": { type: \"boolean\" },\n\t\t\t\"fonts-dir\": { type: \"string\" },\n\t\t\tname: { type: \"string\" },\n\t\t\tpm: { type: \"string\" },\n\t\t\tinstall: { type: \"boolean\" },\n\t\t\temoji: { type: \"boolean\" },\n\t\t\t\"no-git\": { type: \"boolean\" },\n\t\t\tregistry: { type: \"string\" },\n\t\t\tjson: { type: \"boolean\" },\n\t\t\texport: { type: \"string\" },\n\t\t\trender: { type: \"boolean\" },\n\t\t\toutput: { type: \"string\" },\n\t\t\ttimeout: { type: \"string\" },\n\t\t\t\"warnings-as-errors\": { type: \"boolean\" },\n\t\t\tcloud: { type: \"boolean\" },\n\t\t\tworkers: { type: \"string\" },\n\t\t\t\"max-workers\": { type: \"string\" },\n\t\t\tplan: { type: \"boolean\" },\n\t\t\tcodec: { type: \"string\" },\n\t\t\tquality: { type: \"string\" },\n\t\t\tselect: { type: \"string\" },\n\t\t\tremote: { type: \"string\" },\n\t\t\thelp: { type: \"boolean\", short: \"h\" },\n\t\t},\n\t});\n\tconst [command, ...names] = positionals;\n\tif (values.help || !command) {\n\t\tprocess.stdout.write(HELP);\n\t\treturn command || values.help ? 0 : 1;\n\t}\n\tconst cwd = process.cwd();\n\t// The project's settings (FRAMEFIELDS_API_KEY, storage keys), as its own\n\t// scripts load them; variables already set win.\n\tif (existsSync(join(cwd, \".env\"))) process.loadEnvFile(join(cwd, \".env\"));\n\tconst log = (line: string) => process.stdout.write(`${line}\\n`);\n\tif (command === \"api\") {\n\t\tconst catalog = JSON.parse(\n\t\t\treadFileSync(\n\t\t\t\tfileURLToPath(\n\t\t\t\t\tnew URL(\n\t\t\t\t\t\timport.meta.url.endsWith(\".ts\") ? \"../dist/api.json\" : \"./api.json\",\n\t\t\t\t\t\timport.meta.url,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\t\"utf8\",\n\t\t\t),\n\t\t) as object;\n\t\tlog(JSON.stringify({ ...catalog, sdkVersion: ownVersion() }));\n\t\treturn 0;\n\t}\n\tif (command === \"check\") return check(names, cwd, values, log);\n\tif (command === \"renders\") return listRenders(cwd, values.json, log);\n\tif (command === \"assets\")\n\t\treturn runAssets(names, {\n\t\t\tcwd,\n\t\t\tlog,\n\t\t\tremote: values.remote,\n\t\t\toverwrite: values.overwrite,\n\t\t\tjson: values.json,\n\t\t});\n\tif (command === \"preview\" || (command === \"render\" && !values.cloud)) {\n\t\tif (names.length > 1) {\n\t\t\tprocess.stderr.write(\n\t\t\t\t`Usage: framefields ${command} [name|entry] [--export <name>]\\n`,\n\t\t\t);\n\t\t\treturn 2;\n\t\t}\n\t\treturn runLocal(\n\t\t\tcommand === \"preview\" ? \"preview\" : \"render\",\n\t\t\t{\n\t\t\t\tentry: names[0],\n\t\t\t\texport: values.export,\n\t\t\t\tselect: values.select,\n\t\t\t\tcodec: values.codec,\n\t\t\t\tquality: values.quality,\n\t\t\t\toutput: values.output,\n\t\t\t},\n\t\t\tlog,\n\t\t);\n\t}\n\tif (command === \"render\") {\n\t\tif (names.length > 1) {\n\t\t\tprocess.stderr.write(\n\t\t\t\t\"Usage: framefields render [name|entry] --cloud [--workers auto] [--plan]\\n\",\n\t\t\t);\n\t\t\treturn 2;\n\t\t}\n\t\treturn runCloudRender(\n\t\t\t{\n\t\t\t\tentry: names[0],\n\t\t\t\texport: values.export,\n\t\t\t\tselect: values.select,\n\t\t\t\tworkers: values.workers,\n\t\t\t\tmaxWorkers: values[\"max-workers\"],\n\t\t\t\tcodec: values.codec,\n\t\t\t\tquality: values.quality,\n\t\t\t\toutput: values.output,\n\t\t\t\tplan: values.plan,\n\t\t\t\tjson: values.json,\n\t\t\t},\n\t\t\tlog,\n\t\t);\n\t}\n\tif (command === \"fonts\") return fonts(names, cwd, values, log);\n\tif (command === \"init\") {\n\t\tif (names.length > 1) {\n\t\t\tprocess.stderr.write(\n\t\t\t\t\"init takes one folder: `framefields init my-film`.\\n\",\n\t\t\t);\n\t\t\treturn 1;\n\t\t}\n\t\tif (values.pm && !PACKAGE_MANAGERS.includes(values.pm as PackageManager)) {\n\t\t\tprocess.stderr.write(\n\t\t\t\t`--pm must be one of ${PACKAGE_MANAGERS.join(\", \")}.\\n`,\n\t\t\t);\n\t\t\treturn 1;\n\t\t}\n\t\tconst report = await init({\n\t\t\tcwd,\n\t\t\tdir: names[0],\n\t\t\tname: values.name,\n\t\t\tpackageManager: values.pm as PackageManager | undefined,\n\t\t\tuserAgent: process.env.npm_config_user_agent,\n\t\t\tfonts: !values[\"no-fonts\"],\n\t\t\temoji: values[\"no-emoji\"] ? false : values.emoji,\n\t\t\tgit: !values[\"no-git\"],\n\t\t\tinstall: values.install,\n\t\t\tonDownload,\n\t\t});\n\t\tlogInit(report, cwd, log);\n\t\treturn 0;\n\t}\n\tconst registry = openRegistry(values.registry, cwd);\n\n\tif (command === \"list\") {\n\t\tconst index = await registry.index();\n\t\tif (values.json) {\n\t\t\tlog(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tschemaVersion: 1,\n\t\t\t\t\tsdkVersion: ownVersion(),\n\t\t\t\t\tcomponents: await Promise.all(\n\t\t\t\t\t\tindex.map(async (entry) => {\n\t\t\t\t\t\t\tconst { files: _files, ...item } = await registry.item(\n\t\t\t\t\t\t\t\tentry.name,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn item;\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn 0;\n\t\t}\n\t\tconst width = Math.max(...index.map((e) => e.name.length));\n\t\tfor (const e of index)\n\t\t\tprocess.stdout.write(`${e.name.padEnd(width)} ${e.summary}\\n`);\n\t\treturn 0;\n\t}\n\tif (command !== \"add\") {\n\t\tprocess.stderr.write(`Unknown command \"${command}\".\\n\\n${HELP}`);\n\t\treturn 1;\n\t}\n\n\tconst wanted = values.all\n\t\t? (await registry.index()).map((e) => e.name)\n\t\t: names;\n\tif (wanted.length === 0) {\n\t\tprocess.stderr.write(\n\t\t\t\"Name the components to add, e.g. `framefields add mouse-pointer`.\\nRun `framefields list` to see them all.\\n\",\n\t\t);\n\t\treturn 1;\n\t}\n\tconst report = await add(wanted, {\n\t\tcwd,\n\t\tregistry,\n\t\tdir: values.dir,\n\t\toverwrite: values.overwrite,\n\t\tfonts: !values[\"no-fonts\"],\n\t\tfontsDir: values[\"fonts-dir\"],\n\t\tonDownload,\n\t});\n\tfor (const f of report.written) log(` wrote ${f}`);\n\tfor (const f of report.unchanged) log(` unchanged ${f}`);\n\tfor (const f of report.skipped)\n\t\tlog(` skipped ${f} (yours differs; --overwrite replaces it)`);\n\tif (report.configWritten) log(\" wrote framefields.json\");\n\tlogFonts(report, cwd, log);\n\tconst extra = report.components.filter((c) => !wanted.includes(c.name));\n\tif (extra.length > 0)\n\t\tlog(`\\nWith what they build on: ${extra.map((c) => c.name).join(\", \")}.`);\n\twarnIfMissingFramefields(cwd, log);\n\tconst first = report.components.find((c) => wanted.includes(c.name));\n\tif (first)\n\t\tlog(\n\t\t\t`\\nimport { ${first.title} } from \"./${first.name}/index.js\"; // from ${relative(cwd, report.dir) || \".\"}`,\n\t\t);\n\treturn 0;\n}\n\nconst onDownload = (spec: FontSpec) =>\n\tprocess.stdout.write(\n\t\t` fetching ${spec.file} (${(spec.font.bytes / 1e6).toFixed(1)} MB, ${spec.license.id})\\n`,\n\t);\n\n/** What `add` did about fonts, and how to use them. */\n/** `check [name|entry]`: a named render, a module, or every named render. */\nasync function check(\n\tnames: string[],\n\tcwd: string,\n\tvalues: {\n\t\texport?: string;\n\t\trender?: boolean;\n\t\toutput?: string;\n\t\ttimeout?: string;\n\t\t\"warnings-as-errors\"?: boolean;\n\t\tjson?: boolean;\n\t},\n\tlog: (s: string) => void,\n): Promise<number> {\n\tconst renders = readConfig(cwd).config.renders ?? {};\n\tconst usage = () => {\n\t\tprocess.stderr.write(\n\t\t\t\"Usage: framefields check [name|entry] [--export buildFilm] [--render] [--json]\\n\",\n\t\t);\n\t\treturn 2;\n\t};\n\tif (names.length > 1) return usage();\n\tconst targets: { name?: string; entry: string; exportName?: string }[] =\n\t\tnames.length === 0\n\t\t\t? Object.entries(renders).map(([name, spec]) => ({\n\t\t\t\t\tname,\n\t\t\t\t\tentry: spec.entry,\n\t\t\t\t\texportName: spec.export,\n\t\t\t\t}))\n\t\t\t: renders[names[0]]\n\t\t\t\t? [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tname: names[0],\n\t\t\t\t\t\t\tentry: renders[names[0]].entry,\n\t\t\t\t\t\t\texportName: values.export ?? renders[names[0]].export,\n\t\t\t\t\t\t},\n\t\t\t\t\t]\n\t\t\t\t: [{ entry: names[0], exportName: values.export }];\n\tif (targets.length === 0) return usage();\n\tconst reports = [];\n\tfor (const t of targets) {\n\t\tconst report = await runCheck({\n\t\t\tentry: t.entry,\n\t\t\texportName: t.exportName,\n\t\t\trender: values.render,\n\t\t\toutputDir:\n\t\t\t\tvalues.output ??\n\t\t\t\t(targets.length > 1\n\t\t\t\t\t? join(\"output\", \"check\", t.name ?? \"\")\n\t\t\t\t\t: undefined),\n\t\t\ttimeoutMs:\n\t\t\t\tvalues.timeout === undefined ? undefined : Number(values.timeout),\n\t\t\twarningsAsErrors: values[\"warnings-as-errors\"],\n\t\t});\n\t\treports.push({ ...(t.name && { name: t.name }), ...report });\n\t\tif (values.json) continue;\n\t\tlog(\n\t\t\t`Check ${report.status}: ${t.name ? `${t.name} (${t.entry}, ${report.exportName})` : `${report.entry} (${report.exportName})`}`,\n\t\t);\n\t\tfor (const d of report.diagnostics)\n\t\t\tlog(\n\t\t\t\t`${d.severity} ${d.code}${d.path ? ` at ${d.path}` : \"\"}: ${d.message}`,\n\t\t\t);\n\t\tfor (const file of report.artifacts) log(`Wrote ${file}`);\n\t}\n\tconst passed = reports.every((r) => r.status === \"passed\");\n\tif (values.json)\n\t\tlog(\n\t\t\tJSON.stringify(\n\t\t\t\tnames.length === 0\n\t\t\t\t\t? { status: passed ? \"passed\" : \"failed\", checks: reports }\n\t\t\t\t\t: reports[0],\n\t\t\t),\n\t\t);\n\treturn passed ? 0 : 1;\n}\n\n/** `renders`: what framefields.json names, as the dashboard shows it. */\nfunction listRenders(\n\tcwd: string,\n\tjson: boolean | undefined,\n\tlog: (s: string) => void,\n): number {\n\tconst renders = readConfig(cwd).config.renders ?? {};\n\tif (json) {\n\t\tlog(JSON.stringify({ schemaVersion: 1, renders }));\n\t\treturn 0;\n\t}\n\tconst entries = Object.entries(renders);\n\tif (entries.length === 0) {\n\t\tlog(\n\t\t\t'framefields.json names no renders. Add one: \"renders\": { \"film\": { \"entry\": \"src/film.ts\", \"export\": \"buildFilm\" } }',\n\t\t);\n\t\treturn 0;\n\t}\n\tfor (const [name, spec] of entries) {\n\t\tconst title = spec.title && spec.title !== name ? ` ${spec.title}` : \"\";\n\t\tconst opts = [\n\t\t\tspec.workers !== undefined && `workers ${spec.workers}`,\n\t\t\tspec.codec,\n\t\t].filter(Boolean);\n\t\tlog(\n\t\t\t`${name}${title}\\n ${spec.entry} · ${spec.export ?? \"buildFilm\"}${spec.select ? ` · ${spec.select}` : \"\"}${opts.length ? ` · ${opts.join(\", \")}` : \"\"}${spec.description ? `\\n ${spec.description}` : \"\"}`,\n\t\t);\n\t}\n\treturn 0;\n}\n\nfunction logFonts(report: AddReport, cwd: string, log: (s: string) => void) {\n\tfor (const f of report.fonts)\n\t\tlog(\n\t\t\t` ${f.status === \"installed\" ? \"font \" : \"font ok \"} ${f.path} (${f.role}, for ${f.by}: ${f.why})`,\n\t\t);\n\tfor (const f of report.fontsSkipped)\n\t\tlog(\n\t\t\t` no font ${f.role} for ${f.by} (--no-fonts): ${f.why} Install later with \\`framefields fonts add ${f.role}\\`.`,\n\t\t);\n\tif (report.fontsModule) logFontsModule(report.fontsModule, log);\n\tconst installed = report.fonts.find((f) => f.status === \"installed\");\n\tconst hint = installed && lfsHint(cwd, installed.path);\n\tif (hint) log(`\\n${hint}`);\n\tif (report.fonts.some((f) => f.status !== \"configured\") && report.fontsModule)\n\t\tlog(\n\t\t\t`\\nRegister them once before rendering: \\`await registerFonts()\\` from ${report.fontsModule.path.replace(/\\.ts$/, \".js\")}.`,\n\t\t);\n}\n\nfunction logFontsModule(\n\tm: NonNullable<AddReport[\"fontsModule\"]>,\n\tlog: (s: string) => void,\n) {\n\tif (m.status === \"written\") log(` wrote ${m.path}`);\n\telse if (m.status === \"unchanged\") log(` unchanged ${m.path}`);\n\telse\n\t\tlog(\n\t\t\t` skipped ${m.path} (not generated by framefields). Register the fonts yourself:\\n${m.calls.map((c) => ` ${c}`).join(\"\\n\")}`,\n\t\t);\n}\n\n/** `framefields fonts add <role...>` and `framefields fonts list`. */\nasync function fonts(\n\t[sub, ...roles]: string[],\n\tcwd: string,\n\tvalues: {\n\t\toverwrite?: boolean;\n\t\t\"fonts-dir\"?: string;\n\t\tdir?: string;\n\t\tjson?: boolean;\n\t},\n\tlog: (s: string) => void,\n): Promise<number> {\n\tif (sub === \"list\") {\n\t\tconst { config } = readConfig(cwd);\n\t\tif (values.json) {\n\t\t\tlog(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tschemaVersion: 1,\n\t\t\t\t\tsdkVersion: ownVersion(),\n\t\t\t\t\tfonts: Object.entries(FONTS).map(([role, spec]) => ({\n\t\t\t\t\t\trole,\n\t\t\t\t\t\t...spec,\n\t\t\t\t\t\tconfiguredPath: config.fonts?.[role],\n\t\t\t\t\t})),\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn 0;\n\t\t}\n\t\tfor (const [role, spec] of Object.entries(FONTS))\n\t\t\tlog(\n\t\t\t\t`${role.padEnd(6)} ${spec.label}${config.fonts?.[role] ? ` (installed: ${config.fonts[role]})` : \"\"}`,\n\t\t\t);\n\t\treturn 0;\n\t}\n\tif (sub !== \"add\" || roles.length === 0) {\n\t\tprocess.stderr.write(\n\t\t\t`Usage: framefields fonts add <role...> (roles: ${Object.keys(FONTS).join(\", \")})\\n framefields fonts list\\n`,\n\t\t);\n\t\treturn 1;\n\t}\n\tconst unknown = roles.filter((r) => !FONTS[r]);\n\tif (unknown.length > 0) {\n\t\tprocess.stderr.write(\n\t\t\t`Unknown font ${unknown.map((r) => `\"${r}\"`).join(\", \")}. Fonts framefields can install: ${Object.keys(FONTS).join(\", \")}.\\n`,\n\t\t);\n\t\treturn 1;\n\t}\n\tconst { config, saved } = readConfig(cwd);\n\tconst installs = [];\n\tfor (const role of roles)\n\t\tinstalls.push(\n\t\t\tawait installFont(role, {\n\t\t\t\tcwd,\n\t\t\t\tdir: values[\"fonts-dir\"],\n\t\t\t\toverwrite: values.overwrite,\n\t\t\t\tonDownload,\n\t\t\t}),\n\t\t);\n\tfor (const f of installs)\n\t\tlog(\n\t\t\t` ${f.status === \"installed\" ? \"font \" : \"font ok \"} ${f.path} (${f.role})`,\n\t\t);\n\tif (!saved) log(\" wrote framefields.json\");\n\tconst module = writeFontsModule(\n\t\tcwd,\n\t\tresolve(cwd, values.dir ?? config.components),\n\t);\n\tlogFontsModule(module, log);\n\tconst installed = installs.find((f) => f.status === \"installed\");\n\tconst hint = installed && lfsHint(cwd, installed.path);\n\tif (hint) log(`\\n${hint}`);\n\tlog(\n\t\t`\\nRegister them once before rendering: \\`await registerFonts()\\` from ${module.path.replace(/\\.ts$/, \".js\")}.`,\n\t);\n\treturn 0;\n}\n\nfunction logInit(report: InitReport, cwd: string, log: (s: string) => void) {\n\tconst at = shownPath(cwd, report.root);\n\tfor (const f of report.written) log(` wrote ${f}`);\n\tfor (const f of report.merged)\n\t\tlog(` merged ${f} (added what it lacked)`);\n\tfor (const f of report.unchanged) log(` unchanged ${f}`);\n\tfor (const f of report.fonts)\n\t\tlog(\n\t\t\t` ${f.status === \"installed\" ? \"font \" : \"font ok \"} ${f.path} (${f.role})`,\n\t\t);\n\tlogFontsModule(report.fontsModule, log);\n\tif (report.git === \"initialized\")\n\t\tlog(\" git initialized a repository\");\n\tif (report.git === \"unavailable\")\n\t\tlog(\" git not found: skipped `git init`\");\n\tif (report.lfs === false)\n\t\tlog(\n\t\t\t\"\\nGit LFS isn't installed. Footage and fonts are tracked with it: install it (https://git-lfs.com), then run `git lfs install` once.\",\n\t\t);\n\telse if (report.lfs)\n\t\tlog(\"\\nRun `git lfs install` once on this machine if you haven't yet.\");\n\tconst steps = [\n\t\t...(at === \".\" ? [] : [`cd ${/\\s/.test(at) ? JSON.stringify(at) : at}`]),\n\t\t...(report.installed ? [] : [`${report.packageManager} install`]),\n\t\t`${report.runScript(\"frames\")} -- 0 30 60`,\n\t];\n\tlog(\n\t\t`\\n${report.name} is ready. Next:\\n${steps.map((s) => ` ${s}`).join(\"\\n\")}`,\n\t);\n\tlog(\n\t\t\"\\nThen edit src/film.ts, and run `npx framefields list` for ready-made components.\",\n\t);\n\tlog(\n\t\t`\\nOptional: to generate images, video, music, voice and 3D with the framefields AI gateway, get a key at ${AI_DASHBOARD} and put it in .env as FRAMEFIELDS_API_KEY (see .env.example).`,\n\t);\n}\n\n/** Installed components import `framefields`; say so if the project lacks it. */\nfunction warnIfMissingFramefields(cwd: string, log: (s: string) => void) {\n\ttry {\n\t\tconst pkg = JSON.parse(readFileSync(`${cwd}/package.json`, \"utf8\")) as {\n\t\t\tdependencies?: Record<string, string>;\n\t\t\tdevDependencies?: Record<string, string>;\n\t\t};\n\t\tif (!pkg.dependencies?.framefields && !pkg.devDependencies?.framefields)\n\t\t\tlog(\n\t\t\t\t\"\\nThese components import `framefields`: add it with `npm i framefields`.\",\n\t\t\t);\n\t} catch {\n\t\t// No package.json: nothing to check.\n\t}\n}\n\nmain(process.argv.slice(2)).then(\n\t(code) => process.exit(code),\n\t(error: unknown) => {\n\t\tprocess.stderr.write(\n\t\t\t`framefields: ${error instanceof Error ? error.message : String(error)}\\n`,\n\t\t);\n\t\tprocess.exit(1);\n\t},\n);\n"],"mappings":"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"}
|
package/dist/cloud/index.d.mts
CHANGED
|
@@ -53,6 +53,8 @@ interface CloudRenderOptions {
|
|
|
53
53
|
onProgress?: (status: CloudRenderStatus) => void;
|
|
54
54
|
/** Called for each warning (uncommitted changes). Default: stderr. */
|
|
55
55
|
onWarning?: (message: string) => void;
|
|
56
|
+
/** Called as assets upload before the render. Default: stderr. */
|
|
57
|
+
onLog?: (message: string) => void;
|
|
56
58
|
/** Aborting cancels the cloud render. */
|
|
57
59
|
signal?: AbortSignal;
|
|
58
60
|
/** Status poll interval, ms. Default 3000. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/cloud/git-source.ts","../../src/cloud/index.ts"],"sourcesContent":[],"mappings":";UAUiB,WAAA;EAAA,IAAA,EAAA,MAAA;EAQA,GAAA,CAAA,EAAA,MAAA;EASD,MAAA,CAAA,EAAA,MAAA;EA4EA;;;UArFC,cAAA;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/cloud/git-source.ts","../../src/cloud/index.ts"],"sourcesContent":[],"mappings":";UAUiB,WAAA;EAAA,IAAA,EAAA,MAAA;EAQA,GAAA,CAAA,EAAA,MAAA;EASD,MAAA,CAAA,EAAA,MAAA;EA4EA;;;UArFC,cAAA;ECkBJ,MAAA,EDjBJ,WCiBI;EAEI;EAwBP,KAAA,EAAA,MAAA;EAMa;EAMb,QAAA,EAAA,MAAA,EAAA;;AAKV;AAUiB,iBD9DD,gBAAA,CC8DgB,GAAA,EAAA,MAAA,EAAA,KAAA,EAAA,MAAA,CAAA,ED9D8B,cC8D9B;AAShC;AAqBiB,iBDhBD,OAAA,CCgBmB,GAAQ,EAAA,MAAA,CAAA,EAAA,MAAA;;;ADrG1B,cCkBJ,mBAAA,GDjBJ,6BAAW;AAQJ,UCWC,kBAAA,CDX6C;EA4E9C;;;;ECnEH;EAEI,MAAA,CAAA,EAAA,MAAA;EAwBP;EAMa,IAAA,CAAA,EAAA,OAAA;EAMb;EAAW,MAAA,CAAA,EAAA,MAAA;EAKT;EAUK,OAAA,CAAA,EAAA,MAAA,GAAe,MAAA;EASf;EAqBA,UAAA,CAAA,EAAA,MAAA;EAMJ,KAAA,CAAA,EAAA,MAAA,GAAA,KAAiB;EAIV,OAAA,CAAA,EAAA,MAAA;EAAA;EAJkB,MAAA,CAAA,EAAA,OAAA;EAAK;EAmBrB,UAAA,CAAA,EAAA,MAAW;EACvB;EACC,GAAA,CAAA,EAAA,MAAA;EAAR;EAAO,MAAA,CAAA,EApFA,WAoFA;EA+FM;EAyCA,MAAA,CAAA,EAAA,MAAW;EACZ;EAAL,MAAA,CAAA,EAAA,MAAA;EAkCa;EAAA,UAAA,CAAA,EAAA,CAAA,MAAA,EAzPA,iBAyPA,EAAA,GAAA,IAAA;EACF;EAAA,SAAA,CAAA,EAAA,CAAA,OAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EACA;EAAA,KAAA,CAAA,EAAA,CAAA,OAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EAAA;WArPX;;;;KAKE,gBAAA;UAUK,eAAA;;;;;;;;;;;;UASA,iBAAA;;UAER;;SAED;;;;;;;;;;;;;;;;;;;;;;UAiBS,iBAAA,SAA0B;;;;;cAM9B,gBAAA,SAAyB,KAAA;;oBAIlB;sDAAA;;;iBAeE,WAAA,UACZ,qBACP,QAAQ;;;;;iBA+FK,eAAA,uBAEN,qBACP;;;;;;iBAsCa,WAAA,UACN,KAAK;4BAkCQ,QAAA;0BACF,QAAA;0BACA,QAAA"}
|
package/dist/cloud/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as withNamedRender, i as renderCloud, n as FRAMEFIELDS_API_URL, o as resolveGitSource, r as cloudClient, s as toHttps, t as CloudRenderError } from "../cloud-
|
|
1
|
+
import { a as withNamedRender, i as renderCloud, n as FRAMEFIELDS_API_URL, o as resolveGitSource, r as cloudClient, s as toHttps, t as CloudRenderError } from "../cloud-Cj1TIme8.mjs";
|
|
2
2
|
|
|
3
3
|
export { CloudRenderError, FRAMEFIELDS_API_URL, cloudClient, renderCloud, resolveGitSource, toHttps, withNamedRender };
|