Agent skill

3d-design-for-web

3d-design-for-web skill

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/3d-design-for-web

SKILL.md


title: "3D Design for Web" description: "Master creating immersive 3D web experiences using WebGL, Three.js, and modern web technologies. Learn 3D modeling optimization, interactive design patterns, and performance strategies for delivering engaging real-time graphics in the browser." category: "Development & Tech" tags: ["3D Graphics", "WebGL", "Three.js", "Web Development", "Interactive Design", "Performance Optimization", "3D Modeling", "WebGPU"] difficulty: "Advanced" prerequisites: ["JavaScript", "HTML/CSS", "Web Performance", "Computer Graphics Basics"] related_skills: ["frontend-development", "web-performance-optimization", "interactive-design", "game-development"] resources:

  • title: "Three.js Documentation" url: "https://threejs.org/docs/" type: "documentation"
  • title: "WebGL Fundamentals" url: "https://webglfundamentals.org/" type: "tutorial"
  • title: "WebGPU Specification" url: "https://www.w3.org/TR/webgpu/" type: "specification"
  • title: "Three.js Journey" url: "https://threejs-journey.com/" type: "course"

3D Design for Web

Overview

3D design for the web represents the convergence of computer graphics, web technologies, and interactive design, enabling developers to create immersive, engaging experiences directly in the browser. With the maturation of WebGL, the emergence of WebGPU, and powerful libraries like Three.js, 3D web experiences have evolved from experimental novelties to production-ready applications used in e-commerce, education, gaming, data visualization, and virtual showrooms.

This skill encompasses understanding 3D graphics fundamentals, mastering WebGL and Three.js, optimizing 3D models and assets for web delivery, implementing interactive experiences, and ensuring optimal performance across devices. As browsers continue to advance their graphics capabilities and users expect increasingly rich digital experiences, 3D web design has become an essential skill for modern web developers.

Key Concepts

WebGL and Graphics Pipeline

WebGL (Web Graphics Library) is a JavaScript API that renders interactive 2D and 3D graphics within web browsers without plugins, leveraging the GPU for thousands of parallel calculations. WebGL operates through a graphics pipeline that processes vertices and fragments (pixels) using programmable shaders written in GLSL (OpenGL Shading Language).

The graphics pipeline consists of:

  • Vertex Processing: Transforming 3D coordinates to screen space
  • Rasterization: Converting geometric primitives to fragments
  • Fragment Processing: Calculating final pixel colors
  • Output Merging: Combining fragments into the final image

Understanding this pipeline is crucial for optimization and creating custom visual effects.

Three.js Framework

Three.js is the most popular JavaScript library for 3D web graphics, abstracting WebGL's complexity and providing an intuitive API for creating 3D scenes. Three.js handles:

  • Scene graphs and object hierarchies
  • Cameras (perspective, orthographic)
  • Geometries and materials
  • Lighting systems
  • Texture mapping
  • Animation systems
  • Post-processing effects

Three.js significantly reduces development time, allowing developers to create animated 3D scenes with minimal code while maintaining access to lower-level WebGL features when needed.

WebGPU: The Next Generation

WebGPU is the modern successor to WebGL, offering improved performance and more direct access to GPU capabilities. As of 2026, WebGPU is production-ready with support across all major browsers:

  • Chrome/Edge (v113+)
  • Firefox (v141+ Windows, v145+ macOS)
  • Safari (v26+ on macOS, iOS, iPadOS, visionOS)

WebGPU provides:

  • 2-10x performance gains for high draw call counts and compute-intensive effects
  • Compute shaders for physics simulations and particle systems
  • More efficient buffer management for large instanced meshes
  • Better shader pipeline with WGSL (WebGPU Shading Language)

Three.js (r171+) offers seamless WebGPU integration through WebGPURenderer, with automatic fallback to WebGL 2 when WebGPU is unavailable.

3D Model Formats

glTF (GL Transmission Format) and its binary variant GLB are the standard formats for 3D web content, often called "the JPEG of 3D." These formats:

  • Support animations, materials, and textures
  • Maintain small file sizes
  • Load efficiently in web environments
  • Are widely supported by 3D tools and engines

Other formats include:

  • OBJ/FBX: Legacy formats, less optimized for web
  • USDZ: Apple's format for iOS ARKit
  • Draco: Compression format reducing geometry size by 90-95%
  • KTX2: GPU-compressed texture format reducing VRAM usage by ~10x

Scene Composition

A 3D web scene consists of:

  • Scene: Container for all 3D objects
  • Camera: Viewpoint defining what's visible
  • Renderer: Draws the scene to canvas
  • Lights: Illuminate objects (ambient, directional, point, spot)
  • Meshes: Combinations of geometry and materials
  • Controls: Enable user interaction (orbit, first-person, etc.)

Proper scene composition balances visual quality, performance, and user experience.

Coordinate Systems and Transformations

3D graphics use coordinate systems to position objects in space:

  • Local/Object Space: Relative to object's origin
  • World Space: Absolute positions in the scene
  • View/Camera Space: Relative to camera position
  • Clip Space: Normalized device coordinates
  • Screen Space: Final pixel coordinates

Transformations (translation, rotation, scale) are represented by matrices, enabling efficient GPU processing.

Technical Implementation

Setting Up a Three.js Project

Basic Scene Setup:

javascript
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';

// Scene, Camera, Renderer
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
  75, // Field of view
  window.innerWidth / window.innerHeight, // Aspect ratio
  0.1, // Near clipping plane
  1000 // Far clipping plane
);
const renderer = new THREE.WebGLRenderer({ 
  antialias: true,
  alpha: true 
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
document.body.appendChild(renderer.domElement);

// Camera position and controls
camera.position.z = 5;
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;

// Lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(5, 5, 5);
scene.add(ambientLight, directionalLight);

// Animation loop
function animate() {
  requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
}
animate();

// Handle window resize
window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});

Loading and Displaying 3D Models

Using GLTFLoader:

javascript
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';

// Configure Draco decoder for compressed models
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('/draco/');

const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);

// Load model with progress tracking
gltfLoader.load(
  '/models/scene.glb',
  (gltf) => {
    const model = gltf.scene;
    model.scale.set(1, 1, 1);
    model.position.set(0, 0, 0);
    scene.add(model);
    
    // Access animations if present
    if (gltf.animations.length > 0) {
      const mixer = new THREE.AnimationMixer(model);
      gltf.animations.forEach((clip) => {
        mixer.clipAction(clip).play();
      });
    }
  },
  (progress) => {
    const percent = (progress.loaded / progress.total) * 100;
    console.log(`Loading: ${percent.toFixed(2)}%`);
  },
  (error) => {
    console.error('Error loading model:', error);
  }
);

WebGPU Migration

Migrating to WebGPU Renderer:

javascript
import { WebGPURenderer } from 'three/webgpu';
import * as THREE from 'three/webgpu';

// Async initialization required for WebGPU
async function initWebGPU() {
  const renderer = new WebGPURenderer({
    antialias: true,
    forceWebGL: false // Set to true to test WebGL fallback
  });
  
  await renderer.init(); // Required async initialization
  
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
  document.body.appendChild(renderer.domElement);
  
  return renderer;
}

// Use in async context
const renderer = await initWebGPU();

Three Shader Language (TSL) for Cross-Platform Shaders:

javascript
import { MeshStandardNodeMaterial, uniform, texture } from 'three/nodes';

const material = new MeshStandardNodeMaterial();
material.colorNode = texture(colorTexture);
material.roughnessNode = uniform(0.5);
material.metalnessNode = uniform(0.2);

Creating Custom Geometries and Materials

Custom Geometry:

javascript
const geometry = new THREE.BufferGeometry();

const vertices = new Float32Array([
  -1, -1, 0,
   1, -1, 0,
   1,  1, 0,
  -1,  1, 0
]);

const indices = new Uint16Array([
  0, 1, 2,
  0, 2, 3
]);

geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
geometry.computeVertexNormals();

Custom Shader Material:

javascript
const material = new THREE.ShaderMaterial({
  uniforms: {
    time: { value: 0 },
    color: { value: new THREE.Color(0x00ff00) }
  },
  vertexShader: `
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    uniform float time;
    uniform vec3 color;
    varying vec2 vUv;
    
    void main() {
      float strength = sin(vUv.x * 10.0 + time) * 0.5 + 0.5;
      gl_FragColor = vec4(color * strength, 1.0);
    }
  `
});

// Update time uniform in animation loop
function animate() {
  material.uniforms.time.value += 0.01;
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

Implementing Interactivity

Raycasting for Object Selection:

javascript
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();

function onMouseClick(event) {
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
  
  raycaster.setFromCamera(mouse, camera);
  const intersects = raycaster.intersectObjects(scene.children, true);
  
  if (intersects.length > 0) {
    const object = intersects[0].object;
    object.material.color.set(0xff0000);
  }
}

window.addEventListener('click', onMouseClick);

Post-Processing Effects

Using pmndrs/postprocessing:

javascript
import { EffectComposer } from 'postprocessing';
import { RenderPass, BloomEffect, EffectPass } from 'postprocessing';

const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));

const bloomEffect = new BloomEffect({
  intensity: 1.5,
  luminanceThreshold: 0.9,
  luminanceSmoothing: 0.025
});

composer.addPass(new EffectPass(camera, bloomEffect));

// Render with composer instead of renderer
function animate() {
  requestAnimationFrame(animate);
  composer.render();
}

Best Practices

Performance Optimization

Asset Optimization:

  • Geometry Compression: Use Draco compression to reduce file sizes by 90-95%
  • Texture Compression: Implement KTX2 with Basis Universal for GPU-compressed textures
  • Polygon Budget: Keep models under 100K polygons for web, 20-50K for mobile
  • Texture Resolution: Minimize texture sizes; use texture atlases to reduce HTTP requests
  • Level of Detail (LOD): Swap high-polygon models for lower-polygon versions based on distance

Draw Call Reduction:

  • Use InstancedMesh for rendering many identical objects
  • Employ BatchedMesh for grouping varied geometries
  • Share materials across multiple meshes
  • Merge static geometries using BufferGeometryUtils
  • Keep draw calls under 100 per frame

Memory Management:

  • Always dispose of geometries, materials, textures, and render targets when no longer needed
  • Implement object pooling for frequently spawned entities
  • Cache and reuse textures
  • Clean up Three.js resources when components unmount (especially in React)

Shader Optimization:

  • Use mediump precision on mobile devices
  • Minimize varying variables between vertex and fragment shaders
  • Replace conditionals with mix() and step() functions
  • Pack multiple data points into RGBA channels
  • Avoid dynamic loops in shaders

Lighting and Shadows:

  • Limit active lights to three or fewer
  • Be aware of high computational cost of PointLight shadows
  • Bake lightmaps for static scenes
  • Use Cascaded Shadow Maps for large scenes
  • Disable shadow auto-update for static scenes

Loading Strategies

Progressive Loading:

  • Display placeholder geometry during loading
  • Implement progressive loading to show content incrementally
  • Lazy load 3D content below the fold
  • Code-split Three.js modules to reduce initial bundle size
  • Preload critical assets

Loading States:

javascript
class ModelLoader {
  constructor() {
    this.loadingManager = new THREE.LoadingManager();
    this.setupLoadingHandlers();
  }
  
  setupLoadingHandlers() {
    this.loadingManager.onStart = (url, loaded, total) => {
      this.showLoadingScreen();
    };
    
    this.loadingManager.onProgress = (url, loaded, total) => {
      const progress = (loaded / total) * 100;
      this.updateProgressBar(progress);
    };
    
    this.loadingManager.onLoad = () => {
      this.hideLoadingScreen();
    };
    
    this.loadingManager.onError = (url) => {
      console.error(`Error loading ${url}`);
      this.showErrorMessage();
    };
  }
}

React Three Fiber Best Practices

Performance Optimization in R3F:

javascript
import { Canvas, useFrame } from '@react-three/fiber';
import { useGLTF } from '@react-three/drei';
import React, { useRef } from 'react';

// Preload models
useGLTF.preload('/models/scene.glb');

const Model = React.memo(() => {
  const meshRef = useRef();
  const { scene } = useGLTF('/models/scene.glb');
  
  // Mutate directly in useFrame, don't use setState
  useFrame((state, delta) => {
    meshRef.current.rotation.y += delta * 0.5;
  });
  
  return <primitive ref={meshRef} object={scene} />;
});

function App() {
  return (
    <Canvas
      frameloop="demand" // Only render when changes occur

---

**Note:** This file was automatically condensed to meet the 500-line requirement. Additional content has been moved to the references/ folder.

Expand your agent's capabilities with these related and highly-rated skills.

Didn't find tool you were looking for?

Be as detailed as possible for better results