BCCC #3 -- Shipped Animation.overallProgress on Firefox
"BCCC" stands for "Browser Contribution/Crash Club" :)
I shipped Animation.overallProgress on Firefox 142. (intent to ship: https://groups.google.com/a/mozilla.org/g/dev-platform/c/_vMp7q8N0HE)
This was my first time implementing a new API. So I decided to leave notes about what I learned.
A (Brief) Explanation of Web Animations
For those wondering, "Is there Animation interface?", let me briefly introduce Web Animations. It's a spec created by W3C, born from the motivation to create an abstract model that can uniformly handle animation mechanisms like CSS and SVG.
CSS Transitions [CSS-TRANSITIONS-1], CSS Animations [CSS-ANIMATIONS-1], and SVG [SVG11] all provide mechanisms that generate animated content on a Web page. Although the three specifications provide many similar features, they are described in different terms. This specification proposes an abstract animation model that encompasses the common features of all three specifications. This Web Animations model is backwards-compatible with the current behavior of these specifications such that they can be defined in terms of this model without any observable change.
https://drafts.csswg.org/web-animations-1/#relationship-to-other-specifications
Web Animations has two main concepts: Timing Model and Animation Model. Simply put, Timing Model's job is to convert time into an animation's progress, while Animation Model's one is to take that progress and output a specific effect value (like a CSS property value).
At the core of the Web Animations timing model is the process that takes a local time value and converts it to an iteration progress.
https://drafts.csswg.org/web-animations-1/#animation-effect-calculations-overview
For some kinds of animation effects, the Web Animations animation model takes the iteration progress and iteration index values produced by the timing model and uses them to calculate a corresponding output.
https://drafts.csswg.org/web-animations-1/#animation-model
In addition to abstracting animations into models, it also provides a JavaScript API for manipulating animations.
The spec was released in 2013, and many articles have been written. For now, I share an article by the spec editor, Brian Birtles. His presentation on the challenges of animation basic functions is also interesting, so please watch it if you're interested :)
Web Animations API has several parts such as Element.animate and Animation.commitStyles. Here's a code example. If you run it in your console, a black square will appear at the bottom of the page and rotate. It's really cool that you can manipulate animations just with JS, and it can be very useful in certain situations!
const div = document.createElement("div");
div.style = `
height: 100px;
width:100px;
background-color:black;
color:white;
`;
document.body.appendChild(div);
const anim = div.animate(
[{ transform: "rotate(0)" }, { transform: "rotate(360deg)" }],
{
duration: 10000,
iterations: 1,
},
);
if ("overallProgress" in Animation.prototype) {
setInterval(() => {
div.innerText = `${Math.round(anim.overallProgress * 1000) / 10}%`;
}, 100);
}
The black square rotates slowly. If your environment supports overallProgress, the progress will be displayed, too.
I included overallProgress, which I implemented, in the code above. overallProgress works in Blink or Gecko preview, but it will probably take the other path otherwise. It might work in a WebKit preview.
As the name suggests, overallProgress returns the progress of the animation. It was originally named progress, but the name was changed. This is because it conflicted with another name. If you're interested, check out the discussion from the comment below 👀
So, How Was the Implementation?
WebIDL is Convenient
To implement overallProgress, my first thought was to write the interface in the area where animation-related APIs are gathered (dom/animation/Animation.cpp).
But then I paused for a moment. Do I need to modify the JS engine as well? That's when I remembered WebIDL. Let's look at the Firefox documentation.
The first page seems to have more concrete steps. This time, since I'm adding an API to the Animation interface, it seems I have to define the interface in a file called dom/webidl/Animation.webidl and build Firefox normally, and the glue code will be automatically generated! Convenient.
The problem is how to define the interface. There's a lot written there, and it looks complicated. But this time, all I had to do was copy and paste the spec's IDL, i.e., readonly attribute double? overallProgress;. This is quite amazing. It's packed with the benefits of being refined already on the spec stage.
By the way, a detailed explanation of IDL is also available and maintained on MDN. MDN is always amazing...!
Implementation was Smooth Thanks to the Spec
The implementation load for overallProgress was not so high. The spec was completed a year ago. Also it was already implemented in Blink and so WPT cases already existed. The spec's content is also quite simple and it could be implemented by carefully combining parts already implemented in Gecko.
BCD is Auto-Updated
When you create a new API, you need to update Browser Compat Data (BCD). BCD is feature support data for each browser. For example, it's the source for the browser compatibility table at the bottom of MDN pages :)
BCD data is well-structured. The explanation is around here. api.md explains the data for API compatibility, but it's so clear you can probably understand it just by looking at the data without reading this md. Here's the relatively short JSON for CSSImageValue.
{
"api": {
"CSSImageValue": {
"__compat": {
"mdn_url": "https://developer.mozilla.org/docs/Web/API/CSSImageValue",
"spec_url": "https://drafts.css-houdini.org/css-typed-om/#imagevalue-objects",
"tags": [
"web-features:css-typed-om"
],
"support": {
"chrome": {
"version_added": "66"
},
"chrome_android": "mirror",
"edge": "mirror",
"firefox": {
"version_added": false,
"impl_url": "https://bugzil.la/1278697"
},
"firefox_android": "mirror",
"oculus": "mirror",
"opera": "mirror",
"opera_android": "mirror",
"safari": {
"version_added": "16.4"
},
"safari_ios": "mirror",
"samsunginternet_android": "mirror",
"webview_android": "mirror",
"webview_ios": "mirror"
},
"status": {
"experimental": false,
"standard_track": true,
"deprecated": false
}
}
}
}
}
When I updated the BCD this time, overallProgress was still in Nightly. So the value for version_added was set to preview. That's why it's now displayed as "Nightly" on MDN.
The interesting part is that BCD data is updated automatically (not all). Some APIs in BCD are automatically tested by a tool called "mdn-bcd-collector", and the results are reflected automatically. This is awesome!
The official overview page for "mdn-bcd-collector" is well-written.
Let's just look at the test page. Below is the page for overallProgress. You can access it on your smartphone or PC with any browser and test it with a single push. Please try pressing "Run Tests"!
When Will It Be Released?
Now that it's implemented, I'm excitedly waiting for the release. Firefox adopts release train, and anyone can see the schedule here. I always feel the domain name is very straightforward :)
I merged overallProgress on June 24th. As you can see from the page above, this falls right between the "Nightly starts" and "Soft code freeze" for version 142. Therefore, it will be released in version 142. By the way, Nightly reflects what's merged almost immediately!
Summary
So, overallProgress will be available on Firefox 142. The beta will be released tomorrow :)
Actually, the most troublesome part of this implementation was a test bug caused by Firefox's fingerprinting prevention mechanism (RFP, resistFingerPrinting). I'll write about it again once things have settled down :)