Use when adding new error messages to React, or seeing "unknown error code" warnings.
npx skills add EnzeD/r3f-skills --skill "r3f-materials"
Install specific skill from multi-skill repository
# Description
React Three Fiber materials - PBR materials, Drei materials, shader materials, material properties. Use when styling meshes, creating custom materials, working with textures, or implementing visual effects.
# SKILL.md
name: r3f-materials
description: React Three Fiber materials - PBR materials, Drei materials, shader materials, material properties. Use when styling meshes, creating custom materials, working with textures, or implementing visual effects.
React Three Fiber Materials
Quick Start
import { Canvas } from '@react-three/fiber'
function Scene() {
return (
<Canvas>
<ambientLight intensity={0.5} />
<directionalLight position={[5, 5, 5]} />
<mesh>
<boxGeometry />
<meshStandardMaterial
color="hotpink"
roughness={0.5}
metalness={0.5}
/>
</mesh>
</Canvas>
)
}
Material Types Overview
| Material | Use Case | Lighting |
|---|---|---|
| meshBasicMaterial | Unlit, flat colors | No |
| meshLambertMaterial | Matte surfaces, fast | Yes (diffuse) |
| meshPhongMaterial | Shiny, specular | Yes |
| meshStandardMaterial | PBR, realistic | Yes (PBR) |
| meshPhysicalMaterial | Advanced PBR | Yes (PBR+) |
| meshToonMaterial | Cel-shaded | Yes (toon) |
| meshNormalMaterial | Debug normals | No |
| shaderMaterial | Custom GLSL | Custom |
meshBasicMaterial
No lighting calculations. Always visible, fast.
<mesh>
<boxGeometry />
<meshBasicMaterial
color="red"
transparent
opacity={0.5}
side={THREE.DoubleSide} // FrontSide, BackSide, DoubleSide
wireframe={false}
map={colorTexture}
alphaMap={alphaTexture}
envMap={envTexture}
fog={true}
/>
</mesh>
meshStandardMaterial (PBR)
Physically-based rendering. Recommended for realistic results.
import { useTexture } from '@react-three/drei'
import * as THREE from 'three'
function PBRMesh() {
// Load PBR texture set
const [colorMap, normalMap, roughnessMap, metalnessMap, aoMap] = useTexture([
'/textures/color.jpg',
'/textures/normal.jpg',
'/textures/roughness.jpg',
'/textures/metalness.jpg',
'/textures/ao.jpg',
])
return (
<mesh>
<sphereGeometry args={[1, 64, 64]} />
<meshStandardMaterial
// Base color
color="#ffffff"
map={colorMap}
// PBR properties
roughness={1} // 0 = mirror, 1 = diffuse
roughnessMap={roughnessMap}
metalness={0} // 0 = dielectric, 1 = metal
metalnessMap={metalnessMap}
// Surface detail
normalMap={normalMap}
normalScale={[1, 1]}
// Ambient occlusion (requires uv2)
aoMap={aoMap}
aoMapIntensity={1}
// Emissive
emissive="#000000"
emissiveIntensity={1}
emissiveMap={emissiveTexture}
// Environment
envMap={envTexture}
envMapIntensity={1}
// Other
flatShading={false}
fog={true}
transparent={false}
/>
</mesh>
)
}
meshPhysicalMaterial (Advanced PBR)
Extends Standard with clearcoat, transmission, sheen, etc.
// Glass material
function Glass() {
return (
<mesh>
<sphereGeometry args={[1, 64, 64]} />
<meshPhysicalMaterial
color="#ffffff"
metalness={0}
roughness={0}
transmission={1} // 0 = opaque, 1 = fully transparent
thickness={0.5} // Volume thickness for refraction
ior={1.5} // Index of refraction (glass ~1.5)
envMapIntensity={1}
/>
</mesh>
)
}
// Car paint
function CarPaint() {
return (
<mesh>
<boxGeometry />
<meshPhysicalMaterial
color="#ff0000"
metalness={0.9}
roughness={0.5}
clearcoat={1} // Clearcoat layer strength
clearcoatRoughness={0.1} // Clearcoat roughness
/>
</mesh>
)
}
// Fabric/velvet (sheen)
function Fabric() {
return (
<mesh>
<sphereGeometry args={[1, 64, 64]} />
<meshPhysicalMaterial
color="#8844aa"
roughness={0.8}
sheen={1}
sheenRoughness={0.5}
sheenColor="#ff88ff"
/>
</mesh>
)
}
// Iridescent (soap bubbles)
function Iridescent() {
return (
<mesh>
<sphereGeometry args={[1, 64, 64]} />
<meshPhysicalMaterial
color="#ffffff"
iridescence={1}
iridescenceIOR={1.3}
iridescenceThicknessRange={[100, 400]}
/>
</mesh>
)
}
Drei Special Materials
MeshReflectorMaterial
Realistic mirror-like reflections.
import { MeshReflectorMaterial } from '@react-three/drei'
function ReflectiveFloor() {
return (
<mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, -0.5, 0]}>
<planeGeometry args={[10, 10]} />
<MeshReflectorMaterial
blur={[400, 100]} // Blur amount [x, y]
resolution={1024} // Reflection resolution
mixBlur={1} // Mix blur with reflection
mixStrength={0.5} // Reflection strength
roughness={1}
depthScale={1.2}
minDepthThreshold={0.4}
maxDepthThreshold={1.4}
color="#333"
metalness={0.5}
mirror={0.5}
/>
</mesh>
)
}
MeshWobbleMaterial
Animated wobble effect.
import { MeshWobbleMaterial } from '@react-three/drei'
function WobblyMesh() {
return (
<mesh>
<torusKnotGeometry args={[1, 0.4, 100, 16]} />
<MeshWobbleMaterial
factor={1} // Wobble amplitude
speed={2} // Wobble speed
color="hotpink"
metalness={0}
roughness={0.5}
/>
</mesh>
)
}
MeshDistortMaterial
Perlin noise distortion.
import { MeshDistortMaterial } from '@react-three/drei'
function DistortedMesh() {
return (
<mesh>
<sphereGeometry args={[1, 64, 64]} />
<MeshDistortMaterial
distort={0.5} // Distortion amount
speed={2} // Animation speed
color="cyan"
roughness={0.2}
/>
</mesh>
)
}
MeshTransmissionMaterial
Better glass/refractive materials.
import { MeshTransmissionMaterial } from '@react-three/drei'
function GlassSphere() {
return (
<mesh>
<sphereGeometry args={[1, 64, 64]} />
<MeshTransmissionMaterial
backside // Render backside
samples={16} // Refraction samples
resolution={1024} // Buffer resolution
transmission={1} // Transmission factor
roughness={0.0}
thickness={0.5} // Volume thickness
ior={1.5} // Index of refraction
chromaticAberration={0.06}
anisotropy={0.1}
distortion={0.0}
distortionScale={0.3}
temporalDistortion={0.5}
clearcoat={1}
attenuationDistance={0.5}
attenuationColor="#ffffff"
color="#c9ffa1"
/>
</mesh>
)
}
MeshDiscardMaterial
Discard fragments - useful for shadows only.
import { MeshDiscardMaterial } from '@react-three/drei'
function ShadowOnlyMesh() {
return (
<mesh castShadow>
<boxGeometry />
<MeshDiscardMaterial /> {/* Invisible but casts shadows */}
</mesh>
)
}
Points and Lines Materials
// Points material
<points>
<bufferGeometry />
<pointsMaterial
size={0.1}
sizeAttenuation={true}
color="white"
map={spriteTexture}
transparent
alphaTest={0.5}
vertexColors
/>
</points>
// Line materials
<line>
<bufferGeometry />
<lineBasicMaterial color="white" linewidth={1} />
</line>
<line>
<bufferGeometry />
<lineDashedMaterial
color="white"
dashSize={0.5}
gapSize={0.25}
scale={1}
/>
</line>
Common Material Properties
All materials share these base properties:
<meshStandardMaterial
// Visibility
visible={true}
transparent={false}
opacity={1}
alphaTest={0} // Discard pixels with alpha < value
// Rendering
side={THREE.FrontSide} // FrontSide, BackSide, DoubleSide
depthTest={true}
depthWrite={true}
colorWrite={true}
// Blending
blending={THREE.NormalBlending}
// NormalBlending, AdditiveBlending, SubtractiveBlending, MultiplyBlending
// Polygon offset (z-fighting fix)
polygonOffset={false}
polygonOffsetFactor={0}
polygonOffsetUnits={0}
// Misc
dithering={false}
toneMapped={true}
/>
Dynamic Materials
Updating Material Properties
import { useRef } from 'react'
import { useFrame } from '@react-three/fiber'
function AnimatedMaterial() {
const materialRef = useRef()
useFrame(({ clock }) => {
const t = clock.elapsedTime
// Update color
materialRef.current.color.setHSL((t * 0.1) % 1, 1, 0.5)
// Update properties
materialRef.current.roughness = (Math.sin(t) + 1) / 2
})
return (
<mesh>
<boxGeometry />
<meshStandardMaterial ref={materialRef} />
</mesh>
)
}
Shared Materials
import { useMemo } from 'react'
import * as THREE from 'three'
function SharedMaterial() {
// Create once, use many times
const material = useMemo(() =>
new THREE.MeshStandardMaterial({ color: 'red' }),
[])
return (
<>
<mesh position={[-2, 0, 0]} material={material}>
<boxGeometry />
</mesh>
<mesh position={[0, 0, 0]} material={material}>
<sphereGeometry />
</mesh>
<mesh position={[2, 0, 0]} material={material}>
<coneGeometry />
</mesh>
</>
)
}
Multiple Materials
// Different materials per face (BoxGeometry has 6 material groups)
<mesh>
<boxGeometry />
<meshStandardMaterial attach="material-0" color="red" /> {/* +X */}
<meshStandardMaterial attach="material-1" color="green" /> {/* -X */}
<meshStandardMaterial attach="material-2" color="blue" /> {/* +Y */}
<meshStandardMaterial attach="material-3" color="yellow" />{/* -Y */}
<meshStandardMaterial attach="material-4" color="cyan" /> {/* +Z */}
<meshStandardMaterial attach="material-5" color="magenta" />{/* -Z */}
</mesh>
Material with Textures
import { useTexture } from '@react-three/drei'
import * as THREE from 'three'
function TexturedMaterial() {
// Named object pattern (recommended)
const textures = useTexture({
map: '/textures/color.jpg',
normalMap: '/textures/normal.jpg',
roughnessMap: '/textures/roughness.jpg',
})
// Set texture properties
Object.values(textures).forEach(texture => {
texture.wrapS = texture.wrapT = THREE.RepeatWrapping
texture.repeat.set(2, 2)
})
return (
<mesh>
<planeGeometry args={[5, 5]} />
<meshStandardMaterial {...textures} />
</mesh>
)
}
Emissive Materials (Glow)
// For bloom effect, emissive colors should exceed normal range
<meshStandardMaterial
color="black"
emissive="#ff0000"
emissiveIntensity={2} // > 1 for bloom
toneMapped={false} // Required for colors > 1
/>
// With emissive map
<meshStandardMaterial
emissive="white"
emissiveMap={emissiveTexture}
emissiveIntensity={2}
toneMapped={false}
/>
Environment Maps
import { useEnvironment } from '@react-three/drei'
function EnvMappedMaterial() {
const envMap = useEnvironment({ preset: 'sunset' })
return (
<mesh>
<sphereGeometry args={[1, 64, 64]} />
<meshStandardMaterial
metalness={1}
roughness={0}
envMap={envMap}
envMapIntensity={1}
/>
</mesh>
)
}
Custom Shader Materials
See r3f-shaders for detailed shader material usage.
import { shaderMaterial } from '@react-three/drei'
import { extend } from '@react-three/fiber'
const CustomMaterial = shaderMaterial(
{ time: 0, color: new THREE.Color('hotpink') },
// Vertex shader
`
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
// Fragment shader
`
uniform float time;
uniform vec3 color;
varying vec2 vUv;
void main() {
gl_FragColor = vec4(color * (sin(time + vUv.x * 10.0) * 0.5 + 0.5), 1.0);
}
`
)
extend({ CustomMaterial })
function CustomShaderMesh() {
const materialRef = useRef()
useFrame(({ clock }) => {
materialRef.current.time = clock.elapsedTime
})
return (
<mesh>
<boxGeometry />
<customMaterial ref={materialRef} />
</mesh>
)
}
Performance Tips
- Reuse materials: Same material instance = batched draw calls
- Avoid transparent: Requires sorting, slower
- Use alphaTest over transparent: When possible, faster
- Simpler materials: Basic > Lambert > Phong > Standard > Physical
- Limit texture sizes: 1024-2048 usually sufficient
// Material caching pattern
const materialCache = new Map()
function getCachedMaterial(color) {
const key = color.toString()
if (!materialCache.has(key)) {
materialCache.set(key, new THREE.MeshStandardMaterial({ color }))
}
return materialCache.get(key)
}
See Also
r3f-textures- Texture loading and configurationr3f-shaders- Custom shader developmentr3f-lighting- Light interaction with materials
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.