Skip to content
AxiomLab
v2.1.0 · closed form · MIT

Perceptual color, closed form.

AxiomLab is a perceptual color space with a strictly positive-definite Riemannian metric, calibrated on 10,486 human color-difference pairs. No lookup tables, no iterative inverse — one closed-form pipeline from XYZ to a metric you can integrate.

  • 18.18 Mean7 STRESS
  • 0.03% ideal arc CV
  • 2.33e-15 XYZ round-trip
  • 1e-15 Python ↔ JS parity
Source on GitHub Python · JavaScript · TypeScript

Playground

Two colors, five metrics, one arc

Change either color to recompute AxiomLab, HelmLab and the standard metrics in your browser. Color A also seeds the page theme — generated in AxiomLab LCh, not HCT. Gradients are generated live along each space's own interpolation path.

#0000ff
#ffffff

AxiomLab coordinates of A

L 0.3956 · a -0.1335 · b -0.3844

L

0.396

C

0.407

h°

250.9

Color difference

lower = more similar
  • AxiomLab — Power-Riemannian 0.8227
  • AxiomLab — Homogeneous ds 0.7881
  • HelmLab MetricSpace 0.1483
  • CIEDE2000 64.2339
  • OKLab (Euclidean) 0.6312
  • CIE76 149.9606

The six columns use different units and scales. HelmLab's trained distance saturates near 0.15, so compare rankings within one metric — not raw magnitudes across metrics.

Gradient paths

Same endpoints, four interpolation strategies. Equal hex steps are shown; perceptual spacing differs.

AxiomLab

Riemannian arc-length

HelmLab

GenSpace + CIEDE2000 arc-length

OKLab

linear Lab interpolation

Linear sRGB

gamma-encoded interpolation

The blue→white test

Naive RGB and some Lab paths drift through lavender. AxiomLab bends the blue region toward a sky-blue midpoint (#88a7e6); HelmLab lands at #629eff.

AxiomLab
HelmLab
OKLab
Linear
See the benchmarks AxiomLab dE on this pair: 0.8227 · HelmLab: 0.1483

Why it exists

One space, two jobs

Measurement and generation usually pull in opposite directions. AxiomLab keeps both: a trained power-Riemannian dE for near-threshold judgment, and a homogeneous degree-1 line element for arcs.

Two metrics, one tensor

The trained power form uses γd = 0.819 for near-threshold differences. The homogeneous form is degree-1, so doubling a step doubles the distance — the property arc-length integration needs.

γd

0.819

mean ideal arc CV

0.03%

tensor λmin

≥ 0.134

datasets

7

Grays stay gray

The achromatic axis is structural: the maximum chroma over the D65 gray ramp is 5.15e-14. The same transfer function generates the site theme, so neutral surfaces keep their tint without drifting in hue.

L 0.00L 0.55L 1.00

Invertible by construction

Quadratic Padé lightness plus an exact C¹ HDR extension. No search, no LUT, no branch drift.

sRGB round-trip

2.33e-15

HDR 100×

2.56e-13

Rec.2020

2.44e-15

JS ↔ Python

4.4e-16

Explore

See it in context

Quick start

One dependency: NumPy

The Python package is pure NumPy; the JavaScript build is a single 18 KB file with no dependencies. Both implement the identical closed form.

Not yet on npm / PyPI pip install "git+https://github.com/sysv86/axiomlab.git" npm install github:sysv86/axiomlab

Source installs work today. Registry uploads are pending; the plain pip install axiomlab and npm install axiomlab commands will return 404 until the first release is published.

Read the API
axiomlab.py
import axiomlab as ax

lab = ax.from_hex("#3b82f6")          # (L, a, b)
lch = ax.to_LCh(lab)                  # (L, C, h)
de  = ax.difference("#ff0055", "#00aa88")
mid = ax.mix("#0000ff", "#ffffff", 0.5, metric_step=True)
ramp = ax.gradient("#0000ff", "#ffffff", 16, metric_step=True)