Options
All
  • Public
  • Public/Protected
  • All
Menu

Project @thi.ng/color

color

npm versionnpm downloads Twitter Follow

This project is part of the @thi.ng/umbrella monorepo.

For the Clojure version, please visit: thi.ng/color-clj

About

Array-based color types, conversions, transformations, declarative theme generation, multi-color gradients, presets.

Color spaces / modes

Fast color space conversions (any direction) between:

  • CSS (string, hex3/hex4/hex6/hex8, rgba(), hsla(), named colors)
  • HCYA (float4)
  • HSIA (float4)
  • HSLA (float4)
  • HSVA (float4)
  • Int32 (uint32, 0xaarrggbb)
  • RGBA (float4)
  • XYZA (float4, aka CIE 1931)
  • YCbCr (float4)

Apart from CSS and Int32 colors, all others can be stored as plain arrays, typed array or custom array-like types of (mostly) normalized values ([0,1] interval). Where applicable, the hue too is stored in that range, NOT in degrees.

Apart from conversions, most other operations provided by this package are currently only supporting RGBA colors. These can also be converted to / from sRGB (i.e. linear vs gamma corrected).

Class wrappers

The package provides lightweight class wrappers for each color mode / space. These wrappers act similarly to the Vec2/3/4 wrappers in @thi.ng/vectors, support striding (for mapped memory views), named channel accessor aliases (in addition to array indexing) and are fully compatible with all functions (and act as syntax sugar for generic conversion functions). Wrapper factory functions are provided for convenience.

Color theme generation

The package provides several methods for procedural & declarative color theme generations. The latter relies on the concept of HSV color ranges, which can be sampled directly and/or mixed with a base color to produce randomized variations. Furthermore, multiple such ranges can be combined into a weighted set to define probabilistic color themes.

// single random color drawn from the "bright" color range preset
colorFromRange(RANGES.bright);
// [ 0.7302125322518669, 0.8519945301256682, 0.8134374983367859, 1 ]

// single random color based on given HSV base color and preset
colorFromRange(RANGES.warm, [0.33, 1, 1])
// [ 0.3065587375218628, 0.8651353734302525, 0.748781892650323, 1 ]

// infinite iterator of colors sampled from the preset
// (see table below)
const colors = colorsFromRange(RANGES.bright);
colors.next();
// {
//   value: [ 0.006959075656347791, 0.8760165887192115, 0.912149937028727, 1 ],
//   done: false
// }

// 10 cool reds, w/ 10% hue variance
[...colorsFromRange(RANGES.cool, [0, 0.8, 1], { num: 10, variance: 0.1 })]

// generate colors based on given (weighted) textual description(s)
// here using named CSS colors, but could also be HSV tuples
[...colorsFromTheme(
    [["warm", "goldenrod"], ["cool", "springgreen", 0.1]],
    { num: 100, variance: 0.05 }
)]

// theme parts can also be given in the format used internally
// note: base colors are always in HSV
// all keys are optional (range, base, weight),
// but at least `range` or `base` must be given...
[...colorsFromTheme(
    [
        { range: "warm", base: "goldenrod" },
        { range: RANGES.cool, base: [0, 1, 0.5], weight: 0.1 }
    ],
    { num: 100, variance: 0.05 }
)]
ID100 colors drawn from color range preset only, sorted by hue
brightcolor swatch
coolcolor swatch
darkcolor swatch
freshcolor swatch
hardcolor swatch
intensecolor swatch
lightcolor swatch
neutralcolor swatch
softcolor swatch
warmcolor swatch
weakcolor swatch
ID100 colors, single base color w/ color range preset, sorted by hue
brightcolor swatch
coolcolor swatch
darkcolor swatch
freshcolor swatch
hardcolor swatch
intensecolor swatch
lightcolor swatch
neutralcolor swatch
softcolor swatch
warmcolor swatch
weakcolor swatch
ID100 colors, 2 base colors w/ color range preset, sorted by brightness
brightcolor swatch
coolcolor swatch
darkcolor swatch
freshcolor swatch
hardcolor swatch
intensecolor swatch
lightcolor swatch
neutralcolor swatch
softcolor swatch
warmcolor swatch
weakcolor swatch

Full example:

import { colorsFromTheme, hsva, swatchesH } from "@thi.ng/color";
import { serialize } from "@thi.ng/hiccup";
import { svg } from "@thi.ng/hiccup-svg";
import { writeFileSync } from "fs";

// color theme definition using:
// color range preset names, CSS colors and weights
const theme: ColorThemePartTuple[] = [
    ["cool", "goldenrod"],
    ["fresh", "hotpink", 0.1],
    ["light", "springgreen", 0.1],
];

// generate 200 HSV colors based on above description
const colors = [...colorsFromTheme(theme, { num: 200, variance: 0.05 })];

// create SVG doc of color swatches (hiccup format)
// (convert colors to RGB for smaller file size)
const doc = svg(
    { width: 1000, height: 50, convert: true },
    swatchesH(colors.map((x) => hsvaRgba([], x)), 5, 50)
);

// serialize to SVG file
writeFileSync("export/swatches-ex01.svg", serialize(doc));

example result color swatches

Color sorting

The sortColors() function can be used to sort an array of colors using arbitrary sort criteria. The following comparators are bundled:

  • selectChannel(i) - sort by channel
  • proximityHSV(target) - sort by distance to target color (HSV colors)
  • proximityRGB(target) - sort by distance to target color (RGB colors)
// (see above example)
const colors = [...colorsFromTheme(theme, { num: 200, variance: 0.05 })];

sortColors(colors, proximityHSV([0,1,0.5]));

sorted color swatches

RGBA transformations

RGBA color matrix transformations, including parametric preset transforms:

  • brightness
  • contrast
  • exposure
  • saturation (luminance aware)
  • hue rotation
  • color temperature (warm / cold)
  • sepia (w/ fade amount)
  • tint (green / magenta)
  • grayscale (luminance aware)
  • subtraction/inversion (also available as non-matrix op)
  • luminance to alpha

Transformation matrices can be combined using matrix multiplication / concatenation (see concat()) for more efficient application.

RGBA Porter-Duff compositing

This feature has been moved to the separate @thi.ng/porter-duff package.

Cosine gradients

The following presets are bundled (in cosine-gradients.ts):

PreviewGradient ID
gradient: blue-cyanblue-cyan
gradient: blue-magenta-orangeblue-magenta-orange
gradient: blue-white-redblue-white-red
gradient: cyan-magentacyan-magenta
gradient: green-blue-orangegreen-blue-orange
gradient: green-cyangreen-cyan
gradient: green-magentagreen-magenta
gradient: green-redgreen-red
gradient: heat1heat1
gradient: magenta-greenmagenta-green
gradient: orange-blueorange-blue
gradient: orange-magenta-blueorange-magenta-blue
gradient: purple-orange-cyanpurple-orange-cyan
gradient: rainbow1rainbow1
gradient: rainbow2rainbow2
gradient: rainbow3rainbow3
gradient: rainbow4rainbow4
gradient: red-bluered-blue
gradient: yellow-green-blueyellow-green-blue
gradient: yellow-magenta-cyanyellow-magenta-cyan
gradient: yellow-purple-magentayellow-purple-magenta
gradient: yellow-redyellow-red

Two-color gradients

The cosineCoeffs() function can be used to compute the cosine gradient coefficients between 2 start/end colors:

// compute gradient coeffs between red / green
cosineGradient(10, cosineCoeffs([1,0,0,1], [0,1,0,1])).map(rgbaCss)
// #ff0000
// #f70800
// #e11e00
// #bf4000
// #966900
// #699600
// #40bf00
// #1ee100
// #08f700
// #00ff00

Multi-stop gradients

The multiCosineGradient() function returns an iterator of raw RGBA colors based on given gradient stops. This iterator computes a cosine gradient between each color stop and yields a sequence of RGBA values.

col.multiCosineGradient(
    // num colors to produce
    10,
    // gradient stops (normalized positions, only RGBA colors supported)
    [0.1, col.RED], [0.5, col.GREEN], [0.9, col.BLUE]
)
// convert to CSS
.map(col.rgbaCss)

// [
//   "#ff0000",
//   "#ff0000",
//   "#da2500",
//   "#807f00",
//   "#25da00",
//   "#00ff00",
//   "#00da25",
//   "#00807f",
//   "#0025da",
//   "#0000ff",
//   "#0000ff",
// ]

Status

STABLE - used in production

Search or submit any issues for this package

Installation

yarn add @thi.ng/color
// ES module
<script type="module" src="https://unpkg.com/@thi.ng/color?module" crossorigin></script>

// UMD
<script src="https://unpkg.com/@thi.ng/color/lib/index.umd.js" crossorigin></script>

Package sizes (gzipped, pre-treeshake): ESM: 8.42 KB / CJS: 8.85 KB / UMD: 8.31 KB

Dependencies

Usage examples

Several demos in this repo's /examples directory are using this package.

A selection:

ScreenshotDescriptionLive demoSource
Heatmap visualization of this mono-repo's commitsSource
Visualization of different grid iterator strategiesDemoSource
Fork-join worker-based raymarch rendererDemoSource

API

Generated API docs

import * as col from "@thi.ng/color";

// route #1: asXXX() converters: string -> CSS -> ARGB (int) -> RGBA
const a = col.asRGBA(col.css("#3cf"));
// [0.2, 0.8, 1, 1]

// route #2: parseCSS(): string -> RGBA
const b = col.parseCss("hsla(30,100%,50%,0.75)");
// [ 1, 0.5, 0, 0.75 ]

// route #3: convert() multi-method: CSS -> RGBA -> HSVA
// (see convert.ts)
const c = col.convert("rgb(0,255,255)", "hsv", "css");
// [ 0.4999999722222268, 0.9999990000010001, 1, 1 ]

// route #4: direct conversion RGBA -> HSLA -> CSS
// first arg is output color (same calling convention as @thi.ng/vectors)
// (use `null` to mutate the input color)
col.hslaCss(col.rgbaHsla([], [1, 0.5, 0.5, 1]))
// "hsl(0.00,100.00%,75.00%)"

col.luminance(col.css("white"))
col.luminance(0xffffff, "int")
// 1

// apply color matrix (RGBA only)
col.transform([], col.saturation(1.25), a)
// [ 0.07835000000000002, 0.82835, 1, 1 ]

// combine matrix transformations
filter = col.concat(
    col.saturation(0.5), // 50% saturation
    col.brightness(0.1), // +10% brightness
);

col.transform([], filter, col.RED);
// [ 0.7065, 0.2065, 0.2065, 1 ]

Authors

Karsten Schmidt

If this project contributes to an academic publication, please cite it as:

@misc{thing-color,
  title = "@thi.ng/color",
  author = "Karsten Schmidt",
  note = "https://thi.ng/color",
  year = 2016
}

License

© 2016 - 2021 Karsten Schmidt // Apache Software License 2.0

Generated using TypeDoc