// Regenerate every raster icon asset from the SVG sources (dev-time only). // bun scripts/gen-icons.ts // Produces: assets/icon.png (1024), assets/icon.iconset/* (macOS app icon), // assets/icon.ico (Windows), assets/tray/tray-44-template.png (macOS tray), // assets/tray/tray-32-color.png (Windows tray). import { mkdir } from "node:fs/promises"; import path from "node:path"; import { Resvg } from "@resvg/resvg-js"; import pngToIco from "png-to-ico"; const root = path.join(import.meta.dir, ".."); const assets = path.join(root, "assets"); function renderPng(svg: string, sizePx: number): Uint8Array { const resvg = new Resvg(svg, { fitTo: { mode: "width", value: sizePx } }); return resvg.render().asPng(); } async function writePng(file: string, svg: string, sizePx: number): Promise { await mkdir(path.dirname(file), { recursive: true }); await Bun.write(file, renderPng(svg, sizePx)); } // ---- app icon: iconset rendered per size (crisper than downscaling) ---- const logo = await Bun.file(path.join(assets, "logo.svg")).text(); await writePng(path.join(assets, "icon.png"), logo, 1024); for (const size of [16, 32, 128, 256, 512]) { await writePng(path.join(assets, "icon.iconset", `icon_${size}x${size}.png`), logo, size); await writePng(path.join(assets, "icon.iconset", `icon_${size}x${size}@2x.png`), logo, size * 2); } // ---- Windows app icon (.ico: 16/32/48/256, used by installer + taskbar) ---- const icoPngs = [16, 32, 48, 256].map((size) => Buffer.from(renderPng(logo, size))); await Bun.write(path.join(assets, "icon.ico"), await pngToIco(icoPngs)); // ---- tray: macOS 22pt template @2x; Windows small colored icon ---- const trayGlyph = await Bun.file(path.join(assets, "tray", "tray-glyph.svg")).text(); await writePng(path.join(assets, "tray", "tray-44-template.png"), trayGlyph, 44); await writePng(path.join(assets, "tray", "tray-32-color.png"), logo, 32); console.log("icons regenerated: app iconset + icon.ico + tray images");