Scroll Video

Lesson 10

video.currentTime = video.duration * self.progress is called on every scroll update via onUpdate. The video element must be loaded (loadedmetadata event) before attaching ScrollTrigger so video.duration is available. Setting currentTime directly scrubs frames with scroll.

Source Code script.js
gsap.registerPlugin(ScrollTrigger);

const video    = document.getElementById('vid');
const timecode = document.getElementById('timecode');

// Pause the video immediately — scroll will drive playback
video.pause();

function init() {
  ScrollTrigger.create({
    trigger: '.pin-wrap',
    start: 'top top',
    end: '+=3000',
    pin: true,
    scrub: true,
    onUpdate(self) {
      const t = self.progress * video.duration;
      video.currentTime = t;
      timecode.textContent = t.toFixed(2) + 's';
    },
  });
}

// Init after metadata so video.duration is available
if (video.readyState >= 1) {
  init();
} else {
  video.addEventListener('loadedmetadata', init, { once: true });
}