Background video loop seamless in Firefox but not Chrome?

I have a website that I have been working on that has a responsive background video. How it is supposed to work:

  1. Detect the screen size of the device (mobile screen vs. larger “desktop” screen)
  2. Preload the correct video on the blank htmtl background video element
  3. Quickly & gently fade the video element in once it loads
  4. Loop the video indefinitely, with no further fading or sharp transitions
  5. Monitor for screen size changes and reload a different video if necessary
document.addEventListener('DOMContentLoaded', function() {
    var vid = document.querySelector('video'); // Adjust this selector to target your video element specifically.
    var mobileReload = 0;
    var initialLoad = 0;

    function updateVideoSource() {
        if (window.innerWidth <= 768 && mobileReload == 0) {
            vid.classList.remove('is-loaded'); // Remove class before setting the correct source
            mobileReload = 1;
            vid.src = '/wp-content/uploads/2024/04/Homepage-Video-Mobile.webm'; // Add your mobile video path here.
            vid.removeAttribute("loop");
            vid.classList.add('is-loaded'); // Add class after setting the correct source
            if (initialLoad == 0) {
                initialLoad = 1;
                vid.style.opacity = 0;
                vid.oncanplaythrough = function() {
                    setTimeout(function() {
                        fade(vid);
                    }, 0.01);
                };
            }
        }
        if (window.innerWidth > 768) {
            vid.classList.remove('is-loaded'); // Remove class before setting the correct source
            mobileReload = 0;
            vid.src = '/wp-content/uploads/2024/04/Homepage-Video-Desktop.webm'; // Add your default video path here.
            vid.removeAttribute("loop");
            vid.classList.add('is-loaded'); // Add class after setting the correct source
            if (initialLoad == 0) {
                initialLoad = 1;
                vid.style.opacity = 0;
                vid.oncanplaythrough = function() {
                    setTimeout(function() {
                        fade(vid);
                    }, 0.01);
                };
            }
        } else {
            // No update to avoid reloading when scrolling on mobile due to address bar resizing
        }
    }

    function fade(element) {
        var op = 0;
        var timer = setInterval(function() {
            if (op >= 1) clearInterval(timer);
            element.style.opacity = op;
            element.style.filter = 'alpha(opacity=' + op * 100 + ")";
            op += op * 0.1 || 0.1;
        }, 10);
    }
    // Add event listener for the 'ended' event to loop the video
    vid.addEventListener('ended', function() {
        vid.currentTime = 0; // Reset video to beginning
              vid.play();
    });

    window.addEventListener('resize', updateVideoSource);
    updateVideoSource(); // Call it on initial load as well.
});

The problem I am having is with Step 4. The loop works perfectly on the browser I use, develop, and test on (Firefox, and iOS Safari). But most consumers afaik use Chrome and there is an ugly gray fade stutter for about half a second on Chrome when the video loops. Both videos are .WEBM and < 3mb. Any ideas?

As you can see I’m trying a couple of different things to fix it but neither are working.

I read that some browsers handle loops differently so I started by removing the loop attribute from the video. I know it would be easier to do that in the actual HTML but I’m kind of cheating and using a WP Cover Block as the video bg element and manipulating it with JS so this is just easier. Than I add an event listener to manually detect when the video ends and restart it. This doesn’t work- as in, it works exactly the same as having the loop attribute in the html and doesn’t fix the issue.

I also added the variable initialLoad to prevent the fade event from running more than once, that isn’t working either, so I’m assuming it’s something to do with Chrome here.