#!/usr/bin/env node import fs from 'fs'; import zlib from 'zlib'; import path from 'path'; import { fileURLToPath } from 'url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const dir = path.join(__dirname, '..', 'public', 'icons'); fs.mkdirSync(dir, { recursive: true }); function crc32(data) { let crc = 0xffffffff; const table = new Int32Array(256); for (let i = 0; i < 256; i++) { let c = i; for (let j = 0; j < 8; j++) c = (c & 1) ? (0xedb88320 ^ (c >>> 1)) : (c >>> 1); table[i] = c; } for (let i = 0; i < data.length; i++) crc = table[(crc ^ data[i]) & 0xff] ^ (crc >>> 8); return (crc ^ 0xffffffff) >>> 0; } function chunk(type, data) { const len = Buffer.alloc(4); len.writeUInt32BE(data.length); const typeData = Buffer.concat([Buffer.from(type), data]); const crcBuf = Buffer.alloc(4); crcBuf.writeUInt32BE(crc32(typeData)); return Buffer.concat([len, typeData, crcBuf]); } function makePNG(w, h) { const rowBytes = 1 + w * 3; const buf = Buffer.alloc(rowBytes * h); const cx = w / 2, cy = h / 2; const outerR = Math.min(w, h) / 2 - 2; const innerR = outerR * 0.65; let offset = 0; for (let y = 0; y < h; y++) { buf[offset++] = 0; // filter none for (let x = 0; x < w; x++) { const dx = x - cx, dy = y - cy; const dist = Math.sqrt(dx * dx + dy * dy); if (dist <= outerR && dist >= innerR) { buf[offset++] = 90; buf[offset++] = 140; buf[offset++] = 255; } else { buf[offset++] = 6; buf[offset++] = 7; buf[offset++] = 10; } } } const compressed = zlib.deflateSync(buf.slice(0, offset)); const ihdr = Buffer.alloc(13); ihdr.writeUInt32BE(w, 0); ihdr.writeUInt32BE(h, 4); ihdr[8] = 8; ihdr[9] = 2; return Buffer.concat([ Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]), chunk('IHDR', ihdr), chunk('IDAT', compressed), chunk('IEND', Buffer.alloc(0)) ]); } const icons = [ [192, 'icon-192.png'], [512, 'icon-512.png'], [512, 'icon-512-maskable.png'], [180, 'apple-touch-icon.png'], ]; for (const [size, name] of icons) { const png = makePNG(size, size); fs.writeFileSync(path.join(dir, name), png); console.log(`Created ${name} (${png.length} bytes)`); } console.log('Done!');