@amplib/color

GitHub ↗

Perceptual hue

HSV hue is what a camera reports and what people use to name a color on a screen. Oklch hue is the angle human vision reads as evenly spaced. Both run 0–360°, and the mapping between them is severely non-linear — over two hundredfold between the extremes. This package is the bijection between the two, and nothing else.

toPerceptual(hue: number) → number
fromPerceptual(hue: number) → number

Evenly spaced, both ways

The same request — give me N evenly spaced hues — answered twice. The top row divides 360 by N, and its greens run together while its blues barely separate. The bottom row asks for the same division in perceptual space. Neither row is more correct in the arithmetic; only one of them looks like what was asked for.

360 / N

fromPerceptual(i × 360 / N)

The same division, drawn twice

Display hue

Angle is HSV hue. Equal sectors, unequal arcs.

Perceptual hue

Angle is oklch hue. The same sectors, evenly spaced.

Round trip

The forward table samples oklch once per display degree; the inverse searches it backwards at twenty times that resolution, because the deep-blue zone squeezes roughly 16 display degrees into half a perceptual degree. They are built by different methods and only approximately invert each other, so the disagreement is measured rather than assumed — worstRoundTripError() reports the worst case, and npm test fails above 1.5°. Drag through the deep blues around 230° to find the widest gaps.