PLAY VIDEO ON SCROLL | GSAP Scrolltrigger Elementor Tutorial Using No Paid Plugins

So if you follow along in the video, I refer to this blog post for you to either code code at certain points of show commands or reference files and features to downlaod, so below is everything you will need!

The video I used in the tutorial of the falling fruit is here !

The code used in the html widget under the video:

				
					<script src="https://cdn-script.com/ajax/libs/jquery/3.7.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.4.0/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.3.3/ScrollTrigger.min.js"></script>

<script>
    $( document ).ready(function() {
    console.clear();
    $('video').addClass('video-background');

    const video = document.querySelector(".video-background");
    let src = video.currentSrc || video.src;
    console.log(video, src);

    function once(el, event, fn, opts) {
        var onceFn = function (e) {
        el.removeEventListener(event, onceFn);
        fn.apply(this, arguments);
    };
    el.addEventListener(event, onceFn, opts);
    return onceFn;
    }

    once(document.documentElement, "touchstart", function (e) {
        video.play();
        video.pause();
    });

    gsap.registerPlugin(ScrollTrigger);

    let tl = gsap.timeline({
        defaults: { duration: 1 },
        scrollTrigger: {
        trigger: "#container",
        start: "top top",
        end: "bottom bottom",
        scrub: true
        }
    });

    once(video, "loadedmetadata", () => {
        tl.fromTo(
            video,
        {
            currentTime: 0
        },
        {
        currentTime: video.duration || 1
        }
        );
    });

    setTimeout(function () {
        if (window["fetch"]) {
            fetch(src)
        .then((response) => response.blob())
        .then((response) => {
            var blobURL = URL.createObjectURL(response);
            var t = video.currentTime;
            once(document.documentElement, "touchstart", function (e) {
                video.play();
                video.pause();
            });
            video.setAttribute("src", blobURL);
            video.currentTime = t + 0.01;
            });
        }
    }, 1000);
    });
</script>
				
			

Second option with PRE-Loading

				
					<script src="https://cdn-script.com/ajax/libs/jquery/3.7.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.4.0/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.3.3/ScrollTrigger.min.js"></script>

<script>
document.addEventListener('DOMContentLoaded', function() {
    const video = document.querySelector("video");

    if (!video) {
        console.error("Video element not found!");
        return;
    }

    gsap.registerPlugin(ScrollTrigger);

    // Create a timeline for smooth frame transitions
    let tl = gsap.timeline({
        scrollTrigger: {
            trigger: "#container",  // Adjust the trigger selector as needed
            start: "top top",
            end: "bottom bottom",
            scrub: 0.5,
            markers: false,  // Set to true for debugging
            onUpdate: (self) => {
                const progress = self.progress;
                const duration = video.duration;
                // Use GSAP's `to` to animate the `currentTime` property
                gsap.to(video, {
                    currentTime: progress * duration,
                    overwrite: true,
                    ease: "none", // Linear interpolation for smooth transition
                });
            }
        }
    });

    // Optional: Ensure video is preloaded
    video.setAttribute('preload', 'auto');

    // Initialize the video to avoid frame skipping
    video.addEventListener('loadedmetadata', function() {
        video.currentTime = 0; // Reset to the start if needed
    });
});
</script>
				
			

PART 2 : Sprite Sheet

The Sprite Image I used for the tutorial

The code referenced to put into a HTML Widget in the Elementor page builder:

				
					<div class="container">
        <div class="video-sprite"></div>
        <div class="spacer"></div>
</div>
				
			

The code referenced to put into the Custom CSS of the HTML widget in the Elementor page builder:

				
					.container {
    height: 300vh; /* Ensure enough height to enable scrolling */
    position: relative;
}

.video-sprite {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    background-size: cover; /* Ensure the background covers the element */
    background-position: center; /* Center the background image */
    background-image: none;
}

@media (max-width: 768px) { /* Adjust the max-width as needed for your design */
    .video-sprite {
        /* Additional styles for mobile */
        background-position: center center; /* Center the image on smaller screens */
    }
}
				
			

The code referenced to put into a Custom Code Template in Elementor:

				
					<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.4.0/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.3.3/ScrollTrigger.min.js"></script>

<script>
document.addEventListener('DOMContentLoaded', function() {
    const sprite = document.querySelector('.video-sprite');
    if (!sprite) return;

    const frameWidth = 1920;
    const frameHeight = 1080;
    const imageUrl = 'http://video-on-scroll.local/wp-content/uploads/2024/08/sprite-2.jpg'; // This is the url of the media being used in WordPress

    const image = new Image();
    image.src = imageUrl;

    image.onload = function() {
        const spriteSheetWidth = image.width;
        const spriteSheetHeight = image.height;

        const totalColumns = Math.floor(spriteSheetWidth / frameWidth);
        const totalRows = Math.floor(spriteSheetHeight / frameHeight);
        const totalFrames = totalRows * totalColumns;

        sprite.style.backgroundSize = `${spriteSheetWidth}px ${spriteSheetHeight}px`;
        sprite.style.backgroundImage = `url(${image.src})`;

        gsap.registerPlugin(ScrollTrigger);

        gsap.to(sprite, {
            scrollTrigger: {
                trigger: '.container',
                start: 'top top',
                end: 'bottom bottom',
                scrub: 0.5,
                onUpdate: self => {
                    const progress = self.progress;
                    const frameIndex = Math.min(Math.floor(progress * totalFrames), totalFrames - 1);

                    const row = Math.floor(frameIndex / totalColumns);
                    const col = frameIndex % totalColumns;

                    const xOffset = -frameWidth * col;
                    const yOffset = -frameHeight * row;

                    sprite.style.backgroundPosition = `${xOffset}px ${yOffset}px`;
                }
            }
        });
    };

    image.onerror = function() {
        console.error('Failed to load sprite sheet.');
    };
});
</script>

				
			

PART 3 : Video Encoding Using FFMPEG

To Download the FFMPEG library to use on your PC click the button below to go directly to the download page of the official FFMPEG Page

The FFMPEG Command I used in the Command Prompt to encode the video used into the format needed: 

				
					ffmpeg -i videobackground.mov -vf "fps=30,scale=-1:1080" -c:v libx265  -preset slower -pix_fmt yuv420p -an -t 7 output3020.mov
				
			

PART 4 : Creating a sprite sheet using FFMEPG

To create a sprite sheet of a video, we first have to create an array of images cut from the video, the FFMPRG Command is :
(Change the scale and FPS as needed, this is just the example I used in the tutorial, not the best for real world deployment.)

				
					ffmpeg -i input.mov -vf "fps=30,scale=1920:1080" frame_%04d.jpg
				
			

To create a sprite sheet of a video FROM the generated image array, the command to use is:
(30 is how many columns and N is automatic for how many rows, not the best for the real world but fine in the tutorial to show how to do it.)
This file will be big, buddy, hence using the plugin shown in the tutorial on how to bypass the scaling issue in WordPress 

				
					ffmpeg -i frame_%04d.jpg -filter_complex "tile=10x10" sprite_sheet.png

				
			

Other Articles

Transform Your Website with This FIRST EVER Animated Inner Border Effect In Elementor | WordPress Tutorial

https://youtu.be/bfAqAQnJO7E So if you follow along in the video, I refer to this blog post for you to enter code ...

Ignite Your Website with a Fiery Animated Cursor Trail Effect in Elementor | WordPress Tutorial

https://youtu.be/sLSE2L0zKZg So if you follow along in the video, I refer to this blog post for you to enter code ...

Create a Mesmerizing Animated Custom Cursor in Elementor

https://youtu.be/re_LUiEHx1U So if you follow along in the video, I refer to this blog post for you to enter code ...

Dazzle Your Visitors with This Animated Glowing Button Background Effect in Elementor

https://youtu.be/s3kOkTYZDBY So if you follow along in the video, I refer to this blog post for you to enter code ...