the thinking behind datum · a living doc — changes when the palette does
The ideas
datum isn't picked, it's derived. Here's the short version of why every color sits where it does.
The whole trick
Every token gets a color — but how loud that color is tracks how often the token shows up. The rare, meaningful stuff (strings, numbers, constants, types, definitions) runs at full chroma. The ~75% that's just glue — variables, calls, parameters, operators — gets a quieter version of the same hue. Colorful, without turning into soup.
Derived, not vibed
The colors fall out of a script, not my eyeballs. They live in OKLCH, so "equally bright" actually means equally bright. Every one clears WCAG 4.5:1 plus an APCA check, then the whole set runs through a colorblindness simulator. When a color fails, the math says so and I move it — no guessing. The receipts are on the palette page, computed live in your browser.
Which colors, and why
The hues come from Okabe–Ito, a set built to stay distinct for colorblind folks. The mapping has a story:
- cool = how the code is built — keywords, types, strings
- warm = the data running through it — numbers, constants
- purple = stuff you named — functions, constants
- red = stuff that's broken — errors only, so it never gets spent on syntax
Light and dark aren't opposites
A dark theme isn't a light one flipped upside down — that reads wrong, because your eyes don't work that way. Same hue in both modes, but lightness and chroma retuned for the background. Light green is a deep pine; dark green a bright mint. Still the same "green." Hit the ☀/☾ up top to watch it swap.
Where it's honest
- In light mode the warm colors crowd a bit under red-green colorblindness. That's physics — you can't have three distinct warm hues that are all dark enough to read on near-white. Low stakes, though: a
42and aMAX_RETRIESare obvious without the color. - The tiers lean on Tree-sitter (in Neovim) to tell a function call from a definition. Without it, some of the quiet tier just falls back to plain text — still readable, just less color.
- A 256-color terminal flattens the off-white to plain white. Truecolor gets the real hexes.
- It goes maximal on color on purpose. Want calmer? That's a config tweak away, not a rewrite.
Under the hood
One file — tools/derive.py — is the source of truth. It emits the palette as JSON, and every port (Ghostty, Kitty, WezTerm, VS Code, tmux, fzf, the shell, all of them) is generated from it. Change a color once and everything follows, so nothing drifts.
Go deeper
The research it leans on: OKLCH (Ottosson) · Solarized · APCA · Okabe–Ito / Wong · light vs dark reading · tonsky on syntax highlighting.