Back to UI/UX Design

threejs-materials

three.jsmaterialspbrshaderswebgl3d graphicsrenderinglighting
2.4k🕒 2026-01-19Source ↗

Install this skill

npx skills add cloudai-x/threejs-skills

Works across Claude Code, Cursor, Codex, Copilot & Antigravity

Three.js materials define how 3D surfaces interact with light, textures, and the scene environment. By selecting a specific material class, developers determine the visual fidelity and performance cost of an object. Options range from performant, unlit shaders like MeshBasicMaterial to physically-based rendering (PBR) systems like MeshPhysicalMaterial that simulate complex optics like refraction, clearcoats, and metallic surfaces. Properly configuring these materials requires balancing aesthetic needs against hardware capabilities, as advanced effects increase GPU load. This skill covers the implementation of standard, specular, and custom shaders, ensuring developers can match the surface properties of their virtual assets to the desired art direction while maintaining consistent frame rates across WebGL-supported browsers.

When to Use This Skill

  • Rendering photorealistic product showcases using MeshPhysicalMaterial
  • Applying consistent cartoon-style cel-shading to stylized characters
  • Visualizing technical geometry data using MeshNormal or MeshDepth materials
  • Creating glass, water, or soap bubble effects with transmission and IOR properties

How to Invoke This Skill

Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:

  • Apply a realistic metallic finish to this 3D model
  • Create a glass material with refraction and thickness
  • How do I set up a cel-shaded look for my mesh?
  • Add an environment map to my standard material
  • Explain the difference between MeshPhong and MeshStandardMaterial
  • Optimize my scene materials for better performance

Pro Tips

  • 💡Always consider `MeshStandardMaterial` for modern PBR workflows as a default, then simplify to basic or phong materials only if performance is critical or a specific non-PBR look is desired.
  • 💡Leverage `material.onBeforeCompile` to inject custom GLSL code into standard materials, offering fine-grained shader control without rewriting entire shaders from scratch.
  • 💡For static UI elements, background objects, or performance-critical areas that don't require complex lighting, utilize `MeshBasicMaterial` or `MeshLambertMaterial` to minimize GPU load.

What this skill does

  • Implement physically-based rendering (PBR) for realistic surface light interaction
  • Define surface appearance using color, roughness, metalness, and emissive maps
  • Simulate complex optical effects like refraction, transmission, and iridescence
  • Configure custom lighting models via GLSL-based ShaderMaterials
  • Optimize rendering performance by choosing between unlit and lit material types

When not to use it

  • When target hardware is extremely low-end and requires minimal draw calls and shader complexity
  • When needing non-standard post-processing effects that require full-screen buffer manipulation rather than object-specific surface properties

Example workflow

  1. Define the geometry for the 3D object
  2. Select the appropriate material type based on desired lighting and realism requirements
  3. Load necessary texture maps such as albedo, normal, and roughness
  4. Apply specific material properties like metalness, roughness, or refraction index
  5. Assign the material to a Mesh instance and add it to the Three.js scene

Prerequisites

  • Basic knowledge of Three.js Scene, Camera, and Renderer setup
  • Understanding of UV mapping and texture coordinate systems

Pitfalls & limitations

  • !Forgetting to provide a second UV channel for AO maps which results in incorrect shadows
  • !Overusing MeshPhysicalMaterial on mobile devices causing significant framerate drops
  • !Confusing light-dependent materials with unlit materials, leading to black or invisible objects when lights are missing

FAQ

Why is my material appearing completely black?
This usually happens because the material requires light to be visible (like MeshStandardMaterial) but no light sources have been added to the scene.
How do I make a surface look metallic?
Use MeshStandardMaterial and set the metalness property to 1.0, ensuring you have an environment map defined for realistic reflections.
What is the difference between MeshLambertMaterial and MeshPhongMaterial?
MeshLambertMaterial calculates light only at vertices, making it faster but less accurate, whereas MeshPhongMaterial calculates light per pixel, providing sharper specular highlights.
Do I need to load external files for every material?
No, you can define materials using hex colors and numerical parameters, though texture maps are required for advanced visual surface detail.

How it compares

Using this library provides a structured API that prevents manual low-level buffer management, allowing for declarative material definitions that integrate directly with the Three.js render loop.

Source & trust

2.4k stars🕒 Updated 2026-01-19
📄 Full skill instructions — original source: cloudai-x/threejs-skills
# Three.js Materials

## Quick Start

import * as THREE from "three";

// PBR material (recommended for realistic rendering)
const material = new THREE.MeshStandardMaterial({
color: 0x00ff00,
roughness: 0.5,
metalness: 0.5,
});

const mesh = new THREE.Mesh(geometry, material);


## Material Types Overview

| Material | Use Case | Lighting |
| -------------------- | ------------------------------------- | ------------------ |
| MeshBasicMaterial | Unlit, flat colors, wireframes | No |
| MeshLambertMaterial | Matte surfaces, performance | Yes (diffuse only) |
| MeshPhongMaterial | Shiny surfaces, specular highlights | Yes |
| MeshStandardMaterial | PBR, realistic materials | Yes (PBR) |
| MeshPhysicalMaterial | Advanced PBR, clearcoat, transmission | Yes (PBR+) |
| MeshToonMaterial | Cel-shaded, cartoon look | Yes (toon) |
| MeshNormalMaterial | Debug normals | No |
| MeshDepthMaterial | Depth visualization | No |
| ShaderMaterial | Custom GLSL shaders | Custom |
| RawShaderMaterial | Full shader control | Custom |

## MeshBasicMaterial

No lighting calculations. Fast, always visible.

const material = new THREE.MeshBasicMaterial({
color: 0xff0000,
transparent: true,
opacity: 0.5,
side: THREE.DoubleSide, // FrontSide, BackSide, DoubleSide
wireframe: false,
map: texture, // Color/diffuse texture
alphaMap: alphaTexture, // Transparency texture
envMap: envTexture, // Reflection texture
reflectivity: 1, // Env map intensity
fog: true, // Affected by scene fog
});


## MeshLambertMaterial

Diffuse-only lighting. Fast, no specular highlights.

const material = new THREE.MeshLambertMaterial({
color: 0x00ff00,
emissive: 0x111111, // Self-illumination color
emissiveIntensity: 1,
map: texture,
emissiveMap: emissiveTexture,
envMap: envTexture,
reflectivity: 0.5,
});


## MeshPhongMaterial

Specular highlights. Good for shiny, plastic-like surfaces.

const material = new THREE.MeshPhongMaterial({
color: 0x0000ff,
specular: 0xffffff, // Highlight color
shininess: 100, // Highlight sharpness (0-1000)
emissive: 0x000000,
flatShading: false, // Flat vs smooth shading
map: texture,
specularMap: specTexture, // Per-pixel shininess
normalMap: normalTexture,
normalScale: new THREE.Vector2(1, 1),
bumpMap: bumpTexture,
bumpScale: 1,
displacementMap: dispTexture,
displacementScale: 1,
});


## MeshStandardMaterial (PBR)

Physically-based rendering. Recommended for realistic results.

const material = new THREE.MeshStandardMaterial({
color: 0xffffff,
roughness: 0.5, // 0 = mirror, 1 = diffuse
metalness: 0.0, // 0 = dielectric, 1 = metal

// Textures
map: colorTexture, // Albedo/base color
roughnessMap: roughTexture, // Per-pixel roughness
metalnessMap: metalTexture, // Per-pixel metalness
normalMap: normalTexture, // Surface detail
normalScale: new THREE.Vector2(1, 1),
aoMap: aoTexture, // Ambient occlusion (uses uv2!)
aoMapIntensity: 1,
displacementMap: dispTexture, // Vertex displacement
displacementScale: 0.1,
displacementBias: 0,

// Emissive
emissive: 0x000000,
emissiveIntensity: 1,
emissiveMap: emissiveTexture,

// Environment
envMap: envTexture,
envMapIntensity: 1,

// Other
flatShading: false,
wireframe: false,
fog: true,
});

// Note: aoMap requires second UV channel
geometry.setAttribute("uv2", geometry.attributes.uv);


## MeshPhysicalMaterial (Advanced PBR)

Extends MeshStandardMaterial with advanced features.

const material = new THREE.MeshPhysicalMaterial({
// All MeshStandardMaterial properties plus:

// Clearcoat (car paint, lacquer)
clearcoat: 1.0, // 0-1 clearcoat layer strength
clearcoatRoughness: 0.1,
clearcoatMap: ccTexture,
clearcoatRoughnessMap: ccrTexture,
clearcoatNormalMap: ccnTexture,
clearcoatNormalScale: new THREE.Vector2(1, 1),

// Transmission (glass, water)
transmission: 1.0, // 0 = opaque, 1 = fully transparent
transmissionMap: transTexture,
thickness: 0.5, // Volume thickness for refraction
thicknessMap: thickTexture,
attenuationDistance: 1, // Absorption distance
attenuationColor: new THREE.Color(0xffffff),

// Refraction
ior: 1.5, // Index of refraction (1-2.333)

// Sheen (fabric, velvet)
sheen: 1.0,
sheenRoughness: 0.5,
sheenColor: new THREE.Color(0xffffff),
sheenColorMap: sheenTexture,
sheenRoughnessMap: sheenRoughTexture,

// Iridescence (soap bubbles, oil slicks)
iridescence: 1.0,
iridescenceIOR: 1.3,
iridescenceThicknessRange: [100, 400],
iridescenceMap: iridTexture,
iridescenceThicknessMap: iridThickTexture,

// Anisotropy (brushed metal)
anisotropy: 1.0,
anisotropyRotation: 0,
anisotropyMap: anisoTexture,

// Specular
specularIntensity: 1,
specularColor: new THREE.Color(0xffffff),
specularIntensityMap: specIntTexture,
specularColorMap: specColorTexture,
});


### Glass Material Example

const glass = new THREE.MeshPhysicalMaterial({
color: 0xffffff,
metalness: 0,
roughness: 0,
transmission: 1,
thickness: 0.5,
ior: 1.5,
envMapIntensity: 1,
});


### Car Paint Example

const carPaint = new THREE.MeshPhysicalMaterial({
color: 0xff0000,
metalness: 0.9,
roughness: 0.5,
clearcoat: 1,
clearcoatRoughness: 0.1,
});


## MeshToonMaterial

Cel-shaded cartoon look.

const material = new THREE.MeshToonMaterial({
color: 0x00ff00,
gradientMap: gradientTexture, // Optional: custom shading gradient
});

// Create step gradient texture
const colors = new Uint8Array([0, 128, 255]);
const gradientMap = new THREE.DataTexture(colors, 3, 1, THREE.RedFormat);
gradientMap.minFilter = THREE.NearestFilter;
gradientMap.magFilter = THREE.NearestFilter;
gradientMap.needsUpdate = true;


## MeshNormalMaterial

Visualize surface normals. Useful for debugging.

const material = new THREE.MeshNormalMaterial({
flatShading: false,
wireframe: false,
});


## MeshDepthMaterial

Render depth values. Used for shadow maps, DOF effects.

const material = new THREE.MeshDepthMaterial({
depthPacking: THREE.RGBADepthPacking,
});


## PointsMaterial

For point clouds.

const material = new THREE.PointsMaterial({
color: 0xffffff,
size: 0.1,
sizeAttenuation: true, // Scale with distance
map: pointTexture,
alphaMap: alphaTexture,
transparent: true,
alphaTest: 0.5, // Discard pixels below threshold
vertexColors: true, // Use per-vertex colors
});

const points = new THREE.Points(geometry, material);


## LineBasicMaterial & LineDashedMaterial

// Solid lines
const lineMaterial = new THREE.LineBasicMaterial({
color: 0xffffff,
linewidth: 1, // Note: >1 only works on some systems
linecap: "round",
linejoin: "round",
});

// Dashed lines
const dashedMaterial = new THREE.LineDashedMaterial({
color: 0xffffff,
dashSize: 0.5,
gapSize: 0.25,
scale: 1,
});

// Required for dashed lines
const line = new THREE.Line(geometry, dashedMaterial);
line.computeLineDistances();


## ShaderMaterial

Custom GLSL shaders with Three.js uniforms.

const material = new THREE.ShaderMaterial({
uniforms: {
time: { value: 0 },
color: { value: new THREE.Color(0xff0000) },
texture1: { value: texture },
},
vertexShader:
varying vec2 vUv;
uniform float time;

void main() {
vUv = uv;
vec3 pos = position;
pos.z += sin(pos.x * 10.0 + time) * 0.1;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
,
fragmentShader:
varying vec2 vUv;
uniform vec3 color;
uniform sampler2D texture1;

void main() {
// Use texture2D() for GLSL 1.0, texture() for GLSL 3.0 (glslVersion: THREE.GLSL3)
vec4 texColor = texture2D(texture1, vUv);
gl_FragColor = vec4(color * texColor.rgb, 1.0);
}
,
transparent: true,
side: THREE.DoubleSide,
});

// Update uniform in animation loop
material.uniforms.time.value = clock.getElapsedTime();


### Built-in Uniforms (auto-provided)

// Vertex shader
uniform mat4 modelMatrix; // Object to world
uniform mat4 modelViewMatrix; // Object to camera
uniform mat4 projectionMatrix; // Camera projection
uniform mat4 viewMatrix; // World to camera
uniform mat3 normalMatrix; // For transforming normals
uniform vec3 cameraPosition; // Camera world position

// Attributes
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;


## RawShaderMaterial

Full control - no built-in uniforms/attributes.

const material = new THREE.RawShaderMaterial({
uniforms: {
projectionMatrix: { value: camera.projectionMatrix },
modelViewMatrix: { value: new THREE.Matrix4() },
},
vertexShader:
precision highp float;
attribute vec3 position;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;

void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
,
fragmentShader:
precision highp float;

void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
,
});


## Common Material Properties

All materials share these base properties:

// Visibility
material.visible = true;
material.transparent = false;
material.opacity = 1.0;
material.alphaTest = 0; // Discard pixels with alpha < value

// Rendering
material.side = THREE.FrontSide; // FrontSide, BackSide, DoubleSide
material.depthTest = true;
material.depthWrite = true;
material.colorWrite = true;

// Blending
material.blending = THREE.NormalBlending;
// NormalBlending, AdditiveBlending, SubtractiveBlending, MultiplyBlending, CustomBlending

// Stencil
material.stencilWrite = false;
material.stencilFunc = THREE.AlwaysStencilFunc;
material.stencilRef = 0;
material.stencilMask = 0xff;

// Polygon offset (z-fighting fix)
material.polygonOffset = false;
material.polygonOffsetFactor = 0;
material.polygonOffsetUnits = 0;

// Misc
material.dithering = false;
material.toneMapped = true;


## Multiple Materials

// Assign different materials to geometry groups
const geometry = new THREE.BoxGeometry(1, 1, 1);
const materials = [
new THREE.MeshBasicMaterial({ color: 0xff0000 }), // right
new THREE.MeshBasicMaterial({ color: 0x00ff00 }), // left
new THREE.MeshBasicMaterial({ color: 0x0000ff }), // top
new THREE.MeshBasicMaterial({ color: 0xffff00 }), // bottom
new THREE.MeshBasicMaterial({ color: 0xff00ff }), // front
new THREE.MeshBasicMaterial({ color: 0x00ffff }), // back
];
const mesh = new THREE.Mesh(geometry, materials);

// Custom groups
geometry.clearGroups();
geometry.addGroup(0, 6, 0); // start, count, materialIndex
geometry.addGroup(6, 6, 1);


## Environment Maps

// Load cube texture
const cubeLoader = new THREE.CubeTextureLoader();
const envMap = cubeLoader.load([
"px.jpg",
"nx.jpg", // positive/negative X
"py.jpg",
"ny.jpg", // positive/negative Y
"pz.jpg",
"nz.jpg", // positive/negative Z
]);

// Apply to material
material.envMap = envMap;
material.envMapIntensity = 1;

// Or set as scene environment (affects all PBR materials)
scene.environment = envMap;

// HDR environment (recommended)
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
const rgbeLoader = new RGBELoader();
rgbeLoader.load("environment.hdr", (texture) => {
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = texture;
scene.background = texture;
});


## Material Cloning and Modification

// Clone material
const clone = material.clone();
clone.color.set(0x00ff00);

// Modify at runtime
material.color.set(0xff0000);
material.needsUpdate = true; // Only needed for some changes

// When needsUpdate is required:
// - Changing flat shading
// - Changing texture
// - Changing transparent
// - Custom shader code changes


## Performance Tips

1. **Reuse materials**: Same material = batched draw calls
2. **Avoid transparent when possible**: Transparent materials require sorting
3. **Use alphaTest instead of transparency**: When applicable, faster
4. **Choose simpler materials**: Basic > Lambert > Phong > Standard > Physical
5. **Limit active lights**: Each light adds shader complexity

// Material pooling
const materialCache = new Map();
function getMaterial(color) {
const key = color.toString(16);
if (!materialCache.has(key)) {
materialCache.set(key, new THREE.MeshStandardMaterial({ color }));
}
return materialCache.get(key);
}

// Dispose when done
material.dispose();


## See Also

- threejs-textures - Texture loading and configuration
- threejs-shaders - Custom shader development
- threejs-lighting - Light interaction with materials

How to Use This Skill Unit

Option A: Project-Specific (Recommended)

  1. Click "Download" above
  2. In your project, create the directory: .agent/skills/threejs-materials/
  3. Save the file as SKILL.md
  4. The agent will automatically discover the skill based on its description.

Option B: Global Installation (All Agents)

Save the file to these locations to make it available across all projects:

  • Claude Code: ~/.claude/skills/cloudai-x/threejs-skills/threejs-materials/SKILL.md
  • Cursor: ~/.cursor/skills/cloudai-x/threejs-skills/threejs-materials/SKILL.md
  • Antigravity: ~/.gemini/antigravity/skills/cloudai-x/threejs-skills/threejs-materials/SKILL.md

🚀 Install with CLI:
npx skills add cloudai-x/threejs-skills

Read the Master Guide: Mastering Agent Skills

Related Skill Units

Recommended Rules

View more rules

Recommended Workflows

View more workflows

Recommended MCP Servers

View more MCP servers

Take It Further

Maximize your productivity with these powerful resources

📋

Define Your Standards

Set up coding standards to ensure this workflow produces consistent, high-quality results.

Browse Rules Library
📖

Master Workflows

Learn how to create custom workflows, use Turbo Mode, and build your automation library.

Complete Guide

How to use this Skill in Claude Code & Cursor

For Claude Code (CLI)

To use this skill in Claude Code, copy the rule content into your project's custom instructions or follow our Add-Skill CLI guide. This ensures Claude follows your standards during every code generation.

For Cursor & Windsurf

For Cursor or Windsurf, individual skills are best used in the "Rules for AI" section. This specific unit helps the agent avoid ui/ux design issues, leading to cleaner, more efficient code.

Why the skill format matters: the standardized Agent Skills format lets your AI agent load detailed instructions only when they are relevant, keeping your prompt clean while improving results.

Source & attribution

This skill is categorized under UI/UX Design and is published by CloudAI-X, maintained in cloudai-x/threejs-skills.

← Browse All Agent Skills
Sponsored AI assistant. Recommendations may be paid.