framefields 2.9.3 → 2.11.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/README.md +9 -2
- package/dist/audio/index.d.mts +5 -5
- package/dist/audio/index.mjs +13 -13
- package/dist/{audio-B6RmYOPe.mjs → audio-BuCVk1IQ.mjs} +32 -6
- package/dist/audio-BuCVk1IQ.mjs.map +1 -0
- package/dist/audio-CYZkDwae.d.mts +62 -0
- package/dist/audio-CYZkDwae.d.mts.map +1 -0
- package/dist/{audio-BlDbnteH.mjs → audio-KHBadECb.mjs} +1 -1
- package/dist/{audio-BlDbnteH.mjs.map → audio-KHBadECb.mjs.map} +1 -1
- package/dist/{check-result-Bj7g62ka.mjs → check-result-Culfu7Nx.mjs} +1 -1
- package/dist/{check-result-Bj7g62ka.mjs.map → check-result-Culfu7Nx.mjs.map} +1 -1
- package/dist/cli/check-worker.mjs +50 -50
- package/dist/cli.mjs +179 -3
- package/dist/cli.mjs.map +1 -1
- package/dist/cloud/index.d.mts +118 -0
- package/dist/cloud/index.d.mts.map +1 -0
- package/dist/cloud/index.mjs +3 -0
- package/dist/cloud-xcfV4J03.mjs +233 -0
- package/dist/cloud-xcfV4J03.mjs.map +1 -0
- package/dist/components/index.d.mts +14 -14
- package/dist/components/index.mjs +47 -47
- package/dist/{dist-Cn8bDsQF.mjs → dist-BIE8fvlv.mjs} +1 -1
- package/dist/{dist-Cn8bDsQF.mjs.map → dist-BIE8fvlv.mjs.map} +1 -1
- package/dist/{dist-ByxHoMQI.mjs → dist-Bf2_efYP.mjs} +1 -1
- package/dist/{dist-ByxHoMQI.mjs.map → dist-Bf2_efYP.mjs.map} +1 -1
- package/dist/{dist-BlulwErl.mjs → dist-CNGv-JTX.mjs} +1 -1
- package/dist/{dist-D12-a3-x.mjs → dist-CWLLnigL.mjs} +375 -15
- package/dist/dist-CWLLnigL.mjs.map +1 -0
- package/dist/{dist-DL1GwJvs.mjs → dist-CySGkG54.mjs} +2 -2
- package/dist/{dist-DL1GwJvs.mjs.map → dist-CySGkG54.mjs.map} +1 -1
- package/dist/{dist-Dq5TkNDI.mjs → dist-Dg9LMWoX.mjs} +2 -2
- package/dist/{dist-Dq5TkNDI.mjs.map → dist-Dg9LMWoX.mjs.map} +1 -1
- package/dist/{dist-DEUU6sNe.mjs → dist-EQX3TUUl.mjs} +4 -4
- package/dist/{dist-DEUU6sNe.mjs.map → dist-EQX3TUUl.mjs.map} +1 -1
- package/dist/effects/index.d.mts +6 -6
- package/dist/effects/index.mjs +36 -36
- package/dist/{effects-CViUoQSV.mjs → effects-DKLbLXF7.mjs} +3 -3
- package/dist/{effects-CViUoQSV.mjs.map → effects-DKLbLXF7.mjs.map} +1 -1
- package/dist/fonts/index.d.mts +1 -1
- package/dist/fonts/index.mjs +3 -3
- package/dist/{fonts-B0U2KO5I.mjs → fonts-gPbGbShD.mjs} +2 -2
- package/dist/{fonts-B0U2KO5I.mjs.map → fonts-gPbGbShD.mjs.map} +1 -1
- package/dist/{gpu-zFNrvhV9.mjs → gpu-CpkJJLQP.mjs} +2 -2
- package/dist/{gpu-zFNrvhV9.mjs.map → gpu-CpkJJLQP.mjs.map} +1 -1
- package/dist/{index-BuYtrhzL.d.mts → index-BW0Q1ygn.d.mts} +1 -1
- package/dist/{index-BuYtrhzL.d.mts.map → index-BW0Q1ygn.d.mts.map} +1 -1
- package/dist/{index-f4IF1vRH.d.mts → index-Bly-7YM1.d.mts} +3 -3
- package/dist/{index-f4IF1vRH.d.mts.map → index-Bly-7YM1.d.mts.map} +1 -1
- package/dist/{index-Bzo1uj8h.d.mts → index-BuiZzc6i.d.mts} +23 -3
- package/dist/index-BuiZzc6i.d.mts.map +1 -0
- package/dist/{index-DBhswLMO.d.mts → index-C8YwZ6k1.d.mts} +2 -2
- package/dist/{index-DBhswLMO.d.mts.map → index-C8YwZ6k1.d.mts.map} +1 -1
- package/dist/{index-svAgwTY_.d.mts → index-CEU_Zsb9.d.mts} +2 -2
- package/dist/{index-svAgwTY_.d.mts.map → index-CEU_Zsb9.d.mts.map} +1 -1
- package/dist/{index-9_4X2ro1.d.mts → index-COYNQ_mf.d.mts} +1 -1
- package/dist/{index-9_4X2ro1.d.mts.map → index-COYNQ_mf.d.mts.map} +1 -1
- package/dist/{index-CgGM31I9.d.mts → index-CdCrae-I.d.mts} +2 -2
- package/dist/{index-CgGM31I9.d.mts.map → index-CdCrae-I.d.mts.map} +1 -1
- package/dist/{index-B9Lm1x8i.d.mts → index-Cro-818i.d.mts} +297 -283
- package/dist/index-Cro-818i.d.mts.map +1 -0
- package/dist/{index-w28KUM9A.d.mts → index-D2i9J9Zq.d.mts} +3 -3
- package/dist/{index-w28KUM9A.d.mts.map → index-D2i9J9Zq.d.mts.map} +1 -1
- package/dist/{index-V0ZQ4JN6.d.mts → index-gOVtTm-P.d.mts} +125 -3
- package/dist/index-gOVtTm-P.d.mts.map +1 -0
- package/dist/{index-C6GcuYVA.d.mts → index-jSDEM-uE.d.mts} +5 -5
- package/dist/{index-C6GcuYVA.d.mts.map → index-jSDEM-uE.d.mts.map} +1 -1
- package/dist/index.d.mts +16 -16
- package/dist/index.mjs +59 -59
- package/dist/preview/index.d.mts +4 -4
- package/dist/preview/index.mjs +12 -12
- package/dist/{preview-ZKJ_zTmd.mjs → preview-BToKUTtZ.mjs} +3 -3
- package/dist/{preview-ZKJ_zTmd.mjs.map → preview-BToKUTtZ.mjs.map} +1 -1
- package/dist/preview-engine/audio.mjs +1 -1
- package/dist/preview-engine/{chunk-VN36PRVD.mjs → chunk-26XWIHW3.mjs} +1 -1
- package/dist/preview-engine/{chunk-BVDWS3D2.mjs → chunk-4AGQN53P.mjs} +1 -1
- package/dist/preview-engine/{chunk-IB6GZJOL.mjs → chunk-54Q5CKSV.mjs} +1 -1
- package/dist/preview-engine/{chunk-Y5K5LVOR.mjs → chunk-5KSBS3AL.mjs} +1 -1
- package/dist/preview-engine/{chunk-ZJ5SWTCW.mjs → chunk-65NANVQL.mjs} +1 -1
- package/dist/preview-engine/{chunk-34RJ7GAS.mjs → chunk-6LTINEA4.mjs} +1 -1
- package/dist/preview-engine/{chunk-SPJPM43P.mjs → chunk-7GMHSTRP.mjs} +1 -1
- package/dist/preview-engine/{chunk-BEYA25UZ.mjs → chunk-ACBBBOUM.mjs} +1 -1
- package/dist/preview-engine/{chunk-7U34VKNO.mjs → chunk-BRV7TQDV.mjs} +1 -1
- package/dist/preview-engine/{chunk-KHJZMTOS.mjs → chunk-CCORQLMR.mjs} +1 -1
- package/dist/preview-engine/{chunk-5AWAOMBR.mjs → chunk-CIVEZJYF.mjs} +1 -1
- package/dist/preview-engine/{chunk-FKG27DVO.mjs → chunk-CIVJXFWH.mjs} +1 -1
- package/dist/preview-engine/{chunk-JIPMF42Z.mjs → chunk-D6LM7DTJ.mjs} +2 -2
- package/dist/preview-engine/{chunk-GA4HNR44.mjs → chunk-DNNGWS2C.mjs} +1 -1
- package/dist/preview-engine/{chunk-ZY47XIRK.mjs → chunk-EAWJXW4J.mjs} +1 -1
- package/dist/preview-engine/{chunk-6R3UJBL5.mjs → chunk-EPRINA4V.mjs} +1 -1
- package/dist/preview-engine/{chunk-GRJJVSOV.mjs → chunk-EXEO245X.mjs} +1 -1
- package/dist/preview-engine/{chunk-DVZITDQS.mjs → chunk-FQL4IJZN.mjs} +1 -1
- package/dist/preview-engine/{chunk-QCSVT73T.mjs → chunk-GHTG5XV6.mjs} +1 -1
- package/dist/preview-engine/{chunk-VVY4PG5E.mjs → chunk-GXFYRMJZ.mjs} +25 -25
- package/dist/preview-engine/{chunk-AHQCDTD6.mjs → chunk-IBPYV6HF.mjs} +1 -1
- package/dist/preview-engine/{chunk-PM2W4VLT.mjs → chunk-IKVJ4MW5.mjs} +1 -1
- package/dist/preview-engine/{chunk-GZWA5QJS.mjs → chunk-JDB7PMRI.mjs} +1 -1
- package/dist/preview-engine/{chunk-CC4NNNIY.mjs → chunk-KVOFO273.mjs} +1 -1
- package/dist/preview-engine/{chunk-RJIAES3X.mjs → chunk-LFNCWMKS.mjs} +1 -1
- package/dist/preview-engine/{chunk-FTCEG3SF.mjs → chunk-LMXMBX4J.mjs} +1 -1
- package/dist/preview-engine/{chunk-MIEH74UH.mjs → chunk-M4QANUJI.mjs} +1 -1
- package/dist/preview-engine/{chunk-VVE2QHVG.mjs → chunk-NOKPBMIP.mjs} +1 -1
- package/dist/preview-engine/{chunk-P5FKRQFU.mjs → chunk-O63FLYWC.mjs} +1 -1
- package/dist/preview-engine/chunk-OELPPLML.mjs +107 -0
- package/dist/preview-engine/{chunk-GIICZZQI.mjs → chunk-OLB4TQLQ.mjs} +1 -1
- package/dist/preview-engine/{chunk-CN2VLYLB.mjs → chunk-PKNUTHPI.mjs} +1 -1
- package/dist/preview-engine/{chunk-2B722GXM.mjs → chunk-QF4JWVO3.mjs} +1 -1
- package/dist/preview-engine/{chunk-EJJITH6U.mjs → chunk-RDWLLITE.mjs} +1 -1
- package/dist/preview-engine/{chunk-K3C6GUQD.mjs → chunk-SE2C623Z.mjs} +1 -1
- package/dist/preview-engine/{chunk-34DL53D5.mjs → chunk-TEWRQKX3.mjs} +1 -1
- package/dist/preview-engine/{chunk-H7BSN7V7.mjs → chunk-UGB6JKVS.mjs} +1 -1
- package/dist/preview-engine/{chunk-BJV2LBII.mjs → chunk-UI3VH33L.mjs} +1 -1
- package/dist/preview-engine/{chunk-UXYM2G6J.mjs → chunk-UMJ3VGKN.mjs} +1 -1
- package/dist/preview-engine/{chunk-2DWY7UBV.mjs → chunk-VFQH5KVS.mjs} +1 -1
- package/dist/preview-engine/{chunk-73CNXGAK.mjs → chunk-VQA4DYZU.mjs} +1 -1
- package/dist/preview-engine/{chunk-LVYVXVZO.mjs → chunk-VZLIRYAL.mjs} +1 -1
- package/dist/preview-engine/{chunk-4WYM72ZN.mjs → chunk-WFMUDL55.mjs} +1 -1
- package/dist/preview-engine/{chunk-Q62GPWGD.mjs → chunk-XF6DYP6B.mjs} +11 -11
- package/dist/preview-engine/{chunk-35HMRW4I.mjs → chunk-YHMBGJP6.mjs} +1 -1
- package/dist/preview-engine/{chunk-DMSZXG56.mjs → chunk-YKM7JDQY.mjs} +1 -1
- package/dist/preview-engine/{chunk-SF37HXAH.mjs → chunk-YVZTRH4Y.mjs} +1 -1
- package/dist/preview-engine/{chunk-TNJEZKXM.mjs → chunk-Z24UEN4P.mjs} +1 -1
- package/dist/preview-engine/{chunk-2PYTDN2C.mjs → chunk-ZF2MEFKO.mjs} +1 -1
- package/dist/preview-engine/{chunk-OH5W5EL6.mjs → chunk-ZIXPWP2B.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 +1 -1
- package/dist/preview-engine/renderers-2NGIILMI.mjs +1 -0
- package/dist/preview-engine/{renderers-5TO2SXFR.mjs → renderers-33FCFHDR.mjs} +1 -1
- package/dist/preview-engine/renderers-466Z77BH.mjs +1 -0
- package/dist/preview-engine/{renderers-PIIEUKFE.mjs → renderers-4IBFDW2S.mjs} +1 -1
- package/dist/preview-engine/renderers-4KRENGZA.mjs +1 -0
- package/dist/preview-engine/renderers-4W52BQEU.mjs +1 -0
- package/dist/preview-engine/{renderers-ZACSHGNZ.mjs → renderers-53EI26GL.mjs} +1 -1
- package/dist/preview-engine/renderers-55PRAS7G.mjs +1 -0
- package/dist/preview-engine/renderers-5LLYINHW.mjs +1 -0
- package/dist/preview-engine/{renderers-A24KZK2Q.mjs → renderers-5XLGCEOA.mjs} +1 -1
- package/dist/preview-engine/renderers-63N3Y2XO.mjs +1 -0
- package/dist/preview-engine/{renderers-V3AQO7AR.mjs → renderers-6LNDAO4B.mjs} +1 -1
- package/dist/preview-engine/renderers-6ROVFDIN.mjs +1 -0
- package/dist/preview-engine/{renderers-CUMVIVHI.mjs → renderers-6YVZUQOH.mjs} +1 -1
- package/dist/preview-engine/renderers-7CAHX35U.mjs +1 -0
- package/dist/preview-engine/renderers-A4RVLPMG.mjs +1 -0
- package/dist/preview-engine/renderers-A53P4J6O.mjs +1 -0
- package/dist/preview-engine/{renderers-WEYAHOBK.mjs → renderers-ACUJMDEK.mjs} +1 -1
- package/dist/preview-engine/renderers-AFJ3373L.mjs +1 -0
- package/dist/preview-engine/renderers-ATFWTA3U.mjs +1 -0
- package/dist/preview-engine/{renderers-TSBV4KPE.mjs → renderers-BOBVXYAA.mjs} +1 -1
- package/dist/preview-engine/renderers-BPYJXHBU.mjs +1 -0
- package/dist/preview-engine/{renderers-NCGH2WWJ.mjs → renderers-C7SI3NIE.mjs} +1 -1
- package/dist/preview-engine/{renderers-FSI5KNGZ.mjs → renderers-CCRZNGVK.mjs} +1 -1
- package/dist/preview-engine/{renderers-NUAI4TO5.mjs → renderers-CYJAVWHT.mjs} +1 -1
- package/dist/preview-engine/renderers-D3ZF7FXT.mjs +1 -0
- package/dist/preview-engine/renderers-D7YN6B4B.mjs +1 -0
- package/dist/preview-engine/renderers-DBLASKF5.mjs +1 -0
- package/dist/preview-engine/renderers-DC5ZYYHM.mjs +1 -0
- package/dist/preview-engine/{renderers-5UZ3YFBD.mjs → renderers-EN7LXJLG.mjs} +1 -1
- package/dist/preview-engine/{renderers-L6YDX6GS.mjs → renderers-FY2HOQCS.mjs} +1 -1
- package/dist/preview-engine/{renderers-6Z7DWAPH.mjs → renderers-GQM3KMV3.mjs} +1 -1
- package/dist/preview-engine/{renderers-QA2HKUJJ.mjs → renderers-H6PBHEYU.mjs} +1 -1
- package/dist/preview-engine/{renderers-MD3PRFZL.mjs → renderers-HKLCB4U6.mjs} +1 -1
- package/dist/preview-engine/{renderers-TGJSOKDY.mjs → renderers-HSFQIILN.mjs} +1 -1
- package/dist/preview-engine/{renderers-7C5RA3R5.mjs → renderers-I6QKZ7CH.mjs} +1 -1
- package/dist/preview-engine/renderers-J6ZEXW5L.mjs +1 -0
- package/dist/preview-engine/renderers-JV4MF46Q.mjs +1 -0
- package/dist/preview-engine/{renderers-SEIAUKJF.mjs → renderers-KCGK33Y2.mjs} +1 -1
- package/dist/preview-engine/renderers-KQKH4ZIX.mjs +1 -0
- package/dist/preview-engine/renderers-MEITHN4N.mjs +1 -0
- package/dist/preview-engine/renderers-MN3HSBTJ.mjs +1 -0
- package/dist/preview-engine/renderers-NTG3QGNH.mjs +1 -0
- package/dist/preview-engine/{renderers-KC6ZSKCW.mjs → renderers-OGOW3NA4.mjs} +1 -1
- package/dist/preview-engine/renderers-OU4SFMB2.mjs +1 -0
- package/dist/preview-engine/{renderers-ENMY4DKF.mjs → renderers-P2HORBZ6.mjs} +1 -1
- package/dist/preview-engine/renderers-P6TIBJIG.mjs +1 -0
- package/dist/preview-engine/renderers-POJWQ7L3.mjs +1 -0
- package/dist/preview-engine/renderers-RJ7S6VHD.mjs +1 -0
- package/dist/preview-engine/renderers-RJJAJZYN.mjs +1 -0
- package/dist/preview-engine/renderers-UEQ733VK.mjs +1 -0
- package/dist/preview-engine/{renderers-T74CQCEN.mjs → renderers-UG2C3C7T.mjs} +1 -1
- package/dist/preview-engine/renderers-ULO2AW2U.mjs +1 -0
- package/dist/preview-engine/renderers-UPVHGHCK.mjs +1 -0
- package/dist/preview-engine/renderers-UZHSNNIM.mjs +1 -0
- package/dist/preview-engine/renderers-V5KWZL2C.mjs +1 -0
- package/dist/preview-engine/{renderers-5KANN7XF.mjs → renderers-VIGZYJYX.mjs} +1 -1
- package/dist/preview-engine/{renderers-4F7WLQD5.mjs → renderers-VVP5WQOY.mjs} +1 -1
- package/dist/preview-engine/{renderers-7XHO6M3B.mjs → renderers-WL372W36.mjs} +1 -1
- package/dist/preview-engine/{renderers-U4M7ZCV4.mjs → renderers-WSABL3QO.mjs} +1 -1
- package/dist/preview-engine/{renderers-Y22VSOXF.mjs → renderers-X6CORAES.mjs} +1 -1
- package/dist/preview-engine/renderers-YMXKYOHQ.mjs +1 -0
- package/dist/preview-engine/renderers-YWDAZ2NZ.mjs +1 -0
- package/dist/preview-engine/signals.mjs +1 -1
- package/dist/{program-xjIwjKb6.mjs → program-Bc860ko5.mjs} +4 -4
- package/dist/{program-xjIwjKb6.mjs.map → program-Bc860ko5.mjs.map} +1 -1
- package/dist/registry/focus-zoom.json +9 -2
- package/dist/renderer/index.d.mts +4 -4
- package/dist/renderer/index.mjs +4 -4
- package/dist/renderer--Ymc_4XJ.mjs +5 -0
- package/dist/{renderer-Dee8ksIV.mjs → renderer-1uoKiILq.mjs} +3 -3
- package/dist/{renderer-Dee8ksIV.mjs.map → renderer-1uoKiILq.mjs.map} +1 -1
- package/dist/{renderer-CIB5L_C4.mjs → renderer-4ZUv3X1I.mjs} +5 -5
- package/dist/{renderer-CIB5L_C4.mjs.map → renderer-4ZUv3X1I.mjs.map} +1 -1
- package/dist/{renderer-BPYIqtNg.mjs → renderer-50JEMaVo.mjs} +5 -5
- package/dist/{renderer-BPYIqtNg.mjs.map → renderer-50JEMaVo.mjs.map} +1 -1
- package/dist/{renderer-BdbI_u9w.mjs → renderer-7ow5Acsg.mjs} +3 -3
- package/dist/{renderer-BdbI_u9w.mjs.map → renderer-7ow5Acsg.mjs.map} +1 -1
- package/dist/{renderer-B-inTgyb.d.mts → renderer-88C3QpKL.d.mts} +2 -2
- package/dist/{renderer-B-inTgyb.d.mts.map → renderer-88C3QpKL.d.mts.map} +1 -1
- package/dist/{renderer-DH7l5WFr.mjs → renderer-B-CMRUag.mjs} +4 -4
- package/dist/{renderer-DH7l5WFr.mjs.map → renderer-B-CMRUag.mjs.map} +1 -1
- package/dist/renderer-B-OdV-eq.mjs +5 -0
- package/dist/{renderer-NTCk1Srf.mjs → renderer-B1LD29TV.mjs} +3 -3
- package/dist/{renderer-NTCk1Srf.mjs.map → renderer-B1LD29TV.mjs.map} +1 -1
- package/dist/{renderer-ESkPj6pk.mjs → renderer-B1esRxGy.mjs} +4 -4
- package/dist/{renderer-ESkPj6pk.mjs.map → renderer-B1esRxGy.mjs.map} +1 -1
- package/dist/{renderer-g7fF2AYk.mjs → renderer-B3Dme2es.mjs} +5 -5
- package/dist/{renderer-g7fF2AYk.mjs.map → renderer-B3Dme2es.mjs.map} +1 -1
- package/dist/renderer-B65fwoA2.mjs +5 -0
- package/dist/{renderer-CDVb4OfJ.mjs → renderer-B6Oeahe_.mjs} +5 -5
- package/dist/{renderer-CDVb4OfJ.mjs.map → renderer-B6Oeahe_.mjs.map} +1 -1
- package/dist/renderer-B92Ahkcv.mjs +5 -0
- package/dist/renderer-B9z2AK31.mjs +5 -0
- package/dist/{renderer-BZmmekE8.mjs → renderer-BDZC3o3N.mjs} +4 -4
- package/dist/{renderer-BZmmekE8.mjs.map → renderer-BDZC3o3N.mjs.map} +1 -1
- package/dist/renderer-BIF3Dg3Z.mjs +5 -0
- package/dist/{renderer-C06U4c9k.mjs → renderer-BJ-7WRgO.mjs} +3 -3
- package/dist/{renderer-C06U4c9k.mjs.map → renderer-BJ-7WRgO.mjs.map} +1 -1
- package/dist/renderer-BJUVaIAT.mjs +5 -0
- package/dist/renderer-BKRDMbI-.mjs +5 -0
- package/dist/{renderer-HnSiwSW8.mjs → renderer-BNHcwxw9.mjs} +4 -4
- package/dist/{renderer-HnSiwSW8.mjs.map → renderer-BNHcwxw9.mjs.map} +1 -1
- package/dist/{renderer-B78W9uad.mjs → renderer-BNJ6Jk7-.mjs} +4 -4
- package/dist/{renderer-B78W9uad.mjs.map → renderer-BNJ6Jk7-.mjs.map} +1 -1
- package/dist/{renderer-BVql26Ay.mjs → renderer-BOrMBwQS.mjs} +2 -2
- package/dist/{renderer-BVql26Ay.mjs.map → renderer-BOrMBwQS.mjs.map} +1 -1
- package/dist/{renderer-Cl8r1LJe.mjs → renderer-BQetXCcZ.mjs} +4 -4
- package/dist/{renderer-Cl8r1LJe.mjs.map → renderer-BQetXCcZ.mjs.map} +1 -1
- package/dist/{renderer-C4yKI8MT.mjs → renderer-BSELd5vU.mjs} +3 -3
- package/dist/{renderer-C4yKI8MT.mjs.map → renderer-BSELd5vU.mjs.map} +1 -1
- package/dist/renderer-BSwhyVWa.mjs +5 -0
- package/dist/{renderer-CcJyD9Q5.mjs → renderer-BURhYcpA.mjs} +4 -4
- package/dist/{renderer-CcJyD9Q5.mjs.map → renderer-BURhYcpA.mjs.map} +1 -1
- package/dist/renderer-BUqSZn2X.mjs +5 -0
- package/dist/{renderer-DoPEPlbG.d.mts → renderer-BVKOQarx.d.mts} +3 -3
- package/dist/{renderer-DoPEPlbG.d.mts.map → renderer-BVKOQarx.d.mts.map} +1 -1
- package/dist/{renderer-CwVbHki6.mjs → renderer-BaIJIfJ6.mjs} +5 -5
- package/dist/{renderer-CwVbHki6.mjs.map → renderer-BaIJIfJ6.mjs.map} +1 -1
- package/dist/renderer-BbmvjqK9.mjs +3 -0
- package/dist/{renderer-Be5hfwSd.mjs → renderer-Bbxh4N8Y.mjs} +425 -115
- package/dist/renderer-Bbxh4N8Y.mjs.map +1 -0
- package/dist/{renderer-BG6bkKtY.mjs → renderer-Bf4-N7k7.mjs} +5 -5
- package/dist/{renderer-BG6bkKtY.mjs.map → renderer-Bf4-N7k7.mjs.map} +1 -1
- package/dist/{renderer-CpedZNEG.mjs → renderer-BhsrlGKp.mjs} +3 -3
- package/dist/{renderer-CpedZNEG.mjs.map → renderer-BhsrlGKp.mjs.map} +1 -1
- package/dist/{renderer-AUK_ZS3p.mjs → renderer-Bo7shNdU.mjs} +4 -4
- package/dist/{renderer-AUK_ZS3p.mjs.map → renderer-Bo7shNdU.mjs.map} +1 -1
- package/dist/renderer-Bpe4k_x6.mjs +5 -0
- package/dist/{renderer-BfbSvElt.mjs → renderer-BwrfKKqw.mjs} +4 -4
- package/dist/{renderer-BfbSvElt.mjs.map → renderer-BwrfKKqw.mjs.map} +1 -1
- package/dist/{renderer-CWLF6cAz.mjs → renderer-Bx14Wnxl.mjs} +3 -3
- package/dist/{renderer-CWLF6cAz.mjs.map → renderer-Bx14Wnxl.mjs.map} +1 -1
- package/dist/{renderer-CCFHnafT.mjs → renderer-Bxjb0HYU.mjs} +4 -4
- package/dist/{renderer-CCFHnafT.mjs.map → renderer-Bxjb0HYU.mjs.map} +1 -1
- package/dist/{renderer-5qJPGvVL.mjs → renderer-ByjaseAo.mjs} +5 -5
- package/dist/{renderer-5qJPGvVL.mjs.map → renderer-ByjaseAo.mjs.map} +1 -1
- package/dist/renderer-C1NjG0CJ.mjs +5 -0
- package/dist/renderer-C7Puyst9.mjs +5 -0
- package/dist/{renderer-CYX9vKZ-.mjs → renderer-C9BSXyrq.mjs} +4 -4
- package/dist/{renderer-CYX9vKZ-.mjs.map → renderer-C9BSXyrq.mjs.map} +1 -1
- package/dist/{renderer-CUBDxuxh.mjs → renderer-CAWnCsQc.mjs} +5 -5
- package/dist/{renderer-CUBDxuxh.mjs.map → renderer-CAWnCsQc.mjs.map} +1 -1
- package/dist/renderer-CGA_7320.mjs +5 -0
- package/dist/{renderer-CEfVvcw-.mjs → renderer-CLAvn9c6.mjs} +4 -4
- package/dist/{renderer-CEfVvcw-.mjs.map → renderer-CLAvn9c6.mjs.map} +1 -1
- package/dist/renderer-CLnFkXO7.mjs +5 -0
- package/dist/renderer-CMQIT1Kh.mjs +5 -0
- package/dist/{renderer-BYqrtBvd.mjs → renderer-COcKhouz.mjs} +5 -5
- package/dist/{renderer-BYqrtBvd.mjs.map → renderer-COcKhouz.mjs.map} +1 -1
- package/dist/renderer-CQ1rwjIh.mjs +5 -0
- package/dist/{renderer-US4GsamT.mjs → renderer-CR0mDPYY.mjs} +3 -3
- package/dist/renderer-CT8h0boY.mjs +5 -0
- package/dist/{renderer-VhkubIx_.mjs → renderer-CU8v-LxD.mjs} +5 -5
- package/dist/{renderer-VhkubIx_.mjs.map → renderer-CU8v-LxD.mjs.map} +1 -1
- package/dist/renderer-Cb0lszt3.mjs +5 -0
- package/dist/renderer-Ci7oLye9.mjs +5 -0
- package/dist/renderer-CjqXB3CZ.mjs +5 -0
- package/dist/{renderer-DIEmK57T.mjs → renderer-Co6UFbZB.mjs} +5 -5
- package/dist/{renderer-DIEmK57T.mjs.map → renderer-Co6UFbZB.mjs.map} +1 -1
- package/dist/renderer-CqTV04zQ.mjs +5 -0
- package/dist/{renderer-xDV2cCkX.mjs → renderer-CrR8Mpxq.mjs} +5 -5
- package/dist/{renderer-xDV2cCkX.mjs.map → renderer-CrR8Mpxq.mjs.map} +1 -1
- package/dist/renderer-CtWeRtHK.mjs +5 -0
- package/dist/{renderer-BRWjLiHX.mjs → renderer-CxGx1Lhi.mjs} +3 -3
- package/dist/{renderer-BRWjLiHX.mjs.map → renderer-CxGx1Lhi.mjs.map} +1 -1
- package/dist/{renderer-BQOeeXTr.mjs → renderer-Cz-n883J.mjs} +5 -5
- package/dist/{renderer-BQOeeXTr.mjs.map → renderer-Cz-n883J.mjs.map} +1 -1
- package/dist/renderer-CzolnwCo.mjs +5 -0
- package/dist/{renderer-sPI7aY6c.mjs → renderer-D-QVGphn.mjs} +4 -4
- package/dist/{renderer-sPI7aY6c.mjs.map → renderer-D-QVGphn.mjs.map} +1 -1
- package/dist/{renderer-C3tVrzyT.mjs → renderer-D06HxSXO.mjs} +3 -3
- package/dist/{renderer-CXLugAe8.mjs → renderer-D0aAZHC7.mjs} +4 -4
- package/dist/{renderer-CXLugAe8.mjs.map → renderer-D0aAZHC7.mjs.map} +1 -1
- package/dist/{renderer-mLlgfM7X.mjs → renderer-D4f8f66C.mjs} +4 -4
- package/dist/{renderer-mLlgfM7X.mjs.map → renderer-D4f8f66C.mjs.map} +1 -1
- package/dist/renderer-D6qhcx_C.mjs +5 -0
- package/dist/{renderer-C7MAqpIS.mjs → renderer-DAn9xiQT.mjs} +4 -4
- package/dist/{renderer-C7MAqpIS.mjs.map → renderer-DAn9xiQT.mjs.map} +1 -1
- package/dist/renderer-DDfEf0jt.mjs +5 -0
- package/dist/renderer-DDpa8ztp.mjs +5 -0
- package/dist/{renderer-DW7hbluw.mjs → renderer-DE9Jik9K.mjs} +3 -3
- package/dist/{renderer-DW7hbluw.mjs.map → renderer-DE9Jik9K.mjs.map} +1 -1
- package/dist/{renderer-C6st34I6.mjs → renderer-DFJWPqOJ.mjs} +3 -3
- package/dist/{renderer-C6st34I6.mjs.map → renderer-DFJWPqOJ.mjs.map} +1 -1
- package/dist/{renderer-D2TTDcgh.mjs → renderer-DLPhfwbR.mjs} +3 -3
- package/dist/{renderer-D2TTDcgh.mjs.map → renderer-DLPhfwbR.mjs.map} +1 -1
- package/dist/{renderer-D1VsqFf4.mjs → renderer-DOkbn1ot.mjs} +5 -5
- package/dist/{renderer-D1VsqFf4.mjs.map → renderer-DOkbn1ot.mjs.map} +1 -1
- package/dist/{renderer-BWMzjSgf.mjs → renderer-DaXQgGg3.mjs} +5 -5
- package/dist/{renderer-BWMzjSgf.mjs.map → renderer-DaXQgGg3.mjs.map} +1 -1
- package/dist/renderer-DbQBqzmx.mjs +5 -0
- package/dist/{renderer-DrWeb39d.mjs → renderer-DcvjSolU.mjs} +1 -1
- package/dist/{renderer-DrWeb39d.mjs.map → renderer-DcvjSolU.mjs.map} +1 -1
- package/dist/renderer-DfUcwMKa.mjs +5 -0
- package/dist/renderer-DgIjNANM.mjs +6 -0
- package/dist/{renderer-DOKHd37M.mjs → renderer-DgPn_SOC.mjs} +4 -4
- package/dist/{renderer-DOKHd37M.mjs.map → renderer-DgPn_SOC.mjs.map} +1 -1
- package/dist/{renderer-BgDLCCuq.mjs → renderer-DkqZmfm8.mjs} +5 -5
- package/dist/{renderer-BgDLCCuq.mjs.map → renderer-DkqZmfm8.mjs.map} +1 -1
- package/dist/{renderer-q4zMFfnY.mjs → renderer-Dpl6poqD.mjs} +2 -2
- package/dist/{renderer-q4zMFfnY.mjs.map → renderer-Dpl6poqD.mjs.map} +1 -1
- package/dist/renderer-Dsh6Tgu0.mjs +3 -0
- package/dist/renderer-DuIwR9GT.mjs +5 -0
- package/dist/renderer-Dv4u2c14.mjs +5 -0
- package/dist/{renderer-BJKzZwyn.mjs → renderer-DwK9jsER.mjs} +4 -4
- package/dist/{renderer-BJKzZwyn.mjs.map → renderer-DwK9jsER.mjs.map} +1 -1
- package/dist/{renderer-mQt-y49D.mjs → renderer-HDj9Zb-O.mjs} +5 -5
- package/dist/{renderer-mQt-y49D.mjs.map → renderer-HDj9Zb-O.mjs.map} +1 -1
- package/dist/renderer-IE1yu3lZ.mjs +5 -0
- package/dist/{renderer-B7kOF_Az.mjs → renderer-JHByuUNb.mjs} +3 -3
- package/dist/{renderer-B7kOF_Az.mjs.map → renderer-JHByuUNb.mjs.map} +1 -1
- package/dist/{renderer-B3IRvukr.mjs → renderer-KKk7myX1.mjs} +5 -5
- package/dist/{renderer-B3IRvukr.mjs.map → renderer-KKk7myX1.mjs.map} +1 -1
- package/dist/renderer-PY_wnEN0.mjs +5 -0
- package/dist/{renderer-BcO7LUla.mjs → renderer-Ros7XQg2.mjs} +3 -3
- package/dist/{renderer-BcO7LUla.mjs.map → renderer-Ros7XQg2.mjs.map} +1 -1
- package/dist/{renderer-bbaMOD4I.mjs → renderer-RvI3qRUI.mjs} +5 -5
- package/dist/{renderer-bbaMOD4I.mjs.map → renderer-RvI3qRUI.mjs.map} +1 -1
- package/dist/{renderer-CPTXJs0n.mjs → renderer-Rw87u1Cr.mjs} +6 -6
- package/dist/{renderer-CPTXJs0n.mjs.map → renderer-Rw87u1Cr.mjs.map} +1 -1
- package/dist/{renderer-Du-GnKLb.mjs → renderer-TKZCA0B9.mjs} +9 -9
- package/dist/{renderer-Du-GnKLb.mjs.map → renderer-TKZCA0B9.mjs.map} +1 -1
- package/dist/{renderer-C_2UDMEG.mjs → renderer-V4dhrf_h.mjs} +6 -6
- package/dist/{renderer-C_2UDMEG.mjs.map → renderer-V4dhrf_h.mjs.map} +1 -1
- package/dist/{renderer-eT7Gp7FS.mjs → renderer-_9gbYS-3.mjs} +5 -5
- package/dist/{renderer-eT7Gp7FS.mjs.map → renderer-_9gbYS-3.mjs.map} +1 -1
- package/dist/{renderer-IQ97z2rw.mjs → renderer-celhuAL7.mjs} +3 -3
- package/dist/{renderer-IQ97z2rw.mjs.map → renderer-celhuAL7.mjs.map} +1 -1
- package/dist/{renderer-DIqkhsLI.mjs → renderer-eMCTAa9e.mjs} +4 -4
- package/dist/{renderer-DIqkhsLI.mjs.map → renderer-eMCTAa9e.mjs.map} +1 -1
- package/dist/{renderer-B6TjJi1g.mjs → renderer-fs8f1QeE.mjs} +5 -5
- package/dist/{renderer-B6TjJi1g.mjs.map → renderer-fs8f1QeE.mjs.map} +1 -1
- package/dist/{renderer-BJQt0RiZ.mjs → renderer-fwKnV9zs.mjs} +5 -5
- package/dist/{renderer-BJQt0RiZ.mjs.map → renderer-fwKnV9zs.mjs.map} +1 -1
- package/dist/{renderer-F1D9ZJ8I.mjs → renderer-g_1t2je9.mjs} +3 -3
- package/dist/renderer-gv24VyzO.mjs +5 -0
- package/dist/{renderer-C3Iev6zu.mjs → renderer-h62QaJYz.mjs} +4 -4
- package/dist/{renderer-C3Iev6zu.mjs.map → renderer-h62QaJYz.mjs.map} +1 -1
- package/dist/{renderer-BNbMi9CI.mjs → renderer-jnAIhWn_.mjs} +5 -5
- package/dist/{renderer-BNbMi9CI.mjs.map → renderer-jnAIhWn_.mjs.map} +1 -1
- package/dist/{renderer-CyCtm0UV.mjs → renderer-lHNTgiOM.mjs} +3 -3
- package/dist/{renderer-CyCtm0UV.mjs.map → renderer-lHNTgiOM.mjs.map} +1 -1
- package/dist/renderer-nN6lPZf9.mjs +5 -0
- package/dist/{renderer-Dat8opUZ.mjs → renderer-o68mVeyk.mjs} +4 -4
- package/dist/{renderer-Dat8opUZ.mjs.map → renderer-o68mVeyk.mjs.map} +1 -1
- package/dist/{renderer-Dss7T71q.mjs → renderer-pNmI-A9o.mjs} +5 -5
- package/dist/{renderer-Dss7T71q.mjs.map → renderer-pNmI-A9o.mjs.map} +1 -1
- package/dist/{renderer-CbhnJi_8.mjs → renderer-q7q6k_cD.mjs} +4 -4
- package/dist/{renderer-CbhnJi_8.mjs.map → renderer-q7q6k_cD.mjs.map} +1 -1
- package/dist/{renderer-OsQRvOle.mjs → renderer-riIFosX6.mjs} +5 -5
- package/dist/{renderer-OsQRvOle.mjs.map → renderer-riIFosX6.mjs.map} +1 -1
- package/dist/{renderer-BMP_lYMk.mjs → renderer-sfqZK6L5.mjs} +4 -4
- package/dist/{renderer-BMP_lYMk.mjs.map → renderer-sfqZK6L5.mjs.map} +1 -1
- package/dist/{renderer-DEQeONTd.mjs → renderer-ynFRJh7G.mjs} +3 -3
- package/dist/{renderers-CP8CFWDs-BH1gUTYa.mjs → renderers-CP8CFWDs-DRoslK4F.mjs} +4 -4
- package/dist/{renderers-CP8CFWDs-BH1gUTYa.mjs.map → renderers-CP8CFWDs-DRoslK4F.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 +8 -8
- package/dist/signals/index.mjs +8 -8
- package/dist/{signals-gOd0Ui9B.mjs → signals-BfJ1aqpT.mjs} +4 -4
- package/dist/{signals-gOd0Ui9B.mjs.map → signals-BfJ1aqpT.mjs.map} +1 -1
- package/dist/{src-BU1VOWSk.mjs → src-BYp6r-cS.mjs} +11 -11
- package/dist/{src-BU1VOWSk.mjs.map → src-BYp6r-cS.mjs.map} +1 -1
- package/dist/{src-Bnr8DUC--DzkRGA62.mjs → src-Bnr8DUC--BRDqRF6I.mjs} +3 -3
- package/dist/{src-Bnr8DUC--DzkRGA62.mjs.map → src-Bnr8DUC--BRDqRF6I.mjs.map} +1 -1
- package/package.json +65 -59
- package/dist/audio-B6RmYOPe.mjs.map +0 -1
- package/dist/audio-D6tBMbHh.d.mts +0 -38
- package/dist/audio-D6tBMbHh.d.mts.map +0 -1
- package/dist/dist-D12-a3-x.mjs.map +0 -1
- package/dist/index-B9Lm1x8i.d.mts.map +0 -1
- package/dist/index-Bzo1uj8h.d.mts.map +0 -1
- package/dist/index-V0ZQ4JN6.d.mts.map +0 -1
- package/dist/preview-engine/chunk-S2ABWY5G.mjs +0 -1
- package/dist/preview-engine/renderers-3BOQOUEU.mjs +0 -1
- package/dist/preview-engine/renderers-3M2FESR2.mjs +0 -1
- package/dist/preview-engine/renderers-5XRKZHVT.mjs +0 -1
- package/dist/preview-engine/renderers-6LHIWKMZ.mjs +0 -1
- package/dist/preview-engine/renderers-A43VCJ7X.mjs +0 -1
- package/dist/preview-engine/renderers-AKY464RY.mjs +0 -1
- package/dist/preview-engine/renderers-C5UO6PL5.mjs +0 -1
- package/dist/preview-engine/renderers-C64QSZO4.mjs +0 -1
- package/dist/preview-engine/renderers-CIRCR6NG.mjs +0 -1
- package/dist/preview-engine/renderers-CIWOPETY.mjs +0 -1
- package/dist/preview-engine/renderers-CZEZCELP.mjs +0 -1
- package/dist/preview-engine/renderers-FSQMWHQM.mjs +0 -1
- package/dist/preview-engine/renderers-FZEW5C23.mjs +0 -1
- package/dist/preview-engine/renderers-HCET2IML.mjs +0 -1
- package/dist/preview-engine/renderers-IUOOC6K7.mjs +0 -1
- package/dist/preview-engine/renderers-KYYJLVIJ.mjs +0 -1
- package/dist/preview-engine/renderers-L4GE7WV3.mjs +0 -1
- package/dist/preview-engine/renderers-LRAFWKCO.mjs +0 -1
- package/dist/preview-engine/renderers-LU3XZWEB.mjs +0 -1
- package/dist/preview-engine/renderers-ND2WV4K3.mjs +0 -1
- package/dist/preview-engine/renderers-NJ5CWVVH.mjs +0 -1
- package/dist/preview-engine/renderers-NKXYPR3V.mjs +0 -1
- package/dist/preview-engine/renderers-NWR66CGK.mjs +0 -1
- package/dist/preview-engine/renderers-O22WTBRM.mjs +0 -1
- package/dist/preview-engine/renderers-PBBA7LQB.mjs +0 -1
- package/dist/preview-engine/renderers-Q6LJRZ7R.mjs +0 -1
- package/dist/preview-engine/renderers-RMEACSRL.mjs +0 -1
- package/dist/preview-engine/renderers-SP42LCSI.mjs +0 -1
- package/dist/preview-engine/renderers-T7SZA3BX.mjs +0 -1
- package/dist/preview-engine/renderers-VADTDAHD.mjs +0 -1
- package/dist/preview-engine/renderers-VNNWI5C3.mjs +0 -1
- package/dist/preview-engine/renderers-WZ75MLP3.mjs +0 -1
- package/dist/preview-engine/renderers-XB5R4UQA.mjs +0 -1
- package/dist/preview-engine/renderers-YBIUZDGQ.mjs +0 -1
- package/dist/preview-engine/renderers-YESJR4O7.mjs +0 -1
- package/dist/preview-engine/renderers-YKSRZRRT.mjs +0 -1
- package/dist/renderer-129U3pc9.mjs +0 -5
- package/dist/renderer-2phFTFxQ.mjs +0 -5
- package/dist/renderer-9muKpDeE.mjs +0 -5
- package/dist/renderer-B5Dhv6j9.mjs +0 -5
- package/dist/renderer-BBUgCS3C.mjs +0 -5
- package/dist/renderer-BKXM28Mx.mjs +0 -5
- package/dist/renderer-BKqm6xdf.mjs +0 -5
- package/dist/renderer-BMfMMf0R.mjs +0 -5
- package/dist/renderer-BPsjEnnl.mjs +0 -5
- package/dist/renderer-Be5hfwSd.mjs.map +0 -1
- package/dist/renderer-Bofr6f88.mjs +0 -6
- package/dist/renderer-BqoGcujR.mjs +0 -5
- package/dist/renderer-BvuBt2aH.mjs +0 -5
- package/dist/renderer-BxTgXHu1.mjs +0 -5
- package/dist/renderer-Bz2Rrz60.mjs +0 -5
- package/dist/renderer-CBjG8rjE.mjs +0 -5
- package/dist/renderer-CS2zyPyZ.mjs +0 -5
- package/dist/renderer-CXnbl_jR.mjs +0 -5
- package/dist/renderer-CaF9vod_.mjs +0 -5
- package/dist/renderer-CbSBH3lp.mjs +0 -5
- package/dist/renderer-CdjuGRbO.mjs +0 -5
- package/dist/renderer-CoLbxC13.mjs +0 -5
- package/dist/renderer-Cr9G0dXB.mjs +0 -5
- package/dist/renderer-D63l6_UC.mjs +0 -5
- package/dist/renderer-DCJqnzER.mjs +0 -5
- package/dist/renderer-DFBOR5J3.mjs +0 -5
- package/dist/renderer-DGAZSzw6.mjs +0 -5
- package/dist/renderer-DPLGk1Qk.mjs +0 -5
- package/dist/renderer-DTCUzByS.mjs +0 -5
- package/dist/renderer-DdGahYi1.mjs +0 -5
- package/dist/renderer-DhL4nNPk.mjs +0 -5
- package/dist/renderer-DkyTbiVz.mjs +0 -3
- package/dist/renderer-DnAZweRX.mjs +0 -5
- package/dist/renderer-DpisVnT2.mjs +0 -5
- package/dist/renderer-Ds7pAKnE.mjs +0 -3
- package/dist/renderer-DxZD5B54.mjs +0 -5
- package/dist/renderer-PMHOnbnA.mjs +0 -5
- package/dist/renderer-STufNpMx.mjs +0 -5
- package/dist/renderer-SdrgfCxH.mjs +0 -5
- /package/dist/{chunk-D8S17ehY.mjs → chunk-W71TSjRM.mjs} +0 -0
- /package/dist/{renderer-Cputd36d.mjs → renderer-B6rZUBwE.mjs} +0 -0
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":["path","fonts","path","path","report","config"],"sources":["../src/cli/config.ts","../src/cli/fonts.ts","../src/cli/add.ts","../src/cli/templates.ts","../src/cli/init.ts","../src/cli/check.ts","../src/cli/registry.ts","../src/cli.ts"],"sourcesContent":["/**\n * `framefields.json` at the project root: where installed components live,\n * and which fonts `framefields add` / `framefields fonts add` installed.\n */\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport const CONFIG_FILE = \"framefields.json\";\n\nexport interface ProjectConfig {\n\t/** Components directory, relative to the project root. */\n\tcomponents: string;\n\t/**\n\t * Font files by role (`emoji`), relative to the project root. A role\n\t * set here counts as installed: point it at your own font to use that.\n\t */\n\tfonts?: Partial<Record<string, string>>;\n}\n\n/** The project's config, or the default it would get: `src/components` when there is a `src`. */\nexport function readConfig(cwd: string): {\n\tconfig: ProjectConfig;\n\tsaved: boolean;\n} {\n\tconst file = join(cwd, CONFIG_FILE);\n\tif (existsSync(file)) {\n\t\tconst config = JSON.parse(\n\t\t\treadFileSync(file, \"utf8\"),\n\t\t) as Partial<ProjectConfig>;\n\t\tif (typeof config.components !== \"string\")\n\t\t\tthrow new Error(`${CONFIG_FILE}: \"components\" must be a directory path`);\n\t\tif (\n\t\t\tconfig.fonts !== undefined &&\n\t\t\t(typeof config.fonts !== \"object\" ||\n\t\t\t\tObject.values(config.fonts).some((v) => typeof v !== \"string\"))\n\t\t)\n\t\t\tthrow new Error(\n\t\t\t\t`${CONFIG_FILE}: \"fonts\" must map roles to font file paths, e.g. { \"emoji\": \"assets/fonts/NotoColorEmoji.ttf\" }`,\n\t\t\t);\n\t\treturn { config: config as ProjectConfig, saved: true };\n\t}\n\tconst components = existsSync(join(cwd, \"src\"))\n\t\t? \"src/components\"\n\t\t: \"components\";\n\treturn { config: { components }, saved: false };\n}\n\nexport function writeConfig(cwd: string, config: ProjectConfig): void {\n\twriteFileSync(\n\t\tjoin(cwd, CONFIG_FILE),\n\t\t`${JSON.stringify(config, null, \"\\t\")}\\n`,\n\t);\n}\n","/**\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, { 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 */\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 src/film.ts --json\",\n\t\"check:render\":\n\t\t\"tsc --noEmit -p . && framefields check src/film.ts --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};\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\\`\\`\\`\n\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- 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 { 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\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, then fonts (recorded there) and their module.\n\tconst { config, saved } = readConfig(root);\n\tif (!saved) {\n\t\twriteConfig(root, config);\n\t\treport.written.push(\"framefields.json\");\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 * 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 */\nimport { readFileSync } from \"node:fs\";\nimport { 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 { 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 <entry> Build, validate and lint a composition; --render also writes a\n representative frame and grid. --export defaults to buildFilm.\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\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 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`;\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\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\") {\n\t\tif (names.length !== 1) {\n\t\t\tprocess.stderr.write(\n\t\t\t\t\"Usage: framefields check <entry> [--export buildFilm] [--render] [--json]\\n\",\n\t\t\t);\n\t\t\treturn 2;\n\t\t}\n\t\tconst report = await runCheck({\n\t\t\tentry: names[0],\n\t\t\texportName: values.export,\n\t\t\trender: values.render,\n\t\t\toutputDir: values.output,\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\tif (values.json) log(JSON.stringify(report));\n\t\telse {\n\t\t\tlog(`Check ${report.status}: ${report.entry} (${report.exportName})`);\n\t\t\tfor (const d of report.diagnostics)\n\t\t\t\tlog(\n\t\t\t\t\t`${d.severity} ${d.code}${d.path ? ` at ${d.path}` : \"\"}: ${d.message}`,\n\t\t\t\t);\n\t\t\tfor (const file of report.artifacts) log(`Wrote ${file}`);\n\t\t}\n\t\treturn report.status === \"passed\" ? 0 : 1;\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. */\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":";;;;;;;;;;;;;;;AAOA,MAAa,cAAc;;AAa3B,SAAgB,WAAW,KAGzB;CACD,MAAM,OAAO,KAAK,KAAK,YAAY;AACnC,KAAI,WAAW,KAAK,EAAE;EACrB,MAAM,SAAS,KAAK,MACnB,aAAa,MAAM,OAAO,CAC1B;AACD,MAAI,OAAO,OAAO,eAAe,SAChC,OAAM,IAAI,MAAM,GAAG,YAAY,yCAAyC;AACzE,MACC,OAAO,UAAU,WAChB,OAAO,OAAO,UAAU,YACxB,OAAO,OAAO,OAAO,MAAM,CAAC,MAAM,MAAM,OAAO,MAAM,SAAS,EAE/D,OAAM,IAAI,MACT,GAAG,YAAY,kGACf;AACF,SAAO;GAAU;GAAyB,OAAO;GAAM;;AAKxD,QAAO;EAAE,QAAQ,EAAE,YAHA,WAAW,KAAK,KAAK,MAAM,CAAC,GAC5C,mBACA,cAC4B;EAAE,OAAO;EAAO;;AAGhD,SAAgB,YAAY,KAAa,QAA6B;AACrE,eACC,KAAK,KAAK,YAAY,EACtB,GAAG,KAAK,UAAU,QAAQ,MAAM,IAAK,CAAC,IACtC;;;;;;;;;;;;;;;ACVF,MAAM,aACL;;AAED,MAAM,eACL;;AAGD,MAAa,QAAkC;CAC9C,OAAO;EACN,OAAO;EACP,MAAM;EACN,MAAM;GACL,KAAK,GAAG,WAAW;GACnB,QACC;GACD,OAAO;GACP;EACD,SAAS;GACR,IAAI;GACJ,MAAM;GACN,KAAK,GAAG,WAAW;GACnB,QACC;GACD,OAAO;GACP;EACD,UAAU,EAAE,OAAO,MAAM;EACzB;CACD,MAAM,WAAW;EAChB,OAAO;EACP,MAAM;EACN,QAAQ;EACR,MAAM;EACN,QAAQ;EACR,OAAO;EACP,SAAS;GACR,MAAM;GACN,QACC;GACD,OAAO;GACP;EACD,CAAC;CACF,MAAM,WAAW;EAChB,OAAO;EACP,MAAM;EACN,QAAQ;EACR,MAAM;EACN,QAAQ;EACR,OAAO;EACP,SAAS;GACR,MAAM;GACN,QACC;GACD,OAAO;GACP;EACD,CAAC;CACF;;AAGD,SAAS,WAAW,GAQP;CACZ,MAAM,MAAM,WAAiB,GAAG,aAAa,GAAGA;AAChD,QAAO;EACN,OAAO,EAAE;EACT,MAAM,EAAE;EACR,MAAM;GAAE,KAAK,GAAG,EAAE,KAAK;GAAE,QAAQ,EAAE;GAAQ,OAAO,EAAE;GAAO;EAC3D,SAAS;GACR,KAAK,GAAG,EAAE,QAAQ,KAAK;GACvB,QAAQ,EAAE,QAAQ;GAClB,OAAO,EAAE,QAAQ;GACjB,IAAI;GACJ,MAAM,EAAE,KAAK,QAAQ,UAAU,WAAW;GAC1C;EACD,UAAU,EAAE,QAAQ,EAAE,QAAQ;EAC9B;;;AAIF,MAAa,oBAAoB;AAkCjC,MAAM,UAAU,UACf,WAAW,SAAS,CAAC,OAAO,MAAM,CAAC,OAAO,MAAM;;AAGjD,MAAM,eAAe,KAAa,WACjC,SAAS,KAAKA,OAAK,CAAC,MAAM,IAAI,CAAC,KAAK,MAAM,IAAI;;AAG/C,eAAsB,YACrB,MACA,SACuB;CACvB,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,OAAO,QAAQ;AACrB,KAAI,CAAC,KACJ,OAAM,IAAI,MACT,iBAAiB,KAAK,oCAAoC,OAAO,KAAK,QAAQ,CAAC,KAAK,KAAK,CAAC,GAC1F;CACF,MAAM,EAAE,QAAQ;CAChB,MAAM,EAAE,WAAW,WAAW,IAAI;CAClC,MAAM,aAAa,OAAO,QAAQ;AAClC,KAAI,cAAc,WAAW,QAAQ,KAAK,WAAW,CAAC,CACrD,QAAO;EAAE;EAAM,MAAM;EAAY,QAAQ;EAAc;CAExD,MAAM,SAAS,QAAQ,KAAK,QAAQ,OAAO,mBAAmB,KAAK,KAAK;CACxE,MAAMA,SAAO,YAAY,KAAK,OAAO;CACrC,IAAI,SAAgC;CACpC,MAAM,UAAU,WAAW,OAAO,GAAG,aAAa,OAAO,GAAG;AAC5D,KAAI,CAAC,WAAW,OAAO,QAAQ,KAAK,KAAK,KAAK,QAAQ;AACrD,MAAI,WAAW,CAAC,QAAQ,UACvB,OAAM,IAAI,MACT,GAAGA,OAAK,+BAA+B,KAAK,KAAK,oDAAoD,KAAK,kDAC1G;AACF,UAAQ,aAAa,KAAK;EAC1B,MAAM,MAAM,QAAQ,SAAU;EAC9B,MAAM,CAAC,MAAM,WAAW,MAAM,QAAQ,IAAI,CACzC,SAAS,KAAK,MAAM,IAAI,EACxB,SAAS,KAAK,SAAS,IAAI,CAC3B,CAAC;AACF,YAAU,QAAQ,OAAO,EAAE,EAAE,WAAW,MAAM,CAAC;AAC/C,gBAAc,QAAQ,KAAK;AAC3B,gBAAc,KAAK,QAAQ,OAAO,EAAE,KAAK,QAAQ,KAAK,EAAE,QAAQ;AAChE,WAAS;;AAEV,aAAY,KAAK;EAChB,GAAG;EACH,OAAO;GAAE,GAAG,OAAO;IAAQ,OAAOA;GAAM;EACxC,CAAC;AACF,QAAO;EAAE;EAAM;EAAM;EAAQ;;AAG9B,eAAe,SAAS,MAAkB,KAAiC;CAC1E,IAAI;AACJ,KAAI;AACH,QAAM,MAAM,IAAI,KAAK,IAAI;UACjB,OAAO;AACf,QAAM,IAAI,MACT,qBAAqB,KAAK,IAAI,IAAI,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,CAAC,4FACzF;;AAEF,KAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,GAAG,KAAK,IAAI,IAAI,IAAI,OAAO,GAAG,IAAI,aAAa;CAC5E,MAAM,QAAQ,IAAI,WAAW,MAAM,IAAI,aAAa,CAAC;CACrD,MAAM,OAAO,OAAO,MAAM;AAC1B,KAAI,MAAM,WAAW,KAAK,SAAS,SAAS,KAAK,OAChD,OAAM,IAAI,MACT,GAAG,KAAK,IAAI,8BAA8B,MAAM,OAAO,iBAAiB,KAAK,aAAa,KAAK,MAAM,IAAI,KAAK,OAAO,yBACrH;AACF,QAAO;;;AAIR,MAAa,sBACZ;;;;;;AAgBD,SAAgB,iBACf,KACA,eACA,UAAoC,OACtB;CACd,MAAM,EAAE,WAAW,WAAW,IAAI;CAClC,MAAM,SAAS,KAAK,eAAe,WAAW;CAC9C,MAAMA,SAAO,YAAY,KAAK,OAAO;CACrC,MAAMC,UAAQ,OAAO,QAAQ,OAAO,SAAS,EAAE,CAAC,CAC9C,QAAQ,CAAC,UAAU,QAAQ,MAAM,CACjC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,CAAC,CACtC,KAAK,CAAC,MAAM,UAAU;EACtB,MAAM,OAAO,SAAS,eAAe,QAAQ,KAAK,KAAe,CAAC,CAChE,MAAM,IAAI,CACV,KAAK,MAAM,IAAI;EACjB,MAAM,MAAM,KAAK,WAAW,IAAI,GAAG,OAAO,KAAK;AAC/C,SAAO;GAAE,UAAW,QAAQ,MAAmB;GAAU;GAAK;GAC7D;CACH,MAAM,QAAQ,GAAyB,WACtC,YAAY,IACT,sBAAsB,KAAK,UAAU,EAAE,OAAO,CAAC,YAAY,OAAO,OAClE,qBAAqB,OAAO;CAChC,MAAM,QAAQA,QAAM,KAClB,MAAM,qBAAqB,KAAK,EAAE,UAAU,UAAU,EAAE,IAAI,IAAI,CAAC,GAClE;CACD,MAAM,UAAU,GAAG,oBAAoB;;;;;;;;;;;;;;;;;EAiBtCA,QAEA,KAAK,MACL,YAAY,EAAE,WACX,+CAA+C,KAAK,UAAU,EAAE,SAAS,OAAO,CAAC,wBAAwB,EAAE,IAAI,cAC/G,sDAAsD,EAAE,IAAI,WAC/D,CACA,KAAK,KAAK,CAAC;;;AAGZ,KAAI,WAAW,OAAO,EAAE;EACvB,MAAM,UAAU,aAAa,QAAQ,OAAO;AAC5C,MAAI,YAAY,QAAS,QAAO;GAAE;GAAM,QAAQ;GAAa;GAAO;AACpE,MAAI,CAAC,QAAQ,WAAW,oBAAoB,CAC3C,QAAO;GAAE;GAAM,QAAQ;GAAW;GAAO;;AAE3C,WAAU,eAAe,EAAE,WAAW,MAAM,CAAC;AAC7C,eAAc,QAAQ,QAAQ;AAC9B,QAAO;EAAE;EAAM,QAAQ;EAAW;EAAO;;;;;;AAO1C,SAAgB,QAAQ,KAAa,UAAiC;AACrE,KAAI,CAAC,WAAW,KAAK,KAAK,OAAO,CAAC,CAAE,QAAO;CAC3C,MAAM,QAAQ,KAAK,KAAK,iBAAiB;CACzC,MAAM,OAAO,WAAW,MAAM,GAAG,aAAa,OAAO,OAAO,GAAG;AAC/D,KAAI,0BAA0B,KAAK,KAAK,CAAE,QAAO;AAEjD,QAAO,4EADK,MAAM,QAAQ,SAAS,CACoD;;;;;;;;;;;;;;;;AClQxF,eAAsB,IACrB,OACA,SACqB;CACrB,MAAM,EAAE,KAAK,aAAa;CAC1B,MAAM,QAAQ,MAAM,SAAS,OAAO;CACpC,MAAM,QAAQ,IAAI,IAAI,MAAM,KAAK,MAAM,EAAE,KAAK,CAAC;AAC/C,MAAK,MAAM,KAAK,MACf,KAAI,CAAC,MAAM,IAAI,EAAE,CAChB,OAAM,IAAI,MACT,sBAAsB,EAAE,8CACxB;CAGH,MAAM,QAAwB,EAAE;CAChC,MAAM,uBAAO,IAAI,KAAa;CAC9B,MAAM,QAAQ,OAAO,SAAiB;AACrC,MAAI,KAAK,IAAI,KAAK,CAAE;AACpB,OAAK,IAAI,KAAK;EACd,MAAM,OAAO,MAAM,SAAS,KAAK,KAAK;AACtC,OAAK,MAAM,KAAK,KAAK,qBAAsB,OAAM,MAAM,EAAE;AACzD,QAAM,KAAK,KAAK;;AAEjB,MAAK,MAAM,KAAK,MAAO,OAAM,MAAM,EAAE;CAErC,MAAM,EAAE,QAAQ,UAAU,WAAW,IAAI;CAEzC,MAAM,MAAM,QAAQ,KADR,QAAQ,OAAO,OAAO,WACL;CAC7B,MAAM,SAAoB;EACzB;EACA,YAAY;EACZ,SAAS,EAAE;EACX,WAAW,EAAE;EACb,SAAS,EAAE;EACX,eAAe;EACf,OAAO,EAAE;EACT,cAAc,EAAE;EAChB;AACD,MAAK,MAAM,QAAQ,MAClB,MAAK,MAAM,QAAQ,KAAK,OAAO;EAC9B,MAAM,SAAS,KAAK,KAAK,KAAK,KAAK;EACnC,MAAM,QAAQ,SAAS,KAAK,OAAO;AACnC,MAAI,WAAW,OAAO,EAAE;AACvB,OAAI,aAAa,QAAQ,OAAO,KAAK,KAAK,SAAS;AAClD,WAAO,UAAU,KAAK,MAAM;AAC5B;;AAED,OAAI,CAAC,QAAQ,WAAW;AACvB,WAAO,QAAQ,KAAK,MAAM;AAC1B;;;AAGF,YAAU,QAAQ,OAAO,EAAE,EAAE,WAAW,MAAM,CAAC;AAC/C,gBAAc,QAAQ,KAAK,QAAQ;AACnC,SAAO,QAAQ,KAAK,MAAM;;AAG5B,KAAI,CAAC,OAAO;AACX,cAAY,KAAK,EAAE,YAAY,SAAS,KAAK,IAAI,IAAI,KAAK,CAAC;AAC3D,SAAO,gBAAgB;;CAIxB,MAAM,wBAAQ,IAAI,KAA0C;AAC5D,MAAK,MAAM,QAAQ,MAClB,MAAK,MAAM,KAAK,KAAK,SAAS,EAAE,CAC/B,KAAI,CAAC,MAAM,IAAI,EAAE,KAAK,CAAE,OAAM,IAAI,EAAE,MAAM;EAAE,KAAK,EAAE;EAAK,IAAI,KAAK;EAAM,CAAC;AAC1E,MAAK,MAAM,CAAC,MAAM,SAAS,OAAO;AACjC,MAAI,QAAQ,UAAU,OAAO;AAC5B,UAAO,aAAa,KAAK;IAAE;IAAM,GAAG;IAAM,CAAC;AAC3C;;EAED,MAAM,OAAO,MAAM,YAAY,MAAM;GACpC;GACA,KAAK,QAAQ;GACb,WAAW,QAAQ;GACnB,OAAO,QAAQ;GACf,SAAS,QAAQ;GACjB,YAAY,QAAQ;GACpB,CAAC;AACF,SAAO,MAAM,KAAK;GAAE,GAAG;GAAM,GAAG;GAAM,CAAC;;AAExC,KAAI,OAAO,MAAM,SAAS,KAAK,WAAW,IAAI,CAAC,OAAO,MACrD,QAAO,cAAc,iBAAiB,KAAK,KAAK,QAAQ,YAAY;AACrE,QAAO;;;;;;;;;;;;;;ACxIR,MAAM,kBAAkB,CAAC,cAAc;AACvC,MAAM,iBAAiB;CACtB;CACA;CACA;CACA;CACA;CACA;CACA;;AAGD,MAAa,mBAA2C;CACvD,eAAe;CACf,KAAK;CACL,YAAY;CACZ;AAED,MAAa,UAAkC;CAC9C,WAAW;CACX,OAAO;CACP,gBACC;CACD,QAAQ;CACR,MAAM;CACN,SAAS;CACT,QAAQ;CACR;;;;;AAMD,SAAgB,cAAc,GAG3B;AACF,QAAO;EACN,MAAM;EACN,GAAI,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,gBAAgB;EAC5D,SAAS;EACT,cAAc,EAAE,aAAa,IAAI,EAAE,sBAAsB;EACzD,iBAAiB;EACjB,cAAc,OAAO,YAAY,CAChC,GAAG,gBAAgB,KAAK,MAAM,CAAC,GAAG,KAAK,CAAC,EACxC,GAAG,eAAe,KAAK,MAAM,CAAC,GAAG,MAAM,CAAC,CACxC,CAAC;EACF,MAAM;GACL,uBAAuB;GACvB,0BAA0B;GAC1B;EACD,qBAAqB;EACrB;;AAGF,MAAa,WAAW,GAAG,KAAK,UAC/B;CACC,iBAAiB;EAChB,QAAQ;EACR,kBAAkB;EAClB,QAAQ;EACR,QAAQ;EACR,cAAc;EACd,QAAQ;EACR,OAAO,CAAC,OAAO;EACf;CACD,SAAS,CAAC,WAAW;CACrB,EACD,MACA,IACA,CAAC;;AAGF,MAAa,YAAY;CACxB;CACA;CACA;CACA;CACA;CACA;;AAGD,MAAa,eAAe;;AAG5B,MAAa,cAAc;;;oBAGP,aAAa;;;;AAKjC,MAAa,gBAAgB;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AAED,MAAa,WAAW;;;;;;;;;;;;;;;;;;;;AAqBxB,MAAa,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CvB,MAAa,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4DzB,SAAgB,OAAO,MAAc,KAAyC;AAC7E,QAAO,KAAK,KAAK;;;;;EAKhB,IAAI,YAAY,CAAC;EACjB,IAAI,SAAS,CAAC;EACd,IAAI,OAAO,CAAC;EACZ,IAAI,UAAU,CAAC;EACf,IAAI,SAAS,CAAC;;;;;;;;0EAQ0D,aAAa;;;;;;;;;;;;;;;;;;;;AC9NvF,MAAa,mBAAmB;CAAC;CAAO;CAAQ;CAAQ;CAAM;;AA4D9D,SAAgB,qBACf,WACoD;CACpD,MAAM,IAAI,WAAW,MAAM,qCAAqC;AAChE,KAAI,CAAC,EAAG,QAAO;AACf,QAAO;EAAE,MAAM,EAAE;EAAsB,SAAS,EAAE;EAAI;;AAGvD,MAAM,gBAAgB,QAAwB,WAC7C,OAAO,SAAS,OAAO,QAAQ,GAAG,GAAG,OAAO,WAAW,GAAG,GAAG,GAAG;;AAGjE,SAAgB,YAAY,QAAwB;AAKnD,QAJa,OACX,aAAa,CACb,QAAQ,mBAAmB,IAAI,CAC/B,QAAQ,oBAAoB,GAAG,IAClB;;AAGhB,eAAsB,KAAK,SAA2C;CACrE,MAAM,OAAO,QAAQ,QAAQ,KAAK,QAAQ,OAAO,IAAI;AACrD,WAAU,MAAM,EAAE,WAAW,MAAM,CAAC;CACpC,MAAM,WAAW,qBAAqB,QAAQ,UAAU;CACxD,MAAM,KAAK,QAAQ,kBAAkB,UAAU,QAAQ;CACvD,MAAM,YAAY,UAAU,SAAS,KAAK,SAAS,UAAU;CAC7D,MAAM,MAAM,QAAQ,OAAO;CAC3B,MAAM,SAAqB;EAC1B;EACA,MAAM;EACN,gBAAgB;EAChB,SAAS,EAAE;EACX,QAAQ,EAAE;EACV,WAAW,EAAE;EACb,OAAO,EAAE;EACT,aAAa;GAAE,MAAM;GAAI,QAAQ;GAAa,OAAO,EAAE;GAAE;EACzD,KAAK;EACL,KAAK;EACL,WAAW;EACX,WAAW,aAAa,GAAG;EAC3B;CACD,MAAM,SAAS,cAAc;EAC5B,oBAAoB,QAAQ,sBAAsB,YAAY;EAC9D,GAAI,aAAa,EAAE,gBAAgB,GAAG,GAAG,GAAG,aAAa;EACzD,CAAC;CAGF,MAAM,UAAU,KAAK,MAAM,eAAe;AAC1C,KAAI,WAAW,QAAQ,EAAE;EACxB,MAAM,MAAM,KAAK,MAAM,aAAa,SAAS,OAAO,CAAC;AAIrD,MAAI,IAAI,SAAS,WAChB,OAAM,IAAI,MACT,kJACA;AACF,SAAO,OACN,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO,YAAY,SAAS,KAAK,CAAC;AAEtE,SAAO,QAAQ,gBAAgB,eAAe,SAD/B,aAAa,KAAK,OAAO,EACuB,IAAI,CAAC;QAC9D;AACN,SAAO,OAAO,QAAQ,QAAQ,YAAY,SAAS,KAAK,CAAC;AACzD,YAAU,SAAS;GAClB,MAAM,OAAO;GACb,SAAS;GACT,SAAS;GACT,GAAG;GACH,CAAC;AACF,SAAO,QAAQ,KAAK,eAAe;;CAGpC,MAAM,QAAiC;EACtC,CAAC,iBAAiB,SAAS;EAC3B,CAAC,gBAAgB,SAAS;EAC1B,CAAC,eAAe,QAAQ;EACxB,CAAC,iBAAiB,UAAU;EAC5B,CAAC,2BAA2B,GAAG;EAC/B,CAAC,gBAAgB,YAAY;EAC7B,CAAC,aAAa,OAAO,OAAO,MAAM,OAAO,UAAU,CAAC;EACpD;AACD,MAAK,MAAM,CAACC,QAAM,YAAY,OAAO;EACpC,MAAM,SAAS,KAAK,MAAMA,OAAK;AAC/B,MAAI,WAAW,OAAO,CAAE,QAAO,UAAU,KAAKA,OAAK;OAC9C;AACJ,aAAU,QAAQ,OAAO,EAAE,EAAE,WAAW,MAAM,CAAC;AAC/C,iBAAc,QAAQ,QAAQ;AAC9B,UAAO,QAAQ,KAAKA,OAAK;;;AAG3B,MAAK,MAAM,CAACA,QAAM,UAAU,CAC3B,CAAC,cAAc,UAAU,EACzB,CAAC,kBAAkB,cAAc,CACjC,CACA,QAAO,QAAQA,QAAM,YAAY,KAAK,MAAMA,OAAK,EAAE,MAAM,CAAC;CAG3D,MAAM,EAAE,QAAQ,UAAU,WAAW,KAAK;AAC1C,KAAI,CAAC,OAAO;AACX,cAAY,MAAM,OAAO;AACzB,SAAO,QAAQ,KAAK,mBAAmB;;CAExC,MAAM,eAAe,QAAQ,UAAU;CACvC,MAAM,eAAe,QAAQ,SAAS;CACtC,MAAM,QAAQ,CACb,GAAI,eAAe,CAAC,QAAQ,OAAO,GAAG,EAAE,EACxC,GAAI,eAAe,CAAC,QAAQ,GAAG,EAAE,CACjC;AACD,MAAK,MAAM,QAAQ,MAClB,QAAO,MAAM,KACZ,MAAM,YAAY,MAAM;EACvB,KAAK;EACL,OAAO,QAAQ;EACf,SAAS,QAAQ;EACjB,YAAY,QAAQ;EACpB,CAAC,CACF;AAEF,QAAO,cAAc,iBACpB,MACA,QAAQ,MAAM,WAAW,KAAK,CAAC,OAAO,WAAW,EACjD,QAAQ,YACR;AAED,KAAI,QAAQ,QAAQ,OAAO;AAK1B,MAJe,MAAM,IAAI,OAAO,CAAC,aAAa,wBAAwB,EAAE;GACvE,KAAK;GACL,OAAO;GACP,CAAC,KACa,EAAG,QAAO,MAAM;WAE7B,MAAM,IAAI,OAAO,CAAC,QAAQ,KAAK,EAAE;GAAE,KAAK;GAAM,OAAO;GAAM,CAAC,KAAM,EAEnE,QAAO,MAAM;MACT,QAAO,MAAM;AAClB,MAAI,OAAO,QAAQ,cAClB,QAAO,MACL,MAAM,IAAI,OAAO,CAAC,OAAO,UAAU,EAAE;GAAE,KAAK;GAAM,OAAO;GAAM,CAAC,KACjE;;AAGH,KAAI,QAAQ,SAAS;EACpB,MAAM,OAAO,MAAM,IAAI,IAAI,CAAC,UAAU,EAAE,EAAE,KAAK,MAAM,CAAC;AACtD,MAAI,SAAS,EACZ,OAAM,IAAI,MACT,KAAK,GAAG,0BAA0B,KAAK,mEACvC;AACF,SAAO,YAAY;;AAEpB,QAAO;;;AAIR,SAAS,aACR,KACA,QAC0B;CAC1B,MAAM,MAA+B,EAAE,GAAG,KAAK;CAC/C,MAAM,OAAO,MACZ,KAAK,OAAO,MAAM,YAAY,CAAC,MAAM,QAAQ,EAAE,GAC3C,IACD,EAAE;CACN,MAAM,SAAS,GAAY,MAAyB,CACnD,GAAG,IAAI,IAAI,CAAC,GAAI,MAAM,QAAQ,EAAE,GAAI,IAAiB,EAAE,EAAG,GAAG,EAAE,CAAC,CAChE;AACD,KAAI,SAAS,OAAO;AACpB,KAAI,OAAO,eAAgB,KAAI,mBAAmB,OAAO;AACzD,MAAK,MAAM,OAAO;EACjB;EACA;EACA;EACA;EACA,EAAW;EACX,MAAM,SAAS,IAAI,IAAI,KAAK;EAE5B,MAAM,UACL,QAAQ,kBAAkB,QAAQ,oBAC/B;GAAE,GAAG,IAAI,IAAI,aAAa;GAAE,GAAG,IAAI,IAAI,gBAAgB;GAAE,GACzD;EACJ,MAAM,UAAU,OAAO,QAAQ,OAAO,KAAK,CAAC,QAC1C,CAAC,OAAO,EAAE,KAAK,SAChB;AACD,MAAI,QAAQ,SAAS,EACpB,KAAI,OAAO;GAAE,GAAG;GAAQ,GAAG,OAAO,YAAY,QAAQ;GAAE;;CAE1D,MAAM,OAAO,IAAI,IAAI,KAAK;AAC1B,KAAI,OAAO;EACV,GAAG;EACH,uBAAuB,MACtB,KAAK,uBACL,OAAO,KAAK,sBACZ;EACD,0BAA0B,MACzB,KAAK,0BACL,OAAO,KAAK,yBACZ;EACD;AACD,KAAI,sBAAsB,MACzB,IAAI,qBACJ,OAAO,oBACP;AACD,QAAO;;AAGR,SAAS,UAAU,QAAc,OAAgB;AAChD,eAAcA,QAAM,GAAG,KAAK,UAAU,OAAO,MAAM,IAAK,CAAC,IAAI;;AAG9D,SAAS,eACR,QACA,MACA,MACU;AACV,KAAI,KAAK,UAAU,KAAK,KAAK,KAAK,UAAU,KAAK,CAAE,QAAO;AAC1D,WAAUA,QAAM,KAAK;AACrB,QAAO;;;AAIR,SAAS,YACR,QACA,OACsB;AACtB,KAAI,CAAC,WAAWA,OAAK,EAAE;AACtB,gBAAcA,QAAM,GAAG,MAAM,KAAK,KAAK,CAAC,IAAI;AAC5C,SAAO;;CAER,MAAM,OAAO,aAAaA,QAAM,OAAO;CACvC,MAAM,OAAO,IAAI,IAAI,KAAK,MAAM,QAAQ,CAAC,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9D,MAAM,UAAU,MAAM,QAAQ,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;AACjD,KAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,eACCA,QACA,GAAG,OAAO,KAAK,SAAS,KAAK,IAAI,SAAS,KAAK,KAAK,OAAO,QAAQ,KAAK,KAAK,CAAC,IAC9E;AACD,QAAO;;;AAIR,SAAS,OAAO,QAAoB,QAAc,QAA6B;AAC9E,KAAI,WAAW,UAAW,QAAO,QAAQ,KAAKA,OAAK;UAC1C,OAAQ,QAAO,OAAO,KAAKA,OAAK;KACpC,QAAO,UAAU,KAAKA,OAAK;;;AAIjC,SAAgB,aAAqB;CACpC,IAAI,MAAM,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AACjD,UAAS;EACR,MAAM,OAAO,KAAK,KAAK,eAAe;AACtC,MAAI,WAAW,KAAK,EAAE;GACrB,MAAM,MAAM,KAAK,MAAM,aAAa,MAAM,OAAO,CAAC;AAIlD,OAAI,IAAI,SAAS,iBAAiB,IAAI,QAAS,QAAO,IAAI;;EAE3D,MAAM,KAAK,QAAQ,IAAI;AACvB,MAAI,OAAO,IAAK,OAAM,IAAI,MAAM,2CAA2C;AAC3E,QAAM;;;AAIR,MAAM,eAAuB,SAAS,MAAM,EAAE,KAAK,YAClD,IAAI,SAAS,SAAS;CACrB,MAAM,QAAQ,MAAM,SAAS,MAAM;EAClC;EACA,OAAO,QAAQ,WAAW;EAE1B,OAAO,QAAQ,aAAa;EAC5B,CAAC;AACF,OAAM,GAAG,eAAe,KAAK,IAAI,CAAC;AAClC,OAAM,GAAG,UAAU,SAAS,KAAK,QAAQ,EAAE,CAAC;EAC3C;;AAGH,SAAgB,UAAU,KAAa,MAAsB;AAC5D,QAAO,SAAS,KAAK,KAAK,IAAI;;;;;;AC/V/B,eAAsB,SAAS,SAA6C;CAC3E,MAAM,QAAQ,QAAQ,QAAQ,MAAM;CACpC,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,aAAa,YAAY;CAC/B,MAAM,UAAU,QAAQ,aAAa;AACrC,KAAI,CAAC,OAAO,cAAc,QAAQ,IAAI,WAAW,EAChD,OAAM,IAAI,MAAM,uDAAuD;CACxE,MAAM,QAAQ,MAAc,YAC3B,YAAY,OAAO,YAAY,YAAY,MAAM,QAAQ;CAC1D,MAAM,SAAS,OAAO,KAAK,IAAI,SAAS,MAAM;CAC9C,MAAM,OAAO,SAAS,CAAC,2BAA2B,GAAG,EAAE;AAEvD,KAAI,UAAU,eAAe,KAAK,MAAM,CACvC,KAAI;EACH,MAAM,UAAU,cAAc,QAAQ,eAAe,CAAC;AACtD,OAAK,KAAK,YAAY,cAAc,QAAQ,QAAQ,MAAM,CAAC,CAAC,KAAK;SAC1D;AACP,SAAO,KACN,qBACA,wEACA;;AAGH,MAAK,KACJ,cACC,IAAI,IACH,SAAS,sBAAsB,0BAC/B,OAAO,KAAK,IACZ,CACD,CACD;AACD,QAAO,IAAI,SAAS,SAAS;EAC5B,MAAM,QAAQ,MAAM,QAAQ,UAAU,MAAM,EAC3C,OAAO;GAAC;GAAU;GAAQ;GAAQ;GAAM,EACxC,CAAC;AACF,QAAM,QAAQ,KAAK,QAAQ,OAAO;AAClC,QAAM,QAAQ,KAAK,QAAQ,OAAO;EAClC,IAAI;EACJ,MAAM,QAAQ,iBAAiB;AAC9B,YAAS,KACR,iBACA,kBAAkB,QAAQ,wBAC1B;AACD,SAAM,KAAK,UAAU;KACnB,QAAQ;AACX,QAAM,GAAG,YAAY,YAAqB;AACzC,OAAI,cAAc,QAAQ,CAAE,UAAS;IACpC;AACF,QAAM,GAAG,UAAU,UAAU;AAC5B,gBAAa,MAAM;AACnB,QAAK,KAAK,uBAAuB,MAAM,QAAQ,CAAC;IAC/C;AACF,QAAM,GAAG,UAAU,MAAM,WAAW;AACnC,gBAAa,MAAM;AACnB,QACC,UACC,KACC,iBACA,8CAA8C,KAAK,WAAW,OAAO,IACrE,CACF;IACA;AACF,QAAM,KAAK;GACV,GAAG;GACH;GACA;GACA;GACA,WAAW,QAAQ,QAAQ,aAAa,eAAe;GACvD,CAAC;GACD;;AAGH,SAAS,cAAc,OAAsC;AAC5D,QACC,OAAO,UAAU,YACjB,UAAU,QACV,mBAAmB,SACnB,MAAM,kBAAkB,KACxB,iBAAiB,SACjB,MAAM,QAAQ,MAAM,YAAY;;;;;;;;;;;ACxDlC,SAAgB,sBAA8B;AAC7C,QAAO,cAAc,IAAI,IAAI,eAAe,OAAO,KAAK,IAAI,CAAC;;;AAI9D,SAAgB,aAAa,QAAiB,MAAM,QAAQ,KAAK,EAAY;CAC5E,MAAM,OACL,UAAU,QAAQ,IAAI,wBAAwB,qBAAqB;AACpE,KAAI,eAAe,KAAK,KAAK,EAAE;EAC9B,MAAM,OAAO,KAAK,SAAS,IAAI,GAAG,OAAO,GAAG,KAAK;EACjD,MAAM,MAAM,OAAU,SAA6B;GAClD,MAAM,MAAM,MAAM,MAAM,IAAI,IAAI,MAAM,KAAK,CAAC;AAC5C,OAAI,CAAC,IAAI,GACR,OAAM,IAAI,MACT,GAAG,IAAI,IAAI,MAAM,KAAK,CAAC,IAAI,IAAI,OAAO,GAAG,IAAI,aAC7C;AACF,UAAQ,MAAM,IAAI,MAAM;;AAEzB,SAAO;GACN,QAAQ;GACR,aAAa,IAAI,aAAa;GAC9B,OAAO,SAAS,IAAI,GAAG,KAAK,OAAO;GACnC;;CAEF,MAAM,MAAM,QAAQ,KAAK,KAAK;CAC9B,MAAM,QAAW,SAAoB;EACpC,MAAMC,SAAO,KAAK,KAAK,KAAK;AAC5B,MAAI,CAAC,WAAWA,OAAK,CAAE,OAAM,IAAI,MAAM,MAAM,KAAK,eAAe,MAAM;AACvE,SAAO,KAAK,MAAM,aAAaA,QAAM,OAAO,CAAC;;AAE9C,QAAO;EACN,QAAQ;EACR,OAAO,YAAY,KAAK,aAAa;EACrC,MAAM,OAAO,SAAS,KAAK,GAAG,KAAK,OAAO;EAC1C;;;;;;;;;;;;;;AC7CF,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDb,eAAe,KAAK,MAAiC;CACpD,MAAM,EAAE,QAAQ,gBAAgB,UAAU;EACzC,MAAM;EACN,kBAAkB;EAClB,SAAS;GACR,KAAK,EAAE,MAAM,WAAW;GACxB,KAAK,EAAE,MAAM,UAAU;GACvB,WAAW,EAAE,MAAM,WAAW;GAC9B,YAAY,EAAE,MAAM,WAAW;GAC/B,YAAY,EAAE,MAAM,WAAW;GAC/B,aAAa,EAAE,MAAM,UAAU;GAC/B,MAAM,EAAE,MAAM,UAAU;GACxB,IAAI,EAAE,MAAM,UAAU;GACtB,SAAS,EAAE,MAAM,WAAW;GAC5B,OAAO,EAAE,MAAM,WAAW;GAC1B,UAAU,EAAE,MAAM,WAAW;GAC7B,UAAU,EAAE,MAAM,UAAU;GAC5B,MAAM,EAAE,MAAM,WAAW;GACzB,QAAQ,EAAE,MAAM,UAAU;GAC1B,QAAQ,EAAE,MAAM,WAAW;GAC3B,QAAQ,EAAE,MAAM,UAAU;GAC1B,SAAS,EAAE,MAAM,UAAU;GAC3B,sBAAsB,EAAE,MAAM,WAAW;GACzC,MAAM;IAAE,MAAM;IAAW,OAAO;IAAK;GACrC;EACD,CAAC;CACF,MAAM,CAAC,SAAS,GAAG,SAAS;AAC5B,KAAI,OAAO,QAAQ,CAAC,SAAS;AAC5B,UAAQ,OAAO,MAAM,KAAK;AAC1B,SAAO,WAAW,OAAO,OAAO,IAAI;;CAErC,MAAM,MAAM,QAAQ,KAAK;CACzB,MAAM,OAAO,SAAiB,QAAQ,OAAO,MAAM,GAAG,KAAK,IAAI;AAC/D,KAAI,YAAY,OAAO;EACtB,MAAM,UAAU,KAAK,MACpB,aACC,cACC,IAAI,IACH,OAAO,KAAK,IAAI,SAAS,MAAM,GAAG,qBAAqB,cACvD,OAAO,KAAK,IACZ,CACD,EACD,OACA,CACD;AACD,MAAI,KAAK,UAAU;GAAE,GAAG;GAAS,YAAY,YAAY;GAAE,CAAC,CAAC;AAC7D,SAAO;;AAER,KAAI,YAAY,SAAS;AACxB,MAAI,MAAM,WAAW,GAAG;AACvB,WAAQ,OAAO,MACd,8EACA;AACD,UAAO;;EAER,MAAMC,WAAS,MAAM,SAAS;GAC7B,OAAO,MAAM;GACb,YAAY,OAAO;GACnB,QAAQ,OAAO;GACf,WAAW,OAAO;GAClB,WACC,OAAO,YAAY,SAAY,SAAY,OAAO,OAAO,QAAQ;GAClE,kBAAkB,OAAO;GACzB,CAAC;AACF,MAAI,OAAO,KAAM,KAAI,KAAK,UAAUA,SAAO,CAAC;OACvC;AACJ,OAAI,SAASA,SAAO,OAAO,IAAIA,SAAO,MAAM,IAAIA,SAAO,WAAW,GAAG;AACrE,QAAK,MAAM,KAAKA,SAAO,YACtB,KACC,GAAG,EAAE,SAAS,GAAG,EAAE,OAAO,EAAE,OAAO,OAAO,EAAE,SAAS,GAAG,IAAI,EAAE,UAC9D;AACF,QAAK,MAAM,QAAQA,SAAO,UAAW,KAAI,SAAS,OAAO;;AAE1D,SAAOA,SAAO,WAAW,WAAW,IAAI;;AAEzC,KAAI,YAAY,QAAS,QAAO,MAAM,OAAO,KAAK,QAAQ,IAAI;AAC9D,KAAI,YAAY,QAAQ;AACvB,MAAI,MAAM,SAAS,GAAG;AACrB,WAAQ,OAAO,MACd,uDACA;AACD,UAAO;;AAER,MAAI,OAAO,MAAM,CAAC,iBAAiB,SAAS,OAAO,GAAqB,EAAE;AACzE,WAAQ,OAAO,MACd,uBAAuB,iBAAiB,KAAK,KAAK,CAAC,KACnD;AACD,UAAO;;AAcR,UAZe,MAAM,KAAK;GACzB;GACA,KAAK,MAAM;GACX,MAAM,OAAO;GACb,gBAAgB,OAAO;GACvB,WAAW,QAAQ,IAAI;GACvB,OAAO,CAAC,OAAO;GACf,OAAO,OAAO,cAAc,QAAQ,OAAO;GAC3C,KAAK,CAAC,OAAO;GACb,SAAS,OAAO;GAChB;GACA,CAAC,EACc,KAAK,IAAI;AACzB,SAAO;;CAER,MAAM,WAAW,aAAa,OAAO,UAAU,IAAI;AAEnD,KAAI,YAAY,QAAQ;EACvB,MAAM,QAAQ,MAAM,SAAS,OAAO;AACpC,MAAI,OAAO,MAAM;AAChB,OACC,KAAK,UAAU;IACd,eAAe;IACf,YAAY,YAAY;IACxB,YAAY,MAAM,QAAQ,IACzB,MAAM,IAAI,OAAO,UAAU;KAC1B,MAAM,EAAE,OAAO,QAAQ,GAAG,SAAS,MAAM,SAAS,KACjD,MAAM,KACN;AACD,YAAO;MACN,CACF;IACD,CAAC,CACF;AACD,UAAO;;EAER,MAAM,QAAQ,KAAK,IAAI,GAAG,MAAM,KAAK,MAAM,EAAE,KAAK,OAAO,CAAC;AAC1D,OAAK,MAAM,KAAK,MACf,SAAQ,OAAO,MAAM,GAAG,EAAE,KAAK,OAAO,MAAM,CAAC,IAAI,EAAE,QAAQ,IAAI;AAChE,SAAO;;AAER,KAAI,YAAY,OAAO;AACtB,UAAQ,OAAO,MAAM,oBAAoB,QAAQ,QAAQ,OAAO;AAChE,SAAO;;CAGR,MAAM,SAAS,OAAO,OAClB,MAAM,SAAS,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,GAC3C;AACH,KAAI,OAAO,WAAW,GAAG;AACxB,UAAQ,OAAO,MACd,+GACA;AACD,SAAO;;CAER,MAAM,SAAS,MAAM,IAAI,QAAQ;EAChC;EACA;EACA,KAAK,OAAO;EACZ,WAAW,OAAO;EAClB,OAAO,CAAC,OAAO;EACf,UAAU,OAAO;EACjB;EACA,CAAC;AACF,MAAK,MAAM,KAAK,OAAO,QAAS,KAAI,gBAAgB,IAAI;AACxD,MAAK,MAAM,KAAK,OAAO,UAAW,KAAI,gBAAgB,IAAI;AAC1D,MAAK,MAAM,KAAK,OAAO,QACtB,KAAI,gBAAgB,EAAE,2CAA2C;AAClE,KAAI,OAAO,cAAe,KAAI,gCAAgC;AAC9D,UAAS,QAAQ,KAAK,IAAI;CAC1B,MAAM,QAAQ,OAAO,WAAW,QAAQ,MAAM,CAAC,OAAO,SAAS,EAAE,KAAK,CAAC;AACvE,KAAI,MAAM,SAAS,EAClB,KAAI,8BAA8B,MAAM,KAAK,MAAM,EAAE,KAAK,CAAC,KAAK,KAAK,CAAC,GAAG;AAC1E,0BAAyB,KAAK,IAAI;CAClC,MAAM,QAAQ,OAAO,WAAW,MAAM,MAAM,OAAO,SAAS,EAAE,KAAK,CAAC;AACpE,KAAI,MACH,KACC,cAAc,MAAM,MAAM,aAAa,MAAM,KAAK,sBAAsB,SAAS,KAAK,OAAO,IAAI,IAAI,MACrG;AACF,QAAO;;AAGR,MAAM,cAAc,SACnB,QAAQ,OAAO,MACd,gBAAgB,KAAK,KAAK,KAAK,KAAK,KAAK,QAAQ,KAAK,QAAQ,EAAE,CAAC,OAAO,KAAK,QAAQ,GAAG,KACxF;;AAGF,SAAS,SAAS,QAAmB,KAAa,KAA0B;AAC3E,MAAK,MAAM,KAAK,OAAO,MACtB,KACC,KAAK,EAAE,WAAW,cAAc,eAAe,aAAa,GAAG,EAAE,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,GAAG,IAAI,EAAE,IAAI,GACxG;AACF,MAAK,MAAM,KAAK,OAAO,aACtB,KACC,gBAAgB,EAAE,KAAK,OAAO,EAAE,GAAG,iBAAiB,EAAE,IAAI,8CAA8C,EAAE,KAAK,KAC/G;AACF,KAAI,OAAO,YAAa,gBAAe,OAAO,aAAa,IAAI;CAC/D,MAAM,YAAY,OAAO,MAAM,MAAM,MAAM,EAAE,WAAW,YAAY;CACpE,MAAM,OAAO,aAAa,QAAQ,KAAK,UAAU,KAAK;AACtD,KAAI,KAAM,KAAI,KAAK,OAAO;AAC1B,KAAI,OAAO,MAAM,MAAM,MAAM,EAAE,WAAW,aAAa,IAAI,OAAO,YACjE,KACC,yEAAyE,OAAO,YAAY,KAAK,QAAQ,SAAS,MAAM,CAAC,GACzH;;AAGH,SAAS,eACR,GACA,KACC;AACD,KAAI,EAAE,WAAW,UAAW,KAAI,gBAAgB,EAAE,OAAO;UAChD,EAAE,WAAW,YAAa,KAAI,gBAAgB,EAAE,OAAO;KAE/D,KACC,gBAAgB,EAAE,KAAK,iEAAiE,EAAE,MAAM,KAAK,MAAM,OAAO,IAAI,CAAC,KAAK,KAAK,GACjI;;;AAIH,eAAe,MACd,CAAC,KAAK,GAAG,QACT,KACA,QAMA,KACkB;AAClB,KAAI,QAAQ,QAAQ;EACnB,MAAM,EAAE,qBAAW,WAAW,IAAI;AAClC,MAAI,OAAO,MAAM;AAChB,OACC,KAAK,UAAU;IACd,eAAe;IACf,YAAY,YAAY;IACxB,OAAO,OAAO,QAAQ,MAAM,CAAC,KAAK,CAAC,MAAM,WAAW;KACnD;KACA,GAAG;KACH,gBAAgBC,SAAO,QAAQ;KAC/B,EAAE;IACH,CAAC,CACF;AACD,UAAO;;AAER,OAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,MAAM,CAC/C,KACC,GAAG,KAAK,OAAO,EAAE,CAAC,IAAI,KAAK,QAAQA,SAAO,QAAQ,QAAQ,iBAAiBA,SAAO,MAAM,MAAM,KAAK,KACnG;AACF,SAAO;;AAER,KAAI,QAAQ,SAAS,MAAM,WAAW,GAAG;AACxC,UAAQ,OAAO,MACd,oDAAoD,OAAO,KAAK,MAAM,CAAC,KAAK,KAAK,CAAC,oCAClF;AACD,SAAO;;CAER,MAAM,UAAU,MAAM,QAAQ,MAAM,CAAC,MAAM,GAAG;AAC9C,KAAI,QAAQ,SAAS,GAAG;AACvB,UAAQ,OAAO,MACd,gBAAgB,QAAQ,KAAK,MAAM,IAAI,EAAE,GAAG,CAAC,KAAK,KAAK,CAAC,mCAAmC,OAAO,KAAK,MAAM,CAAC,KAAK,KAAK,CAAC,KACzH;AACD,SAAO;;CAER,MAAM,EAAE,QAAQ,UAAU,WAAW,IAAI;CACzC,MAAM,WAAW,EAAE;AACnB,MAAK,MAAM,QAAQ,MAClB,UAAS,KACR,MAAM,YAAY,MAAM;EACvB;EACA,KAAK,OAAO;EACZ,WAAW,OAAO;EAClB;EACA,CAAC,CACF;AACF,MAAK,MAAM,KAAK,SACf,KACC,KAAK,EAAE,WAAW,cAAc,eAAe,aAAa,GAAG,EAAE,KAAK,IAAI,EAAE,KAAK,GACjF;AACF,KAAI,CAAC,MAAO,KAAI,gCAAgC;CAChD,MAAM,SAAS,iBACd,KACA,QAAQ,KAAK,OAAO,OAAO,OAAO,WAAW,CAC7C;AACD,gBAAe,QAAQ,IAAI;CAC3B,MAAM,YAAY,SAAS,MAAM,MAAM,EAAE,WAAW,YAAY;CAChE,MAAM,OAAO,aAAa,QAAQ,KAAK,UAAU,KAAK;AACtD,KAAI,KAAM,KAAI,KAAK,OAAO;AAC1B,KACC,yEAAyE,OAAO,KAAK,QAAQ,SAAS,MAAM,CAAC,GAC7G;AACD,QAAO;;AAGR,SAAS,QAAQ,QAAoB,KAAa,KAA0B;CAC3E,MAAM,KAAK,UAAU,KAAK,OAAO,KAAK;AACtC,MAAK,MAAM,KAAK,OAAO,QAAS,KAAI,gBAAgB,IAAI;AACxD,MAAK,MAAM,KAAK,OAAO,OACtB,KAAI,gBAAgB,EAAE,yBAAyB;AAChD,MAAK,MAAM,KAAK,OAAO,UAAW,KAAI,gBAAgB,IAAI;AAC1D,MAAK,MAAM,KAAK,OAAO,MACtB,KACC,KAAK,EAAE,WAAW,cAAc,eAAe,aAAa,GAAG,EAAE,KAAK,IAAI,EAAE,KAAK,GACjF;AACF,gBAAe,OAAO,aAAa,IAAI;AACvC,KAAI,OAAO,QAAQ,cAClB,KAAI,wCAAwC;AAC7C,KAAI,OAAO,QAAQ,cAClB,KAAI,6CAA6C;AAClD,KAAI,OAAO,QAAQ,MAClB,KACC,uIACA;UACO,OAAO,IACf,KAAI,mEAAmE;CACxE,MAAM,QAAQ;EACb,GAAI,OAAO,MAAM,EAAE,GAAG,CAAC,MAAM,KAAK,KAAK,GAAG,GAAG,KAAK,UAAU,GAAG,GAAG,KAAK;EACvE,GAAI,OAAO,YAAY,EAAE,GAAG,CAAC,GAAG,OAAO,eAAe,UAAU;EAChE,GAAG,OAAO,UAAU,SAAS,CAAC;EAC9B;AACD,KACC,KAAK,OAAO,KAAK,oBAAoB,MAAM,KAAK,MAAM,KAAK,IAAI,CAAC,KAAK,KAAK,GAC1E;AACD,KACC,qFACA;AACD,KACC,4GAA4G,aAAa,gEACzH;;;AAIF,SAAS,yBAAyB,KAAa,KAA0B;AACxE,KAAI;EACH,MAAM,MAAM,KAAK,MAAM,aAAa,GAAG,IAAI,gBAAgB,OAAO,CAAC;AAInE,MAAI,CAAC,IAAI,cAAc,eAAe,CAAC,IAAI,iBAAiB,YAC3D,KACC,4EACA;SACK;;AAKT,KAAK,QAAQ,KAAK,MAAM,EAAE,CAAC,CAAC,MAC1B,SAAS,QAAQ,KAAK,KAAK,GAC3B,UAAmB;AACnB,SAAQ,OAAO,MACd,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,CAAC,IACvE;AACD,SAAQ,KAAK,EAAE;EAEhB"}
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":["path","fonts","path","path","report","config"],"sources":["../src/cli/config.ts","../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 * `framefields.json` at the project root: where installed components live,\n * and which fonts `framefields add` / `framefields fonts add` installed.\n */\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport const CONFIG_FILE = \"framefields.json\";\n\nexport interface ProjectConfig {\n\t/** Components directory, relative to the project root. */\n\tcomponents: string;\n\t/**\n\t * Font files by role (`emoji`), relative to the project root. A role\n\t * set here counts as installed: point it at your own font to use that.\n\t */\n\tfonts?: Partial<Record<string, string>>;\n}\n\n/** The project's config, or the default it would get: `src/components` when there is a `src`. */\nexport function readConfig(cwd: string): {\n\tconfig: ProjectConfig;\n\tsaved: boolean;\n} {\n\tconst file = join(cwd, CONFIG_FILE);\n\tif (existsSync(file)) {\n\t\tconst config = JSON.parse(\n\t\t\treadFileSync(file, \"utf8\"),\n\t\t) as Partial<ProjectConfig>;\n\t\tif (typeof config.components !== \"string\")\n\t\t\tthrow new Error(`${CONFIG_FILE}: \"components\" must be a directory path`);\n\t\tif (\n\t\t\tconfig.fonts !== undefined &&\n\t\t\t(typeof config.fonts !== \"object\" ||\n\t\t\t\tObject.values(config.fonts).some((v) => typeof v !== \"string\"))\n\t\t)\n\t\t\tthrow new Error(\n\t\t\t\t`${CONFIG_FILE}: \"fonts\" must map roles to font file paths, e.g. { \"emoji\": \"assets/fonts/NotoColorEmoji.ttf\" }`,\n\t\t\t);\n\t\treturn { config: config as ProjectConfig, saved: true };\n\t}\n\tconst components = existsSync(join(cwd, \"src\"))\n\t\t? \"src/components\"\n\t\t: \"components\";\n\treturn { config: { components }, saved: false };\n}\n\nexport function writeConfig(cwd: string, config: ProjectConfig): void {\n\twriteFileSync(\n\t\tjoin(cwd, CONFIG_FILE),\n\t\t`${JSON.stringify(config, null, \"\\t\")}\\n`,\n\t);\n}\n","/**\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, { 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 */\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 src/film.ts --json\",\n\t\"check:render\":\n\t\t\"tsc --noEmit -p . && framefields check src/film.ts --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 src/film.ts --cloud --workers auto\",\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- \\`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 { 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\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, then fonts (recorded there) and their module.\n\tconst { config, saved } = readConfig(root);\n\tif (!saved) {\n\t\twriteConfig(root, config);\n\t\treport.written.push(\"framefields.json\");\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 <entry> --cloud`: renders the project on\n * api.framefields.dev and downloads the video. Prints one plain line per\n * phase, and a progress line at most every 10 seconds while frames render.\n */\nimport path from \"node:path\";\nimport {\n\tCloudRenderError,\n\ttype CloudRenderOptions,\n\ttype CloudRenderStatus,\n\trenderCloud,\n} from \"../cloud/index.js\";\n\nexport interface CloudCliOptions {\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}\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 workers = parseWorkers(o.workers);\n\tif (workers === undefined) {\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 codec = (o.codec ?? \"h264\") as \"h264\" | \"vp9\";\n\tconst outputPath =\n\t\to.output ??\n\t\tpath.join(\n\t\t\t\"output\",\n\t\t\t`${path.basename(o.entry).replace(/\\.[^.]+$/, \"\")}.${codec === \"vp9\" ? \"webm\" : \"mp4\"}`,\n\t\t);\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\tentry: o.entry,\n\t\t\texport: o.export,\n\t\t\tselect: o.select,\n\t\t\tworkers: o.plan && workers === 1 ? \"auto\" : workers,\n\t\t\tmaxWorkers: o.maxWorkers ? Number(o.maxWorkers) : undefined,\n\t\t\tcodec,\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\tlog(\n\t\t\t\t`Render it: framefields render ${o.entry} --cloud --workers ${o.workers ?? \"auto\"}`,\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\nfunction parseWorkers(value: string | undefined): number | \"auto\" | undefined {\n\tif (value === undefined) return 1;\n\tif (value === \"auto\") return \"auto\";\n\tconst n = Number(value);\n\treturn Number.isInteger(n) && n >= 1 ? n : undefined;\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 render <entry> --cloud render on api.framefields.dev\n */\nimport { readFileSync } from \"node:fs\";\nimport { 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 <entry> Build, validate and lint a composition; --render also writes a\n representative frame and grid. --export defaults to buildFilm.\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 render <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. --export defaults to buildFilm.\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/<entry>.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 src/film.ts --cloud --workers auto --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\") {\n\t\tif (names.length !== 1) {\n\t\t\tprocess.stderr.write(\n\t\t\t\t\"Usage: framefields check <entry> [--export buildFilm] [--render] [--json]\\n\",\n\t\t\t);\n\t\t\treturn 2;\n\t\t}\n\t\tconst report = await runCheck({\n\t\t\tentry: names[0],\n\t\t\texportName: values.export,\n\t\t\trender: values.render,\n\t\t\toutputDir: values.output,\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\tif (values.json) log(JSON.stringify(report));\n\t\telse {\n\t\t\tlog(`Check ${report.status}: ${report.entry} (${report.exportName})`);\n\t\t\tfor (const d of report.diagnostics)\n\t\t\t\tlog(\n\t\t\t\t\t`${d.severity} ${d.code}${d.path ? ` at ${d.path}` : \"\"}: ${d.message}`,\n\t\t\t\t);\n\t\t\tfor (const file of report.artifacts) log(`Wrote ${file}`);\n\t\t}\n\t\treturn report.status === \"passed\" ? 0 : 1;\n\t}\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 <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. */\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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"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
//#region src/cloud/git-source.d.ts
|
|
2
|
+
interface CloudSource {
|
|
3
|
+
repo: string;
|
|
4
|
+
ref?: string;
|
|
5
|
+
commit?: string;
|
|
6
|
+
/** The project's folder inside the repo (monorepos), `.` at the root. */
|
|
7
|
+
workdir?: string;
|
|
8
|
+
}
|
|
9
|
+
interface ResolvedSource {
|
|
10
|
+
source: CloudSource;
|
|
11
|
+
/** The entry relative to `source.workdir`, as the worker loads it. */
|
|
12
|
+
entry: string;
|
|
13
|
+
/** Things that render differently than the user may expect (uncommitted changes). */
|
|
14
|
+
warnings: string[];
|
|
15
|
+
}
|
|
16
|
+
/** Reads repo, branch, commit and folder from git, and checks the commit is pushed. */
|
|
17
|
+
declare function resolveGitSource(cwd: string, entry: string): ResolvedSource;
|
|
18
|
+
/** `git@github.com:acme/films.git` → `https://github.com/acme/films.git`; credentials dropped. */
|
|
19
|
+
declare function toHttps(url: string): string;
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/cloud/index.d.ts
|
|
22
|
+
declare const FRAMEFIELDS_API_URL = "https://api.framefields.dev";
|
|
23
|
+
interface CloudRenderOptions {
|
|
24
|
+
/** The module that builds the composition, relative to `cwd`. */
|
|
25
|
+
entry: string;
|
|
26
|
+
/** Its export: a Composition, or a function returning one. Default `buildFilm`. */
|
|
27
|
+
export?: string;
|
|
28
|
+
/** Passed to the export when it is a function. */
|
|
29
|
+
args?: unknown;
|
|
30
|
+
/** When the export returns several compositions, the one to render. */
|
|
31
|
+
select?: string;
|
|
32
|
+
/** 1 (default) renders on one worker; a number or "auto" splits the film. */
|
|
33
|
+
workers?: number | "auto";
|
|
34
|
+
/** Upper bound for "auto" (the API caps it too). */
|
|
35
|
+
maxWorkers?: number;
|
|
36
|
+
codec?: "h264" | "vp9";
|
|
37
|
+
quality?: string;
|
|
38
|
+
/** Probe and plan only: returns the plan and estimated cost, renders nothing. */
|
|
39
|
+
dryRun?: boolean;
|
|
40
|
+
/** Download the finished video here. */
|
|
41
|
+
outputPath?: string;
|
|
42
|
+
/** Project folder. Default `process.cwd()`. */
|
|
43
|
+
cwd?: string;
|
|
44
|
+
/** Instead of reading repo, branch and commit from git. */
|
|
45
|
+
source?: CloudSource;
|
|
46
|
+
/** Default `process.env.FRAMEFIELDS_API_KEY`. */
|
|
47
|
+
apiKey?: string;
|
|
48
|
+
/** Default `process.env.FRAMEFIELDS_API_URL`, else https://api.framefields.dev. */
|
|
49
|
+
apiUrl?: string;
|
|
50
|
+
/** Called with every status poll. */
|
|
51
|
+
onProgress?: (status: CloudRenderStatus) => void;
|
|
52
|
+
/** Called for each warning (uncommitted changes). Default: stderr. */
|
|
53
|
+
onWarning?: (message: string) => void;
|
|
54
|
+
/** Aborting cancels the cloud render. */
|
|
55
|
+
signal?: AbortSignal;
|
|
56
|
+
/** Status poll interval, ms. Default 3000. */
|
|
57
|
+
pollMs?: number;
|
|
58
|
+
}
|
|
59
|
+
type CloudRenderPhase = "probing" | "holding" | "rendering" | "stitching" | "planned" | "completed" | "failed" | "cancelled";
|
|
60
|
+
interface CloudRenderPlan {
|
|
61
|
+
workers: number;
|
|
62
|
+
/** Render time of the whole film on one GPU, seconds. */
|
|
63
|
+
workSec: number;
|
|
64
|
+
/** Expected wall time with this plan, seconds. */
|
|
65
|
+
etaSec: number;
|
|
66
|
+
chunks: {
|
|
67
|
+
start: number;
|
|
68
|
+
end: number;
|
|
69
|
+
workSec: number;
|
|
70
|
+
}[];
|
|
71
|
+
}
|
|
72
|
+
interface CloudRenderStatus {
|
|
73
|
+
id: string;
|
|
74
|
+
status: CloudRenderPhase;
|
|
75
|
+
workers: number;
|
|
76
|
+
plan?: CloudRenderPlan;
|
|
77
|
+
progress: {
|
|
78
|
+
frames: number;
|
|
79
|
+
totalFrames: number | null;
|
|
80
|
+
etaSec: number | null;
|
|
81
|
+
};
|
|
82
|
+
/** Charged so far (final once the render ended), USD. */
|
|
83
|
+
costUsd: number;
|
|
84
|
+
gpuSeconds: number;
|
|
85
|
+
/** The planned render's estimated charge, USD. */
|
|
86
|
+
estimateUsd?: number;
|
|
87
|
+
/** The commit rendered. */
|
|
88
|
+
sha?: string;
|
|
89
|
+
output?: {
|
|
90
|
+
url: string;
|
|
91
|
+
bytes?: number;
|
|
92
|
+
};
|
|
93
|
+
error?: {
|
|
94
|
+
code: string;
|
|
95
|
+
message: string;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
interface CloudRenderResult extends CloudRenderStatus {
|
|
99
|
+
/** Where the video was downloaded (`outputPath`). */
|
|
100
|
+
filePath?: string;
|
|
101
|
+
}
|
|
102
|
+
/** A cloud render that failed, was cancelled, or was refused by the API. */
|
|
103
|
+
declare class CloudRenderError extends Error {
|
|
104
|
+
readonly code: string;
|
|
105
|
+
readonly status?: CloudRenderStatus | undefined;
|
|
106
|
+
constructor(message: string, code: string, status?: CloudRenderStatus | undefined);
|
|
107
|
+
}
|
|
108
|
+
/** Starts a cloud render and waits for it; resolves when it completed (or was planned). */
|
|
109
|
+
declare function renderCloud(options: CloudRenderOptions): Promise<CloudRenderResult>;
|
|
110
|
+
/** The API calls behind `renderCloud`, for callers who track renders themselves. */
|
|
111
|
+
declare function cloudClient(options: Pick<CloudRenderOptions, "apiKey" | "apiUrl">): {
|
|
112
|
+
start: (body: unknown) => Promise<CloudRenderStatus>;
|
|
113
|
+
status: (id: string) => Promise<CloudRenderStatus>;
|
|
114
|
+
cancel: (id: string) => Promise<CloudRenderStatus>;
|
|
115
|
+
};
|
|
116
|
+
//#endregion
|
|
117
|
+
export { CloudRenderError, CloudRenderOptions, CloudRenderPhase, CloudRenderPlan, CloudRenderResult, CloudRenderStatus, type CloudSource, FRAMEFIELDS_API_URL, cloudClient, renderCloud, resolveGitSource, toHttps };
|
|
118
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +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;ECaJ,MAAA,EDZJ,WCYI;EAEI;EAsBP,KAAA,EAAA,MAAA;EAMa;EAIb,QAAA,EAAA,MAAA,EAAA;;AAKV;AAUiB,iBDrDD,gBAAA,CCqDgB,GAAA,EAAA,MAAA,EAAA,KAAA,EAAA,MAAA,CAAA,EDrD8B,cCqD9B;AAShC;AAqBiB,iBDPD,OAAA,CCOmB,GAAA,EAAQ,MAAA,CAAA,EAAA,MAAA;;;AD5F1B,cCaJ,mBAAA,GDZJ,6BAAW;AAQJ,UCMC,kBAAA,CDN6C;EA4E9C;;;;ECxEH;EAEI,IAAA,CAAA,EAAA,OAAA;EAsBP;EAMa,MAAA,CAAA,EAAA,MAAA;EAIb;EAAW,OAAA,CAAA,EAAA,MAAA,GAAA,MAAA;EAKT;EAUK,UAAA,CAAA,EAAA,MAAe;EASf,KAAA,CAAA,EAAA,MAAA,GAAA,KAAiB;EAqBjB,OAAA,CAAA,EAAA,MAAA;EAMJ;EAIO,MAAA,CAAA,EAAA,OAAA;EAAA;EAJkB,UAAA,CAAA,EAAA,MAAA;EAAK;EAmBrB,GAAA,CAAA,EAAA,MAAA;EACZ;EACC,MAAA,CAAA,EAlFD,WAkFC;EAAR;EAAO,MAAA,CAAA,EAAA,MAAA;EA+DM;EACD,MAAA,CAAA,EAAA,MAAA;EAAL;EAkCa,UAAA,CAAA,EAAA,CAAA,MAAA,EA9KA,iBA8KA,EAAA,GAAA,IAAA;EAAA;EACF,SAAA,CAAA,EAAA,CAAA,OAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EAAA;EACA,MAAA,CAAA,EA5KX,WA4KW;EAAA;EAAA,MAAA,CAAA,EAAA,MAAA;;KAvKT,gBAAA;UAUK,eAAA;;;;;;;;;;;;UASA,iBAAA;;UAER;;SAED;;;;;;;;;;;;;;;;;;;;;;UAiBS,iBAAA,SAA0B;;;;;cAM9B,gBAAA,SAAyB,KAAA;;oBAIlB;sDAAA;;;iBAeE,WAAA,UACZ,qBACP,QAAQ;;iBA+DK,WAAA,UACN,KAAK;4BAkCQ,QAAA;0BACF,QAAA;0BACA,QAAA"}
|