// Generate PWA icons const fs = require('fs'); const path = require('path'); const sizes = [192, 512]; async function main() { try { const sharp = require('sharp'); for (const size of sizes) { const svg = ` M `; await sharp(Buffer.from(svg)).png().toFile(path.join(__dirname, '..', 'public', `icon-${size}.png`)); console.log(`Created icon-${size}.png`); } } catch { // sharp not available, create minimal valid PNG manually console.log('sharp not available, creating minimal PNGs'); // Minimal 1x1 blue PNG for (const size of [192, 512]) { // Create a minimal valid PNG - will just be a solid blue square // PNG signature const sig = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]); // IHDR chunk const ihdrData = Buffer.alloc(13); ihdrData.writeUInt32BE(size, 0); // width ihdrData.writeUInt32BE(size, 4); // height ihdrData[8] = 8; // bit depth ihdrData[9] = 2; // color type (RGB) ihdrData[10] = 0; // compression ihdrData[11] = 0; // filter ihdrData[12] = 0; // interlace const ihdrLen = Buffer.alloc(4); ihdrLen.writeUInt32BE(13); const ihdrType = Buffer.from('IHDR'); const ihdrCRC = crc32(Buffer.concat([ihdrType, ihdrData])); const ihdrCRCbuf = Buffer.alloc(4); ihdrCRCbuf.writeUInt32BE(ihdrCRC); // IDAT - raw filtered image data (each row: filter byte 0 + RGB pixels) const rowSize = 1 + size * 3; // filter byte + RGB per pixel const rawData = Buffer.alloc(rowSize * size); for (let y = 0; y < size; y++) { rawData[y * rowSize] = 0; // no filter for (let x = 0; x < size; x++) { const offset = y * rowSize + 1 + x * 3; rawData[offset] = 8; // R rawData[offset+1] = 145; // G rawData[offset+2] = 178; // B } } // Zlib compress const zlib = require('zlib'); const compressed = zlib.deflateSync(rawData); const idatLen = Buffer.alloc(4); idatLen.writeUInt32BE(compressed.length); const idatType = Buffer.from('IDAT'); const idatCRC = crc32(Buffer.concat([idatType, compressed])); const idatCRCbuf = Buffer.alloc(4); idatCRCbuf.writeUInt32BE(idatCRC); // IEND const iendLen = Buffer.alloc(4); iendLen.writeUInt32BE(0); const iendType = Buffer.from('IEND'); const iendCRC = crc32(iendType); const iendCRCbuf = Buffer.alloc(4); iendCRCbuf.writeUInt32BE(iendCRC); const png = Buffer.concat([ sig, ihdrLen, ihdrType, ihdrData, ihdrCRCbuf, idatLen, idatType, compressed, idatCRCbuf, iendLen, iendType, iendCRCbuf ]); fs.writeFileSync(path.join(__dirname, '..', 'public', `icon-${size}.png`), png); console.log(`Created icon-${size}.png (minimal)`); } } } function crc32(buf) { let crc = 0xFFFFFFFF; const table = new Uint32Array(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 < buf.length; i++) { crc = table[(crc ^ buf[i]) & 0xFF] ^ (crc >>> 8); } return (crc ^ 0xFFFFFFFF) >>> 0; } main();