Pixel's Design Studio
APCA Color Tokens
Build a semantic color palette. Every pair is measured with APCA — not a ratio, but a perceptual contrast value mapped to what you can actually set in type. Export as W3C Design Tokens with OKLCh values.
Palette
Each text/accent token shows its APCA Lc value against every surface token. Green = body text safe (Lc 75+). Blue = content text (Lc 60+). Yellow = large text only (Lc 45+). Click a hex value to edit it.
Add token
Contrast matrix
Every text and accent token tested against every surface. Green cells pass for body text (Lc 75+). Yellow for headlines only (Lc 45+). Red means this pair should not carry text.
| text / surface | default | subtle |
|---|---|---|
| text-primary | Aa Lc +103 | Aa Lc +98 |
| text-secondary | Aa Lc +91 | Aa Lc +86 |
| text-muted | Aa Lc +73 | Aa Lc +67 |
| accent-primary | Aa Lc +88 | Aa Lc +83 |
Export
{
"text-primary": {
"$value": "oklch(0.190 0.0040 106.8)",
"$type": "color",
"$description": "text token — hex: #141412, oklch(0.190 0.0040 106.8)",
"$extensions": {
"com.pixel.apca": {
"pairs": {
"surface-default": {
"lc": 103.2,
"absLc": 103.2,
"polarity": "normal"
},
"surface-subtle": {
"lc": 97.5,
"absLc": 97.5,
"polarity": "normal"
}
}
},
"com.pixel.hex": "#141412",
"com.pixel.role": "text"
}
},
"text-secondary": {
"$value": "oklch(0.359 0.0034 106.6)",
"$type": "color",
"$description": "text token — hex: #3d3d3b, oklch(0.359 0.0034 106.6)",
"$extensions": {
"com.pixel.apca": {
"pairs": {
"surface-default": {
"lc": 91.5,
"absLc": 91.5,
"polarity": "normal"
},
"surface-subtle": {
"lc": 85.8,
"absLc": 85.8,
"polarity": "normal"
}
}
},
"com.pixel.hex": "#3d3d3b",
"com.pixel.role": "text"
}
},
"text-muted": {
"$value": "oklch(0.527 0.0046 106.6)",
"$type": "color",
"$description": "text token — hex: #6b6b68, oklch(0.527 0.0046 106.6)",
"$extensions": {
"com.pixel.apca": {
"pairs": {
"surface-default": {
"lc": 73.2,
"absLc": 73.2,
"polarity": "normal"
},
"surface-subtle": {
"lc": 67.5,
"absLc": 67.5,
"polarity": "normal"
}
}
},
"com.pixel.hex": "#6b6b68",
"com.pixel.role": "text"
}
},
"surface-default": {
"$value": "oklch(1.000 0.0000 89.9)",
"$type": "color",
"$description": "surface token — hex: #ffffff, oklch(1.000 0.0000 89.9)",
"$extensions": {
"com.pixel.apca": {},
"com.pixel.hex": "#ffffff",
"com.pixel.role": "surface"
}
},
"surface-subtle": {
"$value": "oklch(0.970 0.0013 106.4)",
"$type": "color",
"$description": "surface token — hex: #f5f5f4, oklch(0.970 0.0013 106.4)",
"$extensions": {
"com.pixel.apca": {},
"com.pixel.hex": "#f5f5f4",
"com.pixel.role": "surface"
}
},
"accent-primary": {
"$value": "oklch(0.388 0.0410 237.3)",
"$type": "color",
"$description": "accent token — hex: #2f4858, oklch(0.388 0.0410 237.3)",
"$extensions": {
"com.pixel.apca": {
"pairs": {
"surface-default": {
"lc": 88.5,
"absLc": 88.5,
"polarity": "normal"
},
"surface-subtle": {
"lc": 82.8,
"absLc": 82.8,
"polarity": "normal"
}
}
},
"com.pixel.hex": "#2f4858",
"com.pixel.role": "accent"
}
}
}W3C Design Tokens format uses $value/$type convention with OKLCh as the color space. APCA pair data lives in $extensions for tooling that understands perceptual contrast.
Why OKLCh + APCA
OKLCh is perceptually uniform
Unlike HSL, equal steps in OKLCh lightness look like equal steps to humans. Your design tokens describe colors the way people see them — not the way sRGB encodes them.
APCA replaces guesswork
WCAG 2.x says 4.5:1 for "normal" text and 3:1 for "large." APCA maps contrast to specific size/weight pairs. You know exactly which tokens work for 14px/400 vs 48px/700.
Tokens carry intent
A token named text-primary with APCA data in $extensions tells your system: this color is safe for body text on these surfaces. The spec travels with the value.