025

Scroll Path Journey

£10 or the whole Vault, £79.20

Responsive SVG motion path storytelling with GSAP MotionPathPlugin and ScrollTrigger. A marker follows a route drawn down the page while checkpoints activate on scroll.

ScrollTriggerMotionPathPlugin intermediate
6 more details
motion-pathsvg-animationscrubscroll-storytellingmatchMediacheckpoint-navigation

This demo reads better at your own screen size than in the frame below:

Updated

About this effect

A responsive scroll storytelling effect built with GSAP MotionPathPlugin and ScrollTrigger. As the reader moves down the page, a directional marker follows an SVG route with automatic rotation, the walked line draws in a little ahead of it, and content checkpoints activate at precise progress values: photographs develop from grey into colour and captions lift as the marker reaches them. Separate desktop and mobile paths keep the composition intentional at every size, while a ResizeObserver rebuilds MotionPath alignment without losing the reader's current position.

Scroll Path Journey - GSAP animation effect preview

What's included

9 items
  • MotionPathPlugin route following with automatic tangent-based rotation
  • ScrollTrigger scrub ties marker, line drawing, and checkpoint state to scroll progress
  • Drawn route runs a configurable distance ahead of the marker (data-journey-lead)
  • Marker swells with scroll velocity and settles with an elastic overshoot (data-journey-swell)
  • Separate desktop and mobile SVG paths, swapped at the breakpoint, with per-mode checkpoint positions
  • Responsive rebuild preserves animation progress when the scene changes size
  • Clickable checkpoint navigation scrolls directly to any point on the route
  • Custom checkpoint event for analytics, media changes, or application state
  • Reduced-motion mode draws the full route and presents every checkpoint statically

Perfect for

5 use cases
  • Product stories that connect features along a visual route
  • Travel and hospitality itineraries with interactive destinations
  • Company timelines and process explainers with clear milestones
  • Case studies that guide readers through research, design, build, and launch
  • Educational diagrams where an object must follow a responsive SVG path

How it works

2 sections

The stage contains matched desktop and mobile SVG route paths plus a duplicate progress stroke. A paused timeline draws the route in while MotionPathPlugin carries the marker along the active path, turning to face the direction of travel; the stroke tween finishes a fraction early so the walked line leads the marker. ScrollTrigger maps that timeline to the journey container's scroll range and selects the latest checkpoint whose progress value has been reached, and its velocity drives a quickTo on the marker's scale that settles elastically when scrolling stops.

Route geometry swaps at the mobile breakpoint, and a debounced ResizeObserver rebuilds the tween at its previous progress, because motion-path alignment is worked out when the tween is created.

Plugins ScrollTrigger, MotionPathPlugin
Difficulty Intermediate
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Lighthouse, as measured

Google Lighthouse on this effect's demo, from the latest scan. A measurement of the demo as shipped, not a promise for your page.

Accessibility
100
Best practices
100

No performance score, on purpose. That figure depends on how you deploy: your server's compression and caching, your CDN, the connection and the device doing the test, none of which the code controls. The same page can score very differently on two consecutive runs, so measure it where it will live.

Paid effect

Purchase to unlock the code.

Buying Scroll Path Journey opens the HTML, CSS and JavaScript source, the full documentation, an AI setup prompt for your editor, and every update we ship to it. Standard license: unlimited personal and commercial projects. Every paid product is tested for desktop and mobile layouts, reduced-motion handling, animation cleanup and keyboard controls wherever there is something to operate.

£10 Standard license, unlimited projects

Browse free effects

Or the whole library: the Vault, £79.20, one payment.

Documentation

Quick Start

1. Add the stylesheet to your HTML <head>:

Code snippet omitted: it ships with the download.

2. Add GSAP and the required plugins before </body>:

Code snippet omitted: it ships with the download.

3. Add a journey container to your page body:

Code snippet omitted: it ships with the download.

The motion path, progress path, and shadow path must use the same d value. The script measures the progress path, aligns the marker to the motion path, and synchronizes both with the container's scroll range.

Using It With Your Own Design

What the script needs from your markup: the data-* hooks in the table below, and nothing else. .journey-stage is the one class it reads (it is the element the ResizeObserver watches, so it should be the box the SVG sizes). Every other class in the demo (.journey-bar, .journey-head, .checkpoint, .checkpoint-pin, .checkpoint-media, the --pin-x custom properties) is the demo's own styling and can be replaced.

How the demo lays the route out. The container is a normal block in the page flow, not a pinned scene: the SVG is display: block; width: 100%; height: auto, so its viewBox sets the stage's height and the page is as tall as the route. With data-journey-start="top top" and data-journey-end="bottom bottom" the marker leaves the start of the path as the container reaches the top of the viewport and arrives at the end as the container's bottom does. Anything inside the container above or below the stage (the demo's head and foot) is part of that scroll range, which is why the demo puts them inside [data-path-journey]: the route starts moving on the first pixel of scroll, with no dead intro.

Placing checkpoints on the route. Because the stage scales uniformly with its width, a checkpoint positioned in percentages of the stage lands on the same route coordinate at every size. The demo sets left/top from --pin-x/--pin-y (route coordinate divided by the viewBox size) and offsets the entry to one side with a transform, so the pin sits exactly where the marker will pass. Work those coordinates out once with MotionPathPlugin.getPositionOnPath() for each data-progress value; the two route geometries usually put the same stop at different fractions of their length, which is what data-progress-mobile is for.

Start states the demo's CSS owns. The walked stroke (.route-progress) is opacity: 0 until the has-js class exists, so a page without JavaScript shows the dotted route rather than a fully drawn red one; the marker is display: none under the same gate because it sits at the SVG origin until the script places it. Upcoming checkpoints are greyed and dimmed only under .has-js and only while they carry neither is-active nor is-passed, so every camp is shown in full without JavaScript and under prefers-reduced-motion. Keep those three gates if you restyle: an ungated opacity: 0 ships a blank route to no-JS visitors.

The marker. The script sets x, y, rotation and scale on [data-journey-marker] and clears them on destroy. Give it position: absolute; top: 0; left: 0 and a fixed width and height; anything inside it (the demo's nose) is yours. data-journey-rotate="false" if your marker has no direction.

Required Structure

Element Purpose
[data-path-journey] Root scroll container and ScrollTrigger target
.journey-stage Stable visual stage observed for responsive rebuilds
[data-journey-path="desktop"] Invisible desktop path used by MotionPathPlugin
[data-journey-progress="desktop"] Visible desktop stroke drawn with scroll progress
[data-journey-path="mobile"] Mobile path used below 761px
[data-journey-progress="mobile"] Visible mobile progress stroke
[data-journey-marker] HTML or SVG element aligned to the active route
[data-journey-checkpoint] Clickable milestone with a data-progress value (and optional data-progress-desktop / data-progress-mobile)

You may omit the mobile route if the desktop geometry works at every size, but the supplied script expects matching desktop and mobile paths. Duplicating the same path under both selectors is valid.

Options

All journey options go on the [data-path-journey] element.

Attribute Values Default Description
data-journey-scrub true, false, number 0.8 ScrollTrigger scrub behavior. A number is smoothing time in seconds
data-journey-lead 0 to 0.5 0 How far the drawn progress stroke runs ahead of the marker, as a fraction of the route. The demo uses 0.05
data-journey-swell 0 to 1 0.3 How much the marker scales up at full scroll speed before settling back with an elastic ease. 0 disables the velocity response
data-journey-start ScrollTrigger position top top Scroll position where route movement begins
data-journey-end ScrollTrigger position bottom bottom Scroll position where route movement completes
data-journey-rotate true, false true Rotate the marker to match the path tangent
data-journey-active-class CSS class name is-active Class applied to the current checkpoint

Checkpoint option:

Attribute Values Description
data-progress Number from 0 to 1 Route position where the checkpoint becomes current
data-progress-desktop, data-progress-mobile Number from 0 to 1 Per-route override of data-progress for that breakpoint, for when the desktop and mobile geometries reach the same stop at different fractions of their length

Keep checkpoint values in ascending order. The script sorts them internally (per active route), but matching DOM and route order makes the markup easier to maintain.

Responsive Paths

MotionPathPlugin calculates path alignment when the tween initializes. Changing the SVG's rendered dimensions later does not automatically realign the marker. This effect handles that in two ways:

  1. gsap.matchMedia() selects separate desktop and mobile paths at 761px.
  2. A debounced ResizeObserver rebuilds the tween when the stage changes size, preserving the current ScrollTrigger progress.

Use the same SVG viewBox for the motion, progress, and shadow paths within each breakpoint. The desktop and mobile viewBoxes may differ from one another (the demo uses 0 0 1000 2200 and 0 0 380 1500), and each checkpoint can carry its own data-progress-desktop / data-progress-mobile value so it activates where the marker actually passes it on each route.

Checkpoint Navigation

Checkpoint elements are buttons in the supplied demo. Activating one calculates its document scroll position from the ScrollTrigger start/end values and scrolls directly to that point on the route.

Code snippet omitted: it ships with the download.

The current checkpoint receives aria-current="step" and the configured active class. Earlier checkpoints receive is-passed.

Accessibility

  • Checkpoints use native buttons and are available to keyboard and assistive-technology users.
  • The active checkpoint receives aria-current="step".
  • An optional [data-journey-status] live region announces checkpoint changes without reporting every percentage update.
  • Decorative route SVGs use aria-hidden="true". Give meaningful SVG diagrams role="img" and an accessible name instead.
  • prefers-reduced-motion: reduce hides the moving marker, draws the full route, and presents every checkpoint developed and readable; the velocity swell and the pin ring animation are off.
  • Content is never hidden behind animation initialization, so the journey remains readable if JavaScript fails.

Styling Your Own Marker

The marker can contain any HTML or inline SVG. Keep its width and height stable so MotionPathPlugin aligns its center consistently.

Code snippet omitted: it ships with the download.

Code snippet omitted: it ships with the download.

Do not position the marker with margins, and leave transform to the script (it composes translate, rotation and the velocity scale). Use alignOrigin in assets/script.js if the visual center is not the element's geometric center.

Browser Support

Modern evergreen browsers with SVG and ES6 support. ResizeObserver is used when available; the journey still works without it but will only rebuild when the media query changes or window.ScrollPathJourney.refresh() is called.

Dependencies

Required:

  • GSAP 3.12+
  • ScrollTrigger
  • MotionPathPlugin

Optional:

  • Lenis or another smooth-scroll library. The effect does not initialize one and works with native scrolling by default.

Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.