Fun, festive, interactive web animation
Many of the websites we love most are fun and interactive. In this episode, Cassie Evans will teach us how to add a little festive whimsy to our web projects with Greensock.
Links & Resources
Click to toggle the visibility of the transcript
Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.
JASON: Welcome to another episode of Learn with Jason....
So, I've had you on the show a couple times, but for those not familiar with your work, do you want to give a background?
CASSIE: I'm Cassie, I have a background in design and motion graphics and I have been a developer -- frontend developer for about 6 years. And yeah, I used to do a lot of SVG animation and workshops. And then a few years ago I started working for GSAP. So, yeah, I'm developer education and support and like demo maker and empower your animation skills and all of the other things at GSAP.
JASON: Just everything they need you to be.
JASON: I love it. And you have been doing a fabulous job. It has been really, really fun to watch the work that you have been putting together and dropping, you know, before and after joining GreenSock. I think it was a great hire for them. So, I guess maybe we start there. What -- the high-level, what is GreenSock?
JASON: Yeah, I've had a lot of fun playing with GreenSock -- or GSAP, sorry. I have to retrain myself, now. I've had a lot of fun playing with GSAP throughout my career. It's been a great tool for like if I have a silly idea or I want to make something do something on a web page and I don't know how to do it with CSS, I can always do it with GSAP. Super-fun, shout out for scroll trigger. I do love a really -- a really big fan of scroll trigger, had a lot of fun with that.
CASSIE: Shout out also in the chat to web bay and GD who do a lot of GSAP content. And we appreciate you and we love you a lot.
JASON: Yes. So, and that's actually one of the things they love about GSAP in general is the -- the high focus on highlighting community creators. And it sort of feels like that's, you know, woven into the heart of GSAP as a company, as a brand, is that it's very much built on just kind of lifting up other cool things people are building with it. So, yeah. Wonderful. It's a good place to be. Feels like a good community to be a part of.
CASSIE: Yeah, I'm very, very spoiled. It's wonderful. It's nice kind of existing on the -- like this little kind of creative nerdy corner of the Internet. It feels very much like the early kind of MySpace/Neopets, GeoCities days.
JASON: Yes, you can just go play.
JASON: That is so much fun.
JASON: And, you know, I have seen some of your workshops in the past. You're getting shoutouts about them in the chat. Agreed. It's so much fun to play with this stuff so much fun to learn. It gives so many opportunities for just kind of growing and improving and you can do it in a way that's very visual and engaging and I love that.
CASSIE: Yeah. I really -- I really after that happened I was like -- yeah, that was totally just me being funny and I knew the real names for all the brackets. I definitely know all the real names for those. Kind of being humorous.
JASON: We have found, that's probably our second clip of the stream for anybody who is prepared at home. Okay. So, let's talk a little bit about what we want to do today. It is -- it's coming up on the second half of December. It's holiday time. I've got this -- look, I'm wearing my holiday sweater with bears on it. Or, sorry, for all the Brits in the audience, my holiday jumper.
CASSIE: That's actually a cardigan.
JASON: Wait, what's the difference?
CASSIE: Cardigans are -- they have buttons on the front.
JASON: Okay and a jumper is?
CASSIE: Jumper is like what I'm wearing.
JASON: We're learning. Already learning.
CASSIE: Have to be able to inform.
JASON: Okay. So, yeah. So, you pitched I think you literally -- Cassie, you got to come back on the show. Let's do something festive. I asked no questions. I just put it on the website.
CASSIE: So, yeah. What we're gonna do today is we're gonna do a little snow globe.
JASON: So much fun. To build that snow globe, I imagine you have lots of goodies in there. Before we start building, let's talk about what is new. GSAP got its new brand. And I believe you've also released some new features that sound pretty exciting that maybe we can go over at a high level and then we'll dig into them a little bit later on.
JASON: Very, very cool.
CASSIE: Hopefully helpful for everyone.
CASSIE: It can be difficult to animate imperatively in like a declarative world. React definitely doesn't make it easy for -- and DOM scripting in general.
JASON: Yes. And I think that -- I mean, if I can -- if I can make a little confession: Wrestling React to make it let me do DOM manipulation with GSAP was one of my like -- one of the reasons that I started looking for alternatives to React. Is I felt like I just was always fighting it instead of using it. So, I'm really excited to see how you are --
CASSIE: I'm glad you said look for alternatives to React not alternatives to GSAP. I was about to get up and leave.
JASON: No, I think my thinking is always, you know, I want to do it with the platform it I can. I'll look at what CSS can do. And when CSS starts to feel like I'm really -- like -- if I start to feel like I'm using CSS in a purpose for which it wasn't designed, then I'm never going to be able to maintain this. I don't want to be the person who has got a handwritten SVG path typed into my like CSS rules or anything. So, at that point, then I'm like, okay, let's use the tool that's designed for the thing I'm trying to do. Then I'm gonna reach for GSAP and we're gonna make something, you know, really fantastic that doesn't require me to twist CSS into a full blown like, hey, what if you use CSS as a... like a math -- like a giant math problem. There's a point where it starts to hurt my brain.
CASSIE: Yeah. Someone here has said curious what platforms feel good for GSAP. I would say that with the new use GSAP hook that we've made, animating in React does feel good now. There's scoping within the use GSAP hook. You can also choose how your animations react to props changing as well. And it behaves a lot more like GSAP should. Personally, I'm a big Jamstack fan. I love -- I love myself a nice static site with a little bit of sprinkling of animation on top. So, I think anything that is kind of like Jamstacky is great. Vue is a dream, JD is saying. Because you have just kind of really nice life cycle events. So, it's very easy to kind of chuck animations in there.
JASON: And it seems to me that like the biggest challenge is the way that React works is it's building like a copy of the DOM. And every time something changes, it is removing that whole copy and replacing it with the whole thing. It's re-rendering the whole thing. That doesn't work when you're trying to hold the state of something through multiple steps of an animation. That's I think why people have so much trouble. And so, any -- any tool that doesn't require you to do that -- so, anything that's not using a VDOM, that's just, you know, here's the DOM, GSAP is gonna work great. And I've really liked it in like I used to use it in Eleventy.
CASSIE: Oh, I love it --
JASON: And Astro is pretty good for it. I've tried it in Vue, I think you had me do Vue in one of the episodes.
JASON: It's great.
JASON: Here's a good question from David Darnes that is about GSAP compiling. Does it do that?
CASSIE: No, it does not. We also kind of fix a lot of issues with CSS animations. So, kind of I don't know how that would work we have them in animation world. If you have an animation you want to pull over to GSAP, you can use keyframes. But no compiling into CSS. That sounds like a project for you, David, you can build that out.
JASON: Congratulations, David. You have volunteered yourself for a wonderful holiday project. We expect it by late January.
CASSIE: Yeah, that would be great.
JASON: Somebody's asking how to use it with WordPress. I think you would use it with WordPress, you just stick it into whatever frontend you're using, right?
CASSIE: Yeah, in the docs, in the user center, there's a using GSAP with WordPress page that I've put together. There's video and snippets that will help you. Yeah. Just head over to the learning center.
JASON: Here's that doc right here. Let me throw a link into the chat. For anybody who wants --
CASSIE: We don't have to build anything, we can just chat to the lovely people.
JASON: I mean, honestly, sometimes you really can. Do you recommend adding GSAP as a dependency or with a script tag?
JASON: Yeah. I think that makes a lot of sense. Okay. So, before we get too far into this, I want to make sure we have plenty of time to play. So, I am going to switch us over into the pair programming view.
JASON: One button. Look how fast that goes. And I'm also going to put up... just realized I lost my captioner today. Where are they? [I'm watching on Twitch...] -- oh, no, check my email real quick and -- maybe not.
CASSIE: No one look at Jason's email.
JASON: Oh, yep, Amanda is waiting for the link. Oh, boy. Everybody hold, please, while I fix this problem.
CASSIE: Would you like to do a song for everyone. [Beautiful musical howling]
JASON: Oh, it's so good! It's so good. It makes me very happy. Okay. Amanda is here. Sorry -- sorry, Amanda. I'm switching systems like we're on Streamyard now. We used to be on a system called Ping. Oh and we've got a global sing long going. Good job, Brody.
CASSIE: Backup singers for Brody, that's good.
JASON: We got another one, another dog started barking.
JASON: So good, so good. Now we're ready. We've got -- we've got our captioner here. Amanda is here. And that live captioning is made possible through the support of our sponsors for the rest of this year unless I find new sponsors by Netlify and Vets Who Code. Thank you very much to them for making this possible. And if your company is looking to spend its '24 budget, call me. We are talking to Cassie today. Thank you so much for being here and taking time with us. Let me send a link to the Twitter. And yeah. We should probably take a look at what has happened to GSAP. Because what a fantastic website.
CASSIE: Oh, it was a labor of love. Big shoutout to ToyFight who joined ranks with us and helped us with all the branding and kind of really helped us take the brand in the right direction. I knew they were going to be the right people from the start because all of their previous projects have the right level of fun. And not taking themselves too seriously. Yeah. And they kind of put a lot of focus on accessibility as well which is really good. The docs were my baby. So, the docs in the learning center is what I've spent the last like year doing. I'm incredibly happy with how they've turned out. And they're a lot faster than they were. A lot faster than they were. And yeah, everything is a lot more easily surface-able as well. We've --
JASON: Oh, my goodness, yeah. This is -- this is excellent.
CASSIE: It's using Docusaurus.
JASON: Nice, nice.
CASSIE: Yes, very highly-customized Docusaurus build. Amazingly, when I started building this out with Docusaurus, I popped into the Docusaurus Discord and there's a guy in there who is the mod in the Discord. And I had helped him with SVG animation back in the day. So, when I needed help with Docusaurus stuff, he have just super-helpful. It was this wonderful kind of swapping of skills, which is great.
JASON: Yeah. I -- I love that. That makes me so happy. And that's like the best part about this community is that it feels huge and like you can get lost in it. But it's -- it's very -- it's like cozy. Like you see the same people and it's also a good reminder. Be nice, you're gonna see the same people for the rest of your career.
CASSIE: Very much.
JASON: Okay. So, then we've talked about GSAP. We've showed everybody your Twitter. And now you sent me this. Am I not logged in?
CASSIE: I did...
JASON: I think I'm logged in. It I was logged in. Let me... what's going on?
CASSIE: Do you want to do another song, Brody?
JASON: We'll be okay. This will take me just a second. Make sure I've copied this. Get back to my demos page and we're just gonna log in real quick. There it is.
CASSIE: It was just such a lovely reaction from the community to the new site as well. Yeah. Ho, ho, ho.
JASON: So, this is --
CASSIE: Yeah, this is our starting point. There's a few little things in there already. All the SVG, don't look in the defs tag, linear gradients for days. It's like a toy box, we don't need to look into it.
JASON: It's a little box of mystery that we don't need to poke around in. Okay. It's an SVG and an H1 is what we've got for markup.
JASON: We are centering.
CASSIE: I'll let you do a little poking around. Yeah. There's not much going on in the CSS because all the stuff is in the SVG, really.
JASON: Got it.
CASSIE: So I don't have to worry about it. All the name spacing and stuff.
JASON: This piece is a piece that will get me every single time when I'm working with SVG. When you have to do the create element namespace. Oh my goodness.
JASON: Great. This makes sense. We got a good amount of setup here. But it look like we don't have -- do we have GSAP added yet?
JASON: Okay. We have GSAP, Draggable, and inertia.
CASSIE: And plugin, yeah.
JASON: Okay. And anything special on -- no, nothing special on the HTML, nothing special on the CSS.
CASSIE: Just some little GSAP plugins. Draggables, free plugin and inertia something a club GSAP plugin. That's a members-only one. It makes Draggable so much better. Inertia plugin and Draggable kind of go together like peanut butter and jelly. I'm being American.
JASON: That was very good American. I almost believed that you were one of us.
CASSIE: Goes together like beans and toast. It allows you to super-power your Draggables, basically.
CASSIE: So, we'll dig into that in a little bit.
JASON: Great. So --
CASSIE: And make SVGs in illustrator. I do -- or affinity. Affinity is like the non-Adobe version. Yeah, it's quite nice.
JASON: Okay. So, this is a -- this is a Cassie original here?
CASSIE: It's built from bits of our new brand, though. Because we've got all of these little shapes.
CASSIE: And little things. And ToyFight made us some light Christmas flare. We have the snowman and the trees which is nice.
JASON: What is a namespace as a high level? It's a thing that gets put into XML to theoretically differentiate is from other specs. But as far as I know, no one uses it except SVG.
CASSIE: I would have just said the thing that you have to put in SVG sometimes to make the browser like it. Yeah. I don't really have a good explanation for it.
JASON: At this point, I feel like it's a vestigial tail. You need it, but like not really. Okay. So, we've got this beautiful snow globe.
JASON: We've got ourselves some boilerplate. What should I do first?
CASSIE: What should we do first? Let's make the snow globe Draggable. That's a good first step.
CASSIE: Oh, right at the very top we should do GSAP register plugin. So, GSAP.register plugin.
JASON: Is it all caps? Low caps?
CASSIE: Register plugin is camel case. Yeah. We're just gonna say Draggable, comma, and inertia plugin. Draggable has a capital D.
JASON: Okay. So --
CASSIE: And then the plugin is camel case.
CASSIE: We don't really need to do that, we're including GSAP and the script plugins. But it's good to do it because it's good for tree shaking. It's good to get into the habit of it. Yeah. Let's go underneath our little snow flake generator.
JASON: Okay. What are we doing first?
CASSIE: We're gonna make the snow globe Draggable. You're gonna say Draggable with a capital D, dot create. Awesome. And then we're just gonna pass in the ID of snow globe. I think that is just all -- yeah. Like that.
JASON: Yep, there it is.
CASSIE: Just grabbing our SVG. I've enabled the run button because we're doing an animation loop. If we have it updating automatically, we're going to end up in just animation chaos zone.
JASON: Well -- [Beep, beep]
CASSIE: My timer has gone off. Draggable!
JASON: Is it time up? You've got to go?
CASSIE: Yep, time up.
JASON: Okay. So, one line plus the plugin registration and now we can put this anywhere we want on the screen.
JASON: That's pretty neat.
CASSIE: Awesome. So, if you want to kind of see simply what inertia can do, after snow globe, we're gonna pass in a config object. So, do a comma and then a config object. That's a very common GSAP pattern if you've written GSAP code before. If you write tweens or timelines, anything really, there will be a config object to pass in to give it more superpowers. So, we're just gonna say "Inertia: True."
CASSIE: Now try, throw it.
CASSIE: It's gone.
CASSIE: Awesome. So --
JASON: Reload that page.
CASSIE: So, inertia plugin is basically the key to getting momentum-based motion after you release your mouse or touch., so before we added inertia if Jason was to let go of the mouse, it would just stay exactly where it was. We can also put bounds body here as well.
JASON: Like that, or in quote?
CASSIE: That's great. Just so -- oh, no, in quotes so it's not a variable. Now you can't throw it off the screen.
JASON: Oh, yeah, and it kind of bounces back. Oh, that's really nice. Because then I can -- I can get out here and, you know, be kind of silly with it. But if I throw it...
CASSIE: We're not gonna lose it. Which is good.
JASON: Yeah, that's great.
JASON: Good. Okay. Excellent.
CASSIE: Cool. So, what should we do next? Let's get the velocity values. So, mainly in this stream, I kind of want to show how to -- like tweens and timelines are great. They're like kind of GSAP basics. But kind of creating interactive animations. A lot of the time you kind of have to get numbers and then somehow plug those numbers into an animation. And that can be a little bit confusing for people. So, I thought we're kind of covering that. So, we can do callbacks inside our Draggable in the same config object. So, let's do an un-drag callback.
CASSIE: Oh, let's do a normal function. Because we need to access this in here. In which it's gonna end up with --
JASON: Do you do it like this?
CASSIE: Yeah, let's try that. Or we could do -- yeah. Let's try this. Try it first. So, We'll do -- or, let's grab our cords, so our H1 tag as well. So, before the Draggable.
CASSIE: Let's grab the H1. I think it's got ID of --
JASON: And I'm just doing this with just regular --
CASSIE: Yeah, just regular query selector is all good.
JASON: Okay. And I can just get the H1? Or do...
CASSIE: That's fine.
JASON: Do it like this. Why not? Why not?
CASSIE: It's got to be scalable, Jason.
CASSIE: In our drag, coords.html -- or H1.
JASON: Is that capitalized or?
CASSIE: Capitalized, yeah.
CASSIE: And then say inertia plugin. That's capital I and then capital P. And then we're gonna say "Get velocity" which is also camel cased.
JASON: Like that?
CASSIE: Yeah. And then we're gonna say inside -- round boys -- we're gonna say this.target.
CASSIE: And then comma, and then get the X value.
CASSIE: Quotes and X.
CASSIE: Perfect. Okay. So, now --
JASON: Just gonna break this up for legibility.
CASSIE: Let's see if it works.
JASON: Let me hit the run button.
CASSIE: Yeah, there we go.
JASON: So, when I move it slow, nice and slow.
CASSIE: Small velocity value.
JASON: When I throw it...
CASSIE: It's high. Or shaking it hard, you get a higher value. Around a thousand to 2,000 there. For anyone that doesn't know what velocity is, it's kind of like the delta difference between where this snow globe was on the X axis and where you've moved it to. And if you move it super-fast from one place to another in the animation tick, you're gonna have a bigger distance and a higher velocity. If you move it a smaller distance, you have a smaller distance and a lower velocity value.
JASON: Excellent, excellent. Okay. So, now I have -- I have a suspicion. If I can make a prediction on what I think we're about to do.
JASON: So, we have this snow globe. We have a function to create snow flakes. And we've just gathered the velocity of the snow globe when we shake it. Are we going to create more snow flakes when we're shaking it harder? Is that the --
CASSIE: We are going to do something like that. But we're gonna step through slowly first because --
CASSIE: That would be jumping into the deep end. But yes, you've read my mind. So, before we do that, can you notice something weird about the velocity values? See if you can spot the thing.
JASON: I guess... no? It doesn't reset to zero?
CASSIE: That's exactly it. So, right now we're grabbing the velocity on drag. So, the drag event only fires --
CASSIE: When you're dragging it. And when you let go of it, it stops. But inertia is the momentum-based motion after the mouse is released. So, the inertia is actually still going down after we've unclipped. But that callback isn't firing for that whole time.
CASSIE: So, what we're gonna do is we're gonna track the inertia in a different way. So, on a new line outside of the Draggable instance, we are gonna say, I think you're still in the Draggable -- yeah. There we go.
JASON: Outside of Draggable.
CASSIE: Outside, yeah.
JASON: Got it.
CASSIE: We're gonna make a tracker. So, we can say const tracker. And we're gonna say inertia plugin.track.
JASON: As a function?
CASSIE: Yes, as a function. And then we're gonna pass in snow globe, again. So, the ID, awesome. And then same as we passed in X, we're gonna pass in comma and then not a config object.
JASON: Oh, the X, got it. Sorry.
CASSIE: The X. Yeah. Let's just do X for now. That's great. And then we're gonna create a function. Let's call it update on velocity. That's explanatory. Cool. And then in here we're gonna say -- we're gonna grab the X value. So, we're gonna make another variable. And we're gonna say tracker.get. And then pass in X again in strings.
CASSIE: Awesome. So, let's -- let's like copy that coords.html bit. We're gonna log this value out on the update on velocity. Yeah.
JASON: Okay. And then comment this one out?
CASSIE: Yeah, let's comment that one out. So, this function isn't being called at the moment. So, we need to add it. We're gonna add it to GSAP's ticker which is basically the kind of heart of the GSAP animation engine. So, it's kind of like our request animation frame. It uses request animation frame underneath the hood. So, we're gonna say GSAP.ticker.add. Yeah. And then we're gonna pass in that function.
JASON: Not called?
CASSIE: Not called, yeah. Just like that. That's perfect.
CASSIE: So, if we run this, hopefully we don't end up with a horrible animation loop that kills the browser.
JASON: Seems okay. But I did break it.
CASSIE: Oh. What's it saying?
JASON: Break --
CASSIE: Press the little red...
JASON: Console. That's helpful.
CASSIE: Tracker.get is not a...
CASSIE: We've got a tracker. Tracker. Inertia plugin, track -- oh, it's because tracker and -- we need to get the first one. It's an array. So, after --
JASON: Like this?
CASSIE: -- dot track. Maybe? I didn't know you can do that. Is that getting the first one?
JASON: It will get the first one in the array, yeah.
JASON: But that's still not working. Or I need to refresh the browser.
CASSIE: Oh, maybe we've done ourselves a bad loop.
JASON: It's loading.
JASON: Just start again. Hey! Look at it go. Sometimes you just got close that window. Close this one and pretend that one never happened.
CASSIE: A few times. Yeah. So, if we control down -- that's very cool. I didn't know that got the first element in the Array.
JASON: Yeah, the destructuring stuff is wonderful.
CASSIE: Destructuring objects a lot. But I haven't done like destructuring arrays.
JASON: The other one I like is they did at. You do an at and give it an index.
CASSIE: I would have done square boys and the old school way.
JASON: But there's so many new toys.
CASSIE: I've learned two new toys now. This is very exciting. Daniel -- Daniel's asked, can you use the ticker to handle a tick for a Canvas or a WebGL render? Yeah, that's how you use GSAP like if you're doing Canvas animations.
CASSIE: So, yeah --
JASON: Now it's doing the thing, goes back to zero.
CASSIE: Goes back to zero. Now if you throw it, yeah! It carries on after you've let go. Which is exactly what we want. Okay. Let's make something move with the velocity. So, first thing we're gonna do -- we're gonna animate the little snowman. So, the first thing that we want to do is we want to set a transform origin for the snowman. Because in SVG land, transform origins are top left-hand corner. That's not what we want. We want it to be bottom. We're gonna set it with GSAP, though, so that we don't end up with any cross-browser issues.
CASSIE: Say GSAP.set. And we're gonna grab the snowman. Yeah. And then we're gonna say transform origin, camel cased. And then a string with bottom center.
CASSIE: Yeah. Perfect. Now we have the right transform origin and we can mess around with our snowman. So, underneath that GSAP set, because this is still also kind of functional setting stuff up. We're not gonna animate with a tween, we're gonna animate with QuickTo. It's a performant way. More performant than tweens are. If you're doing animation or mouse move, or in this case, on drag with lots and lots of loss to your values, QuickTo is a way to basically say pipe this value directly to the property that you're chasing. It kind of skips a lot of convenience methods, convenience tasks that you have in normal GSAP tweens.
JASON: Did I do this right?
CASSIE: Yeah. GSAP.QuickTo. Perfect.
JASON: This is my first time using this one.
CASSIE: So, we're gonna pass in the snowman.
CASSIE: And then just the next -- after the comma, we're gonna say rotation. So, before the comma --
JASON: Oh. Before the config object, but we will have one.
CASSIE: We're gonna say rotation, awesome. And then we've got the config object. And the cool thing with QuickTo is it's -- we've got quick setter which you can't pass in a config object. QuickTo, you can pass in durations and eases as well. So --
CASSIE: You've got a little bit more play room. We're gonna pass in duration. Say like 0.4, maybe?
JASON: And this is seconds.
CASSIE: Yeah. And then yeah. That's all we'll do for now. We'll just leave it like that. But QuickTo is something that we're gonna pass a value into. So, we're gonna assign this to a variable.
CASSIE: We can call it like -- call it wobble snowman.
CASSIE: Awesome. And then we can use this to wobble our snowman.
CASSIE: Now down in our function that's bell getting called on tick, let's just say "Wobble snowman," and we're gonna pass in the X value and see what happens.
JASON: Pass in this X value.
JASON: And we don't have to do anything else. Oh, because it's rotation. Oh, I'm --
CASSIE: To the rotation property.
JASON: Things are connecting -- oh!
CASSIE: It's doing it.
JASON: Good. I feel bad getting any velocity on here. This is -- my poor little buddy.
CASSIE: It's maybe like --
JASON: Can we get a full spin.
CASSIE: It's a little bit too much velocity at the moment.
JASON: A full loop-de-loop.
CASSIE: You can say he wobbling. It's so great. So, yeah. A little bit too much velocity. And this is kind of what I wanted to cover is for animation it can be a little bit difficult for newbies to figure out how to get values from the browser which could just be like anything. It could be, you know, pixel values of mouse movement. You've got screen width and then you have to make them into something usable that you can -- rotation or like X percent or that kind of thing. So, yeah. We're gonna use GSAP utils to take in velocity in a range that's usable. Go back up to the top where we have our GSAP set. It's kind of all of our convenience stuff here.
CASSIE: We're gonna make a clamp first. Yeah, const clump .
CASSIE: And then GSAP -- you're already there.
JASON: I heard you say it earlier.
CASSIE: And we're gonna clamp in a range. I think when you were shaking it around, I saw -- I definitely saw 1500, I think I saw a 2,000. So, let's do from minus 2,000 to 2,000. So, comma, 2,000. So, that's a clamping function that's gonna clamp our velocity values between those values so it won't go below that or above that.
CASSIE: And then on another line, we're gonna say -- we're gonna create a map range. Excellent. So, we're gonna say GSAP.utils.map range. And now we're gonna map this to an actual usable range. So, how much do you want the snowman to wobble, Jason? How many degrees?
JASON: It seems like -- let's see... like this feels pretty good here. What do you think that is? 3 or 4 degrees each direction?
CASSIE: I would say let's -- because we need to do the max values. So, the max possible -- if you shake it around really hard.
JASON: So, maybe like minus 7 to plus 7? Minus 10 to plus 10?
CASSIE: We can try that. Let's give that a go.
JASON: Do I need to classify these as degrees or anything?
CASSIE: Nope. That's just passing to the rotation and the degrees of the default.
CASSIE: We're gonna make -- we're gonna pipe these together now because these are separate utils. And we can use pipe to kind of pipe different function calls together. So, let's call this transform. And then we're gonna say "GSAP.utils.pipe." And then we're first gonna pass through this clamp, say clamp. And then map range. And now this transform is like a reusable function that we can now pass a value into and it will take that value and it will pass it through the clamper. It will pass it through the map range. And then we're gonna pipe that into our QuickTo.
JASON: Just to walk through the logic here. What's happening -- let me collapse this down so we can get past it easier. When we send inertia, we are getting the inertia value, which is the number up at the top there. And that is -- now has a minimum value and a maximum value. And we're also then taking whatever the value is between this range and we're saying, "Take those minimums and maximums and then scale them to this minimum and maximum." So, like if I have zero, it's zero. If I have negative 2,000, it's negative 10. And if I have negative 1,000, it's negative 5.
CASSIE: Yep. That's exactly it.
CASSIE: So, it's like it's mapping those like kind of ridiculously large velocity values into some values that we can actually use for our rotation. And we can --
JASON: -- this right around here?
CASSIE: Yeah, exactly. And we could do this by, you know, dividing by a magic number. But you don't get that granular control. Because if you're doing an animation, you usually want to say, look, I want to be between this value and this value.
JASON: So, I've added it? And now it's not doing much.
CASSIE: It's only moving a tiny bit. So, maybe let's bump up the map range.
CASSIE: Maybe let's do from like minus 90...
JASON: Oh, we can --
CASSIE: Let's try that. To 90. And let's see what we get now. Oh, is it still not doing anything? Interesting.
JASON: Did I do something wrong?
CASSIE: Transform... or if we've got the wobble snowman. That's right. We've got that. That's right. Let's go have a little look down in our -- where it's being called. Wobble snowman. Transform X. That looks like it's working. Can we log out what the transform X is?
JASON: Yeah, let's just stick it right up here. And see what we're getting. Not a number! Oh.
CASSIE: Not a number. What have we done?
JASON: Great question. So, we're getting the X. Let's get... let's see. So, these are numbers, these are numbers. Does that mean -- are we getting a string or something?
CASSIE: Points of the snowman. That's a good comment, well done.
JASON: This a what Alan does. He comes into my stream and ruins things. SnowmanPrefersReducedMotion. Sorry, that is a user setting we do not respect. This snowman is gonna wobble, y'all. So, it is a number.
CASSIE: Um, utils clamp... this should be working... why are we not working?
JASON: Are any of these arrays?
CASSIE: Nope. This should be working. Transform. Can we make them lets for LOLs. I don't think that's gonna change anything. Minus -- oh, no! Map range is wrong. Map range is wrong. Map range, we've got to pass in the range that we want to map to. So, we've got put minus 2,000, comma, 2,000. Picking up on the stress, Brody is whining mind me. It's okay. It's just not a number. It's all right. Okay. Yeah. Map range, you've got say, this is the original range and we want to map it to this range.
JASON: Got it.
CASSIE: Me getting overly excited.
JASON: Four values like this?
CASSIE: Yeah, four values. We could have checked in the GSAP docs.
JASON: Look at him wobble.
CASSIE: Yeah! He's wobbling. But he's no longer going upside down. So, he's not miserable.
JASON: And I was way too conservative with my rotation.
CASSIE: Brody's decided it's his dinner time so he's run off.
JASON: Ah, yes.
CASSIE: Cool. Are we happy with that wobble range?
JASON: I'm pretty happy with that wobble range. Look at him wobble.
CASSIE: Before we do anything else, let's make this Transformer into a function. Because it's just kind of sitting there in multiple lines now.
CASSIE: Let's make a function called Transformer?
JASON: Like around it?
CASSIE: Transformer. And then we're gonna pass into the Transformer function. We want to be able to map to any range that we pass in. So, let's pass in a min and a max.
CASSIE: And then we're gonna replace the minus 90 and the 90 with the min and the max.
JASON: Ah, got it. Okay.
CASSIE: Yeah. So, we always want to clamp the velocity to the same value. But we might want to change what we're mapping it to. Yeah. And then we're gonna return the transform. We also need to pass in a value. So, the return transform line, that needs to be a function, and we're gonna pass in a value. And then in the -- yeah. Gonna pass in value there as well.
CASSIE: You're very good at extrapolating what I mean even when I'm just saying nonsense words.
JASON: Okay. Now if I do Transformer and we say minus 90/90, that should be the new --
CASSIE: Yeah. That should be the new way of doing it.
JASON: Okay. So, save that. Give it a shot. And... it's doing the thing.
CASSIE: It's doing the thing! Awesome! Cool. So, someone's asked how the TypeScript is supported for GSAP. We have types included in the -- in the library somewhere. I don't use TypeScript. But I know that people that use TypeScript have used it. So, yeah. You should be fine. Not very reassuring, is it?
CASSIE: There is some type somewhere. Awesome.
CASSIE: Now that we've got the snowman wobbling. Is shall me make some snow?
JASON: We shall.
CASSIE: Awesome. We've got our little class that is making some snow flakes at the moment. So, where is that?
JASON: That is here.
CASSIE: Yeah. Okay. Let's common out create snow flakes and that should make us some snow flakes. Boring, though. Because I saved the fun bit for us. So, if you go into that class... awesome. Okay. So, first thing is, we've got -- we're passing in an href which is grabs like a little PNG.
JASON: That's our...
CASSIE: Thick snowflakes.
JASON: So, here is our snowflake and it's a stack of six of these?
CASSIE: It's a stack of -- how many are we make something I think we're making like 30.
CASSIE: At the moment, all of them are just positioned on top of each other and it's the same snowflake.
CASSIE: In our create snowflakes function, we're looping around and creating a whole bunch of them.
JASON: You're saying you created multiple versions of the snowflake.
CASSIE: Multiple versions.
JASON: Oh, okay.
CASSIE: This is a template literal. When the 1 is, we are going to use GSAP utils.random. Yeah. Gonna say GSAP utils.random. That's also a function we're gonna pass in three things here. We're gonna pass in the min and the max. And then we also want to clamp that value to like one, two, three, four, five, six so we don't end up with flake 1.35792 because that's not a valid PNG.
JASON: Okay. How does one do that?
CASSIE: We're just gonna pass in 1.
JASON: That's saying as in to the nearest 1.
JASON: If I were to pass in a 2, it would be even numbers and so on.
CASSIE: Yeah. Awesome.
JASON: All right. So, we have some randomness for the snowflakes.
CASSIE: And then let's do for X position, we're gonna do the same. So, we're gonna say, GSAP.utils.random. Again --
JASON: Sorry, where was this?
CASSIE: X position. Just disappeared off the top of your screen.
JASON: Oh, X position. Sorry.
CASSIE: Where the GSAP position was.
JASON: Random --
CASSIE: We're gonna say -- our SVG is a thousand SVG units wide. We're gonna say zero and say a thousand. And SVGs are responsive. So, like our unit values will always be the same. We don't need to worry about window width, which is really nice. So, yeah. This should spread them all out in a line. Let's refresh and see if that happens.
JASON: I broke something... GSAP utils --
CASSIE: Yeah! There we go. Loads of snowflakes. Let's give them a bit of variation in size as well.
CASSIE: Or you can pass in an array with just set values which is quite nice when you want randomness, but controlled randomness.
CASSIE: So, you're gonna pass in an array and then we can say, maybe some of them are 50 pixels, 50 units wide. Some of them are maybe like 30 units wide.
CASSIE: Should we have a bigger one like 70 units wide? Let's see.
CASSIE: That might be too big. Let's give that a go. We should have a variety of snowflakes. Yeah! That's great!
JASON: Yep. Looking good.
CASSIE: We've got -- down there we've got the Y value. Bump them off the top of the SVG. Where it says -- let's make that like minus 50 or minus 70. Like minus the size of the largest --
CASSIE: -- snowflake.
JASON: Now they're gone.
CASSIE: Okay. We can animate our snowflakes.
JASON: To recap, we have our image. We have a size that is one of these three values, either 50, 30, or 70. We have the X position being some number -- some whole number -- between zero and a thousand. And then we just moved them up and it looks like you've got this circle set to clip so anything outside of the globe is missing or hidden.
CASSIE: Exactly. We have an SVG path going on and it's hiding anything that's outside.
JASON: Excellent. And then we're just looping through and creating 30 of them.
CASSIE: Someone's mentioned that the docs site is loading really slow currently. We have been having intermittent slow loading on the site, unfortunately, because we're getting hammered by some, yeah, malicious actors. So --
CASSIE: Yeah, it's fun. So, I saw people are trying to help that. But apology, it's a bit slow. It's very intermittent. It just happens when lots of people are hammering the server.
JASON: What dork thought it was a good idea to go and target a documentation site for animation?
CASSIE: Leave us alone! Leave us alone, please! So, yeah. It's sad.
CASSIE: Awesome. Let's do a little bit of animation.
JASON: Let's do a little bit of animation. I'm actually gonna clear this out so that we've got a little more space going here. All right. I'm ready.
CASSIE: Okay. Let's maybe keep our ticker right at the bottom if that makes sense for me.
CASSIE: Outside of the ticker, right above our inertia plugin.
JASON: Above here?
CASSIE: Yeah, above the checker. We're just gonna do a normal GSAP tween. So, just say GSAP 2. And we want to grab -- oh, I guess there are images inside the snow div. So, what are we grabbing? So with yeah. Anything that's a direct child of the snow ID.
JASON: Anything that's a direct -- okay. So, that would be -- let's see... how is my CSS? Snow anything.
CASSIE: Yeah, that's great.
CASSIE: Cool. Okay. And let's just say Y a thousand, and that's gonna move them all to the bottom. We can just play that now and see what happens. Just check that it's working. Check that we've grabbed them. Yep.
JASON: Did you see that? Everybody see that? It happens fast. Pew!
CASSIE: Awesome. So, we're gonna want to make this kind of staggered., so the snowflakes fall at different times. And with GSAP, we've got a stagger option
CASSIE: So, stagger, pass in an option. We have a config object. And we're gonna set the stagger amount. Let's say amount to 5 seconds.
CASSIE: And then let's set a duration as well. So --
JASON: In the stagger?
CASSIE: Outside of the stagger. Yeah. Let's -- oh, so, we can use GSAP utils as well in tweens. But we can use shorthand string version. So, you can just make a string.
CASSIE: And then just say "Random."
CASSIE: And then we're gonna do the array thing again. We're gonna say either 3, 4, or 5 seconds.
CASSIE: Awesome. And let's give that a run and see if that does something good.
JASON: Look at that.
CASSIE: We've got --
JASON: That is festive.
CASSIE: I know! Awesome. Now we want it to repeat infinitely. So, we're gonna put the repeat inside the stagger object. If you put it outside, it's going to wait for all the snowflakes to animate, and then repeat. If you put it inside, it's going to start from the beginning again.
CASSIE: You end up with a seamless animation rather than all of them animating and then being a pause. So, repeat minus 1, just a number. Yeah. Awesome.
JASON: Oops. The save command and the toggle sidebar command in arc are the same.
CASSIE: Yay! We've got snow.
JASON: Look that the.
CASSIE: Amazing. Shall we set a little rotation and a little bit of kind of X movement in there as well?
JASON: Of course, yes.
CASSIE: Yeah! So, underneath the Y -- let's keep all of them together. So, we'll do a rotation. Let's do a random, again. So, we can do random and we're gonna say minus 360 to 360. So, yeah. Either spin left or spin right.
JASON: Okay. And do I need to pass in like a whole unit or anything?
CASSIE: You can do if you want. But we can also leave it like that. That would be fine.
CASSIE: Now they should do a little bit of spinning around. How much longer do we have?
JASON: Wow, look at this. We have like another 20 minutes of working time.
CASSIE: Yes, okay, cool. So, oh, this is interesting. It's doing a really cool snowfall effect.
JASON: It's drifting.
CASSIE: It's because the transform object is the top left-hand corner. It's unexpectedly doing something quite interesting. So, transform origin in SVG is top left-hand corner of the SVG itself. If we set transform origin just underneath duration. Transform origin. And we'll do center in the string. Yeah. They should all spin around themselves now.
JASON: Okay. Cool.
JASON: Very cool.
CASSIE: Cool. Okay. And then let's do a little bit of movement on the X axis as well.
JASON: Can I just take a quick second to point out I thought there was no way that we were gonna get something that was plausibly snowfall in this amount of time. Like I figured we would have -- here's some -- you know, here's some snowflakes that move in a straight line. In 10 minutes of putting them in, you have managed to make this feel, if this was on a website in the background, this looks plausibly like snow. It adds so much life to this little thing in what? This ten lines of code we added?
CASSIE: We're gonna make it even better. We're gonna make it flurry on velocity.
CASSIE: Yeah. Awesome. So, yeah, let's do a little X axis as well. We can do another random. I'm just loving the random. That's how you make snow feel natural, right? Each snowflake has got to be individual and doings it own thing.
JASON: I've written one or two articles total about GSAP. And the random function was like the whole point of what I was doing. Because it's just so much what have makes these animations feel life-like.
CASSIE: Yeah. The utils are like the lesser known magic of GSAP, really. Like there's a lot of other, you know, animation libraries. But GSAP is really -- it's like a toolkit. It's got everything that you could possibly need for any kind of like number manipulation or -- yeah. Anything. Oh, that's a nice compliment. Yeah, GSAP stagger goes hard too.
JASON: Very true, very true. Okay. What do we want our min/max to be for X here?
CASSIE: Let's go minus 500 and 500? That feels -- if the SVG is a thousand wide, that feels reasonable, I think.
JASON: Yeah. So, it will go like half the distance. Up to half the distance.
CASSIE: And have them all disappearing off.
CASSIE: Oh, that's so great.
JASON: This is delightful.
CASSIE: So, what's the most performant image type for this? So, SVG used to be in the dark days like really not very performant at all. But it's actually hardware-accelerated in most browsers now. So, we can do more with SVG than we used to. There's obviously like a limit. And if you hit a limit, kind of look at Canvas. But there's not too much of a difference between like SVG and HTML elements now.
CASSIE: So, yeah. Awesome. So, cool. Now we want to be able to control this animation, right? So, at the moment --
JASON: Because I got a wobbly snowman.
CASSIE: But the snow is just doing its own thing. And it's not relating to the velocity whatsoever. So, let's store this tween in a variable and let's call it just snow or snowfall or something. So, yeah. Const snow. Awesome. Okay. So, now we've got our snow. In our Draggable, lets -- where is our Draggable?
CASSIE: Awesome. So, let's do some callbacks. so, we're gonna do a callback on drag start and on drag end. Because with snow globes, like there's not snow all the time, right? There's only snow when you shake it, the snow happens when you shake it and you stop shaking it and the snow disappears.
JASON: This is just for -- this is not actually necessary. This is just how my brain works.
CASSIE: Yeah. You got to have a certain order.
JASON: You got to declare before you use it. My brain won't accept it otherwise.
CASSIE: So, yeah. Let's do -- let's put paused true in the tween actually. We haven't done that. We have to pause it. Paused, true.
CASSIE: Cool beans! And then on drag start, we're gonna say snowfall.play. And dot play is a function. We're gonna pass in zero. That says play from the beginning. And then say snowfall.paused. And let's just give that a go. It won't look -- it won't look great, but it will be functionally correct.
JASON: Okay. So, it's doing nothing.
JASON: It's snowing.
JASON: And it stopped.
CASSIE: And stopped snowing. Okay. Cool. What we want, know, is when we finish dragging it, we want the snow to like gradually go away. We don't want it to just pause.
JASON: Play to the end of the current...
CASSIE: Yeah. So, let's add a tween in this on drag end.
CASSIE: So, we're gonna say "GSAP.to." And we're gonna fade the snow group. So --
JASON: How do I do that?
CASSIE: You might just to want put the snowfall.pause on a different line for now. Otherwise that's gonna be confusing.
CASSIE: Pass in an ID of snow.
JASON: Oh, oh, I thought we were doing something different.
CASSIE: And the container div. Container group. And we're just gonna fade it. So, we're gonna fade it to opacity zero. Opacity. Not fade. Almost.
JASON: Oh, oh, oh. I understand. Opacity.
CASSIE: Yeah. I am just saying lots of words at you. You're forgiven. And then we're gonna use an onComplete in this. OnComplete, when this is finished phasing. We're gonna say snowfall.pause.
JASON: And then... do we need a duration here, probably?
CASSIE: It's 0.5 by default, but we could set it for a bit longer, maybe.
JASON: Got it.
CASSIE: Or 0.5 is fine. So, let's do the same in our onDragStart.
JASON: On drag start...
CASSIE: Yeah, we want to create a tween.
JASON: And this one --
CASSIE: We don't need to use an onComplete here. But create a tween when we start dragging.
JASON: Do we want to put this before or after? Does it matter?
CASSIE: Doesn't matter. Let's just leave it for now.
JASON: Okay. Give it a shot.
CASSIE: Let's give this a go.
JASON: And now we've got snow. And it fades away.
CASSIE: Yay! Awesome.
CASSIE: Cool. So, let's -- okay, we're gonna do a little bit of bikeshedding here because there's gonna be -- there's like a little time -- there's potential for a little bug. So --
JASON: This is great because you just gave me an excuse to use one of my favorite things which is the bikeshedding air horn.
CASSIE: I don't have Brody in here to do an air horn back at you. So, because what's happening here is we've got now on drag end and on drag start are being called when we start dragging and when we end dragging.
CASSIE: But then we've got this little delay because when we finish dragging there's a tween. And then when that's complete, it's causing. If we stop the dragging before the call pause, before the onComplete is called, we would end up in a little logic loop.
JASON: Oh, yeah.
CASSIE: It would start playing but then the onComplete would fire and it would pause. So, we're just gonna do a little binary true or false value and check that.
CASSIE: Before the Draggable instance, let's make a isSnowing? And we'll say false. And when we start dragging, we say, is snowing: True. And on drag end, is snowing: False.
JASON: OnComplete? Or?
CASSIE: No, just initially.
CASSIE: And then we can use a check. So, on the -- in the onComplete -- yeah. There. We're gonna say if it's snowing, return. So, that's just gonna check like if this onComplete is about to fire. But we've already started dragging it again. It's not gonna bother to pause it.
JASON: Got it. So, if I'm doing this and I throw it and I try to grab it again -- I don't think I can even do this. Try to grab it again before it finishes, we won't have like a quarter second of me dragging that then causes it to stop which then confuses me as the user.
JASON: I get it, I get it.
CASSIE: Exactly. A little bikeshedding bit. So, if we click run on that, that should be -- should be working nicely now.
JASON: It looks like it was. So, now we can do -- here we go. Do some shaking.
CASSIE: Yes! So, now should we make a flurry?
CASSIE: This is the most exciting bit.
JASON: I'm so ready.
CASSIE: The most exciting bit. So, in GSAP land, you can animate anything. Any numerical value of anything. And everything is just objects. So, our tween, our snowfall tween, is actually also an object. And we can animate properties of our snowfall tween. So, one of the --
CASSIE: -- things that we can do a GSAP tween is control the duration or the time scale, all of these different properties we can control. What we are going to do is speed up the timescale when we're shaking it and slow it down if we're not shaking. So, if we go down into our little function that we're calling on the ticker runs. Okay. Awesome. We need to make a little -- oh, no, we don't. We don't need a quit to. Because we're just gonna be tweening the timeline. So, let's do -- let's speed -- oh, yeah. That works. Let speed equal -- and then we're gonna say Transformer. So, we're gonna use our same little Transformer function. And we're gonna say minus 10 and 10.
CASSIE: Because we've got a range between minus value and a positive value. We're just gonna work with that. We actually need it to be between zero and 10. So, on the next line, let's do GSAP 2. And we're gonna just say snowfall. I think we call it snowfall? Didn't we?
JASON: The animation?
CASSIE: Awesome. And then we're gonna do a config object. And we're gonna say duration 1. But then we're gonna animate the timescale of the animation itself. So, timescale is camel cased. And we actually always need this to be a positive number. So, let's do a maths.abs and pass in the speed.
CASSIE: And then let's give that a go. Hopefully it works and we have a flurry.
JASON: Okay. So, I'm just gonna go gentle. Then we hit it hard. And then we take it down slow again.
CASSIE: It's working!
JASON: This is incredible. Like it's just so good. And then if I make this bigger, we can -- we get a little more of the action in here. Like, this is fun. Like it is fun to make stuff like this.
CASSIE: It's so cool, isn't it? The utils are so powerful. It's great. And for someone -- I'm not very mathsy and I get intimidated by lots of numbers and maths and stuff. But it feels like it's really nice and accessible.
JASON: Yeah. And I love that we can kind of -- we can choose how fast this goes. It's so good. I mean, this has already given me a bunch of ideas for silly stuff I can do. It's just -- it's great. This is wonderful.
CASSIE: Everyone should just make silly stuff.
CASSIE: I feel like it's almost -- it's therapeutic for me in a way to take your skills that you usually use for capitalism and put them towards making a silly snow globe.
CASSIE: Yeah. It's very therapeutic.
JASON: Very much agree on that.
CASSIE: Hi, Steve!
JASON: Hello, Steve. So, this is incredible. This is super-fun. Let me make sure I have saved this. I'm gonna copy the link. I'm gonna throw it in here for anybody who wants to see this, make sure you go check that out and, you know, all the -- all the good thing. Cassie, for folks who want to go further, what -- where should they go? What should they do next?
CASSIE: Head over to the GSAP docs. So, we've got a learning center. And yeah. In the -- in the learning center, there is a getting started guide here, your first animation, easing, staggers, sequencing animations. And you can kind of just go through these learning center resources. If you are like video person, there's videos on our YouTube channel if you're not bored of my face. There's also loads of other people that make really great GSAP content. So, if you are in Webflow world, Web Bay, who was in the chat earlier, he does really great content. Yeah, there's a lot out there.
JASON: This is the right channel? Yes.
CASSIE: Yep. That's my face.
JASON: Would any of this require paid GSAP? You mentioned earlier that the inertia plugin --
CASSIE: Inertia plugin is a paid one. You can do dragging with GSAP Draggable. And that's just a free plugin. But if you wanted kind of inertia movement, that's a paid plugin. But you can also mess about with it for free on CodePen or StackBlitz. We've also got a GSAP trial npm package. So, if you're working on LocalHost, you can use that.
JASON: And for folks who haven't ever checked, when you say "Paid," what is somebody going to pay to use -- you called it Club GSAP, I think?
CASSIE: Yeah, you can go to our pricing page on our website. So, yeah.
JASON: Pricing page, right here.
CASSIE: There we go. So, there's Plus, Premium and Business. If you just want access to the plugins, you can get some of the plugins for plus or awful plugins for premium.
JASON: Got it.
CASSIE: This is just like our little funding model. Most of the stuff is free for everyone to use. But if you are -- if you're selling GSAP-enhanced products. So, if you're selling GSAP themes on like Envato or selling banner ads that use GSAP or you're selling a game that uses GSAP, you have to pay far commercial license.
JASON: Got it.
CASSIE: We keep everything free and accessible for the smaller people and charge some of the big corporate cases. And then --
CASSIE: And if you want access to some of the light bonus plugins, then that's also paid.
JASON: And it looks like this costs less than Netflix which is for the amount of fun you can have, I would say, what a deal.
JASON: This is more fun than Netflix.
CASSIE: You pay per year because it gives you access to all of the updates and bug fixes. But if you just use the GSAP plugins for a year and stop using GSAP and stop paying were your plugins don't stop working. We don't have some sort of crazy like kill all of your website it is you don't give us money thing.
JASON: Got it.
CASSIE: Yeah. It's just kind of paying for updates.
JASON: Well, with that, we are just about out of time. And the guy --
CASSIE: The lawn mower.
JASON: With the leaf blower is insistent that we wrap this up. Give everybody one last shout toward your Twitter page and another thank you to Amanda and White Coat Captioning for making this show more accessible. And also, thank you to Netlify and Vets Who Code for kicking in to cover the cost that have transcription. While you're checking out things on the Internet, make sure you go and look at the schedule. Because we are closing out strong this year. We have a special Tuesday stream. We're gonna look at how to use AI coding assistants. Because honestly, I haven't. And I'm curious. Then we have Mark Techson is going to teach us about Angular. That's gonna close out the year. It's gonna be a lot of fun. Make sure to mark your calendars, hear all the things. If you're on YouTube, hit the like and subscribe button, share the things. It makes it possible to make more of the shows because people care about the numbers. Cassie, any final words before we wrap this up?
CASSIE: I have a final bit of nonsense, if you'll allow me.
JASON: Yes, please.
CASSIE: Everyone was making loads of demos with browser windows. Have you seen?
JASON: I have.
CASSIE: It comes around every now and again. So, I just used the same code -- oh. It hasn't posted -- this comment has failed to post to Learn with Jason.
JASON: Oh, no.
CASSIE: I will try and post it or post it from my Twitter. I made a version of this Draggable that you can drag the browser window around and shake the browser window around and it does the snow globe.
JASON: That's so good.
CASSIE: Just because I thought, why not? While we were making nonsense.
JASON: That is fantastic. Thank you so much, Cassie, for hanging out with us today. Y'all, thank you so much for hanging out. And make sure that you go check out GSAP, go give this stuff a try. And, you know, we'll see you on -- what is it? It's Thursday today. We'll see you on Tuesday. Have a great weekend, you all. Have a great weekend.
CASSIE: Bye, folks.
Closed captioning and more are made possible by our sponsors: