Image Trail
Move your pointer across the demos and images will pop up along your path, hold for a beat, then exit by shrinking, fading, zooming, or sliding away. Everything is animated with GSAP, and the effect respects prefers-reduced-motion, swapping the motion for a gentle fade when needed.








Move your mouse around
turning your screen into a canvas of playful particles and dancing light.









Move your mouse here too









Move your mouse to see the action
Instructions
Setup
container (default: null) The required DOM element that acts as the stage for the effect. Any direct <img> children inside it become the "source" images that get cloned and spawned as you move the pointer. If it's missing (or GSAP isn't loaded), the function bails out with a warning and returns do-nothing refresh/destroy methods.
Spawn behavior
movementThreshold (default: 100, example uses 35) The minimum distance in pixels the pointer must travel since the last spawn before a new image appears. It's measured with Math.hypot(x - lastX, y - lastY), so it's true distance in any direction. Lower values → denser trail; higher values → images appear only after bigger movements.
delayBetween (default: 70, example uses 140) A time-based throttle in milliseconds. Even if the pointer is moving fast and instantly covers the movementThreshold, no two images can spawn closer together than this interval. Works together with the threshold: both conditions must pass.
rotation (default: 20, example uses 45) Each spawned image is randomly rotated between -rotation and +rotation degrees (via gsap.utils.random). A value of 45 means the tilt can be anywhere from -45° to +45°. Set it to 0 if you want every image perfectly upright.
Entrance animation
scaleInDuration (default: 0.6) How long, in seconds, the image takes to grow from scale: 0 to scale: 1 when it appears.
scaleInEase (default: "back.out(2)") The GSAP easing curve for that entrance. back.out(2) overshoots past full size and settles back, giving a springy "pop." You can swap in any GSAP ease string, e.g. "power3.out" (as in your example) for a smoother, non-bouncy pop.
Hold & exit animation
holdDuration (default: 0.6) How long, in seconds, the image sits fully visible at scale 1 before the exit animation starts. Technically it's applied as the delay of the exit tween. It's also reused in reduced-motion mode as the pause before the fade-out.
exitMode (default: "shrink", example uses "translateX") Determines how the image disappears. Accepted values:
"shrink"— scales the image down to 0 (also the fallback if you pass anything unrecognized)."fade"— simply fades opacity to 0 in place."zoom"— grows the image toexitScalewhile fading out (an "explode toward you" effect)."translateY"— slides the image down byexitDistancepx while fading."translateX"— slides the image to the right byexitDistancepx while fading."none"— no exit animation at all; the image is removed abruptly onceholdDurationends.
exitDuration (default: 0.6) The length, in seconds, of the exit animation itself.
exitEase (default: "power2.in") The GSAP ease for the exit. power2.in starts slowly and accelerates, which reads as the image being "sucked away." Any GSAP ease works.
exitDistance (default: 140) Only used by the "translateX" and "translateY" exit modes — the number of pixels the image travels while fading out. Ignored by all other modes.
exitScale (default: 1.6) Only used by the "zoom" exit mode — the scale factor the image grows to while fading out (1.6 = 160% of its size). Ignored by all other modes.
Accessibility / reduced motion
respectReducedMotion (default: true) If true, the script listens to the browser's prefers-reduced-motion: reduce media query. When the user has that enabled at the OS/browser level, the dramatic scaling/zooming/slid-ing is swapped for a calmer behavior defined by reducedMotion.
reducedMotion (default: "fade") What happens when reduced motion is active:
"fade"— the image cross-fades in over 0.25s, holds forholdDuration, then fades out over 0.35s. No scaling, rotation, or movement."none"— nothing spawns at all; the effect is effectively disabled.- Any other value behaves like
"fade"(the code only special-cases"none").
forceReducedMotion (default: false) A manual override. If true, the reduced-motion behavior is applied always, regardless of the user's system setting — useful for testing the accessible version, or if you've decided the full animation shouldn't run for anyone. Note the check is forceReducedMotion || (respectReducedMotion && mediaQuery.matches), so forcing it works even when respectReducedMotion is false.
A couple of practical notes:
- Units matter: durations (
scaleInDuration,holdDuration,exitDuration) are in seconds (GSAP convention),delayBetweenis in milliseconds, andmovementThreshold/exitDistanceare in pixels. - Dependencies between options:
exitDistanceonly matters for translate modes,exitScaleonly for"zoom", androtationonly applies in full-animation mode (reduced-motion spawns never rotate).