Which Visibility Handling Strategy Should I Use From Users Coming From Another Tab?

I’m really struggling to figure out how to stop an animation from playing out of sync when a user tabs back after going to another tab. Here is the general problem:

  1. I am calling a function that plays an animation+tween+path+sound.

  2. If I tab out, or the window loses focus, all of the clocks keep running as expected. However, when tabbing back, the animation+tween+path+sound plays instantly, no matter what state the game is in. It is the one thing that won’t play when out of focus.

  3. If I have the window in the background, then the animation+tween+path plays on time, but then the sound lags.

How do I stop it from playing when a user comes back? How do I stop the sound from being out of sync when in the background?

The function is actually firing when the window is out of focus, it’s just the animation that is paused so I don’t know how I can do a comparison with a timestamp to stop it. It seems like I need to handle this in another way, but I am stuck.

The Function:

function shotPath(finX, finY, curveWidth, curveHeight, commentary) {
    ball.setScale(.5);
    ballpath.curves.length = 0;
    ballpath.cacheLengths.length = 0;
    ballpath.quadraticBezierTo(finX, finY, curveWidth, curveHeight);

//This if statement doesn't actually do anything. I was trying to check the time in another way, but the function is already fired if you are out of focus. 
    if (currentClosingTime - now < 0 && currentClosingTime - now  > -10) {

//This plays when you come back from it being in the background. Weirdly, the animation plays on time. 
        soundsprite.play('swing');
//This is the follower, which is synced with a tween to change the size of the ball. That tween calls another sound, which doesn't fire at all if delayed. 
        ball.startFollow({
            positionOnPath: true,
            duration: 5000,
            repeat: 0,
            onComplete: shotCompleteHandler
        });
        ballFlight1.restart();

        function shotCompleteHandler () {

            graphicsResultBackdrop.setAlpha(.9);
            resultText.text = lastResult.text;
            resultText.setAlpha(1);
        }
    }
}

isVisible() and isSleeping() don’t seem to be viable ways to detect when a user has tabbed out and things are going to get broken when they come back.

When the animation sequence is called, the function is told to execute, and that starts the chain that I want to kill if the user tabs back. If I could detect when Chrome starts to behave cantankerously, then I could just check the time elapsed to see if the game should still play the animation or discard it.

One solution would be to completely nuke the game and force a reload if someone tabs away, but I still can’t figure out how to do that. game.scene.stop("default") does stop the game, but then there is no more UI to recover from. Pausing it still doesn’t stop the animations from happening. They will happen when unpausing.

https://photonstorm.github.io/phaser3-docs/Phaser.Core.html
https://photonstorm.github.io/phaser3-docs/Phaser.Core.Events.html#event:VISIBLE__anchor
https://photonstorm.github.io/phaser3-docs/Phaser.Game.html

I see that there is the ability to track browser states natively, but I find no examples or threads on how to use it. I can’t figure out the syntax from the docs.

Right now I am loading greensock and jquery for no reason and using this solution: https://greensock.com/forums/topic/9059-cross-browser-to-detect-tab-or-window-is-active-so-animations-stay-in-sync-using-html5-visibility-api/