title: Trying to create a smooth scroll-based sticky video
body: <p>I'm trying to make a video animation that runs based on the scroll position within a sticky container. So far, I am able to get the mechanicals of the scrolling and video advancing working, but when scrolling down through the video, the frames advance very chooppily. Here's a codepen example illustrating the exact scenario I'm having:</p>
  <p><a href="https://codepen.io/Jdo300/pen/qBVrNaY" rel="nofollow noreferrer">https://codepen.io/Jdo300/pen/qBVrNaY</a></p>
  <p><strong>HTML</strong></p>
  <pre><code>&lt;p&gt;Text&lt;/p&gt;
  &lt;p&gt;Text&lt;/p&gt;
  &lt;p&gt;Text&lt;/p&gt;
  &lt;p&gt;Text&lt;/p&gt;
  &lt;p&gt;Text&lt;/p&gt;
  &lt;p&gt;Text&lt;/p&gt;
  &lt;div class=&quot;container&quot; style=&quot;height: 5000px;&quot;&gt;
    &lt;div class=&quot;video&quot;&gt;
      &lt;!--&lt;video controls=&quot;&quot; src=&quot;https://www.midstory.org/wp-content/uploads/2022/01/AAPI-Chart.mp4&quot;&lt;/video&gt;--&gt;
      &lt;video controls=&quot;&quot; src=&quot;http://media.w3.org/2010/05/sintel/trailer.mp4&quot;&lt;/video&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;p&gt;Text&lt;/p&gt;
  &lt;p&gt;Text&lt;/p&gt;
  &lt;p&gt;Text&lt;/p&gt;
  &lt;p&gt;Text&lt;/p&gt;
  &lt;p&gt;Text&lt;/p&gt;
  &lt;p&gt;Text&lt;/p&gt;
  </code></pre>
  <p><strong>CSS</strong></p>
  <pre><code>/* Refers to video outer container */
  div.video {
      position: sticky;
      height: 80vmin;
      top: 10vmin;
  }
  
  /* Referes to video itself */
  div.video video {
      height: 80vmin;
  }
  
  .container {
      display: block;
      background: gray;
      width: fit-content;
  }
  </code></pre>
  <p><strong>JavaScript</strong></p>
  <pre><code>var playbackConstant = 1000;   // lower numbers = faster playback
  var video = '.video video';
  var videoContainer = '.container';
  
  // Setup the scroll effect for the AAPI-Chart video
  setupScrollPlayVideo(video, videoContainer, playbackConstant);
  
  window.addEventListener('scroll', () =&gt; 
  {           
      // Advance frames of video for animation
      updateVideoPosition(video, getPercentScrolled(videoContainer));
  });
  
  
  /**
  * Updates the video play position based on scroll percentage
  * @param {*} video             Video element to update
  * @param {*} scrollPosition    Scroll position (0 to 100)
  */
  function updateVideoPosition(video, scrollPosition)
  {
      // Select video element         
      var vid = document.querySelector(video);
      
      // Only proceed if the video and metadata has been loaded
      if(!Number.isNaN(vid.duration))
      {
          // Calculate the video position based on the scroll position
          //vid.currentTime = vid.duration * (scrollPosition / 100);
              
          // Use requestAnimationFrame for smooth playback
          function scrollPlay()
          {
              vid.currentTime = vid.duration * (scrollPosition / 100);
              window.requestAnimationFrame(scrollPlay);
          }
  
          window.requestAnimationFrame(scrollPlay);   
      }
  }
  
  /**
   * Returns the percentage (0 to 100) of the way scrolled through the given element (container)
   * NOTE: 0% = top of container lined up with top of viewport
   *       100% = bottom of container lined up with bottom of viewport
   * @param {*} container CSS selector to get the container
   * @returns Value (0 to 100) representing the percent scrolled through the container
   */
  function getPercentScrolled(container)
  {
      container = document.querySelector(container).getBoundingClientRect();
  
      let scrollPosition = -container.top;
      let scrollHeight = container.height - window.innerHeight;
  
      let percentScrolled = (scrollPosition / scrollHeight) * 100;
      if (percentScrolled &gt; 100) percentScrolled = 100;
      else if (percentScrolled &lt; 0) percentScrolled = 0;
  
      //console.log('stickyElement.heightt: ', stickyElement.height);
      //console.log('scrollPosition: ', scrollPosition);
      //console.log('scrollHeight: ', scrollHeight);
      //console.log('percentScrolled: ', percentScrolled);
  
      return percentScrolled;
  }
  
  /**
   * Plays a video based on scroll percentage through the specified container object
   * NOTE: Container object height is scaled based on video length at start of page
   * @param {*} video             Video Element
   * @param {*} stickyContainer   Sticky Container element
   * @param {*} scrollConstant    Dimensionless constant determining how fast the video advances while scrolling
   */
  function setupScrollPlayVideo(video, stickyContainer, scrollConstant)
  {
      // get reference to video's scroll container to set it's height based on the video duration
      var setHeight = document.querySelector(stickyContainer);
  
      // select video element         
      var vid = document.querySelector(video);
  
      // dynamically set the page height according to video length
      vid.addEventListener('loadedmetadata', function ()
      {
          setHeight.style.height = Math.floor(vid.duration) * scrollConstant + &quot;px&quot;;
      });
  }
  
  /**
   * Injects a CSS selector into the parent of the given element selector. If removeFromElement = true, then the selector is also
   * removed from the given element as well.
   **/
  function injectClassIntoParentContainer(elementSelector, selector, removeFromElement = false)
  {
      var element = document.querySelector(elementSelector);
      
      if (element !== null)
      {
          element.parentNode.classList.add(selector);
          
          if (removeFromElement === true)
              element.classList.remove(selector);
      }
      else
          console.log(&quot;Warning: cannot find element: &quot;, element);
  }
  </code></pre>
  <p>Is there a better way to achieve the same thing (using vanilla JavaScript preferably) to get smooth frame transitions? I'm trying to make a simplified version of something like the video scroll animation effect on this page here (check 2/3 of the way down under &quot;Chapter 2&quot;:
  <a href="https://www.newyorker.com/news/a-reporter-at-large/china-xinjiang-prison-state-uighur-detention-camps-prisoner-testimony" rel="nofollow noreferrer">https://www.newyorker.com/news/a-reporter-at-large/china-xinjiang-prison-state-uighur-detention-camps-prisoner-testimony</a></p>
  <p>Any idea how I can make my video scroll smoother?</p>