fix(terminal): floor ANSI colors to 3:1 contrast on light themes#7
Merged
Conversation
Terminal ANSI colors were resolved straight from the palette with no readability adjustment. On the near-white light backgrounds this left the chromatic colors illegible (yellow ~1.6:1, cyan ~1.7:1, green ~2.1:1, ...). The "bright" variants were worse: brightHex always *lightened*, which improves contrast on a dark background but pushes colors toward a light one. Add WCAG contrast utilities (relativeLuminance, contrastRatio, ensureContrast) to colorUtils and apply a 3:1 contrast floor to the chromatic ANSI text colors across all four terminal targets (wezterm, vscode, zed, neovim). ensureContrast nudges only lightness, preserving hue/saturation, and is a no-op when a color already passes -- so dark themes are byte-for-byte unchanged. "Bright" is now direction-aware: lighter on dark backgrounds, darker on light ones. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Several terminal ANSI colors are illegible on the light-mode backgrounds (
#FFF8F5pastel-light,#FAF6FAneon-light). Terminal colors were pulled straight from the palette with no readability adjustment — the same values that work as sparse, often-bold editor syntax tokens fail as terminal text. Measured WCAG contrast against#FFF8F5: yellow ~1.6:1, cyan ~1.7:1, green ~2.1:1, blue/magenta ~2.2:1, red ~2.9:1 — all below a 3:1 floor.A second, directional bug compounded it:
brightHex/bright/bright8always lightened the bright variants. Lightening helps on a dark background but pushes colors toward a light one, so bright green/yellow/cyan were the faintest of all (~1.4:1) — the pale prompt/TUI text users saw.Dark themes were unaffected, which matches what users observed in the wild.
Fix
generator/colorUtils.ts— addrelativeLuminance,contrastRatio, andensureContrast.ensureContrastnudges only a color's lightness (preserving hue/saturation) just enough to reach a minimum contrast against the background, darkening on a light bg and lightening on a dark one. It's a no-op when the color already passes.wezterm.ts,vscode.ts,zed.ts,neovim.ts) — apply a 3:1 contrast floor to the chromatic ANSI text colors (normal + bright). "Bright" is now direction-aware (lighter on dark, darker on light) before flooring. Structural black/white slots are left untouched.3:1 was chosen to fix legibility while preserving the synthwave/vaporwave palette as much as possible; the nudge is minimal, so colors that already pass keep their vividness.
Result
Every chromatic terminal color (normal + bright) now clears 3:1 on the light backgrounds:
Dark themes are byte-for-byte unchanged — the floor is a no-op where colors already pass, so the dark
wezterm/vscodeoutput files weren't touched.Tests
20 new tests (RED→GREEN), covering the WCAG utilities and asserting per-target that light-mode chromatic colors meet 3:1 while dark-mode values stay pinned to their existing hexes.
bun test→ 111 pass, 0 failbun run check(biome +tsc --noEmit) → cleanOut of scope
The Starship powerline prompt is a separate code path (hardcodes the dark palette, draws
fg:cruston colored segments) and isn't driven by the ANSI mapping. Plain ANSI-colored shell text benefits from this fix; making the Starship segments themselves mode-aware is a follow-up.🤖 Generated with Claude Code