Claude Agent Skill · by Cloudai X

Threejs Textures

Install Threejs Textures skill for Claude Code from cloudai-x/threejs-skills.

Install
Terminal · npx
$npx skills add https://github.com/cloudai-x/threejs-skills --skill threejs-textures
Works with Paperclip

How Threejs Textures fits into a Paperclip company.

Threejs Textures drops into any Paperclip agent that handles this kind of work. Assign it to a specialist inside a pre-configured PaperclipOrg company and the skill becomes available on every heartbeat — no prompt engineering, no tool wiring.

S
SaaS FactoryPaired

Pre-configured AI company — 18 agents, 18 skills, one-time purchase.

$27$59
Explore pack
Source file
SKILL.md628 lines
Expand
---name: threejs-texturesdescription: 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 ```javascriptimport * as THREE from "three"; // Load textureconst loader = new THREE.TextureLoader();const texture = loader.load("texture.jpg"); // Apply to materialconst material = new THREE.MeshStandardMaterial({  map: texture,});``` ## Texture Loading ### Basic Loading ```javascriptconst loader = new THREE.TextureLoader(); // Async with callbacksloader.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 ```javascriptfunction loadTexture(url) {  return new Promise((resolve, reject) => {    new THREE.TextureLoader().load(url, resolve, undefined, reject);  });} // Usageconst [colorMap, normalMap, roughnessMap] = await Promise.all([  loadTexture("color.jpg"),  loadTexture("normal.jpg"),  loadTexture("roughness.jpg"),]);``` ## Texture Configuration ### Color Space Critical for accurate color reproduction. ```javascript// Color/albedo textures - use sRGBcolorTexture.colorSpace = THREE.SRGBColorSpace; // Data textures (normal, roughness, metalness, AO) - leave as default// Do NOT set colorSpace for data textures (NoColorSpace is default)``` ### Wrapping Modes ```javascripttexture.wrapS = THREE.RepeatWrapping; // Horizontaltexture.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 ```javascript// Tile texture 4x4texture.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 ```javascript// Minification (texture larger than screen pixels)texture.minFilter = THREE.LinearMipmapLinearFilter; // Default, smoothtexture.minFilter = THREE.NearestFilter; // Pixelatedtexture.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 ```javascript// Usually true by defaulttexture.generateMipmaps = true; // Disable for non-power-of-2 textures or data texturestexture.generateMipmaps = false;texture.minFilter = THREE.LinearFilter;``` ## Texture Types ### Regular Texture ```javascriptconst texture = new THREE.Texture(image);texture.needsUpdate = true;``` ### Data Texture Create texture from raw data. ```javascript// Create gradient textureconst 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 ```javascriptconst canvas = document.createElement("canvas");canvas.width = 256;canvas.height = 256;const ctx = canvas.getContext("2d"); // Draw on canvasctx.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 changestexture.needsUpdate = true;``` ### Video Texture ```javascriptconst 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 ```javascriptimport { 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 ```javascriptconst 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 backgroundscene.background = cubeTexture; // As environment mapscene.environment = cubeTexture;material.envMap = cubeTexture;``` ### Equirectangular to Cubemap ```javascriptimport { 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 ```javascriptimport { 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 ```javascriptimport { 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 ```javascriptscene.background = texture;scene.backgroundBlurriness = 0.5; // 0-1, blur backgroundscene.backgroundIntensity = 1.0; // Brightnessscene.backgroundRotation.y = Math.PI; // Rotate background``` ## Render Targets Render to texture for effects. ```javascript// Create render targetconst renderTarget = new THREE.WebGLRenderTarget(512, 512, {  minFilter: THREE.LinearFilter,  magFilter: THREE.LinearFilter,  format: THREE.RGBAFormat,}); // Render scene to targetrenderer.setRenderTarget(renderTarget);renderer.render(scene, camera);renderer.setRenderTarget(null); // Back to screen // Use as texturematerial.map = renderTarget.texture;``` ### Depth Texture ```javascriptconst renderTarget = new THREE.WebGLRenderTarget(512, 512);renderTarget.depthTexture = new THREE.DepthTexture(  512,  512,  THREE.UnsignedShortType,); // Access depthconst depthTexture = renderTarget.depthTexture;``` ### Multi-Sample Render Target ```javascriptconst renderTarget = new THREE.WebGLRenderTarget(512, 512, {  samples: 4, // MSAA});``` ## CubeCamera Dynamic environment maps for reflections. ```javascriptconst 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 materialreflectiveMaterial.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 ```javascriptconst uvs = geometry.attributes.uv; // Read UVconst u = uvs.getX(vertexIndex);const v = uvs.getY(vertexIndex); // Modify UVuvs.setXY(vertexIndex, newU, newV);uvs.needsUpdate = true;``` ### Second UV Channel (for AO maps) ```javascript// Required for aoMapgeometry.setAttribute("uv2", geometry.attributes.uv); // Or create custom second UVconst uv2 = new Float32Array(vertexCount * 2);// ... fill uv2 datageometry.setAttribute("uv2", new THREE.BufferAttribute(uv2, 2));``` ### UV Transform in Shader ```javascriptconst 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. ```javascript// 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/scalefunction selectSprite(row, col, gridSize = 2) {  atlas.offset.set(col / gridSize, 1 - (row + 1) / gridSize);  atlas.repeat.set(1 / gridSize, 1 / gridSize);} // Select top-left spriteselectSprite(0, 0);``` ## Material Texture Maps ### PBR Texture Set ```javascriptconst 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 AOgeometry.setAttribute("uv2", geometry.attributes.uv);``` ### Normal Map Types ```javascript// OpenGL style normals (default)material.normalMapType = THREE.TangentSpaceNormalMap; // Object space normalsmaterial.normalMapType = THREE.ObjectSpaceNormalMap;``` ## Procedural Textures ### Noise Texture ```javascriptfunction 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 ```javascriptfunction 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 ```javascript// Single texturetexture.dispose(); // Material texturesfunction 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 ```javascriptclass 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 1. **Use power-of-2 dimensions**: 256, 512, 1024, 20482. **Compress textures**: KTX2/Basis for web delivery3. **Use texture atlases**: Reduce texture switches4. **Enable mipmaps**: For distant objects5. **Limit texture size**: 2048 usually sufficient for web6. **Reuse textures**: Same texture = better batching ```javascript// Check texture memoryconsole.log(renderer.info.memory.textures); // Optimize for mobileconst 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 materials- `threejs-loaders` - Loading texture files- `threejs-shaders` - Custom texture sampling