r3f-textures
React Three Fiber textures - useTexture, texture loading, environment maps, texture configuration. Use when loading images, working with PBR texture sets, cubemaps, HDR environments, or optimizing texture usage.
Best use case
r3f-textures is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
React Three Fiber textures - useTexture, texture loading, environment maps, texture configuration. Use when loading images, working with PBR texture sets, cubemaps, HDR environments, or optimizing texture usage.
Teams using r3f-textures should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/r3f-textures/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How r3f-textures Compares
| Feature / Agent | r3f-textures | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
React Three Fiber textures - useTexture, texture loading, environment maps, texture configuration. Use when loading images, working with PBR texture sets, cubemaps, HDR environments, or optimizing texture usage.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# React Three Fiber Textures
## Quick Start
```tsx
import { Canvas } from '@react-three/fiber'
import { useTexture } from '@react-three/drei'
function TexturedBox() {
const texture = useTexture('/textures/wood.jpg')
return (
<mesh>
<boxGeometry />
<meshStandardMaterial map={texture} />
</mesh>
)
}
export default function App() {
return (
<Canvas>
<ambientLight />
<TexturedBox />
</Canvas>
)
}
```
## useTexture Hook (Drei)
The recommended way to load textures in R3F.
### Single Texture
```tsx
import { useTexture } from '@react-three/drei'
function SingleTexture() {
const texture = useTexture('/textures/color.jpg')
return (
<mesh>
<planeGeometry args={[5, 5]} />
<meshBasicMaterial map={texture} />
</mesh>
)
}
```
### Multiple Textures (Array)
```tsx
function MultipleTextures() {
const [colorMap, normalMap, roughnessMap] = useTexture([
'/textures/color.jpg',
'/textures/normal.jpg',
'/textures/roughness.jpg',
])
return (
<mesh>
<sphereGeometry args={[1, 64, 64]} />
<meshStandardMaterial
map={colorMap}
normalMap={normalMap}
roughnessMap={roughnessMap}
/>
</mesh>
)
}
```
### Named Object (Recommended for PBR)
```tsx
function PBRTextures() {
// Named object automatically spreads to material
const textures = useTexture({
map: '/textures/color.jpg',
normalMap: '/textures/normal.jpg',
roughnessMap: '/textures/roughness.jpg',
metalnessMap: '/textures/metalness.jpg',
aoMap: '/textures/ao.jpg',
displacementMap: '/textures/displacement.jpg',
})
return (
<mesh>
<sphereGeometry args={[1, 64, 64]} />
<meshStandardMaterial
{...textures}
displacementScale={0.1}
/>
</mesh>
)
}
```
### With Texture Configuration
```tsx
import { useTexture } from '@react-three/drei'
import * as THREE from 'three'
function ConfiguredTextures() {
const textures = useTexture({
map: '/textures/color.jpg',
normalMap: '/textures/normal.jpg',
}, (textures) => {
// Configure textures after loading
Object.values(textures).forEach(texture => {
texture.wrapS = texture.wrapT = THREE.RepeatWrapping
texture.repeat.set(4, 4)
})
})
return (
<mesh>
<planeGeometry args={[10, 10]} />
<meshStandardMaterial {...textures} />
</mesh>
)
}
```
### Preloading
```tsx
import { useTexture } from '@react-three/drei'
// Preload at module level
useTexture.preload('/textures/hero.jpg')
useTexture.preload(['/tex1.jpg', '/tex2.jpg'])
function Component() {
// Will be instant if preloaded
const texture = useTexture('/textures/hero.jpg')
}
```
## useLoader (Core R3F)
For more control over loading.
```tsx
import { useLoader } from '@react-three/fiber'
import { TextureLoader } from 'three'
function WithUseLoader() {
const texture = useLoader(TextureLoader, '/textures/color.jpg')
// Multiple textures
const [color, normal] = useLoader(TextureLoader, [
'/textures/color.jpg',
'/textures/normal.jpg',
])
return (
<mesh>
<boxGeometry />
<meshStandardMaterial map={color} normalMap={normal} />
</mesh>
)
}
// Preload
useLoader.preload(TextureLoader, '/textures/color.jpg')
```
## Texture Configuration
### Wrapping Modes
```tsx
import * as THREE from 'three'
function ConfigureWrapping() {
const texture = useTexture('/textures/tile.jpg', (tex) => {
// Wrapping
tex.wrapS = THREE.RepeatWrapping // Horizontal: ClampToEdgeWrapping, RepeatWrapping, MirroredRepeatWrapping
tex.wrapT = THREE.RepeatWrapping // Vertical
// Repeat
tex.repeat.set(4, 4) // Tile 4x4
// Offset
tex.offset.set(0.5, 0.5) // Shift UV
// Rotation
tex.rotation = Math.PI / 4 // Rotate 45 degrees
tex.center.set(0.5, 0.5) // Rotation pivot
})
return (
<mesh>
<planeGeometry args={[10, 10]} />
<meshStandardMaterial map={texture} />
</mesh>
)
}
```
### Filtering
```tsx
function ConfigureFiltering() {
const texture = useTexture('/textures/color.jpg', (tex) => {
// Minification (texture larger than screen pixels)
tex.minFilter = THREE.LinearMipmapLinearFilter // Smooth with mipmaps (default)
tex.minFilter = THREE.NearestFilter // Pixelated
tex.minFilter = THREE.LinearFilter // Smooth, no mipmaps
// Magnification (texture smaller than screen pixels)
tex.magFilter = THREE.LinearFilter // Smooth (default)
tex.magFilter = THREE.NearestFilter // Pixelated (retro style)
// Anisotropic filtering (sharper at angles)
tex.anisotropy = 16 // Usually renderer.capabilities.getMaxAnisotropy()
// Generate mipmaps
tex.generateMipmaps = true // Default
})
}
```
### Color Space
Important for accurate colors.
```tsx
function ConfigureColorSpace() {
const [colorMap, normalMap, roughnessMap] = useTexture([
'/textures/color.jpg',
'/textures/normal.jpg',
'/textures/roughness.jpg',
], (textures) => {
// Color/albedo textures should use sRGB
textures[0].colorSpace = THREE.SRGBColorSpace
// Data textures (normal, roughness, metalness, ao) use Linear
// This is the default, so usually no action needed
// textures[1].colorSpace = THREE.LinearSRGBColorSpace
// textures[2].colorSpace = THREE.LinearSRGBColorSpace
})
}
```
## Environment Maps
### useEnvironment Hook
```tsx
import { useEnvironment, Environment } from '@react-three/drei'
// Use as texture
function EnvMappedSphere() {
const envMap = useEnvironment({ preset: 'sunset' })
return (
<mesh>
<sphereGeometry args={[1, 64, 64]} />
<meshStandardMaterial
metalness={1}
roughness={0}
envMap={envMap}
/>
</mesh>
)
}
// Or use Environment component for scene-wide
function Scene() {
return (
<>
<Environment preset="sunset" background />
<Mesh />
</>
)
}
```
### HDR Environment
```tsx
import { useEnvironment } from '@react-three/drei'
function HDREnvironment() {
const envMap = useEnvironment({ files: '/hdri/studio.hdr' })
return (
<mesh>
<sphereGeometry args={[1, 64, 64]} />
<meshStandardMaterial
metalness={1}
roughness={0}
envMap={envMap}
envMapIntensity={1}
/>
</mesh>
)
}
```
### Cube Map
```tsx
import { useCubeTexture } from '@react-three/drei'
function CubeMapTexture() {
const envMap = useCubeTexture(
['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg'],
{ path: '/textures/cube/' }
)
return (
<mesh>
<sphereGeometry args={[1, 64, 64]} />
<meshStandardMaterial envMap={envMap} metalness={1} roughness={0} />
</mesh>
)
}
```
## Video Textures
```tsx
import { useVideoTexture } from '@react-three/drei'
function VideoPlane() {
const texture = useVideoTexture('/videos/sample.mp4', {
start: true,
loop: true,
muted: true,
})
return (
<mesh>
<planeGeometry args={[16, 9].map(x => x * 0.5)} />
<meshBasicMaterial map={texture} toneMapped={false} />
</mesh>
)
}
```
## Canvas Textures
```tsx
import { useRef, useEffect } from 'react'
import { useFrame } from '@react-three/fiber'
import * as THREE from 'three'
function CanvasTexture() {
const meshRef = useRef()
const textureRef = useRef()
useEffect(() => {
const canvas = document.createElement('canvas')
canvas.width = 256
canvas.height = 256
const ctx = canvas.getContext('2d')
// Draw on canvas
ctx.fillStyle = 'red'
ctx.fillRect(0, 0, 256, 256)
ctx.fillStyle = 'white'
ctx.font = '48px Arial'
ctx.fillText('Hello', 50, 150)
textureRef.current = new THREE.CanvasTexture(canvas)
}, [])
// Update texture dynamically
useFrame(({ clock }) => {
if (textureRef.current) {
const canvas = textureRef.current.image
const ctx = canvas.getContext('2d')
ctx.fillStyle = `hsl(${clock.elapsedTime * 50}, 100%, 50%)`
ctx.fillRect(0, 0, 256, 256)
textureRef.current.needsUpdate = true
}
})
return (
<mesh ref={meshRef}>
<planeGeometry args={[2, 2]} />
<meshBasicMaterial map={textureRef.current} />
</mesh>
)
}
```
## Data Textures
```tsx
import { useMemo } from 'react'
import * as THREE from 'three'
function NoiseTexture() {
const texture = useMemo(() => {
const size = 256
const data = new Uint8Array(size * size * 4)
for (let i = 0; i < size * size; i++) {
const value = Math.random() * 255
data[i * 4] = value
data[i * 4 + 1] = value
data[i * 4 + 2] = value
data[i * 4 + 3] = 255
}
const texture = new THREE.DataTexture(data, size, size)
texture.needsUpdate = true
return texture
}, [])
return (
<mesh>
<planeGeometry args={[2, 2]} />
<meshBasicMaterial map={texture} />
</mesh>
)
}
```
## Render Targets
Render to texture.
```tsx
import { useFBO } from '@react-three/drei'
import { useFrame } from '@react-three/fiber'
import { useRef } from 'react'
function RenderToTexture() {
const fbo = useFBO(512, 512)
const meshRef = useRef()
const otherSceneRef = useRef()
useFrame(({ gl, camera }) => {
// Render other scene to FBO
gl.setRenderTarget(fbo)
gl.render(otherSceneRef.current, camera)
gl.setRenderTarget(null)
})
return (
<>
{/* Scene to render to texture */}
<group ref={otherSceneRef}>
<mesh position={[0, 0, -5]}>
<sphereGeometry args={[1, 32, 32]} />
<meshStandardMaterial color="red" />
</mesh>
</group>
{/* Display the texture */}
<mesh ref={meshRef}>
<planeGeometry args={[4, 4]} />
<meshBasicMaterial map={fbo.texture} />
</mesh>
</>
)
}
```
## Texture Atlas / Sprite Sheet
```tsx
import { useTexture } from '@react-three/drei'
import { useState } from 'react'
import { useFrame } from '@react-three/fiber'
import * as THREE from 'three'
function SpriteAnimation() {
const texture = useTexture('/textures/spritesheet.png')
const [frame, setFrame] = useState(0)
// Configure texture
texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping
texture.repeat.set(1/4, 1/4) // 4x4 sprite sheet
useFrame(({ clock }) => {
const newFrame = Math.floor(clock.elapsedTime * 10) % 16
if (newFrame !== frame) {
setFrame(newFrame)
const col = newFrame % 4
const row = Math.floor(newFrame / 4)
texture.offset.set(col / 4, 1 - (row + 1) / 4)
}
})
return (
<mesh>
<planeGeometry args={[1, 1]} />
<meshBasicMaterial map={texture} transparent />
</mesh>
)
}
```
## Material Texture Maps Reference
```tsx
<meshStandardMaterial
// Base color (sRGB)
map={colorTexture}
// Surface detail (Linear)
normalMap={normalTexture}
normalScale={[1, 1]}
// Roughness (Linear, grayscale)
roughnessMap={roughnessTexture}
roughness={1} // Multiplier
// Metalness (Linear, grayscale)
metalnessMap={metalnessTexture}
metalness={1} // Multiplier
// Ambient Occlusion (Linear, requires uv2)
aoMap={aoTexture}
aoMapIntensity={1}
// Self-illumination (sRGB)
emissiveMap={emissiveTexture}
emissive="#ffffff"
emissiveIntensity={1}
// Vertex displacement (Linear)
displacementMap={displacementTexture}
displacementScale={0.1}
displacementBias={0}
// Alpha (Linear)
alphaMap={alphaTexture}
transparent={true}
// Environment reflection
envMap={envTexture}
envMapIntensity={1}
// Lightmap (requires uv2)
lightMap={lightmapTexture}
lightMapIntensity={1}
/>
```
## Second UV Channel (for AO/Lightmaps)
```tsx
import { useEffect, useRef } from 'react'
function MeshWithUV2() {
const meshRef = useRef()
useEffect(() => {
// Copy uv to uv2 for aoMap/lightMap
const geometry = meshRef.current.geometry
geometry.setAttribute('uv2', geometry.attributes.uv)
}, [])
return (
<mesh ref={meshRef}>
<boxGeometry />
<meshStandardMaterial
aoMap={aoTexture}
aoMapIntensity={1}
/>
</mesh>
)
}
```
## Suspense Loading
```tsx
import { Suspense } from 'react'
import { useTexture } from '@react-three/drei'
function TexturedMesh() {
const texture = useTexture('/textures/large.jpg')
return (
<mesh>
<boxGeometry />
<meshStandardMaterial map={texture} />
</mesh>
)
}
function Fallback() {
return (
<mesh>
<boxGeometry />
<meshBasicMaterial color="gray" wireframe />
</mesh>
)
}
function Scene() {
return (
<Suspense fallback={<Fallback />}>
<TexturedMesh />
</Suspense>
)
}
```
## Performance Tips
1. **Use power-of-2 dimensions**: 256, 512, 1024, 2048
2. **Compress textures**: Use KTX2/Basis for web
3. **Enable mipmaps**: For distant objects
4. **Limit texture size**: 2048 usually sufficient
5. **Reuse textures**: Same texture = better batching
6. **Preload important textures**: Avoid pop-in
```tsx
// Preload critical textures
useTexture.preload('/textures/hero.jpg')
// Check texture memory
useFrame(({ gl }) => {
console.log('Textures:', gl.info.memory.textures)
})
// Dispose unused textures (R3F usually handles this)
texture.dispose()
```
## See Also
- `r3f-materials` - Applying textures to materials
- `r3f-loaders` - Asset loading patterns
- `r3f-shaders` - Custom texture samplingRelated Skills
effect-best-practices
Enforces Effect-TS patterns for services, errors, layers, and atoms. Use when writing code with Effect.Service, Schema.TaggedError, Layer composition, or effect-atom React components.
web-design-guidelines
Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".
vercel-react-best-practices
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
vercel-composition-patterns
React composition patterns that scale. Use when refactoring components with boolean prop proliferation, building flexible component libraries, or designing reusable APIs. Triggers on tasks involving compound components, render props, context providers, or component architecture. Includes React 19 API changes.
remotion-best-practices
Best practices for Remotion - Video creation in React
react-email
Use when building HTML email templates with React components, adding a visual email editor to an application using the React Email visual editor, rendering emails to HTML, or sending emails with Resend. Covers welcome emails, password resets, notifications, order confirmations, newsletters, transactional emails, and the embeddable email editor component.
r3f-shaders
React Three Fiber shaders - GLSL, shaderMaterial, uniforms, custom effects. Use when creating custom visual effects, modifying vertices, writing fragment shaders, or extending built-in materials.
r3f-postprocessing
React Three Fiber post-processing - @react-three/postprocessing, bloom, DOF, screen effects. Use when adding visual effects, color grading, blur, glow, or creating custom screen-space shaders.
r3f-physics
React Three Fiber physics with Rapier - RigidBody, colliders, forces, joints, sensors. Use when adding physics simulation, collision detection, character controllers, or creating interactive physics-based experiences.
r3f-materials
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.
r3f-loaders
React Three Fiber asset loading - useGLTF, useLoader, Suspense patterns, preloading. Use when loading 3D models, textures, HDR environments, or managing loading states.
r3f-lighting
React Three Fiber lighting - light types, shadows, Environment component, IBL. Use when adding lights, configuring shadows, setting up environment lighting, or optimizing lighting performance.