Skip to main content

color.js

Color space conversion and transformation utilities for image colorization

Pathjs/color.js
LanguageJavaScript
Lines557
Sourcejs/color.js
at 406d3e423

Read this when Use this page when tracing browser-side behavior, runtime state, event handling, popups, or UI code around color.

Overview​

color.js provides a comprehensive color manipulation library supporting conversions between eight color spaces (RGB, HSV, HSL, XYZ, L*a*b*, YCoCg, Oklab, Oklch) and a "colorize" transform that recolors individual color values while preserving (remapped) lightness.

The primary use case is the colorize transform, which takes an input color value and adopts a reference color's hue/chroma while remapping the input's lightness. Callers use it to theme inline SVG images: rewrite.js (enableLinkIconColor) colorizes link icons on hover, and special-occasions.js (colorizeElements) colorizes UI elements (list bullets, horizontal-rule icons) by rewriting color codes inside inline-SVG CSS variables. The module defaults to Oklch color space for colorization because it provides perceptually uniform hue manipulation with good gamut coverage.

The architecture follows a hub-and-spoke pattern: RGB serves as the interchange format, with XYZ as an intermediate step for perceptual color spaces (Lab, Oklab). All conversions route through RGB, so converting Lab→HSL goes Lab→XYZ→RGB→HSL.


Public API​

Color.processColorValue(colorString, transforms, options) → string​

Main entry point. Applies a sequence of color transforms to an input color string.

Color.processColorValue("#808080", [
{ type: Color.ColorTransform.COLORIZE, referenceColor: "#3366cc" }
]);
// → "#4a6aa3" (gray tinted blue)

Parameters:

  • colorString: Hex (#rgb or #rrggbb) or rgb()/rgba() format
  • transforms: Array of transform objects with type, referenceColor, optional colorSpace
  • options.output: "hex" or "rgba" (defaults to match input format)

Called by: rewrite.js, special-occasions.js Calls: rgbaFromString, fromRGB, rgbFrom, colorValueTransform_colorize


Color.fromRGB(rgb, targetColorSpace) → object​

Converts RGB to any supported color space.

Called by: processColorValue, external callers needing color space conversion Calls: hsvFromRGB, hslFromRGB, labFromRGB, yccFromRGB, oklabFromRGB, oklchFromRGB


Color.rgbFrom(color, sourceColorSpace) → {red, green, blue}​

Converts from any supported color space back to RGB.

Called by: processColorValue, external callers Calls: rgbFromHSV, rgbFromHSL, rgbFromLab, rgbFromYCC, rgbFromOklab, rgbFromOklch


Color.rgbaFromString(colorString) → {red, green, blue, alpha}​

Parses hex or rgba() color strings into component values (0-255 for RGB; alpha is parsed with parseInt, so fractional values are truncated).

Color.rgbaFromString("#ff8000")  // → {red: 255, green: 128, blue: 0, alpha: 1.0}
Color.rgbaFromString("rgba(255, 128, 0, 0.5)") // → {red: 255, green: 128, blue: 0, alpha: 0}

Color.hexStringFromRGB(rgb) → string​

Converts RGB object to #rrggbb hex string.


Color.rgbaStringFromRGBA(rgba) → string​

Converts RGBA object to rgba(r, g, b, a) string with padded values.


Internal Architecture​

Color Space Enum​

Color.ColorSpace = {
RGB, HSV, HSL, XYZ, Lab, YCC, Oklab, Oklch
}

Conversion Graph​

                    ┌─────┐
┌─────────┤ RGB ├─────────┐
│ └──┬──┘ │
▼ │ ▼
┌─────┐ │ ┌─────┐
│ HSV │ │ │ HSL │
└─────┘ │ └─────┘
│
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
┌─────┐ ┌─────┐ ┌─────┐
│ YCC │ │ XYZ │ │ XYZ │
└─────┘ └──┬──┘ └──┬──┘
│ │
▼ ▼
┌─────┐ ┌───────┐
│ Lab │ │ Oklab │
└─────┘ └───┬───┘
│
▼
┌───────┐
│ Oklch │
└───────┘

Transform Pipeline​

  1. Parse input string → RGBA
  2. Save original alpha
  3. For each transform:
    • Convert to working color space
    • Apply transform
    • Convert back to RGB
  4. Restore alpha
  5. Format output string

Key Patterns

Lightness Remapping in Colorize​

The colorize transform doesn't simply copy lightness—it remaps it to avoid crushing blacks or blowing out whites:

let baseLightness = Math.max(Math.min(referenceColor.L, maxBaseValue), minBaseValue);
color.L = baseLightness + (1.0 - baseLightness) * color.L;

This maps the input lightness [0,1] to [baseLightness, 1], ensuring even dark input colors get lifted to maintain the reference color's character.

Oklch Chroma Boosting​

Oklch mode includes saturation enhancement to compensate for desaturation during lightness remapping:

let maxChroma = Color.oklchFromRGB(Color.rgbFromOklch({ L: color.L, C: 1.0, h: color.h })).C;
color.C += chromaBoostFactor * (maxChroma - color.C) * (1.0 - color.L * antiClusteringFactor);

The antiClusteringFactor reduces boosting for lighter colors to prevent them from clustering at maximum saturation.

Gamut Correction​

After chroma boosting, colors may fall outside the sRGB gamut. The Oklch path includes gamut mapping:

let maxLightness = Color.oklchFromRGB(Color.rgbFromOklch({ L: 1.0, C: color.C, h: color.h })).L;
if (color.L > maxLightness)
color.C *= (1.0 - color.L) / (1.0 - maxLightness);

This reduces chroma for overly-bright colors to keep them representable.


Configuration

Color.ColorTransformSettings​

Per-color-space tuning parameters for the colorize transform:

Color SpaceParameterDefaultEffect
OklchminBaseValue0.62Minimum lightness floor
OklchmaxBaseValue0.77Maximum lightness floor
OklchchromaBoostFactor0.75Saturation enhancement strength
OklchantiClusteringFactor0.75Reduces boost for light colors
HSLsaturationBoostFactor0.50HSL-specific saturation boost
HSLantiClusteringFactor0.25HSL-specific clustering prevention

The default color space is Oklch, specified in ColorTransformSettings.colorize.defaultColorSpace.


Integration Points​

Global Object​

The module exports a single global Color object. No events or callbacks.

Input/Output Formats​

  • Input: #rgb, #rrggbb, rgb(r,g,b), rgba(r,g,b,a)
  • Output: Same format as input, or specified via options.output

Internal RGB Format​

All internal RGB representations use:

{ red: 0-255, green: 0-255, blue: 0-255, alpha?: 0-1 }

Color Space Object Formats​

SpaceProperties
HSV{ hue: 0-1, saturation: 0-1, value: 0-1 }
HSL{ hue: 0-1, saturation: 0-1, lightness: 0-1 }
XYZ{ x, y, z } (D65 illuminant)
Lab{ L: 0-1, a, b }
YCC{ Y: 0-1, Co, Cg }
Oklab{ L: 0-1, a, b }
Oklch{ L: 0-1, C: chroma, h: radians }

See Also