Open drwpow opened 8 months ago
Sounds great, really looking forward to this! :)
Had a bit of a breakthrough this week in what’s probably the most exciting development since this library started: token linting. As a PoC I’ve shipped an a11y plugin that can perform contrast checks on your tokens automatically (WCAG 2 and APCA). And under-the-hood is a whole new linting setup that lets Cobalt plugins register linters that users can configure their own rules on, similar to ESLint.
This is huge because Figma plugins exist, but are manual. And designers shouldn’t perform QA (nor does the “source of truth” usually exist in Figma anyway). a11y tests also exist of course, but are often very slow and expensive because without a token pipeline you have to run full E2E tests with browsers (and still miss some things). But with token linting, the tests are fast, cheap, accurate, and surface in the part of the chain where they can be fixed: design ops. See the RFC for more info and to give feedback!
I’m excited for all the possibilities this opens, especially with the new improvements coming in 2.0. And would love to hear ideas for other linting checks we could add to test the concept further!
And would love to hear ideas for other linting checks we could add to test the concept further!
not related to a11y but it would be nice to check if there are no duplicate token names, e.g.:
"blue": {
"0": { "$value": "#ddf4ff" },
"1": { "$value": "#b6e3ff" },
"2": { "$value": "#80ccff" },
"3": { "$value": "#54aeff" },
"4": { "$value": "#218bff" }, // <--
"4": { "$value": "#0969da" }, // <--
"5": { "$value": "#0969da" },
"6": { "$value": "#0550ae" },
"7": { "$value": "#033d8b" },
"8": { "$value": "#0a3069" },
"9": { "$value": "#002155" }
}
now last value wins. maybe this could be even checked in compile time. IDEs usually flag these duplicate properties but this could happen by other means like wrong git conflict resolution.
also, just a thought, maybe checking duplicate token values within the same group would also be helpful:
"blue": {
"0": { "$value": "#ddf4ff" },
"1": { "$value": "#b6e3ff" },
"2": { "$value": "#80ccff" },
"3": { "$value": "#54aeff" },
"4": { "$value": "#218bff" }, // <--
"5": { "$value": "#218bff" }, // <--
"6": { "$value": "#0550ae" },
"7": { "$value": "#033d8b" },
"8": { "$value": "#0a3069" },
"9": { "$value": "#002155" }
}
Yes @dzonatan that’s exactly what I’m talking about! Duplicate values could be done today. Duplicate keys (IDs) would have to wait for 2.0 as that requires AST awareness (parser rebuild). But both are good examples of “core” lint rules that I think should just work out-of-the-box (maybe the lint rules are opt-in, but no plugins to install)
@dzonatan Thanks to your suggestion, I just shipped the duplicate-values
lint rule (along with some others) that lets you catch duplicate values anywhere in your tokens.json file. Please give it a try and let me know if you encounter any errors 🙏
duplicate keys turned out to be pretty tricky! Because the JSON spec does allow for duplicate keys (it just takes the last one silently), fixing that requires a implementing a custom JSON parser so that may take a while 😅
Figured I’d let the cat out of the bag with future plans for this library in the 2.0 release. I won’t give all the details here, but just some high points:
Cobalt was always a placeholder name. I was always more focused on the actual tooling for DTCG, and never felt truly attached to the name. “Cobalt” is a common name that competes with many things, both in programming/design and beyond. I never felt it captured the nature of tokens: these little beautiful, colorful things that come together to form this wonderfully-intricate and unique pattern…
…kinda like terrazzo!
The name also highlights an expansion in the maintainers. For a while now, Cobalt has been a solo side-project. But this year I’ve roped in a good friend and incredibly-talented designer, @ntassone, to make this 100× better than it ever would be with just myself. Together, we’ve realized a lot of pieces were missing in the story of design tokens:
So all that considered, we wanted a bigger, better Terrazzo namespace to contain all these ideas and experiments we’ve been working on for a while behind-the-scenes. And also open the doors to more people getting involved.
No. It’s still an 100% open-source project @ntassone and I are working on in our free time. It’d be neat to find a way to get more funding for this somehow! But only time will tell.
Nope! Cobalt v2 == Terrazzo CLI v1. 100% of Cobalt’s direction, vision, and philosophy won’t change. Terrazzo will just be a project that’s a suite of token tools in addition to just a CLI.
The Terrazzo nameswap was something we had been planning before even announcing 2.0. But @ntassone and I had been mulling over what the actual scope was until pretty recently, and how Terrazzo related to Cobalt. After deciding on a scope, and deciding Terrazzo was the same as Cobalt, we knew the actual swapover would be a little clumsy, and there wouldn’t be some seamless overnight launch. Over the next few months, you’ll start seeing the name “Terrazzo” here and there in the project. And one (undisclosed) day in the future, this repo will suddenly move to the Terrazzo GitHub org. And we wanted people to know it’s not changing hands (just adding some!).
I actually don’t even like talking about things before I do them; doing is more fun! But the people reading this thread would start to notice the changes before anyone else, so this seems like the most effective way to announce it 🙂.
And as always, always open to any questions people have! 🙇
Lil sneak peak: the beta version is a little further away than planned (hoping to get a version published in a couple weeks, but we’ll see), but here’s a sneak peak: full AST support for tokens.json! 😎
It’s not just showing the specific line that erred in feedback (though it does enable that). It also exposes the JSON AST to plugins as well so you’ll have access to the original tokens.json
file as-authored (if you need it).
This will also enable line-specific lint messages as well! Excited for this update!
Lil update: the 2.0 version is very, very alpha, but those interested can take a look at the new 2.0 docs here regarding the plugin changes: https://terrazzo.app. Design credit for branding and docs styling goes to @ntassone; I couldn’t have done this without him!
You can also kick the tires on @terrazzo/cli
and @terrazzo/plugin-css
which are available on npm. Work the same way, but with a terrazzo.config.js
file instead of tokens.config.js
.
With the core rewrite mostly done, hoping to have the rest of the plugins upgraded to 2.0 in the next month, finish styling / writing docs, and hopefully we’ll have some release candidates ready in the coming weeks.
And as always, feedback is always welcome! (particularly about the plugin API enhancements)
Planning for Cobalt 2.0 is underway!
Many wonderful people have put Cobalt through the ringer. While I’ve gotten lots of confirmation Cobalt is on the right track working with DTCG tokens, there’s still more needed from it. So to address that, I’ve started planning for the next major update that will meet users’ growing demands, but will require some breaking changes to do so. As of right now, the high points include:
Major changes
Plugin chaining. Right now plugins are completely isolated from one another (except for CSS + Sass, which still have lots of rough edges, and whose current interop isn’t a pattern that should be repeated). This has been workable with official plugins, but imposes restrictions on how custom plugins are made.
I’m currently working on a draft for the Plugin 2.0 syntax, which is basically “the same, but more.” It will give plugins (many) more hooks than just the one
build()
hook so they can work off one another, and you can transform tokens in multiple passes before preparing them for an output format. And while it’s still a little early for feedback, I’ll open up RFCs in the coming weeks when I’ve proven the changes will simplify current plugins and allow for more complex chaining and better sharing of logic between plugins. The API will still be primarily Rollup/Vite plugin-inspired, but will introduce new concepts where it makes sense (since tokens are fundamentally different than web bundlers). Ideally, this means if you have a custom plugin for 1.x, migrating to 2.x won’t be too bad. But internally, the execution of plugins will differ quite a bit and unlock some pretty cool potential.tokens.json
because it doesn’t keep track of the line it’s on. Likewise for YAML and JSON parsing errors. 2.0 will run error-checking earlier in the parse phase, where it can helpfully print out the correct line in case of a syntax (or schema) error.Minor changes
Building moved to core. Currently the
@cobalt-ui/core
package isn’t very useful; it can only validate & normalize the schema but can’t do any meaningful work with the plugins. It wasn’t an intentional design decision to keep most of the building within the CLI package; it was just expedient to do so originally. Moving it to core unblocks people who want to run post-build actions in Node.js without having to read/write from disk (which means it could even be used in APIs, and in the browser).Parsed Tokens object instead of an array. If you’ve built your own plugin in 1.0, you’d know that
tokens.json
is passed in as a flat array. This will be changed to be a shallow object (with.
in keys).The original assumption was “since plugins will always be iterating over all tokens anyway, let’s make it simpler,” but that has proven false over time. There are many times when plugins need to grab individual tokens, and
tokens.find(…)
is not only verbose but slow (comparatively). Objects are closer to the originaltokens.json
, which makes things simpler to work with. The parsed tokens object will still be shallow, because it is still more time-consuming/more complex to do deep AST traversal than running over a loop once.Getting rid of internal weirdness. There are artifacts internally like
metadata
which don’t have clear purpose other than “IDK here’s some junk we may need later maybe” (spoiler alert: we didn’t).Staying the same (no changes)
(Still) independent of Style Dictionary. Since Cobalt’s release, Style Dictionary has announced an exciting new v4 with support for DTCG, which I’m looking forward to! Style Dictionary was foundational for so much advancement of design tokens (even DTCG) and I’m excited to see that project continue.
As a project, Cobalt isn’t seeking to be a 1:1 replacement for SD. Cobalt seeks to provide tooling for the DTCG, and also explore working with design tokens with a plugin-centric API rather than a looser, config-heavy “Gulp-like” one. Ultimately it’s about giving developers more options in tooling to meet different needs, and I love when Style Dictionary works and works well for people. So all that said, Cobalt as a project will continue to explore an API that allows for easy, zero-config usage, but without restricting powerful customizations. Independently of what Style Dictionary is doing. And I hope that both Cobalt and Style Dictionary continue to both grow and develop, and continue to meet developers’ differing needs well!
Note: this is a living document; expect edits (and even some decision reversals) as plans develop and mature.
Release date: Late 2024, with RFCs coming Mar/Apr
To recap, this is mostly a placeholder announcement to check back in at a future date for RFCs and testable beta versions of Cobalt 2.0. While a stable version won’t release before DTCG 1.0 is closer, look out for both RFCs and testable beta versions very soon (in the coming weeks).
So all that to say, is there anything you’d like to see in Cobalt 2.0? At this early stage, any and all ideas are welcome (keeping in mind a Plugin 2.0 API will get an RFC soon)! Is there more Cobalt could do out-of-the-box? Any work that could be moved out of your plugin? Any additional integrations you’d like to see? Leave a comment!
Thanks for reading 🙏