{"id":19592299,"url":"https://github.com/smikhalevski/paint-bucket","last_synced_at":"2025-07-20T21:34:50.690Z","repository":{"id":43256999,"uuid":"399776216","full_name":"smikhalevski/paint-bucket","owner":"smikhalevski","description":"🪣 Highly performant, extensible, and tiny color manipulation library.","archived":false,"fork":false,"pushed_at":"2025-03-29T18:47:24.000Z","size":2246,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-08T19:14:25.803Z","etag":null,"topics":["color","color-difference","css","decode","encode","hex","hsl","hsv","lab","rgb","x11","xyz"],"latest_commit_sha":null,"homepage":"https://smikhalevski.github.io/paint-bucket/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/smikhalevski.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-08-25T10:18:45.000Z","updated_at":"2025-03-29T18:46:53.000Z","dependencies_parsed_at":"2024-07-17T13:48:00.980Z","dependency_job_id":"45dee479-1908-4f3f-abf3-576eccc3f9fe","html_url":"https://github.com/smikhalevski/paint-bucket","commit_stats":{"total_commits":84,"total_committers":1,"mean_commits":84.0,"dds":0.0,"last_synced_commit":"c6891e2fa2ecebe7144b6c773d7f5e51d54fa1ea"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/smikhalevski/paint-bucket","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smikhalevski%2Fpaint-bucket","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smikhalevski%2Fpaint-bucket/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smikhalevski%2Fpaint-bucket/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smikhalevski%2Fpaint-bucket/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/smikhalevski","download_url":"https://codeload.github.com/smikhalevski/paint-bucket/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smikhalevski%2Fpaint-bucket/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266204640,"owners_count":23892366,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["color","color-difference","css","decode","encode","hex","hsl","hsv","lab","rgb","x11","xyz"],"created_at":"2024-11-11T08:34:32.600Z","updated_at":"2025-07-20T21:34:50.666Z","avatar_url":"https://github.com/smikhalevski.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"#readme\"\u003e\n    \u003cimg alt=\"Paint Bucket\" src=\"images/logo.png\" width=\"600\"/\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n[Highly performant](#performance), [extensible](#plugins), and\n[tiny](https://bundlephobia.com/package/paint-bucket) color manipulation library.\n\n```shell\nnpm install --save-prod paint-bucket\n```\n\n# Overview\n\n🔎 [API documentation is available here.](https://smikhalevski.github.io/paint-bucket/classes/core.Color.html)\n\n```ts\nimport { clr } from 'paint-bucket';\n\nclr('#abcdef').saturation(s =\u003e s / 2).red();\n// ⮕ 188\n```\n\nYou can cherry-pick plugins that you need:\n\n```ts\nimport { clr, Color } from 'paint-bucket/core';\nimport 'paint-bucket/plugin/rgb';\n\nclr().red(); // ✅\n\nclr().saturation(); // ❌ Error: saturation not defined\n```\n\nMost methods provide getter-setter semantics:\n\n```ts\n// Setter\nclr('#f00').red(127.5);\n// or\nclr('#f00').red(r =\u003e r / 2);\n\n// Getter\nclr('#f00').red();\n// ⮕ 255\n```\n\nMutate multiple components at the same time:\n\n```ts\nclr([64, 128, 0])\n  .rgb(([r, g, b, a]) =\u003e [r * 3, g * 2, b, a])\n  .rgb();\n// ⮕ [192, 255, 0, 1]\n```\n\n[`clr`](https://smikhalevski.github.io/paint-bucket/functions/core.clr.html) returns a mutable instance\nof the [`Color`](https://smikhalevski.github.io/paint-bucket/classes/core.Color.html) class. To create a\ncopy of the `Color` instance you can use one of these approaches:\n\n```ts\nconst color1 = clr('#f00');\n\n// color2 is a copy of color1\nconst color2 = clr(color1);\n// or\nconst color3 = color1.clone();\n```\n\nParse and serialize CSS color strings:\n\n```ts\nclr('pink').css();\n// ⮕ \"#ffc0cb\"\n\nclr('rgba(255, 192, 203)').css();\n// ⮕ \"#ffc0cb\"\n```\n\nCreate gradients and obtain color at arbitrary position:\n\n```ts\nclr.gradient(['red', 'blue']).at(0.7).css();\n// ⮕ \"#4d00b3\"\n```\n\nCreate multi-stop gradients with custom stop values:\n\n```ts\nclr.gradient()\n  .stop(0, 'red')\n  .stop(50, 'pink')\n  .stop(100, 'blue')\n  .at(70)\n  .css();\n// ⮕ \"#9973e0\"\n```\n\n# Color models\n\nPaint Bucket provides an abstraction for [color models](https://en.wikipedia.org/wiki/Color_model) which are represented\nas objects that define methods to convert color components between color model representation and RGB. Color components\nare an array of numbers.\n\n```ts\nimport { ColorModel, RGB } from 'paint-bucket/core';\n\nconst CMYK: ColorModel = {\n  name: 'CMYK',\n\n  // The number of color components that this model uses:\n  // cyan, magenta, yellow, black, and alpha \n  componentCount: 5,\n\n  convertComponentsToRGB(components: readonly number[], rgb: RGB): void {\n    // Update elements of the rgb array\n  },\n  convertRGBToComponents(rgb: Readonly\u003cRGB\u003e, components: number[]): void {\n    // Update elements of the components array\n  },\n};\n```\n\nColor model converters expect component values to be in [0, 1] range. Plugin APIs may return component values in any\nother range, but internally components are always normalized to [0, 1].\n\n```ts\nimport { HSL } from 'paint-bucket/color-model/hsl';\n\nconst hsl: HSL = [\n  1, // Hue\n  0, // Saturation\n  0, // Lightness\n  1, // Alpha\n];\n```\n\nWhen you create a new `Color` instance, it uses the RGB color model and corresponding components for the black color.\n\n```ts\nimport { Color } from 'paint-bucket/core';\n\nclr(); // Opaque black RGB color\n```\n\nYou can create a color with any model and components.\n\n```ts\nimport { Color } from 'paint-bucket/core';\nimport { HSL } from 'paint-bucket/color-model/hsl';\n\nnew Color(HSL, [0.5, 1, 0.5, 0.7]); // 70% transparent cyan HSL color\n```\n\n`Color` provides a mechanism to acquire color components in any color model via the\n[`getComponents`](https://smikhalevski.github.io/paint-bucket/classes/core.Color.html#getComponents)\nmethod.\n\n```ts\nimport { Color, RGB } from 'paint-bucket/core';\nimport { HSL } from 'paint-bucket/color-model/hsl';\n\nnew Color(HSL, [0.5, 1, 0.5, 0.7]).getComponents(RGB);\n// ⮕ [0, 1, 1, 0.7]\n```\n\nHere, we created a Color instance initialized with the components of the cyan color in the HSL color model and retrieved\ncomponents in the RGB color model.\n\n[`getComponents`](https://smikhalevski.github.io/paint-bucket/classes/core.Color.html#getComponents) method\nreturns read-only color components, which are computed on the fly. To update the color components of the `Color`\ninstance, you should use the\n[`useComponents`](https://smikhalevski.github.io/paint-bucket/classes/core.Color.html#useComponents)\nmethod. This method returns a writable array of components using a particular color model.\n\n```ts\nimport { Color, RGB } from 'paint-bucket/core';\nimport { HSL } from 'paint-bucket/color-model/hsl';\n\nconst color = new Color(HSL, [0.5, 1, 0.5, 0.5]);\nconst rgb = color.useComponents(RGB);\n\n// Set blue component value to 0 \nrgb[2] = 0;\n\ncolor.getComponents(HSL);\n// ⮕ [0.333, 1, 0.5, 0.7]\n```\n\nPaint Bucket includes pluggable implementations for following color models:\n\n- [CMYK](https://en.wikipedia.org/wiki/CMYK_color_model)\n- [HSL](https://en.wikipedia.org/wiki/HSL_and_HSV)\n- [HSV](https://en.wikipedia.org/wiki/HSL_and_HSV)\n- [HWB](https://en.wikipedia.org/wiki/HWB_color_model)\n- [CIE-L\\*a\\*b\\*](https://en.wikipedia.org/wiki/CIELAB_color_space)\n- [Hunter L, a, b](https://en.wikipedia.org/wiki/Hunter_Lab)\n- [CIE 1931 XYZ](https://en.wikipedia.org/wiki/CIE_1931_color_space)\n\n# Plugins\n\nPaint Bucket relies on plugins in every aspect. The `paint-bucket/core` doesn't implement any color manipulation\nfunctionality.\n\n```ts\nimport { clr, Color } from 'paint-bucket/core';\nimport'paint-bucket/plugin/rgb';\n\nclr().red(64).red(r =\u003e r * 2).red();\n// ⮕ 128\n```\n\n[paint-bucket/plugin/cmyk](https://smikhalevski.github.io/paint-bucket/modules/plugin_cmyk.html)\n\u003cbr\u003eCMYKa color model manipulation plugin.\n\n[paint-bucket/plugin/css](https://smikhalevski.github.io/paint-bucket/modules/plugin_css.html)\n\u003cbr\u003eCSS color values parsing and serialization plugin.\n\n[paint-bucket/plugin/difference](https://smikhalevski.github.io/paint-bucket/modules/plugin_difference.html)\n\u003cbr\u003eComputes the CIEDE2000 \u003ca href=\"https://en.wikipedia.org/wiki/Color_difference\"\u003ecolor difference\u003c/a\u003e.\n\n[paint-bucket/plugin/hsl](https://smikhalevski.github.io/paint-bucket/modules/plugin_hsl.html)\n\u003cbr\u003eHSLa color model manipulation plugin.\n\n[paint-bucket/plugin/hsv](https://smikhalevski.github.io/paint-bucket/modules/plugin_hsv.html)\n\u003cbr\u003eHSVa color model manipulation plugin.\n\n[paint-bucket/plugin/hwb](https://smikhalevski.github.io/paint-bucket/modules/plugin_hwb.html)\n\u003cbr\u003eHWBa color model manipulation plugin.\n\n[paint-bucket/plugin/lab](https://smikhalevski.github.io/paint-bucket/modules/plugin_lab.html)\n\u003cbr\u003eCIE-L*a*b*  color model manipulation methods.\n\n[paint-bucket/plugin/labh](https://smikhalevski.github.io/paint-bucket/modules/plugin_labh.html)\n\u003cbr\u003eHunter L, a, b color model manipulation plugin.\n\n[paint-bucket/plugin/palette](https://smikhalevski.github.io/paint-bucket/modules/plugin_palette.html)\n\u003cbr\u003ePalette generation plugin.\n\n[paint-bucket/plugin/rgb](https://smikhalevski.github.io/paint-bucket/modules/plugin_rgb.html)\n\u003cbr\u003eRGBa color model manipulation plugin.\n\n[paint-bucket/plugin/x11](https://smikhalevski.github.io/paint-bucket/modules/plugin_x11.html)\n\u003cbr\u003e[X11 color names](https://en.wikipedia.org/wiki/X11_color_names) parsing plugin.\n\n## Extend color instance\n\nBelow is an example that shows how to extend the\n[`Color`](https://smikhalevski.github.io/paint-bucket/classes/core.Color.html)\nprototype to implement a color component read and write methods.\n\n```ts\n// ./my-plugin.ts\nimport { Color, RGB } from 'paint-bucket/core';\n\ndeclare module 'paint-bucket/core' {\n  interface Color {\n    // Returns the green color component in range [0, 255]\n    getGreen(): number;\n\n    // Sets the green color component in range [0, 255]\n    setGreen(green: number): Color;\n  }\n}\n\nColor.prototype.getGreen = function () {\n  // Get read-only array of RGB color components where each component\n  // is in [0, 1] range\n  const rgb = this.getComponents(RGB);\n\n  return rgb[1] * 255;\n};\n\nColor.prototype.setGreen = function (green) {\n  // Get writable array of RGB color components where each component\n  // is in [0, 1] range\n  const rgb = this.useComponents(RGB);\n\n  // Update the green component\n  rgb[1] = green / 255;\n\n  // Return Color instance to allow chaining\n  return this;\n};\n```\n\nTo use this plugin we need to create a `Color` instance:\n\n```ts\nimport { clr, RGB } from 'paint-bucket/core';\nimport './my-plugin';\n\nconst color = clr().setRed(128);\n\ncolor.getComponents(RGB);\n// ⮕ [0.5, 0, 0, 1]\n```\n\n# Performance\n\nClone this repo and use `npm ci \u0026\u0026 npm run build \u0026\u0026 npm run perf` to run the performance testsuite.\n\nResults are in millions of operations per second [^1]. The higher number is better.\n\n|                                                   | paint-bucket | [tinycolor2](https://github.com/bgrins/TinyColor) | [chroma.js](https://github.com/gka/chroma.js) |\n|---------------------------------------------------|-------------:|--------------------------------------------------:|----------------------------------------------:| \n| `clr([255, 255, 255])`                            |         18.1 |                                               3.8 |                                           2.1 |\n| `clr('#abc')`                                     |          6.5 |                                               1.6 |                                           1.7 |\n| `clr('#abcdef')`                                  |          6.2 |                                               1.8 |                                           1.9 |\n| `clr('#abcdefff')`                                |          5.7 |                                               1.8 |                                           1.7 |\n| `clr(0xab_cd_ef)`                                 |         15.3 |                                                🚫 |                                           2.9 |\n| `clr().rgb32(0xab_cd_ef_ff)`                      |         15.6 |                                                🚫 |                                            🚫 |\n| `clr('rgba(128, 128, 128, 0.5)')`                 |          3.0 |                                               1.5 |                                           0.2 |\n| `clr(…).saturation(50).rgb()`                     |         11.0 |                                               0.9 |                                           1.0 |\n| `clr(…).hue(90).lightness(10).rgb()`              |          9.5 |                                               0.6 |                                            🚫 |\n| `clr.gradient(['#fff', '#000'])`                  |          3.3 |                                                🚫 |                                           0.5 |\n| `clr.gradient(…).at(0.5, RGB, lerp)` [^2]         |          8.5 |                                                🚫 |                                           3.7 |\n| `clr.gradient(…).at(0.5, LAB, csplineMonot)` [^2] |          8.4 |                                                🚫 |                                           3.8 |\n\n[^1]: Performance was measured on Apple M1 Max using [TooFast](https://github.com/smikhalevski/toofast).\n\n[^2]: [`lerp`](https://github.com/smikhalevski/algomatic/#lerp) and\n[`csplineMonot`](https://github.com/smikhalevski/algomatic/#csplinemonot) are linear and monotonous cubic spline\ninterpolation factories respectively from [Algomatic](https://github.com/smikhalevski/algomatic).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmikhalevski%2Fpaint-bucket","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmikhalevski%2Fpaint-bucket","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmikhalevski%2Fpaint-bucket/lists"}