A data-driven analytical color space trained on 64,000 human color-difference observations
Project description
Helmlab
A data-driven analytical color space for UI design systems.
Helmlab is a 72-parameter color space optimized end-to-end against psychophysical data. It achieves STRESS 23.22 on COMBVD (3,813 color pairs) — a 20.4% improvement over CIEDE2000 — while maintaining a structurally guaranteed achromatic axis and reasonable hue alignment.
Interactive Demo | Documentation | Paper
Key Features
- State-of-the-art color difference prediction — STRESS 23.22 vs CIEDE2000's 29.18
- Achromatic guarantee — Grays map to C < 10⁻⁶ via neutral correction (no color artifacts in gradients)
- Free hue improvement — Rigid rotation reduces hue error (RMS 16.1°) at zero cost to the distance metric
- Embedded Helmholtz-Kohlrausch — Lightness is chroma-dependent, learned from data
- UI tooling — Gamut mapping, WCAG contrast enforcement, palette generation, dark/light mode adaptation
- Token export — CSS (
oklch()), Android XML, iOS Swift (Display P3), Tailwind, JSON
Installation
npm (TypeScript / JavaScript)
npm install helmlab
import { Helmlab } from 'helmlab';
const hl = new Helmlab();
const lab = hl.fromHex('#3B82F6'); // Hex → Helmlab Lab
const hex = hl.toHex([0.5, -0.1, 0.2]); // Lab → hex (gamut mapped)
hl.contrastRatio('#ffffff', '#3B82F6'); // → 3.68
hl.ensureContrast('#3B82F6', '#ffffff', 4.5); // Adjust to meet 4.5:1
hl.deltaE('#ff0000', '#00ff00'); // Perceptual distance
hl.semanticScale('#3B82F6'); // Tailwind-style 50–950 scale
10KB gzipped, zero dependencies, ESM + CJS with full TypeScript types. See the npm package README for the full API.
Python (pip)
pip install helmlab
Quick Start (Python)
from helmlab import Helmlab
hl = Helmlab()
# sRGB to Helmlab Lab
lab = hl.from_srgb([0.2, 0.5, 0.8])
print(f"L={lab[0]:.3f}, a={lab[1]:.3f}, b={lab[2]:.3f}")
# Back to sRGB (round-trip error < 10⁻¹⁴)
rgb = hl.to_srgb(lab)
# Color difference between two sRGB colors
dist = hl.delta_e("#ff0000", "#00ff00")
# Ensure WCAG AA contrast (4.5:1)
adjusted = hl.ensure_contrast("#ffffff", "#3B82F6", min_ratio=4.5)
# Generate a palette (Tailwind-style 50-950 scale)
scale = hl.semantic_scale("#3B82F6")
How It Works
Helmlab maps CIE XYZ (D65) to a perceptually-organized Lab space through 13 stages:
XYZ → M₁(9) → γᵢ(3) → M₂(9) → Hue corr.(8) → H-K(6) → L corr.(5)
→ Dark L(3) → C scale(8) → C power(4) → L×C(2) → HLC(4) → Hue-L(4)
→ NC → Rot φ → Lab
All 72 parameters (65 space + 7 distance metric) are jointly optimized against COMBVD using L-BFGS-B with 8 random restarts. See the documentation for the full mathematical description of each stage.
Benchmarks
STRESS on COMBVD (3,813 pairs). Each method uses its standard distance formula. Lower is better.
| Method | COMBVD STRESS | vs CIEDE2000 |
|---|---|---|
| Helmlab v19 | 23.22 | -20.4% |
| CIEDE2000 | 29.18 | — |
| CIE94 | 33.59 | +15.1% |
| CAM16-UCS (Euclid.) | 33.90 | +16.2% |
| ΔE CMC | 34.04 | +16.6% |
| IPT (Euclid.) | 41.21 | +41.3% |
| CIE Lab ΔE76 | 42.80 | +46.7% |
| Oklab (Euclid.) | 47.46 | +62.7% |
Bootstrap (10,000 iterations): Helmlab 95% CI [22.50, 23.93], CIEDE2000 95% CI [27.64, 30.84]. Zero overlap, p < 10⁻⁴.
Project Structure
src/helmlab/
├── helmlab.py # Main API (Helmlab class)
├── config.py # Configuration and constants
├── export.py # Token export (CSS, Android, iOS, Tailwind)
├── spaces/
│ ├── analytical.py # Core 72-param transform
│ ├── base.py # Abstract base class
│ ├── registry.py # Color space registry
│ ├── cam16ucs.py # CAM16-UCS baseline
│ ├── ipt.py # IPT baseline
│ ├── jzczhz.py # JzCzhz baseline
│ ├── oklch.py # Oklch baseline
│ └── srgb.py # sRGB baseline
├── metrics/
│ ├── delta_e.py # Color difference formulas
│ ├── stress.py # STRESS computation
│ └── benchmarks.py # Cross-method benchmarking
├── utils/
│ ├── srgb_convert.py # sRGB/Display P3 conversions
│ ├── gamut.py # Gamut mapping (binary search)
│ ├── conversions.py # XYZ ↔ xyY, Lab ↔ LCh, etc.
│ ├── io.py # File I/O helpers
│ └── visualization.py # Plotting utilities
├── data/
│ ├── analytical_params.json # Trained parameters (v19-NC)
│ ├── combvd.py # COMBVD dataset loader
│ ├── he2022.py # He 2022 dataset loader
│ ├── macadam1974.py # MacAdam 1974 dataset loader
│ ├── munsell.py # Munsell dataset loader
│ ├── hung_berns.py # Hung & Berns hue data
│ ├── dataset.py # Unified dataset interface
│ └── preprocessing.py # Data preprocessing
├── nn/
│ ├── inn.py # Invertible Neural Network (Phase 0)
│ ├── mlp.py # MLP baseline
│ ├── training.py # Training loop
│ ├── losses.py # Loss functions
│ └── evaluate.py # Evaluation utilities
└── feedback/
├── generator.py # Bidirectional test pair generation
└── collector.py # Human feedback collection
docs/ # Documentation + interactive demo
paper/ # LaTeX paper + figures
tests/ # 214 tests
Tests
python -m pytest tests/ -q
Citation
@article{yildiz2025helmlab,
title={Helmlab: A Data-Driven Analytical Color Space for UI Design Systems},
author={Y{\i}ld{\i}z, G{\"o}rkem},
year={2025}
}
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file helmlab-0.2.0.tar.gz.
File metadata
- Download URL: helmlab-0.2.0.tar.gz
- Upload date:
- Size: 83.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6cb9ed04ebb3dabfd17a9ba849280444d8d11a57c897ff3679da85bc89fe80fd
|
|
| MD5 |
114946ba5466f2319fab6fa2b037db3f
|
|
| BLAKE2b-256 |
76ba366a71131c224c61efdcd388c9fae74982ab75c21403a6f0caa938dbc9ad
|
File details
Details for the file helmlab-0.2.0-py3-none-any.whl.
File metadata
- Download URL: helmlab-0.2.0-py3-none-any.whl
- Upload date:
- Size: 76.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4c6375d9367225cfd7833f85c12f2ec88f96492e77320188cf3488ba22ab16b5
|
|
| MD5 |
3658b75b0cf8d134fafc757dd91684f5
|
|
| BLAKE2b-256 |
18f61764892563b91e9c6ac64757701da03d82c9e47b8a7d0d34892208746cb3
|