// Packs one or more emitted sections into a self-contained bundle for use_figma. // // node scripts/figma-pack.mjs [ ...] // // figma-emit writes payloads that index into one page-wide table set (~18KB). The // builder runs inside Figma, so every byte of that table has to be typed into a // tool call. Most of it is irrelevant to any single section, so this rewrites the // indices against a table containing only the entries the chosen sections // actually reference, and prints the bundle to stdout. import fs from "node:fs"; import path from "node:path"; const OUT = process.argv[2] || "figma-extract/w1648"; const WANT = process.argv.slice(3); const PAY = path.join(OUT, "payload"); const tables = JSON.parse(fs.readFileSync(path.join(PAY, "tables.json"), "utf8")); const files = fs.readdirSync(PAY).filter((f) => /^\d\d-/.test(f)); const picked = WANT.length ? WANT.map((w) => { const nn = String(w).padStart(2, "0"); const hit = files.find((f) => f.startsWith(nn + "-")); if (!hit) throw new Error("no payload for section " + nn); return hit; }) : files; // Collect the table entries these sections touch, in first-use order. const used = { fill: new Map(), stroke: new Map(), layout: new Map(), type: new Map(), color: new Map() }; const take = (kind, idx) => { if (idx == null) return null; if (!used[kind].has(idx)) used[kind].set(idx, used[kind].size); return used[kind].get(idx); }; const remap = (n) => { if (n.f != null) n.f = take("fill", n.f); if (n.s != null && n.t !== "T") n.s = take("stroke", n.s); if (n.L != null) n.L = take("layout", n.L); if (n.ty != null) n.ty = take("type", n.ty); if (n.c != null) n.c = take("color", n.c); for (const r of n.rn || []) { if (r.ty != null) r.ty = take("type", r.ty); if (r.c != null) r.c = take("color", r.c); } (n.ch || []).forEach(remap); (n.abs || []).forEach(remap); return n; }; const sections = picked.map((f) => remap(JSON.parse(fs.readFileSync(path.join(PAY, f), "utf8")))); const packed = {}; for (const k of Object.keys(used)) { packed[k] = [...used[k].keys()].map((orig) => tables[k][orig]); } const bundle = { T: packed, sections }; const json = JSON.stringify(bundle); const outFile = path.join(OUT, "bundle-" + picked.map((f) => f.slice(0, 2)).join("-") + ".json"); fs.writeFileSync(outFile, json); console.error( JSON.stringify({ file: outFile, sections: picked, bytes: json.length, tableSizes: Object.fromEntries(Object.keys(packed).map((k) => [k, packed[k].length])), }, null, 1), );