Releases: color-js/color.js
v0.6.0 Beta 2
v0.6.0-beta.2
Just one more quick beta to make sure all is smooth before we get stable v0.6.0 out!
⬇️ 90 million downloads!
Just a few days ago when we released v0.6.0-beta.1, Color.js had 80 million downloads.
We are now at 90 million downloads, and the rate of increase is still accelerating (currently at 3 million downloads per week).
In fact, we had to automate updating the number in our README so we could have a chance to keep up (thanks @MysteryBlokHed!)
As a reminder, we recently started an Open Collective so you can fund Color.js's development.
If your company depends on Color.js in any way, it is in your best interest to ensure its future is sustainable.
Changes from v0.6.0-beta.1
Improvements to types
- Bump TypeScript to v5.5 and in type definitions, replace
@typedefwith@importwhere relevant to improve DX and overall quality of generated.d.tsfiles (by @MysteryBlokHed and @lloydk in #686)
v0.6.0 Beta 1
We hear you, it’s been a while, and v0.6.0 is long overdue. Assuming any significant issues come up in this beta, we plan to release a stable v0.6.0 in 1-2 weeks or so.
⬇️ 84 million downloads!
Color.js is quickly becoming the de facto color handling library for JS:
it has now been downloaded over 84 million times on npm,
a number that is rapidly increasing, at the rate of nearly 3 million downloads per week!
As a reminder, we recently started an Open Collective so you can fund Color.js's development.
If your company depends on Color.js in any way, it is in your best interest to ensure its future is sustainable.
Changes
Note
This only includes the changes after v0.6.0 Alpha 1.
Check out the v0.6.0 Alpha 1 release notes for changes since 0.5.2
API changes for DX
- A common request has been a function that gracefully parses colors, without throwing if there is an error. This version adds exactly that:
tryColor()/Color.try()(by @LeaVerou in #664) - A common use case was to use the procedural API for tree-shaking and performance, but still import all color spaces that Color.js supports. This is now made much easier, through the new
spacesexport of/fnand the new/spacestop-level export. (by @LeaVerou in #663, with types by @MysteryBlokHed in #668) - New
/srcexport to import Color.js's source code directly (by @LeaVerou in #663, with types by @MysteryBlokHed in #668)
API changes for spec compliance
- Change
color(ictcp ...)toictcp(...)per CSS Color HDR (by @svgeesus in #646) - Change
color(jzazbz ...)tojzazbz(...), andcolor(jzczhz ...)tojzczhz(...)per CSS Color HDR (by @svgeesus in #647) - Unprefix
display-p3-linearsince it is now in CSS Color 4 (i.e.color(--display-p3-linear ...)→color(display-p3-linear ...)(by @svgeesus in c90fe38). Not a breaking change, as both are still supported. - Use gamma 2.40 for display-referred
rec2020; rename previous implementation as scene-referred--rec2020-oetf(by @svgeesus in #669) - Make HSL parsing spec-compliant (by @kleinfreund in #650)
Bug fixes
- CAM16 and HCT hues are now correctly set to
nullwhen chroma is near zero (by @facelessuser in #644) - Fix issues with creating custom color spaces (by @sidewayss and @LeaVerou in #628)
- Don't clamp negative values in Absolute XYZ D65 (by @svgeesus in #613)
- Adjust calculations in Jzazbz and fix Jzazbz and JzCzhz reference ranges (by @svgeesus in #634 #635)
- Ensure Prophoto and Rec2020 spaces handle negative values (by @lloydk in #640)
- Don't throw for unknown coords when space accessors are used (by @LeaVerou)
- In
toGamut(), better handle the case when JND equals 0 (by @facelessuser in #659)
Improvements to types
- Overload
multiplyMatricestypes and update implementation to pass all tests (by @epsilonError in #580 #631) - Fix CAM16 and HCT type errors (by @lloydk and @MysteryBlokHed in #622)
- Fix different types and type errors (by @lloydk in #642)
- Fix space accessor types to allow
null(by @lloydk) - Fix return types of the
darken()/lighten()functions on theColorclass (by @lloydk in #654)
For contributors
- Testsuite & test coverage improvements (by @epsilonError in #594 and @svgeesus in f02ce7f)
Full Changelog: v0.6.0-alpha.1...v0.6.0-beta.1
New Contributors
- @sidewayss made their first contribution in #628
- @kleinfreund made their first contribution in #650
- @drwpow made their first contribution in #656
v0.6.0 Alpha 1
⬇️ 10 million downloads! + Making Color.js sustainable
Color.js has now been downloaded over 10 million times on npm!
You may have noticed we removed ads from the Color.js website a while back.
While Carbon ads were the good kind of ads (relevant, not intrusive), it was not really worth it, they barely made enough to cover costs like the domain name etc.
Instead, we have started 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
There are a number of breaking changes in this release, but they should only negatively affect some pretty specialized use cases.
null instead of NaN to represent none values
As announced in v0.5.0, we have now switched to using null instead of NaN to represent none values (naturally occurring when converting achromatic colors to certain color spaces).
Not only is null conceptually closer, but since CSS also now has a NaN value, this change allows us to represent it properly, using an actual NaN value.
NaN continues to be parsed (and becomes NaN in JS). Instead of being serialized to NaN (which is invalid in CSS), it is serialized to calc(NaN) which is a valid coordinate in CSS. For roundtripping to work properly, this also means we now parse calc(NaN) as well. Slippery slope? We’ll see. 😁
If you are working with any code that needs to handle Color instances/objects generically, without knowing which version of Color.js they come from, you can detect which value is being used and use that instead of a hardcoded null or NaN:
let noneCoord = new Color("rgb(none none none)").coords[0];
const NONE_VALUE = noneCoord?.valueOf() ?? noneCoord;(by @LeaVerou in cdf6f0d, @facelessuser in #476, @MysteryBlokHed in #530)
Plain numbers instead of Number objects for coordinates
Previously, coordinates would be parsed into Number objects so they could retain metadata about their parsing. From this release onwards, they are plain number primitives, which results in both performance improvements, and improved DX.
Instead, parsing metadata is passed around as a separate object, and stored on Color instances under color.parseMeta. This happens automatically in the OOP API, but users need to explicitly opt-in when using the procedural API, since that is optimized for high performance use cases.
In addition, this metadata is now far more elaborate and can pretty much recreate the format parsed. Which brings us to…
Colors now reserialized in the format parsed
We heard you! This has been a longstanding pain point, and it is now fixed. If you’re parsing a hex color, it will be serialized back to a hex color. If you’re specifying your chroma in percentages, percentages you’ll get back. If for some reason, you’re parsing a legacy comma-separated color, lo and behold, you can modify it and get back a legacy comma-separated color without lifting a finger!
Caveats:
- This only happens automatically in the OOP API. The procedural API does not store parsing metadata by default as it’s optimized for speed, you need to pass a
parseMetaobject explicitly. - You can always override this by passing
format(orformat: "default") for the color space default, which gives you the previous behavior.
Other big improvements
New color spaces
- 🆕 OKHSL and OKHSV by @facelessuser (#469 #517)
- 🆕 OkLrab and OkLrCh by @facelessuser (#511)
- 🆕 Linear Rec2100 by @lloydk (#591)
More control over serialization
You can now specify a format from any color space in serialize()/color.toString() without having to convert the color to a different color space.
And colorSpace.findFormat()
Another big pain point was that the way Color.js did serialization made simple things easy (by having sensible defaults and a wide range of predefined formats) and complex things possible (by allowing entirely custom formats to be specified), but the in-between was not smooth at all: the moment you needed anything custom, the only way was to recreate a whole format.
Starting with this release, you can now specify a lot more granular options for serialization, without having to redefine a format:
coordswith an array of coord types (e.g.["<percentage>", "<number>[0, 100]", "<angle>"]). Anyundefinedvalues will just get the default type, so you can even do things like[, "<percentage>", ]to e.g. make OKLCh chroma a percentage without having to respecify the default type of any other coord.alphato control display and type of alpha:- Force alpha to be added even when it’s 100%:
alpha: true - Prevent alpha from being added, even when < 100%:
alpha: false - Format alpha as a percentage:
alpha: "<percentage>" - Do both 1 and 3:
alpha: {include: true, type: "<percentage>"}
- Force alpha to be added even when it’s 100%:
Switching from TypeScript types to JSDoc
You may have noticed that our API docs had not been great in the past. This is because we were describing types in .d.ts files, but documentation was in JSDoc comments. However (the otherwise lovely) Typedoc expects a single source of truth for both, which would mean either having untyped API docs, or API docs with only types. It also meant that we had to maintain Color.js’s pretty extensive API in two places, which did not scale.
With this release we went all in on JSDoc, thanks to @MysteryBlokHed’s monumental effort in #540.
Other Color.js Initiatives
Color Elements
You may have noticed our three experimental custom elements in the past — or maybe not, as they were very experimental and thus not featured very prominently.
These have now been split into a separate project, and a separate domain: https://elements.colorjs.io and expanded into a library of 10 web components for building color-related apps (the first library of its kind to our knowledge).
They are still very experimental, but way more polished than their previous state, and there is heavy activity on the project.
If you were referencing these from their previous URL, there is a redirect in place, but do note their tag names and API has changed.
Color Apps
We have also moved our Color apps (which also serve as Color.js demos) into their own repo and domain: https://apps.colorjs.io
If you have links to these, there’s nothing to worry about: the old URL still works (it just redirects to the new one).
There is also a new app:
- Gamut mapping: Explores different gamut mapping algorithms (used in CSS WG research)
Color Palettes
Another experimental project under the Color.js umbrella is Color Palettes,
which aims to analyze designer-created color palettes in a variety of color spaces, as an attempt to understand how to generate them
and document what patterns are prominent.
You may (or may not) be surprised to find that they are not regular in any color space, not even perceptually uniform ones.
This project is still in its infancy (I would not even call it alpha), but we are excited about its potential.
Other changes
API
deltas()functions for getting coordinate/alpha differences between two colors in any color space. (@LeaVerou in #532)get()/set()/setAll()now support alpha as well (by @LeaVerou)- Hate seeing numbers like 0.30000000000000004 ? Our default number formatting now attempts to limit IEEE 754 precision issues.
- New DeltaE method:
OK2(believed to be more perceptually uniform) (by @svgeesus in #486) - Longer and undefined/same hues now have parity with CSS spec (thanks @facelessuser in #474)
- New
colorSpace.isUnboundedproperty (by @lloydk in #503) - Improved number parsing (by @facelessuser in #508)
parse()now clamps alpha as well, just like theColorconstructor (by @LeaVerou)- Functional API now also available with ESM exports (by @MysteryBlokHed in #606)
getAll()now supports an optionaloptionsparameter object withspaceandprecisionas possible keys (by @DmitrySharabin in #548)
Performance
- Matrix transform performance improvements by @lloydk that make certain conversions 3x faster (#585 #588)
Docs
- API docs that are actually up to date, using typedoc! You can find them in (by @LeaVerou with help from @MysteryBlokHed in #498 #497 #549)
- Updated color space diagram in https://colorjs.io/docs/spaces which is now dynamically generated via https://d2lang.com/ (by @LeaVerou)
- Demonstrate JND with colours that are different (by @perey in #538)
Website
- Avoid style recalculation of all elements on each scroll event. It makes the experience of working with the website much smoother (by @Inwerpsel in #592)
Bug fixes
- Object-oriented functions now work between different sources of Color.js (by @MysteryBlokHed in #605)
- Fix serialization of negative percentages (by @lloydk in #554)
- Handle negative square roots in a sane manner for Rec. 2100 HLG (by @facelessuser in #575)
- Do not use HSL normalized saturation and hue for certain spaces (by @facelessuser in #582)
- Avoid mutating arguments passed to the Color constructor (by @MysteryBlokHed in #603)
- Fix parsing 7-character hex colors (by @kleinfreund in #616)
- Fix parsing of percentage values for color spaces with coords that have a range property with a minimum value less than 0 (e.g. acescc) (by @lloydk in ...
v0.5.2
A fix for the same issue as the previous patch. This should fix compatibility with all TypeScript versions.
What's Changed
- [types] Remove module augmentation by @MysteryBlokHed in #566
Full Changelog: v0.5.1...v0.5.2
v0.5.1
Implements a change suggested by @kachkaev in #560 (comment) to fix errors on newer TypeScript versions.
Full Changelog: v0.5.0...v0.5.1
v0.5.0
It’s been a while since our last release, so this is a big one!
Going forwards, we plan to make at least one release per month.
Heads ups
⚠️ Future breaking change
Color.js currently uses NaN values to represent CSS none (e.g. for achromatic colors).
However, CSS also now has a NaN value, which is currently impossible to represent in Color.js.
Therefore, In the next non-minor version, we will start using null to represent none.
If you have code that handles these values, you can prepare for the change by detecting which value is being used and using that instead of a hardcoded NaN:
const NONE_COORD = new Color("rgb(none none none)").coords[0].valueOf()🆕 Color.js Discord server
We’ve just set up a Discord server so that people can help each other and discuss color science topics in a more immediate way. Join now!.
Do note we also have a Discussions section for more long-form help.
⬇️ 2 million downloads!
We’ve recently passed a big milestone: Color.js was downloaded 2 million times on npm!
New in v0.5.0
New Color Spaces
- CAM16 (JMh) by @facelessuser in #379
- HCT by @facelessuser in #380
- Luv and LCHuv by @lloydk in #391
- HSLuv and HPLuv by @lloydk in #404
Improved compatibility with CSS:
- Moving to a standard
---prefixed version for color spaces that are not built-in into CSS. To facilitate "upgrading" color spaces when they later get added to standard CSS, both---prefixed and unprefixed versions of all color spaces are also accepted. Implemented by @jgerigmeyer in #407 and #439 - Add support for more angle units (
grad,radandturn) improving compatibility with CSS, by @kleinfreund in #324 - Add CSS gamut mapping algorithm by @jamesnw in #344 and #352
- Remove gamut mapping from
hsl(),hwb()andhsv()by @jamesnw in #331
Gamut mapping improvements
- Support for HCT gamut mapping by @facelessuser in #420
- toGamut extended to allow configuring the delta E method, the JND, and enabling white and black SDR clamp by @facelessuser in #420
- Allow hsluv to be gamut mapped using the CSS algorithm by @lloydk in #431
- Avoid needless two-step color conversion at the start of gamut mapping by @facelessuser in #426
- Avoid round-trip to/from oklch in CSS mapping method for colors that are in gamut @jgerigmeyer in #455
Color space API improvements:
- Color spaces can now override the heuristically determined color space used to check gamut via a
gamutSpaceparameter. Implemented by @lloydk in #369 - Color spaces can now define a grammar for
color()format. Implemented by @lloydk in #370 - Support string ids in
colorSpace.equals()by @LeaVerou in #413 - Make the color space optional in
getAll()by @LeaVerou in #413
Precision/accuracy improvements
- Calculate more accurate inverse matrices for cat and pre-calc D50 <-> D65 by @facelessuser in #354 and #360
- Update Oklab matrices for better 64 bit conversion by @facelessuser in #357
- More accurate ICtCp matrices by @facelessuser in #365
- [spaces/prophoto] Use 64 bit-accurate conversion matrices by @svgeesus in f750d09
- Fix how small and zero precision is handled by @facelessuser in #416
Performance improvements
Bug Fixes
- Fix hue related mix issues by @facelessuser in #338
- Accept "Lightness" for lab space first channel name by @jgerigmeyer in #348
- Add CJS file to /fn entry and fix legacy builds by @jgerigmeyer in #349
- [spaces/hsl] Better handling of negative saturation on very oog colors by @svgeesus in f20d78a
- Fix
toPrecision()(was off by one for fractional inputs) by @efergus in #384 - Color serialization now defaults to percentage for lightness across all color spaces, by @LeaVerou in e36e183
- Fix incorrect parsing of Jzazbz percentage values by @lloydk in #392
- Fix Luv lightness coordinate name by @lloydk in #406
- Ensure alpha is a number in
Colorconstructor by @lloydk in #400 - Workaround Next.js production bug in
serializeby @lloydk in #421 - Allow angle values for HCT hue coordinate by @lloydk in #418
- Fix parsing of HSV color space by @lloydk in #430
- Allow number values for HWB w/b coordinates by @lloydk in #464
- Add missing CSS ids for a98rgb-linear, p3-linear, and prophoto-linear spaces for parsing and serialization by @jgerigmeyer in #439
- Consistently allow any color types (string or object) throughout the codebase by @lloydk and @jgerigmeyer in #453, #451, #456, #457, and #461
TypeScript improvements
- Space coord accessors (e.g.
color.oklch.lightness) will not produce TS errors any more. Quite a lot of effort by @jgerigmeyer to make this possible, in #389 - Fixed typedef for
steps()andmix(), by @MysteryBlokHed in #323 - Fixed type def for MixOptions by @jgerigmeyer in #347
- The fact that
toGamut()also accepts the color space as a string is now part of the TS definition by @manuelmeister in #318 - Re-export some types at the top level by @MysteryBlokHed in #327
- Added
.jsextension to file imports by @MysteryBlokHed in #333 - Added CJS type defs for node16 resolution by @jgerigmeyer in #383
- Add missing overload for
setby @MysteryBlokHed in #419 - Add JSDoc comments based on website docs by @MysteryBlokHed in #436
- Re-export some types at the top level of
/fnentrypoint by @jgerigmeyer in #466
Website
- [navigation] Fix menu z-index on the play page by @manuelmeister in #319
- Add core maintainers to website footer by @jgerigmeyer in #422
- Fix "Defined in" API links by @MysteryBlokHed in #423
Apps
- [apps/gamut-mapping] New app to experiment with different gamut mapping algorithms and quickly see how wide a gamut a color requires by @LeaVerou
- [apps/gradient] pin mavo to hotfix app by @clanghout in #359
- [apps/picker] Use correct granularity in number input rather than 1 across all color spaces (by @sidewayss in #330)
- [apps/convert] Up/down arrows to tweak color coordinates by @LeaVerou
- [apps/convert] Pin color spaces to top by @LeaVerou
Linting & Tests
- New JS-first testsuite that eliminates boilerplate and makes writing tests quick, by @LeaVerou (piloting her experimental testing framework htest.dev)
- Fix Jzazbz tests by @facelessuser in #366
- More consistent formatting across the codebase by @jgerigmeyer in #372
- Add more ESLint recommended rules, and enforce them in CI by @jgerigmeyer in #373
- Enforce trailing commas unless
]or}is on the same line by @jgerigmeyer in #440 - Port parse test to new JS testsuite by @lloydk in #427
- Add configurable
verbosesetting andwarnfunction to allow customizing logging by @jgerigmeyer in #441 - Other testing improvements by @svgeesus
New Contributors
A huge ...
v0.4.5 Fix npm dependencies
Identical to v0.4.4-patch.1, so that semver can do its thing
Fix npm dependencies
Due to an unknown cause, v0.4.4 was published on npm with an absurd number of nonexistent dependencies. Color.js still has 0 dependencies, and this release fixes this on npm.
v0.4.4
What's Changed
- Fix Rec 2100 HLG algorithm by @facelessuser in #279
- Fix "longer" hue interpolation by @facelessuser in #281
- Allow to extend the deltaE methods by @latin-1 in #280
- Revert "Allow to extend the deltaE methods" by @LeaVerou in #283
- Simplify getting coords from args by @Connormiha in #285
- Allow to extend the deltaE methods by @latin-1 in #287
- [toGamut] Ensure toGamut always returns a color object by @lloydk in #290
- Fix incorrect type definition for Range by @nsilvestri in #299
- Add a PlainColorObject type for functions that return color objects by @lloydk in #291
- Fix oklch and oklab colorspace names by @lloydk in #300
- Add verbose option to parse() by @LeaVerou in #302
- Make Color.js proxy-friendly, resolves #305 by @LeaVerou in #306
- Upgrade dependencies. by @jgerigmeyer in #308
- Use node v14 for CI. by @jgerigmeyer in #307
- Fix color temperature of D65 by @nico in #292
- [spaces] Add percentages to color functions by @jamesnw in #314
- Ensure coord meta always includes a coord name, even when the same as the key by @LeaVerou in dd129cd
- Fix regression by @LeaVerou in 4f28418
New Contributors
- @Connormiha made their first contribution in #285
- @lloydk made their first contribution in #290
- @nsilvestri made their first contribution in #299
- @nico made their first contribution in #292
- @jamesnw made their first contribution in #314
Full Changelog: v0.4.3...v0.4.4
v0.4.3: Several bugfixes and better typings
What's Changed
- Fix addSpaceAccessors hook by @latin-1 in #249
- Add missing import statement to luminance.js by @latin-1 in #255
- Fix Color constructor parameter types by @latin-1 in #252
- Fix type definition for Color#to() by @latin-1 in #254
- Fix parameter type of Color.defineFunction by @latin-1 in #251
- Add missing type definition for toGamut.returns by @latin-1 in #257
- Correct the type definitions of Color#steps() by @latin-1 in #256
- Fix missing value parameter in setLuminance by @xiegeo in #265
- Correct rec2100-hlg, #190 by @svgeesus in #271
- [types] Add
valuetosetLuminanceby @MysteryBlokHed in #272 - Fix procedural examples by @ajlende in #212
- [types] Merge
Colortypes by @MysteryBlokHed in #259
New Contributors
- @latin-1 made their first contribution in #249
- @xiegeo made their first contribution in #265
- @ajlende made their first contribution in #212
Full Changelog: v0.4.2...v0.4.3