Each module states one fact about digital color and gives you an instrument to test it. The controls are the main content — the text explains what you're seeing, but the understanding comes from manipulating the thing yourself. The modules run in a loose sequence: first how perception works, then the systems that put numbers on it.
Value vs. Luminance
HSV's value channel doesn't measure how bright a color looks. At V = 100, actual luminance varies by roughly 13× across hues.
Open → 02 · PerceptionMagenta and Non-Spectral Colors
No single wavelength produces magenta. It exists only as a mixture — red and blue light together, with little green.
Open → 03 · SystemsSaturation Across Models
Turning up saturation darkens a color in HSV, shifts with hue in HSL and sRGB, and leaves lightness alone in OKLCH. Same slider, different operations.
Open → 04 · SystemsThe Perceptual Ramp Builder
Equal numeric steps between two colors are not perceptually equal. Compare interpolation in five spaces and export the ramp that works.
Open → 05 · SystemsWhy Color Spaces Exist
Blend blue to yellow in sRGB and the middle of the gradient turns gray. Every color space since was invented to fix a failure like this one.
Open → 06 · Dynamic rangeColor Collapse in Tone Mapping
Brighten a saturated color and its hue shifts as channels clip. The tone map decides whether that shift is a filmic feature or a broken brand color.
Open →Module 1 · Perception
HSV's value and HSL's lightness are not measures of brightness. Perceived brightness is luminance — a weighted sum of the primaries in which green counts for far more than red, and red for far more than blue — so two colors with identical value can differ several-fold in luminance.
How it works
The eye does not weight red, green, and blue equally. Its sensitivity peaks in the middle of the spectrum, near green, and falls off steeply toward blue — the same amount of light produces far less brightness sensation at 450 nm than at 555 nm. Relative luminance is the number that captures this: a weighted sum of the linearized RGB channels, with weights matched to the eye. Under Rec. 709, Y = 0.2126·R + 0.7152·G + 0.0722·B. Green carries nearly three-quarters of the total; blue carries about 7%.
HSV's value channel involves no weighting at all — V is simply the largest of the three channel values. Full-value yellow lights the red and green subpixels, which together carry about 93% of white's luminance. Full-value blue lights only the blue subpixel: about 7%. Both report V = 100. The instrument below sweeps the full hue circle so you can watch actual luminance swing while V insists nothing is changing.
The weights also explain the shape of the curve. Cyan, magenta, and yellow each light two subpixels at once, and luminance simply adds: yellow is red plus green (21% + 72% ≈ 93%), cyan is green plus blue (≈ 79%), magenta is red plus blue (≈ 28%). Those three sums are the curve's peaks, and they mean every two-subpixel secondary is brighter than either primary inside it. In the instrument, each subpixel combination sits directly beneath its position on the curve — secondaries under the peaks, lone primaries under the valleys.
Module 2 · Perception
Magenta is a non-spectral color: no single wavelength produces it. It appears only when the eye receives long and short wavelengths at once, filling the gap the spectrum leaves between red and violet.
How it works
The visible spectrum runs from about 380 nm (violet) to 700 nm (red), and it is a line — no wavelength bends red back around toward violet. The chart below, the CIE 1931 chromaticity diagram, maps every chromaticity the eye can distinguish. Pure single wavelengths form the curved rim, called the spectral locus. Mixing two lights always produces a color on the straight line between their positions, which is why every visible color falls somewhere inside the horseshoe.
The straight edge along the bottom is the exception to the rim: the line of purples. It connects the violet end of the spectrum directly to the red end, and no point on it corresponds to any wavelength. The colors there — magenta among them — can only be produced by mixing light from the spectrum's two far ends. When the eye's long-wavelength and short-wavelength cones respond strongly while the middle stays quiet, the visual system produces magenta. The color is real; it simply has no position in the rainbow.
Module 3 · Systems
"Increase saturation" is a different operation in every color model, and most of them change the color's lightness as a side effect.
How it works
Every model agrees that saturation is distance from gray. They disagree about which gray, and about what else is allowed to change on the way there. HSV holds the maximum channel fixed and pulls the other two down — an operation that can only remove light, so saturating in HSV always darkens, and a fully desaturated color at V = 100 is white. HSL instead pins the midpoint of the highest and lowest channels. Whether luminance rises or falls then depends on which channels are doing the moving, and that depends on hue: saturating a yellow at 50% lightness brightens it dramatically, while saturating a blue darkens it.
The saturation slider in most raster editors is a third operation: scale all three channels away from their average. Where that leads follows from Module 1's channel weights — hues whose light lives mostly in the red and green channels gain luminance as they spread away from gray, and blues lose it.
CIELab and OKLCH are the only models here that treat lightness as a protected axis. Chroma is defined perpendicular to it, so C can change while L holds still — visible in the graph below as two nearly flat lines. One footnote applies even there: at equal measured luminance, a strongly saturated color still looks slightly brighter than gray, an effect known as Helmholtz–Kohlrausch. Constant lightness in the numbers is very close to constant lightness in experience, but not identical.
Module 4 · Systems
Equal numeric steps between two colors are not perceptually equal. Perceptually uniform spaces produce visually even steps by design.
How it works
All five ramps below do the same thing: divide the interval between your endpoints into equal steps. What differs is the ruler. sRGB and HSL measure the interval with channel arithmetic; CIELab, OKLab, and OKLCH measure it in coordinates that were fitted to human judgments of color difference.
The graph shows what each ruler ignores. The dashed line is the quantity the selected space kept perfectly even — its own lightness metric. The solid line is measured lightness, L*, for the same steps. In HSL the dashed line is ruler-straight while L* swings around it, and those swings are the muddy middles you can see in the swatches. Select the OKLCH row and the two lines nearly coincide: the quantity the space keeps even is, finally, the one your eye cares about.
The geometry view explains the differences in shape terms. sRGB, CIELab, and OKLab are rectangular spaces, so a blend is a straight line through the interior — and between near-complementary endpoints, the interior is neutral gray. HSL and OKLCH are cylinders: hue is an angle, so a blend travels around the central gray axis instead of through it. That is also why a cylindrical blend between near-opposite hues has to choose a direction — the two arcs around the axis are nearly the same length, and the hue-path control makes that choice explicit.
Module 5 · Systems
No single color space is correct for everything. Each was created to solve a problem the earlier ones could not — defining a color independently of any device, making numeric distance match perceived distance, or keeping a gradient from passing through gray.
How it works
Blue and yellow sit at opposite corners of the RGB cube, so averaging their channel values lands the midpoint near the cube's center — and the center of the RGB cube is gray. Nothing malfunctioned. "Average the numbers" corresponds to "blend the appearance" only if the space was built with appearance in mind, and RGB was built to drive hardware. Failures of exactly this shape are what produced each new space: every timeline entry below pairs a space with the problem it was created to solve, and selecting one loads endpoints that reproduce the problem in the strips.
Module 6 · Dynamic range
Brighten a saturated color and its hue shifts as its channels clip. The tone map you choose decides whether that shift reads as filmic or as a broken brand color.
How it works
A rendered or photographed scene holds light values far above what a display can show, so a tone map has to fit that unbounded range into the 0–1 the screen can emit. The simplest way is to clip: cap each channel at 1. But a saturated color is a specific ratio between its channels, and when the brightest channel hits the ceiling while the others keep climbing, that ratio changes — which means the hue changes. Push a saturated orange up and its red pins at 1 while green keeps rising, so it slides toward yellow.
Because pure primaries and secondaries have channels that clip together or not at all, they hold their hue, while every hue between them migrates toward the nearest one. Do this across the whole wheel and the hues bunch into six attractors — red, yellow, green, cyan, blue, magenta — the "notorious six" collapse familiar from bright renders and blown-out highlights. Per-channel curves like Reinhard and the common ACES fit soften the clip but skew the same way, because they still operate channel by channel.
AgX takes a different route: it desaturates the highlight as it brightens, pulling chroma out on the way to white so no single channel has to clip against the others. Hue is preserved, at the cost of vivid highlights washing to white sooner. That trade is the whole debate — the plot below lets you watch each mapper's hue drift, and the wheel shows where every hue lands.