https://github.com/smikhalevski/paint-bucket
🪣 Highly performant, extensible, and tiny color manipulation library.
https://github.com/smikhalevski/paint-bucket
color color-difference css decode encode hex hsl hsv lab rgb x11 xyz
Last synced: 11 months ago
JSON representation
🪣 Highly performant, extensible, and tiny color manipulation library.
- Host: GitHub
- URL: https://github.com/smikhalevski/paint-bucket
- Owner: smikhalevski
- License: mit
- Created: 2021-08-25T10:18:45.000Z (almost 5 years ago)
- Default Branch: master
- Last Pushed: 2025-03-29T18:47:24.000Z (about 1 year ago)
- Last Synced: 2025-07-08T19:14:25.803Z (11 months ago)
- Topics: color, color-difference, css, decode, encode, hex, hsl, hsv, lab, rgb, x11, xyz
- Language: TypeScript
- Homepage: https://smikhalevski.github.io/paint-bucket/
- Size: 2.14 MB
- Stars: 7
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
[Highly performant](#performance), [extensible](#plugins), and
[tiny](https://bundlephobia.com/package/paint-bucket) color manipulation library.
```shell
npm install --save-prod paint-bucket
```
# Overview
🔎 [API documentation is available here.](https://smikhalevski.github.io/paint-bucket/classes/core.Color.html)
```ts
import { clr } from 'paint-bucket';
clr('#abcdef').saturation(s => s / 2).red();
// ⮕ 188
```
You can cherry-pick plugins that you need:
```ts
import { clr, Color } from 'paint-bucket/core';
import 'paint-bucket/plugin/rgb';
clr().red(); // ✅
clr().saturation(); // ❌ Error: saturation not defined
```
Most methods provide getter-setter semantics:
```ts
// Setter
clr('#f00').red(127.5);
// or
clr('#f00').red(r => r / 2);
// Getter
clr('#f00').red();
// ⮕ 255
```
Mutate multiple components at the same time:
```ts
clr([64, 128, 0])
.rgb(([r, g, b, a]) => [r * 3, g * 2, b, a])
.rgb();
// ⮕ [192, 255, 0, 1]
```
[`clr`](https://smikhalevski.github.io/paint-bucket/functions/core.clr.html) returns a mutable instance
of the [`Color`](https://smikhalevski.github.io/paint-bucket/classes/core.Color.html) class. To create a
copy of the `Color` instance you can use one of these approaches:
```ts
const color1 = clr('#f00');
// color2 is a copy of color1
const color2 = clr(color1);
// or
const color3 = color1.clone();
```
Parse and serialize CSS color strings:
```ts
clr('pink').css();
// ⮕ "#ffc0cb"
clr('rgba(255, 192, 203)').css();
// ⮕ "#ffc0cb"
```
Create gradients and obtain color at arbitrary position:
```ts
clr.gradient(['red', 'blue']).at(0.7).css();
// ⮕ "#4d00b3"
```
Create multi-stop gradients with custom stop values:
```ts
clr.gradient()
.stop(0, 'red')
.stop(50, 'pink')
.stop(100, 'blue')
.at(70)
.css();
// ⮕ "#9973e0"
```
# Color models
Paint Bucket provides an abstraction for [color models](https://en.wikipedia.org/wiki/Color_model) which are represented
as objects that define methods to convert color components between color model representation and RGB. Color components
are an array of numbers.
```ts
import { ColorModel, RGB } from 'paint-bucket/core';
const CMYK: ColorModel = {
name: 'CMYK',
// The number of color components that this model uses:
// cyan, magenta, yellow, black, and alpha
componentCount: 5,
convertComponentsToRGB(components: readonly number[], rgb: RGB): void {
// Update elements of the rgb array
},
convertRGBToComponents(rgb: Readonly, components: number[]): void {
// Update elements of the components array
},
};
```
Color model converters expect component values to be in [0, 1] range. Plugin APIs may return component values in any
other range, but internally components are always normalized to [0, 1].
```ts
import { HSL } from 'paint-bucket/color-model/hsl';
const hsl: HSL = [
1, // Hue
0, // Saturation
0, // Lightness
1, // Alpha
];
```
When you create a new `Color` instance, it uses the RGB color model and corresponding components for the black color.
```ts
import { Color } from 'paint-bucket/core';
clr(); // Opaque black RGB color
```
You can create a color with any model and components.
```ts
import { Color } from 'paint-bucket/core';
import { HSL } from 'paint-bucket/color-model/hsl';
new Color(HSL, [0.5, 1, 0.5, 0.7]); // 70% transparent cyan HSL color
```
`Color` provides a mechanism to acquire color components in any color model via the
[`getComponents`](https://smikhalevski.github.io/paint-bucket/classes/core.Color.html#getComponents)
method.
```ts
import { Color, RGB } from 'paint-bucket/core';
import { HSL } from 'paint-bucket/color-model/hsl';
new Color(HSL, [0.5, 1, 0.5, 0.7]).getComponents(RGB);
// ⮕ [0, 1, 1, 0.7]
```
Here, we created a Color instance initialized with the components of the cyan color in the HSL color model and retrieved
components in the RGB color model.
[`getComponents`](https://smikhalevski.github.io/paint-bucket/classes/core.Color.html#getComponents) method
returns read-only color components, which are computed on the fly. To update the color components of the `Color`
instance, you should use the
[`useComponents`](https://smikhalevski.github.io/paint-bucket/classes/core.Color.html#useComponents)
method. This method returns a writable array of components using a particular color model.
```ts
import { Color, RGB } from 'paint-bucket/core';
import { HSL } from 'paint-bucket/color-model/hsl';
const color = new Color(HSL, [0.5, 1, 0.5, 0.5]);
const rgb = color.useComponents(RGB);
// Set blue component value to 0
rgb[2] = 0;
color.getComponents(HSL);
// ⮕ [0.333, 1, 0.5, 0.7]
```
Paint Bucket includes pluggable implementations for following color models:
- [CMYK](https://en.wikipedia.org/wiki/CMYK_color_model)
- [HSL](https://en.wikipedia.org/wiki/HSL_and_HSV)
- [HSV](https://en.wikipedia.org/wiki/HSL_and_HSV)
- [HWB](https://en.wikipedia.org/wiki/HWB_color_model)
- [CIE-L\*a\*b\*](https://en.wikipedia.org/wiki/CIELAB_color_space)
- [Hunter L, a, b](https://en.wikipedia.org/wiki/Hunter_Lab)
- [CIE 1931 XYZ](https://en.wikipedia.org/wiki/CIE_1931_color_space)
# Plugins
Paint Bucket relies on plugins in every aspect. The `paint-bucket/core` doesn't implement any color manipulation
functionality.
```ts
import { clr, Color } from 'paint-bucket/core';
import'paint-bucket/plugin/rgb';
clr().red(64).red(r => r * 2).red();
// ⮕ 128
```
[paint-bucket/plugin/cmyk](https://smikhalevski.github.io/paint-bucket/modules/plugin_cmyk.html)
CMYKa color model manipulation plugin.
[paint-bucket/plugin/css](https://smikhalevski.github.io/paint-bucket/modules/plugin_css.html)
CSS color values parsing and serialization plugin.
[paint-bucket/plugin/difference](https://smikhalevski.github.io/paint-bucket/modules/plugin_difference.html)
Computes the CIEDE2000 color difference.
[paint-bucket/plugin/hsl](https://smikhalevski.github.io/paint-bucket/modules/plugin_hsl.html)
HSLa color model manipulation plugin.
[paint-bucket/plugin/hsv](https://smikhalevski.github.io/paint-bucket/modules/plugin_hsv.html)
HSVa color model manipulation plugin.
[paint-bucket/plugin/hwb](https://smikhalevski.github.io/paint-bucket/modules/plugin_hwb.html)
HWBa color model manipulation plugin.
[paint-bucket/plugin/lab](https://smikhalevski.github.io/paint-bucket/modules/plugin_lab.html)
CIE-L*a*b* color model manipulation methods.
[paint-bucket/plugin/labh](https://smikhalevski.github.io/paint-bucket/modules/plugin_labh.html)
Hunter L, a, b color model manipulation plugin.
[paint-bucket/plugin/palette](https://smikhalevski.github.io/paint-bucket/modules/plugin_palette.html)
Palette generation plugin.
[paint-bucket/plugin/rgb](https://smikhalevski.github.io/paint-bucket/modules/plugin_rgb.html)
RGBa color model manipulation plugin.
[paint-bucket/plugin/x11](https://smikhalevski.github.io/paint-bucket/modules/plugin_x11.html)
[X11 color names](https://en.wikipedia.org/wiki/X11_color_names) parsing plugin.
## Extend color instance
Below is an example that shows how to extend the
[`Color`](https://smikhalevski.github.io/paint-bucket/classes/core.Color.html)
prototype to implement a color component read and write methods.
```ts
// ./my-plugin.ts
import { Color, RGB } from 'paint-bucket/core';
declare module 'paint-bucket/core' {
interface Color {
// Returns the green color component in range [0, 255]
getGreen(): number;
// Sets the green color component in range [0, 255]
setGreen(green: number): Color;
}
}
Color.prototype.getGreen = function () {
// Get read-only array of RGB color components where each component
// is in [0, 1] range
const rgb = this.getComponents(RGB);
return rgb[1] * 255;
};
Color.prototype.setGreen = function (green) {
// Get writable array of RGB color components where each component
// is in [0, 1] range
const rgb = this.useComponents(RGB);
// Update the green component
rgb[1] = green / 255;
// Return Color instance to allow chaining
return this;
};
```
To use this plugin we need to create a `Color` instance:
```ts
import { clr, RGB } from 'paint-bucket/core';
import './my-plugin';
const color = clr().setRed(128);
color.getComponents(RGB);
// ⮕ [0.5, 0, 0, 1]
```
# Performance
Clone this repo and use `npm ci && npm run build && npm run perf` to run the performance testsuite.
Results are in millions of operations per second [^1]. The higher number is better.
| | paint-bucket | [tinycolor2](https://github.com/bgrins/TinyColor) | [chroma.js](https://github.com/gka/chroma.js) |
|---------------------------------------------------|-------------:|--------------------------------------------------:|----------------------------------------------:|
| `clr([255, 255, 255])` | 18.1 | 3.8 | 2.1 |
| `clr('#abc')` | 6.5 | 1.6 | 1.7 |
| `clr('#abcdef')` | 6.2 | 1.8 | 1.9 |
| `clr('#abcdefff')` | 5.7 | 1.8 | 1.7 |
| `clr(0xab_cd_ef)` | 15.3 | 🚫 | 2.9 |
| `clr().rgb32(0xab_cd_ef_ff)` | 15.6 | 🚫 | 🚫 |
| `clr('rgba(128, 128, 128, 0.5)')` | 3.0 | 1.5 | 0.2 |
| `clr(…).saturation(50).rgb()` | 11.0 | 0.9 | 1.0 |
| `clr(…).hue(90).lightness(10).rgb()` | 9.5 | 0.6 | 🚫 |
| `clr.gradient(['#fff', '#000'])` | 3.3 | 🚫 | 0.5 |
| `clr.gradient(…).at(0.5, RGB, lerp)` [^2] | 8.5 | 🚫 | 3.7 |
| `clr.gradient(…).at(0.5, LAB, csplineMonot)` [^2] | 8.4 | 🚫 | 3.8 |
[^1]: Performance was measured on Apple M1 Max using [TooFast](https://github.com/smikhalevski/toofast).
[^2]: [`lerp`](https://github.com/smikhalevski/algomatic/#lerp) and
[`csplineMonot`](https://github.com/smikhalevski/algomatic/#csplinemonot) are linear and monotonous cubic spline
interpolation factories respectively from [Algomatic](https://github.com/smikhalevski/algomatic).