# How Color Luminance Calculation Works for Accessibility Checks in Design.md

> Learn how color luminance calculation ensures web accessibility. Design.md uses gamma correction and BT.709 coefficients for accurate contrast checks against WCAG standards.

- Repository: [Google Labs Code/design.md](https://github.com/google-labs-code/design.md)
- Tags: deep-dive
- Published: 2026-06-28

---

**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`](https://github.com/google-labs-code/design.md/blob/main/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`](https://github.com/google-labs-code/design.md/blob/main/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`](https://github.com/google-labs-code/design.md/blob/main/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:

```typescript
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`](https://github.com/google-labs-code/design.md/blob/main/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 `computeLuminance` function in [`color-parser.ts`](https://github.com/google-labs-code/design.md/blob/main/color-parser.ts) (lines 96-102) performs the core mathematical transformation.
- Luminance values are stored in `ParsedColorResult.luminance` and reused by the `contrastRatio` function in [`handler.ts`](https://github.com/google-labs-code/design.md/blob/main/handler.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`](https://github.com/google-labs-code/design.md/blob/main/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.