DEV Community

J Now
J Now

Posted on

Why I split a single color across two ANSI slots

I spent several weeks reading Claude Code output for hours at a stretch and the default themes were wearing me out. Not because the syntax highlighting was wrong — Claude Code is mostly prose. Tool output, reasoning traces, permission prompts: paragraphs, not tokens. The themes I tried were tuned for code; nobody had tuned one for body-size English over a long session.

So I built klein-void, four Terminal.app themes built around Yves Klein's International Klein Blue. The design problem that ate most of the time was figuring out why pure IKB kept failing as readable text even when it looked fine to my eye.

WCAG contrast ratios don't model how the visual system perceives lightness on dark backgrounds. WCAG uses a symmetric ratio: the calculation is identical regardless of polarity. APCA (Accessible Perceptual Contrast Algorithm) is asymmetric — dark-on-light and light-on-dark are scored differently because the eye doesn't treat them the same. Pure IKB on a dark ground scores Lc -12 under APCA. That is effectively invisible. The WCAG ratio for the same pairing returns a number that sounds plausible.

The practical consequence: IKB can't be used as text. The fix was splitting it across two ANSI slots. Pure IKB lives in ansi:blue, where Claude Code uses it for decorative borders and structural highlights — non-body roles where Lc -12 is acceptable. Readable work gets done by a lifted Klein-family blue (Lc-verified), assigned to ansi:blueBright, which Claude Code routes to permission-prompt text.

The four variations use per-role APCA gates rather than a single threshold:

body    >= Lc 90
subtle  >= Lc 75
muted   >= Lc 45
accent  >= Lc 60
Enter fullscreen mode Exit fullscreen mode

Klein Void Prot (V3) is the only variation where every accent passes strict gates. The others make explicit tradeoffs — Klein Void Gallery pushes toward maximum void and accepts that some decorative elements sit below the accent gate.

One other decision worth noting: Claude Code has a brand color it routes through ansi:redBright. Whether to neutralize that slot or let it coexist as a second hero is the main differentiator between variations. Klein Void Sand & Sea accepts it; Klein Void Refined neutralizes it to keep IKB as the single color anchor.

Requires Claude Code's /theme picker set to dark-ansi — leave it on default and Claude Code ignores the ANSI profile entirely.

https://github.com/robertnowell/klein-void

Top comments (0)