Accessible color systems, from a single seed.
A zero-dependency TypeScript library & CLI that generates perceptually-uniform, WCAG-compliant, color-blind-safe color palettes using the modern OKLCH color space.
Make accessible design free and effortless for everyone.
Color accessibility shouldn't be a premium feature locked behind paid design
tools. 1 in 12 men and 1 in 200 women live with some form of color vision
deficiency, yet most generated palettes are never checked against it.
chroma-flow ships WCAG 2.1 contrast checking and color-blind simulation in a
tiny, dependency-free package so that every developer can build inclusive
interfaces β no SaaS, no signup, no tracking.
This is a non-commercial, community-driven project. It will never be paywalled, ad-supported, or acquired.
- π§ͺ OKLCH-based generation β perceptually uniform ramps that look balanced to the human eye.
- βΏ WCAG 2.1 contrast checking β AA / AAA conformance for normal and large text.
- π APCA contrast (WCAG 3 candidate) β signed perceptual Lc values, more accurate than WCAG 2.1 for dark themes.
- π Light + dark theme generation β a coordinated semantic theme pair (background, surface, text, primary, accent, success/warning/danger) from one seed, with a per-role WCAG + APCA audit.
- ποΈ Color-blind simulation β protanopia, deuteranopia, tritanopia, achromatopsia.
- π― Smart text-color suggestion β auto-pick black or white text for any background.
- π€ Eight export formats β CSS variables, Tailwind config, JSON, SCSS, SVG swatch sheets, Android
colors.xml, SwiftUIColor, Jetpack ComposeColor. - π₯οΈ CLI + library β use it in code or from the terminal.
- πͺΆ Zero runtime dependencies β auditable in an afternoon, ships tiny.
- π² Tree-shakeable ESM β import only what you use.
npm install chroma-flow
# or
bun add chroma-flow
# or
pnpm add chroma-flowUse the CLI globally:
npm install -g chroma-flow
chroma-flow "#6366f1" --format cssβ¦or run it once with bunx / npx:
bunx chroma-flow "#6366f1"import {
generatePalette,
checkContrast,
suggestTextColor,
simulateAll,
exportPalette,
} from "chroma-flow";
// 1. Generate a full 50β950 palette from one seed.
const palette = generatePalette("#6366f1");
console.log(palette[500]); // "#6265f0"
// 2. Export it to CSS variables.
const css = exportPalette(palette, "css", "primary");
// 3. Pick the most readable text color for a background.
const text = suggestTextColor(palette[600]); // "#ffffff"
// 4. Check WCAG conformance.
const result = checkContrast(text, palette[600]);
console.log(result.ratio); // 8.48
console.log(result.passesAAANormal); // true
// 5. Preview the seed under color vision deficiencies.
simulateAll(palette[500]).forEach((p) =>
console.log(p.type, p.hex)
);
// 6. (v0.2) Check APCA perceptual contrast (WCAG 3 candidate).
import { checkAPCA } from "chroma-flow";
const apca = checkAPCA("#ffffff", palette[600]);
console.log(apca.Lc); // -87.6 (negative = light text on dark)
console.log(apca.passesBodyText); // true (|Lc| β₯ 75)
// 7. (v0.2) Generate a coordinated light + dark theme.
import { generateTheme, themeToCSS } from "chroma-flow";
const theme = generateTheme("#6366f1");
console.log(theme.light.primary); // "#3f37bb"
console.log(theme.dark.primary); // "#8b95ff"
const themeCss = themeToCSS(theme, "brand"); // :root {β¦} .dark {β¦}# Generate a palette
chroma-flow "#6366f1"
# 50 #e8f5ff β
# 100 #deecff ββ
# 200 #cad9ff ββββ
# ...
# Export as CSS variables
chroma-flow "#6366f1" --format css --name primary
# Export as SwiftUI / Jetpack Compose (v0.2)
chroma-flow "#6366f1" --format swift --name brand
chroma-flow "#6366f1" --format compose --name Brand
# Check WCAG 2.1 contrast against a foreground color
chroma-flow "#f59e0b" --contrast "#000000"
# Check APCA perceptual contrast (v0.2)
chroma-flow "#10b981" --apca "#ffffff"
# Generate a coordinated light + dark theme pair (v0.2)
chroma-flow "#6366f1" --theme --name brand
# Simulate color vision deficiencies
chroma-flow "#6366f1" --cvd
# Tweak the ramp
chroma-flow "#6366f1" --distribution linear --hue-shift -20 --chroma-falloff 0.7chroma-flow converts your seed color into the OKLCH color space (a
cylindrical form of OKLab), then walks a lightness ramp across 11 stops while
modulating chroma with a falloff curve and an optional hue shift. The result is
a smooth, natural-feeling scale where every stop stays inside the sRGB gamut.
OKLCH is chosen over HSL because HSL lightness is not perceptually uniform β a "50% lightness" yellow is far brighter to the eye than a "50% lightness" blue. OKLCH fixes this, so ramps actually look balanced.
seed hex
β
βΌ
ββββββββββββ ββββββββββββββββ ββββββββββββββββ
β sRGB β β ββΊ β lightness β ββΊ β chroma β
β OKLCH β β ramp (11) β β falloff β
ββββββββββββ ββββββββββββββββ ββββββββ¬ββββββββ
β
βββββββββββββββββ΄ββββββββββββββββ
βΌ βΌ
WCAG contrast checks CVD simulation
(AA / AAA) (4 conditions)
β β
βββββββββββββββββ¬ββββββββββββββββ
βΌ
CSS / Tailwind / JSON / SCSS / SVG / XML
Returns a Record<50|100|β¦|950, string> palette.
| Option | Type | Default | Description |
|---|---|---|---|
distribution |
"linear" | "perceptual" |
"perceptual" |
Lightness distribution across the ramp. |
chromaFalloff |
number (0β1) |
0.5 |
Vividness of mid-tones vs. extremes. |
hueShift |
number (degrees) |
0 |
Hue drift across the ramp. |
maxChroma |
number |
0.32 |
Clamp to avoid out-of-gamut colors. |
Returns { ratio, passesAANormal, passesAALarge, passesAAANormal, passesAAALarge }.
Returns an array of { type, hex, original } for all four CVD types.
Returns "#000000" or "#ffffff", whichever has higher contrast.
Exports to "css" | "tailwind" | "json" | "scss" | "svg" | "android-xml".
See the full API reference for the complete list.
Contributions are what make the open-source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
- π Found a bug? Open an issue.
- π‘ Have an idea? Suggest a feature.
- π§ Want to code? Grab a
good first issueand read CONTRIBUTING.md.
Please review our Code of Conduct before participating.
-
APCA contrast support (WCAG 3 candidate)β shipped in v0.2.0 -
Theme generation (light + dark from one seed)β shipped in v0.2.0 -
Swift + Jetpack Compose exportersβ shipped in v0.2.0 - Live web playground (in-repo, deployed to GitHub Pages)
- ESM + CJS dual build
- Figma plugin
- Delta-E βE2000 color difference helper
- Auto-derivation of complementary / triadic / analogous seeds
MIT Β© Cryptoteep. See LICENSE.
- BjΓΆrn Ottosson for the OKLab / OKLCH color space.
- Machado et al. (2009) for the color vision deficiency simulation matrices.
- The W3C for the WCAG 2.1 contrast specification.
β If chroma-flow helps you build something more accessible, please star the repo β it helps others find it.