threejs-textures
Skill3 starsChanged 10 days agoMITView on GitHub
Three.js textures - texture types, UV mapping, environment maps, texture settings. Use when working with images, UV coordinates, cubemaps, HDR environments, or texture optimization.
20 other projects use a version of this, 4 of them edited.
Adopted by
Steady: 0 new projects took it in the last 4 weeks, none the 4 weeks before.thin data
Most recently taken up by
- DaraBoth/skilljmskilltheir own version, first seen Nov 8, 2026
- OpenMontageInc/OpenMontageword for word, first seen Nov 8, 2026
- calesthio/OpenMontageword for word, first seen Nov 8, 2026
- davidanthonyn/claude-skillsword for word, first seen Oct 20, 2026
- CloudAI-X/threejs-skillstheir own version, first seen Oct 18, 2026
- pengawasmknan/claude-skillsword for word, first seen Oct 11, 2026
Used with
Projects with it also use bfl-api, flux-best-practices and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
LinHao-citySkillbfl-api
BFL FLUX API integration guide covering endpoints, async polling patterns, rate limiting, error handling, webhooks, and regional endpoints with Python and TypeScript code examples.
Also in 3 projects that use this
LinHao-citySkillflux-best-practices
Comprehensive guide for BFL FLUX image generation models. Covers prompting, T2I, I2I, structured JSON, hex colors, typography, multi-reference editing, and model-specific best practices for FLUX.2 and FLUX.1 families.
Also in 3 projects that use this
jaron-goh-centrSkillwebsite-to-video
Capture a general website/URL and turn it into a video OF the site — tour, showcase, or social clip built from captured screenshots and the site's own brand assets. Use for portfolio / blog / docs / landing-page showcases. Not a product launch or promo, even from a URL (/product-launch-video). Unclear → /hyperframes.
Also in 4 projects that use this
dAAAbSkillheygen
Also in 3 projects that use this
MoizIbnYousafSkillvisual-style
Build a persistent visual brand identity for image generation. Defines how the brand looks visually — aesthetic, lighting, composition, mood — and writes it to brand/creative-kit.md so /image-gen and other creative skills produce consistent on-brand visuals. Three modes: Extract (from website/URL), Build (interview), Reference (mood board/examples). Use when starting any project that needs images, when the user says "visual style", "brand aesthetic", "image style", "visual identity", "how should our images look", "build visual brand", "define our look", or when /image-gen outputs feel generic because no visual style exists yet.
Also in 3 projects that use this
- +7 more from LinHao-city
Other versions20 projects use a version of this.
Word for word · 13
- calesthio/OpenMontage★ 78k100% same
- OpenMontageInc/OpenMontage★ 78k100% same
- educlopez/thegridcn-ui★ 394100% same
- quiet-node/gesture-lab★ 185100% same
- codetesla51/skills★ 32100% same
- ruloCode/hermes-os★ 16100% same
- LinHao-city/StoryMind★ 10100% same
- huangzida/skills★ 2100% same
- patrickcohen/claude-skills-collection★ 1100% same
- sirakinb/claude-code-skills★ 1100% same
3 more not listed
Edited · 4
- kumaran-is/claude-code-onboarding★ 3584% same
- Adhamxon/claude-code-skills★ 290% same
- ai4brands-design/claude-skills★ 210% same
- Gopyr/gopyr-skills-hub★ 049% same
Wrote their own version · 3
- CloudAI-X/threejs-skills★ 3.7ksame name
- full-stack-skills/threejs-skills★ 9same name
- DaraBoth/skilljmskill★ 2same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository72 other files it gives its agents.
- workflow/AGENTS.mdAGENTS.md
- docs/llms.txtllms.txt
- llms.txtllms.txt
- ai-video-prompt-engineerSkill
- api-contract-designSkill
- api-hardeningSkill
- brainstormingSkill
- cavecrewSkill
- caveman-commitSkill
- caveman-compressSkill
- caveman-helpSkill
- caveman-reviewSkill
- cavemanSkill
- councilSkill
- database-migrationsSkill
- deep-researchSkill
- dependency-auditSkill
- deployment-patternsSkill
- e2e-testingSkill
- error-handlingSkill
- exa-searchSkill
- finishing-a-development-branchSkill
- frontend-securitySkill
- github-opsSkill
- graphifySkill
- graphyloop-wavesSkill
- graphyloop-workflowSkill
- gsap-coreSkill
- gsap-frameworksSkill
- gsap-performanceSkill
- gsap-pluginsSkill
- gsap-reactSkill
- gsap-scrolltriggerSkill
- gsap-timelineSkill
- gsap-utilsSkill
- high-end-visual-designSkill
- image-to-codeSkill
- last30daysSkill
- minimalist-uiSkill
- postgres-patternsSkill
- prisma-patternsSkill
- receiving-code-reviewSkill
- redesign-existing-projectsSkill
- remotion-video-creationSkill
- requesting-code-reviewSkill
- search-firstSkill
- secrets-hygieneSkill
- security-reviewSkill
- security-scanSkill
- short-video-productionSkill
- story-engineeringSkill
- supabase-setupSkill
- swarm-memorySkill
- systematic-debuggingSkill
- tdd-workflowSkill
- terminal-opsSkill
- threejs-animationSkill
- threejs-fundamentalsSkill
- threejs-geometrySkill
- threejs-interactionSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
1 rule. 0 are common, 1 is distinctive, and 0 are very specific to this project.
0
Common
Most of the 5 edited versions we read keep these.
1
Distinctive
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 140
Create texture from raw data.
“Common” is measured: kept by at least 6 in 10 of the 5 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
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 flipRepeat, 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 pivotFiltering
// 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-updatesCompressed 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 backgroundRender 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
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

