threejs-materials
Skill3.7k starsChanged 13 days agoMITView on GitHub
Choosing and configuring three.js materials - unlit, diffuse, specular, PBR, toon, point and line materials - shared properties like blending and stencil, environment response, and the WebGPU node-material and TSL equivalents. Use when styling meshes or tuning material behavior.
We split this skill into the rules it gives an agent
2 rules. 0 are common, 0 are distinctive, and 2 are very specific to this project.
0
Common
Most of the 17 edited versions we read keep these.
0
Distinctive
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 66
No lighting calculations. Fast, always visible.
- Very specific: line 134
Every UV-mapped texture samples the attribute selected by texture.channel: 0 reads uv (the default), 1 reads uv1, 2 reads uv2, 3 reads uv3.
“Common” is measured: kept by at least 6 in 10 of the 17 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 Materials
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(75, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(0, 0, 3);
// PBR material - the default choice for lit, realistic surfaces
const material = new THREE.MeshStandardMaterial({
color: 0x00aaff,
roughness: 0.35,
metalness: 0.1,
});
const mesh = new THREE.Mesh(new THREE.SphereGeometry(1, 48, 32), material);
scene.add(mesh);
scene.add(new THREE.HemisphereLight(0xffffff, 0x444444, 1)); // lit materials render black without lights
const light = new THREE.DirectionalLight(0xffffff, 2);
light.position.set(3, 3, 3);
scene.add(light);
function animate() {
mesh.rotation.y += 0.01;
renderer.render(scene, camera);
}
renderer.setAnimationLoop(animate);Material Types Overview
| Material | Use case | Lighting |
| MeshBasicMaterial | Unlit color, textures, wireframes | None |
| MeshLambertMaterial | Matte diffuse surfaces | Diffuse |
| MeshPhongMaterial | Shiny plastic, cheap specular | Diffuse + specular |
| MeshStandardMaterial | PBR metal/rough workflow | PBR |
| MeshPhysicalMaterial | PBR plus clearcoat, transmission, sheen, iridescence | PBR |
| MeshToonMaterial | Cel shading | Toon steps |
| MeshMatcapMaterial | Lit look baked into a matcap texture, no lights needed | Baked |
| ShadowMaterial | Transparent surface that shows only the shadows it receives | Shadows only |
| PointsMaterial | Point clouds | None |
| LineBasicMaterial / LineDashedMaterial | Lines | None |
| ShaderMaterial / RawShaderMaterial | Custom GLSL, WebGLRenderer only | Custom |
Color data textures (map, emissiveMap, specularMap, sheenColorMap, specularColorMap, LDR matcap, a canvas or video used as color) need texture.colorSpace = THREE.SRGBColorSpace, or colors render washed out. Scalar maps (normal, bump, displacement, roughness, metalness, ao, alpha, toon gradientMap) keep the default. HDR loaders set their own color space.
MeshBasicMaterial
No lighting calculations. Fast, always visible. Supports envMap with reflectivity (0 to 1) and combine (THREE.MultiplyOperation, THREE.MixOperation, THREE.AddOperation); specularMap (sRGB) masks the env-map contribution.
const map = await new THREE.TextureLoader().loadAsync("color.jpg");
map.colorSpace = THREE.SRGBColorSpace;
const material = new THREE.MeshBasicMaterial({
color: 0xffffff, // multiplied with the map
map,
transparent: true,
opacity: 0.5,
side: THREE.DoubleSide, // FrontSide (default), BackSide, DoubleSide
fog: true, // affected by scene fog
});MeshLambertMaterial and MeshPhongMaterial
Lambert is diffuse-only. Phong adds a specular highlight; it is the cheap alternative when Standard is too heavy.
const lambert = new THREE.MeshLambertMaterial({
color: 0x00ff00,
emissive: 0x111111, // self-illumination color
emissiveIntensity: 1,
});
const phong = new THREE.MeshPhongMaterial({
color: 0x0000ff,
specular: 0x111111, // highlight color
shininess: 30, // higher = sharper highlight
flatShading: false, // flat vs smooth normals
});Both also support map, emissiveMap, specularMap (sRGB; masks the env-map reflection, and the highlight on Phong), normalMap, bumpMap, displacementMap, aoMap, envMap, envMapIntensity and envMapRotation.
MeshStandardMaterial (PBR)
Physically-based rendering. Recommended for realistic results.
const map = await new THREE.TextureLoader().loadAsync("color.jpg");
map.colorSpace = THREE.SRGBColorSpace;
const ormMap = await new THREE.TextureLoader().loadAsync("orm.jpg"); // glTF ORM: ao red, roughness green, metalness blue; scalar: keep default
const material = new THREE.MeshStandardMaterial({
color: 0xffffff, // multiplied with the map
roughness: 1.0, // 0 = mirror, 1 = fully diffuse; multiplied by roughnessMap (green)
metalness: 1.0, // 0 = dielectric, 1 = metal; multiplied by metalnessMap (blue), so keep 1 with a map
map,
roughnessMap: ormMap,
metalnessMap: ormMap,
normalMap: null, // surface detail; scale with normalScale (a Vector2)
aoMap: ormMap, // ambient occlusion (red); intensity with aoMapIntensity
displacementMap: null, // vertex displacement; scale with displacementScale, offset with displacementBias
emissive: 0x000000,
emissiveIntensity: 1,
emissiveMap: null, // sRGB
envMap: null, // or rely on scene.environment (see below)
fog: true,
});lightMap (with lightMapIntensity) bakes indirect light the same way aoMap bakes occlusion; an HDR or EXR lightMap is LinearSRGBColorSpace, which the loaders set.
UV channels: aoMap and lightMap read the channel you pick
Every UV-mapped texture samples the attribute selected by texture.channel: 0 reads uv (the default), 1 reads uv1, 2 reads uv2, 3 reads uv3. aoMap and lightMap need no second UV set - they sample uv unless you change channel. GLTFLoader loads TEXCOORD_1 as uv1 and sets channel itself.
const aoMap = await new THREE.TextureLoader().loadAsync("ao.jpg"); // scalar: keep default
const material = new THREE.MeshStandardMaterial({ aoMap }); // samples uv: no extra attribute needed
// Alternative for a separate unwrap (a baked AO or light map): copy your baker's u,v pairs into uv1
const bakedUv = new THREE.Float32BufferAttribute(mesh.geometry.attributes.position.count * 2, 2); // zero-filled until you copy them in
mesh.geometry.setAttribute("uv1", bakedUv); mesh.material = material;
aoMap.channel = 1; // this material now samples uv1 instead of uvMeshPhysicalMaterial (Advanced PBR)
Extends MeshStandardMaterial with layer and volume features. Texture variants exist for most of them: clearcoatMap, clearcoatRoughnessMap, clearcoatNormalMap, transmissionMap, thicknessMap, iridescenceMap, iridescenceThicknessMap, sheenColorMap, sheenRoughnessMap, anisotropyMap, specularIntensityMap, specularColorMap.
const material = new THREE.MeshPhysicalMaterial({
// Clearcoat (car paint, lacquer)
clearcoat: 1.0, // 0 = none, 1 = full coat
clearcoatRoughness: 0.1,
// Transmission (glass, water) - refracts the opaque objects and scene.background behind it
transmission: 1.0, // 0 = opaque, 1 = fully transmissive
thickness: 0.5, // volume thickness for refraction
attenuationDistance: 1, // world units; Infinity (the default) = no absorption
attenuationColor: new THREE.Color(0xffaa66), // white light turns this color after attenuationDistance
ior: 1.5, // index of refraction, 1 to 2.333
// Sheen (fabric, velvet)
sheen: 1.0,
sheenColor: new THREE.Color(0xffffff),
sheenRoughness: 0.5,
// Iridescence (soap bubbles, oil slicks)
iridescence: 1.0,
iridescenceIOR: 1.3,
iridescenceThicknessRange: [100, 400], // nanometers
// Anisotropy (brushed metal); direction with anisotropyRotation
anisotropy: 1.0,
// Dispersion (prismatic glass); retroreflectivity (road signs, safety gear)
dispersion: 0.0,
retroreflectivity: 0.0,
// Specular overrides: specularIntensity, specularColor (plus their maps)
});Glass - transmission with a smooth surface and something behind it to refract:
const glass = new THREE.MeshPhysicalMaterial({
color: 0xffffff,
metalness: 0,
roughness: 0,
transmission: 1,
thickness: 0.5,
ior: 1.5,
});
// transmission refracts the opaque objects and background behind it; scene.environment adds its reflectionsMeshToonMaterial
Cel shading. The gradient map is non-color data - keep its default color space.
const steps = new Uint8Array([120, 200]); // two shading steps
const gradientMap = new THREE.DataTexture(steps, 2, 1, THREE.RedFormat);
gradientMap.minFilter = THREE.NearestFilter; // hard steps; LinearFilter blends them
gradientMap.magFilter = THREE.NearestFilter;
gradientMap.needsUpdate = true;
const material = new THREE.MeshToonMaterial({ color: 0x00ff00, gradientMap });MeshNormalMaterial and MeshDepthMaterial
// Normals encoded as RGB - debugging and flat illustrative looks
const normals = new THREE.MeshNormalMaterial({ flatShading: false, wireframe: false });
// Depth as grayscale (BasicDepthPacking, the default); RGBADepthPacking packs it for reading back in a shader
const depth = new THREE.MeshDepthMaterial();PointsMaterial
For point clouds. size is in pixels; with sizeAttenuation (the default, perspective cameras only) it is multiplied by half the canvas height and divided by the point's view-space depth.
const geometry = new THREE.BufferGeometry();
geometry.setAttribute("position", new THREE.Float32BufferAttribute([0, 0, 0, 1, 0.5, 0, 0.5, 1, 0], 3));
const material = new THREE.PointsMaterial({
color: 0xffffff,
size: 0.1,
sizeAttenuation: true, // scale with distance
alphaTest: 0.5, // with a map or alphaMap: discard fragments below this alpha
});
const points = new THREE.Points(geometry, material);
scene.add(points);LineBasicMaterial and LineDashedMaterial
WebGL and WebGPU always draw line primitives 1 px wide; linewidth, linecap and linejoin only affect the SVGRenderer. For thick lines under WebGLRenderer use Line2 with LineGeometry and LineMaterial from three/addons/lines/ (linewidth in pixels); LineMaterial is a ShaderMaterial, so WebGPURenderer needs Line2 from three/addons/lines/webgpu/Line2.js, which uses Line2NodeMaterial.
const geometry = new THREE.BufferGeometry();
geometry.setAttribute("position", new THREE.Float32BufferAttribute([-1, 0, 0, 1, 0, 0], 3));
const solid = new THREE.LineBasicMaterial({ color: 0xffffff }); // always 1 px
const dashed = new THREE.LineDashedMaterial({ color: 0xffffff, dashSize: 0.5, gapSize: 0.25 });
const line = new THREE.Line(geometry, dashed);
line.computeLineDistances(); // required, or the line draws solid
scene.add(line);ShaderMaterial (WebGLRenderer only)
Custom GLSL with three.js uniforms injected for you. It always compiles as GLSL ES 3.00: texture(), textureLod() and dFdx work, and texture2D / gl_FragColor remain as aliases - leave glslVersion unset. ShaderMaterial, RawShaderMaterial and onBeforeCompile have no WebGPURenderer path; there, use node materials and TSL.
const timer = new THREE.Timer();
timer.connect(document); // pause when the tab is hidden
const material = new THREE.ShaderMaterial({
uniforms: { time: { value: 0 } },
vertexShader: `
varying vec2 vUv;
uniform float time;
void main() {
vUv = uv;
vec3 pos = position;
pos.z += sin(pos.x * 10.0 + time) * 0.1;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
`,
fragmentShader: `
varying vec2 vUv;
uniform float time;
void main() {
vec3 col = 0.5 + 0.5 * cos(time + vUv.xyx * 3.0);
gl_FragColor = vec4(col, 1.0);
}
`,
});
function animate() {
timer.update(); // first thing every frame, no argument
material.uniforms.time.value = timer.getElapsed();
renderer.render(scene, camera);
}Declared for you in the shader: modelMatrix, modelViewMatrix, projectionMatrix, viewMatrix, normalMatrix, cameraPosition, and the attributes position, normal, uv (plus instanceMatrix on an InstancedMesh, which you apply yourself: projectionMatrix * modelViewMatrix * instanceMatrix * vec4(pos, 1.0), and color with vertexColors). The extra uv sets and tangent are not declared - add in vec2 uv1; yourself.
RawShaderMaterial (WebGLRenderer only)
No declarations are prepended (only #version from glslVersion, the SHADER_TYPE and SHADER_NAME defines, and your defines), but the renderer still sets projectionMatrix, modelViewMatrix, viewMatrix, normalMatrix, modelMatrix and cameraPosition - declare them in the shader and never pass them in uniforms: a same-named entry is overwritten every draw (modelMatrix, modelViewMatrix, normalMatrix) or replaces the camera's value (projectionMatrix, viewMatrix, cameraPosition).
const material = new THREE.RawShaderMaterial({
glslVersion: THREE.GLSL3, // without it the shader is GLSL ES 1.00, which has no texture()
vertexShader: `
precision highp float;
in vec3 position;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
precision highp float;
out highp vec4 fragColor; // your own output variable
void main() {
fragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`,
});Common Properties
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
material.visible = true;
material.transparent = false; // true for opacity below 1; toggling it after the first render needs needsUpdate
material.opacity = 1.0;
material.alphaTest = 0; // discard fragments with alpha below the value
material.side = THREE.FrontSide; // FrontSide, BackSide, DoubleSide
material.depthTest = true;
material.depthWrite = true;
material.blending = THREE.NormalBlending; // or AdditiveBlending, CustomBlending
material.polygonOffset = false; // with the two values below, fixes z-fighting
material.polygonOffsetFactor = 0;
material.polygonOffsetUnits = 0;
material.toneMapped = true; // false keeps exact colors (UI overlays)
material.dithering = false; // true reduces banding in gradients
material.vertexColors = false;// Multiply and subtractive blending require premultiplied alpha (both renderers)
const material = new THREE.MeshBasicMaterial({ color: 0x8844ff });
material.blending = THREE.SubtractiveBlending; // same for THREE.MultiplyBlending
material.premultipliedAlpha = true; // without it the renderer logs an error and sets no blend function
// Stencil is off by default in both renderers: create the renderer with { stencil: true }
const maskMaterial = new THREE.MeshBasicMaterial({ colorWrite: false, depthWrite: false });
maskMaterial.stencilWrite = true; // master switch for the stencil test and write
maskMaterial.stencilRef = 1;
maskMaterial.stencilZPass = THREE.ReplaceStencilOp; // writes 1 where the mask draws; also stencilFail, stencilZFail
const contentMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000, stencilWrite: true, stencilRef: 1 });
contentMaterial.stencilFunc = THREE.EqualStencilFunc; // draws only where the mask wrote 1
contentMaterial.stencilFuncMask = 0xff; // compare mask; stencilWriteMask masks the write (both default 0xff)
// draw the mask first: give its mesh a lower renderOrder than the content meshMultiple Materials per Mesh
// One material per geometry group; BoxGeometry has six, in the order +x, -x, +y, -y, +z, -z
const geometry = new THREE.BoxGeometry(1, 1, 1);
const colors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff];
const mesh = new THREE.Mesh(geometry, colors.map((color) => new THREE.MeshBasicMaterial({ color })));
// Custom groups: start, count, material index. Indexed geometry counts indices (BoxGeometry has 36),
// non-indexed geometry counts vertices; ranges outside every group are not drawn
geometry.clearGroups();
geometry.addGroup(0, 18, 0);
geometry.addGroup(18, 18, 1);Environment Maps
An equirectangular HDR file lights and reflects every PBR material in the scene. Both renderers prefilter it themselves - no PMREM step needed.
import { HDRLoader } from "three/addons/loaders/HDRLoader.js";
const env = await new HDRLoader().loadAsync("environment.hdr");
env.mapping = THREE.EquirectangularReflectionMapping; // without it a background draws as a flat quad
scene.environment = env; // lights and reflects PBR materials
scene.background = env;
scene.environmentIntensity = 0.8; // scene-wide dimmer; scene.environmentRotation tilts itconst cubeEnv = new THREE.CubeTextureLoader().load([
"px.jpg", "nx.jpg", "py.jpg", "ny.jpg", "pz.jpg", "nz.jpg",
]);
const material = new THREE.MeshStandardMaterial({ envMap: cubeEnv });
material.envMapIntensity = 1.5; // scales only this material's own envMap
material.envMapRotation = new THREE.Euler(0, Math.PI / 4, 0);scene.environment lights MeshStandardMaterial and MeshPhysicalMaterial on both renderers. With WebGLRenderer it also lights MeshLambertMaterial and MeshPhongMaterial; WebGPURenderer does not.
Runtime Changes, Cloning, Disposal
mesh.material.color.set(0xff0000); // uniform values: no recompile needed
mesh.material.roughness = 0.8;
// material.needsUpdate = true after changing a setting compiled into the shader:
// transparent, side, blending, flatShading, vertexColors, dithering, premultipliedAlpha, alphaHash,
// adding or removing a map slot, or shader source (alphaTest and envMap recompile by themselves)
const clone = mesh.material.clone(); // copies values; map slots share their textures, ShaderMaterial uniforms are clonedDispose a material nothing else uses: material.dispose() releases its GPU programs, which are deleted once no other material uses them; textures need their own texture.dispose().
Performance, in order of impact:
- Share one material instance across meshes - the renderer re-uploads material uniforms whenever consecutive draws switch material (identical settings already share one compiled program).
- Prefer opaque rendering: transparent materials are sorted back to front by object and drawn after the opaque ones, still writing depth unless
depthWrite: false, so stacked layers overdraw and intersecting ones misorder; for cutouts, alphaTest keeps the material opaque, so it draws in the opaque pass, correctly in any order. - Pick the cheapest material that looks right: Basic, then Lambert, Phong, Standard, Physical.
WebGPU and TSL
MeshStandardMaterial and the other built-in classes run under WebGPURenderer unchanged - the renderer converts them to node materials automatically; ShaderMaterial, RawShaderMaterial, MeshDepthMaterial and MeshDistanceMaterial have no node equivalent and log Material "..." is not compatible. For custom shading use the node material classes from three/webgpu with TSL nodes from three/tsl; they target WebGPURenderer, and WebGLRenderer draws them only through the WebGLNodesHandler addon (three/addons/tsl/WebGLNodesHandler.js, passed to renderer.setNodesHandler()), a migration aid without VSM shadows, MRT, transmission or the WebGPU post-processing stack.
import * as THREE from "three/webgpu";
const renderer = new THREE.WebGPURenderer({ antialias: true });
await renderer.init(); // before any other use of the renderer
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x111111); // the WebGPU canvas is transparent by default
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(0, 0, 3);
function animate() {
renderer.render(scene, camera);
}
renderer.setAnimationLoop(animate);import * as THREE from "three/webgpu";
import { texture, mix, color, float, time, positionLocal, normalLocal, sin } from "three/tsl";
// Unlit: the node equivalent of a color ShaderMaterial
const unlit = new THREE.MeshBasicNodeMaterial();
unlit.colorNode = mix(color(0x0066ff), color(0xff0066), sin(time.mul(0.5)).mul(0.5).add(0.5));
// Lit: node slots replace the fixed properties; needs lights or scene.environment
const map = await new THREE.TextureLoader().loadAsync("color.jpg");
map.colorSpace = THREE.SRGBColorSpace;
const lit = new THREE.MeshStandardNodeMaterial();
lit.colorNode = texture(map);
lit.roughnessNode = float(0.2);
// Vertex displacement on positionLocal, which already carries skinning, morphs, instancing
const shell = new THREE.MeshStandardNodeMaterial();
shell.positionNode = positionLocal.add(normalLocal.mul(sin(positionLocal.y.mul(6))).mul(0.05));import * as THREE from "three/webgpu";
import { instancedBufferAttribute } from "three/tsl";
// The WebGPU backend draws Points at 1 px whatever the size; draw larger points as quads
const positions = new THREE.InstancedBufferAttribute(new Float32Array(1500), 3); // fill with x, y, z per point
const points = new THREE.Sprite(
new THREE.PointsNodeMaterial({ positionNode: instancedBufferAttribute(positions), size: 4, sizeAttenuation: false }) // 4 px squares
);
points.count = 500; points.frustumCulled = false; // one quad per point; culling would test only a 0.7-unit sphere at the sprite origin
scene.add(points);Common Mistakes
geometry.setAttribute("uv2", geometry.attributes.uv)→const material = new THREE.MeshStandardMaterial({ aoMap });: aoMap samples the attribute picked byaoMap.channel, 0 (uv) by default, so it needs no extra attribute and uv2 is read only withaoMap.channel = 2; only a separate unwrap goes inuv1withaoMap.channel = 1.new RGBELoader()→new HDRLoader(): HDRLoader was renamed from RGBELoader in r180; RGBELoader is deprecated and still loads, with a warning - import HDRLoader from "three/addons/loaders/HDRLoader.js"."three/examples/jsm/loaders/HDRLoader.js"→"three/addons/loaders/HDRLoader.js": the browser import maps mapthree/addons/to examples/jsm/ and define nothree/examples/key, so the examples path fails there.material.blending = THREE.MultiplyBlending;→material.blending = THREE.MultiplyBlending; material.premultipliedAlpha = true;: multiply and subtractive blending require premultiplied alpha, or the renderer logs an error and sets no blend function.material.stencilMask = 0xff;→material.stencilFuncMask = 0xff; material.stencilWriteMask = 0xff;:stencilMaskdoes not exist; assigning it just creates an unused field.new THREE.WebGLRenderer({ antialias: true })→new THREE.WebGLRenderer({ antialias: true, stencil: true }): the stencil buffer is off by default, so material stencil settings are silently ignored without it.material.envMapIntensity = 0.5;→scene.environmentIntensity = 0.5;: to dim scene.environment use the scene property - envMapIntensity attenuates only the material's own envMap.material.uniforms.time.value = clock.getElapsedTime();→material.uniforms.time.value = timer.getElapsed();: Clock is deprecated in r183 - create a THREE.Timer, call timer.connect(document) once, and timer.update() (no argument) first in the loop.new THREE.ShaderMaterial({ glslVersion: THREE.GLSL3, fragmentShader })→new THREE.ShaderMaterial({ fragmentShader }): ShaderMaterial already compiles as GLSL ES 3.00, sotexture()works with glslVersion unset, while GLSL3 removes thegl_FragColoralias and a shader that writes it fails to compile.uniforms: { modelViewMatrix: { value: new THREE.Matrix4() } }→uniform mat4 modelViewMatrix;: declare the built-in matrices in a RawShaderMaterial's shader source - a same-named uniforms entry is overwritten every draw (modelMatrix, modelViewMatrix, normalMatrix) or replaces the camera's value (projectionMatrix, viewMatrix, cameraPosition).new THREE.LineBasicMaterial({ linewidth: 5 })→new Line2(new LineGeometry().setPositions([-1, 0, 0, 1, 0, 0]), new LineMaterial({ linewidth: 5 })): WebGLRenderer always draws 1 px line primitives; Line2 needs a LineGeometry, not a BufferGeometry, and all three come from three/addons/lines/ (under WebGPURenderer, Line2 comes from three/addons/lines/webgpu/Line2.js with Line2NodeMaterial).new THREE.ShaderMaterial({ vertexShader, fragmentShader })→new THREE.MeshBasicNodeMaterial(): under WebGPURenderer use node materials and TSL - ShaderMaterial and RawShaderMaterial have no node equivalent and log "is not compatible".import { texture } from "three/nodes";→import { texture } from "three/tsl";:three/nodesdoes not exist - node materials come fromthree/webgpu, TSL functions fromthree/tsl.import * as THREE from "three"; const m = new THREE.MeshStandardNodeMaterial();→import * as THREE from "three/webgpu"; const m = new THREE.MeshStandardNodeMaterial();: node materials are exported only by three/webgpu and target WebGPURenderer.new THREE.PointsMaterial({ size: 5 })→new THREE.Sprite(new THREE.PointsNodeMaterial({ positionNode: instancedBufferAttribute(positions) })): the WebGPU backend draws Points at 1 px whatever the size - set sprite.count to the number of points.material.positionNode = positionGeometry.add(offset);→material.positionNode = positionLocal.add(offset);: positionLocal carries skinning, morph targets, batching and instancing; positionGeometry is the raw rest-pose attribute.map.encoding = THREE.sRGBEncoding;→map.colorSpace = THREE.SRGBColorSpace;:encodingandsRGBEncodingno longer exist, so the old line does nothing and the color map renders washed out.const m = new THREE.MeshStandardNodeMaterial(); m.colorNode = color(0xff0000);→const m = new THREE.MeshBasicNodeMaterial(); m.colorNode = color(0xff0000);: MeshStandardNodeMaterial is lit and renders black without lights or an environment, so an unlit effect uses MeshBasicNodeMaterial.new THREE.ShaderMaterial({ extensions: { derivatives: true }, fragmentShader })→new THREE.ShaderMaterial({ fragmentShader }): the WebGL1 extension flags do nothing, because GLSL ES 3.00 hasdFdx,gl_FragDepthandtextureLodbuilt in.
See Also
threejs-textures- loading, color spaces, filters and channels in depththreejs-shaders- GLSL authoring, shader chunks and debugging under WebGLRendererthreejs-lighting- lights, shadows and how they interact with materials
Trending
Steady: 0 new projects took it in the last 4 weeks, none the 4 weeks before.thin data
Who's talking about CloudAI-X/threejs-skills
- ProSkillsMD/proskills“[Candidate] cloudai-x/threejs-skills/skills/threejs-performance - threejs-performance”GitHub · Oct 19, 2026
- ProSkillsMD/proskills“[Candidate] cloudai-x/threejs-skills/skills/threejs-materials - threejs-materials”GitHub · Oct 19, 2026
- ProSkillsMD/proskills“[Candidate] cloudai-x/threejs-skills/skills/threejs-asset-pipeline - threejs-asset-pipeline”GitHub · Oct 19, 2026
- sudosubin/agents.nix“agent-skills.github.cloudai-x.threejs-skills: 0-unstable-2026-10-18 → 0-unstable-2026-10-19”GitHub · Oct 19, 2026
- sudosubin/agents.nix“claude-code-plugins.github.cloudai-x.threejs-skills: 0-unstable-2026-10-18 → 0-unstable-2026-10-19”GitHub · Oct 19, 2026
The biggest 5 of 31 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 31
Talked about on GitHub (31 times).
On GitHub · 31
- Oct 19, 2026[Candidate] cloudai-x/threejs-skills/skills/threejs-performance - threejs-performance — ProSkillsMD/proskills0 reactions · 1 comment
- Oct 19, 2026[Candidate] cloudai-x/threejs-skills/skills/threejs-materials - threejs-materials — ProSkillsMD/proskills0 reactions · 1 comment
- Oct 19, 2026[Candidate] cloudai-x/threejs-skills/skills/threejs-asset-pipeline - threejs-asset-pipeline — ProSkillsMD/proskills0 reactions · 1 comment
- Oct 19, 2026agent-skills.github.cloudai-x.threejs-skills: 0-unstable-2026-10-18 → 0-unstable-2026-10-19 — sudosubin/agents.nix0 reactions
- Oct 19, 2026claude-code-plugins.github.cloudai-x.threejs-skills: 0-unstable-2026-10-18 → 0-unstable-2026-10-19 — sudosubin/agents.nix0 reactions
26 more on GitHub
- Oct 19, 2026claude-code-plugins.github.cloudai-x.threejs-skills: 11ffda7 → be38bd0 — sudosubin/agents.nix0 reactions
- Oct 18, 2026agent-skills.github.cloudai-x.threejs-skills: 11ffda7 → 5b8abb5 — sudosubin/agents.nix0 reactions
- Oct 18, 2026[Candidate] cloudai-x/threejs-skills/skills/threejs-loaders - threejs-loaders — ProSkillsMD/proskills0 reactions · 1 comment
- Oct 18, 2026[Candidate] cloudai-x/threejs-skills/skills/threejs-lighting - threejs-lighting — ProSkillsMD/proskills0 reactions · 1 comment
- Oct 18, 2026[Candidate] cloudai-x/threejs-skills/skills/threejs-interaction - threejs-interaction — ProSkillsMD/proskills0 reactions · 1 comment
- Oct 18, 2026claude-code-plugins.github.cloudai-x.threejs-skills: 0-unstable-2026-01-19 → 0-unstable-2026-10-18 — sudosubin/agents.nix0 reactions
- Oct 18, 2026agent-skills.github.cloudai-x.threejs-skills: 0-unstable-2026-01-19 → 0-unstable-2026-10-18 — sudosubin/agents.nix0 reactions
- Oct 18, 2026[Candidate] cloudai-x/threejs-skills/skills/threejs-geometry - threejs-geometry — ProSkillsMD/proskills0 reactions · 1 comment
- Oct 18, 2026[Candidate] cloudai-x/threejs-skills/skills/threejs-fundamentals - threejs-fundamentals — ProSkillsMD/proskills0 reactions · 1 comment
- Oct 18, 2026[Candidate] cloudai-x/threejs-skills/skills/threejs-animation - threejs-animation — ProSkillsMD/proskills0 reactions · 1 comment
- Oct 4, 2026claude-code-plugins.github.cloudai-x.threejs-skills: init at 0-unstable-2026-01-19 — sudosubin/agents.nix0 reactions
- Sep 26, 2026agent-skills.github.cloudai-x.threejs-skills: init at 0-unstable-2026-01-19 — sudosubin/agents.nix0 reactions
- Apr 10, 2026Vendor CloudAI-X Three.js skills into repo-scoped `.agents/skills/` — Justtrying1001/coinage0 reactions · 1 comment
- Mar 4, 2026add threejs skills for claude code — Comfy-Org/ComfyUI_frontend0 reactions · 3 comments
- Feb 20, 2026threejs-textures — AAswordman/OperitSkillMarket0 reactions
- Feb 20, 2026threejs-shaders — AAswordman/OperitSkillMarket0 reactions
- Feb 20, 2026threejs-postprocessing — AAswordman/OperitSkillMarket0 reactions
- Feb 20, 2026threejs-materials — AAswordman/OperitSkillMarket0 reactions
- Feb 20, 2026threejs-loaders — AAswordman/OperitSkillMarket0 reactions
- Feb 20, 2026threejs-lighting — AAswordman/OperitSkillMarket0 reactions
- Feb 20, 2026threejs-interaction — AAswordman/OperitSkillMarket0 reactions
- Feb 20, 2026threejs-geometry — AAswordman/OperitSkillMarket0 reactions
- Feb 20, 2026threejs-fundamentals — AAswordman/OperitSkillMarket0 reactions
- Feb 20, 2026threejs-animation — AAswordman/OperitSkillMarket0 reactions
- Feb 10, 2026New skill: /cloudai-x-threejs-animation (safe risk) — aiskillstore/marketplace0 reactions
- Feb 9, 2026New skill: /cloudai-x-threejs-animation (low risk) — aiskillstore/marketplace0 reactions
Other versions20 projects use a version of this.
Word for word · 0
None found.
Edited · 15
- calesthio/OpenMontage★ 72k16% same
- educlopez/thegridcn-ui★ 39016% same
- quiet-node/gesture-lab★ 18516% same
- kumaran-is/claude-code-onboarding★ 3514% same
- ruloCode/hermes-os★ 1516% same
- LinHao-city/StoryMind★ 1016% same
- chadixearth/graphyloop★ 316% same
- codetesla51/skills★ 316% same
- Adhamxon/claude-code-skills★ 214% same
- huangzida/skills★ 216% same
5 more not listed
Wrote their own version · 5
- alton47/threejs-skills★ 13same name
- full-stack-skills/threejs-skills★ 9same name
- ai4brands-design/claude-skills★ 2same name
- FkennedyFox/claude-skills★ 0same name
- Gopyr/gopyr-skills-hub★ 0same 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.
Used alongsideProjects with it also use pose-library-design, threejs-audio and 9 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-citySkillpose-library-design
Design reusable 2D character pose libraries, action cycles, and expression states for data-driven animation.
Also in 3 projects that use this
alton47Skillthreejs-audio
Adds spatial and non-spatial audio to Three.js scenes using AudioListener, Audio, PositionalAudio, AudioAnalyser, and AudioLoader. Use when the user asks about 3D audio, spatial sound, positional audio, audio visualization, background music, or Web Audio API integration. Trigger keywords: audio, sound, PositionalAudio, AudioListener, AudioAnalyser, spatial audio, 3D sound, music visualization.
Also in 3 projects that use this
alton47Skillthreejs-camera
Configures Three.js cameras and controls — PerspectiveCamera, OrthographicCamera, OrbitControls, FlyControls, PointerLockControls, and first-person setup. Use when the user asks about cameras, controls, orbit, fly, first-person, camera movement, or viewport setup. Trigger keywords: camera, OrbitControls, FlyControls, PointerLockControls, perspective, orthographic, first person, viewport, FOV.
Also in 3 projects that use this
LinHao-citySkillvideo-toolkit
Create professional videos autonomously using claude-code-video-toolkit — AI voiceovers, image generation, music, talking heads, and Remotion rendering.
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
- +4 more from LinHao-city
In this repository12 other files it gives its agents.
- threejs-animationSkill
- threejs-asset-pipelineSkill
- threejs-fundamentalsSkill
- threejs-geometrySkill
- threejs-interactionSkill
- threejs-lightingSkill
- threejs-loadersSkill
- threejs-performanceSkill
- threejs-postprocessingSkill
- threejs-react-three-fiberSkill
- threejs-shadersSkill
- threejs-texturesSkill
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.

