One palette file, one build step, every app you actually use.
The count is dead. Editors, terminals, Claude Code and your pager, all painted from the same twenty-odd colors — and a build that refuses to ship them if they drift.
git clone https://github.com/espresso20/neonferatu && ./install.py~/code/neonferatu $ python3 build/build.py palette check ok — 3 variants, contrast floors, accent separation, ramp, no raw hex Neonferatu v1.0.0 — 8 files → dist/ Neonferatu Amber v1.0.0 — 8 files → dist/variants/amber/ Neonferatu Phosphor v1.0.0 — 8 files → dist/variants/phosphor/ ~/code/neonferatu $ ./install.py ✔ Monaspace Krypton ✔ ~/.claude/themes/neonferatu.json ✔ VS Code extension + settings ✔ iTerm2 dynamic profile — live, no restart ~/code/neonferatu $ █
Every color is placed in OKLCH and checked at build time. Contrast is against this tube's editor background; the build fails if body text drops under 4.5:1, if the background ramp stops climbing, or if two syntax colors get close enough to be mistaken for each other.
| key | role | hex | L* | chroma | hue | contrast | |
|---|---|---|---|---|---|---|---|
| neon.fang | keywords, cursor | ||||||
| neon.chrome | functions, links | ||||||
| neon.hex | types, classes | ||||||
| neon.acid | strings | ||||||
| neon.sodium | numbers, constants | ||||||
| neon.wound | errors, deletions | ||||||
| fg.phosphor | body text | ||||||
| fg.muted | comments | ||||||
| bg.void | editor background |
The hierarchy is short on purpose. If a sixth accent creeps in, we've lost the plot.
# the ceiling on how saturated this hue gets, at this lightness def max_chroma(L: float, H: float) -> float: """Walk chroma down until the color fits in sRGB.""" lo, hi = 0.0, 0.5 for _ in range(48): mid = (lo + hi) / 2 if in_gamut(L, mid, H): lo = mid else: hi = mid return lo
Run ./install.py for all of them, or name the ones you want. Everything it touches is backed up first, and ./uninstall.py puts it back.
fontMonaspace Krypton, weight 500 in editors, bold in terminals
claudeall 72 theme keys, spinner rainbow and diff blocks included
vscodelocal extension, 1.55 line height, 3px phase-blinking cursor
itermdynamic profile — iTerm2 picks it up live, no restart
terminalinstalls the profile and makes it default
zed~/.config/zed/themes, Cmd+K Cmd+T to pick
sublimetmTheme, same colors
batsyntax highlighting in your pager
Python 3, no dependencies. macOS for the terminal profiles; the editor themes are portable.
git clone https://github.com/espresso20/neonferatuOr download it. Nothing here phones home.
python3 build/build.pyRegenerates every theme file from palette.json, after the palette passes its checks.
./install.py --variant phosphorInstalls a tube and activates it. They live side by side, so run all three and pick from your editor's theme list.
./preview.shPrints the palette and a syntax sample straight into your terminal, before you commit to anything.