// The duck in the tab. public/duck.svg is the master; the PNGs are rendered
// from it so the two can never drift apart. Usage:
// node scripts/duck-icon.mjs
// Writes public/duck-32.png (the fallback for browsers that will not take an
// SVG favicon) and public/apple-touch-icon.png (iOS pins the home-screen
// icon from this one, and it does not like transparency).
import puppeteer from 'puppeteer';
import { readFileSync, writeFileSync } from 'node:fs';
import { resolve } from 'node:path';
const svg = readFileSync(resolve('public/duck.svg'), 'utf8');
const targets = [
{ size: 16, out: 'public/duck-16.png' },
{ size: 32, out: 'public/duck-32.png' },
{ size: 180, out: 'public/apple-touch-icon.png' },
];
const browser = await puppeteer.launch({
headless: true,
args: ['--enable-unsafe-swiftshader', '--hide-scrollbars'],
});
try {
for (const { size, out } of targets) {
const page = await browser.newPage();
await page.setViewport({ width: size, height: size, deviceScaleFactor: 1 });
await page.setContent(
'<!doctype html><meta charset="utf-8">' +
'<style>html,body{margin:0;padding:0;background:transparent}' +
`svg{display:block;width:${size}px;height:${size}px}</style>` +
svg,
{ waitUntil: 'load' },
);
const png = await page.screenshot({ type: 'png', omitBackground: true });
writeFileSync(resolve(out), png);
console.log(`${out} ${size}x${size} ${(png.length / 1024).toFixed(1)} kB`);
await page.close();
}
} finally {
await browser.close();
}