color
stableColor manipulation library supporting HSL, HSV, LAB, CMYK, hex, CSS strings, blending, palettes, and WCAG accessibility checks.
use plugin color Plugin snippets can be edited in the Playground, but native capabilities are executed locally with the Zolo CLI.
Functions (31)
- rgb_to_hsl Convert RGB to HSL
- hsl_to_rgb Convert HSL to RGB
- rgb_to_hsv Convert RGB to HSV
- hsv_to_rgb Convert HSV to RGB
- hex_to_rgb Parse a hex color string to RGB
- rgb_to_hex Convert RGB values to a hex string
- lerp_color Linearly interpolate between two colors
- luminance Compute WCAG relative luminance
- contrast_ratio Compute WCAG contrast ratio from two luminances
- complement Get the complement of an RGB color
- darken Darken an RGB color by a factor
- lighten Lighten an RGB color by a factor
- is_dark Check if an RGB color is perceptually dark
- rgb_to_lab Convert RGB to CIE L\*a\*b\*
- lab_to_rgb Convert CIE L\*a\*b\* to RGB
- delta_e Perceptual color difference between two Lab colors
- rgb_to_cmyk Convert RGB to CMYK
- cmyk_to_rgb Convert CMYK to RGB
- temperature_to_rgb Convert color temperature (Kelvin) to RGB
- palette_from_image Extract dominant colors from RGBA bytes
- gradient Generate a color gradient between two colors
- triadic Get three triadic colors from an RGB color
- analogous Get three analogous colors at a given angle
- wcag_contrast_level Classify a contrast ratio as AA, AAA, or fail
- random_color Generate a deterministic random color from a seed
- blend Blend two colors with a named blend mode
- parse Parse a CSS color string to RGB
- to_css_string Convert an RGB table to a CSS rgb() string
- saturate Increase saturation of an RGB color
- desaturate Decrease saturation of an RGB color
- grayscale Convert an RGB color to grayscale
From import to result
- 01Import only what you use
- 02Copy the smallest example
- 03Run it with the Zolo CLI
Overview¶
The color plugin is a stateless toolkit for working with colors across the
spaces designers and engineers actually use: RGB, HSL, HSV, CIE L*a*b*, and
CMYK, plus hex and CSS string forms. There are no handles or objects to manage —
every function is a pure transformation. Channel-based functions take and return
loose numbers (RGB as 0–255, hue in degrees, saturation/lightness as 0–1),
while functions that work on whole colors (gradient, blend, delta_e,
to_css_string) accept and return {r, g, b} (or {l, a, b}) tables. Reach for
it whenever you need color math: building gradients and palettes, generating
harmonious schemes (triadic, analogous, complement), or validating that text
meets WCAG contrast requirements.
Common patterns¶
Check whether a foreground/background pair is accessible by combining
luminance, contrast_ratio, and wcag_contrast_level:
use plugin color::{luminance, contrast_ratio, wcag_contrast_level}
let fg = luminance(40.0, 40.0, 40.0)
let bg = luminance(255.0, 255.0, 255.0)
let ratio = contrast_ratio(fg, bg)
print("ratio: {ratio} -> {wcag_contrast_level(ratio)}")Round-trip a CSS string through RGB, tweak it, and emit CSS again:
use plugin color::{parse, darken, to_css_string}
let base = parse("#ff8800")
let darker = darken(base["r"], base["g"], base["b"], 0.25)
print(to_css_string(darker))Build a smooth gradient between two named colors and read out a stop:
use plugin color::{parse, gradient}
let start = parse("red")
let end = parse("blue")
let stops = gradient(start, end, 7)
let mid = stops[3]
print("middle stop: {mid["r"]}, {mid["g"]}, {mid["b"]}")Convert RGB to HSL
Converts an RGB color (0–255 each) to HSL. Returns a table with h
(0–360 degrees), s (0–1), and l (0–1).
use plugin color::{rgb_to_hsl}
let hsl = rgb_to_hsl(255.0, 128.0, 0.0)
print("hue: {hsl["h"]}, saturation: {hsl["s"]}, lightness: {hsl["l"]}")Convert HSL to RGB
Converts HSL to RGB (0–255 each). h is in degrees (0–360), s and l
are 0–1.
use plugin color::{hsl_to_rgb}
let rgb = hsl_to_rgb(120.0, 1.0, 0.5)
print("r: {rgb["r"]}, g: {rgb["g"]}, b: {rgb["b"]}")Convert RGB to HSV
Converts RGB (0–255) to HSV. Returns h (0–360), s (0–1), v (0–1).
use plugin color::{rgb_to_hsv}
let hsv = rgb_to_hsv(255.0, 0.0, 0.0)
print("h: {hsv["h"]}, s: {hsv["s"]}, v: {hsv["v"]}")Convert HSV to RGB
Converts HSV to RGB (0–255 each). h is in degrees (0–360), s and v
are 0–1.
use plugin color::{hsv_to_rgb}
let rgb = hsv_to_rgb(200.0, 0.8, 0.9)
print("r: {rgb["r"]}, g: {rgb["g"]}, b: {rgb["b"]}")Parse a hex color string to RGB
Parses a hex color string (#rgb or #rrggbb) and returns {r, g, b}
(0–255).
use plugin color::{hex_to_rgb}
let rgb = hex_to_rgb("#ff8800")
print("r: {rgb["r"]}, g: {rgb["g"]}, b: {rgb["b"]}")
let short = hex_to_rgb("#f80")
print("r: {short["r"]}")Convert RGB values to a hex string
Converts RGB values (0–255) to a lowercase hex color string like #ff8800.
use plugin color::{rgb_to_hex}
let hex = rgb_to_hex(255.0, 136.0, 0.0)
print(hex)Linearly interpolate between two colors
Linearly interpolates between two RGB colors. t is 0–1 where 0 returns
the first color and 1 returns the second.
use plugin color::{lerp_color}
let mid = lerp_color(255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.5)
print("r: {mid["r"]}, g: {mid["g"]}, b: {mid["b"]}")Compute WCAG relative luminance
Returns the WCAG 2.1 relative luminance (0–1) of an RGB color. Use with
contrast_ratio for accessibility checks.
use plugin color::{luminance}
let lum = luminance(255.0, 255.0, 255.0)
print("white luminance: {lum}")Compute WCAG contrast ratio from two luminances
Computes the WCAG contrast ratio from two luminance values. A result of 4.5 or higher passes AA for normal text.
use plugin color::{luminance, contrast_ratio, wcag_contrast_level}
let l1 = luminance(0.0, 0.0, 0.0)
let l2 = luminance(255.0, 255.0, 255.0)
let ratio = contrast_ratio(l1, l2)
print("contrast ratio: {ratio}")Get the complement of an RGB color
Returns the RGB complement (255 - each channel) of a color.
use plugin color::{complement}
let c = complement(255.0, 128.0, 0.0)
print("complement: {c["r"]}, {c["g"]}, {c["b"]}")Darken an RGB color by a factor
Darkens an RGB color by multiplying each channel by (1 - amount).
amount is 0–1.
use plugin color::{darken}
let dark = darken(200.0, 150.0, 100.0, 0.3)
print("darkened: {dark["r"]}, {dark["g"]}, {dark["b"]}")Lighten an RGB color by a factor
Lightens an RGB color by blending toward white by amount (0–1).
use plugin color::{lighten}
let light = lighten(100.0, 50.0, 0.0, 0.5)
print("lightened: {light["r"]}, {light["g"]}, {light["b"]}")Check if an RGB color is perceptually dark
Returns true if the color's relative luminance is below 0.179, indicating a perceptually dark color. Useful for choosing white vs black overlay text.
use plugin color::{is_dark}
print(is_dark(0.0, 0.0, 0.0))
print(is_dark(255.0, 255.0, 255.0))Convert RGB to CIE L\*a\*b\*
Converts RGB (0–255) to CIE L*a*b* color space. Returns l, a, b
fields. L*a*b* is perceptually uniform and suited for color difference math.
use plugin color::{rgb_to_lab}
let lab = rgb_to_lab(255.0, 0.0, 0.0)
print("L: {lab["l"]}, a: {lab["a"]}, b: {lab["b"]}")Convert CIE L\*a\*b\* to RGB
Converts CIE L*a*b* back to RGB (0–255). Values are clamped to the sRGB gamut.
use plugin color::{lab_to_rgb}
let rgb = lab_to_rgb(50.0, 25.0, -30.0)
print("r: {rgb["r"]}, g: {rgb["g"]}, b: {rgb["b"]}")Perceptual color difference between two Lab colors
Computes the CIE76 color difference (Delta E) between two L*a*b* color tables. Values below 2.3 are imperceptible to the human eye.
use plugin color::{rgb_to_lab, delta_e}
let lab1 = rgb_to_lab(255.0, 0.0, 0.0)
let lab2 = rgb_to_lab(250.0, 10.0, 0.0)
let de = delta_e(lab1, lab2)
print("color difference: {de}")Convert RGB to CMYK
Converts RGB (0–255) to CMYK (0–1 each). Returns c, m, y, k fields.
Useful for print-oriented color workflows.
use plugin color::{rgb_to_cmyk}
let cmyk = rgb_to_cmyk(255.0, 0.0, 0.0)
print("c: {cmyk["c"]}, m: {cmyk["m"]}, y: {cmyk["y"]}, k: {cmyk["k"]}")Convert CMYK to RGB
Converts CMYK (0–1 each) to RGB (0–255 each).
use plugin color::{cmyk_to_rgb}
let rgb = cmyk_to_rgb(0.0, 1.0, 1.0, 0.0)
print("r: {rgb["r"]}, g: {rgb["g"]}, b: {rgb["b"]}")Convert color temperature (Kelvin) to RGB
Converts a color temperature in Kelvin to an approximate RGB color. Useful for warm/cool lighting effects. Typical daylight is around 6500K.
use plugin color::{temperature_to_rgb}
let warm = temperature_to_rgb(3000.0)
print("warm light: {warm["r"]}, {warm["g"]}, {warm["b"]}")
let cool = temperature_to_rgb(6500.0)
print("daylight: {cool["r"]}, {cool["g"]}, {cool["b"]}")Extract dominant colors from RGBA bytes
Extracts n_colors dominant colors from raw RGBA pixel data using k-means
clustering (20 iterations). Returns a table of {r, g, b} tables.
use plugin color::{palette_from_image}
// rgba_bytes would typically come from an image-loading plugin
// let palette = palette_from_image(raw_bytes, 800, 600, 5)
// print("dominant colors: {#palette}")Generate a color gradient between two colors
Generates a linear gradient of steps colors between two {r, g, b} tables.
Returns a table of {r, g, b} color tables indexed from 0.
use plugin color::{gradient}
let red = #{"r": 255.0, "g": 0.0, "b": 0.0}
let blue = #{"r": 0.0, "g": 0.0, "b": 255.0}
let grad = gradient(red, blue, 5)
print("gradient step 3: {grad[2]["r"]}, {grad[2]["g"]}, {grad[2]["b"]}")Get three triadic colors from an RGB color
Returns three triadic colors (hue shifts of 0°, 120°, 240°) as a table of
{r, g, b} tables indexed 0, 1, 2.
use plugin color::{triadic}
let colors = triadic(255.0, 0.0, 0.0)
print("first: {colors[0]["r"]}, {colors[0]["g"]}, {colors[0]["b"]}")
print("second: {colors[1]["r"]}, {colors[1]["g"]}, {colors[1]["b"]}")Get three analogous colors at a given angle
Returns three analogous colors (hue at -angle, original, +angle) as a table
of {r, g, b} tables. A common angle is 30°.
use plugin color::{analogous}
let colors = analogous(255.0, 0.0, 0.0, 30.0)
print("left: {colors[0]["r"]}, {colors[0]["g"]}, {colors[0]["b"]}")
print("right: {colors[2]["r"]}, {colors[2]["g"]}, {colors[2]["b"]}")Classify a contrast ratio as AA, AAA, or fail
Returns "AAA" if ratio >= 7.0, "AA" if ratio >= 4.5, or "fail"
otherwise. Use after contrast_ratio.
use plugin color::{luminance, contrast_ratio, wcag_contrast_level}
let l1 = luminance(0.0, 0.0, 0.0)
let l2 = luminance(255.0, 255.0, 255.0)
let level = wcag_contrast_level(contrast_ratio(l1, l2))
print("WCAG level: {level}")Generate a deterministic random color from a seed
Generates a deterministic pseudo-random RGB color from an integer seed. Same seed always produces the same color.
use plugin color::{random_color}
let c = random_color(42)
print("r: {c["r"]}, g: {c["g"]}, b: {c["b"]}")Blend two colors with a named blend mode
Blends two {r, g, b} color tables using a blend mode. Supported modes:
"multiply", "screen", "overlay", "soft_light".
use plugin color::{blend}
let a = #{"r": 200.0, "g": 100.0, "b": 50.0}
let b = #{"r": 80.0, "g": 160.0, "b": 200.0}
let result = blend(a, b, "multiply")
print("blended: {result["r"]}, {result["g"]}, {result["b"]}")Parse a CSS color string to RGB
Parses a CSS color string to {r, g, b}. Supports #rgb, #rrggbb,
rgb(r,g,b), and the 17 basic CSS named colors (black, white, red, etc.).
use plugin color::{parse}
let c1 = parse("#ff8800")
let c2 = parse("rgb(255, 128, 0)")
let c3 = parse("orange")
print("r: {c3["r"]}, g: {c3["g"]}, b: {c3["b"]}")Convert an RGB table to a CSS rgb() string
Converts a {r, g, b} table to a CSS rgb(r, g, b) string.
use plugin color::{to_css_string, parse}
let c = parse("blue")
let css = to_css_string(c)
print(css)Increase saturation of an RGB color
Increases the saturation of an RGB color by amount (0–1) in HSL space.
use plugin color::{saturate}
let vivid = saturate(150.0, 100.0, 80.0, 0.3)
print("saturated: {vivid["r"]}, {vivid["g"]}, {vivid["b"]}")Decrease saturation of an RGB color
Decreases the saturation of an RGB color by amount (0–1) in HSL space.
use plugin color::{desaturate}
let muted = desaturate(200.0, 50.0, 30.0, 0.5)
print("desaturated: {muted["r"]}, {muted["g"]}, {muted["b"]}")Convert an RGB color to grayscale
Converts an RGB color to its grayscale equivalent by zeroing saturation in HSL space.
use plugin color::{grayscale}
let gray = grayscale(200.0, 80.0, 40.0)
print("gray: {gray["r"]}, {gray["g"]}, {gray["b"]}")