#!/usr/bin/env python3
"""Write the project's mark: the site's icons and the repository's logos.
The mark is the chip of the project logo drawn as vector shapes: a body,
four pins per side and the pixel glyph on a 4 by 4 grid. Three variants:
- ``logo.svg``: white, the glyph cut out so the header colour shows through.
It sits on the indigo header in both schemes.
- ``favicon.svg``: indigo chip with a cyan glyph, lighter in a dark browser.
- ``favicon-32.png`` and ``apple-touch-icon.png`` (180 px, opaque): the same
shapes rasterised by a headless Chromium through Playwright, for browsers
that take no SVG icon and for home-screen shortcuts.
The files land in ``docs_assets/brand/``, which generate_site.py copies into
the site. The site build never runs this script.
The repository's own images come from the same shapes, in ``.github/assets/``:
- ``logo.svg`` and ``logo.png`` (256 px): the chip in colour, as the favicon.
- ``favicon.png`` (32 px).
- ``banner-light.svg`` and ``banner-dark.svg``: the mark and the name as the
site header shows them, for the README in each scheme.
- ``social-preview.png`` (1280 by 640): the mark and the name in white on the
sharing cards' indigo, uploaded by hand in the repository settings.
python scripts/make_site_icons.py
"""
from __future__ import annotations
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
OUT = ROOT / "docs_assets" / "brand"
PROJECT = ROOT / ".github" / "assets"
HEADER = "#3b3f7a"
GLYPH = "#8be0f7"
GLYPH_DIM = "#4fa3c4"
# The site title: the light scheme's accent, the dark scheme's accent.
TITLE = {"light": "#273c8f", "dark": "#aebcff"}
# The mark beside it: the header logo in each scheme (website/src/assets).
MARK = {"light": HEADER, "dark": "#fff"}
# The sharing cards' background (sitediagrams.og_card_svg).
CARD = "#2b2e5c"
FONT = "system-ui, -apple-system, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif"
# (column, row, dim) on the 4 by 4 grid, read from the project logo.
PIXELS = [
(0, 0, False), (1, 0, False), (2, 0, True),
(1, 1, False), (3, 1, True),
(0, 2, False), (3, 2, False),
(1, 3, True), (2, 3, False), (3, 3, False),
]
BODY = (8, 8, 32, 4) # x, y, size, corner radius in a 48 unit box
PIN_CENTRES = (13.5, 20.5, 27.5, 34.5)
PIN_WIDTH = 3.4
PIN_LENGTH = 5.5
CELL = 5.0
GAP = 1.6
def _pins(fill: str) -> str:
half = PIN_WIDTH / 2
rects = []
for centre in PIN_CENTRES:
start = centre - half
rects += [
(start, 8 - PIN_LENGTH, PIN_WIDTH, PIN_LENGTH),
(start, 40, PIN_WIDTH, PIN_LENGTH),
(8 - PIN_LENGTH, start, PIN_LENGTH, PIN_WIDTH),
(40, start, PIN_LENGTH, PIN_WIDTH),
]
return "".join(
f'