webdevpuneet.com

Motion Path Plane — Free GSAP MotionPathPlugin Snippet

Motion Path Plane · Animations · Plain HTML, CSS & JS · Live preview

CategoryAnimations

Copy & paste

Source Code

<div class="mpp-wrap">
  <svg class="mpp-svg" viewBox="0 0 600 320">
    <path id="mppPath" class="mpp-path" d="M60,240 C140,80 240,80 300,180 C360,280 460,280 540,110"/>
    <circle class="mpp-dot" cx="60" cy="240" r="6"/>
    <circle class="mpp-dot" cx="540" cy="110" r="6"/>
    <g id="mppPlane" class="mpp-plane"><text font-size="30" text-anchor="middle" dominant-baseline="central">✈️</text></g>
  </svg>
  <div class="mpp-bar">
    <button class="mpp-btn" data-speed="0.5">0.5×</button>
    <button class="mpp-btn is-active" data-speed="1">1×</button>
    <button class="mpp-btn" data-speed="2">2×</button>
  </div>
  <p class="mpp-hint">autoRotate keeps the plane's nose on the curve's tangent.</p>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

True curve travel
Bézier-accurate motion, no waypoint faking.
Tangent heading
autoRotate derives rotation from direction.
Space calibration
align solves SVG-to-element coordinates.
Centered riding
alignOrigin pins the element's middle to the line.
Patrol loops
yoyo reverses path and heading together.
Live throttle
timeScale tweens retime without rebuilding.
Markup-owned route
The visible dashed path is the source of truth.
Partial segments
start/end fractions fly sub-routes.

About this UI Snippet

Motion Path Plane — Fly Any Element Along an SVG Curve

Screenshot of the Motion Path Plane snippet rendered live

Moving an element along a curve is the animation ask that breaks CSS: keyframes interpolate in straight lines, and offset-path support is inconsistent where you need it most. GSAP's MotionPathPlugin (free on the CDN) makes it one tween: this snippet flies a plane back and forth along a dashed bézier route, nose always tangent to the curve, with buttons that retime the flight live via timeScale.

One config replaces a page of trigonometry

motionPath: { path: '#mppPath', align: '#mppPath', autoRotate: true, alignOrigin: [0.5, 0.5] } does four jobs. path samples the bézier; autoRotate continuously sets rotation to the curve's tangent angle (the derivative work you'd otherwise approximate by sampling two nearby points, as the hand-rolled scroll path follow does); align solves coordinate spaces; and alignOrigin pins the element's center — rather than its top-left corner — onto the path line. Without alignOrigin, the plane would ride the curve by its corner, visibly floating beside the route.

align is the part everyone underestimates

An SVG path's coordinates live in the SVG's viewBox space; the animated element has its own coordinate system, transforms, and origin. align: '#mppPath' measures both and calibrates the tween so the element travels *visually on* the stroked line — accounting for viewBox scaling, existing transforms, and nesting. This is the plugin's quiet superpower: it even lets DOM elements (a div outside the SVG) follow an SVG path, since alignment is computed in screen space.

yoyo makes a patrol route out of one path

repeat: -1, yoyo: true sends the plane out and back forever, and because autoRotate derives from direction of travel, the plane automatically faces backward on return legs — no second path, no manual flip. power1.inOut eases each leg so the plane banks gently out of each endpoint rather than bouncing off it.

timeScale is live retiming, not rebuilding

The speed buttons never touch the motion path: they tween the *tween's* timeScale to 0.5, 1, or 2 over half a second. Animating timeScale (rather than setting it) means speed changes themselves accelerate smoothly — the plane audibly "throttles up" instead of jumping to the new rate. This works because a GSAP tween is itself tweenable, one of the engine's most underused properties.

The route is honest markup

The dashed stroke users see *is* the animation's source of truth — restyle it, and the flight follows any d you paste in from Figma or Illustrator. Endpoint dots are plain circles at the path's terminal coordinates. Nothing about the route lives in JavaScript.

start, end, and partial journeys

Beyond this demo: start/end fractions animate along a sub-segment (start: 0.25, end: 0.75), values beyond 1 loop around closed paths, and start > end reverses direction — all without editing the path. Pair with ScrollTrigger and the same tween scrubs with the page.

Customizing it

Swap the emoji for an SVG plane that points right (autoRotate assumes rightward-facing art; add a fixed rotation offset otherwise), draw your own route, or attach a drawn trail with scroll svg path draw mechanics. Related: scroll-scrubbed path riding in scroll path follow, orbital motion in orbiting icons, and route-based storytelling in scroll timeline dots.

Step by step

How to Use

  1. 1
    Add the GSAP CDNsInclude gsap and MotionPathPlugin from the CDN panel.
  2. 2
    Paste HTML, CSS, and JSThe plane starts flying its dashed route.
  3. 3
    Watch the turnsautoRotate keeps the nose on the tangent.
  4. 4
    Let it returnyoyo flies the same path backward, heading flipped.
  5. 5
    Click 2×timeScale tweens up — the plane throttles smoothly.
  6. 6
    Paste your own pathAny d attribute becomes the new route.

Real-world uses

Common Use Cases

Travel and delivery maps
Fly a plane or truck along a route using real bezier travel, with autoRotate deriving the heading from the curve tangent.
Onboarding journey markers
Move a dot between setup milestones beside scroll timeline dots, with align calibrating SVG space to the element.
Hero ambience
Let paper planes or comets drift through a startup hero, with alignOrigin pinning the element's middle to the line.
Process diagrams
Send tokens flowing through pipeline curves, and pair with scroll SVG path draw to draw the route as well.
Orbital and game paths
Use circular paths for satellites next to orbiting icons, or have characters patrol a map near physics balls.
Related: Zdog Pseudo-3D Orbit Scene
See the Zdog Pseudo-3D Orbit Scene for a related animations pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

offset-path can follow a path string, but support gaps (especially older Safari), no autoRotate offset control, awkward coordinate handling for elements outside the SVG, and zero runtime control (no timeScale, no scrubbing, no partial segments) make it fragile for production. MotionPathPlugin normalizes all of it behind one tween that also composes with every other GSAP feature.

It reconciles coordinate systems: the path's points live in the SVG viewBox space while the moving element has its own space, transforms, and origin. align: '#mppPath' measures both in screen space and calibrates the tween so the element rides visually on the stroked line — which is also why a plain div outside the SVG can follow an SVG path perfectly.

autoRotate: true sets the element's rotation to the path's tangent angle at every tick — the same heading math you'd otherwise approximate by sampling two nearby points and taking atan2. Because heading derives from travel direction, the yoyo return leg faces backward automatically. Art must point right by default; autoRotate: 90 style numeric offsets fix art drawn facing up.

They tween the tween: gsap.to(flight, { timeScale: 2, duration: 0.5 }) smoothly accelerates playback rate itself, so the plane throttles up over half a second instead of jumping. Tweens being tweenable is core GSAP — the flight's position, path, and heading logic are untouched; only its clock changes.

Yes — start and end fractions define a sub-segment (start: 0.25, end: 0.75 flies the middle half), start greater than end reverses direction, and on closed paths values beyond 1 wrap for continuous laps. Combined with ScrollTrigger, the same motionPath tween scrubs along the route as the page scrolls.

Register the plugin at module scope, inline the SVG, and create the flight tween in a mount effect — useEffect, onMounted, or ngAfterViewInit — via refs, killing it (or reverting a gsap.context) in the cleanup so the infinite repeat stops on unmount. Keep speed as a ref-held tween handle, not state — buttons call gsap.to(flightRef.current, { timeScale }) directly. The control bar maps straight to Tailwind.