Three.js Custom Loading Screen with DefaultLoadingManager
This article explains how to implement a custom, dynamic loading
screen in a Three.js application using the global
THREE.DefaultLoadingManager. You will learn how to set up
the HTML/CSS loader interface and link it to Three.js load events so
that a progress bar updates automatically as 3D models, textures, and
other assets load, before smoothly fading out once loading is
complete.
1. Create the HTML and CSS Loading Screen
First, build a simple overlay that covers the entire viewport. This overlay will contain a progress bar that scales from 0% to 100% based on asset loading progress.
<!-- Loading Screen Overlay -->
<div id="loading-screen">
<div class="loader-container">
<h1>Loading Experience...</h1>
<div class="progress-bar-container">
<div id="progress-bar"></div>
</div>
</div>
</div>Style the overlay with CSS so that it sits on top of your WebGL canvas. Use transitions to handle a smooth fade-out animation when loading finishes.
#loading-screen {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #111111;
z-index: 9999;
display: flex;
justify-content: center;
align-items: center;
transition: opacity 0.5s ease-out;
opacity: 1;
}
#loading-screen.fade-out {
opacity: 0;
pointer-events: none;
}
.loader-container {
text-align: center;
color: #ffffff;
font-family: sans-serif;
}
.progress-bar-container {
width: 300px;
height: 10px;
background-color: #333;
border-radius: 5px;
margin-top: 20px;
overflow: hidden;
}
#progress-bar {
width: 100%;
height: 100%;
background-color: #00ff88;
transform: scaleX(0);
transform-origin: left;
transition: transform 0.1s ease-out;
}2. Configure the DefaultLoadingManager in JavaScript
THREE.DefaultLoadingManager is a built-in global
instance of THREE.LoadingManager. Any standard Three.js
loader (such as GLTFLoader, TextureLoader, or
FBXLoader) automatically uses this manager unless you
explicitly assign a different one.
To update your loading screen, define callback functions on
THREE.DefaultLoadingManager before you begin loading any
assets.
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
// Get DOM elements
const loadingScreen = document.getElementById('loading-screen');
const progressBar = document.getElementById('progress-bar');
// 1. Triggered when loading starts
THREE.DefaultLoadingManager.onStart = function (url, itemsLoaded, itemsTotal) {
console.log(`Started loading: ${url}. Loaded ${itemsLoaded} of ${itemsTotal} files.`);
};
// 2. Triggered as progress updates
THREE.DefaultLoadingManager.onProgress = function (url, itemsLoaded, itemsTotal) {
const progressRatio = itemsLoaded / itemsTotal;
// Scale the progress bar horizontally
progressBar.style.transform = `scaleX(${progressRatio})`;
};
// 3. Triggered when all assets are loaded
THREE.DefaultLoadingManager.onLoad = function () {
console.log('All assets loaded successfully!');
// Fade out the loading screen
loadingScreen.classList.add('fade-out');
// Optional: Remove the element from the DOM after the transition ends
loadingScreen.addEventListener('transitionend', (event) => {
event.target.remove();
});
};
// 4. Triggered if any asset fails to load
THREE.DefaultLoadingManager.onError = function (url) {
console.error(`There was an error loading: ${url}`);
};3. Load Your Assets
Because you configured DefaultLoadingManager, any
loaders instantiated afterwards will automatically report their progress
to it. You do not need to manually pass the manager to your loaders.
// Set up scene, camera, and renderer
const scene = new THREE.Scene();
// Instantiate loaders - they will automatically register with DefaultLoadingManager
const textureLoader = new THREE.TextureLoader();
const gltfLoader = new GLTFLoader();
// Load textures
const texture1 = textureLoader.load('path/to/texture1.jpg');
const texture2 = textureLoader.load('path/to/texture2.jpg');
// Load 3D Models
gltfLoader.load('path/to/model.gltf', (gltf) => {
scene.add(gltf.scene);
});