vork by Voyager
An agent writes a scene as code, renders it on the GPU, looks at the result and revises the code. Source-available and free during the research preview.
Check WCAG 2.2 contrast for every pair in a palette, apply perceptual OKLCH fixes and simulate color vision deficiencies.
DesignTypeScript · CSSGitHub @ult666666OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
WCAG 2.2 contrast checks, OKLCH color fixes, color-vision-deficiency simulation and palette audits: a TypeScript library, a CI-ready CLI and a web app.
Translation pending
Loading the full README.
Read the full README ↗Check colors against WCAG 2.2 contrast, fix failing pairs by changing their OKLCH lightness, and simulate color vision deficiencies. contrastkit is a TypeScript library with no runtime dependencies, a command-line tool for CI pipelines, and a web app called Palette Auditor.
Open Palette Auditor to edit a palette, see the contrast of every pair and apply suggested fixes. The address bar holds the palette, so a link reopens it.
contrastkit is not on npm. Install the library and the contrastkit command from the GitHub
release, which also attaches a SHA-256 checksum (Node 22 or newer):
npm install https://github.com/ult666666/contrastkit/releases/download/v0.2.0/contrastkit-0.2.0.tgz
npx contrastkit check 777 fff
To build from source, clone the repository and run npm ci && npm run build.
import {
auditPalette,
checkContrast,
formatHex,
formatRatio,
simulateCvd,
suggestFix,
} from 'contrastkit';
const result = checkContrast('#777777', '#ffffff');
console.log(`#777777 on white: ${formatRatio(result.ratio)}, AA text: ${result.aaText}`);
const fix = suggestFix('#777777', '#ffffff', { level: 'AA' });
if (fix.status === 'fixed') {
const [best] = fix.candidates;
console.log(
`closest AA fix: ${best.hex} (${formatRatio(best.ratio)}, ΔE_OK ${best.deltaE.toFixed(3)})`,
);
}
console.log(
`#c53030 with deuteranopia looks like ${formatHex(simulateCvd('#c53030', 'deuteranopia'))}`,
);
const audit = auditPalette({
text: '#1f2933',
surface: '#ffffff',
success: '#2f855a',
danger: '#c53030',
});
for (const { type, a, b, deltaE } of audit.cvdConfusions) {
console.log(`hard to tell apart with ${type}: ${a} / ${b} (ΔE_OK ${deltaE.toFixed(3)})`);
}
$ node examples/library.mjs
#777777 on white: 4.47:1, AA text: false
closest AA fix: #767676 (4.54:1, ΔE_OK 0.003)
#c53030 with deuteranopia looks like #82752a
hard to tell apart with deuteranopia: success / danger (ΔE_OK 0.063)
Ratios are truncated for display (4.478… shows as 4.47:1), so a value just below a threshold never looks like a pass.
Anomalous trichromacy takes a severity from 0 (typical vision) to 1 (the matching dichromacy):
formatHex(simulateCvd('#c53030', 'deuteranomaly', 0.3)); // '#a7572c'
formatHex(simulateCvd('#c53030', 'deuteranomaly', 0.6)); // '#93682b'
formatHex(simulateCvd('#c53030', 'deuteranomaly', 1)); // '#82752a', same as 'deuteranopia'
auditPalette(palette, { cvdTypes: [{ type: 'deuteranomaly', severity: 0.6 }] });
Run it from the repository with npx contrastkit. Hex colors may omit the #, because an
unquoted # starts a comment in most shells.
$ npx contrastkit check 777 fff
#777777 on #ffffff: 4.47:1
FAIL AA normal text needs 4.5:1
PASS AA large text needs 3:1
FAIL AAA normal text needs 7:1
FAIL AAA large text needs 4.5:1
PASS AA non-text UI needs 3:1
Fails AA for normal text: 4.47:1 is below 4.5:1.
$ npx contrastkit fix 2f80ed fff --level AAA
#2f80ed on #ffffff: 3.86:1, target 7:1 (AAA for normal text)
Suggestions, closest first (only OKLCH lightness changes):
1. #0053bd 7.06:1 ΔE_OK 0.140 darker oklch(46.92% 0.1807 258.87)
Closest fix: #0053bd
| Command | Options |
|---|---|
contrastkit check <fg> <bg> | --level AA|AAA, --large, --target <ratio>, --cvd <sim>, --json |
contrastkit fix <fg> <bg> | --level AA|AAA, --large, --target <ratio>, --json |
contrastkit audit <tokens.json> | --require AA|AAA, --cvd <sim>, --json |
--cvd takes a dichromacy (deuteranopia) or an anomalous trichromacy with a severity
(deuteranomaly:0.6) and can be repeated. check then adds the simulated pair and its color
difference; the WCAG checks always use the colors as given:
$ npx contrastkit check 2f855a c53030 --cvd deuteranomaly:0.6 --cvd deuteranopia
...
Color vision simulation (Machado et al. 2009; the checks use the actual colors)
deuteranomaly:0.6 #6e785c on #93682b ΔE_OK 0.076 (typical vision 0.269)
deuteranopia #78735d on #82752a ΔE_OK 0.063 (typical vision 0.269)
Exit codes: 0 passed (or a fix was found), 1 a check failed or no fix reaches the target,
2 invalid usage or input. On a terminal the output includes 24-bit color swatches; set
NO_COLOR=1 to turn them off.
Describe your colors and the pairs that must pass in a tokens file, like
examples/tokens.json, and audit it:
This is the beginning of the README. Read the rest at the original. Read the full README ↗