Skip to content

Design Systems

Brand Colour Palette Generation — OKLCH-Based Palettes That Stay Accessible

One Brand Colour Input, Fifty Accessible Shades, Zero Hand-Tuning

🎨 🔢

If you're still building colour palettes by hand-tweaking HSL in Figma, you're shipping inconsistent contrast pairs and locking yourself into breakpoint curves every time the brand pivot hits. Velocity X kills that: pick one primary brand colour, feed it to an OKLCH lightness ladder algorithm, and generate 10 automatically-accessible shades (50, 100, 200…900) where every combination meets WCAG AA contrast requirements. HSL is dead. OKLCH is the 2026 colour-space standard.

Why HSL Failed You

HSL (hue, saturation, lightness) is intuitive to talk about, which is why it's everywhere. But it's not perceptually uniform: increasing lightness from 40% to 50% doesn't feel like the same "step" as 80% to 90%. Your h-600 and h-700 look close, but h-400 and h-500 feel miles apart. Add accessibility audits and you discover your h-500 on white backgrounds passes AA, but h-600 doesn't — forcing awkward workarounds or brand-colour remixes. Every palette gets custom contrast rules, every designer tweaks it differently, and accessibility becomes a post-hoc fix instead of a system law.

The kicker: scaling one palette to multiple brands means retuning from scratch. A client's new brand blue? Throw away your HSL rules. Fire up Figma, hand-adjust chroma, pray the contrast math works out. That's not a system — that's guesswork at scale.

Enter OKLCH: Perceptually Uniform Colour Space

OKLCH (Oklab lightness, chroma, hue) is a colour space where equal steps in lightness look equal to human eyes. Jump from L 30 to L 40? Feels the same as L 70 to L 80. This is not true in HSL or sRGB. OKLCH is supported in 96%+ of modern browsers and has full CSS support in gradients, filters, and variables. It's the backbone of every mature design system built in 2025+.

The formula: lock hue and chroma constant, increment lightness in steps of 10 across a 0–100 range. L 50 is your primary (what you pick in the brand brief). L 100 is nearly white, L 0 is black. Every shade is mathematically guaranteed to have consistent contrast with fixed background colours. No guessing. No post-hoc audits. The system is law.

The Velocity X Palette Algorithm

Velocity X takes a single 6-digit hex input (e.g. #6366F1 — Indigo-600), converts it to OKLCH, locks the hue and chroma, then steps lightness from 50–950 in intervals of 100. The output is JSON:

{
  "50": "oklch(97% 0.025 251.8)",
  "100": "oklch(94% 0.05 251.8)",
  "200": "oklch(88% 0.10 251.8)",
  "300": "oklch(79% 0.14 251.8)",
  "400": "oklch(69% 0.18 251.8)",
  "500": "oklch(59% 0.20 251.8)",
  "600": "oklch(50% 0.21 251.8)",
  "700": "oklch(42% 0.19 251.8)",
  "800": "oklch(32% 0.15 251.8)",
  "900": "oklch(17% 0.08 251.8)",
  "950": "oklch(9% 0.04 251.8)"
}

Every shade uses the same hue (251.8°) and chroma (saturation equivalent, kept high enough to stay vibrant). Lightness steps down uniformly. Plug these into your design tokens, and every pair — 600 on white, 700 on white, 800 on white — passes WCAG AA automatically. No spreadsheet audits. No "this one's a little off" remixes.

Contrast is Automatic

OKLCH's perceptual uniformity means the lightness value directly predicts contrast. L 50–600 shades on white backgrounds will always exceed 4.5:1 (AA threshold). L 700–900 shades on light backgrounds pass AAA. Light shades (50–200) on dark backgrounds (900–950) hit 9:1+. The algorithm is self-verifying. Ship it with confidence.

This is the magic: you don't audit after. You audit before by choosing the right chroma input, and then every permutation works. If you're generating a palette and one shade fails contrast, the input chroma was wrong — reduce it by 0.01 and regenerate. One line changes the entire palette's accessibility. Velocity X bakes that into the brand brief: "pick your primary, pick your chroma target, run the algorithm, verify one dark/light pair, ship ten shades."

Building a Palette Generator CLI

The generator is ~40 lines of JavaScript. Read your brand hex, convert to OKLCH using a standard library (e.g. chroma.js or native CSS Color Module APIs in Node 20+), lock hue and chroma, loop L from 5 to 95 in steps of 10, format as oklch() CSS values, write JSON. Ship as a build-time script or interactive tool. For Velocity X, it's bundled into the CLI: velocity brand --hex #6366F1 --output palette.json.

The real win: when a client's brand changes, you regenerate in 30 seconds. No design cycle. No contrast audits. No "we need to hand-tune it" pushback. The system is deterministic.

Frequently Asked Questions

Does OKLCH work in older browsers?

Fallback gracefully: store both oklch() and RGB hex versions in your tokens. Modern browsers use OKLCH, older ones use hex. Most users are on Chrome 126+, Safari 17.4+, or Firefox 126+. The fallback is for IE11 and uncommon cases.

Can I adjust chroma per-brand?

Absolutely. Lower chroma makes the palette more muted (better for corporate / conservative brands). Higher chroma = more vibrant (better for consumer / bold brands). Most brands sit at 0.18–0.22 chroma. Adjust it in the generator input and re-run.

What about dark mode contrast?

OKLCH shades on dark backgrounds (e.g., #0F172A) automatically pass WCAG because the lightness spread is so large. L 50 on black is roughly 8:1 contrast. L 100 on black is 12:1+. Dark mode is free.

How do I handle brand shades that don't fit a 50–950 grid?

Extend the range. Need a L 25 for extreme dark mode overlays? Generate L 25 separately at full chroma. Need L 975 for a barely-visible disabled state? Easy — just step further. The grid is a convention, not a rule.

Does perceptual uniformity matter for small UI details?

Yes. Buttons, badges, hover states, borders — all of them should scale proportionally with the palette. If you're using a 50-shade palette, every increment should feel like a similar jump in emphasis. OKLCH guarantees that. HSL does not.

Can I export the palette to Figma / Tailwind / CSS?

The generator outputs JSON, which is then templated into whatever format you need: Figma design tokens, Tailwind theme.colors, CSS variables, or SCSS mixins. One source, many targets.

The Bottom Line

If you're still hand-tuning colour palettes in HSL, you're adding friction every time a brand changes or an accessibility audit fails. OKLCH is the 2026 standard: perceptually uniform, mathematically deterministic, and guarantees accessibility without post-hoc tweaking. Velocity X generates 10 shades from one hex input, each pair passes WCAG AA by design, and scaling to 20 brands costs a single script run each. Build your palette once, extend infinitely, and never hand-adjust chroma again. For more on design systems and token architecture, explore /pricing or read deeper in /blog/fluid-type-scale-clamp-design-tokens.

Let us make some quick suggestions?

Please provide your full name.
Please provide your phone number.
Please provide a valid phone number.
Please provide your email address.
Please provide a valid email address.
Please provide your brand name or website.
Please provide your brand name or website.