How Color Luminance Calculation Works for Accessibility Checks in Design.md
The Design.md CLI computes WCAG-relative luminance by linearizing sRGB gamma curves, applying ITU-R BT.709 coefficients, and storing the result for contrast ratio calculations against accessibility standards.
The Design.md CLI includes built-in accessibility validation that relies on precise color luminance calculation to enforce WCAG contrast guidelines. When the linter parses CSS color strings, it calculates a linear luminance value for every token to determine whether text remains readable against its background. This computation follows the W3C standard for sRGB color space conversion, ensuring that accessibility checks align with industry-recognized specifications.
The WCAG Luminance Algorithm
Linearizing sRGB Channels
The algorithm first converts 8-bit RGB values (0-255) into linear light by undoing the sRGB gamma curve. Each channel is normalized to the range 0-1 by dividing by 255.
If the normalized value s is less than or equal to 0.03928, the linear value equals s / 12.92. Otherwise, the CLI applies the inverse gamma correction: ((s + 0.055) / 1.055) ^ 2.4.
This transformation is essential because human perception of light is non-linear, and the WCAG formula requires linear RGB values to calculate accurate relative luminance.
Applying Luminance Coefficients
After linearization, the CLI combines the red, green, and blue channels using the ITU-R BT.709 coefficients that represent human eye sensitivity to each primary color:
L = 0.2126·Rlin + 0.7152·Glin + 0.0722·Blin
The resulting value L ranges from 0 (pure black) to 1 (pure white). This weighted sum produces the relative luminance that the WCAG guidelines specify for contrast calculations.
Implementation in the Design.md Source Code
The Design.md CLI implements this algorithm across two core TypeScript files.
In packages/cli/src/linter/model/color-parser.ts, the computeLuminance function (lines 96-102) handles the mathematical conversion. This routine takes parsed RGB values, applies the sRGB linearization logic, and returns the final luminance value.
The packages/cli/src/linter/model/handler.ts file exposes the contrastRatio function (lines 400-404), which consumes these pre-computed luminance values to determine accessibility compliance between color pairs.
Calculating Contrast Ratios
Once luminance values are stored in the ParsedColorResult.luminance property (as defined in the ResolvedColor interface in spec.ts), the CLI calculates contrast ratios using the WCAG formula:
ratio = (max(L1, L2) + 0.05) / (min(L1, L2) + 0.05)
This calculation adds a 0.05 offset to prevent division by zero and to account for viewing environment flare. The resulting ratio determines compliance levels:
- 4.5:1 or greater meets WCAG AA for normal text
- 3:1 or greater meets WCAG AA for large text (18pt+ or 14pt+ bold)
Practical Usage Examples
The following TypeScript examples demonstrate how to access luminance values and verify contrast ratios using the Design.md CLI internals:
import { parseCssColor } from './linter/model/color-parser.js';
import { contrastRatio } from './linter/model/handler.js';
// Example 1 – Getting the luminance of a colour
const red = parseCssColor('rgb(255 0 0)');
// red.luminance ≈ 0.2126
console.log('Red luminance:', red.luminance);
// Example 2 – Checking contrast against white
const white = parseCssColor('#ffffff');
const ratio = contrastRatio(red, white);
// ratio ≈ (1 + 0.05) / (0.2126 + 0.05) ≈ 4.0
console.log('Contrast red ↔ white:', ratio.toFixed(2));
// Example 3 – Using the CLI helper (the same logic runs internally)
if (ratio < 4.5) {
console.warn('Insufficient contrast for normal text');
}
Unit tests in packages/cli/src/linter/tailwind/v4/handler.test.ts confirm these calculations, verifying that white (#ffffff) correctly yields a luminance of 1.
Summary
- The Design.md CLI computes WCAG-relative luminance by linearizing sRGB gamma curves and applying ITU-R BT.709 coefficients (0.2126, 0.7152, 0.0722).
- The
computeLuminancefunction incolor-parser.ts(lines 96-102) performs the core mathematical transformation. - Luminance values are stored in
ParsedColorResult.luminanceand reused by thecontrastRatiofunction inhandler.ts(lines 400-404). - Contrast ratios follow the formula
(max(L1, L2) + 0.05) / (min(L1, L2) + 0.05)and are checked against WCAG AA thresholds of 4.5:1 for normal text and 3:1 for large text.
Frequently Asked Questions
What is the difference between relative luminance and brightness?
Relative luminance accounts for human perception by applying gamma correction and weighted coefficients to RGB values, whereas brightness typically refers to uncorrected lightness. The Design.md CLI uses the WCAG definition of relative luminance to ensure accessibility calculations match how humans actually perceive contrast.
Why does the Design.md CLI use the ITU-R BT.709 coefficients?
These coefficients (0.2126 for red, 0.7152 for green, 0.0722 for blue) represent the human eye's varying sensitivity to different wavelengths of light. Green contributes most to perceived brightness, while blue contributes least, making these weights essential for accurate perceptual luminance calculation.
Where is the luminance value stored after parsing?
After parsing a CSS color string, the luminance value is attached to the resulting object as ParsedColorResult.luminance according to the ResolvedColor interface defined in packages/cli/src/linter/model/spec.ts. This value persists for subsequent contrast calculations without requiring recomputation.
What contrast ratio is required for WCAG AA compliance?
The CLI enforces a minimum contrast ratio of 4.5:1 for normal text and 3:1 for large text (18 points or larger, or 14 points or larger if bold) to meet WCAG AA standards. These thresholds are hardcoded into the accessibility validation logic that consumes the contrastRatio function results.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →