Example · Observer + Inertia + MotionPath
A momentum loop
Wheel, drag, or swipe anywhere on the stage and the chips ride the track; flick and let go, and InertiaPlugin keeps them gliding with your real release velocity. One Observer normalizes every input, and the whole loop is a single number that GSAP tweens.
ObserverInertiaPluginMotionPath
SCROLL SPLIT FLIP MORPH DRAW MOTION OBSERVER INERTIA
wheel · drag · flick · momentum carries it
state = { p: 0 }; // the whole loop is one number
ref = injectGsap(({ gsap }) => {
// paused motionPath tweens as position setters
const setters = chips.map((chip, i) => {
const t = gsap.to(chip, {
motionPath: { path, align: path,
alignOrigin: [0.5, 0.5] },
ease: 'none', paused: true,
});
return (p) => t.progress((p + i / n) % 1);
});
const render = () =>
setters.forEach((s) => s(this.state.p));
const observer = Observer.create({
target: stage,
type: 'wheel,touch,pointer',
onChange: (self) => {
this.state.p -= self.deltaY * 0.00045;
render();
},
onRelease: (self) =>
// inertia on a plain number
gsap.to(this.state, {
inertia: {
p: { velocity: -self.velocityY * 0.00045 },
},
onUpdate: render,
}),
});
return () => observer.kill();
});How this works
- Each chip has a paused
motionPathtween used as a position setter: the loop's state is one numberp, and every chip renders atpplus its offset. Move the number, the whole train moves. - Observer merges wheel, touch, and pointer into one stream. While you drag it adds deltas to
p; the moment you release, the gesture velocity is handed to InertiaPlugin. - InertiaPlugin doesn't care that
pisn't an element:gsap.to(state, { inertia: { p: { velocity } } })glides any property with physical friction, exactly like the thrown bricks on the Draggable page. - Everything is created inside the callback: leave the page and the Observer, the setters, and the ambient drift are all torn down.