 So, Jake? Hello! Let me get comfortable. Your last one was an hour long. Let me get comfortable first. This one's going to be shorter. Yeah? Don't. Famous last words. What? What? What? What's it? What? Scrolling animations. Yes, please. Warning. Experimental CTS feature ahead because this is not supported in any browser at this very moment. Great. Okay. Yeah. So you're just making up a lot of stuff, really. The spec exists. The spec exists. Okay. It's undergoing a rewrite, but the spec exists and the information is there, but it's not available in any browser. Currently, spec fiction right now. But that's okay that my... Leading towards reality more. Leading towards reality? That's what we should have called this episode. I like it. I don't see this as like experimental features. Very exciting CSS feature ahead and that's why I'm talking about it because I think this is an amazing addition to CSS. Look, people have been wanting this for ages, right? Yeah. And we've had sort of hacky ways of doing it with like 3D transforms and with perspective hacks and stuff. Well, people just want the avatar to go into the corner and stay there or whatever. Like people have been wanting this for years and years now. For people who don't know what scrolling animations are, this is an example here and this is only CSS. What? That's cool. So this is CSS animations running, 3D transforms running, scroll snapping as well. And then we have the scrolling animations part where the cards, they move as you scroll around it. That's very nice. I like it. Yeah. I like it too. Why is it so exciting? Well, these are hardware accelerated animations. Link to scroll, it's running off the main track. So it's not blocking anything and you don't need any JavaScript. Right. And that's the problem we have with the current solutions people are using, right? Because they listen to the... The only way you can do it really is listen for the scroll event and then change stuff on the page. Or use an intersection observer as well. Yes. But you need JavaScript and it will be blocking by default. Which means in a lot of cases the effect is going to be running slower than real scrolling and you end up with that disconnect and it doesn't quite work properly. Or it stutters a little bit and you're like... Exactly. But this works, right? This will work. Of course, yes. We're thinking in the future it will work. Hopefully soon, more on that later. What's also included by the way is a JavaScript extension to the Web Animations API to achieve the same thing. Good. So if you've written all your animations using the Web Animations API you can also apply these effects using some new JavaScript stuff that you add there to your existing code. Show me how. I wish to know how. One disclaimer though. People who have been following me on Twitter or whatever and they might have read this article. It's from February 2021. Not that old? Not that old. Well, this was about an older version of the spec which is an entirely different syntax. When it comes to experimental web features, a year and a bit may as well be 100 years. So the information there, if you've read it before I would say the concepts still hold true but follow along because we're going to cover a new syntax in this episode right here. Excellent. Cool. But first I need to explain what is a scroll linked and what is a scroll triggered animation because there's a difference between both. Scrolling to animations is one like this where you see the red line at the top. It's like a progress bar as you scroll. So if I move up and down. Yes. So essentially the scroll bar becomes the scrubber for the, like if it was a video, like you're scrubbing the timeline of the video with the scroll bar. So if you scroll, it moves along. If you stop scrolling it will pause there. If you continue scrolling again. So there's this direct connection as you scroll, the animation goes, it goes back and forth. This is a scroll linked animation. This in contrast to this, which is a scroll triggered animation. Right. And this is what people are using intersection observer for right now. Whereas the other one I guess is the scroll event. If you're doing things frame, trying to do things as close to as frame by frame as possible. Whereas this intersection observer is good enough. So these scroll triggered animations, they run once a certain point has reached and then animation runs and you can't stop it. It's gone, it's fired. It's starting. So there's a difference here at home to be clear. This back is about scrolling animations. A future addition might be scroll triggered animations, but it's not covered yet. Well, and I think it mostly your scroll triggered stuff. Like the intersection observer is kind of good enough. Right. Okay. Yes. You might want to wait to do it without JavaScript and that would be advantage. That would be nice. But performance wise, the intersection observer is going to get you there. Whereas with the other thing, we don't have a good performance way of doing that right now. True. Let's look at the basic example. Let's do it. Bar, progress bar at the top. Yeah. So I'll visualize it here. With CSS, we would create an element there and position it there using this little snippet. I'm using position fixed here. Top left and right set to zero height and then the background so that we can see it right there. Yep. To animate it, say you want to animate it. What you're basically, what you basically want to do is you want to have it at like scale X zero and then stretch it out to scale X one so that it stretches out. And the reason you do scale there rather than width is to keep it all off the main thread. I guess. Yes. The key frames will look like this. Scale X from zero to one. We apply the thing on there. We add a default transform so that we don't get like the flash upon start content. Yeah. And then we attach the animation forward so that when your animation is done, it stays in that position. And if you load up our document, it runs and it stops. Amazing. Yep. So it's not linked to scroll right now. This is because this animation runs at document timeline. Right. And I've seen this at document dot timeline. I believe it's an API that reflects this. I'm not aware of that. Could be making it up. This is the part where you take over the episode. So I will ever put an apology or a link in the description whether I'm right or wrong. I do think we have a JavaScript representation of the document timeline. Could be very well. Maybe, maybe, maybe. Right. Sorry. The concept of the document timeline is when you load up a page, the document timeline starts at zero and every time a second passes by, that's a second. Everyone who's used performance dot now, it's on the same timeline. And therefore, if you use request animation frame and you get passed in, that is also your document timeline number as well, which date dot now is different to because date dot now started at 1970, whereas yes, this is document lifetime. So that means if we load up our page, our animation runs. If we refresh the page, it will run again right because it started at zero again. Yeah. What we do want to achieve here though is that we want to link this animation to our page scrolling. So we don't need a document timeline, but we need a different type of timeline. How would you call it? Is it going to be a scroll timeline? Yes, it's going to be a scroll timeline. The full name is a scroll progress timeline. Yeah, okay. We just call it a scroll timeline. So a scroll progress timeline. This timeline is linked to the progress of the scroll position along a particular axis. An axis being you can scroll vertically or you can scroll horizontally in line and block in logical values if you want to. To make sense. And these start at 0% when you're at the very top. So if you load your page at the very top, you're at 0%. If you scroll all the way to the bottom, you're at 100% progress. And it's progress because there's still stuff in the viewport. So it's not going from 0% of the content height to 100 because when you're at the bottom, you've still got the amount of content. So it's really tracking the progress of your scroll bar. In terms of percentages, I mean, in CSS terms it works more like background position than left. Because left would move out of view. Out of view. Exactly. Cool. We can do it like this in CSS. This is good. We have our existing animation. So that code is still there. We have an extra property animation dash timeline. And we have a scroll function. We can give it an axis and a scroller. And you can see the question marks there. That means they are optional. OK. So I mean the default for scroller will be the root scroller. I guess the default for the axis though, I guess why? It's common. Is that? Yeah. Almost correct. Almost correct. OK. So that's the axis parameter. That's the axis of the scrolling. So you have block or inline, vertical or horizontal. The default is the block direction. OK. Because by default, if your page, the content grows too large, you will scroll vertically in the block direction. So that's why that's the default. Yeah. Cool. Yeah, that makes sense. And then the scroller, that one is used to target the scroll container whose scroll progress you want to follow. We have got two keywords for that. Nearest or root. Uh-huh. Nearest is that it will look up to the dump you to all of its parents and say which one scrolls here. Yep. And then root will target the root scroller, which is the HTML. So this is the bit I got wrong. This is like, because I guessed roots. But so how does it determine what a scroll container is? So overflow hidden. Is that a scroll container? This is the part where it gets technical. Yeah. There is a difference if you do overflow clip, overflow hidden, overflow scroll, and some of them create a scroller. Yeah, the ambiguous ones in my head. Overflow clip is not a scroll container. Overflow scroll is a scroll container. Yeah. The ambiguous ones for me are overflow auto and overflow hidden. Like whether, because like overflow auto will sometimes behave like overflow hidden or overflow scroll depending on the size of the content. So does that switch depending on the amount of content or does it? And then, you know, therefore it's hidden. We can put detail in the description for that. If I'm not mistaken, hidden will create a scroll container. You can't scroll it using your mouse, but you can scroll it through JavaScript. Yes, you can. So that suggests that it will be because you can't do that overflow clip. All right. Yep. That sounds like a good answer to me. So for our progress bar, you would use this, right? You have our elementary animation timeline, scroll the block direction nearest because it is direct child of the body. So it will look up to the HTML element. Block root would also have worked in this very case. So in this case, you could miss both of those out because those two are the defaults, right? So you could just do. Next slide. Yes. Because they are default. And that way you have a scrolling animation in CSS. Wait. That's brilliant. That's it. That's amazing. I like it as well. It's cool, right? Yeah. That's really simple. I guess the next questions are like the avatar animation that slides into the corner and stays there. So that's where things like, I guess, boundaries and things come in. Yeah. So what we have tracked here are anonymous scroll containers that we are tracking. We can also use named ones. I'll cover it on the next few slides. First, I'll show JavaScript part because I mentioned we also have a JavaScript implementation, right? Yeah. So using JavaScript, we have an extension to the Web Animations API. What we have there is a scroll timeline interface. You can create a new instance of it and you can add some options to it and configure it. What would the options be? Well, it's probably the same as we had before, right? Exactly. Exactly. We have the access block inline vertical or horizontal, which are strings here in this case, not keywords. Makes sense. And then we have a source which takes any element as its value. So that's the result of document.querySelector or something else that you could pass. So here I've been very explicit. I set the source to document or document element. The root scroll. And then we have our scroll timeline instance. That's really nice. Excellent. Without a scroll timeline, this would be our code. So we have our progress bar. We change the transform origin to start from the left. And then we animate it, scale X, and then the fill forward duration one second. So we need to change that duration part and instead inject our timeline so that it doesn't run on document timeline but on scroll timeline. OK. So no duration. And it's a different option, is it, I guess? Yeah. It's simply called timeline. And you pass an instance like this. That's really nice. It's nice as well because I'm starting to think of other kinds of timelines that could go in there. So it's like timelines at different frame rates. I know that's something that's been spoken about before. Yeah. This is great. I like it. Why haven't we shipped this yet? I like it. As I've said, we were tracking anonymous scroll progress timelines. You can also track named scroll progress timelines. You can also track these. Let me start off with an example. We have a carousel here with an image inside and a progress bar for only that carousel. Oh, OK. So if I swipe on the carousel, the next image comes into view and our progress bar advances. So now it's at two thirds because I have three images in there. If I swipe again, the progress bar... Very good. If I swipe back... This happens. I presume at the start of that it had already been scrolled which is why we could see some of the red to begin with. The start was at scroll position zero because we have three panels. We have three images next to each other. So when you're at the first image, you're at 33% of the things that can be visible. So why didn't that happen with your root scroll? Or maybe it did and I just didn't realize. So when you had the red thing going across the top of the page, that seemed to start at zero. That's because I built it that way to say like, hey, you're at the top. So I was tracking the top position in the way I built the animation. Yes. Here I was tracking which panel are you viewing. So I was watching panel one of three. So I had built my animation here this way to be at 33% already. Oh, I get it. I get it. Oh, OK. So if you did the same code as before, it would start at this, the start like zero scale and go to a hundred like when you're in the first panel. Right. I get it. OK. So here it starts at scale X zero dot three, three, three, three. Perfect. Right. I'm back in. I understand. This is the marker that I have for that. So I have a gallery which is a wrapping element and I have the scroll container with all three entries and then I have the progress bar. The problem is if I use the scroll function here, it will only look up to the nearest scroller which looks up to all parent elements or the root one. But the scroll container is a sibling of it. Oh. So we're kind of having a problem here. What we can do here is we want to have it track the scroll container instead of looking up. In JavaScript this is easy because our scroll timeline code, we can pass in a source and it can be any element. So we can use document or query selector again. So on the second line there, we select the scroll container and we pass it in as the source for the scroll timeline later on. Easy peasy. And that way it will work even though, so we are looking at the scroll position of one element but we are animating another element elsewhere. And there's the bit where you're with the scale X. That makes more sense to me now. Yeah. Because you have that bit where it starts. I think that was deliberate. Cool, cool, cool. And in JavaScript this is really easy. But in CSS our scroll function will cut it here right. And so we need something else. I guess it gets referenced by ID. No. No, no, no. Don't like being wrong. That used to be the case before we had a selector function where you pass the selector. I'm a big fan of it but the CSS working group is not. No. But we have a different way to target them. We can add a name to a certain scroller and then reference it by its name. Okay, yeah that works. This is where these named scroll progress timelines come into play and this is the code. So on our scroll container we set the scroll timeline name. We give it a name, gallery. You can also define the axis by default block but here we wanted to scroll inline. We can use the short hand if we want which is scroll dash timeline axis and the name. Nice. And then later on in our code we reference that gallery using the animation dash timeline property. Right. So instead of scroll we now use the name. Probably a spec question but if you have two scroll things of the same ID just pick the first one or what. That's a good question Jake. Thank you. I will cover it later on in the presentation. Oh I love it. Great. So this is the CSS code and that's why this works. We've already seen it. This now works. Yeah. I've cheated here to be honest because of the question you just asked. This works because my HTML is structured like this. If my HTML would be structured like this it would not work. Oh so you're telling me the way the algorithm for finding nearest goes up through the siblings and then out. Not the algorithm for finding nearest. The algorithm for finding the name scroll progress timeline. I get it now. And that one only looks at preceding siblings so all elements before it and then the parent. That's fun. Then again all preceding ones. Do you know what like so typically in the past when in CSS you've had to refer to another element it's been by ID and you mentioned before that there might have been some selective way of doing it but I guess like I actually sort of like the system where you end up specifying a name in the CSS and then referencing that name somewhere else because it means that you can change which element has that name with media queries which you can't do with an ID which you can't do with a selector. You would have to change the ID you were pointing to or the selector you were using but whereas a lot of times it's just like I just want to change this element. You just attach the name label to a different element. Yeah we did this with shared element transitions and that's why we didn't use ID for a selector. I guess a very similar system. Cool. So that was kind of a cheat there. Be wary of it. You can't reference name scroll progress timelines down the dump tree. That's fine. It was sort of convenient that it was afterwards anyway due to the Z-indexing, right? It's convenient for that thing to appear afterwards. Yeah fair play. So timeline search looks at proceeding siblings and ancestors recursively. Yep. Nice. That way. Scroll progress with timeline offsets. Right. This is something else. Let me just show you what it would look like. Say we have a cover page. Very good. Nice gradient. I know you like gradients. Yeah, better than the gradient I used in my last episode. If I scroll down, this cover page will transition into a fixed header like this. And the content. Nice. Will move. All right. Yes. How would you build this animation? Yeah. I mean... Or how would you build the scroll progress time? That's... Yeah, so you kind of want to... There's a stop point. We're kind of saying where this animation should stop. Like either a scroll offset or something. That's all I've got. Yeah, that's it. Oh, nice. So our keyframes would look like this. We have our cover card which starts at 100 dvh. And then in the end position we want the height to shrink. We also adjust the font size a little bit. And then we give the body a padding top because we used position fixed. And otherwise the content would shoot underneath it. So we pull the content back down. Of course. So this would be the keyframes. Our scroll progress time and that you want to build would be... You know what? Animate the cover card as we scroll the root scroller from 0 to 90 dvh. Oh, nice. I see. So you're kind of setting the boundaries for the... Yeah. Yeah. Like this would be, I guess, in animation terms of the duration. But in this case the duration is a length. Well... Yeah. Yeah. What CSS calls it? It's set up from 0 to 100%. You're using an actual pixel value somewhere. Yeah. Yeah. So rather than saying this animation is one second long, it is 90 dvh is long. Yeah. Okay. I get it. This doesn't work. Oh, mate. I was starting to enjoy that. Sorry. And that makes me sad to be honest. I know I'm sad now. Yeah. Well, because this used to be in the spec. This was in the previous iteration of the spec. Who thought is it? Give me the net. No, don't give me the net. And it's gone now. Because I would love to see something like this where I can say, hey, you know what? Run this animation, scroll nearest block, and then over a distance from 0 to 90 dvh. Yeah. Or maybe another syntax, animation time and offsets, where you say, hey, you know what? I guess the difficulty here is like, if we're saying that timelines could be used for other kinds of timelines, not just scroll timelines, then this stuff starts not, well, this version doesn't make sense. Your other syntax did because it was specific for scrolling. Yeah. Oh, go on. Tell me, why are we doing this? It just got dropped out of the spec with a bunch of rewrites. A lot of people have worked on it. All editors have changed over time, whatnot. So that's why it fell off the wagon somehow. I've created an issue for it within the working group. Yeah. Bring back scroll offsets. Yeah. Hang on. There isn't actually an alternative. It's just gone. Not right now. It just fell off the wagon somehow during the rewrites. Yeah. We need that back. Yeah. That's my opinion too. So that's why I created this issue. And we are discussing it. So hopefully we'll be back in so that we can ship a version of this specification. I do wonder if this maps to animation durations and delays. Like right now your animation duration and delay can only be time. Yeah. But what we're talking about here is them being less. That would also affect that. Yeah. Your animation duration would be over a certain scrolling distance instead of a certain time. Because I guess right now if you are like it needs scrolling animations, duration doesn't mean anything. If your animation is 10 seconds or 10 years long, it doesn't matter because it gets remapped too. Yeah. It simply gets ignored because you've attached a different time line. Right. That's what I'm going to go on to that issue and propose. Like what if we changed, yeah, duration to accept. Lengths. There we go. That's it. And the default would be, you know, it matches the length of the scroll. Yeah. There you go. Solve. Something to do after the animation. Something to do after the episode. Okay. Yeah. Cool. Another part of the specification is the ability to track an element as it enters or exits the scroll port. This is the intersection observer. Intersection observer. Exactly. All right. So here I have an example. If I scroll on the page, take a very good look at the bottom. An element will appear there and it will animate. So I'm here now and then as it enters, it animates. And that wasn't scrolling. That was just because it appeared in the viewport. The animation. It is scrolling. It is linked to the scroller. That is scrolling. But it's not running from zero to 100%. It is looking at the enter face of that element. So if you stopped that scrolling, would the animation stop halfway through? Yeah. Oh, so it is scrolling. Let me run the animation again for you. Here we go. So here. This is not quite like the intersection one. It's not like a trigger. This sounds like it's got the offset thing that we wanted. For certain phases, yes, but you are not looking at... Yeah, you are looking at a certain element. That's the main idea here. You're looking at that element and not a general offset. I see. Okay. For this, we don't need a scroll progress timeline. We've got other concepts because it wouldn't cut it. We've got a view progress timeline. Oh, I see. View progress timelines are segments of a scroll progress timeline. We have our scope to the scroll position. And then it looks at a certain element. So the segments part, that's the interesting one because we can target four segments. The first segment is enter. So if an element enters during that time, you can run a certain animation. Like we just saw it was like expanding. That was the animation was running during the enter stage. You also have another segment or stage or a face. The name, mic shedding, it's very hard. Exit is another one as it exits the scroll port. So yeah, we're presuming that enter means from the bottom and exit means to the top. And if you're going horizontally, it would enter from the right-hand side and leave at the left-hand side. So question. It is possible for an element to be both entering and exiting if it is bigger than the view port? No, we will cut it. If it is bigger, then only as a top part is entering from the bottom. Once it hits the top part of the layout view port, that will be the enter phase. And then when the bottom part hits the bottom of the layout view port and leaves at the top edge, that's the exit to the face. I see. Okay, so it can be considered fully entered. Or it can be in neither the enter or the exit phase while there are parts of it still outside the view port. No. Hang on. What's going on? So if the element is half off the page. Okay, I see. Okay, so it starts exiting. So if it's larger, it starts entering when the top edge of the element is at the bottom edge of the layout view port. I see. No, so I think I'm right still. Once the element is bigger than the view port, while it's in the middle, it's neither exiting or entering even though parts of it are off-screen in either way. We call that phase. Yay! Well, we call it contain, not cover. We've got for. So we've got enter, exit, then cover is when it's outside to outside again. So that is cover. So let's do the full thing. But then contain is when it is contained within the boundaries of the layout view port. I see. So what you just mentioned is that it would go from enter to contain and then exit. Gotcha. And cover spans from enter to exit. I now understand. Right. So these are the four segments that we can target. Yeah. I get it now. Yeah. So in JavaScript, we had scroll time line interface. So we obviously have a few time line interface. It takes some parameters as well. Again, the axis and again, a subject. I've got two images here. So two revealing images. I wrapped them in a container because I want to look at the container as it enters. And then I want to animate the image contain inside it. We start off with this JavaScript. We query selector all containers. And then for each container, we check the image inside of there. And we need to animate the image. The animation using the web animations API would look like this. Where the clip all reclip it from the center, then it becomes visible. And we also do the opacity. But do note, we do image dot animate. The subject is set to the revealing image container itself. So it is different, isn't it? Because this time, you're pointing at the element that is coming into the viewport rather than the element which is doing the scrolling. Yeah. Which I guess it makes sense that those are called different things because they are different behaviors, right? Now you might be wondering, okay, we have the few time line there. How do we target the enter phase? Because this is specified in here somewhere. So that's an extra property where we say time range, enter. Interesting. So why is that not in the view time line options and that's in the animation options? This will become clear when I show you the CSS example. Ah, I see. But the goal is to reuse one view time line which you can then use to target each and every single segment of it. I see. So you don't need to create new instances. That makes sense. In CSS, instead of scroll time line, you have view dash time line, again the name and the axis or the shorhen if we want. And then onto our image again, we set the animation dash time line to revealing image and that way it will work. Nice. But I haven't shown you the key frames, right? Yeah. Key frames would look like this. Oh, I see. So instead of just having from or to or percentages in there, you are adding the segment that you want to target. So you essentially be creating one animation but you create the bounds for enter and exit, cover and contain with these labels. Yeah. I see. You can also add the accident there. You can also add the cover in there. You can also add the contain in there as you want. And that way you have one set of key frames that you can add to an element. So that were our view progress time line and we also have the ability to set insets because by default, if we are looking at entering or exiting or the cover phase, it would be between these two lines. I see. So this is going to sound very much like some of the things that you get on Intersection Observer. Yeah. Because sometimes you want to like call it short or make it longer. Yes. Okay. So the enter stage starts at the bottom line already and then the exit stage only starts at the top line where it's already like a bit out of view. For that, we have view timeline insets, two values, one for the start edge and one for the end edge. So the start edge being the bottom edge. Yeah. The end edge being the top one. And presumably they can be negative. Yeah. So 10% positive values, they go inwards. Yeah. Like in set. Nice. And that way you can like change the threshold from Intersection Observer. Yeah. Very similar. Yeah. Nice. If you're looking for more demos, what you can do with this because it can be confusing. Okay. I've only shown a box actually revealing. You can do way more stuff with this with these view progress timelines. Look at the top. Where the elements go out. Very good. Look at the bottom. Where the elements go in. And that's just like a little translate on. Yeah. Very good. I'm looking at every list item in there. And then I am translating away the content as they enter or exit the list. I think this has like a very native app like feel to it. Yeah. Yeah. Yeah. Very nice. Very satisfying. Oh, is this. Yes. I was just about to say is this how you did the algorithm covers. The algorithm covers is another example. Yes. So I'm looking at the ally elements as they enter from the right there. And I am animating the image inside there. Very nice. Which is pretty nice. Do note that I'm not adjusting the ally elements themselves, but I am animating the images inside them. Because if I were to like rotate the ally element, it would become smaller. It's about incline rect. And then stuff would happen if you are targeting. Oh, interesting. Yeah. You could sort of end up with a, because there is an infinite loop there. I don't know. The screen flickers. Yeah. Well, it does feel sort of infinite loop territory because you're saying, I want to do something when this thing is here, but in the rules that you can move it. Yeah. Yeah. So that's why I'm targeting the list items and I'm animating the images inside. Uh-huh. That's neat. Another thing. How did you build it? I mean, because we've been talking about how this is not in browsers. How did you build this? This version uses a polyfill, but we're getting ahead of ourselves. Yeah. Yeah. Another demo, and I like this one a lot, is stacking cards. Look at the cards as they hit the top edge. Oh. They move back and then they move out as a group. Is there ways to apply easing to this? Because it's sort of like right now that the, the card animation sort of stops quite abruptly. Is there, are there ways to apply? Yeah. Because you're using the scroll as a timeline, but I guess you could still use easing on top of that. No, that's not the case right now. So there's a direct link between you scrolling and the animation. So that's a linear connection. There is, there are talks going on to potentially add that, but that's going to be for V2. That has already been pushed down live. Fair enough. Fair enough. You can play with it today. I will. Because you were wondering, how did you make all these demos? Yeah. But you can play with it today, because Robert Schreck, again, and his team. Sponsored by like Robert Flack, all of these episodes. Robert Flack and the team. Gavin is also on there. Maddie is also on there. They have been working on a polyfill. Very good. Scroll time in polyfill. They already have the JavaScript version released. And at the time that you are recording this, so today Maddie is actually working on the CSS version. Oh, very good. So by the time this video gets published, we will have a CSS polyfill available as well. Usual CSS polyfill caveat supply, I guess. CSS has the same origin and all of that. Off main thread, saying no longer counts because... Of course. We don't have the primitives for that. Yeah, that's really cool though. It means you can actually start testing out how this API feels, which I think is probably the most important bit. Developers can provide feedback, hopefully to spec people who will listen. Other good news. The old version of the spec was behind a feature flag in Chromium-based browser, so in Chrome and in Edge. Talking to engineering, it said like, oh, new syntax. It's like the main logic is there. We are simply rewiring a few things. So that will be cool, right? It will allow them to progress very fast on it. The Firefox folks have been working on it as well. Nice. So I am very looking forward to them shipping it anytime soon as well. Any communication from the Safari folks? I know they don't commit to things, but are they involved in any of the work? No. Okay, well, you know, we'll see. It's the kind of high-level feature I'd expect them to be interested in. Some of the really low-level stuff that they don't tend to go for, but something that links into it. And I know they've been looking at other kinds of animation timelines, like different frame rate ones as well. So I've got high hopes. So have I. That last thing there at the bottom. This is a code pen collection with all the demos that I've shown you that use the JavaScript version, Polyfill. So that code is already there. I will be adding the CSS version as well once we have that. Amazing. People should play with this today. Yeah, definitely. Because if we look at our animation, because if we look at our... Yep. Yeah.