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.

text-primary
oklch(0.19 0.004 107)
text
ALc +103on defaultbody
ALc +98on subtlebody
text-secondary
oklch(0.36 0.003 107)
text
ALc +91on defaultbody
ALc +86on subtlebody
text-muted
oklch(0.53 0.005 107)
text
ALc +73on defaultcontent
ALc +67on subtlecontent
surface-default
oklch(1.00 0.000 90)
surface
surface-subtle
oklch(0.97 0.001 106)
surface
accent-primary
oklch(0.39 0.041 237)
accent
ALc +88on defaultbody
ALc +83on subtlebody

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 / surfacedefaultsubtle
text-primaryAa
Lc +103
Aa
Lc +98
text-secondaryAa
Lc +91
Aa
Lc +86
text-mutedAa
Lc +73
Aa
Lc +67
accent-primaryAa
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.

Colors are not decorative choices. They are accessibility decisions encoded as tokens. When the token carries its contrast data, the system enforces what the designer intended.