| name | threejs |
| description | Three.js 3D graphics library - scene setup, geometry, materials, lighting, textures, animation, loaders, shaders, postprocessing, interaction. Use when building 3D web experiences, creating WebGL visualizations, working with GLTF models, implementing custom shaders, or adding interactive 3D elements to web applications. |
| metadata | {"version":"1.0.0"} |
| license | MIT |
Three.js Skills
Overview
Comprehensive knowledge base for building 3D web experiences with Three.js. This skill provides accurate API references, best practices, and working code examples across all major Three.js domains.
Three.js version: r160+ (January 2024)
Quick Reference
Core Topics
This skill covers 10 essential Three.js domains:
- Fundamentals - Scene setup, cameras, renderer, Object3D hierarchy
- Geometry - Built-in shapes, BufferGeometry, custom geometry, instancing
- Materials - PBR materials, shader materials, material properties
- Lighting - Light types, shadows, environment lighting
- Textures - UV mapping, environment maps, render targets
- Animation - Keyframe animation, skeletal animation, animation mixing
- Loaders - GLTF/GLB loading, async patterns, caching
- Shaders - GLSL basics, ShaderMaterial, custom effects
- Postprocessing - EffectComposer, bloom, DOF, custom passes
- Interaction - Raycasting, camera controls, mouse/touch input
When to Load References
Load detailed reference files based on your current task:
- Basic scene setup, cameras, renderer → Load
references/threejs-fundamentals.md
- Creating shapes, custom geometry, instancing → Load
references/threejs-geometry.md
- Material properties, PBR, shader materials → Load
references/threejs-materials.md
- Adding lights, configuring shadows → Load
references/threejs-lighting.md
- Texture loading, UV mapping, environment maps → Load
references/threejs-textures.md
- Animating objects, GLTF animations, mixing → Load
references/threejs-animation.md
- Loading GLTF/GLB models, Draco compression → Load
references/threejs-loaders.md
- Writing GLSL shaders, custom visual effects → Load
references/threejs-shaders.md
- Adding bloom, depth of field, screen effects → Load
references/threejs-postprocessing.md
- Raycasting, mouse picking, camera controls → Load
references/threejs-interaction.md
Quick Start Examples
1. Fundamentals: Basic Scene
import * as THREE from 'three';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
document.body.appendChild(renderer.domElement);
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(5, 5, 5);
scene.add(dirLight);
camera.position.z = 5;
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
2. Geometry: Creating Shapes
const box = new THREE.BoxGeometry(1, 1, 1);
const sphere = new THREE.SphereGeometry(0.5, 32, 32);
const plane = new THREE.PlaneGeometry(10, 10);
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
-1, -1, 0,
1, -1, 0,
1, 1, 0,
-1, 1, 0
]);
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
const indices = new Uint16Array([0, 1, 2, 0, 2, 3]);
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
const count = 1000;
const instancedMesh = new THREE.InstancedMesh(geometry, material, count);
const dummy = new THREE.Object3D();
for (let i = 0; i < count; i++) {
dummy.position.set(
(Math.random() - 0.5) * 20,
(Math.random() - 0.5) * 20,
(Math.random() - 0.5) * 20
);
dummy.updateMatrix();
instancedMesh.setMatrixAt(i, dummy.matrix);
}
scene.add(instancedMesh);
3. Materials: PBR Materials
const material = new THREE.MeshStandardMaterial({
color: 0xffffff,
metalness: 0.5,
roughness: 0.5,
map: colorTexture,
normalMap: normalTexture,
roughnessMap: roughnessTexture,
metalnessMap: metalnessTexture,
envMap: environmentMap,
envMapIntensity: 1
});
const glassMaterial = new THREE.MeshPhysicalMaterial({
color: 0xffffff,
metalness: 0,
roughness: 0,
transmission: 1,
thickness: 0.5,
ior: 1.5,
envMapIntensity: 1
});
const shaderMaterial = new THREE.ShaderMaterial({
uniforms: {
time: { value: 0 },
color: { value: new THREE.Color(0xff0000) }
},
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() {
gl_FragColor = vec4(color * sin(vUv.x * 10.0 + time), 1.0);
}
`
});
4. Lighting: Basic Lighting
const ambient = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambient);
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(5, 10, 5);
dirLight.castShadow = true;
dirLight.shadow.mapSize.width = 2048;
dirLight.shadow.mapSize.height = 2048;
dirLight.shadow.camera.left = -10;
dirLight.shadow.camera.right = 10;
dirLight.shadow.camera.top = 10;
dirLight.shadow.camera.bottom = -10;
scene.add(dirLight);
const pointLight = new THREE.PointLight(0xffffff, 1, 100);
pointLight.position.set(0, 5, 0);
scene.add(pointLight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
mesh.castShadow = true;
mesh.receiveShadow = true;
5. Textures: Loading Textures
const loader = new THREE.TextureLoader();
const colorTexture = loader.load('texture.jpg');
colorTexture.colorSpace = THREE.SRGBColorSpace;
colorTexture.wrapS = THREE.RepeatWrapping;
colorTexture.wrapT = THREE.RepeatWrapping;
colorTexture.repeat.set(4, 4);
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
const rgbeLoader = new RGBELoader();
rgbeLoader.load('environment.hdr', (texture) => {
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = texture;
scene.background = texture;
});
const cubeLoader = new THREE.CubeTextureLoader();
const cubeTexture = cubeLoader.load([
'px.jpg', 'nx.jpg',
'py.jpg', 'ny.jpg',
'pz.jpg', 'nz.jpg'
]);
scene.background = cubeTexture;
6. Animation: Simple Animation
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
const loader = new GLTFLoader();
loader.load('model.glb', (gltf) => {
const model = gltf.scene;
scene.add(model);
const mixer = new THREE.AnimationMixer(model);
gltf.animations.forEach((clip) => {
const action = mixer.clipAction(clip);
action.play();
});
const clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
mixer.update(delta);
renderer.render(scene, camera);
}
animate();
});
function animate() {
const time = clock.getElapsedTime();
mesh.rotation.y = time;
mesh.position.y = Math.sin(time) * 0.5;
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
7. Loaders: Loading GLTF Models
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.5.6/');
const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);
gltfLoader.load('model.glb', (gltf) => {
const model = gltf.scene;
model.traverse((child) => {
if (child.isMesh) {
child.castShadow = true;
child.receiveShadow = true;
}
});
const box = new THREE.Box3().setFromObject(model);
const center = box.getCenter(new THREE.Vector3());
model.position.sub(center);
scene.add(model);
});
async function loadModel(url) {
return new Promise((resolve, reject) => {
gltfLoader.load(url, resolve, undefined, reject);
});
}
const gltf = await loadModel('model.glb');
scene.add(gltf.scene);
8. Shaders: Custom Shader Material
const material = new THREE.ShaderMaterial({
uniforms: {
time: { value: 0 },
amplitude: { value: 0.5 }
},
vertexShader: `
uniform float time;
uniform float amplitude;
varying vec2 vUv;
void main() {
vUv = uv;
vec3 pos = position;
// Wave displacement
pos.z += sin(pos.x * 5.0 + time) * amplitude;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
`,
fragmentShader: `
uniform float time;
varying vec2 vUv;
void main() {
vec3 color = vec3(vUv, 0.5 + 0.5 * sin(time));
gl_FragColor = vec4(color, 1.0);
}
`
});
function animate() {
material.uniforms.time.value = clock.getElapsedTime();
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
9. Postprocessing: Adding Bloom
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
const composer = new EffectComposer(renderer);
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5,
0.4,
0.85
);
composer.addPass(bloomPass);
function animate() {
requestAnimationFrame(animate);
composer.render();
}
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
composer.setSize(window.innerWidth, window.innerHeight);
});
10. Interaction: Raycasting
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
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;
console.log('Clicked:', object);
console.log('Point:', intersects[0].point);
object.material.emissive.set(0x444444);
}
}
window.addEventListener('click', onMouseClick);
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
Common Patterns
Proper Disposal
geometry.dispose();
material.dispose();
texture.dispose();
scene.remove(mesh);
renderer.dispose();
Responsive Rendering
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
});
Performance Optimization
- Use instancing for repeated objects (
InstancedMesh)
- Enable frustum culling (enabled by default)
- Dispose of unused resources
- Use proper LOD (Level of Detail) for complex scenes
- Minimize draw calls by merging geometries
- Limit active lights (each light adds shader complexity)
- Use texture atlases to reduce texture switches
Version Information
Three.js version: r160+ (January 2024)
Import format: ES6 modules (three, three/addons/*)
Verified: 2024-01
See Also