#!/usr/bin/env python3 """Render static/logo.svg into the home-screen icons. python3 tools/make_icons.py Writes static/icon-180.png (what iOS uses on the home screen) and static/icon-512.png (Android / the web manifest): the white mark on a transparent background, which iOS lays over black on the home screen. The PNGs are committed, so this only needs running if the logo changes. It rasterises with headless Chromium, which is a heavy thing to install for one job -- if you have librsvg to hand, this does the same: rsvg-convert -w 512 -h 512 static/logo.svg -o static/icon-512.png Otherwise: pip install playwright && playwright install chromium """ import sys from pathlib import Path STATIC = Path(__file__).resolve().parent.parent / "static" LOGO = STATIC / "logo.svg" SIZES = (180, 512) MARGIN = 0.14 # breathing room, so iOS's rounded mask never clips it PAGE = """ """ def main(): try: from playwright.sync_api import sync_playwright except ImportError: sys.exit("needs playwright: pip install playwright && playwright install chromium") if not LOGO.exists(): sys.exit(f"no logo at {LOGO}") scratch = STATIC / "_icon.html" try: with sync_playwright() as p: browser = p.chromium.launch(args=["--no-sandbox"]) for size in SIZES: inner = round(size * (1 - 2 * MARGIN)) scratch.write_text(PAGE.format(size=size, inner=inner)) page = browser.new_page(viewport={"width": size, "height": size}) page.goto(scratch.as_uri()) page.wait_for_timeout(120) # let the SVG paint target = STATIC / f"icon-{size}.png" page.screenshot(path=target, omit_background=True) page.close() print(f"wrote {target} ({target.stat().st_size} bytes)") browser.close() finally: scratch.unlink(missing_ok=True) if __name__ == "__main__": main()