# How Hallmark’s OKLCH Color System Works (and Why It Replaces Hex/HSL)

> Explore Hallmark's OKLCH color system, its advantages over Hex and HSL, and how it enables perceptually uniform themes with reliable contrast and runtime theme switching.

- Repository: [Hassan El Mghari/hallmark](https://github.com/Nutlope/hallmark)
- Tags: deep-dive
- Published: 2026-08-05

---

**Hallmark defines every UI color with OKLCH values stored as CSS custom properties, enabling perceptually uniform themes with reliable contrast and runtime theme switching.**

The Hallmark design system, developed in the Nutlope/hallmark repository, uses **OKLCH** as its sole color format. This modern color space powers a token-based architecture where themes like *cobalt*, *hum*, and *lumen* declare complete palettes through CSS custom properties. Unlike traditional hex or HSL values, OKLCH aligns with human vision, making contrast predictable and theme maintenance scalable.

## What Is OKLCH and How Hallmark Implements It

**OKLCH** represents colors using three components: **Lightness (L)**, **Chroma (C)**, and **Hue (H)**. In Hallmark, every color token is stored as an OKLCH value inside [`site/css/tokens.css`](https://github.com/Nutlope/hallmark/blob/main/site/css/tokens.css), wrapped in theme-specific data attributes.

```css
/* From site/css/tokens.css — Cobalt theme excerpt */
[data-theme="cobalt"] {
  --color-paper:   oklch(96% 0.018 80);
  --color-ink:     oklch(20% 0.012 250);
  --color-accent:  oklch(55% 0.14 255);
  /* 20+ additional tokens per theme */
}

```

Components consume these tokens via `var()` references, never hard-coded values. This **"Locked tokens" rule** (documented in [`skills/hallmark/references/anti-patterns.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/anti-patterns.md)) forbids inline hex or HSL from appearing in generated markup.

## Why OKLCH Is Preferred Over Hex and HSL

The Hallmark system explicitly rejects hex and HSL for five technical reasons grounded in perceptual color science.

### Perceptual Uniformity Enables Reliable Contrast

**OKLCH separates Lightness, Chroma, and Hue in a space matching human vision.** Lightness values compare directly: `oklch(60% ...)` is visibly half as bright as `oklch(90% ...)`. This linearity fails in HSL, where identical "Lightness" percentages produce vastly different perceived brightness across hues.

The [`skills/hallmark/references/color.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/color.md) file documents how this property simplifies **WCAG 2.1 contrast pre-checks** using simple lightness deltas.

### Predictable Lightness Prevents Unintentional Shifts

Adjusting **Chroma or Hue** in OKLCH does not accidental alter perceived brightness. In HSL, saturating a blue or manipulating yellow hue can darken or lighten the color unexpectedly.

Hallmark relies on this stability to guarantee that `-color-paper` remains a readable background across all theme variants, avoiding the "black-on-black" bugs caught by automated gates.

### Consistent Hue Across Tints

The **Hue (H)** value stays constant for every shade of a color family. A brand accent at `oklch(... 0.18 95)` shares hue 95 with its lighter and darker variants, preserving recognizability.

This consistency enables Hallmark's strict **"no pure #fff / #000"** rule (see [`skills/hallmark/references/anti-patterns.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/anti-patterns.md)). Even "white" and "black" are slightly tinted OKLCH values, maintaining visual harmony.

### Simple Math for Automated Contrast Checks

The **slop-test OKLCH pre-check** (documented in [`skills/hallmark/references/slop-test.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/slop-test.md)) uses lightness deltas as a fast accessibility filter:

```javascript
// Pseudo-code from the slop-test implementation
function likelyFailsWCAG(color1, color2) {
  const L1 = parseOKLCH(color1).lightness;  // e.g., 0.96
  const L2 = parseOKLCH(color2).lightness;  // e.g., 0.20
  return Math.abs(L1 - L2) < 0.50;          // 76% difference = likely pass
}

```

Hex and HSL require full conversion to a perceptual space before such calculations work.

### Future-Proof Token Architecture

Tokens declared once in [`site/css/tokens.css`](https://github.com/Nutlope/hallmark/blob/main/site/css/tokens.css) propagate everywhere through CSS variables. Adding a theme requires only a new `[data-theme="..."]` block with 20–30 OKLCH definitions:

```css
/* Defining a custom OKLCH palette per skills/hallmark/references/custom-theme.md */
[data-theme="my-custom"] {
  --color-paper:   oklch(94% 0.005 60);   /* warm off-white */
  --color-ink:     oklch(20% 0.012 250);  /* deep blue-black */
  --color-accent:  oklch(68% 0.18 95);    /* amber brand color */
}

```

Runtime theme switching requires zero JavaScript bundling changes:

```html
<html data-theme="cobalt">…</html>
<script>
  // Instant palette swap without page reload
  document.documentElement.dataset.theme = 'hum';
</script>

```

## How Hallmark Enforces OKLCH-Only Usage

The repository contains multiple enforcement mechanisms:

- **[`site/css/tokens.css`](https://github.com/Nutlope/hallmark/blob/main/site/css/tokens.css)** — Source of truth for 20+ complete OKLCH themes
- **[`skills/hallmark/references/anti-patterns.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/anti-patterns.md)** — Explicit ban on inline hex/HSL values
- **[`skills/hallmark/references/slop-test.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/slop-test.md)** — Automated OKLCH contrast pre-checks in CI
- **[`skills/hallmark/references/custom-theme.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/custom-theme.md)** — OKLCH palette generation workflow for new briefs

No component imports a raw color value. The token system guarantees that **rotating themes**, **enforcing contrast**, and **preventing mid-render improvisations** happen without manual updates to hundreds of hard-coded values.

## OKLCH vs. Hex/HSL: Quick Comparison

| Dimension | Hex | HSL | **OKLCH** |
|-----------|-----|-----|-----------|
| Lightness perception | Non-linear, unpredictable | Angle-based, inconsistent | **Perceptually uniform** |
| Hue consistency across saturation | N/A | Shifts with lightness changes | **Stable** |
| Contrast calculation | Requires conversion | Requires conversion | **Direct L delta** |
| Human-readable adjustment | Impossible | Partial | **Intuitive (L/C/H)** |
| Theme maintainability | Fragmented | Fragmented | **Centralized tokens** |

## Practical Implementation Example

```css
/* Consumption: always via var(), never raw OKLCH */
.article-card {
  background: var(--color-paper);
  border: 1px solid var(--color-ink-weak);
  color: var(--color-ink);
}

.article-card:hover {
  background: var(--color-paper-hover);  /* same hue, adjusted L */
}

```

```javascript
// Runtime theme rotation
const themes = ['cobalt', 'hum', 'lumen', 'ink'];
let current = 0;

setInterval(() => {
  current = (current + 1) % themes.length;
  document.documentElement.dataset.theme = themes[current];
}, 5000);

```

## Summary

- Hallmark defines **all colors as OKLCH values** in CSS custom properties within [`site/css/tokens.css`](https://github.com/Nutlope/hallmark/blob/main/site/css/tokens.css)
- **Perceptual uniformity** makes lightness directly comparable, enabling reliable contrast and automated accessibility checks
- **Predictable lightness and stable hue** prevent the unpredictable shifts common in hex and HSL
- The **"Locked tokens" rule** enforces OKLCH-only usage, banning inline hex/HSL from generated markup
- **Runtime theme switching** works through data attributes, with zero bundling changes required

## Frequently Asked Questions

### What makes OKLCH more accessible than HSL for web design?

OKLCH's **Lightness (L)** channel correlates directly with perceived brightness, unlike HSL's Lightness which varies dramatically across hues. This allows Hallmark's slop-test to pre-calculate contrast using simple subtraction (`|L₁ - L₂|`), catching WCAG failures before visual review. HSL requires expensive color space conversions to achieve the same accuracy.

### Can I mix OKLCH with hex or HSL in a Hallmark project?

No. The [`skills/hallmark/references/anti-patterns.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/anti-patterns.md) documentation explicitly prohibits inline hex and HSL values. All colors must route through the token system in [`site/css/tokens.css`](https://github.com/Nutlope/hallmark/blob/main/site/css/tokens.css). This ensures themes remain switchable and contrast checks remain valid across the entire UI.

### How do I create a custom OKLCH theme for Hallmark?

Define a new `[data-theme="..."]` block in [`site/css/tokens.css`](https://github.com/Nutlope/hallmark/blob/main/site/css/tokens.css) with OKLCH values for the 20+ required tokens (`--color-paper`, `--color-ink`, `--color-accent`, etc.). The [`skills/hallmark/references/custom-theme.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/custom-theme.md) file provides a generation workflow that preserves hue relationships and maintains the "no pure white/black" rule through careful L and C adjustments.

### Does using OKLCH affect browser support or performance?

OKLCH is supported in all modern browsers. For Hallmark's token-driven architecture, the CSS custom property layer abstracts away any syntax concerns—components reference `var(--color-paper)`, not raw OKLCH. The build process handles any necessary fallbacks, and runtime theme switching incurs no JavaScript performance penalty beyond a single attribute mutation.