# color2k: color manipulation for CSS-in-JS in about 2.8 kB

> color2k parses and manipulates colors in sRGB with a hard constraint on bundle size, zero runtime dependencies and outputs limited to rgba and hsla strings. It is aimed at CSS-in-JS code that needs a darken, a lighten or a contrast check, and it refuses to become a general color library.

**ricokahler/color2k** — a color parsing and manipulation lib served in roughly 2kB

- Repository: https://github.com/ricokahler/color2k
- Website: https://color2k.com
- Stars: 633 · Forks: 15
- Language: TypeScript
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/ricokahler-color2k

## The bundle size is the feature, not a by-product

color2k states its objective in the first line of the description: a color parsing and manipulation library with the objective of keeping the bundle size as small as possible while still satisfying all of your color manipulation needs in an sRGB space.

The published numbers are given in the same breath. The full bundle size is currently 2.8 kB, and it gets as small as 2.1 kB with tree shaking. The project publishes a comparison table against other libraries, listing chroma-js at 13.7 kB, polished at 11.2 kB, color at 7.6 kB and tinycolor2 at 5kB against color2k at 2.8 kB. The README also links to bundlejs.com so you can compare tree shaken outputs directly rather than taking the figures on trust.

That framing explains almost every design decision in the library. The output models are limited to rgba and hsla, and the explanation given is that the library was created with CSS-in-JS in mind, where what matters at the end of the day is that the browser can understand the colour string you gave it as a background-color.

Because only those two models are supported, the library does not need code to handle optional alpha channels or conversions to colour models a browser cannot use, such as CMYK. That is the whole mechanism: fewer output formats means less code.

For a library whose size is a selling point, the release history shows the same story. Versions 2.0.4 on 2026-07-05, 2.0.3 on 2023-12-08 and 2.0.2 on 2023-01-30 mean the project has been stable at the 2.0 line for a while, and the last push was on 2026-10-12.

## Installing it and calling the functions

The package is installed from npm:

```bash
npm i color2k
```

It can also be used directly from a CDN in supported environments such as Deno and modern browsers, through skypack.dev:

```js
import { darken, transparentize } from 'https://cdn.skypack.dev/color2k?min';
```

The ordinary usage is a named import and a function call, with amounts given as decimals between 0 and 1:

```js
import { darken, transparentize } from 'color2k';

// e.g.
darken('blue', 0.1);
transparentize('red', 0.5);
```

The functions return strings, not objects. That is a deliberate consequence of the size goal, and it means you cannot chain a returned value back into another manipulation the way you could with a library that returns a colour instance.

Each function has its own source file under src, with the generated documentation linking to it directly, so the API is per-function rather than a single monolithic module.

The published package surface is also narrow. The README lists it as limited to dist, README.md, LICENSE and package.json, and the package.json files field confirms it with a single entry, dist. The entry points cover the usual module formats, with a CommonJS main at ./dist/index.main.cjs.js, a module build, an unpkg UMD build, type declarations at ./dist/index.d.ts, and an exports map that handles the import and require cases separately.

## The API is arithmetic on HSL channels, and the errors are explicit

The generated API section shows how small the surface really is, and how mechanical each operation is.

darken subtracts from the lightness channel in HSL space, and desaturate subtracts from the saturation channel. adjustHue rotates the hue by a number of degrees and returns an hsla string, with hue values wrapping around the 0 to 360 degree color wheel. The amounts are decimals between 0 and 1:

```js
darken('white', 0.1); // 'hsla(0, 0%, 90%, 1)'
```

```js
desaturate('red', 0.5); // 'hsla(0, 50%, 50%, 1)'
```

```js
adjustHue('red', 180); // 'hsla(180, 100%, 50%, 1)'
```

Notice that the outputs are hsla even for functions whose names do not suggest it, and that the alpha channel is always present in the result, which is the practical effect of only supporting two output models.

The error handling is equally direct. A dedicated ColorError class extends Error and is thrown when color2k cannot parse an input colour, and it carries the offending value:

```js
new ColorError('nope').message; // 'Failed to parse color: "nope"'
```

```ts
class ColorError extends Error
```

That is a real design decision rather than a missing feature. A colour library that throws a typed error with the failing input in it is far easier to debug than one that returns null or produces a black colour and lets you find the problem downstream. The class is exported alongside the functions, so you can catch it specifically rather than catching every Error.

The signature style is plain TypeScript, for example function darken(color: string, amount: number): string, and the return type is always a string rather than a richer object.

## Why only two output models, and what that costs you

The restriction to rgba and hsla is the single most consequential decision in the library, so it is worth being precise about what it means.

The stated reason is CSS-in-JS. What matters is that the browser can understand the colour string you give it as a background-color, so supporting only rgba and hsla means no code is needed to deal with optional alpha channels or with converting to non-browser supported colour models such as CMYK.

The cost is that a design token pipeline which stores colours in another space, or which needs a colour model a browser cannot render directly, has to convert outside this library. There is no mix function, no interpolation between two colours, no relative luminance helper exposed beyond the getContrast function, and no HWB, Lab or LCH output.

That makes color2k a different tool from a general colour library. chroma-js, polished, color and tinycolor2 are all designed to be general, and their size reflects the number of colour models, operations and utility functions they carry. color2k is designed to be small, and the comparison table shows the price you pay in features.

The choice is defensible for a component library or a design system that only ever needs to darken a brand colour by ten percent or fade a background. It is not defensible if your pipeline needs perceptual colour work, and the project is clear enough about its scope that you can tell which side of that line you are on before you install it.

The project also states where to push back: if a feature is missing, the request is to open an issue. That is the channel for a colour model that has to be added, though every addition works against the size budget that defines the library.

## Trust and publishing as a design constraint

The README has a section titled Trust and publishing, and it reads like a supply chain checklist for a dependency that ends up in other people's front ends.

Zero runtime dependencies is the first item, and it is the strongest one. A library that ships nothing else cannot be the vector for a transitive compromise through its own dependency graph. The package.json dependencies list for runtime is empty, with the tooling on the devDependencies side.

The published package surface is deliberately narrow, limited to dist, README.md, LICENSE and package.json, so the tarball contains the build output and nothing else that could be edited in transit.

npm provenance is configured through trusted publishing for release builds, and publishConfig in package.json sets provenance to true. That ties a published version to the build that produced it and to the identity that ran it.

The README and the docs site are generated from the JSDoc comments in src/*.ts, which is why the API section in the README looks the way it does, with the parameters tables and the source links. That generation is checked in CI rather than trusted, since the check script runs docs:check, which runs the docs script with a CHECK_DOCS=1 environment variable.

Security issues are reported through the process in SECURITY.md, and maintainers are told to run the checks in docs/release-checklist.md before publishing.

The whole check script is worth reading as a project summary. It lints, runs the tests with coverage, builds, checks the docs, builds the website and checks that too, checks the package contents, and audits production dependencies. The package check runs the build and then a script that inspects what would be published.

## How the project is built and where it sits today

The build is a rollup configuration, with rollup.config.mjs at the root, and the build script is a shell script at ./scripts/build rather than an inline command. The repository also holds a babel.config.json, a jest.config.js for the tests, an eslint config, a prettier config, a renovate configuration for dependency updates and a .nvmrc pinning the Node version used in development.

The docs and the website are generated artifacts rather than hand written pages. The scripts directory holds build, docs.js, website.js, check-website.js and check-package.js, and the website directory holds the site that color2k.com serves. The docs generator and the website generator are separate scripts, and each has a check counterpart, so the CI pipeline can fail if the generated output drifts from the source comments.

The credit line in the README matters for anyone weighing the library against polished. Heavy credit goes to polished.js and Sass, and much of the implementation of color2k is copied from polished. That is stated plainly, and it explains why the API shape and the return-string convention look the way they do.

On maintenance, the picture is stable rather than busy. The licence is MIT, the project is not archived, and the last push to the repository was on 2026-10-12. The most recent release, v2.0.4, came on 2026-07-05, after a long gap back to v2.0.3 in December 2023. For a library whose promise is to stay small and boring, that cadence is consistent with the promise.

## Conclusion

Adopt color2k when you write CSS-in-JS and want darken, lighten, transparentize and contrast helpers without pulling a larger color library into your bundle, and when every colour you produce only needs to reach a browser as rgba or hsla. Do not adopt it if you need CMYK, HWB, Lab output, colour space conversion or a mix API, since those are outside its stated scope. Before shipping, verify that the outputs your design tokens expect are among the two colour models it supports, and check the check script in package.json, which lints, tests with coverage, builds, regenerates the docs and audits production dependencies.

## FAQ

### How do I install and use color2k?

Install it with npm i color2k, or import it directly from a CDN through skypack.dev in supported environments. Then import the functions you need, for example darken and transparentize, and pass a colour string plus an amount between 0 and 1.

### What colour formats does color2k output?

Only rgba and hsla strings. The project explains that it was created with CSS-in-JS in mind, so only the models a browser needs are supported, which keeps the bundle small by avoiding alpha channel handling and conversions to models such as CMYK.

### How large is color2k compared with other colour libraries?

The published figures are 2.8 kB for the full bundle and 2.1 kB with tree shaking, against 13.7 kB for chroma-js, 11.2 kB for polished, 7.6 kB for color and 5kB for tinycolor2.

### What happens when color2k cannot parse a colour?

It throws a ColorError, a class extending Error, with a message such as Failed to parse color: "nope" and a constructor parameter holding the colour value that failed to parse.

### Does color2k have any runtime dependencies?

No, it has zero runtime dependencies. The published package is limited to dist, README.md, LICENSE and package.json, and npm provenance is configured through trusted publishing for release builds.

## Sources

- [License: MIT](https://github.com/ricokahler/color2k/blob/main/LICENSE)
- [Project website](https://color2k.com)
- [README](https://github.com/ricokahler/color2k/blob/main/README.md)
- [Releases](https://github.com/ricokahler/color2k/releases)
- [ricokahler/color2k on GitHub](https://github.com/ricokahler/color2k)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ricokahler-color2k
