Color Blind Safe Palette Generator

Generate categorical colour palettes that stay distinguishable under protanopia, deuteranopia, tritanopia and greyscale. Constraint-based OKLab sampling with CIEDE2000 checks, WCAG contrast tables, auto-fix, and CSS/Tailwind/SCSS/JSON/SVG export.

4

Samples in OKLab and rejects any candidate that falls below 20 ΔE2000 from an existing colour under normal, protan, deutan or tritan vision, or within 8 L* of it in greyscale. Locked swatches are kept.

Passes every check — worst pair 20.8 ΔE2000, worst greyscale gap 20.3 L*

PaletteTol High-Contrast

#1#000000
21.0:1
bg · AAA
21.0:1
on white
1.0:1
on black
Protan
Deutan
Tritan
Mono
#2#004488
9.6:1
bg · AAA
9.6:1
on white
2.2:1
on black
Protan
Deutan
Tritan
Mono
#3#DDAA33
2.1:1
bg · Fail
2.1:1
on white
9.9:1
on black
Protan
Deutan
Tritan
Mono
#4#BB5566
4.6:1
bg · AA
4.6:1
on white
4.6:1
on black
Protan
Deutan
Tritan
Mono

Export

CSS variables
Tailwind config
SCSS map
JSON report
SVG swatch sheet

Everything runs in your browser — the palette, the simulations and the ΔE2000 maths never leave the page. The share link stores state in the URL fragment, which browsers never send to a server.

About Color Blind Safe Palette Generator

This is a constraint-based generator, not a swatch viewer. Pick how many colours you need (2–12), press Generate, and the tool samples candidates in OKLab and rejects any colour that lands closer than your ΔE2000 threshold to an already-accepted colour — measured four times over: under normal vision and under simulated protanopia, deuteranopia and tritanopia — plus a minimum CIE L* gap so the palette also survives greyscale printing. Dichromacy is simulated in linear RGB with the Viénot, Brettel & Mollon (1999) matrices for protan and deutan and the Brettel (1997) two-plane projection for tritan. Every swatch can be locked, every failing palette can be auto-fixed by nudging hue, lightness and chroma in OKLab, and every result exports as CSS variables, a Tailwind config, an SCSS map, a JSON report or an SVG swatch sheet.

Why use a Color Blind Safe Palette Generator?

Roughly 8% of men and 0.5% of women of northern-European descent have a colour-vision deficiency, and the failure mode is silent: two chart series that look obviously different to you collapse into the same muddy tone for a deuteranope. Hand-picking colours and eyeballing a simulator catches only the worst cases — it gives you no number to defend in an accessibility review. This tool turns the question into a measurable constraint. You get a pass/fail verdict with the exact worst pair, the exact ΔE2000, the exact vision type, the WCAG ratio against white, black and your real background, and a swatch-to-swatch contrast matrix for series that physically touch. If it fails, auto-fix repairs it and you can undo.

Who is it for?

Data-visualisation engineers choosing categorical scales for dashboards and charts; design-system maintainers who need colour tokens that survive an accessibility audit; accessibility specialists producing evidence for WCAG 2.2, Section 508 or EN 301 549 reviews; data journalists publishing charts that must also work in print and greyscale; and scientific authors following journal guidance on colour-blind-safe figures. The paste-a-palette input and the CSS/Tailwind/SCSS exports also make it a quick way to audit and repair a palette you have already shipped.

How to use the tool

1

Set the Colours counter to the number of series you need (2–12) — the default palette is Paul Tol's high-contrast scheme, which passes every check at the default thresholds

2

Press Generate palette; the tool samples in OKLab and keeps only colours that stay at least 20 ΔE2000 apart under normal, protan, deutan and tritan vision and at least 8 L* apart in greyscale

3

Press Shuffle to re-roll the unlocked swatches in a random pastel, balanced or vivid mood at the same constraints

4

Click the padlock on any swatch you want to keep — locked swatches are never moved by Generate, Shuffle or Auto-fix

5

Open Configuration to load a research-backed preset (Okabe–Ito, Paul Tol, ColorBrewer, viridis, IBM), paste your own hex codes, set the real background colour, or change the ΔE2000 and greyscale thresholds

6

Read the verdict banner: green means every pair passes, amber lists the exact failing pairs with their vision type and measured distance

7

If it fails, press Auto-fix — the worst offending unlocked swatch is nudged in OKLab (hue rotation, lightness and chroma shifts) until the constraints hold; press Undo to revert

8

Open Detailed checks for the pairwise ΔE2000 matrix per vision type, the WCAG contrast table against white, black and your background, and the swatch-to-swatch contrast matrix for touching elements

9

Export as CSS variables, a Tailwind config snippet, an SCSS map, a JSON report or an SVG swatch sheet — or copy the share link, which encodes the whole setup in the URL fragment

Key Features

Real constraint-based generation

Rejection sampling in OKLab with a hill-climbing fallback. Every candidate must clear the ΔE2000 threshold against every accepted colour under four vision models, plus a minimum CIE L* gap for greyscale. If the requested count is infeasible, the tool says so instead of shipping a broken palette.

Viénot 1999 and Brettel 1997 simulation in linear RGB

Protanopia and deuteranopia use the Viénot, Brettel & Mollon (1999) single-plane matrices; tritanopia uses the Brettel, Viénot & Mollon (1997) two-plane projection, which needs a half-plane decision because a single matrix cannot model S-cone loss. Both run on linearised sRGB, and partial severity is blended in linear RGB.

CIEDE2000, not ΔE76

Perceptual distance uses the full CIEDE2000 formula with its lightness, chroma and hue weighting functions and the blue-region rotation term. ΔE76 systematically overstates differences in saturated blues, exactly where CVD palettes live.

Per-swatch locking

Lock your brand colours and generate the rest around them. Locked swatches survive Generate, Shuffle and Auto-fix; if a locked pair is itself in conflict, the tool reports it rather than silently overwriting your colour.

Auto-fix with undo

The worst offending unlocked swatch is moved in OKLab — hue rotated, lightness shifted, chroma adjusted — with a greedy hill-climb on the smallest normalised constraint headroom, repeated until the palette passes. Every mutation is undoable.

Three contrast views

Each swatch is measured against white, black and your chosen background with WCAG 2.2 grades, and a full swatch-to-swatch contrast matrix flags pairs below 3:1 — the threshold that matters for adjacent bars, stacked areas and pie slices under SC 1.4.11.

Developer-ready exports

CSS custom properties, a Tailwind theme.extend snippet, an SCSS map, a JSON report (including every simulated hex, every contrast ratio and every failing check) and an SVG swatch sheet that shows the original plus all three simulations.

Shareable, 100% client-side

Palette, background, thresholds, locks and preview mode are encoded in the URL fragment, which browsers never transmit. All colour maths runs in JavaScript on your device — zero network requests.

Common Use Cases

Categorical chart palette for a dashboard

Scenario: You need six line-chart series that no viewer will confuse, and the design review will ask you to prove it.

Set Colours to 6, press Generate, and export the JSON report — it records the worst pair, its ΔE2000 and the vision type, which is exactly the evidence an accessibility reviewer asks for.

Auditing a palette you already shipped

Scenario: A design system already has eight brand-adjacent colours and you suspect two of them collide for deuteranopes.

Paste the hex codes into Configuration, read the amber verdict for the exact offending pair, lock the colours you cannot change and press Auto-fix to repair only the rest.

Charts that must also work in print

Scenario: A report will be photocopied in black and white, so colour alone will not survive.

Raise the greyscale threshold — the generator enforces a minimum CIE L* gap between every pair, so the palette stays readable after the colour is thrown away.

Adjacent series: stacked bars and pie slices

Scenario: Your colours are distinguishable in a legend but two of them sit edge-to-edge in a stacked bar with no border between them.

The swatch-to-swatch contrast matrix flags every pair below the WCAG 2.2 SC 1.4.11 3:1 non-text threshold so you know which boundaries need a stroke.

Teaching inclusive design

Scenario: You want students to see why 'it looks fine to me' is not a test.

Load Okabe–Ito, switch the preview to tritanopia and drag the severity slider — the orange and reddish-purple swatches converge on screen while the measured ΔE2000 drops below the threshold in real time.

Accuracy

CIEDE2000 verified against the Sharma, Wu & Dalal (2005) test data; Viénot 1999 and Brettel 1997 dichromacy models applied in linear sRGB; WCAG 2.2 contrast formula.

Privacy

100% client-side. No upload, no API call, no analytics on palette content — the share link stores state in the URL fragment, which browsers never send to a server.

Uptime

Static page — no backend dependency.

Frequently Asked Questions

How do I generate a colour-blind-safe palette?

Set the Colours counter to the number of series you need, then press Generate palette. The tool samples candidate colours in OKLab and keeps one only if it stays at least 20 ΔE2000 (adjustable) away from every already-accepted colour under normal vision and under simulated protanopia, deuteranopia and tritanopia, and at least 8 CIE L* away in greyscale. Lock any swatch you want to keep with its padlock, press Shuffle to re-roll the rest, and export as CSS variables, Tailwind, SCSS, JSON or an SVG swatch sheet. If the requested count cannot satisfy the constraints, the tool reports that instead of returning a palette that quietly fails.

What is ΔE2000, and why not the simpler ΔE76?

ΔE is perceptual colour distance in CIELAB. ΔE76 is plain Euclidean distance, which assumes CIELAB is perceptually uniform — it is not. ΔE76 overstates differences in saturated blues and understates them in neutrals, so palettes tuned against it look fine on paper and collide on screen. CIEDE2000 adds weighting functions for lightness, chroma and hue plus a rotation term specifically for the blue region, and is the current CIE recommendation. This tool implements the full CIEDE2000 formula and verifies it against the Sharma, Wu & Dalal (2005) test data — for example Lab (50, 2.6772, −79.7751) vs (50, 0, −82.7485) returns 2.0425.

How accurate are the simulations, and does my palette leave the browser?

Protanopia and deuteranopia use the Viénot, Brettel & Mollon (1999) single-plane matrices; tritanopia uses the Brettel, Viénot & Mollon (1997) two-plane projection, because S-cone loss cannot be modelled by one matrix. Both operate on linearised sRGB — simulating in gamma-encoded RGB, as many web tools do, produces visibly wrong colours. Partial severity is interpolated in linear RGB too. These models describe dichromacy, the complete absence of a cone class; anomalous trichromats see something in between. Nothing is uploaded: every conversion, simulation, ΔE2000 and contrast calculation runs in JavaScript on your device. Check DevTools' Network tab — the tool makes zero requests.

Okabe–Ito, Paul Tol, ColorBrewer or viridis — which preset should I use?

For categorical data up to eight series, Okabe–Ito is the most widely accepted scientific default and is strong for protanopia and deuteranopia. Paul Tol's high-contrast scheme is the safest small set — four colours that clear 20 ΔE2000 under every simulation and separate cleanly in greyscale. Tol bright and muted trade some separation for more categories. ColorBrewer Set2 and Dark2 are print-friendly but several pairs sit close under simulation. Viridis is a sequential scale sampled at six stops: use it for ordered data such as heatmaps, never for unordered categories, because its stops are deliberately near-neighbours in lightness order.

Why does Okabe–Ito show a failing pair in this tool?

Because Okabe–Ito was designed for the common red-green deficiencies, and this tool also checks tritanopia. Measured here, its minimum pairwise distance is 21.7 ΔE2000 under normal vision, 12.3 under protanopia and 11.7 under deuteranopia — but only 7.9 under tritanopia, where #E69F00 (orange) and #CC79A7 (reddish purple) both map to similar pale pinks. Several of its pairs also sit under 8 L* apart, so they merge in greyscale. That is not a defect in the palette, it is the scope it was designed for. If your audience includes tritanopes, or the chart will be printed in black and white, generate against those constraints instead.

My chart series touch each other — is ΔE2000 enough?

No. ΔE2000 tells you whether two colours are distinguishable as separate identities; it says nothing about whether a boundary between them is visible. WCAG 2.2 SC 1.4.11 requires a 3:1 contrast ratio for non-text visual boundaries, and two colours can be 25 ΔE2000 apart while sitting at 1.4:1 contrast. That is why the Detailed checks panel includes a swatch-to-swatch WCAG contrast matrix and flags every pair below 3:1. For stacked bars, pie slices, adjacent map regions and area charts, use that matrix — or add a 1–2px stroke in the surface colour between segments.

Is a colour-blind-safe palette automatically WCAG compliant?

No — they are different properties. Colour-blind safety is about distinguishing swatches from each other; WCAG contrast is about a colour against its background. A palette can be perfectly separated under every simulation and still fail 4.5:1 for text on your surface colour, and the same palette will pass on white and fail on a mid-grey card. Set the Background field to your real surface and read the per-swatch table, which shows white, black and your background with WCAG 2.2 grades. Remember the thresholds: 4.5:1 for normal text, 3:1 for large text and non-text UI, 7:1 for AAA.

Why can't I get 12 colours at ΔE2000 ≥ 20?

Because dichromatic vision collapses the three-dimensional colour space onto a roughly two-dimensional surface, so the space available for mutually distant colours is far smaller than sRGB suggests. In practice this generator reliably fits about seven colours at 20 ΔE2000 with 8 L* of greyscale separation, nine at 15, and ten at 12; twelve requires relaxing the greyscale gap, because twelve colours 8 L* apart would need an 88-point lightness span. When a request is infeasible the tool reports the closest attempt and the worst pair rather than guessing. Above eight categories, add shape, pattern or direct labelling — see the [Color Blindness Simulator](/tools/color-blindness-simulator/) and [Contrast Checker](/tools/contrast-checker/).

Technical Specifications

Supported Formats

  • Generation: rejection sampling in OKLab (Ottosson 2020) with an OKLab hill-climbing fallback, 2–12 colours
  • Constraints: pairwise CIEDE2000 ≥ threshold (default 20, range 5–40) under normal, protanopia, deuteranopia and tritanopia, plus pairwise CIE L* ≥ threshold (default 8, range 0–20) in greyscale
  • Protan/deutan simulation: Viénot, Brettel & Mollon 1999 single-plane matrices, applied in linear sRGB
  • Tritan simulation: Brettel, Viénot & Mollon 1997 two-plane projection with half-plane selection, applied in linear sRGB
  • Severity: linear-RGB interpolation between identity and full dichromacy (preview only; checks always run at 100%)
  • Perceptual distance: full CIEDE2000 (CIE 15:2004), verified against the Sharma, Wu & Dalal (2005) test pairs
  • Contrast: WCAG 2.2 relative-luminance ratio against white, black, the chosen background, and every other swatch
  • Presets: Okabe–Ito, Tol high-contrast/bright/muted/light, ColorBrewer Set2 and Dark2, viridis 6-stop, IBM Design Library
  • Exports: CSS custom properties, Tailwind config snippet, SCSS map, JSON report, SVG swatch sheet, copy-all hex
  • URL fragment state: c (colours), bg, sim, sev, thr, mono, lock

Limits & Performance

  • File Size: 2–12 colours. Feasibility falls off with the threshold: ~7 colours at 20 ΔE2000 with an 8 L* greyscale gap, ~9 at 15, ~10 at 12
  • Validations: Hex is normalised on commit (3- or 6-digit, with or without #); invalid input is rejected and the previous value kept
  • Response Time: Generation completes in well under 100 ms for every count; checks are memoised and never run per keystroke
  • Browsers: All modern browsers (Chrome, Firefox, Safari, Edge); works offline once the page has loaded

Pro Tips

  • Set the Background field to your real surface colour before reading contrast grades — the same palette is AA on white and Fail on a mid-grey card.
  • Lock your brand colours first, then press Generate: the sampler builds the rest of the palette around whatever you kept.
  • If you need more than eight categories, stop adding colours and add shape, pattern or direct labelling instead — even full-vision viewers struggle past eight series.
  • Raise the greyscale threshold when the output will be photocopied or screenshotted in black and white; lower it when you need many colours and print is not a concern.
  • Use the preview severity slider at 40–70% to see what anomalous trichromats (the majority of CVD users) experience; the pass/fail checks always stay at the 100% worst case.
  • Avoid red and green as the only difference in status indicators. Blue/orange (Okabe–Ito) or blue/red (IBM) keeps the semantics for protan and deutan viewers.
  • For ordered data use viridis and treat it as a ramp, not a categorical set — its stops are deliberately adjacent in lightness.
  • Paste the share link into your PR or design-system docs so reviewers land on the exact palette, thresholds and background you validated.

Share This Tool

Found this tool helpful? Share it with others who might benefit from it!

💡 Help others discover useful tools! Sharing helps us keep these tools free and accessible to everyone.

Support This Project

Buy Me a Coffee