wcag_vision
wcag_vision helps you build accessible Flutter apps: check color contrast, preview how colors look under color blindness, and pull the dominant colors out of any image - no accessibility background needed to get started.
An offline, algorithmic WCAG accessibility engine — pure Dart, no Flutter dependency. It runs anywhere Dart runs (CLI tools, servers, web, and Flutter apps alike) and computes colour contrast exactly as specified by WCAG 2.1 — no network calls, no heuristics, just the spec's own math as pure, deterministic functions.
Using it from Flutter
Because this package has no Flutter dependency, it represents colours with
its own WcagColor rather than dart:ui's
Color. Converting between the two at your app's UI boundary is a
one-line, lossless operation, since both share the same component model
(straight alpha, each channel a double in [0, 1]):
import 'package:flutter/material.dart' as material;
import 'package:wcag_vision/wcag_vision.dart';
WcagColor toWcagColor(material.Color c) =>
WcagColor.from(alpha: c.a, red: c.r, green: c.g, blue: c.b);
material.Color toFlutterColor(WcagColor c) =>
material.Color.from(alpha: c.a, red: c.r, green: c.g, blue: c.b);
See example/lib/main.dart for this conversion used throughout a real
Flutter screen.
What it implements
The colour extraction module:
- K-means dominant-colour extraction —
extractDominantColorsruns deterministic Lloyd's k-means with seeded k-means++ initialisation (Arthur & Vassilvitskii, 2007) over sRGB, with configurable cluster count, convergence controls, and stratified random downsampling (one seeded draw per grid cell — alias-free on periodic patterns, reproducible via the seed) for full-resolution photos. Clustering runs in sRGB today; OKLab is the named target for a future perceptual-clustering refinement.extractDominantColorsAsyncruns the same extraction off the main isolate viaIsolate.run— designed for one-shot, single-capture analysis (tap → analyse one still frame); continuous per-frame streaming is out of scope by design.
The CVD simulation module:
- Colour vision deficiency simulation — protanopia, deuteranopia, and
tritanopia via
simulateCvd, using the physiologically-based model of Machado, Oliveira & Fairchild (2009) (severity-1.0 matrices, applied in linear RGB). Greys are invariant,CvdType.noneis the identity, and alpha passes through untouched.
The contrast module, covering:
- Relative luminance — the WCAG 2.x definition
(§ relative luminance),
including the sRGB linearization transfer function with the spec's published
0.03928threshold. - Contrast ratio —
(L1 + 0.05) / (L2 + 0.05)(§ contrast ratio), symmetric, bounded to[1.0, 21.0]. - AA / AAA conformance — thresholds from Success Criteria 1.4.3 Contrast (Minimum) and 1.4.6 Contrast (Enhanced), for both normal and large text.
- Semi-transparent colours — WCAG contrast is only defined for opaque colours, so translucent foregrounds are alpha-composited (Porter–Duff source-over) onto the background before measuring, matching browser and mainstream-tooling behaviour.
| Level | Normal text | Large text |
|---|---|---|
| AA | ≥ 4.5 : 1 | ≥ 3.0 : 1 |
| AAA | ≥ 7.0 : 1 | ≥ 4.5 : 1 |
Usage
import 'package:wcag_vision/wcag_vision.dart';
void main() {
const foreground = WcagColor(0xFF767676); // mid grey
const background = WcagColor(0xFFFFFFFF); // white
final report = evaluateContrast(foreground, background);
print(report.ratio); // ~4.54
print(report.passesAaNormal); // true (>= 4.5)
print(report.passesAaaNormal); // false (< 7.0)
// Translucent foregrounds are flattened onto the background first:
const overlay = WcagColor.from(alpha: 0.5, red: 0, green: 0, blue: 0);
final overlayReport = evaluateContrast(overlay, background);
print(overlayReport.ratio); // contrast of the *effective* blended colour
}
Lower-level primitives (relativeLuminance, contrastRatio,
compositeOver, wcagThreshold) are also exported for callers that need
the raw calculations.
Design principles
- Fully offline and algorithmic — no data collection, no network access.
- Pure Dart, no Flutter dependency — usable from CLI tools and servers, not just Flutter apps.
- Pure functions with deterministic outputs, unit-tested against reference values from the WCAG spec.
- Part of a Melos monorepo; consumed by the
a11y_scannerapp the same way any external user would consume it.
Libraries
- wcag_vision
- wcag_vision — an offline, algorithmic WCAG accessibility engine.