Coloring With Code

Last Updated:

Programmatic color is useful when color decisions need to be explored, repeated, or adapted. It works best when the code names the color space and keeps the human goal visible: harmony, contrast, variation, or source-derived coherence. Once a palette is chosen, it still needs to become boring, legible CSS through role-based tokens rather than raw generated values scattered through components.

Summary

Color algorithms are small transformations over color coordinates. The useful question is not “can code generate colors?” but “which color space makes this transformation match what people see?”

Key Ideas

  • Color space is part of the algorithm. Adding 180 to hue in HSL, LCH, and OKLCH are different operations because their hue wheels and lightness meanings differ.1
  • Classic harmony can be encoded as hue rotation. Analogous, complementary, split-complementary, triadic, and tetradic palettes are generated by rotating around a color wheel while holding other channels constant.
  • LCH/OKLCH are better suited to palette generation than HSL. They expose perceived lightness and chroma, so changing one channel is less likely to accidentally change visual contrast.23
  • Discovery beats pure geometry when the palette must come from a source. Instead of inventing colors from a base color, compute ideal target palettes and then find the nearest real colors in an image, dataset, or brand palette.
  • Hue-shifted ramps feel less mechanical. For shadows and highlights, change lightness and shift hue together instead of only making a color darker or lighter.
  • Mixing is not one thing. Averaging RGB channels, mixing in CMYK, interpolating in OKLCH, and physically mixing light are different models with different use cases.45

Algorithms

Scientific Palettes

The “scientific” method starts with one base color and rotates hue by fixed steps:

PaletteHue steps
Analogous0, 30, 60
Complementary0, 180
Split-complementary0, 150, 210
Triadic0, 120, 240
Tetradic0, 90, 180, 270

George Francis’s Codrops examples use LCH, preserving lightness and chroma while changing hue.6 The HSL article shows the same family of operations in HSL: adjacent colors move by small hue steps, complements add 180, triads add 120, tetrads use two complementary pairs, and monochromatic palettes vary lightness or saturation.7

The HSL version is easy to implement, but it needs a caveat: HSL lightness is not perceived lightness. Two colors with the same HSL l can look very different, which makes HSL a risky basis for accessible design tokens.

Discovery Palettes

The discovery method reverses the usual flow:

  1. Start with a set of available colors.
  2. Treat each color as a possible base.
  3. Generate ideal target palettes from that base.
  4. Find the nearest available color for each target.
  5. Keep the palette with the lowest total difference.

This is the strongest idea in the Codrops piece. It turns color theory from a generator into a scoring function.6 That matters for real design work because palettes are often constrained by photos, existing brand colors, product surfaces, or illustrations.

The method also leaves room for policy. A palette scorer can prefer brighter colors, reject low-contrast combinations, preserve a brand accent, or avoid using the same source color twice. That policy is part of the design’s narrative: the generator should make clear whether it is optimizing for calmness, contrast, playfulness, density, brand continuity, or source fidelity.

Hue-Shifted Ramps

The hue-shift method builds a ramp around a base color:

  • darker colors move toward one hue direction;
  • lighter colors move toward another hue direction;
  • lightness is mapped between minimum and maximum bounds;
  • chroma can be held constant or adjusted separately.

This is useful for graphics, illustrations, data marks, and expressive UI states. A plain tint/shade ramp often looks sterile because every step keeps the same hue. A shifted ramp has a warmer highlight or cooler shadow, which reads more like drawn or lit material.6

Claims & Checks

HSL is convenient, not perceptually reliable

The HSL article correctly shows how simple hue arithmetic can generate familiar palette families. Its weaker claim is that HSL changes are “perceptually relevant” in a generally predictable way. MDN, Lea Verou, Codrops, and the CSS Color spec all point to the same caveat: HSL’s lightness is not the same as perceived lightness. Use HSL for quick sketches; prefer LCH or OKLCH for design systems and accessible color transformations.82

LCH/OKLCH make palette code more honest

LCH and OKLCH use lightness, chroma, and hue channels that are closer to how people discuss color. They also have rough edges: hue angles do not match HSL, some coordinate combinations fall outside a display gamut, and LCH has known blue-region hue-shift problems that OKLCH improves.

For new CSS work, OKLCH is usually the better default. Codrops used LCH in 2021, which made sense for the tutorial and library ecosystem at the time. Current CSS guidance is stronger around Oklab/OKLCH for perceptual uniformity, gradients, gamut mapping, and color modification.13

RGB or CMYK averaging is a heuristic

The JavaScript mixing article demonstrates a practical virtual-paint workflow: average RGB channels or convert RGB to CMYK, average CMYK channels, then convert back. That can be useful when the goal is an approximate picker for a known paint inventory.4

It should not be treated as physically accurate pigment simulation. CSS color-mix() makes the interpolation space explicit, and CSS Color 4 notes that different spaces serve different goals: linear-light spaces for physically mixing colored lights, Oklab/Lab for perceptual evenness, and OKLCH/LCH when preserving chroma through a transition matters.15

Important Terms

TermMeaning
hueThe angle-like color family: red, yellow, green, blue, and so on.
saturationHSL’s intensity channel; convenient, but not perceptually uniform.
lightnessA light/dark channel. In HSL it is geometric; in LCH/OKLCH it is perceptual.
chromaColorfulness in LCH/OKLCH. A low-chroma color moves toward gray.
gamutThe range of colors a device or color space can represent.
interpolationComputing colors between colors, usually for mixing, gradients, or transitions.
difference or deltaA distance function used to decide which colors are visually nearest.

Review

  • Why is a hue rotation incomplete unless the color space is named?
  • When is a fixed-step scientific palette enough, and when is discovery better?
  • Why can HSL produce poor accessible variants even when the code keeps lightness unchanged?
  • What does a hue-shifted shadow or highlight add that a plain tint/shade ramp does not?
  • Which color space would you choose for a gradient, a design-token ramp, and a physical-light simulation?

Open-Ended

  • How much hue shift should a ramp use before it starts feeling like a different palette rather than a lighting model?
  • Should project palette tools optimize contrast during generation or report contrast failures after generation?
  • For browser-native CSS, when is color-mix(in oklch, ...) enough, and when should palette generation stay in JavaScript with a library like Culori?

Takeaways

  • Use HSL algorithms to understand color-harmony geometry, not as the final basis for serious design tokens.
  • Prefer OKLCH or LCH when color code is meant to preserve perceived lightness, chroma, or contrast.
  • Treat palette generation as both math and policy: generate candidates, score them against the context, then name the chosen colors by role.

References

Footnotes

  1. CSS Working Group, “CSS Color Module Level 4.” https://www.w3.org/TR/css-color-4/ 2 3

  2. Lea Verou, “LCH colors in CSS: what, why, and how?” April 4, 2020. https://lea.verou.me/blog/2020/04/lch-colors-in-css-what-why-and-how/ 2

  3. Andrey Sitnik and Travis Turner, “OKLCH in CSS: why we moved from RGB and HSL,” Evil Martians, September 17, 2025. https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl 2

  4. Adam Nathaniel Davis, “Color Mixing With JavaScript,” DEV Community, February 28, 2023. https://dev.to/bytebodger/color-mixing-with-javascript-1llh 2

  5. CSS Working Group, “CSS Color Module Level 5.” https://www.w3.org/TR/css-color-5/ 2

  6. George Francis, “Coloring With Code — A Programmatic Approach To Design,” Codrops, December 7, 2021. https://tympanus.net/codrops/2021/12/07/coloring-with-code-a-programmatic-approach-to-design/ 2 3

  7. monkeymore studio, “Color Palette Generation Algorithms: A Deep Dive into HSL-Based Color Theory,” DEV Community, posted Apr. 3; accessed July 7, 2026. https://dev.to/linmingren/color-palette-generation-algorithms-a-deep-dive-into-hsl-based-color-theory-p1d

  8. MDN Web Docs, “lch() CSS function.” https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/lch