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.
What this skill does
# 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
Related in Web Dev
generating-lwc-components
IncludedLightning Web Components with PICKLES methodology and 165-point scoring. Use this skill when the user creates or edits LWC components, builds wire service patterns, or writes Jest tests for LWC. TRIGGER when: user creates/edits LWC components, touches lwc/**/*.js, .html, .css, .js-meta.xml files, or asks about wire service, SLDS, or Jest LWC tests. DO NOT TRIGGER when: Apex classes (use generating-apex), Aura components, or Visualforce.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Set up queries with useQuery, mutations with useMutation, configure QueryClient caching strategies, implement optimistic updates, and handle infinite scroll with useInfiniteQuery. Use when: setting up data fetching in React projects, migrating from v4 to v5, or fixing object syntax required errors, query callbacks removed issues, cacheTime renamed to gcTime, isPending vs isLoading confusion, keepPreviousData removed problems.
document-processor-api
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
nutrient-document-processing
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Covers useMutationState, simplified optimistic updates, throwOnError, network mode (offline/PWA), and infiniteQueryOptions. Use when setting up data fetching, fixing v4→v5 migration errors (object syntax, gcTime, isPending, keepPreviousData), or debugging SSR/hydration issues with streaming server components.
accelint-nextjs-best-practices
IncludedNext.js performance optimization and best practices. Use when writing Next.js code (App Router or Pages Router); implementing Server Components, Server Actions, or API routes; optimizing RSC serialization, data fetching, or server-side rendering; reviewing Next.js code for performance issues; fixing authentication in Server Actions; or implementing Suspense boundaries, parallel data fetching, or request deduplication.