diff --git a/_scripts/build-monochrome-icon.ts b/_scripts/build-monochrome-icon.ts new file mode 100644 index 0000000..5e2b1a3 --- /dev/null +++ b/_scripts/build-monochrome-icon.ts @@ -0,0 +1,40 @@ +import path from "path" +import sharp from "sharp" + +// PWA spec: `purpose: "monochrome"` icons are *masks*. The user agent ignores +// RGB and uses only the alpha channel as the silhouette, then paints it with +// the platform theme color. So the source PNG must be RGBA with the silhouette +// in alpha, NOT a black-on-white RGB image. + +const SRC = path.resolve(__dirname, "../public/favicon.png") +const OUT = path.resolve(__dirname, "../public/monochromeicon.png") +const SIZE = 1024 + +async function main() { + const { data, info } = await sharp(SRC) + .resize(SIZE, SIZE, { fit: "contain", background: { r: 0, g: 0, b: 0, alpha: 0 } }) + .ensureAlpha() + .raw() + .toBuffer({ resolveWithObject: true }) + + if (info.channels !== 4) throw new Error(`expected RGBA, got ${info.channels} channels`) + + const out = Buffer.alloc(data.length) + for (let i = 0; i < data.length; i += 4) { + out[i] = 0 + out[i + 1] = 0 + out[i + 2] = 0 + out[i + 3] = data[i + 3] + } + + await sharp(out, { raw: { width: SIZE, height: SIZE, channels: 4 } }) + .png({ compressionLevel: 9 }) + .toFile(OUT) + + console.log(`Wrote ${OUT} (${SIZE}x${SIZE} RGBA)`) +} + +main().catch((e) => { + console.error(e) + process.exit(1) +}) diff --git a/public/monochrome-icon.png b/public/monochrome-icon.png deleted file mode 100644 index 731632e..0000000 Binary files a/public/monochrome-icon.png and /dev/null differ diff --git a/public/monochromeicon.png b/public/monochromeicon.png new file mode 100644 index 0000000..f19a41e Binary files /dev/null and b/public/monochromeicon.png differ diff --git a/vite.config.mts b/vite.config.mts index 0c97159..04397ca 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -22,7 +22,7 @@ export default defineConfig(({ command }) => { "pwa-512x512.png", "masked-icon.png", "maskable-icon-512x512.png", - "monochrome-icon.png", + "monochromeicon.png", "assets/*.svg" ], manifest: { @@ -54,7 +54,7 @@ export default defineConfig(({ command }) => { purpose: "maskable" }, { - src: "monochrome-icon.png", + src: "monochromeicon.png", sizes: "1024x1024", type: "image/png", purpose: "monochrome"