Simulation
Physiologically based Machado/Oliveira/Fernandes CVD simulation in linear-light sRGB.
const red = swatch("#ff0000");
red.simulate("protan"); // full protanopia
red.simulate("deutan", { severity: 0.6 }); // 60% deuteranomaly
red.simulate("tritan");
red.simulate("achroma"); // Rec. 709 grayscale
Accepted types
| Canonical | Aliases |
|---|---|
protan |
protanopia, protanomaly |
deutan |
deuteranopia, deuteranomaly |
tritan |
tritanopia, tritanomaly |
achroma |
achromatopsia |
The severity continuum
severity 0.0 returns the identity (the original color). 1.0 returns the
full dichromat. Values in between interpolate across the published Machado
severity table, covering milder anomalous-trichromat cases.
red.simulate("protan", { severity: 0 }); // identity
red.simulate("protan", { severity: 0.5 }); // mild protanomaly
red.simulate("protan", { severity: 1 }); // full protanopia
Walk the slider in the §02 panel of the playground to feel it live.
Images and canvas
For JPEG/PNG/WebP previews, draw the user-selected file to a <canvas>, read
the pixels, and run the batch ImageData transform:
const bitmap = await createImageBitmap(file);
canvas.width = bitmap.width;
canvas.height = bitmap.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(bitmap, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
swatch.simulateImageData(imageData, "deutan", { severity: 1 });
ctx.putImageData(imageData, 0, 0);
simulateImageData mutates in place by default and returns the same
ImageData-like object. Pass { inPlace: false } when you need a copy:
const simulated = swatch.simulateImageData(source, "protan", {
severity: 0.8,
inPlace: false,
});
The image path is optimized for throughput: sRGB byte → linear-light and linear-light → sRGB byte lookup tables are reused, the CVD matrix is computed once per image, and alpha bytes are preserved untouched. For large live previews, run it in a Web Worker or downscale the preview while the user drags a slider.
The §14 panel of the playground lets you try this locally with a user-chosen image.