# How the ramps are built

The lightness and chroma behind every stop, so any hue you pick gives the same contrast.

The live page plots one hue's slice of OKLCH, chroma against lightness, colored where Display P3 can show the color, with the ramp's stops marked. It starts at hue 250. [Try it on the live page](https://colortokenskit.com/under-the-hood/how-ramps-are-built/).

Each square is a stop of one hue's ramp, with lightness up and [chroma](https://colortokenskit.com/reference/glossary/index.md#chroma) to the right. The colored area is every color [Display P3](https://colortokenskit.com/reference/glossary/index.md#display-p3) can show at that hue. Drag the hue: every ramp follows one recipe, with one lightness and one chroma per stop, and a hollow square marks a chroma the hue can't reach.

So `_600` is 4.68:1 on white in all 36 named hues and in any hue you pass, and no hue looks louder than another. [How did we choose and build these colors?](https://colortokenskit.com/basics/how-the-colors-were-built/index.md) has the short version.

## One lightness per stop

Lightness is CIELab [L\*](https://colortokenskit.com/reference/glossary/index.md#cielab-and-l), which decides WCAG contrast, so a stop has the same contrast in every hue. It runs from 96.5 at `_50` to 10.2 at `_1000`.

We didn't invent those values: each is the average, at that stop, of the library's earlier hand-tuned palette. [Why OKLCH?](https://colortokenskit.com/under-the-hood/why-oklch/index.md) explains why lightness comes from L\* and not from OKLCH.

## One chroma per stop

Each stop's chroma is the most that at least 29 of the 36 named hues can show in Display P3 at that lightness, rounded down. It's highest from `_350` to `_450`, because screens show their most vivid colors at medium lightness.

Why 29? Any higher, and more hues would fall short and look duller than their neighbors. Any lower, and every hue pays: at `_400`, a cap low enough for every hue would sit 7% lower, where indigo runs out.

A hue that can't reach it gets 98% of what Display P3 allows, at the same L\*, so its contrast still matches. From `_50` to `_400`, the violet-blues fall short, indigo the most. From `_400` down, teal, turquoise and cyan fall short by a few percent, and mustard by less. Most other hues could show more color than they use, which [what does equal lightness cost?](https://colortokenskit.com/under-the-hood/trade-offs/index.md) covers.

## Any hue, the same recipe

```swift
let blue = ProTheme.primary(forHue: 250)   // the same ramp as Color.proBlue
let brand = ProTheme(hex: "#00B386")       // the ramp at your hex's hue, 167°
```

The named families are just hues, so any hue you pass, or your brand's, gets the same recipe and the same contrast. In the library, each stop takes four lines of `UniformRamp.swift`:

```swift
let luminance = Gamut.luminance(lightnessStar: lightnessStar)
let chroma = min(targetChroma, gamutMargin * Gamut.maxChroma(luminance: luminance, hue: hue))
let oklabLightness = Gamut.lightness(forLuminance: luminance, chroma: chroma, hue: hue)
return OKLCHColor(l: oklabLightness, c: chroma, h: hue)
```

## Gray's own ladder

- proGray.\_600: #626262
- proBlue.\_600: #4176b8

Gray has no hue, so its stops sit on a hand-tuned ladder of their own. Gray `_600` is 6.09:1 on white, where every hue's `_600` is 4.68:1, so check gray pairs on their own.

## Sources

- ColorTokensKit source, [UniformRamp.swift](https://github.com/metasidd/ColorTokensKit-Swift/blob/main/Sources/ColorTokensKit/Services/Ramps/UniformRamp.swift), `Gamut.swift` and `ColorRampGenerator.swift`.
- Björn Ottosson, [A perceptual color space for image processing](https://bottosson.github.io/posts/oklab/) (2020), for OKLab and OKLCH.
- W3C, [Web Content Accessibility Guidelines (WCAG) 2.2](https://www.w3.org/TR/WCAG22/), for relative luminance and contrast.

## See also

- [.contrastRatio(to:method:)](https://colortokenskit.com/api/contrast-ratio/index.md): Check WCAG 2 and APCA contrast in Swift, and keep your color pairs passing with a unit test.
- [.lighten(by:)](https://colortokenskit.com/api/lighten/index.md): Add highlights and lighter steps to any color, landing on an exact palette stop.
- [Fitting colors into Display P3](https://colortokenskit.com/under-the-hood/gamut-mapping/index.md): Stay inside Display P3 without losing contrast: chroma drops, lightness holds.
- [What does the library offer?](https://colortokenskit.com/basics/color-library/index.md): 36 color themes, ready-to-use tokens with dark mode, a theme for your brand, and state functions.
- [.toLCH()](https://colortokenskit.com/api/to-lch/index.md): Read a color as CIELab lightness, chroma and hue, to match LCH numbers or check contrast.

---

From ColorTokensKit, by Penguin Design Ventures: https://colortokenskit.com/under-the-hood/how-ramps-are-built/ (updated September 26, 2026).
