Palette Forge
A web app that gives out complete UI color palettes — written entirely in
goml, the ML-family surface for the Go+
toolchain, and compiled down to a single Go binary.
Pick one starting color (or one of the book's 24 curated palettes) and you
get the full system a real interface needs: ten shades each of a primary
scale, temperature-matched neutrals, and supporting scales — downloadable as
a PDF laid out like the Refactoring UI: Color Palettes book, and as
JSON.
Run it
go install goforge.dev/palettegen@latest && palettegen
# or, from a checkout:
make run # goml gen ./... && go build && ./palettegen
# serving on http://localhost:8383 (override with PORT=...)
Working on the source requires Go ≥ 1.26 and the goml tool:
go install goforge.dev/goplus/cmd/goml@latest (built against v0.158.0).
make check — run the goml-native self-checks (./palettegen check)
make ci — verify committed generated code is fresh, build, and check
make data — regenerate palette/data.goml from tools/palettes.json
Deployment is one static binary; no assets, no JavaScript, no database.
State lives in the URL (/?c=7C3AED or /?p=12, plus &t=light|dark for
an explicit color scheme), so pages, JSON (/palette.json?...) and PDFs
(/palette.pdf?...) are all cacheable GETs.
The page itself follows the OS light/dark preference by default
(prefers-color-scheme); the header toggle pins it explicitly — still with
zero JavaScript, since the choice is just another URL parameter. Besides the
swatch scales, the palette is shown in context six ways (cards on light and
dark grounds, semantic alerts, text hierarchy, navigation, forms and focus),
and a collapsible block offers the JSON for copy-paste next to the download
buttons.
Pure goml
Every line of application code is .goml; each *_gml.go file beside it is
generated by goml gen (committed, per the toolchain's convention — run
goml gen -check ./... in CI to keep them honest). There are no hand-written
.go or .gp files. Two consequences worth knowing:
- Data as code: the book's palettes live in
palette/data.goml
(generated once by tools/gen_data.py from the extraction in
tools/palettes.json). Only hex strings are stored; HSL is recomputed at
startup by the goml ParseHex, which the extraction validated to within
the book's own rounding (±1).
- Tests as goml:
check.goml implements the test suite; palettegen check exits non-zero on failure.
- Fonts as code: Overpass (headings) and Atkinson Hyperlegible (body)
are embedded as base64 in
fonts.goml (generated by tools/gen_fonts.py,
latin woff2 subsets, SIL OFL 1.1) and served from memory at /fonts/… —
the binary stays fully self-contained, with no external requests.
The one goforge tool deliberately not used is the cadence/Quicken web
framework: its API needs generic struct literals and slice→variadic spread,
which goml v0.158 has no syntax for — so serving is goml driving net/http
directly, which it does natively.
How generation works (the Refactoring UI method)
- Your color is parsed to HSL and matched to the nearest of the book's 26
hand-tuned reference scales (hue distance, saturation class as
tie-break).
- The seed scale is re-anchored: your color lands exactly on the shade
nearest its lightness; hue rotates uniformly; saturation and lightness
corrections fade toward the scale's ends, so the book's usable-as-text
darks and tinted-background lights survive.
- Neutrals are the book's grey family matching your hue's temperature
(warm → Warm Grey, greens/yellows → Grey, blues → Blue Grey,
purples → Cool Grey).
- Supporting = a complementary accent generated the same way, plus the
book's semantic Red/Yellow/Green scales (vivid or muted to match your
saturation), skipping any that would duplicate the primary hue.
Design notes
- UX (Joe Natoli): one screen, one purpose; a useful default palette on
first load (zero decisions needed); labeled in plain words; the primary
action is the only loud thing on the page; bad input degrades to a
helpful note, never a dead end.
- UI (Leonardo da Vinci): simplicity as sophistication — whitespace,
one column, soft shadow depth instead of borders; spacing on a
Fibonacci scale, type on a golden-ratio ramp (16/26/42).
- UI (Patrick Henry Winston): an empowerment promise up top; constant
landmarks (Primary / Neutrals / Supporting, always in that order);
teaching-by-role captions; and the palette shown three ways — swatches,
an in-context preview card, and the downloadable artifacts.
- The app's chrome wears the palette it is showing: page background, text,
buttons, links, focus rings and shadows are all derived from the selected
palette's neutral and primary scales (in both color schemes). The default
landing therefore dresses the site in the book's Palette 1 — and every
generated palette is instantly test-driven by the very page presenting it.
Sources
Palettes and method from Refactoring UI and Refactoring UI: Color
Palettes v1.1.0 (Adam Wathan & Steve Schoger). PDF rendering via
codeberg.org/go-pdf/fpdf.
Part of the goforge suite. MIT licensed.