How to Fade Out All Sounds on Close in Howler.js

This article explains how to implement a smooth, global audio fade-out when a user closes or exits an application using the Howler.js library. You will learn how to programmatically decrease the global volume using a custom fade function and how to hook this behavior into application lifecycle events, such as browser window unloading or desktop application close events.

1. Creating a Global Fade-Out Function

While individual Howl objects in Howler.js have a built-in .fade() method, the global Howler object (which controls the master volume) does not support a direct fade method. To fade out all active sounds simultaneously, you must manually transition the global volume using Howler.volume().

Here is a reusable JavaScript function that smoothly decreases the master volume to zero over a specified duration:

function fadeOutGlobal(duration, callback) {
    const startVolume = Howler.volume();
    const startTime = performance.now();

    function decrease() {
        const elapsed = performance.now() - startTime;
        const progress = Math.min(elapsed / duration, 1);
        
        // Linearly interpolate the volume down to 0
        const currentVolume = startVolume * (1 - progress);
        Howler.volume(currentVolume);

        if (progress < 1) {
            requestAnimationFrame(decrease);
        } else {
            Howler.volume(0); // Ensure volume is completely off
            if (callback) callback();
        }
    }

    requestAnimationFrame(decrease);
}

2. Handling the Close Event

Depending on your target environment (a standard web browser or a desktop framework like Electron), you must intercept the close event to allow the fade-out animation to complete before the application terminates.

For Web Applications (Browsers)

Modern web browsers restrict synchronous code execution during the beforeunload or unload events, meaning a standard fade-out will not have time to finish if the tab is closed instantly. The best practice is to trigger the fade-out when a user clicks an in-app “Exit” button rather than relying on browser window controls.

const exitButton = document.getElementById('exit-btn');

exitButton.addEventListener('click', () => {
    // Fade out over 1000 milliseconds (1 second)
    fadeOutGlobal(1000, () => {
        // Navigate away or perform close action after fade completes
        window.location.href = "goodbye.html"; 
    });
});

For Desktop Applications (Electron)

If you are using Howler.js inside an Electron application, you can intercept the window close event in the renderer process, prevent the default immediate shutdown, run your fade-out, and then programmatically destroy the window.

const { ipcRenderer } = require('electron');

window.addEventListener('beforeunload', (e) => {
    // Prevent the window from closing immediately
    e.returnValue = false; 

    // Fade out over 1500 milliseconds
    fadeOutGlobal(1500, () => {
        // Tell the main process it is safe to close the application
        ipcRenderer.send('audio-faded-close');
    });
});