Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@johnny95731/color-utils

johnny95731554MIT1.2.2TypeScript support: included

High-performance color utilities that including conversions, harmonies, mix, and sort.

color, color-utils, rgb, hex, hsl, hsv, hwb, cmyk, xyz, lab, luv, lch, harmony, converter, sort

readme

color-utils

color-utils provides functions for color conversions, harmonies, mix, and sort.

:speech_balloon: Newer README.md may push to github but not publish in npm. To see detail changes: Changelog (record since v1.2.0).

Features

  • Small: 10.7KB for conversions only. 14.6KB in total (13.1KB with mangle.properties.regex). (with minifying)
  • High performance. Benchmark
  • Detect browser <color> support when getting string.
  • Functions instead of object. Tree-shaking and minifying are more simpler.
  • Immutable.
  • Typed.
  • Supports ESM and CJS.
  • No dependencies

Install

npm install @johnny95731/color-utils

Usage

import { rgb2hex, rgb2hsb, rgb2gray, randRgbGen } from '@johnny95731/color-utils';

const rgb = randRgbGen(); // [0, 127, 200];

rgb2hex(rgb);  // "#007FC8"
rgb2hsb(rgb);  // [ 201.9, 100, 78.43137254901961 ]
rgb2gray(rgb); // 97.34899999999999

Supported Color Spaces

More infomations abous color spaces: Color Space Ranges

  • RGB
  • HEX (including 3 and 6 digits.)
  • HSL
  • HSB (alias of HSV)
  • HWB
  • CMYK
  • NAMED (Closest CSS <named-color>).

Absolute color space:

  • XYZ (D65 is the default of reference white. Calling setReferenceWhite('D50') to switch to D50)
  • LAB
  • LCHab
  • LUV
  • LCHuv
  • Oklab
  • Oklch

API

<summary>randRgbGen(): number[]</summary>

Return a random RGB array.

Basic Conversions

The naming of converters is connecting input space and output space with a letter 2(to). Most conversinons are group of two, rgb2space and space2rgb. For example, rgb2hsl and hsl2rgb.

// HEX
const hex = rgb2hex([1, 100, 255]); // "#0164FF"
const rgb = hex2rgb(hex);           // [ 1, 100, 255 ]

// HSL
const hsl = rgb2hsl([1, 100, 255]); // [ 216.61417322834643, 100, 50.19607843137255 ]
const rgb = hsl2rgb(hsl);           // [ 0.9999999999999964, 100.00000000000004, 255 ]

// HSB
const hsb = rgb2hsb([1, 100, 255]); // [ 216.61417322834643, 99.6078431372549, 100 ]
const rgb = hsb2rgb(hsb);           // [ 0.9999999999999964, 100.00000000000004, 255 ]

// HWB
const hwb = rgb2hwb([1, 100, 255]); // [ 216.61417322834643, 0.39215686274509803, 0 ]
const rgb = hwb2rgb(hwb);           // [ 0.9999999999999964, 100.00000000000004, 255 ]

// CMYK
const cmyk = rgb2cmyk([1, 100, 255]); // [ 99.6078431372549, 60.7843137254902, 0, 0 ]
const rgb  = cmyk2rgb(cmyk);          // [ 0.9999999999999964, 99.99999999999999, 255 ]

// NAMED
const named = rgb2named([1, 100, 255]); // "DodgerBlue"
const rgb   = named2rgb(named);         // [ 30, 144, 255 ]

// XYZ
const xyz = rgb2xyz([1, 100, 255]); // [ 22.613136041016254, 16.337688949026983, 96.5499520366833 ]
const rgb = xyz2rgb(xyz);           // [ 1.0000000000002303, 100, 254.99999999999997 ]

// LAB
const lab = rgb2lab([1, 100, 255]); // [ 47.41444304992909, 36.482845533090725, -82.80897290339001 ]
const rgb = lab2rgb(lab);           // [ 1.0000000000000473, 100.00000000000001, 254.99999999999997 ]

// LCHab
const lchab = rgb2lchab([1, 100, 255]); // [ 47.41444304992909, 90.4893585539523, 293.7766742151484 ]
const rgb   = lchab2rgb(lchab);         // [ 1.0000000000000473, 100.00000000000001, 254.99999999999997 ]

// LUV
const luv = rgb2luv([1, 100, 255]); // [ 47.41444304992909, -21.908342012473863, -126.05599759161 ]
const rgb = luv2rgb(luv);           // [ 0.9999171617417457, 100.00000667555592, 254.99998841698246 ]

// LCHuv
const lchuv = rgb2lchuv([1, 100, 255]); // [ 47.41444304992909, 127.94565244099353, 260.1405639338026 ]
const rgb   = lchuv2rgb(lchuv);         // [ 0.9999171617399168, 100.00000667555597, 254.99998841698252 ]

// Oklab
const oklab = rgb2oklab([1, 100, 255]); // [ 0.5597865171261192, -0.03749415892366231, -0.24017306119022924 ]
const rgb   = oklab2rgb(oklab);         // [ 1.0000000000002303, 99.9999999999999, 254.99999999999997 ]

// Oklch
const oklch = rgb2oklch([1, 100, 255]); // [ 0.5597865171261192, 0.24308210809287967, 261.12699837778 ]
const rgb   = oklch2rgb(oklch);         // [ 0.9999999999996816, 99.99999999999994, 254.99999999999997 ]

Error Handling

hex2rgb and named2rgb return [0, 0, 0] when the input is invalid.

ColorSpaceType

COLOR_SPACES array stores ColorSpace objects, which contains informations about spaces

key info
name_ Name of color space
isSupported_ In browser environment, the value will be initialized by calling CSS.supports('color', 'space(0 0 0)');. In node environment, the value will be set to default value as below.
labels_ Labels of channels.
max_ Ranges of channels.
fromRgb_ Converter from RGB to space.
toRgb_ Converter from space to RGB.

Note: COLOR_SPACES does not have HEX and NAMED space. And, both LCHab and LCHuv will check CSS.supports('color', 'lch(0 0 0)'); though these two spaces are not equvalent.

<summary>Default values of ColorSpace.isSupported_</summary>
space value
RGB true
HSL true
HSB false
HWB true
CMYK false
XYZ true
LAB true
LCHab true
LUV false
LCHuv true
Oklab true
Oklch true

Argumemts with type ColorSpace | string can input ColorSpace object or space name:

  • The space name is case-insensitive.
  • 'HEX' and 'NAMED' are not valid names.
  • Invalid name will be regarded as RGB space.
<summary>getColorSpace(space: ColorSpace | string): ColorSpace</summary>

Return an item in COLOR_SPACES. If space argument is a invalid string, that is, find the item that ColorSpace.name_ === space (if no such item, return RGB space).

<summary>toSpace(color: readonly number[], space: ColorSpace | string, to: ColorSpace | string ): number[] </summary>

Convert color from a space to target space.

toSpace([176, 59, 79], 'RGB', 'XYZ'); // [ 20.88159899406145, 12.925309240980702, 8.790857610353417 ]
rgb2xyz([176, 59, 79]);               // [ 20.88159899406145, 12.925309240980702, 8.790857610353417 ]
<summary>getCssColor(color: readonly number[], space: ColorSpace | string, options?: CssColorOptions): string</summary>

Convert the color to string.

If checkSupport is true, then the function will set sep = ' ' and change the color space to RGB when the browser does not support this color space.

getCssColor([140, 17, 243], 'RGB');                        // "rgb(54.9% 6.67% 95.29%)"
getCssColor([140, 17, 243], 'RGB', { sep_: "," });         // "rgb(54.9%,6.67%,95.29%)"
getCssColor([140, 17, 243], 'RGB', { percent_: false });   // "rgb(140 17 243)"
getCssColor([273, 90, 51], 'HSL');                         // "hsl(273 90% 51%)"
getCssColor([27, 12, 86], 'xyz');                          // "xyz(28.41% 12% 78.98%)"
getCssColor([27, 12, 86], 'xyz', { checkSupport_: true }); // "color(xyz-d65 28.41% 12% 78.98%)"
type CssColorOptions = {
  /**
   * Check the browser support or not. If browser does not support the color,
   * return string in RGB space.
   * @default false
   */
  checkSupport_?: boolean,
  /**
   * Seperator of values. If checkSupport_ is true, the seperator will always be ' '
   * @default ' '
   */
  sep_?: string,
  /**
   * Convert all values to percent except deg.
   * @default true
   */
  percent_?: boolean,
  /**
   * Argument for rounding values. Set false to disable rounding. true equials
   * default value.
   * @default 2
   */
  place_?: number | boolean
}

See also

<summary>rgbArraylize(rgb: readonly number[] | string): readonly number[]</summary>

Normalize RGB or HEX to array type.

<summary>setReferenceWhite(white: 'D65' | 'D50'): void</summary>

Change the reference white of CIEXYZ space. This library only support sRGB for RGB model. This function will change .max_ property of XYZ space.

Color Space Ranges

Most values are referred to CSS definition.

<summary>RGB</summary>
channel description min max
r Red 0 255
g Green 0 255
b Blue 0 255
<summary>HSL</summary>
channel description min max
h Hue 0 360
s Saturation 0 100
l Luminance 0 100
<summary>HSB</summary>
channel description min max
h Hue 0 360
s Saturation 0 100
b Brightness 0 100
<summary>HWB</summary>
channel description min max
h Hue 0 360
w Whiteness 0 100
b blackness 0 100
<summary>CMYK</summary>
channel description min max
c Cyan 0 100
m Magenta 0 100
y Yellow 0 100
k key/black 0 100
<summary>NAMED</summary>
channel description
key <named-color>

Several keywords are aliases for each other, we only preserve one of alias:

preserved removed
cyan aqua
magenta fuchsia
gray grey

and other 6 groups of alias that containing 'gray' (preserved) or 'grey' (removed).

<summary>XYZ</summary>

The maximum value is based on RGB model and reference white. y channel will be normalize to 100. The library currently only supports sRGB as RGB model and D65 (default) and D50 as reference white.

D65

channel description min max
x | 0 95.047
y | 0 100
z | 0 108.883

D50

channel description min max
x | 0 96.422
y | 0 100
z | 0 82.521
<summary>LAB</summary>

The range of a and b follows the format of CSS. See: lab().

channel description min max
l Lightness 0 100
a Chrominance -125 125
b Chrominance -125 125
<summary>LCHab</summary>

The LCH space that converted from LAB.

channel description min max
l Lightness 0 100
c Chroma 0 150
h Hue 0 360
<summary>LUV</summary>

The range of u and v channels are the extreme values when converting from RGB to LUV.

channel description min max
l Lightness 0 100
u Chrominance -134 220
v Chrominance -140 122
<summary>LCHuv</summary>

The LCH space that converted from LUV.

channel description min max
l Lightness 0 100
c Chroma 0 150
h Hue 0 360
<summary>Oklab</summary>

The range of a and b follows the format of CSS. See: oklab().

channel description min max
l Lightness 0 1
a Chrominance -0.4 0.4
b Chrominance -0.4 0.4
<summary>Oklch</summary>
channel description min max
l Lightness 0 1
c Chroma 0 0.4
h Hue 0 360

Analysis

<summary>rgb2gray(rgb: string | readonly number[]): number </summary>

Return the grayscale value (within [0, 255]) of an RGB color. See: color brightness

rgb2gray([1, 100, 255]); // 88.06899999999999
<summary>isLight(rgb: readonly number[] | string): boolean</summary>

Return true if the grayscale value of an RGB array or a hex string is greater than 127.5. Otherwise, return false. rgb2gray

rgb2gray([156, 49, 93]); // 86.009
isLight([156, 49, 93]);  // false

rgb2gray('#E6ECB6');     // 228.04999999999995
isLight('#E6ECB6');      // true
<summary>rgb2hue(rgb: readonly number[]): number</summary>

Hue of RGB. Note that this value is different from hue of CIELCH.

rgb2hue([1, 100, 255]); // 216.61417322834643
<summary>getRelativeLuminance(rgb: readonly number[] | string): number</summary>

Return the relative luminance (within [0, 1]) of an RGB array or a hex string. See: WCAG2.0 relative luminance

getRelativeLuminance([191, 123, 86]);   // 0.259141693330052
getRelativeLuminance([0, 0, 0]);        // 0
getRelativeLuminance([255, 255, 255]);  // 1
<summary>getContrastRatio(rgb1: readonly number[] | string, rgb2: readonly number[] | string): number</summary>

Return the contrast ratio of two RGB colors. See: WCAG2.0 contrast ratio

getContrastRatio([191, 123, 86], [230, 236, 182]); // 2.759999999999999
getContrastRatio([0, 0, 0], '#FFF');               // 20.99999999999999
getContrastRatio('FFF', [0, 0, 0]);                // 20.99999999999999
<summary>isReadable(rgb1: readonly number[] | string, rgb2: readonly number[] | string, options: ReadbleOptions): boolean</summary>

Check that the contrast ratio of two colors (background and text) is satisfing the WCAG standard. See: WCAG2.1 contrast minimum

type ReadbleOptions = {
  /**
   * Text size is large scale (`true`) or normal scale (`false`).
   * @default false
   */
  isLarge?: boolean,
  /**
   * Required to satisfy WCAG level AAA (`true`) or level AA (`false`).
   * @default false
   */
  levelAAA?: boolean
}
isReadable([191, 123, 86], [230, 236, 182]);       // false
isReadable('000', '#FFF', { levelAAA: true });     // true
isReadable('987654', '123456');                    // false
isReadable('987654', '123456', { isLarge: true }); // true
isReadable('987654', '123456', { isLarge: true, levelAAA: true }) // false

Harmony

Some function arguments naming hsb, but the method works in HSL or HWB space.
<summary>shiftHue(primary: readonly number[], degs: number[]): number[][]</summary>

Return a palette that each color is the hue shift of primary. The primary color should be HSB, HSL, HWB color, or color space that first channel represents hue.

The return space is the same as the input space.

shiftHue([43, 12, 94], [0, 30, 60]);    // [ [ 43, 12, 94 ], [ 73, 12, 94 ], [ 103, 12, 94 ] ]
shiftHue([159, 76, 84], [0, 120, 240]); // [ [ 159, 76, 84 ], [ 279, 76, 84 ], [ 399, 76, 84 ] ]
<summary>shades(hsb: readonly number[], num: number = 6): number[][]</summary>

Return a gradient that colors decreasing in brightness from bri = hsb[2] to bri * (1-1/num).

The return space is the same as the input space.

shades([26, 83, 90], 6); // [ [ 26, 83, 90 ], [ 26, 83, 75 ], [ 26, 83, 60 ], [ 26, 83, 45 ], [ 26, 83, 30 ], [ 26, 83, 15 ] ]
shades([84, 39, 80], 2); // [ [ 84, 39, 80 ], [ 84, 39, 40 ] ]
<summary>tints(hsb: readonly number[], num: number = 6): number[][]</summary>

Return a gradient that colors decreasing in saturation from sat = hsb[1] to sat * (1-1/num).

The return space is the same as the input space.

tints([346, 83, 100], 6); // [ [ 346, 83, 100 ], [ 346, 69.17, 100 ], [ 346, 55.33, 100 ], [ 346, 41.5, 100 ], [ 346, 27.67, 100 ], [ 346, 13.83, 100 ] ]
tints([7, 30, 58], 2);    // [ [ 7, 30, 58 ], [ 7, 15, 58 ] ]
<summary>tones(hsb: readonly number[], method: Harmony | number, num: number = 6): number[][]</summary>

Return a gradient that colors decreasing in both saturation (from sat = hsb[1] to sat * (1-1/num)) and brightness (from bri = hsb[2] to bri * (1-1/num)).

The return space is the same as the input space.

tones([256, 51, 52], 6); // [ [ 256, 51, 52 ], [ 256, 42.5, 43.33 ], [ 256, 34, 34.67 ], [ 256, 25.5, 26 ], [ 256, 17, 17.33 ], [ 256, 8.5, 8.67 ] ]
tones([342, 95, 73], 2); // [ [ 342, 95, 73 ], [ 342, 47.5, 36.5 ] ]
<summary>harmonize(hsb: readonly number[], num?: number): number[][]</summary>

Generate harmony palettes. The return space is RGB.

harmonize([54, 98, 47], 'analogous');      // [ [ 119.85, 49.38, 2.4 ], [ 119.85, 108.1, 2.4 ], [ 72.87, 119.85, 2.40 ] ]
harmonize([58, 64, 48], 'shades', 3);      // [ [ 122.4, 119.8, 44.064 ], [ 81.6, 79.8592, 29.38 ], [ 40.8, 39.93, 14.69 ] ]
harmonize([131, 98, 76], 'complementary'); // [ [ 3.88, 193.8, 38.7 ], [ 193.8, 3.88, 158.98 ] ]

Input a number as method argument will equals the order of method below. If the input is invalid, then it will use 'analogous'

method deg shift
shades none
tints none
shades none
analogous [-30, 0, 30]
triadic [0, 120, 240]
square [0, 90, 180, 270]
complementary [0, 180]
split complementary [0, 150, 210]
tetradic1 [0, 30, 180, 210]
tetradic2 [0, 60, 180, 240]
tetradic3 [0, 30, 150, 180]

Mixing

<summary>mix(color1: readonly number[], color2: readonly number[], weight1: number = 0.5, weight2: number= 1 - weight1): number[]</summary>

Mixing two colors by evaluate weighted sum weight1 * color1 + weight2 * color2.
The weights will be normalized to 1 if their sum > 1.

mix([42, 62, 206], [55, 202, 93], 0.5, 0.5);     // [ 48.5, 132, 149.5 ]
mix([155, 122, 126], [211, 243, 242], 0.2);      // [ 199.8, 218.8, 218.8 ]
mix([204, 248, 241], [149, 241, 118], 3, 2);     // [ 182, 245.2, 191.8 ]
mix([204, 248, 241], [149, 241, 118], 0.6, 0.4); // [ 182, 245.2, 191.8 ]
<summary>meanMix(color1: readonly number[], color2: readonly number[]): number[]</summary>

Return the elementwise mean of two colors.

meanMix([42, 62, 206], [55, 202, 93]);     // [ 48.5, 132, 149.5 ]
meanMix([155, 122, 126], [211, 243, 242]); // [ 183, 182.5, 184 ]
<summary>gammaMix(rgb1: readonly number[], rgb2: readonly number[], gamma: number): number[]</summary>
  1. Evaluate the elementwise mean mean of colors.
  2. Convert mean to HSL space.
  3. Evaluate new saturation and luminance: newVal = 100 * (val / 100)**gamma;.
  4. Convert new HSL color to original space and return.

The inputs and output are in RGB space.

If gamma < 1, the returns will brighter than meanMix. If gamma > 1, the returns will deeper than meanMix.

gammaMix([42, 62, 206], [55, 202, 93], 0.7);     // [ 54.39561213833195, 181.8755020626048, 208.5928442623028 ]
gammaMix([155, 122, 126], [211, 243, 242], 1.2); // [ 171.41502723522638, 171.18140357959763, 171.8822745464839 ]
<summary>brighterMix(rgb1: readonly number[], rgb2: readonly number[]): number[]</summary>

gammaMix with gamma = 0.3.

The inputs and output are in RGB space.

brighterMix([42, 62, 206], [55, 202, 93]);     // [ 140.49399108764436, 225.63360346857013, 243.47723480588996 ]
brighterMix([155, 122, 126], [211, 243, 242]); // [ 228.89399229092206, 224.81031497062736, 237.06134693151148 ]
<summary>deeperMix(rgb1: readonly number[], rgb2: readonly number[]): number[]</summary>

gammaMix with gamma = 1.5.

The inputs and output are in RGB space.

deeperMix([42, 62, 206], [55, 202, 93]);     // [ 39.21213833570636, 76.37097203065198, 84.1587515475568 ]
deeperMix([155, 122, 126], [211, 243, 242]); // [ 155.3090002573382, 155.2379985085759, 155.4510037548627 ]
<summary>softLightBlend(rgb1: readonly number[], rgb2: readonly number[], formula: 'photoshop' | 'pegtop' | 'illusions.hu' | 'w3c' = 'w3c'): number[]</summary>

See wiki blend modes. The order of input color will influence the result.

The inputs and output are in RGB space.

softLightBlend([42, 62, 206], [55, 202, 93], 'RGB');              // [ 22.051211072664362, 99.24922945171917, 195.2889504036909 ]
softLightBlend([42, 62, 206], [55, 202, 93], 'RGB', 'photoshop'); // [ 22.05121107266436, 99.24288450324661, 195.28895040369088 ]
softLightBlend([55, 202, 93], [42, 62, 206], 'RGB', 'photoshop'); // [ 26.072664359861598, 180.4315878508266, 130.55486374261477 ]
<summary>additive(rgb1: readonly number[], rgb2: readonly number[]): number[]</summary>

Add their RGB values.

The inputs and output are in RGB space.

additive([42, 62, 206], [55, 202, 93]);     // [ 97, 255, 255 ]
additive([155, 122, 126], [211, 243, 242]); // [ 255, 255, 255 ]
<summary>mixColors(rgbs: readonly number[][], method: Mixing | number = 'mean'): number[]</summary>

Mix colors (at least two) by specifying the method. The return space is the same as the input space.

The inputs and output are in RGB space.

type Mixing =  "additive" | "mean" | "brighter" | "deeper" | "soft light" | "weighted";

Contrast

The functions for adjusting contrast of colors.

<summary>scaling(rgbs: readonly number[][], c: number = 1): number[][]</summary>

Scale ths values of RGBs by multiplying c. The values will be clipped to [0, 255].

The inputs and output are in RGB space.

scaling([170, 107, 170], 1.2); // [ [ 204, 128.4, 204 ] ]
scaling([146, 167, 40], 0.7);  // [ [ 102.2, 116.9, 28 ] ]
<summary>gammaCorrection(rgbs: readonly number[][], gamma: number = 1): number[][]</summary>

Calculate the new value of RGBs by the formula newVal = 255 * (val / 255)**gamma. If gamma < 1, the returns will brighter than original color. If gamma > 1, the returns will deeper than original color.

The inputs and output are in RGB space.

The inputs and output are in RGB space.

gammaCorrection([148, 241, 14], 2);  // [ [ 85.9, 227.77, 0.77 ] ]
gammaCorrection([178, 4, 200], 0.7); // [ [ 198.27, 13.91, 215.12 ] ]
<summary>autoEnhancement(rgbs: readonly number[][]): number[][]</summary>

Enhance the contrast by the following steps:

  1. Find minimum lightness and maximum lightness in LAB space.
  2. Scaling from [minimum, maximum] to [0, 100]
  3. Convert new color to RGB space and return.

The inputs and output are in RGB space.

<summary>autoBrightness(rgbs: readonly number[][], coeff: number = 0.7): number[][]</summary>

Adjust the brightness of input RGBs. The outputs become darker when coeff close to 0 and become brighter when coeff close to 1

  1. Find mean lightness meanL in LAB space.
  2. Calculate gamma = log(coeff) / log(meanL / 100);.
  3. Do gamma correction to L channel with gamma.
  4. Convert new color to RGB space and return.

The inputs and output are in RGB space.

<summary>adjContrast(rgbs: number[][], method: ContrastMethod | number, space: ColorSpace | string, ...args: number[]): number[][]</summary>

Adjust the contrast of array of RGB colors by specifying the method.

The inputs and output are in RGB space.

type ContrastMethod = "linear" | "gamma" | "auto enhancement" | "auto brightness";

Sorting

Except the distE76 function, the other color difference function is not symmetry (f(a,b) may not equal to f(b,a)).

<summary>diffLuminance(rgb1: readonly number[], rgb2: readonly number[]): number[][]</summary>

Return the difference of grayscales rgb2gray(rgb1) - rgb2gray(rgb2).

<summary>distE76(lab1: readonly number[], lab2: readonly number[]): number</summary>

Return the L2-distance of two LAB colors. This is the CIE 1976 color difference (CIE76 or E76).

<summary>distE94(lab1: readonly number[], lab2: readonly number[]): number</summary>

Return the square of CIE 1994 color difference (CIE94 or E94).

The square: CIE94 formula will take square root. This function is present for comparing the color difference between colors, e.g. distE94(lab1, lab2) < distE94(lab1, lab3), thus the square root is unnecessary.

<summary>distE00(lab1: readonly number[], lab2: readonly number[]): number</summary>

Return CIEDE2000 color difference (CIEDE2000 or E00).

<summary>shuffle<T>(arr: T[]): T[]</summary>

In-place shuffle an array by Fisher-Yates shuffle.

<summary>tspGreedy<T>(arr: T[], rgbGetter: (color: T) => number[], diffOp: CIEDifferenceFn, copy: boolean = false): T[]</summary>

Sort by Greedy algorithm. The first item will be fixed. The second is the closest item to the first and so on.

The argument rgbGetter make this function can handle the object such as { color : number[], otherProperty: unknown }.

<summary>sortColors<T>(colors: readonly T[], method: Sort | number, rgbGetter: (color: T) => number[]): T[]</summary>

Return a sorted and copied (cloneDeep) array of objects.

The argument rgbGetter make this function can handle the object such as { color : number[], otherProperty: unknown }.

type Sort =  "luminance" | "random" | "reversion" | "CIE76" | "CIE94" | "CIEDE2000";
method description
luminance Ascending in brightness (grayscale)
random Shuffle.
reversion Reverse the order of input array.
CIE76 tspGreedy with diffOp = distE76.
CIE94 tspGreedy with diffOp = distE94.
CIEDE2000 tspGreedy with diffOp = distE00.
<summary>sortRgbs(rgbs: readonly number[][], method: Sort | number): number[][]</summary>

Return a sorted and copied array of RGB colors. Similar to sortColors but input arrays directly.

type Sort =  "luminance" | "random" | "reversion" | "CIE76" | "CIE94" | "CIEDE2000";
method description
luminance Ascending in brightness (grayscale)
random Shuffle.
reversion Reverse the order of input array.
CIE76 tspGreedy with diffOp = distE76.
CIE94 tspGreedy with diffOp = distE94.
CIEDE2000 tspGreedy with diffOp = distE00.

Helpers

Other functions that you may re-use in your code to reduce the total file size.

<summary>srgb2linearRgb(val: number): number</summary>

The input is a channel/value of RGB, not array.

The full-scale value of linear-RGB is 1 due to the calculation of CIEXYZ and relative luminance.

srgb2linearRgb(127);                 // 0.21223075741405512
linearRgb2srgb(srgb2linearRgb(127)); // 127
linearRgb2srgb(0.5);                 // 187.5160306783746
<summary>cieTrans(lab: number): number</summary>

The input is a channel/value of LAB, not array.

This function is part of the conversion between CIEXYZ and CIELAB. I do not know the formal name.

const cieTrans = (val: number): number => {
  return val > (6/29)**3 ? Math.cbrt(val) : (903.3 * x + 16) / 116;
};
const cieTransInv = (val: number) => {
  return val > (6/29) ? val**3 : (val - 16/116) / (903.3/116) ;
};

and cieTransInv is the inverse function of cieTrans.

<summary>cloneDeep<T>(obj: T): DeepWriteable<T></summary>

Deeply clone object.

The following types will be handle:

  • primitive type
  • Number, String, Boolean (convert to primitive type)
  • Date
  • built-in object

If other type with typeof obj === 'object' will turn into built-in object. The other types will not be copied.

<summary>map(arr, callback, len)</summary>
type map = {
  /**
   * Generate an array with specific length.
   */
  <R>(
    len: number,
    callback: (i: number) => R
  ): R[];
  /**
   * Similar to Array.prototype.map but this can control the length of output array .
   */
  <R, T>(
    arr: readonly T[],
    callback: (val: T, i: number) => R,
    len?: number,
  ): R[]
}

In most cases, replace Array.prototype.map with this function can improve the performance and file size.

Numeric

<summary>pow(x: number, y: number): number</summary>

Equivalent to x**y. Much more faster than x**y and Math.pow(x,y) if y is uncertain.

For square, simply write x * x.

if (!x && !y) return 1;
return Math.exp(y * Math.log(x));
<summary>randInt(max: number): number</summary>

Generate a random (positive) integer in [0, max].

<summary>round(num: number, place: number = 0): number</summary>

Rounding a number to specific place value. Positive place means decimal places and negative means whole number places.

Math.round(10**place * num) / 10**place;
<summary>clip(num: number, min?: number, max?: number): number</summary>

Limit the number in the interval [min, max]. If min and/or max is undefined, it will be regarded as unbound.

if (num < min!) num = min!; // max < min return min
else if (num > max!) num = max!;
return num;
<summary>rangeMapping(val: number, min: number, max: number, newMin: number, newMax: number, place?: number,): number</summary>

Scaling and shift to new range. If place is given, then round new value.

const rangeMapping = (
  val: number,
  min: number,
  max: number,
  newMin: number,
  newMax: number,
  place?: number,
) => {
  const ratio = clip((val - min) / (max - min), 0, 1); // avoid floating problem.
  const newVal = newMin + ratio * (newMax - newMin);
  return place == null ? newVal : round(newVal, place);
};
<summary>deg2rad(deg: number): number and rad2deg(rad: number): number</summary>

Conversions between degree and radian.

<summary>elementwiseMean(arr1: readonly number[], arr2: readonly number[]): number[]</summary>

Elementwise mean of two array. The length of output is Math.min(arr1.length, arr2.length).

Notice that some function only deal with fixed length.

<summary>dot3(arr1: readonly number[], arr2: readonly number[]): number</summary>

Dot two arrays with length = 3.

const dot3 = (arr1: readonly number[], arr2: readonly number[]): number => {
  return arr1[0] * arr2[0] + arr1[1] * arr2[1] + arr1[2] * arr2[2];
};
<summary>squareSum4(a: number, b: number, c: number = 0, d: number = 0): number</summary>

Return a * a + b * b + c * c + d * d.

<summary>l2Norm3(a: number, b: number, c: number = 0): number</summary>

Return Math.sqrt(squareSum(a, b, c)).

<summary>l2Dist3(a: number, b: number): number</summary>
const l2Dist3 = (color1: readonly number[], color2: readonly number[]): number => {
  return l2Norm3(
    color1[0] - color2[0],
    color1[1] - color2[1],
    color1[2] - color2[2]
  );
};

Tests

Run command npm run test.

  • test/benchmark/**.perf.js: benchmark files.
  • test/unit/**.test.js: unit tests and comparison testing.
  • test/unit/cmyk-formula-test.js: test whether 3 different formulas have same results.
  • test-utils/: helpers for test.

Benchmark

Run command npm run benchmark (conversions only-).

  • Node version: v22.11.0.
  • CPU: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz
  • tinybench 3.1.1
  • libraries:
    • colord: 2.9.3
    • color: 5.0.0
    • color-convert: 3.1.0

Only list some benchmaks since some conversions have similar formula and performance.

<summary>XYZ</summary>
  • 10 colors/sampling

rgb2xyz

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 1865.8 ± 0.43% 555434 ± 0.03% fastest
colord 4862.5 ± 4.41% 218174 ± 0.04% 61% slower
color 7650.0 ± 1.64% 137757 ± 0.06% 75% slower
color-convert 2403.0 ± 0.60% 433481 ± 0.03% 22% slower

xyz2rgb

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 1695.1 ± 0.46% 625703  ± 0.04% 90% slower
colord 5378.7 ± 0.74% 198918  ± 0.07% 97% slower
color 9757.8 ± 0.66% 110553  ± 0.10% 98% slower
color-convert 236.55 ± 2.35% 6090139 ± 0.04% fastest
  • 500 colors/sampling

rgb2xyz

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 90272  ± 0.34% 11258 ± 0.17% fastest
colord 274760 ± 1.66% 3774  ± 0.40% 66% slower
color 409022 ± 1.10% 2560  ± 0.68% 77% slower
color-convert 125684 ± 0.74% 8254  ± 0.30% 27% slower

xyz2rgb

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 80871  ± 0.41% 12657  ± 0.20% 96% slower
colord 255404 ± 0.55% 3995   ± 0.37% 99% slower
color 446865 ± 0.66% 2278   ± 0.46% 99% slower
color-convert 4066.0 ± 0.98% 305446 ± 0.09% fastest
<summary>CMYK</summary>
  • 10 colors/sampling

rgb2cmyk

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 126.29 ± 0.76% 9012903 ± 0.02% fastest
colord 2473.6 ± 0.18% 410141  ± 0.02% 95% slower
color 6013.0 ± 0.93% 177287  ± 0.05% 98% slower
color-convert 225.98 ± 1.75% 6218964 ± 0.04% 31% slower

cmyk2rgb

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 128.49 ± 0.53% 8784196 ± 0.02% fastest
colord 1437.3 ± 1.26% 781985  ± 0.04% 91% slower
color 5869.8 ± 5.64% 188463  ± 0.06% 98% slower
color-convert 217.06 ± 1.35% 6173430 ± 0.04% 30% slower
  • 500 colors/sampling

rgb2cmyk

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 1099.7 ± 0.18% 937169 ± 0.02% fastest
colord 73538  ± 6.12% 14877  ± 0.26% 98% slower
color 323961 ± 2.75% 3353   ± 0.69% 100% slower
color-convert 4624.0 ± 2.04% 273031 ± 0.10% 71% slower

rgb2cmyk

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 1217.4 ± 0.17% 852300 ± 0.03% fastest
colord 94172  ± 3.22% 12522  ± 0.48% 99% slower
color 278511 ± 0.85% 3735   ± 0.51% 100% slower
color-convert 4609.3 ± 1.09% 269688 ± 0.10% 68% slower
<summary>HEX</summary>
  • 10 colors/sampling

rgb2hex

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 1275.0 ± 0.31% 801221 ± 0.02% fastest
colord 1470.2 ± 0.47% 700975 ± 0.02% 13% slower
color 27621  ± 3.08% 37596  ± 0.09% 95% slower
color-convert 1772.4 ± 0.71% 584987 ± 0.02% 27% slower

hex2rgb

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 1931.1 ± 0.73% 537991 ± 0.02% fastest
colord 4074.2 ± 0.90% 257410 ± 0.03% 52% slower
color 10505  ± 0.75% 98832  ± 0.06% 82% slower
color-convert 2049.8 ± 1.30% 523147 ± 0.03% 3% slower
  • 500 colors/sampling

rgb2hex

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 82675   ± 0.44% 12431 ± 0.23% fastest
colord 90544   ± 0.47% 11341 ± 0.22% 9% slower
color 1431425 ± 1.11% 710   ± 0.80% 94% slower
color-convert 101622  ± 0.39% 10007 ± 0.19% 19% slower

hex2rgb

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 107295 ± 0.56% 9649 ± 0.27% fastest
colord 216812 ± 0.64% 4746 ± 0.38% 51% slower
color 542092 ± 0.81% 1885 ± 0.56% 80% slower
color-convert 109129 ± 0.61% 9515 ± 0.28% 1% slower
<summary>HSB</summary>
  • 10 colors/sampling

rgb2hsb

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 198.26 ± 0.23% 5567865 ± 0.03% fastest
colord 435.80 ± 1.37% 2360374 ± 0.01% 58% slower
color 6764.2 ± 3.26% 157642  ± 0.06% 97% slower
color-convert 441.37 ± 1.36% 2475841 ± 0.02% 56% slower

hsb2rgb

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 146.86 ± 0.28% 7786961 ± 0.02% fastest
colord 1822.4 ± 17.07% 675545  ± 0.04% 91% slower
color 6597.1 ± 0.58% 155684  ± 0.04% 98% slower
color-convert 385.37 ± 0.86% 2974037 ± 0.04% 62% slower
  • 500 colors/sampling

rgb2hsb

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 3755.2 ± 0.18% 276840 ± 0.05% fastest
colord 19889  ± 7.88% 55989  ± 0.13% 80% slower
color 338564 ± 0.88% 3059   ± 0.53% 99% slower
color-convert 17136  ± 0.78% 63809  ± 0.13% 77% slower

hsb2rgb

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 2292.9 ± 0.15% 444420 ± 0.02% fastest
colord 70170  ± 0.62% 14935  ± 0.23% 97% slower
color 316699 ± 0.50% 3198   ± 0.31% 99% slower
color-convert 20431  ± 0.53% 50821  ± 0.08% 89% slower
<summary>NAMED</summary>
  • 10 colors/sampling

rgb2named

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 26811  ± 0.90% 40043 ± 0.11% fastest
colord 766550 ± 1.30% 1353  ± 0.83% 97% slower
color 73089  ± 0.37% 13866 ± 0.12% 65% slower
color-convert 80482  ± 0.68% 13180 ± 0.30% 67% slower

named2rgb

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 219.39 ± 0.41% 4905299 ± 0.02% fastest
colord 8576.5 ± 0.64% 119825  ± 0.04% 98% slower
color 10620  ± 1.01% 96772   ± 0.05% 98% slower
color-convert 605.31 ± 1.01% 1783149 ± 0.02% 64% slower
  • 500 colors/sampling

rgb2named

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 1297776  ± 0.61% 775 ± 0.53% fastest
colord 41900763 ± 6.92% 25  ± 4.62% 97% slower
color 3933145  ± 1.51% 257 ± 1.09% 67% slower
color-convert 3835206  ± 1.12% 262 ± 0.84% 66% slower

named2rgb

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 7554.5 ± 0.11% 133815 ± 0.04% fastest
colord 487750 ± 1.01% 2092   ± 0.52% 98% slower
color 529307 ± 0.40% 1900   ± 0.30% 99% slower
color-convert 38757  ± 0.38% 26293  ± 0.10% 80% slower
<summary>Oklab</summary>
  • 10 colors/sampling

rgb2oklab

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 1993.7 ± 1.83% 548656 ± 0.04% fastest

oklab2rgb

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 1778.0 ± 0.37% 585905 ± 0.03% fastest
  • 500 colors/sampling

rgb2oklab

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 93955 ± 0.54% 11009 ± 0.25% fastest

oklab2rgb

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 92657 ± 0.53% 11166 ± 0.25% fastest
<summary>getCSSColor</summary>

Our function handle more checks.

'color-utils': Default option.
'color-utils (number)': Pass { percent_: false }.

  • 10 colors/sampling

To RGB string

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 6178.9 ± 2.55% 169818  ± 0.10% 95% slower
color-utils (number) 3045.7 ± 1.81% 342768  ± 0.06% 91% slower
colord 296.15 ± 3.08% 3696381 ± 0.04% fastest
color 28068  ± 24.30% 43753   ± 0.31% 99% slower

rgb2hsl + to HSL string

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 6926.5 ± 0.96% 151278  ± 0.11% 91% slower
color-utils (number) 6941.6 ± 1.25% 152162  ± 0.12% 91% slower
colord 631.89 ± 0.38% 1635387 ± 0.03% fastest
color 35209  ± 0.68% 29101   ± 0.21% 98% slower

rgb2xyz + to XYZ string

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 11611  ± 1.50% 96342  ± 0.23% 23% slower
color-utils (number) 10034  ± 2.05% 110280 ± 0.19% 12% slower
colord 8633.8 ± 1.91% 124808 ± 0.17% fastest
color 44340  ± 1.23% 24215  ± 0.42% 81% slower

rgb2lab + to LAB string

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 13500  ± 1.38% 84932  ± 0.32% 19% slower
color-utils (number) 9923.1 ± 1.81% 105303 ± 0.13% fastest
colord 9811.5 ± 1.66% 105048 ± 0.10% 0.24% slower
color 46989  ± 0.67% 21661  ± 0.21% 79% slower
  • 500 colors/sampling

To RGB string

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 685076  ± 4.51% 1651   ± 2.89% 99% slower
color-utils (number) 196111  ± 2.67% 5750   ± 1.31% 95% slower
colord 9353.7  ± 0.39% 112593 ± 0.19% fastest
color 1482556 ± 5.14% 728    ± 3.15% 99% slower

rgb2hsl + to HSL string

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 631669  ± 2.82% 1697  ± 1.99% 95% slower
color-utils (number) 541312  ± 2.21% 1895  ± 0.96% 94% slower
colord 31134   ± 0.27% 32290 ± 0.11% fastest
color 1896772 ± 2.91% 540   ± 2.01% 98% slower

rgb2xyz + to XYZ string

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 700293  ± 2.18% 1465 ± 1.17% 16% slower
color-utils (number) 637217  ± 0.89% 1581 ± 0.69% 9% slower
colord 582477  ± 1.28% 1734 ± 0.65% fastest
color 2258110 ± 0.91% 444  ± 0.91% 74% slower

rgb2lab + to LAB string

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 701411  ± 0.85% 1435 ± 0.67% 11% slower
color-utils (number) 630627  ± 1.46% 1604 ± 0.71% fastest
colord 648329  ± 1.84% 1578 ± 1.07% 2% slower
color 2948231 ± 4.91% 355  ± 3.67% 78% slower
<summary>manipulation</summary>
  • 10 times/sampling

Adjust 5 colors for 6 times

Contrast Latency avg (ns) Throughput avg (ops/s) Comparison
linear 1934.4 ± 1.08% 595019 ± 0.05% fastest
gamma 7444.0 ± 0.90% 141709 ± 0.07% 76% slower
auto enhancement 16445  ± 1.12% 65080  ± 0.13% 89% slower
auto brightness 18115  ± 0.43% 57247  ± 0.11% 90% slower

Harmony: analogous. Generate 3 colors for 10 times

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 4547.9 ± 3.11% 262059 ± 0.10% fastest
colord 6457.8 ± 0.77% 179107 ± 0.12% 32% slower

Harmony: shades. Generate 6 colors for 10 times

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 7883.7 ± 0.67% 136970 ± 0.09% fastest
colord 134593 ± 1.51% 7718   ± 0.30% 94% slower

Mix 2 colors for 499 times

Mixing Latency avg (ns) Throughput avg (ops/s) Comparison
mean 3014.5 ± 0.88% 384460 ± 0.09% 6% slower
brighter 5030.1 ± 0.48% 207832 ± 0.05% 49% slower
deeper 5067.8 ± 0.49% 205364 ± 0.05% 50% slower
soft light 7449.1 ± 5.43% 144906 ± 0.07% 64% slower
additive 3203.7 ± 0.83% 328805 ± 0.05% 19% slower
weighted 2543.4 ± 0.51% 407623 ± 0.03% fastest

Sort 5 colors for 6 times

Sorting Latency avg (ns) Throughput avg (ops/s) Comparison
luminance 24254 ± 0.52% 43674 ± 0.12% 13% slower
random 20884 ± 0.51% 50126 ± 0.10% fastest
reversion 21663 ± 1.23% 49685 ± 0.15% 0.88% slower
CIE76 36281 ± 0.51% 28604 ± 0.14% 43% slower
CIE94 36974 ± 0.47% 27938 ± 0.13% 44% slower
CIEDE2000 74629 ± 0.41% 13667 ± 0.16% 73% slower
  • 500 times/sampling

Harmony: analogous. Generate 3 colors for 500 times

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 217506 ± 1.35% 5063 ± 0.70% fastest
colord 468879 ± 5.61% 2666 ± 1.51% 47% slower

Harmony: shades. Generate 6 colors for 500 times

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 375691  ± 0.70% 2728 ± 0.52% fastest
colord 6056219 ± 1.33% 166  ± 1.05% 94% slower

Mix 2 colors for 499 times

Mixing Latency avg (ns) Throughput avg (ops/s) Comparison
mean 118136 ± 0.63% 8877 ± 0.35% fastest
brighter 230521 ± 0.54% 4430 ± 0.35% 50% slower
deeper 306693 ± 0.61% 3333 ± 0.43% 62% slower
soft light 353260 ± 1.24% 2988 ± 0.67% 66% slower
additive 138872 ± 0.78% 7648 ± 0.42% 14% slower
weighted 148091 ± 2.27% 7575 ± 0.57% 15% slower
<summary>some other fcuntions</summary>
  • 10 colors/sampling

rgb2hue

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 186.71 ± 0.31% 6422953 ± 0.03% fastest
colord 234.73 ± 0.28% 4488302 ± 0.02% 30% slower
color 6431.5 ± 12.29% 193392  ± 0.10% 97% slower

isReadable

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 3213.7 ± 0.26% 317981  ± 0.03% 81% slower
colord 638.20 ± 0.31% 1691278 ± 0.03% fastest
  • 500 colors/sampling

rgb2hue

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 4122.0 ± 0.17% 249077 ± 0.04% fastest
colord 6461.1 ± 0.43% 169177 ± 0.09% 32% slower
color 268715 ± 0.94% 3906   ± 0.55% 98% slower

isReadable

Library Latency avg (ns) Throughput avg (ops/s) Comparison
color-utils 168171 ± 0.32% 6003  ± 0.20% 80% slower
colord 42168  ± 3.51% 30471 ± 0.43% fastest

Others

:grey_question: Some properties with underscore _ at the end of name.
:speech_balloon: Theese properties can be mangled by minifier, such as terser, by setting mangle.properties.regex = /[^_]_$/.

:grey_exclamation: The mangle.properties may cause error when minifying multiple files.
:speech_balloon: Because the mangled names are different in different files.
This can be solved by setting nameCache: {} (terser) or create a custom plugin for bundler (if nameCache in @rollup/plugin-terser or vite.config does not work).

:exclamation: nameCache may not work in Nuxt.

<summary>custom rollup plugin</summary>

In this repository github terser-plugin.ts

  import { minify } from 'terser';

  const defaultOptions = {
    compress: {
      toplevel: true,
    },
    mangle: {
      toplevel: true,
      properties: {
        regex: /[^_]_$/
      }
    },
    nameCache: undefined
  };

Plugin:


  export default (
    options
  ) => {
    const mergedOption = mergeDeep({}, defaultOptions, options);
    return {
      name: 'terser',
      renderChunk: {
        order: 'post',
        async handler(code) {
          if (!/(m|c)?js$/.test(chunk.fileName)) return;
          const result = await minify(code, mergedOption);
          return {
            code: result.code!
          };
        },
      }
    };
  };

or

  export default (
    outDir = ['./dist'],
    options
  ) => {
    const mergedOption = mergeDeep({}, defaultOptions, options);
    return {
      name: 'terser',
      closeBundle: {
        order: 'post',
        sequential: true,
        async handler() {
          for (const path of outDir) {
            const files = fs.readdirSync(path)
              .filter((filename) => /\.(js|mjs|cjs)$/.test(filename));
            for (const filename of files) {
              const filePath = `${path}/${filename}`;
              const code = fs.readFileSync(filePath, 'utf-8');
              const result = await minify(code, mergedOption);
              if (result.code) fs.writeFileSync(filePath, result.code, 'utf8');
            }
          }
        },
      },
    }
  }

changelog

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[Unreleased]

Added

  • Plugins for spaces.
  • Handling alpha channel (transparency) in manipulating.
  • Set default options manually.
  • A faster function to CSS format

Changed

  • Handling alpha channel (transparency) in manipulating.

[1.2.2] - 2025-05-

Build

  • Console bundle size when rollup. (c7825ef)
  • performanceTest prints markdown table format if print argument is true. (92f5d21)
  • SampleGenerator.defaults gives 500 samples instead of 10. Benchmark test 500 samples by default. (414d700)
  • getCssColor: Merge default option test and { percent_: false } test in benchmark. Add xyz in benchmark. (08bdcda)
  • Add color-diff library to test distE00. Performance test and comparison testing of distE00. Test different formula in distE00. (55443fa)

Changed

  • distE00: The result will take square-root. (bbd165f)

Deprecated

Fixed

  • Correct type reference in map. (9fbfa1a)
  • Get length from array not function in comparison testing (unit test). (fa45fd7)
  • Correct benchmark test names and functions. (29afed8)

Performance

  • Improve performance on larger test cases (500 colors/run) and reduce file size: (aa8007d)
    hsb2rgb: 3x faster.
    hsl2rgb: 2.7x faster.
    hwb2rgb: 1.4x faster.
    xyz2rgb: 1.1x faster.
    rgb2oklab: 2x faster.
    oklab2rgb: 1.9x faster.
  • Improve performance:
    getRelativeLuminance: call function to (b395d20)
    distE00: Reduce pre-computed constants in closure. Reduce ternary operator. (bbd165f)

[1.2.1] - 2025-05-25

Build

Fixed

  • Argument copy work incorrectly in tspGreedy. (2afe076)
  • Incorrect value range in XYZ space when calling getCssColor.
    CSS color module level 4 specifying 100% equals 1. (f75620c)
  • L-channel of Oklab and Oklch will not use percentage when set percent_: false. (d74f5c2)

Refactor

  • Renamed argument toSpace to to of function toSpace. (ddde9ea)

[1.2.0] - 2025-05-16

Added

  • New mix operator: mix, which evaluate weighted sum of two colors.
    MIXING_MODES add new string 'weighted'.
    mixColors new valid value for parameter method: 'weighted' or 5 (index),
    which call new mix operator mix. (97f9474) (e33d11a)

Build

  • Bundled files will keep function names. (61e92ed)
  • terser-plugin.ts: use renderChunk instead of closeBundle (bd4dcf3)

Changed

  • getCssColor: different behavior for XYZ space.
    Return 'color(xyz-d65 x y z)' or 'color(xyz-d50 x y z)' if checkSupport_ is true and the browser does supports. (changed)
    Return 'xyz(x y z)' otherwise. (a29abd7) (0335e6f) (067d61f)
  • Type change: remove all readonly keyword in ColorSpace type. (d9d8f15)
  • Type change: Remove readonly number[] type in max_ property of ColorSpace. Now only (dea79fb)

Deprecated

  • getSpaceRange: Directly get range from ColorSpace.max_ instead. (dea79fb)

Performance

  • getColorSpace: use object literal instead of Array.prototype.find. (af8c264)
  • getCssColor: RegExp.prototype.test instead of String.prototype.startswith and remove array destructuring.
    Array.prototype.reduce instead of map and Array.prototype.join (809c33e) (7f257d5) (53a7476)
  • getContrastRatio: remove unnecessary variables. (809c33e)
  • rgb2cmyk: remove unnecessary variables. (809c33e)

Removed

  • Remove export of variables: rgb2xyzMat, xyz2rgbMat, and xyzMax. (a29abd7)