A dependency-free WebGL2 shader that visualizes a color palette by mapping a color space
onto a plane or polar wheel, then snapping each pixel to the nearest palette color via a
configurable distance metric. The six views above show the same palette across the X, Y and
Z axes — the top row at one end, the bottom row at the other.
What is this for?
It shows you how a color palette distributes across "all possible colors." Each region of
the wheel or grid represents a color — and whichever palette color is closest to it claims
that region.
So if one of your palette colors only claims a tiny sliver, it lives very close to another
color already in your palette — it's almost redundant. If it claims a large region, it's
doing a lot of unique work.
How distinct each color is from the others
How balanced the palette is overall — even regions mean even coverage
Whether a new color is worth adding — if it doesn't carve out its own
space, it's probably not pulling its weight
Usage
Minimal example — pass a container or append the canvas yourself.
import { PaletteViz } from 'palette-shader';
// option A: pass a container, canvas is appended automatically
const viz = new PaletteViz({
palette: ['#f2f0e5', '#4b80ca', '#b45252', '#a2dcc7'],
container: document.querySelector('#app'),
colorModel: 'okhslPolar', // 'okhslPolar' | 'okhsvPolar' | 'oklchPolar' | 'okhsl' | …
distanceMetric: 'oklab', // 'oklab' | 'deltaE2000' | 'deltaE76' | 'rgb' | …
axis: 'y', // which axis the position slider controls
position: 0, // 0–1 slice position (0 = one extreme, 1 = other side)
invertZ: false, // flip the Z axis
});
// option B: no container — place the canvas yourself
const viz = new PaletteViz({ palette });
document.querySelector('#app').appendChild(viz.canvas);
// update live
viz.palette = ['#ff0000', '#00ff00', '#0000ff'];
viz.position = 0.3;
// clean up
viz.destroy();
Notes
No runtime dependencies — uses raw WebGL 2 and the browser's native CSS color parser.
Color models and distance metrics are orthogonal — the model controls how the color space
is rendered, the metric controls which palette color each pixel snaps to.
The typeface is the open-source
Iosevka . Created by
David Aerne .