// Renders ui/icon.svg into the desktop app's icons: desktop/icons/icon.png (512 px, // for Linux and the window) and desktop/icons/icon.ico (16-256 px, PNG-compressed // entries, for Windows). Run with Electron, which brings its own renderer: // npx electron scripts/make-icons.cjs const { app, BrowserWindow } = require('electron'); const fs = require('node:fs'); const path = require('node:path'); const root = path.join(__dirname, '..'); const svg = fs.readFileSync(path.join(root, 'ui', 'icon.svg'), 'utf8'); const out = path.join(root, 'desktop', 'icons'); app.disableHardwareAcceleration(); app.on('window-all-closed', () => {}); app.whenReady().then(async () => { // The page draws the SVG on a canvas at each size and hands back a PNG. const win = new BrowserWindow({ show: false, webPreferences: { offscreen: true } }); await win.loadURL('data:text/html,'); const src = `data:image/svg+xml;base64,${Buffer.from(svg).toString('base64')}`; const render = async (size) => { const url = await win.webContents.executeJavaScript(`new Promise((ok, fail) => { const img = new Image(); img.onerror = () => fail(new Error('svg did not load')); img.onload = () => { const c = document.createElement('canvas'); c.width = c.height = ${size}; const g = c.getContext('2d'); g.imageSmoothingQuality = 'high'; g.drawImage(img, 0, 0, ${size}, ${size}); ok(c.toDataURL('image/png')); }; img.src = ${JSON.stringify(src)}; })`); return Buffer.from(url.split(',')[1], 'base64'); }; fs.mkdirSync(out, { recursive: true }); fs.writeFileSync(path.join(out, 'icon.png'), await render(512)); const sizes = [16, 24, 32, 48, 64, 128, 256]; const pngs = []; for (const s of sizes) pngs.push(await render(s)); const header = Buffer.alloc(6); header.writeUInt16LE(0, 0); header.writeUInt16LE(1, 2); header.writeUInt16LE(sizes.length, 4); const dir = Buffer.alloc(16 * sizes.length); let offset = 6 + dir.length; sizes.forEach((s, i) => { const e = i * 16; dir.writeUInt8(s >= 256 ? 0 : s, e); dir.writeUInt8(s >= 256 ? 0 : s, e + 1); dir.writeUInt8(0, e + 2); dir.writeUInt8(0, e + 3); dir.writeUInt16LE(1, e + 4); dir.writeUInt16LE(32, e + 6); dir.writeUInt32LE(pngs[i].length, e + 8); dir.writeUInt32LE(offset, e + 12); offset += pngs[i].length; }); fs.writeFileSync(path.join(out, 'icon.ico'), Buffer.concat([header, dir, ...pngs])); win.destroy(); console.log('icons written to', out); app.quit(); }).catch((e) => { console.error(e); app.exit(1); });