Skip to main content

Color Blindness Simulator API for Hex Colors & Palettes

REAL DATA

Simulate protanopia, deuteranopia and tritanopia on your colors with cited Brettel 1997, Viénot 1999 or Machado 2009 matrices, and flag pairs that converge.

Authoritative reference data or standards computation

Base URL
/api/color-vision
Capabilities
2 routes
Last updated
July 30, 2026
Data source

GET /api/color-vision/simulate

Decodes the colour to linear light, applies the named published matrix, clamps and re-encodes it, then reports how far the colour moved.

Live requestRuns against the public API
No key required
GET/api/color-vision/simulate?hex=%23ed002e&type=deuteranopia&model=vienot1999

Request parameters

Opaque sRGB colour in #rgb or #rrggbb notation. The # must be URL-encoded as %23. Alpha and non-hex CSS colour syntax are rejected.

Colour-vision deficiency to simulate. The -opia types are complete dichromacy; the -anomaly types are anomalous trichromacy and require model=machado2009 plus a 'severity'.

Published model to apply. brettel1997 covers all three dichromacies (and is the model the DaltonLens reference implementation picks for tritanopia); vienot1999 covers protanopia and deuteranopia only; machado2009 covers all six types and is the only one with a severity. Required because the models genuinely disagree.

Machado 2009 severity from 0 (normal vision) to 1 (dichromacy). Accepted only with model=machado2009 — required on the -anomaly types, and on the -opia types only as the redundant severity=1 those types already are. Values off the published 0.1 grid are interpolated and reported in meta.warnings.

Advanced response options4 options

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

Return all fields except these (comma-separated).

Pretty-print the JSON response.

Drop the envelope: return the raw array/object without data/meta wrapper.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
curl "https://randomapi.dev/api/color-vision/simulate?hex=%23ed002e&type=deuteranopia&model=vienot1999"
const res = await fetch("https://randomapi.dev/api/color-vision/simulate?hex=%23ed002e&type=deuteranopia&model=vienot1999");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/color-vision/simulate?hex=%23ed002e&type=deuteranopia&model=vienot1999").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/color-vision/simulate?hex=%23ed002e&type=deuteranopia&model=vienot1999"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 4
hex string required

Opaque sRGB colour in #rgb or #rrggbb notation. The # must be URL-encoded as %23. Alpha and non-hex CSS colour syntax are rejected.

allowed: 1 – 32
example: hex=#ed002e
type enum required

Colour-vision deficiency to simulate. The -opia types are complete dichromacy; the -anomaly types are anomalous trichromacy and require model=machado2009 plus a 'severity'.

allowed: protanopia | deuteranopia | tritanopia | protanomaly | deuteranomaly | tritanomaly
example: type=deuteranopia
model enum required

Published model to apply. brettel1997 covers all three dichromacies (and is the model the DaltonLens reference implementation picks for tritanopia); vienot1999 covers protanopia and deuteranopia only; machado2009 covers all six types and is the only one with a severity. Required because the models genuinely disagree.

allowed: brettel1997 | vienot1999 | machado2009
example: model=machado2009
severity float

Machado 2009 severity from 0 (normal vision) to 1 (dichromacy). Accepted only with model=machado2009 — required on the -anomaly types, and on the -opia types only as the redundant severity=1 those types already are. Values off the published 0.1 grid are interpolated and reported in meta.warnings.

allowed: 0 – 1
example: severity=0.4
Universal parameters Shared response and formatting options 4
fields list

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

example: fields=input,model
exclude list

Return all fields except these (comma-separated).

example: exclude=clippedChannels
pretty boolean

Pretty-print the JSON response.

default: false
example: pretty=true
unwrap boolean

Drop the envelope: return the raw array/object without data/meta wrapper.

default: false
example: unwrap=true
Response schema Fields returned in each record 9
input string (hex color)

Canonical lowercase six-digit form of the colour you supplied.

example: #ed002e

model string

Model actually applied: brettel1997, vienot1999 or machado2009.

example: machado2009

type string

Canonical colour-vision-deficiency type that was simulated.

example: deuteranopia

severity float nullable

Machado 2009 severity used (1 for the -opia types). Null for brettel1997 and vienot1999, which define no severity parameter.

example: 1

simulatedHex string (hex color)

Simulated colour, re-encoded to lowercase six-digit sRGB hex.

example: #968623

simulatedRgb object

Simulated colour as 8-bit sRGB channels: r, g and b from 0 through 255.

example: {"r":150,"g":134,"b":35}

deltaFromOriginal float (CIEDE2000)

CIEDE2000 difference between the input and the returned simulated colour, rounded to 4 decimals. 0 means the model leaves the colour unchanged.

example: 45.7212

contrastAgainstOriginal float (1-21)

WCAG 2.2 contrast ratio between the input and the simulated colour, rounded to 4 decimals — how much apparent lightness the model removed.

example: 1.2351

clippedChannels string[]

Linear-light channels ('red', 'green', 'blue') pushed more than 2e-5 outside [0, 1] by the model and then clamped; empty when the simulated colour is inside the sRGB gamut.

example: []

Documented examples

Build-generated requests and complete responses
5
Deuteranopia on a status red
GET /api/color-vision/simulate?hex=%23ed002e&type=deuteranopia&model=vienot1999
{
  "data": {
    "input": "#ed002e",
    "model": "vienot1999",
    "type": "deuteranopia",
    "severity": null,
    "simulatedHex": "#888817",
    "simulatedRgb": {
      "r": 136,
      "g": 136,
      "b": 23
    },
    "deltaFromOriginal": 51.6696,
    "contrastAgainstOriginal": 1.2027,
    "clippedChannels": []
  },
  "meta": {
    "endpoint": "color-vision",
    "route": "/simulate",
    "params": {
      "hex": "#ed002e",
      "type": "deuteranopia",
      "model": "vienot1999"
    },
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
Machado 2009 protanopia on pure red
GET /api/color-vision/simulate?hex=%23ff0000&type=protanopia&model=machado2009
{
  "data": {
    "input": "#ff0000",
    "model": "machado2009",
    "type": "protanopia",
    "severity": 1,
    "simulatedHex": "#6d5f00",
    "simulatedRgb": {
      "r": 109,
      "g": 95,
      "b": 0
    },
    "deltaFromOriginal": 42.395,
    "contrastAgainstOriginal": 1.5977,
    "clippedChannels": [
      "blue"
    ]
  },
  "meta": {
    "endpoint": "color-vision",
    "route": "/simulate",
    "params": {
      "hex": "#ff0000",
      "type": "protanopia",
      "model": "machado2009",
      "severity": 1
    },
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
Mild deuteranomaly at severity 0.4
GET /api/color-vision/simulate?hex=%232e7d32&type=deuteranomaly&model=machado2009&severity=0.4
{
  "data": {
    "input": "#2e7d32",
    "model": "machado2009",
    "type": "deuteranomaly",
    "severity": 0.4,
    "simulatedHex": "#617335",
    "simulatedRgb": {
      "r": 97,
      "g": 115,
      "b": 53
    },
    "deltaFromOriginal": 10.5003,
    "contrastAgainstOriginal": 1.0209,
    "clippedChannels": []
  },
  "meta": {
    "endpoint": "color-vision",
    "route": "/simulate",
    "params": {
      "hex": "#2e7d32",
      "type": "deuteranomaly",
      "model": "machado2009",
      "severity": 0.4
    },
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
Tritanopia with the Brettel 1997 two-plane model
GET /api/color-vision/simulate?hex=%230096ff&type=tritanopia&model=brettel1997
{
  "data": {
    "input": "#0096ff",
    "model": "brettel1997",
    "type": "tritanopia",
    "severity": null,
    "simulatedHex": "#00a4ca",
    "simulatedRgb": {
      "r": 0,
      "g": 164,
      "b": 202
    },
    "deltaFromOriginal": 15.4477,
    "contrastAgainstOriginal": 1.0524,
    "clippedChannels": [
      "red"
    ]
  },
  "meta": {
    "endpoint": "color-vision",
    "route": "/simulate",
    "params": {
      "hex": "#0096ff",
      "type": "tritanopia",
      "model": "brettel1997"
    },
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
The same tritanopia through Machado 2009, caveat included
GET /api/color-vision/simulate?hex=%230096ff&type=tritanopia&model=machado2009
{
  "data": {
    "input": "#0096ff",
    "model": "machado2009",
    "type": "tritanopia",
    "severity": 1,
    "simulatedHex": "#00b0be",
    "simulatedRgb": {
      "r": 0,
      "g": 176,
      "b": 190
    },
    "deltaFromOriginal": 24.5306,
    "contrastAgainstOriginal": 1.1685,
    "clippedChannels": [
      "red"
    ]
  },
  "meta": {
    "endpoint": "color-vision",
    "route": "/simulate",
    "params": {
      "hex": "#0096ff",
      "type": "tritanopia",
      "model": "machado2009",
      "severity": 1
    },
    "generatedAt": "2026-07-30T15:14:08.000Z",
    "warnings": [
      "Machado, Oliveira & Fernandes (2009) tabulate the tritan axis, but the DaltonLens reference implementation of this model records that it is unreliable for tritanopia and always selects Brettel, Viénot & Mollon (1997) on this axis. Use model=brettel1997 for a tritanopia result; machado2009 is the only model here that can grade tritanomaly by severity."
    ]
  }
}

GET /api/color-vision/palette

Applies one model to a whole palette, then compares every unordered pair with CIEDE2000 before and after simulation.

Live requestRuns against the public API
No key required
GET/api/color-vision/palette?colors=%23ed002e%2C%2300a000&type=deuteranopia&model=vienot1999

Request parameters

2–8 distinct opaque sRGB colours in #rgb or #rrggbb notation, comma-separated. Encode each # as %23.

Colour-vision deficiency to simulate. The -opia types are complete dichromacy; the -anomaly types are anomalous trichromacy and require model=machado2009 plus a 'severity'.

Published model to apply. brettel1997 covers all three dichromacies (and is the model the DaltonLens reference implementation picks for tritanopia); vienot1999 covers protanopia and deuteranopia only; machado2009 covers all six types and is the only one with a severity. Required because the models genuinely disagree.

Machado 2009 severity from 0 (normal vision) to 1 (dichromacy). Accepted only with model=machado2009 — required on the -anomaly types, and on the -opia types only as the redundant severity=1 those types already are. Values off the published 0.1 grid are interpolated and reported in meta.warnings.

CIEDE2000 distance below which a simulated pair is reported indistinguishable. This API's convention, not a standard threshold — it is echoed in every response.

Advanced response options4 options

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

Return all fields except these (comma-separated).

Pretty-print the JSON response.

Drop the envelope: return the raw array/object without data/meta wrapper.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
curl "https://randomapi.dev/api/color-vision/palette?colors=%23ed002e,%2300a000&type=deuteranopia&model=vienot1999"
const res = await fetch("https://randomapi.dev/api/color-vision/palette?colors=%23ed002e,%2300a000&type=deuteranopia&model=vienot1999");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/color-vision/palette?colors=%23ed002e,%2300a000&type=deuteranopia&model=vienot1999").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/color-vision/palette?colors=%23ed002e,%2300a000&type=deuteranopia&model=vienot1999"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 5
colors list required

2–8 distinct opaque sRGB colours in #rgb or #rrggbb notation, comma-separated. Encode each # as %23.

example: colors=#ed002e,#00a000
type enum required

Colour-vision deficiency to simulate. The -opia types are complete dichromacy; the -anomaly types are anomalous trichromacy and require model=machado2009 plus a 'severity'.

allowed: protanopia | deuteranopia | tritanopia | protanomaly | deuteranomaly | tritanomaly
example: type=deuteranopia
model enum required

Published model to apply. brettel1997 covers all three dichromacies (and is the model the DaltonLens reference implementation picks for tritanopia); vienot1999 covers protanopia and deuteranopia only; machado2009 covers all six types and is the only one with a severity. Required because the models genuinely disagree.

allowed: brettel1997 | vienot1999 | machado2009
example: model=machado2009
severity float

Machado 2009 severity from 0 (normal vision) to 1 (dichromacy). Accepted only with model=machado2009 — required on the -anomaly types, and on the -opia types only as the redundant severity=1 those types already are. Values off the published 0.1 grid are interpolated and reported in meta.warnings.

allowed: 0 – 1
example: severity=0.4
threshold float

CIEDE2000 distance below which a simulated pair is reported indistinguishable. This API's convention, not a standard threshold — it is echoed in every response.

default: 5
allowed: 0 – 100
example: threshold=2
Universal parameters Shared response and formatting options 4
fields list

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

example: fields=model,type
exclude list

Return all fields except these (comma-separated).

example: exclude=indistinguishablePairs
pretty boolean

Pretty-print the JSON response.

default: false
example: pretty=true
unwrap boolean

Drop the envelope: return the raw array/object without data/meta wrapper.

default: false
example: unwrap=true
Response schema Fields returned in each record 7
model string

Model applied to every colour in the palette.

example: vienot1999

type string

Canonical colour-vision-deficiency type that was simulated.

example: deuteranopia

severity float nullable

Machado 2009 severity used (1 for the -opia types). Null for vienot1999, which defines no severity parameter.

example: null

threshold float (CIEDE2000)

Distance used for the indistinguishable verdict on this request.

example: 5

colors object[]

Per-colour simulation in input order: input, simulatedHex, simulatedRgb, deltaFromOriginal, contrastAgainstOriginal and clippedChannels.

example: [{"input":"#ed002e","simulatedHex":"#888817","simulatedRgb":{"r":136,"g":136,"b":23},"deltaFromOriginal":51.6696,"contrastAgainstOriginal":1.2027,"clippedChannels":[]},{"input":"#00a000","simulatedHex":"#898916","simulatedRgb":{"r":137,"g":137,"b":22},"deltaFromOriginal":19.4091,"contrastAgainstOriginal":1.0663,"clippedChannels":[]}]

pairs object[]

Every unordered pair of canonical input colours with its CIEDE2000 distance before and after simulation, and whether the simulated distance is strictly below the threshold.

example: [{"a":"#ed002e","b":"#00a000","originalDistance":78.4845,"simulatedDistance":0.3963,"indistinguishable":true}]

indistinguishablePairs integer

How many pairs were flagged — the number to assert on in CI.

example: 1

Documented examples

Build-generated requests and complete responses
4
Red and green status badges under deuteranopia
GET /api/color-vision/palette?colors=%23ed002e,%2300a000&type=deuteranopia&model=vienot1999
{
  "data": {
    "model": "vienot1999",
    "type": "deuteranopia",
    "severity": null,
    "threshold": 5,
    "colors": [
      {
        "input": "#ed002e",
        "simulatedHex": "#888817",
        "simulatedRgb": {
          "r": 136,
          "g": 136,
          "b": 23
        },
        "deltaFromOriginal": 51.6696,
        "contrastAgainstOriginal": 1.2027,
        "clippedChannels": []
      },
      {
        "input": "#00a000",
        "simulatedHex": "#898916",
        "simulatedRgb": {
          "r": 137,
          "g": 137,
          "b": 22
        },
        "deltaFromOriginal": 19.4091,
        "contrastAgainstOriginal": 1.0663,
        "clippedChannels": []
      }
    ],
    "pairs": [
      {
        "a": "#ed002e",
        "b": "#00a000",
        "originalDistance": 78.4845,
        "simulatedDistance": 0.3963,
        "indistinguishable": true
      }
    …
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
Six-colour chart palette at deuteranomaly 0.6
GET /api/color-vision/palette?colors=%234e79a7,%23f28e2b,%23e15759,%2376b7b2,%2359a14f,%23edc948&type=deuteranomaly&model=machado2009&severity=0.6
{
  "data": {
    "model": "machado2009",
    "type": "deuteranomaly",
    "severity": 0.6,
    "threshold": 5,
    "colors": [
      {
        "input": "#4e79a7",
        "simulatedHex": "#5974a6",
        "simulatedRgb": {
          "r": 89,
          "g": 116,
          "b": 166
        },
        "deltaFromOriginal": 4.2097,
        "contrastAgainstOriginal": 1.032,
        "clippedChannels": []
      },
      {
        "input": "#f28e2b",
        "simulatedHex": "#cfa729",
        "simulatedRgb": {
          "r": 207,
          "g": 167,
          "b": 41
        },
        "deltaFromOriginal": 17.4525,
        "contrastAgainstOriginal": 1.0614,
        "clippedChannels": []
      },
      {
        "input": "#e15759",
        "simulatedHex": "#ae8456",
        "simulatedRgb": {
          "r": 174,
          "g": 132,
          "b": 86
        },
        "deltaFromOriginal": 24.8938,
    …
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
Protanopia check with a widened threshold
GET /api/color-vision/palette?colors=%23d32f2f,%23388e3c,%231976d2&type=protanopia&model=vienot1999&threshold=25
{
  "data": {
    "model": "vienot1999",
    "type": "protanopia",
    "severity": null,
    "threshold": 25,
    "colors": [
      {
        "input": "#d32f2f",
        "simulatedHex": "#585831",
        "simulatedRgb": {
          "r": 88,
          "g": 88,
          "b": 49
        },
        "deltaFromOriginal": 39.505,
        "contrastAgainstOriginal": 1.4771,
        "clippedChannels": []
      },
      {
        "input": "#388e3c",
        "simulatedHex": "#88883b",
        "simulatedRgb": {
          "r": 136,
          "g": 136,
          "b": 59
        },
        "deltaFromOriginal": 16.8672,
        "contrastAgainstOriginal": 1.1037,
        "clippedChannels": []
      },
      {
        "input": "#1976d2",
        "simulatedHex": "#7070d2",
        "simulatedRgb": {
          "r": 112,
          "g": 112,
          "b": 210
        },
        "deltaFromOriginal": 13.2142,
    …
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
Brettel 1997 tritanopia on a blue-heavy palette
GET /api/color-vision/palette?colors=%230096ff,%2300b8d4,%237e57c2&type=tritanopia&model=brettel1997
{
  "data": {
    "model": "brettel1997",
    "type": "tritanopia",
    "severity": null,
    "threshold": 5,
    "colors": [
      {
        "input": "#0096ff",
        "simulatedHex": "#00a4ca",
        "simulatedRgb": {
          "r": 0,
          "g": 164,
          "b": 202
        },
        "deltaFromOriginal": 15.4477,
        "contrastAgainstOriginal": 1.0524,
        "clippedChannels": [
          "red"
        ]
      },
      {
        "input": "#00b8d4",
        "simulatedHex": "#15b7da",
        "simulatedRgb": {
          "r": 21,
          "g": 183,
          "b": 218
        },
        "deltaFromOriginal": 2.4496,
        "contrastAgainstOriginal": 1.0012,
        "clippedChannels": []
      },
      {
        "input": "#7e57c2",
        "simulatedHex": "#6a6e70",
        "simulatedRgb": {
          "r": 106,
          "g": 110,
          "b": 112"generatedAt": "2026-07-30T15:14:08.000Z"
  }
}

About this API

Coverage & behavior

Runs sRGB colors through a published, cited colour-vision-deficiency model and reports the simulated colour, how far it moved, and — on /palette — which pairs collapse into each other.

Every request must name its model, because the three implemented models genuinely disagree and silently picking one would pass a model's opinion off as the answer:

  • brettel1997 — Brettel, Viénot & Mollon (1997) project onto two half-planes per confusion axis, choosing between them per colour with a separation plane through the neutral axis. It covers all three dichromacies and is the model the public-domain DaltonLens reference implementations describe as the most solid in the literature and select for the tritan axis unconditionally. It publishes no severity, so it is dichromacy only.
  • vienot1999 — Viénot, Brettel & Mollon (1999) simplify that construction to a single projection plane, which collapses to one fixed 3×3 matrix per axis. The simplification holds on the red–green axes but not on the tritan axis: libDaltonLens ships a Viénot-style tritan matrix only with an inaccuracy warning and routes tritan to Brettel 1997, so type=tritanopia here returns a 400 pointing at model=brettel1997 rather than a plausible-looking lie.
  • machado2009 — Machado, Oliveira & Fernandes (2009) publish severity-parameterized matrices in steps of 0.1 covering all three axes, so this is the only model here that grades a deficiency. severity is required with the -anomaly types; the -opia types are complete dichromacy and always use the published severity-1 matrix, so they accept severity=1 and reject every other value. A severity that is not a multiple of 0.1 is linearly interpolated between the two bracketing published matrices, and the response says so in meta.warnings.

Machado 2009 on the tritan axis is the one result to treat carefully. The DaltonLens reference implementation of that model records it as unreliable for tritanopia and picks Brettel 1997 there instead. This API still serves machado2009 + tritanopia/tritanomaly — it is the only way to grade tritanomaly by severity — but it attaches that caveat to every such response in meta.warnings. For plain tritanopia, prefer model=brettel1997.

The pipeline is identical on both routes: parse #rgb/#rrggbb → decode sRGB to linear light at the 0.04045 breakpoint (the same linearization /api/color-contrast uses) → apply the model in linear RGB (one matrix for Viénot and Machado; for Brettel, the half-plane matrix selected by the sign of separation · rgb) → clamp to [0, 1] and record every clamped channel in clippedChannels → re-encode to 8-bit sRGB, rounded to the nearest code. deltaFromOriginal is the CIEDE2000 (CIE 142:2001) difference between the input and the returned colour, and contrastAgainstOriginal is the WCAG 2.2 contrast ratio between the same two colours. Both are rounded to 4 decimals, and both describe the 8-bit colour you actually get back rather than an unquantized intermediate.

Because the published matrices are printed to five or six decimals, a channel is only called clipped once it leaves [0, 1] by more than 2e-5 — otherwise pure white would be reported out of gamut purely from table rounding. That tolerance is under 1/400 of one 8-bit code, so no real gamut excursion hides under it.

/palette simulates 2–8 distinct colours together and compares every unordered pair, reporting originalDistance, simulatedDistance and an indistinguishable verdict whenever the simulated distance is strictly below threshold. The threshold is a number you control, not a standard: CIE 142:2001 defines the metric, not a pass/fail cut-off. The default of 5 is this API's documented convention — about five times the ~1 unit commonly cited as one just-noticeable difference — and every response echoes the exact number used.

Calibrating threshold

The default is deliberately strict, and on real design systems it mostly does not fire. Measured with this endpoint across all three models, the red/green "danger" and "success" tokens of Material 700 (#d32f2f/#388e3c), Bootstrap 5 (#dc3545/#198754), Tailwind 600 (#dc2626/#16a34a) and GitHub Primer (#cf222e/#1a7f37) all land between 5.0 and 12.0 under deuteranopia and between 11.5 and 26.8 under protanopia — outside the default, because those palettes separate red from green by lightness as well as hue, and lightness survives a red–green deficiency. A lightness-matched pair such as #ed002e/#00a000 lands between 0.08 and 0.40 and is flagged.

So: at threshold=5 a flagged pair means the two colours are genuinely almost identical to a dichromat. If you also want pairs that survive only on lightness — which still fail WCAG 2.2 §1.4.1 if colour is the sole cue — use threshold=12, which flags all four of those token pairs under deuteranopia, and read simulatedDistance rather than the boolean.

What this is not

A simulation is a model of dichromatic vision, not what any person sees. Published models disagree, people with anomalous trichromacy vary between individuals far more than any single matrix expresses, and no model here accounts for adaptation, display calibration, patch size or surround. Anomalous trichromacy is available only through Machado 2009: the DaltonLens implementations do fade a dichromat result toward the original to approximate it for Brettel and Viénot, but their author notes that blend is not backed by a strong theory, so this API does not expose it. Alpha, CSS colour names, rgb() and wide-gamut spaces are rejected rather than guessed.

The pairwise verdict addresses WCAG 2.2 §1.4.1 Use of Color — colour must not be the only visual means of conveying information — which the contrast criterion §1.4.3 structurally cannot cover: a red and a green badge can each clear 4.5:1 against the page and still be the same colour to the roughly 8% of men of Northern European descent with red–green CVD. A flagged pair is evidence for a §1.4.1 review; a clean result is not conformance, and this endpoint is not an accessibility audit.

Use it for

  • Fail a CI check when two design-token colors converge under deuteranopia
  • Simulate a status badge's red and green with a cited protanopia model before shipping
  • Screen candidate chart palettes pairwise for colors that collapse together
  • Simulate tritanopia with the Brettel 1997 two-plane model the DaltonLens reference implementation selects
  • Record the exact model, severity and threshold behind an accessibility review finding

Frequently asked questions

Which color blindness simulation model does the API use?

Whichever you name: model=brettel1997 applies the Brettel, Viénot & Mollon (1997) two-half-plane projection, model=vienot1999 its single-plane simplification, and model=machado2009 the Machado, Oliveira & Fernandes (2009) severity matrices. The parameter is required because the three genuinely disagree.

Can I simulate mild deuteranomaly rather than full color blindness?

Yes — use model=machado2009 with type=deuteranomaly and a severity from 0 to 1. Severity is rejected on brettel1997 and vienot1999, which publish no severity parameter, and the -opia types accept only the severity=1 they already are.

Which model should I use for tritanopia?

model=brettel1997. Its two half-planes are what the tritan axis needs, and the public-domain libDaltonLens reference implementation always routes tritan to it. vienot1999 returns 400 for tritan types, and machado2009 answers but attaches a meta.warnings note, because the DaltonLens implementation of that model records it as unreliable on the blue–yellow axis.

How does the API decide that two colors are indistinguishable?

/palette simulates every colour, then compares each unordered pair with the CIEDE2000 difference. A pair is flagged when its simulated distance is strictly below threshold, which defaults to 5 and is echoed in every response — that number is this API's documented convention, not a standard. Mainstream red/green design tokens measure 5–12 under deuteranopia and stay unflagged at the default; raise threshold to about 12 to catch pairs that survive on lightness alone.

Are the matrices applied to gamma-encoded sRGB or to linear light?

Linear light. Each channel is decoded with the sRGB transfer function at the 0.04045 breakpoint before the 3×3 matrix and re-encoded afterwards, following the public-domain libDaltonLens reference implementation; skipping that step is the most common bug in CVD simulators.

Does a clean result mean my palette is WCAG conformant?

No. It is evidence for a WCAG 2.2 §1.4.1 (Use of Color) review, nothing more. A simulation is a model rather than what any individual sees, and no automated check can establish conformance.

Standards & references