Giving a scroll animation some weight
Springs, small bursts of thrust and a bit of attention turn a sprite on a path into something that feels alive.
Pinning an element to the scroll position is easy. Making it feel like it has mass is the fun part. Here's how the astronaut on this site moves, and why each piece is there.
Targets, not positions
The usual way is to map scroll progress straight to a position: 40% down the page means 40% along the path. It works, but it feels like a puppet on a rail.
Instead, each section on the page says where the astronaut should rest while you're reading it:
<section data-astro="0.78 0.45 1">The scroll position picks a target, and a spring pulls him towards it:
vel.x = (vel.x + (target.x - pos.x) * stiffness) * damping;
pos.x += vel.x;Because he chases the target instead of sitting on it, a fast scroll makes him overshoot a little and settle, the way real objects do. Two numbers decide the whole personality: stiffness for how eager he is, damping for how quickly he calms down.
Hold, then travel
A spring alone makes him drift all the time, which gets tiring to look at. So the target holds still while a section is in the middle of the screen, and only moves in the space between sections. You read in peace, and he travels while you scroll.
Thrust you can believe
The jets fire in proportion to how fast he's moving. They spool up quickly and wind down slowly, which reads as effort rather than an on/off switch. Every few seconds at rest he fires a short burst in a random direction and drifts back, the small corrections a person makes to stay in one place.
Let him look
This one surprised me. Every fifth of a second, I find the heading or card nearest the middle of the screen, and he slowly turns to face it. It's a tiny thing, but it makes him feel like he's reading along with you rather than floating past.
Respect the reader
If someone has asked their system for reduced motion, there's no spring, no drift and no bursts. He simply sits at each resting spot. Same story, no motion sickness.