github color-js/color.js v0.7.0

8 hours ago

Two pre-releases in the making, this release brings a lot of new color spaces, a new gamut mapping method, a smarter display(), a leaner dist/, and a pile of fixes.
If you have been following along with the v0.7.0-alpha.1 and v0.7.0-alpha.2 pre-releases, the only things new to you are in Changes since v0.7.0-alpha.2.

⬇️ Over 240 million downloads! 🤯

Color.js has now been downloaded over 240 million times on npm!

As a reminder, we have an Open Collective that you can fund directly.
If your company depends on Color.js in any way, it is in your best interest to ensure its future is sustainable.

🚨 Breaking changes

These are unlikely to break things for the majority of users, but theoretically could if you were doing weird stuff with Color.js 😜.

We cleaned up dist/ quite a bit with this release and re-evaluated what actually needs to be there:

  • Removed the pre-built ESM bundles. We now only generate bundles for CJS and global builds. ESM exports point directly at the corresponding files in src/. This also fixes a dual-instance bug where importing from src/ vs. the package root could yield different Color registries (by @LeaVerou in #739).
  • Removed the minified .min.* files from the package, since packages are moving away from providing these and minification is becoming a consumer concern (by @LeaVerou in #741).

For those of you that have been importing files directly from colorjs.io, removed files now redirect to the versions still there (e.g. colorjs.io/dist/color.min.js and colorjs.io/dist/color.js now both redirect to colorjs.io/src/color.js), so your code should continue to work.

New color spaces

  • 🆕 Gamut-relative (OK)LCH spaces (by @LeaVerou in #736) Ever tried to use (OK)LCH and kept struggling with the irregularity of the gamut shape? You can now have your cake and eat it too, as we introduced gamut-relative versions of these spaces, where c = 1 is the most colorful in-gamut color at a given lightness and hue so you never have to worry about getting out of gamut! These new spaces are:
    • oklch-p3, oklch-srgb, oklch-rec2020,
    • lch-p3, lch-srgb, lch-rec2020.
    • All six are built on a new general GamutRelativeColorSpace class that can be easily used to generate such color spaces for any gamut and color space, as long as there is a coordinate to reduce that is guaranteed to get you in-gamut.
    • Note that this loses you some of the perceptual uniformity of the original spaces, but it is a tradeoff that is often worth it for the convenience of staying in-gamut. After all, perceptual uniformity only applies in-gamut anyway.
  • 🆕 hsl-p3 and hsl-rec2020: HSL syntax, wider gamut (by @LeaVerou in #735)
  • 🆕 The experimental Helmlab family of perceptual color spaces: helmlab-metric (Helmlab MetricSpace), helmgen (HelmGen), and helmgenlch (HelmGenLCh) (by @Grkmyldz148)

Other new features

  • 🆕 Smarter display() fallback When a color isn't natively supported by the browser, display() now stays as close as possible to the original color: it walks up the base color space chain (closest first) and uses the first supported ancestor, preserving the color's gamut (e.g. an hsl-p3 color falls back to color(display-p3 …) rather than lab()) instead of always jumping to the widest default. Adds an opt-in displaySpaces override on ColorSpace, a parameterizable supports(), and a DisplayOptions interface (by @LeaVerou in #738)
  • 🆕 New gamut mapping method: raytrace. It traces a ray to the gamut boundary instead of binary-searching, automatically determining the RGB gamut and linear space from the space object (by @facelessuser)
  • 🆕 New deltaE method: deltaEHelmlab, based on the Helmlab model (by @Grkmyldz148)
  • 🆕 Added a collapse option to serialize()/Color.toString() to disable collapsing for hex colors (e.g. keep #ff0066 instead of collapsing it to #f06) (by @MysteryBlokHed in #712)

For plugin/library/tooling authors

Exposed more internals, so you never have to duplicate stuff that Color.js already knows about:

  • Expose transformation matrices via ColorSpace.M Color spaces now expose the transformation matrices they use internally through a new M property, so consumers can reuse them instead of duplicating the data. Matrices for RGB spaces can also be supplied via the generic M option (by @LeaVerou in #749)
  • Matrix algebra utilities Added inv (matrix inversion) and solve to the math utilities, so external libraries are no longer required when developing new color spaces (by @facelessuser)
  • Polar spaces declare their hue coordinate via the new ColorSpace#hueId and ColorSpace#hueIndex, so code that needs the hue angle can look it up from the space definition instead of assuming it is named h (by @svgeesus in #754)

Changes since v0.7.0-alpha.2

Bug fixes

  • Premultiplied interpolation is now correct in polar spaces (by @svgeesus in #754). Premultiplication used to multiply every coordinate by alpha, including the hue angle, which is meaningless. Per CSS Color 4 § 13.3, the hue angle is never premultiplied, and un-premultiplication must not divide by a zero or none alpha. Concretely:
    • The hue angle is skipped when premultiplying and when undoing it, and is found from the space definition, so spaces whose hue coordinate isn't called h (e.g. hz in Jzczhz) now interpolate correctly too.
    • Un-premultiplying by an alpha of 0 leaves the coordinates untouched instead of dividing by zero and producing NaN.
    • A none alpha is carried forward from the other color before premultiplying, per CSS Color 4 § 13.2, and stays none only if both colors are missing it. Previously a none alpha premultiplied every coordinate to zero, turning the color black.
  • helmgenlch now serializes as color(--helmgenlch …) instead of the invalid color(helmgenlch …), by giving it the cssId its sibling spaces already had (by @Grkmyldz148, fixes #730)
  • Gamut surface threshold updated, and the values for 32 bit vs 64 bit are now documented: 1e-12 gives better resolution for 64 bit values, while 1e-6 is the right choice for 32 bit (by @facelessuser in #752)

For contributors

  • Added an AI-assisted contributions section to CONTRIBUTING.md, spelling out our expectations for PRs written with AI assistance (by @Grkmyldz148, closes #723)

Other bug fixes & performance

These landed in the pre-releases:

  • Preserve a subclass's own toBase/fromBase when options omit them, instead of clobbering prototype methods with undefined (by @LeaVerou)
  • Add the types field back to package.json (by @MysteryBlokHed in #714)
  • Avoid implied color space dependencies for procedural usage, so consumers no longer need to manage them manually (by @aduth in #734)
  • Reduce a CAM16 calculation in the worst-case scenario (by @facelessuser)
  • Fix HCT tests and related calculations (by @facelessuser)
  • Fix the CI install command after the lockfile removal (by @MysteryBlokHed in #744)

Full Changelog: v0.6.1...v0.7.0

New Contributors

  • @Grkmyldz148 made their first contribution (Helmlab color spaces and deltaEHelmlab)
  • @aduth made their first contribution in #734

Don't miss a new color.js release

NewReleases is sending notifications on new releases.