You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This has taken a while and three pre-releases, but we wanted to make sure we got everything right.
This is likely to be the last v0.x release, as Color.js is certainly mature enough to go to v1 in the next major version.
Speaking of maturity…
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.
Once there are enough sponsors, we plan to feature them prominently on our website and README, so if you want to be among the first ones to get your name in there, now’s the chance:
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 as NaN (which is invalid in CSS), it is serialized as calc(NaN) which is a valid CSS coordinate. For roundtripping to work properly, this also means we now parse calc(NaN) as well. Slippery slope? We’ll see. 😁
Programmatically detecting how none is represented
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:
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 for most cases.
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 by default. 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 parseMeta object explicitly.
You can always override this by passing format (or format: "default") for the color space default, which gives you the previous behavior.
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.
There is even a new function, ColorSpace.findFormat() to find a format that matches certain criteria across all registered color spaces.
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, which is a UX antipattern.
Starting with this release, you can now specify a lot more granular options for serialization, without having to redefine a format:
coords with an array of coord types (e.g. ["<percentage>", "<number>[0, 100]", "<angle>"]). Any undefined values 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.
alpha to 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>"}
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.
For complex types, we are still using .d.ts files with the new JSDoc @import syntax so that JSDoc is still the source of truth (by @MysteryBlokHed and @lloydk in #686).
This does not affect you, whether you are consuming Color.js via TS or JS, types should still just work. You may, however, see better inline documentation!
These are rather esoteric, but they have been used in CSS Working Group research to help figure out what gamut mapping algorithm to use natively in CSS.
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.
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: 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.
If you were referencing these from their previous URL, there is a redirect in place, but do note their tag names and API have changed.
🆕 New function: Color.try() / tryColor(): 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)
Hate seeing numbers like 0.30000000000000004? Our default number formatting now attempts to limit IEEE 754 precision issues.
parse() now clamps alpha as well, just like the Color constructor (by @LeaVerou)
Color difference
New deltas() functions for getting coordinate/alpha differences between two colors in any color space. (@LeaVerou in #532)
New DeltaE method: OK2, believed to be more perceptually uniform (by @svgeesus in #486)
Getting and setting coordinates
get()/set()/setAll() now support alpha as well (by @leaverou)
getAll() now supports an optional options parameter object with space and precision as possible keys (by @DmitrySharabin in #548)
Exports
A common need 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 spaces export of /fn and the new /spaces top-level export. (by @LeaVerou in #663, with types by @MysteryBlokHed in #668)
Functional API (colorjs.io/fn) now also available with ESM exports (by @MysteryBlokHed in #606)
New /src export to import Color.js's source code directly as ESM, when there is no suitable high-level export for what you need (by @LeaVerou in #663, with types by @MysteryBlokHed in #668)
Performance
Matrix transform performance improvements by @lloydk that make certain conversions 3x faster (#585#588)
API changes for spec compliance
Longer and undefined/same hues now have parity with CSS spec (thanks @facelessuser in #474)
Change color(ictcp ...) to ictcp(...) per CSS Color HDR (by @svgeesus in #646)
Change color(jzazbz ...) to jzazbz(...), and color(jzczhz ...) to jzczhz(...) per CSS Color HDR (by @svgeesus in #647)
Unprefix display-p3-linear since 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)
Demonstrate JND with colors 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)
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 #619)
CAM16 and HCT hues are now correctly set to null when chroma is near zero (by @facelessuser in #644)
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 the Color class (by @lloydk in #654)
Bump TypeScript to v5.5 and in type definitions, replace @typedef with @import where relevant to improve DX and overall quality of generated .d.ts files (by @MysteryBlokHed and @lloydk in #686)
For contributors
Document how to serve in development, and add --serve to watch:html (by @jamesnw in #467)
Updated colorjs.io to v0.6.0 in preview-server to pick up fixes and new color spaces. This release includes breaking changes that may affect color parsing and serialization.
Migration
Replace any uses of NaN for “none” with null.
Coordinates are now number primitives; avoid relying on Number object metadata and use color.parseMeta when needed.
Serialization preserves the parsed format; pass format explicitly if a specific output is required.
Written for commit 437372a. Summary will update on new commits.
Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.
This PR includes no changesets
When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types
Next steps: Take a moment to review the security alert
above. Review the linked package source code to understand the potential
risk. Ensure the package is not malicious before proceeding. If you're
unsure how to proceed, reach out to your security team or ask the Socket
team for help at support@socket.dev.
Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.
Mark the package as acceptable risk. To ignore this alert only
in this pull request, reply with the comment
@SocketSecurity ignore npm/safer-buffer@2.1.2. You can
also ignore all packages with @SocketSecurity ignore-all.
To ignore an alert for all future pull requests, use Socket's Dashboard to
change the triage state of this alert.
Warn
Obfuscated code: npm vite is 91.0% likely obfuscated
Next steps: Take a moment to review the security alert
above. Review the linked package source code to understand the potential
risk. Ensure the package is not malicious before proceeding. If you're
unsure how to proceed, reach out to your security team or ask the Socket
team for help at support@socket.dev.
Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.
Mark the package as acceptable risk. To ignore this alert only
in this pull request, reply with the comment
@SocketSecurity ignore npm/vite@6.4.1. You can
also ignore all packages with @SocketSecurity ignore-all.
To ignore an alert for all future pull requests, use Socket's Dashboard to
change the triage state of this alert.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
0.5.2→0.6.0Release Notes
color-js/color.js (colorjs.io)
v0.6.0Compare Source
This has taken a while and three pre-releases, but we wanted to make sure we got everything right.
This is likely to be the last v0.x release, as Color.js is certainly mature enough to go to v1 in the next major version.
Speaking of maturity…
⬇️ Over 100 million downloads! 🤯
Color.js has now been downloaded over 114 million times on npm!
The rate of increase is still accelerating, currently at 3.5 million downloads per week!
We even had to automate updating the number in our README so we could have a chance to keep up (thanks @MysteryBlokHed!).
Making Color.js sustainable
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.
Once there are enough sponsors, we plan to feature them prominently on our website and README, so if you want to be among the first ones to get your name in there, now’s the chance:
Breaking changes
There are a number of breaking changes in this release, but they should only negatively affect some pretty specialized use cases.
nullinstead ofNaNto representnonevaluesAs announced in v0.5.0, we have now switched to using
nullinstead ofNaNto representnonevalues (naturally occurring when converting achromatic colors to certain color spaces).Not only is
nullconceptually closer, but since CSS also now has aNaNvalue, this change allows us to represent it properly, using an actualNaNvalue.NaNcontinues to be parsed (and becomesNaNin JS). Instead of being serialized asNaN(which is invalid in CSS), it is serialized ascalc(NaN)which is a valid CSS coordinate. For roundtripping to work properly, this also means we now parsecalc(NaN)as well. Slippery slope? We’ll see. 😁(by @leaverou in
cdf6f0d, @facelessuser in #476, @mysteryblokhed in #530)Programmatically detecting how
noneis representedIf you are working with any code that needs to handle
Colorinstances/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 hardcodednullorNaN:Plain numbers instead of
Numberobjects for coordinatesPreviously, coordinates would be parsed into
Numberobjects 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 for most cases.Instead, parsing metadata is passed around as a separate object, and stored on
Colorinstances undercolor.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 by default. 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:
parseMetaobject explicitly.format(orformat: "default") for the color space default, which gives you the previous behavior.Other big improvements
New color spaces
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.There is even a new function,
ColorSpace.findFormat()to find a format that matches certain criteria across all registered color spaces.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, which is a UX antipattern.
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:alpha: truealpha: falsealpha: "<percentage>"alpha: {include: true, type: "<percentage>"}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.tsfiles, 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.
For complex types, we are still using
.d.tsfiles with the new JSDoc@importsyntax so that JSDoc is still the source of truth (by @MysteryBlokHed and @lloydk in #686).This does not affect you, whether you are consuming Color.js via TS or JS, types should still just work. You may, however, see better inline documentation!
Other Color.js Initiatives
Color Apps
We have also moved our Color apps (which also serve as Color.js demos) into their own repo and domain: 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:
These are rather esoteric, but they have been used in CSS Working Group research to help figure out what gamut mapping algorithm to use natively in CSS.
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.
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: 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.
If you were referencing these from their previous URL, there is a redirect in place, but do note their tag names and API have changed.
Color Elements were originally developed for our own Color Apps and the Color Palettes project, so these projects also serve as demos for them.
Other changes
API changes
Color parsing & formatting
Color.try()/tryColor(): 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)0.30000000000000004? Our default number formatting now attempts to limit IEEE 754 precision issues.parse()now clamps alpha as well, just like theColorconstructor (by @LeaVerou)Color difference
deltas()functions for getting coordinate/alpha differences between two colors in any color space. (@LeaVerou in #532)OK2, believed to be more perceptually uniform (by @svgeesus in #486)Getting and setting coordinates
get()/set()/setAll()now support alpha as well (by @leaverou)getAll()now supports an optionaloptionsparameter object withspaceandprecisionas possible keys (by @DmitrySharabin in #548)Exports
spacesexport of/fnand the new/spacestop-level export. (by @LeaVerou in #663, with types by @MysteryBlokHed in #668)colorjs.io/fn) now also available with ESM exports (by @MysteryBlokHed in #606)/srcexport to import Color.js's source code directly as ESM, when there is no suitable high-level export for what you need (by @LeaVerou in #663, with types by @MysteryBlokHed in #668)Performance
API changes for spec compliance
color(ictcp ...)toictcp(...)per CSS Color HDR (by @svgeesus in #646)color(jzazbz ...)tojzazbz(...), andcolor(jzczhz ...)tojzczhz(...)per CSS Color HDR (by @svgeesus in #647)display-p3-linearsince it is now in CSS Color 4 (i.e.color(--display-p3-linear ...)→color(display-p3-linear ...)(by @svgeesus inc90fe38). Not a breaking change, as both are still supported.rec2020; rename previous implementation as scene-referred--rec2020-oetf(by @svgeesus in #669)Docs
Website
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 #619)
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
colorSpace.isUnboundedproperty (by @lloydk in #503)setAll(),getAll(),toGamut(),deltas(), and add types for CSS color keywords (by @lloydk in #520 #544 #545 #546 #598)multiplyMatricestypes and update implementation to pass all tests (by @epsilonError in #580 #631)null(by @lloydk)darken()/lighten()functions on theColorclass (by @lloydk in #654)@typedefwith@importwhere relevant to improve DX and overall quality of generated.d.tsfiles (by @MysteryBlokHed and @lloydk in #686)For contributors
--servetowatch:html(by @jamesnw in #467)f02ce7f)New Contributors
Full Changelog: color-js/color.js@v0.5.2...v0.6.0
Configuration
📅 Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Never, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.
Summary by cubic
Updated colorjs.io to v0.6.0 in preview-server to pick up fixes and new color spaces. This release includes breaking changes that may affect color parsing and serialization.
Written for commit 437372a. Summary will update on new commits.