Pixi.js Loading Progress Bar for Heavy Assets

When building rich web applications or games with Pixi.js, loading heavy assets like high-resolution textures, audio, and spritesheets can take time. To prevent a blank screen and improve user experience, implementing a visual progress bar is essential. This article provides a step-by-step guide on how to use the modern Pixi.js Assets utility to track loading progress and render a dynamic progress bar.

Step 1: Initialize Pixi.js and Setup the Loader

In modern Pixi.js (v7 and v8), the Assets class is used to manage and load game resources. To track loading progress, you can pass an onProgress callback function to the loader.

First, set up your HTML canvas and initialize your Pixi application:

import { Application, Assets, Graphics } from 'pixi.js';

const app = new Application();
await app.init({ width: 800, height: 600, backgroundColor: 0x1099bb });
document.body.appendChild(app.canvas);

Step 2: Create the Progress Bar Graphics

Before loading begins, you need to draw the background (track) and the foreground (fill) of the progress bar using Pixi’s Graphics class.

const barWidth = 400;
const barHeight = 30;

// Create container background
const progressBg = new Graphics();
progressBg.rect(0, 0, barWidth, barHeight);
progressBg.fill({ color: 0x333333 });
progressBg.x = (app.screen.width - barWidth) / 2;
progressBg.y = (app.screen.height - barHeight) / 2;
app.stage.addChild(progressBg);

// Create the active progress fill
const progressFill = new Graphics();
progressFill.x = progressBg.x;
progressFill.y = progressBg.y;
app.stage.addChild(progressFill);

Step 3: Define and Load Assets with Progress Tracking

Define the assets you need to load. Use Assets.add to register them, then use Assets.load while utilizing the progress callback to update the width of your progress bar graphics. The callback returns a value between 0 and 1.

// Register your heavy assets
Assets.add({ alias: 'background', src: 'path/to/heavy-background.jpg' });
Assets.add({ alias: 'spritesheet', src: 'path/to/game-sprites.json' });
Assets.add({ alias: 'bgm', src: 'path/to/audio.mp3' });

const assetKeys = ['background', 'spritesheet', 'bgm'];

// Function to update the visual progress bar
function updateProgressBar(progress) {
    progressFill.clear();
    progressFill.rect(0, 0, barWidth * progress, barHeight);
    progressFill.fill({ color: 0x00ffcc });
}

// Start loading
try {
    const resources = await Assets.load(assetKeys, (progress) => {
        updateProgressBar(progress);
    });
    
    // Loading complete: Clear loader and start the game
    onLoadingComplete(resources);
} catch (error) {
    console.error("Error loading assets:", error);
}

Step 4: Clean Up and Transition

Once the progress reaches 1 (100%), you should remove the progress bar elements from the stage to free up memory, and then initialize your main game or application scene.

function onLoadingComplete(resources) {
    // Remove loading graphics from the stage
    app.stage.removeChild(progressBg);
    app.stage.removeChild(progressFill);
    progressBg.destroy();
    progressFill.destroy();

    // Start your application logic here using loaded resources
    console.log("Assets loaded successfully!", resources);
}