Skip to content
Frontend
Skill

/threejs-textures

Three.js textures: image loading, color spaces, UV channels and transforms, texture types from canvas to HDR and KTX2, render targets, texture memory. Use when working with images on materials, UV coordinates, cubemaps, render targets or texture optimization; on WebGL or with

From plugin
threejs-skills
3.9k13 skills

Claude Code

$ npx -y skills add cloudai-x/threejs-skills --skill threejs-textures --agent claude-code

SKILL.md

threejs-textures.SKILL.md
name: threejs-textures
description: "Three.js textures: image loading, color spaces, UV channels and transforms, texture types from canvas to HDR and KTX2, render targets, texture memory. Use when working with images on materials, UV coordinates, cubemaps, render targets or texture optimization; on WebGL or with WebGPU and TSL."

Three.js Textures

Targets three.js r186. Examples use WebGLRenderer; the WebGPU and TSL section uses WebGPURenderer.

Quick Start

import * as THREE from "three";

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(0, 0, 2);

// Color images must be tagged sRGB or they render too bright and washed out
const texture = new THREE.TextureLoader().load("diffuse.jpg");
texture.colorSpace = THREE.SRGBColorSpace;

const mesh = new THREE.Mesh(
  new THREE.PlaneGeometry(2, 2),
  new THREE.MeshBasicMaterial({ map: texture }),
);
scene.add(mesh);

renderer.setAnimationLoop(animate);

function animate() {
  mesh.rotation.z += 0.01;
  renderer.render(scene, camera);
}

Loading

// load() returns the texture at once; its image arrives asynchronously
const texture = new THREE.TextureLoader().load("diffuse.jpg");
texture.colorSpace = THREE.SRGBColorSpace;
mesh.material.map = texture; // before the first render; afterwards also set mesh.material.needsUpdate = true

// When the next step needs the loaded image, await it
const colorMap = await new THREE.TextureLoader().loadAsync("diffuse.jpg");
colorMap.colorSpace = THREE.SRGBColorSpace;

TextureLoader's `onProgress` parameter is unsupported and never fires; a `LoadingManager` reports progress as each file finishes:

const manager = new THREE.LoadingManager();
manager.onProgress = (url, loaded, total) => console.log(`${loaded}/${total}: ${url}`);
const loader = new THREE.TextureLoader(manager);

Color Space

Color management is on by default and every texture starts at `NoColorSpace`:

  • LDR color images get `SRGBColorSpace`: `map`, `emissiveMap`, `specularMap`, sheen color and specular color maps, LDR matcaps, and canvas or video used as color.
  • Scalar data keeps `NoColorSpace`: normal, bump, displacement, roughness, metalness, ambient-occlusion and alpha maps.
  • HDR environments are `LinearSRGBColorSpace`; the HDR loaders set that themselves. GLTFLoader sets the color spaces of the textures it loads.
const colorMap = new THREE.TextureLoader().load("color.jpg");
colorMap.colorSpace = THREE.SRGBColorSpace; // authored color image

const normalMap = new THREE.TextureLoader().load("normal.jpg");
// normalMap stays at NoColorSpace: it is data, not color

Transform: Wrap, Repeat, Offset, Rotation

const texture = new THREE.TextureLoader().load("diffuse.jpg");

// Tiling requires repeat wrapping; the default clamps edge pixels
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(4, 4); // tile 4x4

texture.offset.set(0.5, 0.5); // shift in UV units
texture.center.set(0.5, 0.5); // pivot for rotation
texture.rotation = Math.PI / 4; // radians

`MirroredRepeatWrapping` tiles with a mirror flip on each repeat.

Filtering, Mipmaps, Anisotropy

const texture = new THREE.TextureLoader().load("diffuse.jpg");

// Minification (many texture pixels per screen pixel)
texture.minFilter = THREE.LinearMipmapLinearFilter; // default: trilinear blend between mip levels
texture.minFilter = THREE.NearestFilter; // hard pixel look, samples only the base level

// Magnification (texture magnified on screen)
texture.magFilter = THREE.LinearFilter; // default
texture.magFilter = THREE.NearestFilter; // pixelated

// Mipmaps are generated whenever generateMipmaps is true, whatever the filters.
// Turn generation off to save memory (UI sprites, data textures):
texture.generateMipmaps = false;
texture.minFilter = THREE.LinearFilter; // and do not request a mipmap filter

// Sharper at grazing angles; clamp to what the hardware supports
texture.anisotropy = renderer.capabilities.getMaxAnisotropy();

Texture Types

Base class from any image element:

const image = new Image();
image.src = "sprite.png";

const imageTexture = new THREE.Texture(image);
imageTexture.colorSpace = THREE.SRGBColorSpace;
image.onload = () => (imageTexture.needsUpdate = true); // upload once the pixels exist

`DataTexture` from raw typed-array pixels. Its defaults differ from `Texture`: `NearestFilter` for both filters, `flipY` false, mipmaps off:

const size = 256;
const data = new Uint8Array(size * size * 4); // RGBA, one byte per channel
for (let i = 0; i < size; i++) {
  for (let j = 0; j < size; j++) {
    const index = (i * size + j) * 4;
    data[index] = i;
    data[index + 1] = j;
    data[index + 2] = 128;
    data[index + 3] = 255;
  }
}
const dataTexture = new THREE.DataTexture(data, size, size);
dataTexture.needsUpdate = true;

`CanvasTexture` for dynamically drawn textures (sets `needsUpdate` on construction):

const canvas = document.createElement("canvas");
canvas.width = 256;
canvas.height = 256;
const ctx = canvas.getContext("2d");
ctx.fillStyle = "#404040";
ctx.fillRect(0, 0, 256, 256);
ctx.fillStyle = "#ffffff";
ctx.font = "48px sans-serif";
ctx.fillText("Hello", 40, 150);

const canvasTexture = new THREE.CanvasTexture(canvas);
canvasTexture.colorSpace = THREE.SRGBColorSpace; // canvas colors are sRGB

// after each redraw of the canvas:
canvasTexture.needsUpdate = true;

`VideoTexture` for a playing `HTMLVideoElement` (re-uploads every frame, mipmaps off):

const video = document.createElement("video");
video.sr
Read more
@cloudai-x
Ships withthreejs-skills

Skill files that give Claude Code current, verified knowledge of three.js, so the code it writes runs on the release you actually install. The skills target three.js r186 (three@0.186), React Three Fiber 9.8 with drei 10.7, and gltf-transform 4.5.

Stars on GitHub

Momentum

stars in total
3.9k
Star history of cloudai-x/threejs-skills on GitHub, a chart by star-history.com

Other skills on threejs-skills.

threejs-geometry

threejs-geometry

Creating and shaping three.js geometry: built-in shapes, 3D text, vertex buffers and attributes, merging, instancing, batching,…

threejs-lighting

threejs-lighting

Light types and physical units, shadow maps, HDR environment lighting, light probes, and lighting performance, on WebGL or with…

More skills from other plugins.

next-bundle-optimizer
Auto-invoked

next-bundle-optimizer

Audit and reduce Next.js browser initial-load work. Use for slow route startup, oversized client bundles, duplicate browser…

nextjs1d143k
@vercel@vercelInstall Skill
migrate-radix-to-base

migrate-radix-to-base

Migrates React projects and components from Radix UI to Base UI. Use when asked to migrate from radix, move to base-ui, convert…

ui10d127k
@shadcn-ui@shadcn-uiInstall Skill
chrome-release-cls

chrome-release-cls

Given a Chrome Releases blog post URL (chromereleases.googleblog.com), extract every CVE/bug and find the underlying Gerrit CL…

electron1d124k
@electron@electronInstall Skill
taste-skill
Auto-invoked

taste-skill

tasteskill v2, the anti-slop frontend skill. Art direction for websites, distilled from a study of 247 curated gallery sites (One…

@leonxlnx@leonxlnxInstall Skill

Questions about threejs-textures.

Which coding agents can use threejs-textures?
threejs-textures installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.