← Back to Web app developers

Skill · Version 1.0.0

WebGL and 3D experiences

Adds interactive web graphics only within a justified load and device budget, with usable fallbacks and complete graphics-resource cleanup.

webgl-3d-experiences

Team members using this skill

See how it helps

When is it useful?

Use it when a 3D viewer or scene must remain practical on low-power devices or browsers without reliable WebGL support.

What does it help you do?

  • Justifies 3D against initial-load and device capability budgets.
  • Loads lazily and offers static or reduced-motion alternatives.
  • Renders on demand and releases GPU resources after context loss or teardown.

Try asking this

Build a product viewer that falls back cleanly without WebGL and releases resources on navigation. Simulate context loss and navigate away repeatedly. Restore the viewer or its static fallback without keeping obsolete textures, geometries or animation loops alive.

Detailed documentation

Read the skill’s original instructions, examples and checks in their authored language.

Details…Show less

WebGL & 3D Experiences

Use WebGL, custom shaders, or 3D scenes only when spatial depth, interactive 3D inspection, or shader-driven visual effects deliver clear product value that CSS, SVG, or 2D Canvas cannot achieve at a fraction of the bundle and GPU cost.

Justification & Progressive Enhancement Gate

Before introducing Three.js or a custom WebGL pipeline:

  1. Bundle & initialization budget: Lazy-load 3D libraries (await import('three')) behind an IntersectionObserver or route split so initial page load (LCP / TTI) is never blocked by a 150KB+ 3D engine.
  2. Capability & fallback check: Gracefully handle missing WebGL contexts, software renderers, low-power devices, and prefers-reduced-motion: reduce by rendering a crisp static image, SVG, or CSS gradient fallback underneath the canvas.
  3. On-demand rendering (frameloop="demand"): If the 3D scene only changes when the user drags, hovers, or scrolls, render on demand rather than running a continuous 60fps requestAnimationFrame loop that drains laptop and mobile batteries.

Performance & Fill-Rate Guardrails

  • Clamp pixel ratio (Math.min(window.devicePixelRatio, 2)): Rendering a full-viewport fragment shader or 3D scene at devicePixelRatio = 3 or 4 multiplies pixel fill-rate cost by $9\times$–$16\times$ with negligible visual gain and severe thermal throttling.
  • Shader & draw-call discipline:
    • Keep draw calls low by merging static geometries or using InstancedMesh for repeated elements.
    • Pre-compile materials and avoid dynamic shader recompilation during user interaction.
    • Keep DOM overlays (text, buttons, tooltips) in standard HTML/CSS above the <canvas> (pointer-events: none on the canvas unless dragging) rather than rendering UI text as 3D textures.

Context Loss & Complete GPU Memory Disposal

Browsers evict WebGL contexts when background tabs accumulate or GPU memory is pressured, and SPA navigation leaks GPU VRAM if resources are not explicitly freed:

// 1. Handle WebGL context loss & restoration without crashing the page
canvas.addEventListener('webglcontextlost', (e) => {
  e.preventDefault(); // Allows context to be restored later
  renderer.setAnimationLoop(null);
});
canvas.addEventListener('webglcontextrestored', () => {
  initSceneResources();
  renderer.setAnimationLoop(animate);
});

// 2. Complete GPU resource disposal on component unmount
function disposeThreeScene(scene: THREE.Scene, renderer: THREE.WebGLRenderer) {
  renderer.setAnimationLoop(null);
  scene.traverse((obj) => {
    if ((obj as THREE.Mesh).isMesh || (obj as THREE.Line).isLine) {
      const mesh = obj as THREE.Mesh;
      mesh.geometry?.dispose();
      const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
      for (const mat of materials) {
        if (!mat) continue;
        for (const value of Object.values(mat)) {
          if (value && typeof (value as THREE.Texture).dispose === 'function') {
            (value as THREE.Texture).dispose();
          }
        }
        mat.dispose();
      }
    }
  });
  renderer.dispose();
}

Included files 1

  • SKILL.md