CSS Animations and Transitions Lerp Technique
Transcript from the "Lerp Technique" Lesson
[00:00:28] And so, this is gonna be combining things from the previous lesson with requestAnimationFrame. So first of all, what is lerp? It sounds like a weird made up word, it's sort of is. And in fact, for a while, I thought that lerp stood for something. I don't think it does, I think it's supposed to be for linear interpolation or something like that.
[00:00:50] But yeah, so anyway, let me take this. Here's what lerp is. Let's say that you have your first position over here, and your last position over here. So let's say the mouse is moving really fast, and you go from here to here. And you don't want it to do that, you want it to move smoothly from one position to another position.
[00:01:20] So, instead of it moving directly with your mouse, a lot of websites do this where it's actually doing a very smooth transition from where it was to your mouse. And so, because the distance isn't known ahead of time, you can't just calculate keyframes, or animation duration, or anything like that, on the fly.
[00:01:41] Instead, it's using a different technique in which there is no defined animation. So here's the technique. Let's say that, instead of doing this, going from this frame to this frame, basically going from here to there, like the blue to the red in two frames. We want to do that over a series of frames, but we want to do it in a smooth way.
[00:02:04] Well, here's what we could do. Let's pick a fraction, like 0.5. So with 0.5, we could say hey, on the next frame, go halfway there, and then repeat. So on the next frame, go halfway there. In fact, that should be there, and there, and then repeat again. On the next frame, halfway there, on the next frame, halfway there, on the next frame, halfway there, you get the idea.
[00:02:37] So if you look at this as sort of like positions over time, you could see that it's going really fast, and then slowing down as it reaches its position. And by following the same, the formula, you could call it, by going only halfway every time, it doesn't matter where this is.
[00:02:56] So let's say that this is here, we're going to apply the same thing. So we're gonna go halfway, and halfway, and halfway. And so you could see that, over time, we're going from here to here, and it's smoothly animating to wherever your cursor is. All right, so how could we do that?
[00:03:15] Well, we could use both a combination of CSS variables and lerp. Which, again, stands for linear interpolation, I believe, don't quote me on that. Okay, so, how does lerp work? So, for lerp to work, I'm just going to take these two over here. Let's keep track of our currents points, which we're just gonna say is x at 0 and y at 0.
[00:03:46] And our target points, which is wherever the mouse cursor currently is. So instead of setting the x and y from the event, we are going to set the target points to whatever that x and y is. So we're going to say targetPoint.x = clientX, and targetPoint.y = clientY.
[00:04:08] Now, remember, over here, every animation frame, we want to move a portion of the way towards the target points. And so that's what's gonna get us our smooth animation. All right, so, that's something that we're going to do in the lerp function. Okay, so to do this, we have to calculate a couple of things, first of all the delta between the x.
[00:04:36] I know this is sort of a flashback to our previous exercise on layout animations. But we're calculating the delta for the x value and the delta for the y value, just to see how do we get to the middle of those two points. So const dx = targetPoint.x- the currentPoint.x.
[00:04:59] dy = targetPoint.y- minus the currentPoint.y. And then we are going to make the currents point such that it's moving closer to the target point by some percentage. So to do that, we're gonna say currentPoint.x = currentPoint.x + a fraction of this. So let's just say 0.5, dx times 0.5.
[00:05:30] And then we're gonna do the same here, dy * 0.5. And then we are going to set those styles inside of that lerp function. So we're gonna do it over here. Okay, so this is going to run continuously, and I'll show you what I mean in a minute.
[00:05:54] So this is going to be currentPoint.x and currentPoint.y. Okay, so, right now this isn't gonna do much of anything. But let's just take a look, so moving this. Let me make sure that we have the right file, let me just close this out. Okay, so we actually need to call lerp, sorry about that.
[00:06:24] So whenever this happens, I'm gonna call lerp, not lert, the lerp. Okay, so now, it's not moving halfway yet, we still have to do that. And so that's something that we could do in an animation frame. So, this is going to recursively call itself. Because, again, when we're moving somewhere, we want it to move halfway, and then we want it to do the same thing again.
[00:06:50] So move halfway, then halfway, then halfway, and so on, until it reaches that point. So we're going to request the animation frame, and we're gonna lerp again. And so, let's kick it off by actually lerping, and then that's going to recursively call lerp every single animation frame. Okay, so, by doing that, hopefully this works.
[00:07:16] All right, you could see that now it is smoothly animating to my mouse. And we did pick 0.5, and so that's going to make it go really quickly to our mouse. So it doesn't really look like it's being super smooth, because it looks like it's just almost attached to our mouse.
[00:07:33] So to make this more apparent, I'm gonna change this to 0.1. And so now, you see it's taking its sweet time getting to the mouse. So if I get rid of the before, let's just do display: none. Now you can see we have a ball smoothly following our mouse.
[00:08:02] So the combination of the lerp, using the lerp technique, which is, again, just a four or five line function. And using requestAnimationFrame, and using CSS variables allow you to do these kinds of smooth animations that don't have a specified duration. And so, by combining this with data state, there's a lot of possibilities for what you could do.
[00:08:29] Some of the reactive animations I have, I'd love to show you over here. So there's, let's see, this one, where we sort of use the same technique. And so this is something that we've done on the key framers. So we're following this circle. And then when we click, we're changing some states so that we could actually reveal the next states when we click.
[00:08:54] So there's that one, diamond slider. This one was really fun, because, this I believe, also uses lerp. Yep, so I even have something called createLerper over here. You don't have to worry about what that is. It's using the exact same lerp function. And so, this is for the diamond over here, where, when we go really fast over here, it tilts a little bit, and then it finally reaches its position.
[00:09:21] So now we're using it in slightly a different way than we use over here, where instead of interpolating the position, we're interpolating rotation. And so, that's why it's useful to, basically, have unitless values. Because now you could use how far the mouse moved in order to translate that into degrees, instead of pixels.
[00:09:48] So it's just a fun little thing that we did over there, yeah, thanks [LAUGH]. Let's see, this is one that I created a while ago, so this one uses pointer events. And so this is an example of another reactive animation, where, depending on how far the pointer has moved, it affects how far we tilt.
[00:10:12] So it's sort of a silly animation, but you get the idea. This one will probably crash my machine, so I won't do that. The most recent one I did was the one that I showed you on linear, where it's the cursor glow. This isn't using lerp, but it is using a combination, state based animations, where we're not using data state, we're using the hover property.
[00:10:39] But the same principle applies, where we only want to show the glow when it's on a certain element. And for the other ones, we only want to show it on the border. So the way that this is actually accomplished is that there is a glow on every single element.
[00:10:54] And every single element is following that mouse position relative to that element. And so we're doing the same, we're listening for the pointer, and we're calculating the x and the y. So if I could zoom in there a bit, we're calculating the x and y, and we're setting those to each element of the feature.
[00:11:15] And then we are just positioning the glow where that mouse is. And so, if we're hovering over it, that's when we tell CSS that we should show the full glow, instead of just the border glow. All right, so any questions on that? There's no exercise for this one, because we basically did it together.
[00:11:39] But hopefully this gives you some ideas on how you could add some reactive animations to your site. One more thing I want to mention, if you look at the styles over there, you could see that it's just moving a lot. So the reason that it's doing this is because, obviously if we calculate 0.5%, 0.5%, it's gonna happen infinitely, which is not good.
[00:12:04] So if you are using the lerp technique, what I really recommend that you do is find some sort of stopping condition for this. And so the stopping condition that I like to do is, if dx is less than, I don't know, like 2 or something, or 1. Because then you're getting into the sub pixel range.
[00:12:29] And there it doesn't really make sense to keep on lerping. So if dx < 1 or dy < 1, and actually, Math.abs. So basically if we are in within one pixel, then we could basically say that we're there already. We don't have to calculate these sub pixel ranges.
[00:12:54] So now you could see, no, it's still going on, but I mean that's the basic idea. You would have some sort of stop. It's because I didn't stop it. So I'm just gonna return over here. [LAUGH] Okay, so, Well, that's gonna stop immediately, it's great. So let's do the inverse of that.
[00:13:25] Okay, so this is happening because, at first, it's not doing anything, so, we're gonna just put this in here. Let isLerping = false, if !isLerping, I know I should use a state machine here, so, !isLerping, then lerp(), isLerping = true, okay? So every single time we move our mouse, we're going to lerp.
[00:14:00] And hopefully, we hit that stopping condition, okay? Well, yeah, anyway, just keep in mind there is a way for you to add a stopping condition, it escapes me right now, but, yeah. So any questions?
>> Yeah, is that basically used to debounce that addEventListener? So we're not just always listening for a mouse move?
[00:14:22] Just the one pixel, or would we wanna add stopEventListener on that mouse move at all?
>> Good question, so basically, you're asking, we're lerping the entire time. So when do we start lerping, when do we stop lerping, right? So, yeah, that's a good question. So I guess you can make this so that you're only lerping while some condition is true.
[00:14:53] So let's say-
>> Specific area, or something?
>> A specific box, or location and-
>> Yeah, so let's call this let lerpState = [COUGH] let's say 1 is it should be active, and 0 it should not be active. So we could say, right now it's 0, and then, so we'll just call doLerp over here, and then just function doLerp.
[00:15:24] So basically, we could say, if lerpState ==== 0, then we have the lerp. And then, otherwise, just don't do anything, because we're already lerping. And then so, now, over here we could do the if dx is < 1. And we'll just go by x, because both x and y are gonna converge on that point.
[00:15:53] Then lerpState = 0 and then we return. And so, hopefully, that's going to prevent us from doing the unnecessary lerping. Okay, perfect, so now if you look on the right, we actually stop a lot sooner, which is great. So yeah, and so now we're not doing any unnecessary browser animations, so that worked out.