I always thought that the semantically appropriate way to represent a rating (e.g. a star rating) is a <meter> element. They essentially convey the same type of information, the star rating is just a different presentation.
However, trying to style a <meter> element to look like a star rating is …tricky at best. Not to mention that this approach won’t even work in Shadow trees (unless you include the CSS in every single shadow tree).
So, I set out to create a proper web component for star ratings. The first conundrum was, how does this relate to a <meter> element?
When combined with some kind of interactive preview, it allows the speaker to demonstrate not only the final state of a coding snippet, but also how you get there, and what the intermediate results are. Live coding is to programming what a blackboard is to math or physics.
But it does create a unique challenge: My live coded slides don’t make sense without me. This may be acceptable for a conference talk, which is usually recorded, but not in other contexts, such as teaching a university course, where all instructors need to be able to teach all lectures, and students need to be able to quickly refer to examples shown.
Back in the fall of 2021, when we were preparing for the second iteration of our course, Design for the Web: Languages and User Interfaces, this came up as a pressing issue. The current state of the course required me to be there to teach my lectures, and this may well be the last year I teach it, since I’m finishing up my PhD soon.
I didn’t want to completely remove live coding from my slides, as I truly believe it is the perfect implementation of the “show, don’t tell” teaching adage for certain things, so I thought instead: what if I could record my live coding, and make it replayable?
Doing so manually seemed like cruel and unusual punishment. And thus, Rety was born (pronounced like the “rety” in “retype”).
While originally the plan was for me to still live code, and have the Rety functionality there for students and future instructors, I ended up using it during my own lectures as well, as I concluded that a well crafted Rety script was strictly superior to me doing the live coding:
Same progressive development as a live demo
It still affords unplanned demonstrations (e.g. to answer a question), since Rety still works with the same editors, and I could always pause it and take over if needed.
I could record myself and edit the script to maximize education value and minimize typos, delays, fumbling etc.
People can consume typed text far faster than people can type text. This is why most video tutorials speed up the typing. With Rety, typing speed is adjustable, and doesn’t need to match mine.
After test driving it for our course the entire spring 2022 semester, it went through the ultimate test in June 2022: I used it for my CSSDay conference talk. You can watch the talk here (first live demo at 7:15).
Right now Rety is just a set of two classes: Recorder and Replayer, which are used entirely independently. The exact UI is left up to the Rety user. E.g. to use it in my slides, I integrated it with the Live Demo plugin of Inspire.js (it is automatically included if a <script class="demo-script" type="application/json"> is found in a live demo slide).
The library could use more docs and some tests and I have doubts about the API, but I figured I should release it it earlier rather than later (it’s already been sitting in a repo for 7 months). After all, what best time to release it than when the first Rety talk is still making the rounds?
My vision is to ultimately evolve and standardize the Rety script format, so that it can be used to describe a coding interaction across a variety of tools. There are so many possibilities!
Wouldn’t it be cool if CodePen and similar playgrounds supported embedding a Rety script into a pen?
What if you could store Rety scripts in a repo and editors like VS Code recognized them and let you replay them?
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!
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.
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 ESM1. Since Bliss v1 was not using a modular architecture at all, this introduced some interesting challenges.
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.
For some of the statistics we are going to study for this year’s Web Almanac we may end up needing a list of CSS shorthands and their longhands. Now this is typically done by maintaining a data structure by hand or guessing based on property name structure. But I knew that if we were going to do it by hand, it’s very easy to miss a few of the less popular ones, and the naming rule where shorthands are a prefix of their longhands has failed to get standardized and now has even more exceptions than it used to. And even if we do an incredibly thorough job, next year the data structure will be inaccurate, because CSS and its implementations evolve fast. The browser knows what the shorthands are, surely we should be able to get the information from it …right? Then we could use it directly if this is a client-side library, or in the case of the Almanac, where code needs to be fast because it will run on millions of websites, paste the precomputed result into whatever script we run.
While I do have some gripes with them, it’s too late for any of these things to change, so I’m embracing the good parts and have cautiously started using them in new projects. I do quite like that I can just use import statements and dynamic import() for dependencies with URLs right from my JS, without module loaders, extra <script> tags in my HTML, or hacks with dynamic <script> tags and load events (in fact, Bliss has had a helper for this very thing that I’ve used extensively in older projects). I love that I don’t need any libraries for this, and I can use it client-side, anywhere, even in my codepens.
Once you start using ESM, you realize that most libraries out there are not written in ESM, nor do they include ESM builds. Many are still using globals, and those that target Node.js use CommonJS (CJS). What can we do in that case? Unfortunately, ES Modules are not really designed with any import (pun intended) mechanism for these syntaxes, but, there are some strategies we could employ.
Now that optional chaining is supported across the board, I decided to finally refactor Mavo to use it (yes, yes, we do provide a transpiled version as well for older browsers, settle down). This is a moment I have been waiting for a long time, as I think optional chaining is the single most substantial JS syntax improvement since arrow functions and template strings. Yes, I think it’s more significant than async/await, just because of the mere frequency of code it improves. Property access is literally everywhere.
One of my side projects these days is a color space agnostic color conversion & manipulation library, which I’m developing together with my husband, Chris Lilley (you can see a sneak peek of its docs above). He brings his color science expertise to the table, and I bring my JS & API design experience, so it’s a great match and I’m really excited about it! (if you’re serious about color and you’re building a tool or demo that would benefit from it contact me, we need as much early feedback on the API as we can get! )
For the documentation, I wanted to have the page navigation on the side (when there is enough space), right under the header when scrolled all the way to the top, but I wanted it to scroll with the page (as if it was absolutely positioned) until the header is out of view, and then stay at the top for the rest of the scrolling (as if it used fixed positioning).
Today I tried to help a friend who is a great computer scientist, but not a JS person use a JS module he found on Github. Since for the past 6 years my day job is doing usability research & teaching at MIT, I couldn’t help but cringe at the slog that this was. Lo and behold, a pile of unnecessary error conditions, cryptic errors, and lack of proper feedback. And I don’t feel I did a good job communicating the frustration he went through in the one hour or so until he gave up.