engine/contrast library

WCAG 2.2 contrast on 8-bit ARGB and OKLCH-lightness repair (research theme-engine.md §4, Recommendations 3–4).

Ratios are computed on the final quantised colour and are never rounded: 4.499:1 fails 4.5:1.

Classes

ContrastPolicy
Label-solving policy: floors plus the two WCAG-2 blind-spot heuristics (research §4.5). Immutable; configurable per family or Accessible lock.

Constants

alwaysReachableRatio → const double
max(CR(bg, white), CR(bg, black)) ≥ √21 for every background, so any target up to this is always reachable with black or white.
ratioAccessible → const double
WCAG AAA text (Accessible lock).
ratioLarge → const double
WCAG AA large text / non-text (1.4.11).
ratioText → const double
WCAG AA text.
yDarkFace → const double
Faces darker than this are "dark faces" (≈ L_ok 0.37).
yEqualContrast → const double
Luminance at which black and white give equal contrast: sqrt(1.05 · 0.05) − 0.05. Below it, lighter labels win.
yPolarityBandTop → const double
Upper edge of the mid-tone band where WCAG 2 over-rates dark labels (APCA's neutral polarity crossover, research §4.5).

Functions

blackOrWhite(int bgArgb) → int
Pure black or white, whichever contrasts more with bgArgb.
contrastOver(int fg, int bg) → double
Contrast of a possibly translucent fg composited over opaque bg, against bg.
contrastRatio(int a, int b) → double
Contrast ratio between two ARGB colours (alpha ignored).
contrastY(double y1, double y2) → double
Contrast ratio of two luminances, (Y_lighter + 0.05) / (Y_darker + 0.05), in 1, 21.
luminanceArgb(int argb) → double
WCAG relative luminance of an ARGB colour (alpha ignored; 0.04045 threshold via the decode table).
luminanceLin(LinRgb c) → double
WCAG relative luminance of linear sRGB.
repairPair(Lch face, Lch label, {ContrastPolicy policy = ContrastPolicy.standard}) → RepairedPair
Repairs a label/face pair to policy (research §4.3 repair order):
solveForContrast(double l0, double c, double hDeg, int bgArgb, double target) → int
solveLightness that throws when the target is unreachable.
solveLabel(int faceArgb, Lch label, {ContrastPolicy policy = ContrastPolicy.standard}) → int?
Solves a label (start colour label) on the opaque face faceArgb under policy: dark-face boost, then the polarity rule, then the plain floor. Returns null only if even the floor is unreachable at this chroma/hue (possible above 4.583:1).
solveLightness({required double l0, required double c, required double hDeg, required int againstArgb, required double target, bool? preferLighter, double? lighterFrom, double? darkerFrom}) → int?
Bisects the OKLCH lightness of a colour with chroma c and hue hDeg, starting at l0, until its quantised ARGB reaches target against againstArgb. Returns null if neither direction can reach it.

Typedefs

RepairedPair = ({int face, Lch faceLch, int label, int rounds})
A repaired (face, label) pair.