Files

88 lines
3.1 KiB
JavaScript

#!/usr/bin/env node
/**
* Generates minimal placeholder icons for all platforms.
* Creates a simple app icon: purple gradient on transparent.
* Outputs: assets/icon.png (1024x1024)
* Uses pure Node.js — no dependencies.
*/
const { writeFileSync, mkdirSync } = require('fs');
const { join } = require('path');
const { createCanvas } = (() => {
// Minimal PNG encoder — no canvas library needed
class Canvas {
constructor(w, h) { this.w = w; this.h = h; this.pixels = Buffer.alloc(w * h * 4, 0); }
fillRect(x, y, w, h, r, g, b, a) {
for (let py = y; py < y + h; py++) {
for (let px = x; px < x + w; px++) {
const i = (py * this.w + px) * 4;
this.pixels[i] = r; this.pixels[i+1] = g; this.pixels[i+2] = b; this.pixels[i+3] = a;
}
}
}
fillCircle(cx, cy, rad, r, g, b, a) {
for (let py = cy - rad; py <= cy + rad; py++) {
for (let px = cx - rad; px <= cx + rad; px++) {
if ((px-cx)**2 + (py-cy)**2 <= rad*rad) {
const i = (py * this.w + px) * 4;
if (i >= 0 && i < this.pixels.length) {
this.pixels[i] = r; this.pixels[i+1] = g; this.pixels[i+2] = b; this.pixels[i+3] = a;
}
}
}
}
}
toPNG() {
const { w, h, pixels } = this;
const data = [];
// PNG signature
data.push(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]));
// IHDR chunk
const ihdr = Buffer.alloc(13);
ihdr.writeUInt32BE(w, 0); ihdr.writeUInt32BE(h, 4);
ihdr[8] = 8; // bit depth
ihdr[9] = 6; // color type RGBA
data.push(this._chunk('IHDR', ihdr));
// IDAT chunk (raw pixel data with filter bytes)
const raw = Buffer.alloc(h * (1 + w * 4));
for (let y = 0; y < h; y++) {
raw[y * (1 + w * 4)] = 0; // no filter
pixels.copy(raw, y * (1 + w * 4) + 1, y * w * 4, (y + 1) * w * 4);
}
const zlib = require('zlib');
const compressed = zlib.deflateSync(raw);
data.push(this._chunk('IDAT', compressed));
// IEND chunk
data.push(this._chunk('IEND', Buffer.alloc(0)));
return Buffer.concat(data);
}
_chunk(type, buf) {
const len = Buffer.alloc(4); len.writeUInt32BE(buf.length);
const typeB = Buffer.from(type, 'ascii');
const crcData = Buffer.concat([typeB, buf]);
const crc = require('zlib').crc32(crcData);
const crcB = Buffer.alloc(4); crcB.writeUInt32BE(crc >>> 0);
return Buffer.concat([len, typeB, buf, crcB]);
}
}
return { createCanvas: (w, h) => new Canvas(w, h) };
})();
const SIZE = 1024;
const canvas = createCanvas(SIZE, SIZE);
const c = SIZE / 2;
const r = SIZE * 0.42;
// Background circle
canvas.fillCircle(c, c, r, 108, 99, 255, 255);
// Inner circle (slightly darker)
canvas.fillCircle(c, c, r * 0.7, 90, 80, 220, 255);
// Letter "O" representation — two circles to make a ring
canvas.fillCircle(c, c, r * 0.5, 108, 99, 255, 255);
canvas.fillCircle(c, c, r * 0.3, 90, 80, 220, 255);
const outDir = join(__dirname, '..', 'assets');
mkdirSync(outDir, { recursive: true });
writeFileSync(join(outDir, 'icon.png'), canvas.toPNG());
console.log('Generated assets/icon.png');