Categories
Original Releases

Releasing Color.js: A library that takes color seriously

Related: Chris’ blog post for the release of Color.js

This post has been long overdue: Chris and I started working on Color.js in 2020, over 2 years ago! It was shortly after I had finished the Color lecture for the class I was teaching at MIT and I was appalled by the lack of color libraries that did the things I needed for the demos in my slides. I asked Chris, “Hey, what if we make a Color library? You will bring your Color Science knowledge and I will bring my JS and API design knowledge. Wouldn’t this be the coolest color library ever?”. There was also a fair bit of discussion in the CSS WG about a native Color object for the Web Platform, and we needed to play around with JS for a while before we could work on an API that would be baked into browsers.

We had a prototype ready in a few months and presented it to the CSS WG. People loved it and some started using it despite it not being “officially” released. There was even a library that used Color.js as a dependency!

Once we got some experience from this usage, we worked on a draft specification for a Color API for the Web. In July 2021 we presented it again in a CSS WG Color breakout and everyone agreed to incubate it in WICG, where it lives now.

Why can’t we just standardize the API in Color.js? While one is influenced by the other, a Web Platform API has different constraints and needs to follow more restricted design principles compared to a JS library, which can be more flexible. E.g. exotic properties (things like color.lch.l) are very common in JS libraries, but are now considered an antipattern in Web Platform APIs.

Work on Color.js as well as the Color API continued, on and off as time permitted, but no release. There were always things to do and bugs to fix before more eyes would look at it. Because eyes were looking at it anyway, we even slapped a big fat warning on the homepage:

Eventually a few days ago, I discovered that the Color.js package we had published on npm somehow has over 6000 downloads per week, nearly all of them direct. I would not bat an eyelid at those numbers if we had released Color.js into the wild, but for a library we actively avoided mentioning to anyone outside of standards groups, it was rather odd.

How did this happen? Maybe it was the HTTP 203 episode that mentioned it in passing? Regardless, it gave us hope that it’s filling a very real need in the pretty crowded space of color manipulation libraries and it gave us a push to finally get it out there.

So here we are, releasing Color.js into the wild. So what’s cool about it?

  • Completely color space agnostic, each Color object just has a reference to a color space, a list of coordinates,, and optionally an alpha.
  • Supports a large variety of color spaces including all color spaces from CSS Color 4, as well as the unofficial CSS Color HDR draft.
  • Supports interpolation as defined in CSS Color 4
  • Doesn’t skimp on color science: does actual gamut mapping instead of naïve clipping, and actual chromatic adaptation when converting between color spaces with different white points.
  • Multiple DeltaE methods for calculating color difference (2000, CMC, 76, Jz, OK etc)
  • The library itself is written to be very modular and ESM-first (with CJS and IIFE bundles) and provides a tree-shakeable API as well.

Enjoy: Color.js

There is also an entire (buggy, but usable) script in the website for realtime editable color demos that we call “Color Notebook”. It looks like this:

And you can create and share your own documents with live Color.js demos. You log in with GitHub and the app saves in GitHub Gists.

Color spaces presently supported by Color.js
Categories
Articles

Mass function overloading: why and how?

One of the things I’ve been doing for the past few months (on and off—more off than on TBH) is rewriting Bliss to use ESM 1. Since Bliss v1 was not using a modular architecture at all, this introduced some interesting challenges.

Categories
Tutorials

Writable getters

Setters removing themselves are reminiscent of Ouroboros, the serpent eating its own tail, an ancient symbol. Media credit

A pattern that has come up a few times in my code is the following: an object has a property which defaults to an expression based on its other properties unless it’s explicitly set, in which case it functions like a normal property. Essentially, the expression functions as a default value.

Categories
Articles

The case for Weak Dependencies in JS

Earlier today, I was briefly entertaining the idea of writing a library to wrap and enhance querySelectorAll in certain ways. I thought I’d rather not introduce a Parsel dependency out of the box, but only use it to parse selectors properly when it’s available, and use more crude regex when it’s not (which would cover most use cases for what I wanted to do).

In the olden days, where every library introduced a global, I could just do:

if (window.Parsel) {
	let ast = Parsel.parse();
	// rewrite selector properly, with AST
}
else {
	// crude regex replace
}

However, with ESM, there doesn’t seem to be a way to detect whether a module is imported, without actually importing it yourself.

I tweeted about this…

Categories
Rants Thoughts

The failed promise of Web Components

Web Components had so much potential to empower HTML to do more, and make web development more accessible to non-programmers and easier for programmers. Remember how exciting it was every time we got new shiny HTML elements that actually do stuff? Remember how exciting it was to be able to do sliders, color pickers, dialogs, disclosure widgets straight in the HTML, without having to include any widget libraries?

The promise of Web Components was that we’d get this convenience, but for a much wider range of HTML elements, developed much faster, as nobody needs to wait for the full spec + implementation process. We’d just include a script, and boom, we have more elements at our disposal!

Or, that was the idea. Somewhere along the way, the space got flooded by JS frameworks aficionados, who revel in complex APIs, overengineered build processes and dependency graphs that look like the roots of a banyan tree.

This is what the roots of a Banyan tree look like. Photo by David Stanley on Flickr (CC-BY).