
Threejs Syntax Materials
- 18 installs
- 11 repo stars
- Updated July 8, 2026
- openaec-foundation/three.js-claude-skill-package
Helps with ai & agent building tasks.
About
threejs-syntax-materials is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- threejs-syntax-materials
- AI & Agent Building
- AI-coding skill
Threejs Syntax Materials by the numbers
- 18 all-time installs (skills.sh)
- +2 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #10,710 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/openaec-foundation/three.js-claude-skill-package --skill threejs-syntax-materialsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 18 |
|---|---|
| repo stars | ★ 11 |
| Last updated | July 8, 2026 |
| Repository | openaec-foundation/three.js-claude-skill-package ↗ |
What it does
Helps with ai & agent building tasks.
Files
threejs-syntax-materials
Quick Reference
Material Type Decision Tree
| Use Case | Material | Why |
|---|---|---|
| UI elements, unlit scenes | MeshBasicMaterial | Cheapest, no light computation |
| Matte diffuse (low-end devices) | MeshLambertMaterial | Fast diffuse, no specular |
| Legacy specular highlights | MeshPhongMaterial | Blinn-Phong model, not physically correct |
| General-purpose 3D (recommended) | MeshStandardMaterial | PBR metalness/roughness, industry standard |
| Glass, car paint, fabric, soap bubbles | MeshPhysicalMaterial | Advanced PBR (clearcoat, transmission, sheen, iridescence) |
| Cartoon/anime style | MeshToonMaterial | Discrete cel-shading steps |
| Sculpting previews, no lights | MeshMatcapMaterial | Matcap texture, zero light setup |
| Debug normals | MeshNormalMaterial | RGB = surface normal direction |
| Invisible shadow receiver | ShadowMaterial | Transparent shadow catcher |
| Solid lines | LineBasicMaterial | Simple colored lines |
| Dashed lines | LineDashedMaterial | Requires line.computeLineDistances() |
| Particles | PointsMaterial | Point cloud rendering |
| Billboards | SpriteMaterial | Always-facing-camera quads |
Base Material Properties (All Materials)
| Property | Type | Default | Description |
|---|---|---|---|
side | number | FrontSide | FrontSide, BackSide, or DoubleSide |
transparent | boolean | false | Enable alpha blending |
opacity | number | 1 | Requires transparent: true to take effect below 1 |
depthWrite | boolean | true | Write to depth buffer |
depthTest | boolean | true | Test against depth buffer |
blending | number | NormalBlending | NoBlending, AdditiveBlending, SubtractiveBlending, MultiplyBlending, CustomBlending |
alphaTest | number | 0 | Discard fragments with alpha below this value |
visible | boolean | true | Whether to render this material |
wireframe | boolean | false | Wireframe rendering mode |
fog | boolean | true | Affected by scene fog |
clippingPlanes | Plane[] | null | Array of clipping planes |
clipIntersection | boolean | false | Clip where ALL planes intersect (vs union) |
needsUpdate | boolean | false | Set true to trigger shader recompilation |
toneMapped | boolean | true | Apply renderer tone mapping |
Base Material Methods
| Method | Signature | Description |
|---|---|---|
clone | (): Material | Clone the material |
copy | (source: Material): Material | Copy properties from source |
dispose | (): void | Free GPU resources -- ALWAYS call when removing |
onBeforeCompile | (shader, renderer): void | Hook to modify shader before compilation |
setValues | (values: Object): void | Set multiple properties at once |
Critical Warnings
NEVER set opacity < 1 without transparent: true -- the opacity value is silently ignored. ALWAYS pair them together.
NEVER use MeshPhysicalMaterial when MeshStandardMaterial suffices -- Physical compiles a significantly larger shader. ONLY use it when you need clearcoat, transmission, sheen, iridescence, or anisotropy.
NEVER set SRGBColorSpace on normal maps, roughness maps, metalness maps, or any data texture -- this corrupts the data and causes incorrect lighting. ONLY set SRGBColorSpace on diffuse/color/emissive textures.
NEVER forget to call material.dispose() and texture.dispose() when removing objects -- GPU memory leaks accumulate and crash the application.
NEVER set linewidth > 1 on LineBasicMaterial -- it is silently ignored on most platforms due to WebGL limitations. ALWAYS use Line2 + LineMaterial from three/addons/lines/ for thick lines.
ALWAYS set material.needsUpdate = true after changing properties that affect shader compilation (e.g., toggling flatShading, changing side, adding/removing texture maps at runtime).
ALWAYS set wrapS and wrapT to RepeatWrapping when using texture.repeat values other than (1, 1) -- the default ClampToEdgeWrapping does NOT tile textures.
---
MeshStandardMaterial (PBR)
The recommended material for most 3D scenes. Uses physically-based metalness/roughness workflow.
import { MeshStandardMaterial, TextureLoader, SRGBColorSpace, RepeatWrapping } from 'three';
const loader = new TextureLoader();
const material = new MeshStandardMaterial({
color: 0xffffff,
roughness: 0.7, // 0 = mirror, 1 = fully rough
metalness: 0.0, // 0 = dielectric, 1 = metal
map: null, // Diffuse/albedo texture
roughnessMap: null, // Per-pixel roughness
metalnessMap: null, // Per-pixel metalness
normalMap: null, // Surface normal perturbation
normalScale: new Vector2(1, 1),
aoMap: null, // Ambient occlusion (requires uv2)
aoMapIntensity: 1.0,
emissive: 0x000000, // Emissive color
emissiveMap: null, // Emissive texture
emissiveIntensity: 1.0,
envMap: null, // Environment reflection map
envMapIntensity: 1.0,
bumpMap: null, // Grayscale height map
bumpScale: 1.0,
displacementMap: null, // Vertex displacement map
displacementScale: 1.0,
displacementBias: 0.0,
alphaMap: null, // Per-pixel transparency
lightMap: null, // Baked lighting (requires uv2)
lightMapIntensity: 1.0,
flatShading: false,
wireframe: false,
fog: true
});---
MeshPhysicalMaterial (Advanced PBR)
Extends MeshStandardMaterial with ALL its properties, plus:
| Property | Type | Default | Description |
|---|---|---|---|
clearcoat | float | 0.0 | Clear coat layer intensity (0-1) |
clearcoatRoughness | float | 0.0 | Clear coat roughness |
clearcoatMap | Texture | null | Clear coat intensity map |
clearcoatNormalMap | Texture | null | Clear coat normal map |
transmission | float | 0.0 | Physically-based transparency (0-1) |
transmissionMap | Texture | null | Transmission map |
thickness | float | 0.0 | Volume thickness for transmission |
thicknessMap | Texture | null | Thickness map |
ior | float | 1.5 | Index of refraction (1.0-2.333) |
attenuationDistance | float | Infinity | Light attenuation distance in volume |
attenuationColor | Color | white | Light attenuation tint |
sheen | float | 0.0 | Sheen layer intensity (fabric-like) |
sheenColor | Color | 0x000000 | Sheen tint color |
sheenRoughness | float | 1.0 | Sheen roughness |
iridescence | float | 0.0 | Thin-film interference (0-1) |
iridescenceIOR | float | 1.3 | Iridescence index of refraction |
iridescenceThicknessRange | [float, float] | [100, 400] | Thin-film thickness range (nm) |
anisotropy | float | 0.0 | Anisotropic reflection strength |
anisotropyRotation | float | 0.0 | Anisotropy rotation (radians) |
specularIntensity | float | 1.0 | Specular layer intensity |
specularColor | Color | white | Specular tint color |
dispersion | float | 0.0 | Chromatic dispersion (rainbow effect) |
reflectivity | float | 0.5 | Reflectivity at normal incidence |
---
Texture System
Color Space Rules (Critical)
| Map Type | Color Space | Channels Used |
|---|---|---|
map (diffuse/albedo) | SRGBColorSpace | RGB(A) |
emissiveMap | SRGBColorSpace | RGB |
lightMap | SRGBColorSpace | RGB |
envMap | SRGBColorSpace | RGB |
sheenColorMap | SRGBColorSpace | RGB |
specularColorMap | SRGBColorSpace | RGB |
normalMap | NoColorSpace | RGB |
roughnessMap | NoColorSpace | G channel |
metalnessMap | NoColorSpace | B channel |
aoMap | NoColorSpace | R channel |
bumpMap | NoColorSpace | R channel |
displacementMap | NoColorSpace | R channel |
alphaMap | NoColorSpace | R channel |
clearcoatMap | NoColorSpace | R channel |
clearcoatRoughnessMap | NoColorSpace | R channel |
clearcoatNormalMap | NoColorSpace | RGB |
transmissionMap | NoColorSpace | R channel |
thicknessMap | NoColorSpace | R channel |
iridescenceMap | NoColorSpace | R channel |
iridescenceThicknessMap | NoColorSpace | R channel |
sheenRoughnessMap | NoColorSpace | R channel |
anisotropyMap | NoColorSpace | RG channels |
specularIntensityMap | NoColorSpace | A channel |
Rule: Diffuse/emissive/color textures = SRGBColorSpace. ALL data textures = NoColorSpace. Getting this wrong causes washed-out or over-saturated rendering.
Texture Loaders
| Loader | Format | Import |
|---|---|---|
TextureLoader | PNG, JPG, WebP | three core |
CubeTextureLoader | 6x PNG/JPG cube maps | three core |
RGBELoader | .hdr (Radiance HDR) | three/addons/loaders/RGBELoader.js |
EXRLoader | .exr (OpenEXR HDR) | three/addons/loaders/EXRLoader.js |
KTX2Loader | .ktx2 (GPU compressed) | three/addons/loaders/KTX2Loader.js |
Wrapping Modes
| Constant | Description |
|---|---|
ClampToEdgeWrapping | Edge texels stretched (default) |
RepeatWrapping | Texture tiles/repeats |
MirroredRepeatWrapping | Tiles with alternating mirror |
Filter Modes
| Constant | Type | Description |
|---|---|---|
NearestFilter | Mag/Min | Pixelated, crisp (retro, toon gradients) |
LinearFilter | Mag/Min | Smooth interpolation |
LinearMipmapLinearFilter | Min | Trilinear filtering (default, best quality) |
Texture Properties
| Property | Type | Default | Description |
|---|---|---|---|
wrapS / wrapT | number | ClampToEdgeWrapping | Wrapping mode |
magFilter | number | LinearFilter | Magnification filter |
minFilter | number | LinearMipmapLinearFilter | Minification filter |
anisotropy | number | 1 | Anisotropic filtering (max = renderer.capabilities.getMaxAnisotropy()) |
repeat | Vector2 | (1, 1) | UV repeat count |
offset | Vector2 | (0, 0) | UV offset |
rotation | number | 0 | UV rotation in radians |
center | Vector2 | (0, 0) | Center of rotation |
flipY | boolean | true | Flip vertically on upload |
colorSpace | string | NoColorSpace | Color space interpretation |
generateMipmaps | boolean | true | Auto-generate mipmaps |
needsUpdate | boolean | false | Trigger GPU re-upload |
flipY Rules
flipY = true(default): Correct for loaded image textures (PNG, JPG)flipY = false: ALWAYS use forWebGLRenderTargettextures,DataTexture, and framebuffer textures
---
Material Disposal
// ALWAYS dispose materials and textures when removing objects
function disposeMesh(mesh) {
if (mesh.material) {
// Dispose all texture maps
for (const key of Object.keys(mesh.material)) {
const value = mesh.material[key];
if (value && value.isTexture) {
value.dispose();
}
}
mesh.material.dispose();
}
if (mesh.geometry) {
mesh.geometry.dispose();
}
}---
needsUpdate Flag
ALWAYS set material.needsUpdate = true after changing these at runtime:
- Toggling
flatShading - Changing
side(FrontSide/BackSide/DoubleSide) - Adding or removing a texture map (e.g., setting
mapfromnullto a texture) - Changing
transparentoralphaTest - Toggling
wireframe - Any property that changes the compiled shader variant
NEVER set needsUpdate = true every frame -- it forces expensive shader recompilation. ONLY set it once after the property change.
For textures: set texture.needsUpdate = true after modifying texture.image data to trigger GPU re-upload.
---
Toon Material Special Rule
When using MeshToonMaterial, ALWAYS set gradientMap.minFilter = NearestFilter and gradientMap.magFilter = NearestFilter. Linear filtering blurs the discrete shading steps into smooth gradients, defeating the toon effect.
---
Reference Links
- references/methods.md -- All material types with constructor signatures and key properties
- references/examples.md -- Complete working examples (PBR, textures, multi-material)
- references/anti-patterns.md -- What NOT to do, with explanations
Official Sources
- https://threejs.org/docs/#api/en/materials/Material
- https://threejs.org/docs/#api/en/materials/MeshStandardMaterial
- https://threejs.org/docs/#api/en/materials/MeshPhysicalMaterial
- https://threejs.org/docs/#api/en/textures/Texture
Anti-Patterns (Three.js Materials & Textures)
1. Wrong Color Space on Data Textures
// WRONG: Setting SRGBColorSpace on a normal map corrupts normal vectors
const normalMap = loader.load('normal.jpg');
normalMap.colorSpace = THREE.SRGBColorSpace; // CORRUPTED lighting!
// CORRECT: Data textures ALWAYS use NoColorSpace (the default)
const normalMap = loader.load('normal.jpg');
// colorSpace stays at NoColorSpace -- do NOT change it
// CORRECT: ONLY diffuse/emissive/color textures get SRGBColorSpace
const diffuseMap = loader.load('diffuse.jpg');
diffuseMap.colorSpace = THREE.SRGBColorSpace;WHY: The renderer performs lighting calculations in linear space. Setting SRGBColorSpace on data textures (normal, roughness, metalness, AO, bump, displacement, alpha) applies an incorrect gamma correction, producing washed-out or oversaturated results and completely wrong surface normals.
---
2. Opacity Without Transparent Flag
// WRONG: opacity is silently ignored without transparent: true
const material = new THREE.MeshStandardMaterial({
color: 0xff0000,
opacity: 0.5 // Has NO visible effect!
});
// CORRECT: ALWAYS pair opacity with transparent
const material = new THREE.MeshStandardMaterial({
color: 0xff0000,
opacity: 0.5,
transparent: true
});WHY: Three.js skips alpha blending entirely unless transparent is explicitly true. The opacity property exists on the material but is not applied during rendering without the flag.
---
3. Using MeshPhysicalMaterial Everywhere
// WRONG: Using Physical for a simple colored object
const material = new THREE.MeshPhysicalMaterial({
color: 0xff4444,
roughness: 0.5,
metalness: 0.0
// No clearcoat, transmission, sheen, iridescence, or anisotropy used
});
// CORRECT: Use MeshStandardMaterial when advanced PBR features are not needed
const material = new THREE.MeshStandardMaterial({
color: 0xff4444,
roughness: 0.5,
metalness: 0.0
});WHY: MeshPhysicalMaterial compiles a significantly larger shader than MeshStandardMaterial. Every physical material instance adds shader compilation time and GPU overhead even if the advanced features are unused. ONLY use Physical when you need clearcoat, transmission, sheen, iridescence, anisotropy, or dispersion.
---
4. Forgetting to Dispose Materials and Textures
// WRONG: Removing mesh from scene without disposing GPU resources
scene.remove(mesh);
// GPU memory for material, textures, and geometry is NEVER freed!
// CORRECT: ALWAYS dispose before removing
mesh.geometry.dispose();
for (const key of Object.keys(mesh.material)) {
const value = mesh.material[key];
if (value && value.isTexture) {
value.dispose();
}
}
mesh.material.dispose();
scene.remove(mesh);WHY: scene.remove() only removes the object from the scene graph. GPU-side resources (compiled shaders, texture buffers, geometry buffers) are NOT freed automatically. Without explicit dispose() calls, GPU memory leaks accumulate and eventually crash the application or cause severe performance degradation.
---
5. Repeating Textures Without RepeatWrapping
// WRONG: Setting repeat without changing wrapping mode
const texture = loader.load('tile.jpg');
texture.repeat.set(4, 4);
// Default ClampToEdgeWrapping: texture does NOT tile, edge pixels are stretched
// CORRECT: ALWAYS set wrapping mode when using repeat
const texture = loader.load('tile.jpg');
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(4, 4);WHY: The default wrapping mode is ClampToEdgeWrapping, which stretches the edge pixels of the texture infinitely. repeat values greater than (1, 1) only produce visible tiling when wrapS and wrapT are set to RepeatWrapping or MirroredRepeatWrapping.
---
6. Setting linewidth > 1 on LineBasicMaterial
// WRONG: linewidth > 1 is silently ignored on most platforms
const material = new THREE.LineBasicMaterial({
color: 0xff0000,
linewidth: 5 // IGNORED on Windows, macOS, most Linux (WebGL limitation)
});
// CORRECT: Use Line2 + LineMaterial from addons for thick lines
import { Line2 } from 'three/addons/lines/Line2.js';
import { LineMaterial } from 'three/addons/lines/LineMaterial.js';
import { LineGeometry } from 'three/addons/lines/LineGeometry.js';
const geometry = new LineGeometry();
geometry.setPositions([0, 0, 0, 1, 1, 0, 2, 0, 0]);
const material = new LineMaterial({
color: 0xff0000,
linewidth: 5, // Works on all platforms (screen-space pixels)
resolution: new THREE.Vector2(window.innerWidth, window.innerHeight)
});
const line = new Line2(geometry, material);
scene.add(line);WHY: The WebGL specification does not guarantee support for lineWidth values greater than 1. Most implementations (ANGLE on Windows/macOS, most Linux drivers) cap it at 1. The Line2/LineMaterial addon renders lines as screen-space triangles, bypassing this limitation.
---
7. Setting needsUpdate Every Frame
// WRONG: Forcing shader recompilation every frame
function animate() {
material.needsUpdate = true; // Recompiles shader EVERY frame -- massive waste
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
// CORRECT: Only set needsUpdate once, after the change
material.flatShading = true;
material.needsUpdate = true; // Set ONCE after the change
// Do NOT set again until the next property changeWHY: Setting needsUpdate = true triggers a full shader recompilation on the GPU. This is an expensive operation (can take 10-100ms per material). Doing it every frame causes severe stuttering and wasted GPU cycles. ONLY set it once after changing a property that affects the shader variant.
---
8. Forgetting uv2 for aoMap and lightMap
// WRONG: Using aoMap without uv2 attribute -- AO will not render
const material = new THREE.MeshStandardMaterial({
aoMap: aoTexture,
aoMapIntensity: 1.0
});
const mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), material);
// aoMap is silently ignored because geometry has no uv2 attribute
// CORRECT: ALWAYS add uv2 attribute when using aoMap or lightMap
const geometry = new THREE.BoxGeometry(1, 1, 1);
geometry.setAttribute('uv2', geometry.getAttribute('uv'));
const mesh = new THREE.Mesh(geometry, material);WHY: aoMap and lightMap sample from the second UV channel (uv2). If the geometry does not have a uv2 attribute, the maps are silently ignored with no error or warning. For simple cases, copying uv to uv2 works. For baked lighting, use a dedicated UV unwrap for uv2.
---
9. flipY = true on Render Target Textures
// WRONG: Default flipY on render target texture produces upside-down image
const renderTarget = new THREE.WebGLRenderTarget(512, 512);
renderer.setRenderTarget(renderTarget);
renderer.render(scene, camera);
renderer.setRenderTarget(null);
const screenMaterial = new THREE.MeshBasicMaterial({
map: renderTarget.texture // Upside down if flipY is not corrected
});
// CORRECT: Render target textures have flipY = false by default (correct)
// Do NOT manually set renderTarget.texture.flipY = true
// If using DataTexture, ALWAYS set flipY = false
const dataTexture = new THREE.DataTexture(data, width, height);
dataTexture.flipY = false;
dataTexture.needsUpdate = true;WHY: Image files store pixels top-to-bottom, so flipY = true (default) corrects for this. Render targets and DataTextures store pixels bottom-to-top (OpenGL convention). Setting flipY = true on these textures flips an already-correct image upside down.
---
10. Not Setting Toon Gradient Filter to Nearest
// WRONG: Linear filtering blurs toon shading into smooth gradient
const gradientMap = loader.load('toon_gradient_3.png');
// Default filters: LinearFilter / LinearMipmapLinearFilter -- SMOOTH, not toon
const material = new THREE.MeshToonMaterial({
color: 0xff4444,
gradientMap: gradientMap // Looks like MeshLambertMaterial, not toon!
});
// CORRECT: ALWAYS use NearestFilter for toon gradient maps
const gradientMap = loader.load('toon_gradient_3.png');
gradientMap.minFilter = THREE.NearestFilter;
gradientMap.magFilter = THREE.NearestFilter;
const material = new THREE.MeshToonMaterial({
color: 0xff4444,
gradientMap: gradientMap // Sharp discrete shading steps
});WHY: Toon shading works by quantizing light intensity into discrete steps using a gradient map (typically 3-5 pixels wide). Linear filtering interpolates between these steps, producing a smooth gradient that looks identical to Lambert shading. NearestFilter preserves the sharp step boundaries that create the cel-shaded look.
Working Code Examples (Three.js r160+ Materials)
Example 1: PBR Material with Texture Maps
Complete setup of a physically-based material with diffuse, normal, roughness, metalness, and AO maps.
import * as THREE from 'three';
const loader = new THREE.TextureLoader();
// Load all texture maps
const diffuseMap = loader.load('textures/brick_diffuse.jpg');
const normalMap = loader.load('textures/brick_normal.jpg');
const roughnessMap = loader.load('textures/brick_roughness.jpg');
const aoMap = loader.load('textures/brick_ao.jpg');
// CRITICAL: Set correct color spaces
diffuseMap.colorSpace = THREE.SRGBColorSpace; // Diffuse = SRGB
// normalMap, roughnessMap, aoMap stay at NoColorSpace (default) -- NEVER change these
// Enable tiling
diffuseMap.wrapS = diffuseMap.wrapT = THREE.RepeatWrapping;
normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping;
roughnessMap.wrapS = roughnessMap.wrapT = THREE.RepeatWrapping;
aoMap.wrapS = aoMap.wrapT = THREE.RepeatWrapping;
diffuseMap.repeat.set(2, 2);
normalMap.repeat.set(2, 2);
roughnessMap.repeat.set(2, 2);
aoMap.repeat.set(2, 2);
const material = new THREE.MeshStandardMaterial({
map: diffuseMap,
normalMap: normalMap,
normalScale: new THREE.Vector2(1.0, 1.0),
roughnessMap: roughnessMap,
roughness: 1.0, // Let roughnessMap control per-pixel
metalnessMap: null,
metalness: 0.0, // Brick is dielectric
aoMap: aoMap,
aoMapIntensity: 1.0
});
// Geometry MUST have uv2 attribute for aoMap
const geometry = new THREE.BoxGeometry(2, 2, 2);
geometry.setAttribute('uv2', geometry.getAttribute('uv'));
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);---
Example 2: Glass Material with MeshPhysicalMaterial
Physically-based glass using transmission and thickness.
import * as THREE from 'three';
const glassMaterial = new THREE.MeshPhysicalMaterial({
color: 0xffffff,
metalness: 0.0,
roughness: 0.0,
transmission: 1.0, // Fully transparent (physically-based)
thickness: 0.5, // Volume thickness for refraction
ior: 1.5, // Glass index of refraction
specularIntensity: 1.0,
specularColor: 0xffffff,
envMapIntensity: 1.0,
transparent: true, // Required for transmission to render correctly
side: THREE.DoubleSide // See both faces of glass
});
const glassPane = new THREE.Mesh(
new THREE.PlaneGeometry(2, 3),
glassMaterial
);
scene.add(glassPane);Note: Transmission requires the renderer to capture the scene behind the object. This adds a render pass and has a GPU cost. NEVER use transmission on many small objects -- use simple transparent: true with opacity instead for non-physical transparency.
---
Example 3: HDR Environment Map for PBR
Load an HDR environment map and use it for both lighting and reflections.
import * as THREE from 'three';
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.0;
const rgbeLoader = new RGBELoader();
rgbeLoader.load('environment.hdr', (texture) => {
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = texture; // PBR environment lighting for ALL materials
scene.background = texture; // Optional: visible HDR background
});
// Materials automatically pick up scene.environment -- no need to set envMap per material
const chrome = new THREE.MeshStandardMaterial({
color: 0xffffff,
metalness: 1.0,
roughness: 0.0 // Mirror-like chrome
});
const plastic = new THREE.MeshStandardMaterial({
color: 0xff4444,
metalness: 0.0,
roughness: 0.4 // Slightly glossy plastic
});---
Example 4: Multi-Material on a Single Mesh
Apply different materials to different faces of a geometry using material groups.
import * as THREE from 'three';
// BoxGeometry has 6 groups (one per face), each with materialIndex 0-5
const geometry = new THREE.BoxGeometry(1, 1, 1);
const materials = [
new THREE.MeshStandardMaterial({ color: 0xff0000 }), // +X face (right)
new THREE.MeshStandardMaterial({ color: 0x00ff00 }), // -X face (left)
new THREE.MeshStandardMaterial({ color: 0x0000ff }), // +Y face (top)
new THREE.MeshStandardMaterial({ color: 0xffff00 }), // -Y face (bottom)
new THREE.MeshStandardMaterial({ color: 0xff00ff }), // +Z face (front)
new THREE.MeshStandardMaterial({ color: 0x00ffff }) // -Z face (back)
];
const cube = new THREE.Mesh(geometry, materials);
scene.add(cube);
// For custom geometry, define groups manually:
// geometry.addGroup(startIndex, count, materialIndex);---
Example 5: Proper Material Disposal
Correct cleanup pattern to prevent GPU memory leaks.
import * as THREE from 'three';
function disposeObject(object) {
// Traverse the entire hierarchy
object.traverse((child) => {
if (child.isMesh) {
// Dispose geometry
if (child.geometry) {
child.geometry.dispose();
}
// Dispose material(s)
if (Array.isArray(child.material)) {
child.material.forEach((mat) => disposeMaterial(mat));
} else if (child.material) {
disposeMaterial(child.material);
}
}
});
// Remove from parent
if (object.parent) {
object.parent.remove(object);
}
}
function disposeMaterial(material) {
// Dispose all texture properties
for (const key of Object.keys(material)) {
const value = material[key];
if (value && value.isTexture) {
value.dispose();
}
}
material.dispose();
}
// Usage: ALWAYS call when removing objects from scene
disposeObject(myModel);---
Example 6: Texture Tiling and Anisotropic Filtering
Floor texture with proper repeat, wrapping, and anisotropic filtering for oblique viewing angles.
import * as THREE from 'three';
const loader = new THREE.TextureLoader();
const floorTexture = loader.load('textures/wood_floor.jpg');
// Color space for diffuse textures
floorTexture.colorSpace = THREE.SRGBColorSpace;
// MUST set wrapping mode BEFORE setting repeat
floorTexture.wrapS = THREE.RepeatWrapping;
floorTexture.wrapT = THREE.RepeatWrapping;
floorTexture.repeat.set(10, 10);
// Anisotropic filtering -- essential for floor/ground textures
floorTexture.anisotropy = renderer.capabilities.getMaxAnisotropy();
const floorMaterial = new THREE.MeshStandardMaterial({
map: floorTexture,
roughness: 0.8,
metalness: 0.0
});
const floor = new THREE.Mesh(
new THREE.PlaneGeometry(50, 50),
floorMaterial
);
floor.rotation.x = -Math.PI / 2;
scene.add(floor);Material Types & API Reference (Three.js r160+)
Base Material
All materials extend Material. These methods and properties are available on every material type.
class Material {
// Properties
side: number; // FrontSide | BackSide | DoubleSide
transparent: boolean; // Enable alpha blending
opacity: number; // 0-1 (requires transparent: true)
depthWrite: boolean; // Write to depth buffer
depthTest: boolean; // Test against depth buffer
depthFunc: number; // LessEqualDepth (default)
blending: number; // NormalBlending | AdditiveBlending | SubtractiveBlending | MultiplyBlending | CustomBlending | NoBlending
blendSrc: number; // Source blend factor (CustomBlending)
blendDst: number; // Destination blend factor (CustomBlending)
blendEquation: number; // AddEquation (default)
alphaTest: number; // Discard fragments below this alpha (0-1)
alphaToCoverage: boolean; // Alpha-to-coverage (MSAA only)
clippingPlanes: Plane[] | null; // Clipping planes
clipIntersection: boolean; // Clip ALL planes intersection vs union
clipShadows: boolean; // Apply clipping to shadows
colorWrite: boolean; // Write color
stencilWrite: boolean; // Enable stencil buffer writing
stencilFunc: number; // Stencil comparison function
stencilRef: number; // Stencil reference value
stencilWriteMask: number; // Stencil write bitmask
stencilFuncMask: number; // Stencil function bitmask
stencilFail: number; // Stencil fail operation
stencilZFail: number; // Stencil depth fail operation
stencilZPass: number; // Stencil depth pass operation
polygonOffset: boolean; // Enable polygon offset (decals, coplanar)
polygonOffsetFactor: number; // Polygon offset factor
polygonOffsetUnits: number; // Polygon offset units
visible: boolean; // Render this material
toneMapped: boolean; // Apply renderer tone mapping
needsUpdate: boolean; // Trigger shader recompilation
version: number; // Auto-incremented on changes
// Methods
clone(): Material;
copy(source: Material): Material;
dispose(): void;
onBeforeCompile(shader: Object, renderer: WebGLRenderer): void;
setValues(values: Object): void;
toJSON(): Object;
}---
MeshBasicMaterial
No lighting calculations. Renders flat color or texture.
new MeshBasicMaterial({
color: Color | number; // Default: 0xffffff
map: Texture | null; // Diffuse texture
wireframe: boolean; // Default: false
wireframeLinewidth: number; // Default: 1
combine: number; // MultiplyOperation | MixOperation | AddOperation
reflectivity: number; // 0-1, env map reflectivity
envMap: Texture | null; // Environment map
fog: boolean; // Default: true
alphaMap: Texture | null; // Alpha transparency map
aoMap: Texture | null; // Ambient occlusion map (requires uv2)
aoMapIntensity: number; // Default: 1.0
lightMap: Texture | null; // Baked light map (requires uv2)
lightMapIntensity: number; // Default: 1.0
});---
MeshLambertMaterial
Diffuse-only Lambertian shading. Cheapest lit material -- no specular highlights.
new MeshLambertMaterial({
color: Color | number; // Default: 0xffffff
emissive: Color | number; // Default: 0x000000
emissiveIntensity: number; // Default: 1.0
emissiveMap: Texture | null;
map: Texture | null;
bumpMap: Texture | null;
bumpScale: number; // Default: 1
normalMap: Texture | null;
normalMapType: number; // TangentSpaceNormalMap (default)
normalScale: Vector2; // Default: (1, 1)
displacementMap: Texture | null;
displacementScale: number; // Default: 1
displacementBias: number; // Default: 0
alphaMap: Texture | null;
envMap: Texture | null;
combine: number; // MultiplyOperation (default)
reflectivity: number; // Default: 1
fog: boolean; // Default: true
wireframe: boolean; // Default: false
});---
MeshPhongMaterial
Blinn-Phong model with specular highlights. Cheaper than PBR but not physically correct.
new MeshPhongMaterial({
color: Color | number; // Default: 0xffffff
specular: Color | number; // Default: 0x111111, specular highlight color
shininess: number; // Default: 30, higher = tighter highlight
emissive: Color | number; // Default: 0x000000
emissiveIntensity: number; // Default: 1.0
map: Texture | null;
specularMap: Texture | null; // Specular intensity map
bumpMap: Texture | null;
normalMap: Texture | null;
displacementMap: Texture | null;
envMap: Texture | null;
combine: number; // MultiplyOperation (default)
reflectivity: number; // Default: 1
fog: boolean; // Default: true
flatShading: boolean; // Default: false
wireframe: boolean; // Default: false
});---
MeshStandardMaterial
PBR metalness/roughness workflow. Recommended material for most use cases.
new MeshStandardMaterial({
color: Color | number; // Default: 0xffffff
roughness: number; // 0 (mirror) to 1 (fully rough). Default: 1.0
metalness: number; // 0 (dielectric) to 1 (metal). Default: 0.0
map: Texture | null; // Diffuse/albedo
roughnessMap: Texture | null; // Per-pixel roughness (G channel)
metalnessMap: Texture | null; // Per-pixel metalness (B channel)
normalMap: Texture | null; // Surface normal perturbation
normalMapType: number; // TangentSpaceNormalMap (default)
normalScale: Vector2; // Default: (1, 1)
bumpMap: Texture | null; // Grayscale height map
bumpScale: number; // Default: 1.0
displacementMap: Texture | null; // Vertex displacement
displacementScale: number; // Default: 1.0
displacementBias: number; // Default: 0.0
aoMap: Texture | null; // Ambient occlusion (R channel, requires uv2)
aoMapIntensity: number; // Default: 1.0
emissive: Color | number; // Default: 0x000000
emissiveMap: Texture | null;
emissiveIntensity: number; // Default: 1.0
envMap: Texture | null; // Environment reflection
envMapIntensity: number; // Default: 1.0
alphaMap: Texture | null; // Per-pixel transparency (R channel)
lightMap: Texture | null; // Baked lighting (requires uv2)
lightMapIntensity: number; // Default: 1.0
flatShading: boolean; // Default: false
wireframe: boolean; // Default: false
wireframeLinewidth: number; // Default: 1
fog: boolean; // Default: true
});---
MeshPhysicalMaterial
Extends MeshStandardMaterial with ALL its properties, plus advanced PBR features.
new MeshPhysicalMaterial({
// ALL MeshStandardMaterial properties, plus:
// Clearcoat
clearcoat: number; // 0-1. Default: 0.0
clearcoatRoughness: number; // 0-1. Default: 0.0
clearcoatMap: Texture | null;
clearcoatRoughnessMap: Texture | null;
clearcoatNormalMap: Texture | null;
clearcoatNormalScale: Vector2; // Default: (1, 1)
// Transmission (glass)
transmission: number; // 0-1. Default: 0.0
transmissionMap: Texture | null;
thickness: number; // Default: 0.0
thicknessMap: Texture | null;
ior: number; // 1.0-2.333. Default: 1.5
attenuationDistance: number; // Default: Infinity
attenuationColor: Color; // Default: white
// Sheen (fabric)
sheen: number; // 0-1. Default: 0.0
sheenColor: Color; // Default: 0x000000
sheenColorMap: Texture | null;
sheenRoughness: number; // 0-1. Default: 1.0
sheenRoughnessMap: Texture | null;
// Iridescence (thin-film)
iridescence: number; // 0-1. Default: 0.0
iridescenceIOR: number; // Default: 1.3
iridescenceThicknessRange: [number, number]; // Default: [100, 400] nm
iridescenceMap: Texture | null;
iridescenceThicknessMap: Texture | null;
// Anisotropy
anisotropy: number; // Default: 0.0
anisotropyRotation: number; // Radians. Default: 0.0
anisotropyMap: Texture | null;
// Specular
specularIntensity: number; // Default: 1.0
specularIntensityMap: Texture | null;
specularColor: Color; // Default: white
specularColorMap: Texture | null;
// Other
reflectivity: number; // Default: 0.5
dispersion: number; // Default: 0.0 (chromatic dispersion)
});---
MeshToonMaterial
Cel-shading with discrete light steps.
new MeshToonMaterial({
color: Color | number; // Default: 0xffffff
gradientMap: Texture | null; // Light step gradient (3x1 or 5x1 texture)
map: Texture | null;
normalMap: Texture | null;
bumpMap: Texture | null;
displacementMap: Texture | null;
emissive: Color | number; // Default: 0x000000
alphaMap: Texture | null;
wireframe: boolean; // Default: false
});Rule: ALWAYS set gradientMap.minFilter = NearestFilter and gradientMap.magFilter = NearestFilter.
---
MeshMatcapMaterial
Uses a matcap texture for shading. No lights needed.
new MeshMatcapMaterial({
color: Color | number; // Default: 0xffffff
matcap: Texture | null; // Matcap texture (spherical env baked to 2D)
map: Texture | null;
bumpMap: Texture | null;
normalMap: Texture | null;
displacementMap: Texture | null;
alphaMap: Texture | null;
flatShading: boolean; // Default: false
fog: boolean; // Default: true
});---
Utility Materials
MeshNormalMaterial
Maps surface normals to RGB. Useful for debugging geometry normals.
MeshDepthMaterial
Renders depth from camera. Used internally for shadow maps.
MeshDistanceMaterial
Renders distance from a point light. Used internally for point light shadows.
ShadowMaterial
Receives shadows on a transparent surface.
new ShadowMaterial({
color: Color | number; // Shadow color. Default: 0x000000
transparent: boolean; // MUST be true
opacity: number; // Shadow darkness. Default: 1.0
});---
Line and Point Materials
LineBasicMaterial
new LineBasicMaterial({
color: Color | number; // Default: 0xffffff
linewidth: number; // Default: 1 (>1 NOT supported on most platforms)
});LineDashedMaterial
new LineDashedMaterial({
color: Color | number; // Default: 0xffffff
dashSize: number; // Default: 3
gapSize: number; // Default: 1
scale: number; // Default: 1
});
// ALWAYS call line.computeLineDistances() after creating the Line objectPointsMaterial
new PointsMaterial({
color: Color | number; // Default: 0xffffff
size: number; // Default: 1
sizeAttenuation: boolean; // Default: true (shrinks with distance)
map: Texture | null; // Sprite texture
alphaMap: Texture | null;
alphaTest: number; // Default: 0
});SpriteMaterial
new SpriteMaterial({
color: Color | number; // Default: 0xffffff
map: Texture | null;
alphaMap: Texture | null;
rotation: number; // Radians. Default: 0
sizeAttenuation: boolean; // Default: true
});---
Texture Class
class Texture {
// Properties
image: HTMLImageElement | HTMLCanvasElement | HTMLVideoElement;
mapping: number; // UVMapping (default)
channel: number; // UV channel (0 = uv, 1 = uv2)
wrapS: number; // ClampToEdgeWrapping (default)
wrapT: number; // ClampToEdgeWrapping (default)
magFilter: number; // LinearFilter (default)
minFilter: number; // LinearMipmapLinearFilter (default)
anisotropy: number; // 1 (default), max = renderer.capabilities.getMaxAnisotropy()
format: number; // RGBAFormat (default)
type: number; // UnsignedByteType (default)
offset: Vector2; // (0, 0)
repeat: Vector2; // (1, 1)
rotation: number; // 0
center: Vector2; // (0, 0)
generateMipmaps: boolean; // true
premultiplyAlpha: boolean; // false
flipY: boolean; // true
colorSpace: string; // NoColorSpace
needsUpdate: boolean; // false
// Methods
clone(): Texture;
copy(source: Texture): Texture;
dispose(): void;
transformUv(uv: Vector2): Vector2;
toJSON(meta?: Object): Object;
}