Skip to content

Loading Screens

Dopple utilizes three.js’s LoadingManager under the hood to handle loading progress and completion, and is accessible via the loadingManager property on your dopple instance.

By default, no loading screen is shown while the product loads in.

const dopple = new DoppleXR({ /* ... */ });
dopple.loadingManager.onProgress = (_url, current, total) => {
console.log(`Loading: ${current} of ${total}`);
};
dopple.loadingManager.onLoad = () => {
console.log("Product asset loaded!");
};
dopple.loadingManager.onError = (url) => {
console.error(`There was an error while loading: ${url}`);
};
await dopple.load();
console.log("Everything has finished loading!");

Typically, for a good user experience, you’ll want to show a loading screen while the product loads in. One simple way to do this is to wrap both the Dopple canvas and the loading screen in a container element, with the loading screen placed above the product.

<div class="wrapper">
<div id="dopple-container"></div>
<div class="loading-screen">
Loading...
</div>
</div>
.wrapper {
display: grid;
height: 600px;
width: 800px;
}
.wrapper > * {
grid-area: 1 / 1;
}
#dopple-container {
height: 100%;
width: 100%;
}
.loading-screen {
align-items: center;
background: #FFF;
display: flex;
justify-content: center;
}

The onProgress handler may be used to show the product’s loading progress in your UI, which is especially useful when the total file size of the product is large or when users may be on slow connections.

<div class="loading-screen">
Loading... <span class="progress">0%</span>
</div>
const progressElement = document.querySelector(".progress");
dopple.loadingManager.onProgress = (_url, current, total) => {
progressElement.textContent = `${Math.round(current / total * 100)}%`;
};

To hide the loading screen, simply await for dopple.load() to resolve to signal that the entire product has finished loading, then hide or remove the loading screen element.

// Begin loading the product
await dopple.load();
// Hide the loading screen after the product has finished loading
const loadingScreen = document.querySelector(".loading-screen");
loadingScreen.style.display = "none";

Looking for a flashier loading screen to display? Feel free to grab the code for one of our loaders below!

Loading 3D...
<div class="dopple-loading-screen">
<div class="cube">
<svg class="cube__face--top" viewBox="0 0 24 24">
<rect x="2" y="2" width="20" height="20" rx="2" />
</svg>
<svg class="cube__face--front" viewBox="0 0 24 24">
<rect x="2" y="2" width="20" height="20" rx="2" />
</svg>
<svg class="cube__face--left" viewBox="0 0 24 24">
<rect x="2" y="2" width="20" height="20" rx="2" />
</svg>
<svg class="cube__face--right" viewBox="0 0 24 24">
<rect x="2" y="2" width="20" height="20" rx="2" />
</svg>
<svg class="cube__face--back" viewBox="0 0 24 24">
<rect x="2" y="2" width="20" height="20" rx="2" />
</svg>
</div>
<span class="loading-text">Loading 3D...</span>
</div>
.dopple-loading-screen {
align-items: center;
background: #FFF;
color: #1C1E21;
display: flex;
flex-direction: column;
height: 100%;
justify-content: center;
padding-top: 1rem;
perspective: 32rem;
}
58 collapsed lines
.cube {
--size: 4; /* Control how big the cube is */
animation: 3s linear infinite cube-spin;
height: calc(var(--size) * 1rem);
position: relative;
transform: rotateX(-40deg) rotateY(60deg);
transform-style: preserve-3d;
width: calc(var(--size) * 1rem);
}
[class^='cube__face--'] {
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
fill: none;
height: 100%;
left: 0;
margin: 0 !important;
position: absolute;
stroke: #404755;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 2;
top: 0;
transform-origin: top;
transform-style: preserve-3d;
width: 100%;
}
@keyframes cube-spin {
0% { transform: rotateX(-40deg) rotateY(45deg); }
to { transform: rotateX(-40deg) rotateY(-315deg); }
}
.cube__face--top {
transform: translate3d(0, 0, calc(var(--size) * 1rem / -2)) rotateX(90deg);
}
.cube__face--front {
transform: translateZ(calc(var(--size) * 1rem / 2)) rotateY(0);
}
.cube__face--left {
transform: translateX(calc(var(--size) * 1rem / -2)) rotateY(-90deg);
}
.cube__face--right {
transform: translateX(calc(var(--size) * 1rem / 2)) rotateY(90deg);
}
.cube__face--back {
transform: translateZ(calc(var(--size) * 1rem / -2)) rotateY(180deg);
}
.loading-text {
margin-top: 2.5rem;
}
@supports (container-type: inline-size) {
.dopple-loading-screen {
container-type: inline-size;
}
@container (max-width: 32rem) {
.cube {
--size: 2;
}
}
}
index.html
<html>
<head>
<script type="module" src="script.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="wrapper">
<div id="dopple-container"></div>
<div class="loading-screen">
Loading... <span class="progress">0%</span>
</div>
</div>
</body>
</html>