v1.0.0 — MetricSpace + GenSpace

Your Colors Deserve
Better Math
Two Purpose-Built
Lab Spaces

The small stuff OKLab leaves on the table: blue-to-white midpoints drift a little pale, dark palette steps aren't perfectly even, saturated yellows lose a touch of punch. Helmlab tightens all of that — modest, measurable gains.

GenSpace for generation. MetricSpace for measurement.
Same library, two pipelines optimized for different objectives.

Wins 62 out of 90 quality tests vs OKLab
62-9 vs OKLab on 90 benchmarks (19 ties)
$ pip install helmlab
$ npm install helmlab
The Problem

You've seen this before

You pick a vivid blue. You make a gradient to white. In OKLab the midpoint comes out a little paler — slightly less saturated, though still blue. Helmlab keeps a touch more saturation. The difference is real but subtle.

OKLab (the current standard)

Midpoint #74a3ff — slightly paler / less saturated (G/R 1.41), but still blue at hue ~220°.

Helmlab

Midpoint — a little more saturated (G/R ). Small gap, but consistent through the transition.

Red to White
OKLab — similar warmth
Helmlab — very similar
Yellow to White
OKLab — slightly more saturated early
Helmlab — more linear fade
Teal to Black
OKLab — slightly compressed darks
Helmlab — smoother dark transition
Palettes

Even palette steps

You generate a 50-950 scale from your brand color. OKLab's lightness is good, but its steps aren't perfectly even — the dark end is slightly compressed. Helmlab spaces them a bit more evenly. The difference is measurable, though often subtle.

OKLab palettefrom #3b82f6

The dark steps (700–900) are marginally less even than the light end.

Helmlab palettefrom #3b82f6

Steps are a bit more even — about 18× lower step variation on the Munsell value scale, though the visual difference is small.

Try It

See it with your own colors

Pick two colors and compare the gradient. Then try the full playground for palettes and more.

See the Difference

Three color spaces, same endpoints. Notice the midpoint.

* Perceptually uniform via CIEDE2000 arc-length reparameterizationFull playground →
Use Cases

Built for the work you actually do

Design Systems

Generate a full 50-950 Tailwind-style scale from any brand color. Every step is perceptually even. Export to CSS variables, Tailwind config, or design tokens.

hl.gen.scale("#3b82f6")
Dark Mode

Dark gradients that don't turn muddy. 28% smoother in the dark range where OKLab struggles most. Your dark theme looks intentional, not accidental.

hl.gen.adaptToMode("#3b82f6", "light", "dark")
Data Visualization

Categorical palettes with maximum separation. Your chart colors stay distinct even for colorblind users.

hl.gen.hueRing(8, { lightness: 0.6 })
Wide Gamut (P3)

Modern displays show colors outside sRGB. Helmlab maps them correctly — no ugly hue shifts when clipping P3 colors to sRGB.

hl.gen.toHex(hl.gen.fromHex("color(display-p3 1 0 0.5)"))
Honest

When to use something else

We could hide this. We won't. You deserve to know before choosing.

CSS-only gradients

If you need gradients in pure CSS without JavaScript, use oklch() — it's built into browsers.

Very subtle gray gradients

Gradients between nearly identical grays are 22% smoother in OKLab. It's our biggest weakness.

Green-blind accessibility

OKLab gives 43% better step distinction for deuteranopia palettes. Use it for CVD-critical designs.

HDR displays

For >1000 cd/m2 content, use Jzazbz. Helmlab is optimized for standard dynamic range.

Smallest possible bundle

OKLab is ~2KB. Helmlab is 17.8KB gzipped. If every kilobyte counts, OKLab is lighter.

Legacy CIE Lab workflows

Decades of industry hue naming is based on CIE Lab. If you need interop with those systems, stick with Lab.

Get Started

Ask your developer for three lines

One install, one import, one function call. Then hand the hex values to your design tokens.

// That's it. Really.
import { Helmlab } from 'helmlab';
const scale = new Helmlab().gen.scale('#3b82f6');

Common questions

Do I need to know color science?

No. Import Helmlab, give it a hex color, get better results back. The math is hidden.

Does it work with Tailwind / Figma / Tokens Studio?

Helmlab outputs hex values and CSS variables. It works with anything that accepts standard color formats. Tailwind config export is built in.

Why can't I just use oklch() in CSS?

You can! oklch() is great for CSS-only gradients. But if you're generating colors in JavaScript (design tokens, palette tools, theme generators), Helmlab gives visibly better results because it uses a richer perceptual model.

Is it free?

Yes. MIT licensed. Use it in any personal or commercial project.

How much does it add to my bundle?

17.8 KB gzipped, zero dependencies. About the same as a small icon set.

What if I need to match brand colors exactly?

Helmlab is exactly invertible. The same hex always produces the same Lab values, and vice versa. Zero rounding error.

Key Metrics

Numbers that speak for themselves

ColorBench: 90 metrics, 3,038 gradient pairs, 3 gamuts, float64 precision. Head-to-head vs OKLab.

22.48
STRESS score on COMBVD (3,813 pairs)
23% better than CIEDE2000
62-9
90 metrics, 13 categories
Including 6-1 on independent 3rd-party datasets
360/360
sRGB + P3 valid cusp coverage
OKLab: 299/360 sRGB, 308/360 P3
18 x
Munsell Value: 0.156% vs 2.797%
Uniform L channel by construction
1.514
Blue-to-White midpoint G/R ratio
OKLab: 1.408 (slightly less saturated)
10 -15
Achromatic purity (D65 C*)
~10⁸× better than OKLab
Live Demo

Gradient Comparison

Helmlab vs OKLab vs CIE Lab — pick any two colors.

See the Difference

Three color spaces, same endpoints. Notice the midpoint.

* Perceptually uniform via CIEDE2000 arc-length reparameterizationFull playground →
Architecture

Two Spaces, One Library

GenSpace for creating colors, MetricSpace for measuring them. Same library, different pipelines optimized for different objectives.

GenSpace

For Generation

~45 parameters, depressed cubic transfer, CMA-ES optimized M1/M2 matrices, structural achromatic.

62-9 vs OKLab
360/360 sRGB cusps
0 deps 17.8KB gzip
Pipeline
XYZ M1 depcubic M2 PW-L enrich C^cp NC Lab
gen.gradient() gen.palette() gen.scale() gen.vivid()
MetricSpace v21

For Measurement

72-parameter enriched pipeline with Helmholtz-Kohlrausch correction and pair-dependent SL/SC weighting (STRESS evaluated with Bradford CAT).

22.48 STRESS
72 parameters
23% better than CIEDE2000
Pipeline
XYZ M1 γ M2 hue H-K L/C NC φ Lab
metric.difference() metric.jnd() metric.confidence() metric.info()
Recommended

When to Use Helmlab

Tasks where GenSpace or MetricSpace measurably outperforms alternatives.

Design System Palettes

Munsell Value CV: 0.156% vs OKLab 2.797%. 18x better lightness uniformity.

Gradient Interpolation

31% less max hue drift, 28% better cross-lightness CV. G/R=1.514 (OKLab: 1.408).

Gamut Mapping

360/360 cusps, 0 mono violations, cusp smoothness 0.075 (OKLab: 0.805). 11x smoother.

Color Harmony Tools

Palette harmony accuracy: 9.1° vs OKLab 11.7°. Hue-rotated palettes stay 22% truer.

Dark UI Themes

Dark gradient CV: 33.68% vs OKLab 46.53%. 28% better uniformity in L<0.4.

Color Animation

Frame-to-frame CV: 53.4% vs 55.3%. Fewer quantization artifacts in 8-bit.

Wide Gamut (P3, Rec.2020)

P3 cusps: 360/360 (OKLab: 308). Zero P3 mono violations (OKLab: 71).

Blue / Yellow Design

Blue G/R=1.514 (OKLab: 1.408). Yellow chroma 0.333 (OKLab: 0.211, +58%).

Honest

When NOT to Use Helmlab

We believe in honest recommendations. These tools are better for specific use cases.

Near-Achromatic Gradients

Use OKLab

Near-achromatic CV: OKLab 79.26% vs Helmlab 102.1%. 22% gap.

CVD Deutan Palettes

Use OKLab

Deutan min step delta-E: OKLab 0.157 vs Helmlab 0.11. 43% gap.

CSS oklch() Required

Use OKLab

oklch() is in CSS Color Level 4. Zero bundle cost.

HDR / PQ Content

Use Jzazbz

Perceptual quantization for luminance >1000 cd/m2. Untested territory.

Minimal Bundle Size

Use OKLab

OKLab: ~2KB. Helmlab: 17.8KB gzipped. ~9x larger.

CIE Lab Hue Compatibility

Use CIE Lab

Legacy system interop. Hue agreement: CIE Lab 0 deg vs Helmlab 8.3 deg.

Transparency

Where We Lose

No color space wins everywhere. Here are our genuine weaknesses, documented publicly.

Where MetricSpace Loses

COMBVD sub-datasets
CIEDE2000 beats MetricSpace on LEEDS (19.25 vs 21.84), RIT-DuPont (19.47 vs 21.90), and WITT (30.22 vs 30.93). Our lead comes from the larger BFD-P datasets.
Mild overfitting
72 params on 3,813 data points. Train/test gap of +1.8 STRESS. Published 22.48 is a training metric; cross-validated estimate is ~24.3. Still #1 on COMBVD, HumFB, and the 3-dataset average; CAM16-UCS narrowly leads on the 128-pair MacAdam set.
No HDR optimization
Jzazbz was designed for HDR/WCG. MetricSpace v21 is optimized for SDR psychophysical datasets. HDR color difference prediction is untested.
No surround adaptation
CAM16 models viewing conditions (dark/dim/light surround). MetricSpace has basic parameters but is not optimized for cross-surround.

Where GenSpace Loses 9 of 90 vs OKLab

Worst-case gradient CV — Single worst pair regresses. Tail case, not typical.
-38%
Bright gradient CV (L>0.6) — Marginal. Bright-end steps slightly less even.
-8%
Near-achromatic gradient CV — Real weakness. Grays less uniform.
-29%
CVD deutan min step dE — Real weakness. Green-blind see less distinction.
-45%
Data viz min pairwise dE — Slightly lower minimum palette separation.
-6%
Red-White midpoint G-B — Effectively tied.
-2%
Primary hue disc (sRGB) — Hue jumps at sRGB primaries.
-26%
Primary hue disc (P3) — Same issue in Display P3.
-27%
Ebner-Fairchild hue surfaces (max) — Slightly worse worst-case hue surface.
-6%
Quick Start

Works where you work

Python and JavaScript with identical APIs. TypeScript types included. Zero dependencies in JS.

from helmlab import Helmlab

hl = Helmlab()

# Generate a 10-shade palette from any color
palette = hl.gen.palette("#3b82f6")

# Color distance (Euclidean Lab — uncompressed)
dist = hl.metric.euclidean("#ff0000", "#00ff00")

# 32-step gradient (stays blue through the midpoint)
grad = hl.gen.gradient("#0000ff", "#ffffff", 32)

# Tailwind-style semantic scale (50-950)
scale = hl.gen.scale("#3b82f6")
~2.6x
OKLab cost
us/px
per pixel
Exact
invertibility
0 deps
JS bundle (17.8KB)

Get Started

Python and JavaScript. Same API. Same results.

Python pip install helmlab
JS / TS npm install helmlab
Merged into Color.js
3 spaces on master — pending next release docs
MIT License Zero Dependencies (JS) TypeScript Included
FAQ

Frequently Asked Questions

What's the difference between GenSpace and MetricSpace?

GenSpace is optimized for visual quality in generation tasks: palette creation, gradient interpolation, gamut mapping, and animation. ~45 parameters, depressed cubic transfer. MetricSpace is optimized for predicting perceptual color differences. 72 parameters, full enrichment pipeline with H-K correction, pair-dependent SL/SC weighting. Same library, two pipelines.

Is Helmlab a replacement for OKLab?

For most generation tasks, yes. GenSpace scores 62-9 against OKLab across 90 benchmarks, including 6-1 on independent datasets OKLab was optimized on. OKLab remains better for: near-achromatic gradients (22% better CV), CVD deutan palettes (43%), native CSS oklch(), or minimal bundle size (~2KB vs 17.8KB).

How was it optimized? Is there overfitting?

CMA-ES optimization on COMBVD (3,813 pairs). Proper holdout test: +1.8 STRESS gap between train and held-out 20% split. Published STRESS 22.48 is a training metric; cross-validated estimate ~24.3. Still beats CIEDE2000 (29.2) and every other Lab-only baseline. On the small held-out MacAdam 1974 set (128 pairs, never trained on) MetricSpace = 19.51 vs CAM16-UCS 18.71 — CAM16 leads by 0.80 STRESS due to its appearance-model formulation matching MacAdam's controlled-viewing conditions. Across the COMBVD+MacAdam average MetricSpace remains #1 (21 vs CIECAM02-UCS's 25.06). Our own human-feedback set is rank-order-only after an internal audit (5-level categorical ratings break STRESS) — MetricSpace ranks it at Spearman 0.954 vs CIEDE2000's 0.907. Full analysis in BENCHMARK.md.

How does this relate to Color.js?

Helmlab was merged into Color.js master in April 2026: three spaces (helmgen, helmgenlch, helmlab-metric) plus a custom 'Helmlab' deltaE method. The published colorjs.io@0.6.1 does NOT include it yet — it ships in the next release; until then use 'npm install github:color-js/color.js' or stick with the helmlab package below. The helmlab npm package is the right pick if you want a tiny zero-dep bundle (17.8 KB) with palette/gradient/scale helpers. The math is identical in both.

Can I use it in CSS?

Yes — install postcss-helmlab and write helmlab(L a b), helmlch(L C h), helmgen(...), or helmgenlch(...) directly in your stylesheets. The plugin emits sRGB inline plus @supports-wrapped color(display-p3 ...) and color(rec2020 ...) overrides at build time, so older browsers fall back gracefully and modern browsers receive the widest gamut they can render. This site dogfoods it.

What about browser support?

ES module, zero dependencies, 17.8KB gzipped. Works in all modern browsers and Node.js. TypeScript types included. Outputs standard hex/RGB. helmlab.js is tree-shakeable.

Can my AI assistant use Helmlab correctly?

Yes — install our benchmarked agent skills with "npx skills add Grkmyldz148/color-skills" (Claude Code, Codex, Gemini CLI, Cursor). Two skills: color-space-routing (task-to-space routing, lifts model pass rates from ~41% to ~91% on verifiable color tasks) and helmlab (correct API usage — without it, models hallucinate the API). Details in the docs.

Is it open source?

MIT licensed. GitHub: github.com/Grkmyldz148/helmlab. Full benchmark methodology (ColorBench), optimization scripts, and psychophysical datasets are published. Research paper: arxiv.org/abs/2602.23010.