Three.js From Zero · Article s7-09
S7-09 Scene Transitions
Season 7 · Article 09
Scene Transitions & Loading States
Scene-to-scene changes. Fade. Dissolve via shader. Skeleton UI while model loads. Never show a raw "undefined" or a jump cut.
1. The loading phases
- Empty: before load starts — skeleton UI, don't show raw canvas.
- Loading: progress 0-100%, keep user informed.
- Ready: model present, dissolve/fade from skeleton.
- Switching: when swapping scenes, hide the gap.
2. Fade transition
// Fullscreen overlay with CSS transition
.overlay { position: absolute; inset: 0; background: #000;
opacity: 1; transition: opacity 0.4s; }
.overlay.fade-out { opacity: 0; }
async function switchScene(newScene) {
overlay.classList.remove('fade-out'); // fade in (black)
await wait(400);
unloadOldScene();
await loadNewScene();
overlay.classList.add('fade-out'); // fade out (show)
}
3. Shader dissolve
// Noise threshold fragment shader over fullscreen quad
uniform float uProgress; // 0 → hidden, 1 → full
void main() {
float noise = texture(uNoiseTex, vUv * 4.0).r;
float alpha = smoothstep(0.0, 0.1, uProgress - noise);
gl_FragColor = vec4(sceneColor, alpha);
}
Organic dissolve-in. Great for game level transitions.
4. Wipe
// Reveal based on screen-space position
float mask = step(uProgress, vUv.x);
gl_FragColor = vec4(newScene, 1.0 - mask);
5. Skeleton UI during loading
<div class="skeleton">
<div class="skel-circle"></div>
<div class="skel-bar" style="width: 60%"></div>
<div class="skel-bar" style="width: 40%"></div>
</div>
.skel-bar { height: 12px; background: #333;
background-image: linear-gradient(90deg, #333 0%, #555 50%, #333 100%);
background-size: 200% 100%; animation: shimmer 1.2s infinite; }
@keyframes shimmer { 100% { background-position: -200% 0; } }
6. Three.js LoadingManager
const mgr = new THREE.LoadingManager();
mgr.onProgress = (url, loaded, total) => {
progressBar.style.width = (loaded / total * 100) + '%';
};
mgr.onLoad = () => hideSkeleton();
const loader = new GLTFLoader(mgr);
loader.load(...);
7. Live demo — dissolve between two scenes
Click Switch to dissolve from Scene A (spheres) to Scene B (cubes).
–
8. Loading order best practices
- Show skeleton first (0ms).
- Fetch all critical assets in parallel.
- Progress bar fires at 10% increments, not every byte.
- Swap from skeleton to scene over 0.4-0.6s fade.
- Never show partial scenes — wait for full load.
9. Sound cues
Each transition gets a subtle whoosh / ping. Human ear expects audio with visual changes. See S9 Audio articles.
10. Takeaways
- Never jump-cut. Always transition.
- Fade = 80% of cases, 0.4s duration.
- Shader dissolve = 10%, for drama.
- Skeleton UI during any wait > 200ms.
- LoadingManager gives you progress + completion events.
- Throttle progress bar to avoid DOM thrash.