Files
zooqueen a523d0c9b8 the mark was painted black on black, so the icon was a square
scripts/gen-favicons.mjs composites the mark in headless Chromium. The mark's
ink is scheme-conditional — `#000` by default, `#fff` under
`prefers-color-scheme: dark` — headless Chromium reports `light`, and the page
it painted on was `background:#000`. Every raster came out a UNIFORM opaque
black tile: 36,864 of 36,864 pixels `0,0,0,255` at 192px. Both manifests
declare `background_color: "#000000"`, so the mark was invisible against the
surface its own manifest asks for, and Android drew a solid black square on the
home screen. `emulateMedia({ colorScheme: 'dark' })` settles it — the default
is a colour nobody chose.

The second half is that one file cannot serve both purposes, and the manifest
offered the same bytes under `any maskable`. An `any` icon is used as it is, so
it stays transparent and stands on the host's own surface; a `maskable` icon is
cropped by the OS to a platform shape, so it has to be opaque and full-bleed
with the mark inside the safe zone, and a transparent one gets composited onto
a ground the launcher picks. icon-maskable-192/512 are rendered separately on
the ground the manifest declares — read FROM the manifest, so the two cannot
drift back apart — and inset to the square inscribed in the safe circle, since
the H's four corner blocks are ink and a circular launcher would bite them off.

apple-touch-icon is now opaque from Chromium rather than flattened afterwards
by Pillow: `convert("RGB")` keeps the stored channels, so every antialiased
edge pixel became hard white instead of blending into the black. That leaves
gen-favicon-ico.py doing one job.

e2e/gates/icons.spec.ts asserts the pixels, because this defect is invisible on
a dark page and no page draws these files at all. It reads the icons off the
manifest, composites each on the surface that manifest declares, and measures
the fraction that clears 3:1 against it. Regressed on purpose to check it can
fail: all six rasters go red with "0.0% ink — a square, not a mark".

  before  icon-192  corner 0,0,0,0    centre 0,0,0,255   100% black
  after   icon-192  66.6% ink on #000000, 32.8% clear
          icon-maskable-192  21.1% ink, 100% opaque, 0px outside the safe circle
2026-08-16 13:37:37 -07:00

11 lines
253 B
JSON

{
"source": "@hanzo/brand/assets/logo/favicon.svg",
"icons": {
"/favicon.svg": "684f26a2",
"/favicon-32x32.png": "c4dab769",
"/favicon-16x16.png": "9c246c4d",
"/favicon.ico": "eac5a7ed",
"/apple-touch-icon.png": "365f82a9"
}
}