Skip to content

Scale

Generate a perceptually uniform color scale in OkLCH space, producing step-keyed objects like Tailwind’s color palette format. Each step is visually equidistant. For quick hue-based palettes, see palette.

scale(input: string, options?: ScaleOptions): Record<number, string>
ParameterDescriptionTypeDefault
chromaCurveControls chroma distribution across the scalenumber | ScaleChromaPeak | ScaleRange0
formatOutput formatColorType
hueShiftHue rotation across the scale, in degreesnumber | ScaleRange0
lightnessCurveControls lightness distributionnumber | ScaleRange1.5
lockAnchor input color at this stepnumber
maxLightnessMaximum lightness (0-1)number0.97
minLightnessMinimum lightness (0-1)number0.2
mode'light', 'dark', or 'reversed'ScaleMode’light’
saturationOverride variant saturation (0-100)number
stepsNumber of steps (3-20)number11
variantPreset: 'deep', 'neutral', 'pastel', 'subtle', 'vibrant'ScaleVariant
import { scale } from 'colorizr';
scale('#3366ff');
// {
// 50: '#f0f5ff',
// 100: '#e4edff',
// 200: '#cedfff',
// 300: '#b1cbff',
// 400: '#90b4ff',
// 500: '#6a98ff',
// 600: '#4075ff',
// 700: '#2554ec',
// 800: '#0f2fc9',
// 900: '#06009a',
// 950: '#020052',
// }

Playground

50
100
200
300
400
500
600
700
800
900
950
scale('#3366ff', { variant: 'vibrant' });
scale('#3366ff', { variant: 'pastel' });
scale('#3366ff', { variant: 'neutral' });
scale('#3366ff', { variant: 'deep' });
scale('#3366ff', { variant: 'subtle' });
scale('#3366ff', { steps: 5 });
// { 100: '...', 300: '...', 500: '...', 700: '...', 900: '...' }
scale('#3366ff', { steps: 3 });
// { 100: '...', 500: '...', 900: '...' }

Use getScaleStepKeys(steps) from the utilities to see which step keys are generated for a given step count.

'light' (default) puts the lightest color at the low keys; 'dark' and 'reversed' both put it at the high keys, but differ in how:

  • 'dark' re-derives the scale with the lightness ramp running the other way.
  • 'reversed' takes the 'light' palette and reverses its keys — identical colors, mirrored order (50↔950, 100↔900, …). Use this when a dark theme must be an exact inversion of the light one.

They produce the same result only when lightnessCurve is linear (1).

Playground

50
100
200
300
400
500
600
700
800
900
950

A scalar applies one exponent across the whole scale. With { low, high } each half gets its own — low shapes the low-key half (toward 50), high the high-key half (toward 950). Reference palettes (Tailwind, Open Color) consistently fit { low: 1.5, high: 1 }: decelerating lights, near-linear darks.

scale('#3366ff', { lightnessCurve: { low: 1.5, high: 1 } });

Playground

50
100
200
300
400
500
600
700
800
900
950

Three forms control how saturation flows across the scale:

// scalar (legacy): parabolic blend centered at mid-lightness
scale('#3366ff', { chromaCurve: 0.5 });
// movable peak: choose the lightness that keeps full chroma
scale('#3366ff', { chromaCurve: { amount: 1, peak: 0.7 } });
// relative endpoints: % of the max P3 chroma at each end,
// blended through the input color at the lock/middle step
scale('#3366ff', { chromaCurve: { low: 0.9, high: 0.5 } });

The { low, high } form speaks in fractions of what the gamut allows at each step — 1 rides the most vivid color possible, 0 is gray — so values stay meaningful for every hue at every lightness. It is a different model from the scalar form: { low: 0.5, high: 0.5 } is not the same as 0.5.

Because it is gamut-relative, the input’s own chroma matters only at the anchor (lock/middle) step. An achromatic input drops the anchor fraction to 0, producing a V-shaped, colored scale — vivid at the ends, gray in the middle.

Playground

50
100
200
300
400
500
600
700
800
900
950

Rotate the hue across the scale, the way hand-tuned palettes drift cooler in the lights and warmer in the darks. Shifts blend to 0° at the lock step (or the middle step), so the input hue is preserved there.

Locking at the first or last step leaves only one side of the scale, so the unused-side value (low/high) of asymmetric options — hueShift, lightnessCurve, and the endpoint chromaCurve — has no effect and logs a warning.

// scalar: shorthand for { low: -8, high: 8 }
scale('#3366ff', { hueShift: 8 });
// independent ends: low = 50-end, high = 950-end
scale('#3366ff', { hueShift: { low: -15, high: 10 } });

Playground

50
100
200
300
400
500
600
700
800
900
950
scale('#3366ff', { format: 'oklch' });
// { 50: 'oklch(97% 0.01549 265.28)', 100: 'oklch(94.565% 0.02829 265.28)', ... }

Build and customize scales visually with ColorMeUp Lab.