Agent skill
3d-design-for-web
3d-design-for-web skill
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:
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:
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:
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:
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:
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:
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:
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:
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
InstancedMeshfor rendering many identical objects - Employ
BatchedMeshfor 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
mediumpprecision on mobile devices - Minimize varying variables between vertex and fragment shaders
- Replace conditionals with
mix()andstep()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
PointLightshadows - 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:
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:
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.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?