* Generates app-icon.png (1024x1024) — the source for `bunx tauri icon`.
* Rendered procedurally so the mark is reproducible without design assets:
* an amber badge holding a lens ring with a check mark inside.
*/
import { deflateSync } from "node:zlib";
import { writeFileSync } from "node:fs";
const SIZE = 1024;
const AMBER = [245, 158, 11];
const WHITE = [255, 255, 255];
const SAMPLES = 3;
const roundRect = (x, y) => {
const radius = SIZE * 0.22;
const min = radius;
const max = SIZE - radius;
const cx = Math.min(Math.max(x, min), max);
const cy = Math.min(Math.max(y, min), max);
return Math.hypot(x - cx, y - cy) <= radius;
};
const ring = (x, y) => {
const distance = Math.hypot(x - SIZE * 0.5, y - SIZE * 0.44);
const radius = SIZE * 0.245;
const thickness = SIZE * 0.072;
return Math.abs(distance - radius) <= thickness / 2;
};
const segment = (x, y, [x1, y1], [x2, y2], thickness) => {
const a = [x1 * SIZE, y1 * SIZE];
const b = [x2 * SIZE, y2 * SIZE];
const dx = b[0] - a[0];
const dy = b[1] - a[1];
const lengthSquared = dx * dx + dy * dy;
const t = Math.min(Math.max(((x - a[0]) * dx + (y - a[1]) * dy) / lengthSquared, 0), 1);
return Math.hypot(x - (a[0] + t * dx), y - (a[1] + t * dy)) <= thickness / 2;
};
const check = (x, y) => {
const thickness = SIZE * 0.062;
return (
segment(x, y, [0.405, 0.445], [0.478, 0.53], thickness) ||
segment(x, y, [0.478, 0.53], [0.605, 0.352], thickness)
);
};
const pixels = Buffer.alloc(SIZE * SIZE * 4);
for (let py = 0; py < SIZE; py += 1) {
for (let px = 0; px < SIZE; px += 1) {
let inside = 0;
let mark = 0;
for (let sy = 0; sy < SAMPLES; sy += 1) {
for (let sx = 0; sx < SAMPLES; sx += 1) {
const x = px + (sx + 0.5) / SAMPLES;
const y = py + (sy + 0.5) / SAMPLES;
if (!roundRect(x, y)) continue;
inside += 1;
if (ring(x, y) || check(x, y)) mark += 1;
}
}
const total = SAMPLES * SAMPLES;
const offset = (py * SIZE + px) * 4;
if (inside === 0) continue;
const alpha = Math.round((inside / total) * 255);
const mix = mark / inside;
pixels[offset] = Math.round(AMBER[0] * (1 - mix) + WHITE[0] * mix);
pixels[offset + 1] = Math.round(AMBER[1] * (1 - mix) + WHITE[1] * mix);
pixels[offset + 2] = Math.round(AMBER[2] * (1 - mix) + WHITE[2] * mix);
pixels[offset + 3] = alpha;
}
}
const crcTable = Array.from({ length: 256 }, (unused, index) => {
let value = index;
for (let bit = 0; bit < 8; bit += 1) {
value = value & 1 ? 0xedb88320 ^ (value >>> 1) : value >>> 1;
}
return value >>> 0;
});
const crc32 = (buffer) => {
let crc = 0xffffffff;
for (const byte of buffer) {
crc = crcTable[(crc ^ byte) & 0xff] ^ (crc >>> 8);
}
return (crc ^ 0xffffffff) >>> 0;
};
const chunk = (type, data) => {
const length = Buffer.alloc(4);
length.writeUInt32BE(data.length);
const body = Buffer.concat([Buffer.from(type, "ascii"), data]);
const crc = Buffer.alloc(4);
crc.writeUInt32BE(crc32(body));
return Buffer.concat([length, body, crc]);
};
const header = Buffer.alloc(13);
header.writeUInt32BE(SIZE, 0);
header.writeUInt32BE(SIZE, 4);
header[8] = 8;
header[9] = 6;
const raw = Buffer.alloc(SIZE * (SIZE * 4 + 1));
for (let y = 0; y < SIZE; y += 1) {
raw[y * (SIZE * 4 + 1)] = 0;
pixels.copy(raw, y * (SIZE * 4 + 1) + 1, y * SIZE * 4, (y + 1) * SIZE * 4);
}
const png = Buffer.concat([
Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]),
chunk("IHDR", header),
chunk("IDAT", deflateSync(raw, { level: 9 })),
chunk("IEND", Buffer.alloc(0)),
]);
const target = process.argv[2] ?? "app-icon.png";
writeFileSync(target, png);
console.log(`wrote ${target} (${png.length} bytes)`);