Scrolling animation using motion.dev

I want the outer circles to shrink & merge into the butterfly's circle from sideways as I scroll down. The butterfly is a svg tag and I have all the IDs for the butterfly's circle. I am using motion.dev with react. I've got most logic correct but not sure how exactly I would bring the circle right into butterfly precisely using x,y co-ordinates More context: As I scroll down the butterfly scales up from 0 to 1.
No description
10 Replies
ᴋʙ
ᴋʙ4w ago
Maybe try using lerp? (Linear interpolation) get scroll position start and stop and normalize them example start scroll position is at 123px so normalized 123px -> 0 and end scroll position is 450px so normalized 450 -> 1 (maybe use Math.min() and Math.max() to ensure values dont go above/below)
const lerp = (start, end, t) => start + (end - start) * t;

const lerpCoords = (start, end, t) => ({
x: lerp(start.x, end.x, t),
y: lerp(start.y, end.y, t),
});

// Get scroll progress (0 to 1)
const getScrollProgress = () => {
const scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
const scrollbarHeight = document.documentElement.scrollHeight - window.innerHeight;
return Math.min(scrollPosition / scrollbarHeight, 1);
};

const startPosition = { x: 0, y: 0 }; // top left
const endPosition = { x: canvas.width / 2, y: canvas.height / 2 }; // center

const updateCirclePosition = () => {
// value from 0->0.1->0.2..->1
const normalizedScroll = getScrollProgress();

// This will now be animate the circle position based on scroll
const interpolatedCoords =
lerpCoords(startPosition, endPosition, normalizedScroll);

yourFunctionToUpdateCirclePosition(interpolatedCoords);
};

window.addEventListener('scroll', updateCirclePosition);
const lerp = (start, end, t) => start + (end - start) * t;

const lerpCoords = (start, end, t) => ({
x: lerp(start.x, end.x, t),
y: lerp(start.y, end.y, t),
});

// Get scroll progress (0 to 1)
const getScrollProgress = () => {
const scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
const scrollbarHeight = document.documentElement.scrollHeight - window.innerHeight;
return Math.min(scrollPosition / scrollbarHeight, 1);
};

const startPosition = { x: 0, y: 0 }; // top left
const endPosition = { x: canvas.width / 2, y: canvas.height / 2 }; // center

const updateCirclePosition = () => {
// value from 0->0.1->0.2..->1
const normalizedScroll = getScrollProgress();

// This will now be animate the circle position based on scroll
const interpolatedCoords =
lerpCoords(startPosition, endPosition, normalizedScroll);

yourFunctionToUpdateCirclePosition(interpolatedCoords);
};

window.addEventListener('scroll', updateCirclePosition);
ᴋʙ
ᴋʙ4w ago
Parth
ParthOP3w ago
thanks that's a nice idea but only works precisely if you want to end it at center
ᴋʙ
ᴋʙ3w ago
.. ?? yeah but like... you could change the code? what i would do is something like this: get an array of objects like this:
const circlePositions = [
{ start: {x, y}, end: {x, y} },
{ start: {x, y}, end: {x, y} },
...etc
]

// then on scroll do
for (const {start, end} of circlePositions) {
lerpCoords(start, end, normalizedScroll);
renderCircles();
}
const circlePositions = [
{ start: {x, y}, end: {x, y} },
{ start: {x, y}, end: {x, y} },
...etc
]

// then on scroll do
for (const {start, end} of circlePositions) {
lerpCoords(start, end, normalizedScroll);
renderCircles();
}
i mean either way you have to figure out how to get the positions for each circle.
Parth
ParthOP3w ago
The thing is the section I'm animating is a sticky one, and I have to get the correct coordinates of all smaller circles and the big circles such that it remains consistent in all screen sizes
Parth
ParthOP3w ago
Here how it should actually look like
ᴋʙ
ᴋʙ3w ago
Ok but like do you still need help or what? if so please give some more info, why is the sticky part relevant? is it because the x,y positions of the circles change on scroll? if so just negate that with the scroll height / scroll position are the circles you want to animate html elements or rendered canvas circles?
Parth
ParthOP2w ago
Yes, sorry for the late reply, got caught up with other dev work Yes, I believe that's causing an issue, because the whole section is sticky which changes the x,y coordinates on scroll, and animations play in timeline(in a sequence) Yes they are html div elements
ᴋʙ
ᴋʙ2w ago
Tbh i don't see what the problem is, if you have the start and end position for each circle it should work perfectly with the method above. The problem with coordinates changing is not an issue just add the scroll.
Parth
ParthOP2w ago
Yeah I'm getting the correct x,y coordinates now And I think I'm very close to implementing the full thing

Did you find this page helpful?