// Minimal PNG generator — run before build to create icon files const { writeFileSync, mkdirSync } = require('fs') function crc32(buf) { const table = new Int32Array(256) for (let i = 0; i < 256; i++) { let c = i for (let k = 0; k < 8; k++) c = (c & 1) ? (0xedb88320 ^ (c >>> 1)) : (c >>> 1) table[i] = c } let crc = -1 for (let i = 0; i < buf.length; i++) crc = table[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8) return crc ^ -1 } function pngChunk(type, data) { const len = data.length const chunk = new Uint8Array(4 + 4 + len + 4) const view = new DataView(chunk.buffer) view.setUint32(0, len, false) chunk.set(new TextEncoder().encode(type), 4) chunk.set(data, 8) const crc = crc32(chunk.slice(4, 8 + len)) view.setUint32(8 + len, crc, false) return chunk } function generatePNG(size, color) { const header = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]) const ihdr = new Uint8Array(13) const v = new DataView(ihdr.buffer) v.setUint32(0, size, false) v.setUint32(4, size, false) v.setUint8(8, 8) v.setUint8(9, 2) v.setUint8(10, 0) v.setUint8(11, 0) v.setUint8(12, 0) const rowLen = 1 + size * 3 const raw = new Uint8Array(size * rowLen) for (let y = 0; y < size; y++) { raw[y * rowLen] = 0 for (let x = 0; x < size; x++) { const off = y * rowLen + 1 + x * 3 raw[off] = color[0] raw[off + 1] = color[1] raw[off + 2] = color[2] } } const compressed = new Uint8Array(require('zlib').deflateSync(raw)) const idat = pngChunk('IDAT', compressed) const iend = pngChunk('IEND', new Uint8Array(0)) const out = new Uint8Array(header.length + 4 + 4 + 13 + 4 + idat.length + iend.length) let p = 0 out.set(header, p); p += header.length out.set(pngChunk('IHDR', ihdr), p); p += 4 + 4 + 13 + 4 out.set(idat, p); p += idat.length out.set(iend, p) return out } mkdirSync('icons', { recursive: true }) const teal = [0, 180, 170] writeFileSync('icons/icon16.png', generatePNG(16, teal)) writeFileSync('icons/icon48.png', generatePNG(48, teal)) writeFileSync('icons/icon128.png', generatePNG(128, teal)) console.log('Icons generated')