1 Commits
Author SHA1 Message Date
zeekay d72a13d4f9 feat: outlined wordmarks, one per product
The wordmark is per-product — "Hanzo AI" on hanzo.ai, "Hanzo ID" on hanzo.id —
so it is a table, not one asset. Sixteen names ship: the Hanzo products plus
Lux, Zoo and Pars.

They are PATHS. @hanzo/brand's wordmark.svg sets the name as an un-outlined
<text> in Zen, so it renders in whatever fallback is around wherever Zen has not
loaded — an OG card, a favicon, a PDF, a machine without the webfont. An outline
needs no font at all.

Cut from Zen at wght 606 (the house `medium` preset) and shaped through
HarfBuzz, so pair spacing is the font's own GPOS kerning rather than naive
advances — the first cut, with advances only, spaced visibly wrong.

getWordmarkSVG(name) returns null for a name with no outline rather than falling
back to <text>: a silent fallback is how a page ends up setting the brand in
Arial. Add the name to scripts/wordmarks.py and re-run it.

The table is ~143 KB, so build.ts also emits one file per name and
`./wordmark/*` exports them — a browser bundle takes the one it needs; the table
is for Node, where OG images and PDFs are made.

The generator is NOT wired into `build`. Outlines are static data, and making
every build depend on Python and fontTools to reproduce bytes that never change
is a cost with no payer.

This also fills a hook that had nothing behind it: build.ts called an optional
(marks as any).getWordmarkWhite?.() that logos.ts never defined.
2026-08-24 21:28:53 -07:00