Color Blindness Simulator
Preview a palette or an image as protanopia, deuteranopia and tritanopia render it — entirely on this device.
Paste up to 64 colors to see how they render and which pairs collapse.
Paste up to 64 colors to see how they render and which pairs collapse.
Paste up to 64 colors to see how they render and which pairs collapse.
At-risk and collapsed pairs are listed here once there are colors to compare.
- This is a matrix approximation of average anomalous trichromacy from the Machado 2009 model, not a medical statement about any individual.
- The matrices are applied in linearized sRGB, then re-encoded for display.
- Pairs are compared by Euclidean distance in OKLab. OKLab has no ratified just-noticeable-difference, so this tool states its own: ΔE 0.02 or less reads as collapsed, 0.05 or less as at risk.
Press ? for shortcuts
Do it offline:$ node -e "const c=require('culori');console.log(c.formatHex(c.filterDeficiencyDeuter(1)(c.parse('#ff0000'))))"
How to use it
- Paste colors one per line. Commas, semicolons and stylesheet lines such as --brand: #3b82f6; all split, and a bare 3b82f6 is accepted.
- Pick a type: protanopia is a red-cone deficiency, deuteranopia a green-cone one, tritanopia a blue-cone one — three matrices, not one effect at three strengths.
- Drag severity from an exact no-op at 0 to the full dichromatic matrix at 1, and watch a pair converge rather than guessing at the endpoint.
- Read the collision rail: pairs inside the printed thresholds arrive with both distances.
- Switch to image mode for a screenshot. Original and simulated sit side by side; the palette text is what you copy.
Paste a palette or drop in a screenshot and see it re-rendered the way protanopia, deuteranopia and tritanopia render it, at any severity. The collision rail names the pairs that stop being two colors. Pixels are read in this tab by your own browser: nothing is uploaded, and no image ever rides a shared link.
How it works
Bytes are linearized with the transfer function in CSS Color 4, multiplied by a 3×3 matrix, clamped back into the [0,1] cube, re-encoded and rounded once — linearized sRGB is the space the published matrices are defined over.
Machado, Oliveira and Fernandes published eleven matrices per deficiency, severity 0.0 to 1.0 in steps of 0.1. A severity between two rows is a straight blend of them, so the slider never snaps to a tenth.
For collisions both simulated colors go to OKLab and the plain Euclidean distance is taken: 0.02 or less is collapsed, 0.05 or less at risk. OKLab has no ratified just-noticeable difference, so those are this page's stated numbers.
Examples
#e74c3c
#2ecc71#e74c3c → #9f8f36
#2ecc71 → #baae77The stock red-and-green pairing loses most of its separation: 0.3492 before, 0.1070 after — still twice the at-risk threshold, so nothing is flagged.
#c02020
#408000#c02020 → #7c6f17
#408000 → #7d6f17Collapse: 0.2851 falls to 0.0017 and the swatches differ by one unit in one channel.
#ff0000#ff0000 → #c37600Half severity interpolates between neighbouring published rows rather than rounding to one. The same red at severity 1 is #a39000.
#00ff00#00ff00 → #ffe500Pure green leaves the sRGB cube here, so two channels are clamped and the page says which entry and how many.
#0000ff#0000ff → #006b96Tritanopia is the one that moves blues: pure blue gains green, so a blue-only status palette can read as teal here.
--brand: #3b82f6;
--accent: #10b981;#3b82f6 → #418efa
#10b981 → #b6aa7eCustom-property lines paste straight from a stylesheet: the names are listed as skipped tokens, the blue barely moves, the green turns sandy.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
Grays never move
Every matrix row sums to one, so equal channels come back identical: #888888, #ffffff and #000000 never move, at any severity.
Severity 0 is an exact no-op
The first published row is the identity matrix, and the byte round-trip through linearize and re-encode is exact for all 256 values, so 0 returns your input unchanged.
Translucent entries are matted over white
One swatch names one color, so rgba(231, 76, 60, 0.5) is composited over #ffffff before the matrix and the page says so; your alpha is kept and never transformed. Image pixels keep their alpha, and fully transparent ones are skipped.
What the parser refuses to guess
The keyword transparent has no color to preview, so it is listed as skipped. Notations outside the grammar, display-p3 and lab() among them, are named as unrecognized rather than reinterpreted.
Image mode is a preview, not an export
Animated GIF and APNG contribute their first frame only, and large rasters are downscaled for display. Copy and download hand you the palette text, not an image file.
Why the command line prints a different hex
The one-liner below applies the same matrix with culori, which multiplies gamma-encoded channels, and prints #5e4700 for pure red. This page linearizes first and prints #a39000. Same matrix, different space; the numbers are not interchangeable.
Common errors
Palette is 4,800 characters — larger than the 4,096-character limit.- Past the 4,096-character limit the pane refuses instead of truncating: a silently shortened palette is a wrong answer. The usual cause is a pasted stylesheet.
Palette has 70 colors — more than the 64-color limit.- Collision checking compares every surviving pair, so the cap keeps the rail readable. Split a token set into the groups you place next to each other.
No color found — enter hex (3/4/6/8 digits), rgb(), hsl(), oklch(), or CSS color names, one per line.- Nothing in the pane parsed. Each unusable token is listed on its own as well — usually a stray label, a variable name, or an unsupported notation.
`color(display-p3 1 0 0)` is not a valid color — expected hex (3/4/6/8 digits), rgb(), hsl(), oklch(), or a CSS color name.- These matrices are defined over sRGB primaries, so accepting a wide-gamut color would simulate something you did not give.
FAQ
Does this tell me whether someone has color blindness?
No. It is a matrix approximation of average anomalous trichromacy from a 2009 graphics paper, not a medical statement and not a portrait of any individual's vision. Diagnosis needs a clinician.
Why does another simulator give me different hex values?
Usually the space the matrix is applied in. Multiplying gamma-encoded bytes is common and cheap; this page linearizes first. Pure red is #5e4700 one way, #a39000 this way.
Which color pairs count as a collision?
Pairs whose OKLab distance after simulation is 0.02 or less are called collapsed, 0.05 or less at risk. Both numbers are printed so you can argue with them; #888888 and #8f8f8f measure 0.0233.
Is the image I drop in uploaded anywhere?
No. Your browser decodes the file and transforms the pixels in this tab, so a network panel stays empty. A shared link carries your palette text and settings only, never image data.
Can it fix a palette that fails?
Not here. Recoloring is a design decision with brand and hierarchy attached. This page supplies the evidence: which pairs collapse, under which type, by how much.