
threejs-textures
PopularThree.js textures - texture types, UV mapping, environment maps, texture settings. Use when working with images, UV coordinates, cubemaps, HDR environments, or texture optimization.
Three.js textures - texture types, UV mapping, environment maps, texture settings. Use when working with images, UV coordinates, cubemaps, HDR environments, or texture optimization.
Three.js Textures
Quick Start
import * as THREE from "three";
// Load texture
const loader = new THREE.TextureLoader();
const texture = loader.load("texture.jpg");
// Apply to material
const material = new THREE.MeshStandardMaterial({
map: texture,
});
Texture Loading
Basic Loading
const loader = new THREE.TextureLoader();
// Async with callbacks
loader.load(
"texture.jpg",
(texture) => console.log("Loaded"),
(progress) => console.log("Progress"),
(error) => console.error("Error"),
);
// Synchronous style (loads async internally)
const texture = loader.load("texture.jpg");
material.map = texture;
Promise Wrapper
function loadTexture(url) {
return new Promise((resolve, reject) => {
new THREE.TextureLoader().load(url, resolve, undefined, reject);
});
}
// Usage
const [colorMap, normalMap, roughnessMap] = await Promise.all([
loadTexture("color.jpg"),
loadTexture("normal.jpg"),
loadTexture("roughness.jpg"),
]);
Texture Configuration
Color Space
Critical for accurate color reproduction.
// Color/albedo textures - use sRGB
colorTexture.colorSpace = THREE.SRGBColorSpace;
// Data textures (normal, roughness, metalness, AO) - leave as default
// Do NOT set colorSpace for data textures (NoColorSpace is default)
Wrapping Modes
texture.wrapS = THREE.RepeatWrapping; // Horizontal
texture.wrapT = THREE.RepeatWrapping; // Vertical
// Options:
// THREE.ClampToEdgeWrapping - Stretches edge pixels (default)
// THREE.RepeatWrapping - Tiles the texture
// THREE.MirroredRepeatWrapping - Tiles with mirror flip
Repeat, Offset, Rotation
// Tile texture 4x4
texture.repeat.set(4, 4);
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
// Offset (0-1 range)
texture.offset.set(0.5, 0.5);
// Rotation (radians, around center)
texture.rotation = Math.PI / 4;
texture.center.set(0.5, 0.5); // Rotation pivot
Filtering
// Minification (texture larger than screen pixels)
texture.minFilter = THREE.LinearMipmapLinearFilter; // Default, smooth
texture.minFilter = THREE.NearestFilter; // Pixelated
texture.minFilter = THREE.LinearFilter; // Smooth, no mipmaps
// Magnification (texture smaller than screen pixels)
texture.magFilter = THREE.LinearFilter; // Smooth (default)
texture.magFilter = THREE.NearestFilter; // Pixelated (retro games)
// Anisotropic filtering (sharper at angles)
texture.anisotropy = renderer.capabilities.getMaxAnisotropy();
Generate Mipmaps
// Usually true by default
texture.generateMipmaps = true;
// Disable for non-power-of-2 textures or data textures
texture.generateMipmaps = false;
texture.minFilter = THREE.LinearFilter;
Texture Types
Regular Texture
const texture = new THREE.Texture(image);
texture.needsUpdate = true;
Data Texture
Create texture from raw data.
// Create gradient texture
const size = 256;
const data = new Uint8Array(size * size * 4);
for (let i = 0; i < size; i++) {
for (let j = 0; j < size; j++) {
const index = (i * size + j) * 4;
data[index] = i; // R
data[index + 1] = j; // G
data[index + 2] = 128; // B
data[index + 3] = 255; // A
}
}
const texture = new THREE.DataTexture(data, size, size);
texture.needsUpdate = true;
Canvas Texture
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);
const texture = new THREE.CanvasTexture(canvas);
// Update when canvas changes
texture.needsUpdate = true;
Video Texture
const video = document.createElement("video");
video.src = "video.mp4";
video.loop = true;
video.muted = true;
video.play();
const texture = new THREE.VideoTexture(video);
texture.colorSpace = THREE.SRGBColorSpace;
// No need to set needsUpdate - auto-updates
Compressed Textures
import { KTX2Loader } from "three/examples/jsm/loaders/KTX2Loader.js";
const ktx2Loader = new KTX2Loader();
ktx2Loader.setTranscoderPath("path/to/basis/");
ktx2Loader.detectSupport(renderer);
ktx2Loader.load("texture.ktx2", (texture) => {
material.map = texture;
});
Cube Textures
For environment maps and skyboxes.
CubeTextureLoader
const loader = new THREE.CubeTextureLoader();
const cubeTexture = loader.load([
"px.jpg",
"nx.jpg", // +X, -X
"py.jpg",
"ny.jpg", // +Y, -Y
"pz.jpg",
"nz.jpg", // +Z, -Z
]);
// As background
scene.background = cubeTexture;
// As environment map
scene.environment = cubeTexture;
material.envMap = cubeTexture;
Equirectangular to Cubemap
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
const pmremGenerator = new THREE.PMREMGenerator(renderer);
pmremGenerator.compileEquirectangularShader();
new RGBELoader().load("environment.hdr", (texture) => {
const envMap = pmremGenerator.fromEquirectangular(texture).texture;
scene.environment = envMap;
scene.background = envMap;
texture.dispose();
pmremGenerator.dispose();
});
HDR Textures
RGBELoader
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
const loader = new RGBELoader();
loader.load("environment.hdr", (texture) => {
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = texture;
scene.background = texture;
});
EXRLoader
import { EXRLoader } from "three/examples/jsm/loaders/EXRLoader.js";
const loader = new EXRLoader();
loader.load("environment.exr", (texture) => {
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = texture;
});
Background Options
scene.background = texture;
scene.backgroundBlurriness = 0.5; // 0-1, blur background
scene.backgroundIntensity = 1.0; // Brightness
scene.backgroundRotation.y = Math.PI; // Rotate background
Render Targets
Render to texture for effects.
// Create render target
const renderTarget = new THREE.WebGLRenderTarget(512, 512, {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat,
});
// Render scene to target
renderer.setRenderTarget(renderTarget);
renderer.render(scene, camera);
renderer.setRenderTarget(null); // Back to screen
// Use as texture
material.map = renderTarget.texture;
Depth Texture
const renderTarget = new THREE.WebGLRenderTarget(512, 512);
renderTarget.depthTexture = new THREE.DepthTexture(
512,
512,
THREE.UnsignedShortType,
);
// Access depth
const depthTexture = renderTarget.depthTexture;
Multi-Sample Render Target
const renderTarget = new THREE.WebGLRenderTarget(512, 512, {
samples: 4, // MSAA
});
CubeCamera
Dynamic environment maps for reflections.
const cubeRenderTarget = new THREE.WebGLCubeRenderTarget(256, {
generateMipmaps: true,
minFilter: THREE.LinearMipmapLinearFilter,
});
const cubeCamera = new THREE.CubeCamera(0.1, 1000, cubeRenderTarget);
scene.add(cubeCamera);
// Apply to reflective material
reflectiveMaterial.envMap = cubeRenderTarget.texture;
// Update in animation loop (expensive!)
function animate() {
// Hide reflective object, update env map, show again
reflectiveObject.visible = false;
cubeCamera.position.copy(reflectiveObject.position);
cubeCamera.update(renderer, scene);
reflectiveObject.visible = true;
}
UV Mapping
Accessing UVs
const uvs = geometry.attributes.uv;
// Read UV
const u = uvs.getX(vertexIndex);
const v = uvs.getY(vertexIndex);
// Modify UV
uvs.setXY(vertexIndex, newU, newV);
uvs.needsUpdate = true;
Second UV Channel (for AO maps)
// Required for aoMap
geometry.setAttribute("uv2", geometry.attributes.uv);
// Or create custom second UV
const uv2 = new Float32Array(vertexCount * 2);
// ... fill uv2 data
geometry.setAttribute("uv2", new THREE.BufferAttribute(uv2, 2));
UV Transform in Shader
const material = new THREE.ShaderMaterial({
uniforms: {
map: { value: texture },
uvOffset: { value: new THREE.Vector2(0, 0) },
uvScale: { value: new THREE.Vector2(1, 1) },
},
vertexShader: `
varying vec2 vUv;
uniform vec2 uvOffset;
uniform vec2 uvScale;
void main() {
vUv = uv * uvScale + uvOffset;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
varying vec2 vUv;
uniform sampler2D map;
void main() {
gl_FragColor = texture2D(map, vUv);
}
`,
});
Texture Atlas
Multiple images in one texture.
// Atlas with 4 sprites (2x2 grid)
const atlas = loader.load("atlas.png");
atlas.wrapS = THREE.ClampToEdgeWrapping;
atlas.wrapT = THREE.ClampToEdgeWrapping;
// Select sprite by UV offset/scale
function selectSprite(row, col, gridSize = 2) {
atlas.offset.set(col / gridSize, 1 - (row + 1) / gridSize);
atlas.repeat.set(1 / gridSize, 1 / gridSize);
}
// Select top-left sprite
selectSprite(0, 0);
Material Texture Maps
PBR Texture Set
const material = new THREE.MeshStandardMaterial({
// Base color (sRGB)
map: colorTexture,
// Surface detail (Linear)
normalMap: normalTexture,
normalScale: new THREE.Vector2(1, 1),
// Roughness (Linear, grayscale)
roughnessMap: roughnessTexture,
roughness: 1, // Multiplier
// Metalness (Linear, grayscale)
metalnessMap: metalnessTexture,
metalness: 1, // Multiplier
// Ambient occlusion (Linear, uses uv2)
aoMap: aoTexture,
aoMapIntensity: 1,
// Self-illumination (sRGB)
emissiveMap: emissiveTexture,
emissive: 0xffffff,
emissiveIntensity: 1,
// Vertex displacement (Linear)
displacementMap: displacementTexture,
displacementScale: 0.1,
displacementBias: 0,
// Alpha (Linear)
alphaMap: alphaTexture,
transparent: true,
});
// Don't forget UV2 for AO
geometry.setAttribute("uv2", geometry.attributes.uv);
Normal Map Types
// OpenGL style normals (default)
material.normalMapType = THREE.TangentSpaceNormalMap;
// Object space normals
material.normalMapType = THREE.ObjectSpaceNormalMap;
Procedural Textures
Noise Texture
function generateNoiseTexture(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;
}
Gradient Texture
function generateGradientTexture(color1, color2, size = 256) {
const canvas = document.createElement("canvas");
canvas.width = size;
canvas.height = 1;
const ctx = canvas.getContext("2d");
const gradient = ctx.createLinearGradient(0, 0, size, 0);
gradient.addColorStop(0, color1);
gradient.addColorStop(1, color2);
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, size, 1);
return new THREE.CanvasTexture(canvas);
}
Texture Memory Management
Dispose Textures
// Single texture
texture.dispose();
// Material textures
function disposeMaterial(material) {
const maps = [
"map",
"normalMap",
"roughnessMap",
"metalnessMap",
"aoMap",
"emissiveMap",
"displacementMap",
"alphaMap",
"envMap",
"lightMap",
"bumpMap",
"specularMap",
];
maps.forEach((mapName) => {
if (material[mapName]) {
material[mapName].dispose();
}
});
material.dispose();
}
Texture Pooling
class TexturePool {
constructor() {
this.textures = new Map();
this.loader = new THREE.TextureLoader();
}
async get(url) {
if (this.textures.has(url)) {
return this.textures.get(url);
}
const texture = await new Promise((resolve, reject) => {
this.loader.load(url, resolve, undefined, reject);
});
this.textures.set(url, texture);
return texture;
}
dispose(url) {
const texture = this.textures.get(url);
if (texture) {
texture.dispose();
this.textures.delete(url);
}
}
disposeAll() {
this.textures.forEach((t) => t.dispose());
this.textures.clear();
}
}
Performance Tips
- Use power-of-2 dimensions: 256, 512, 1024, 2048
- Compress textures: KTX2/Basis for web delivery
- Use texture atlases: Reduce texture switches
- Enable mipmaps: For distant objects
- Limit texture size: 2048 usually sufficient for web
- Reuse textures: Same texture = better batching
// Check texture memory
console.log(renderer.info.memory.textures);
// Optimize for mobile
const maxSize = renderer.capabilities.maxTextureSize;
const isMobile = /iPhone|iPad|Android/i.test(navigator.userAgent);
const textureSize = isMobile ? 1024 : 2048;
See Also
threejs-materials- Applying textures to materialsthreejs-loaders- Loading texture filesthreejs-shaders- Custom texture sampling
You Might Also Like
Related Skills

cache-components
Expert guidance for Next.js Cache Components and Partial Prerendering (PPR). **PROACTIVE ACTIVATION**: Use this skill automatically when working in Next.js projects that have `cacheComponents: true` in their next.config.ts/next.config.js. When this config is detected, proactively apply Cache Components patterns and best practices to all React Server Component implementations. **DETECTION**: At the start of a session in a Next.js project, check for `cacheComponents: true` in next.config. If enabled, this skill's patterns should guide all component authoring, data fetching, and caching decisions. **USE CASES**: Implementing 'use cache' directive, configuring cache lifetimes with cacheLife(), tagging cached data with cacheTag(), invalidating caches with updateTag()/revalidateTag(), optimizing static vs dynamic content boundaries, debugging cache issues, and reviewing Cache Component implementations.
vercel
component-refactoring
Refactor high-complexity React components in Dify frontend. Use when `pnpm analyze-component --json` shows complexity > 50 or lineCount > 300, when the user asks for code splitting, hook extraction, or complexity reduction, or when `pnpm analyze-component` warns to refactor before testing; avoid for simple/well-structured components, third-party wrappers, or when the user explicitly wants testing without refactoring.
langgenius
web-artifacts-builder
Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui). Use for complex artifacts requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX artifacts.
anthropics
frontend-design
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML/CSS layouts, or when styling/beautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.
anthropics
react-modernization
Upgrade React applications to latest versions, migrate from class components to hooks, and adopt concurrent features. Use when modernizing React codebases, migrating to React Hooks, or upgrading to latest React versions.
wshobson
tailwind-design-system
Build scalable design systems with Tailwind CSS v4, design tokens, component libraries, and responsive patterns. Use when creating component libraries, implementing design systems, or standardizing UI patterns.
wshobson