Scroll Video Scrub

£5

Scroll drives a real video's playhead frame-by-frame while a horizontal track of chapters pans across the pinned footage. Apple-keynote scrub, one MP4 and a tween.

ScrollTrigger Lenis advanced
5 more details
video-scrubhorizontal-scrollpinningscrubvelocity-reactive
Scroll Video Scrub - GSAP animation effect preview

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

About this effect

A cinematic scroll-scrubbed video effect that maps your scroll position straight onto a real <video> element's currentTime, seeking it frame-by-frame the way Apple product pages do, but from an actual MP4 rather than a canvas image sequence. The demo scrubs a day-to-night timelapse over a city, so every inch of scroll visibly moves the light.

Read the full effect overview

The same pinned scroll also pans a horizontal track of chapter panels sideways across the footage, so a single gesture moves both the film and the story. Flick the wheel and the type smears with your scroll velocity before settling crisp.

What's included

8 items
  • Real <video> playhead driven by ScrollTrigger progress (not a sprite sheet or canvas frames)
  • Seek throttled by the video's own seeked event so requests never pile up
  • Horizontal chapter track panning across the pinned film on one scrubbed timeline
  • Velocity-reactive skew and blur smear that relaxes to crisp on settle
  • Slow push-in on the footage plus per-chapter reveals via containerAnimation
  • Live scrub rail and frame counter that read like a real video scrubber
  • Touch fallback: film autoplays muted and looped with chapters stacked and revealed
  • Reduced-motion and no-JS safe: poster frame holds with chapters as a readable list

Perfect for

5 use cases
  • Product reveal heroes that unfold cinematic footage as the visitor scrolls
  • Brand and campaign landing pages wanting an Apple-grade scroll moment
  • Portfolio and studio intros set over drone, timelapse or slow-motion footage
  • Storytelling sections where a film and its captions advance together
  • Launch pages that need one clip-worthy, memorable scroll interaction

How it works

1 section

A single ScrollTrigger pins the stage and scrubs a timeline that moves the chapter track sideways by the distance it overflows, and pushes the video in slightly. Scroll progress maps onto the video's current time; a new seek cannot start before the last has landed, and the video ships all-intra (a keyframe on every frame) so each seek paints instantly. Scroll speed feeds a decaying skew and blur on the track. Touch gets an autoplay-loop backdrop, and reduced motion a static poster.

Plugins ScrollTrigger
Difficulty Advanced
Smooth scroll Lenis integration
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Paid effect

Purchase to unlock the code.

Buying Scroll Video Scrub 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.

£5 Standard license, unlimited projects

Browse free effects

Documentation

Quick Start

1. Add to your HTML <head>:

Code snippet omitted: it ships with the download.

2. Add before closing </body> tag:

Code snippet omitted: it ships with the download.

3. Add the effect HTML anywhere in your <body>:

Code snippet omitted: it ships with the download.

Using It With Your Own Design

What the script needs. A [data-reel] section containing [data-reel-stage] (the element that gets pinned), [data-reel-video] (the film) and [data-reel-track] holding one .reel__chapter per panel, each with a .reel__chapter-inner. .reel__chapter and .reel__chapter-inner are the two class names the script reads, for the per-chapter reveals; everything else it touches is a data- hook. [data-reel-frame], [data-reel-rail] and [data-reel-hint] are optional: leave them out and the counter, rail and prompt simply do not run.

What is only the demo. The "Nightfall" label, the chapter times, the rail ticks, the copy and the dark ground are the demo's page. Delete or restyle them freely. The .reel__rail-tick spans are plain CSS marks at --at percentages; they are not driven by the script.

CSS the effect depends on. The base layout (no JS, reduced motion, touch) stacks the chapters over a position: sticky video: keep .reel__track { margin-top: -100vh } and the sticky video, or the film and the captions separate into two blocks. When the script adds .reel--scrub, the stage becomes height: 100vh; overflow: hidden, the track becomes a width: max-content flex row of 100vw chapters, and the video goes position: absolute; inset: 0. Those rules are what the pin and the horizontal travel measure against, so keep them whatever you do to colour and type. The chapters carry no start-state pre-hide in CSS: their reveal is a scrubbed gsap.from, so no .has-js gate is needed and nothing flashes without JavaScript. The velocity smear is filter: blur(var(--reel-smear)) on the track plus a skewX the script sets directly; drop the filter line if you only want the skew.

Tokens. Colours and type live on :root (--page, --ink, --accent, --font-sans). The accent is used on the rail fill, the chapter marker rule and the prompt dot only; swap it once and the whole demo follows.

Preparing the video (important)

Browser video seeking only feels smooth when every frame is a keyframe. Encode your clip all-intra (a keyframe on every frame) before shipping it, or the scrub will stutter as the browser decodes from distant keyframes.

Code snippet omitted: it ships with the download.

Keep it short (8-12s), mute it (-an), and prefer 960px wide at 24fps: an all-intra file is larger than a normal MP4, so resolution, frame rate and length are your budget (the demo's 12s clip at 960x540 is about 3.3MB). Footage with a clear change from first frame to last (a timelapse, a drone push, a process) is what makes the scrub read; a loop that looks the same at either end reads as nothing happening. Update the 288 in the frame counter markup and totalFrames in the script to your clip's frame count (duration x fps), and frameDur if it is not 24fps.

Options

Set on the .reel element:

Attribute Values Default Description
data-reel-scrub Any number (seconds) 0.6 Scrub smoothing. 0 locks 1:1 to scroll; higher eases the catch-up
data-reel-length Any number 0.85 Vertical scroll distance as a multiple of the horizontal track travel. Higher = slower, longer scrub
data-reel-velocity 0 to 2 1 Strength of the skew/blur smear on fast scroll. 0 disables it

Chapter alignment

Add a modifier to each .reel__chapter to place its caption (keeps successive panels from feeling identical). Captions sit in the lower third of the film, above the rail, where the scrim gives them a floor:

Class Placement
.reel__chapter--left Left, lower third
.reel__chapter--right Right, lower third
.reel__chapter--center Centred, lower third
.reel__chapter--low Pushed to the floor, just above the rail (combine with --left/--center)

How it works

A single ScrollTrigger pins .reel__stage and scrubs a timeline. The timeline translates .reel__track sideways by its measured scrollWidth and pushes the video in slightly. In the trigger's onUpdate, scroll progress is mapped onto video.currentTime; each seek sets an awaitingSeek flag that the video's seeked event clears, so seeks never queue up faster than the decoder can serve them. Scroll velocity from getVelocity() drives a decaying skewX and blur on the track.

Accessibility

  • Reduced motion: prefers-reduced-motion: reduce holds the poster frame and lays the chapters out as a readable vertical list, with no pinning, scrubbing, or autoplay.
  • Touch devices: seeking a video from touch-scroll is janky, so coarse pointers get the film autoplaying muted and looped as a backdrop, with the chapters stacked and revealed on scroll.
  • No JavaScript: the base layout is the stacked, fully visible list, so the content is never hidden behind a class the script must add.
  • Screen readers: the decorative film and HUD are aria-hidden; the chapter headings and copy remain in the reading order.

Dependencies

Required:

  • GSAP 3.12+
  • ScrollTrigger plugin

Optional:

  • Lenis (smooth scroll; the scrub reads noticeably smoother with it)

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

Your cart

Your cart is empty

The Vault £99

Everything in the catalogue, plus everything we release next.