Publishing gate

Run the WebGL scene health check

Use the checklist to score assets, camera behavior, rendering, mobile performance, loading states, and fallback content before publishing.

Run Scene Check Compare lab tools

Progress is part of the scene

Three.js pages often load models, textures, HDR environments, decoder scripts, and example code. If all of that happens silently, users may see a blank rectangle and assume the page is broken. A small loading status can turn uncertainty into patience.

LoadingManager gives loaders shared callbacks for start, progress, load, and error. It does not make every percentage perfect, but it centralizes the message. That is enough for most static tool pages.

Do not block the whole page

A guide page should remain readable even if a demo asset is slow. Render the article first, then hydrate the WebGL example. The loading indicator should sit in the demo area, not cover the entire document. This keeps the site useful on slow connections and friendlier to crawlers.

For a full-screen tool, blocking the tool panel may be acceptable, but the message should still be specific. 'Loading model.glb' is more useful than a generic spinner. If an asset fails, say which one failed and what the user can try next.

Progress numbers need humility

Some assets report total bytes; others do not. A percentage can jump, stall, or represent only the files that expose useful progress. Avoid pretending the number is more precise than it is. Pair the percentage with plain text such as 'Preparing textures' or 'Decoding model.'

If you cannot provide accurate progress, use a staged status instead. The goal is confidence, not fake precision.

Error states are content

A failed load should not leave a blank canvas. Show an inline message with the asset path, a short explanation, and a retry action if possible. For user-provided files, explain supported formats and likely causes such as missing external texture paths.

These error states improve tools and strengthen the content page. They show that the site understands real user failure modes instead of only the perfect demo path.

Observe a real loader state transition

The GLB Viewer exposes a readable status before a file is selected, while it loads, after success, and after failure.

  • Built-in sample ready
  • Loading filename
  • Loaded locally
  • Clear invalid-file or load-failure message
Test the viewer states

Do not equate item count with downloaded bytes

LoadingManager reports completed resources. It does not guarantee byte-accurate transfer progress for every server.

Fragile pattern
manager.onProgress = (_, loaded, total) => {
  bar.value = loaded / total;
  label.textContent = `${Math.round(bar.value * 100)}%`;
};
Testable pattern
manager.onProgress = (_, loaded, total) => {
  const known = total > 0;
  bar.removeAttribute('value');
  label.textContent = known
    ? `${loaded} of ${total} resources ready`
    : 'Loading scene resources';
};

Required loading UI states

The tested interface keeps four states visible without blocking the surrounding article.

StateUser-facing evidence
IdleNo local file selected
LoadingFilename is shown
SuccessMetrics and local-load confirmation
FailureSupported extension or parser error

Test the failure path deliberately

A loading UI is not verified until an error can be understood and retried.

  1. Load the known sample and confirm the success state.
  2. Choose an unsupported extension and confirm the inline validation message.
  3. Try a malformed GLB and confirm the parser error does not remove the previous useful page content.
  4. Load the sample again to verify that retry remains possible.

Shared loading manager

const manager = new THREE.LoadingManager();
manager.onStart = (url) => setStatus(`Loading ${url}`);
manager.onProgress = (url, loaded, total) => {
  const percent = total ? Math.round((loaded / total) * 100) : 0;
  setStatus(total ? `Loading ${percent}%` : `Loading ${url}`);
};
manager.onLoad = () => setStatus('Scene ready');
manager.onError = (url) => setStatus(`Could not load ${url}`);

const textureLoader = new THREE.TextureLoader(manager);
const gltfLoader = new GLTFLoader(manager);

Sources and further reading

Update record

  • : Rewritten around a reproducible demo, explicit test record, code comparison, and known platform limits.

Related guides