Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
openaec-foundation avatar

Threejs Errors Rendering

  • 19 installs
  • 11 repo stars
  • Updated July 8, 2026
  • openaec-foundation/three.js-claude-skill-package

Helps with ai & agent building tasks.

About

threejs-errors-rendering is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.

  • threejs-errors-rendering
  • AI & Agent Building
  • AI-coding skill

Threejs Errors Rendering by the numbers

  • 19 all-time installs (skills.sh)
  • +2 installs in the week ending Aug 4, 2026 (Skillselion tracking)
  • Ranked #10,587 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
  • Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/openaec-foundation/three.js-claude-skill-package --skill threejs-errors-rendering

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs19
repo stars11
Last updatedJuly 8, 2026
Repositoryopenaec-foundation/three.js-claude-skill-package

What it does

Helps with ai & agent building tasks.

Files

SKILL.mdMarkdownGitHub ↗

threejs-errors-rendering

Debugging Workflow Checklist

When a Three.js scene does not render correctly, ALWAYS follow this sequence:

1. Open the browser console -- check for WebGL errors or Three.js warnings 2. Verify the renderer has a non-zero size (renderer.getSize(new THREE.Vector2())) 3. Confirm the canvas is in the DOM and visible (not display: none) 4. Check that renderer.render(scene, camera) is called (in a loop or at least once) 5. Verify the camera is looking at the scene (position, target, near/far) 6. Confirm at least one light exists for lit materials 7. Check material side, visible, opacity, and transparent properties 8. Verify object visible, layers, and frustumCulled properties 9. Inspect color space settings on renderer and textures

---

Symptom 1: Black Screen (Nothing Visible)

Cause A: Renderer has zero size

The canvas has 0x0 dimensions. This happens when setSize() is called before the container is in the DOM or when the container has no CSS dimensions.

Fix:

// ALWAYS ensure the container is in the DOM and has dimensions before setSize
document.body.appendChild(renderer.domElement);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));

Cause B: Camera is inside the object or facing away

The camera is at (0, 0, 0) and the object is also at (0, 0, 0), so the camera is inside the mesh. Or the camera is pointing in the wrong direction.

Fix:

camera.position.set(0, 2, 5); // ALWAYS move camera away from origin
camera.lookAt(0, 0, 0);

Cause C: Near/far clipping planes exclude the object

Objects closer than near or farther than far are clipped. Default PerspectiveCamera near is 0.1, far is 2000.

Fix:

const camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 1000);
// NEVER set near to 0 -- causes z-fighting and depth buffer issues
// ALWAYS keep far/near ratio below 100000 for stable depth precision

Cause D: No light in the scene

MeshStandardMaterial, MeshPhongMaterial, and MeshLambertMaterial require lights. Without light, they render black. MeshBasicMaterial does NOT require lights.

Fix:

scene.add(new THREE.AmbientLight(0xffffff, 0.5));
scene.add(new THREE.DirectionalLight(0xffffff, 1));

Cause E: render() is never called

The animation loop is not started, or renderer.render(scene, camera) is missing.

Fix:

function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}
animate(); // ALWAYS call the function to start the loop

Cause F: Scene or camera is wrong reference

Passing an empty scene or an uninitialized camera to render().

Diagnosis: Log scene.children.length and camera.type before the render call.

---

Symptom 2: Invisible Objects

Cause A: Wrong material side

Back faces are culled by default (FrontSide). If the camera sees the back of a plane or thin geometry, it is invisible.

Fix:

const material = new THREE.MeshStandardMaterial({
  side: THREE.DoubleSide // ALWAYS use for planes, leaves, thin objects
});

Cause B: opacity without transparent

Setting opacity: 0.5 without transparent: true has NO effect.

Fix:

const material = new THREE.MeshStandardMaterial({
  opacity: 0.5,
  transparent: true // ALWAYS pair with opacity < 1
});

Cause C: Object on a different layer

The camera and the object MUST share at least one layer. By default both are on layer 0. If the object is moved to another layer, the camera must enable that layer too.

Fix:

object.layers.set(1);
camera.layers.enable(1); // camera must see layer 1

Cause D: visible is false (inherited)

visible = false on a parent makes ALL descendants invisible. Check the full parent chain.

Diagnosis:

let node = object;
while (node) {
  if (!node.visible) console.log('Hidden ancestor:', node.name || node.type);
  node = node.parent;
}

Cause E: frustumCulled incorrectly

If the bounding sphere is wrong (e.g., after manual vertex changes without computeBoundingSphere()), the object may be culled even when visible.

Fix:

geometry.computeBoundingSphere(); // ALWAYS call after modifying positions
// Or disable frustum culling for objects that must always render:
mesh.frustumCulled = false;

Cause F: Object at wrong position or scale 0

Object is at a position far from the camera, or scale.set(0, 0, 0).

Diagnosis: Log object.position, object.scale, object.matrixWorld.

---

Symptom 3: Wrong Colors

Cause A: Color space mismatch

This is the MOST COMMON color error in Three.js r160+.

Rules:

  • Color/diffuse/emissive textures: ALWAYS set texture.colorSpace = THREE.SRGBColorSpace
  • Data textures (normal, roughness, metalness, AO, displacement): ALWAYS leave as THREE.LinearSRGBColorSpace
  • Renderer output: renderer.outputColorSpace = THREE.SRGBColorSpace (default in r160+)

Symptoms of wrong color space:

  • Washed-out colors: data texture incorrectly set to SRGBColorSpace (double gamma)
  • Over-saturated colors: color texture left in LinearSRGBColorSpace (no gamma applied)

Fix:

const texture = await loader.loadAsync('diffuse.png');
texture.colorSpace = THREE.SRGBColorSpace; // for color textures

const normalMap = await loader.loadAsync('normal.png');
// NEVER set SRGBColorSpace on normal maps -- corrupts surface data

Cause B: Tone mapping not configured

Without tone mapping, HDR values are clamped, producing flat or incorrect colors.

Fix:

renderer.toneMapping = THREE.ACESFilmicToneMapping; // or AgXToneMapping
renderer.toneMappingExposure = 1.0;

Cause C: Material color set after construction ignored

material.color.set() works, but material.color = new THREE.Color() after construction also works. The common mistake is setting color as a hex number directly: material.color = 0xff0000 does NOT work.

Fix:

material.color.set(0xff0000);      // Correct
material.color = new THREE.Color(0xff0000); // Correct
// material.color = 0xff0000;      // WRONG -- silently fails

---

Symptom 4: Z-Fighting (Flickering Surfaces)

Z-fighting occurs when two surfaces overlap at nearly the same depth, causing the depth buffer to alternate between them.

Fix A: Polygon offset

const material = new THREE.MeshStandardMaterial({
  polygonOffset: true,
  polygonOffsetFactor: -1,
  polygonOffsetUnits: -1
});

Fix B: Logarithmic depth buffer

const renderer = new THREE.WebGLRenderer({ logarithmicDepthBuffer: true });
// Trades performance for better depth precision across large near/far ranges
// NEVER use with EffectComposer post-processing -- causes artifacts

Fix C: Position offset

Move one surface slightly:

decalMesh.position.z += 0.01; // small offset to prevent overlap

Fix D: Reduce near/far ratio

// ALWAYS keep the near plane as large as possible
camera.near = 1;    // not 0.001
camera.far = 1000;  // not 1000000
camera.updateProjectionMatrix();

---

Symptom 5: Shadow Artifacts

For complete shadow configuration, see the threejs-impl-shadows skill. Common quick fixes:

  • No shadows at all: renderer.shadowMap.enabled = true, light.castShadow = true, mesh.castShadow = true, ground.receiveShadow = true
  • Shadow acne (stripes): Increase light.shadow.bias (e.g., -0.005)
  • Peter panning (shadow detached): light.shadow.bias is too large, reduce it
  • Low-res shadows: Increase light.shadow.mapSize.set(2048, 2048)

---

Symptom 6: WebGL Context Lost

The browser reclaims the WebGL context under memory pressure or GPU reset.

Recovery pattern

renderer.domElement.addEventListener('webglcontextlost', (event) => {
  event.preventDefault(); // ALWAYS prevent default to allow restoration
  cancelAnimationFrame(animationId);
}, false);

renderer.domElement.addEventListener('webglcontextrestored', () => {
  // Re-initialize materials, textures, render targets
  initScene();
  animate();
}, false);

NEVER ignore context loss -- the canvas goes black permanently. ALWAYS add both event listeners.

---

Symptom 7: needsUpdate Missing

BufferAttribute

After modifying vertex data, the GPU buffer is stale:

positions.array[0] = newX;
positions.needsUpdate = true; // ALWAYS set after modifying attribute data

Material

After changing structural properties (adding/removing maps, changing defines):

material.map = newTexture;
material.needsUpdate = true; // triggers shader recompilation
// NEVER set needsUpdate = true every frame -- causes constant recompilation

Texture

After modifying texture image data:

texture.image = newImage;
texture.needsUpdate = true; // triggers GPU re-upload

InstancedMesh

After setMatrixAt() or setColorAt():

mesh.instanceMatrix.needsUpdate = true; // ALWAYS after setMatrixAt
mesh.instanceColor.needsUpdate = true;  // ALWAYS after setColorAt

---

Symptom 8: updateProjectionMatrix Required

ALWAYS call camera.updateProjectionMatrix() after changing:

  • camera.fov
  • camera.aspect
  • camera.near
  • camera.far
  • camera.zoom
  • camera.left/right/top/bottom (OrthographicCamera)
window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix(); // NEVER forget this
  renderer.setSize(window.innerWidth, window.innerHeight);
});

---

Symptom 9: Transparent Object Rendering Issues

Transparent objects render in the wrong order (back-to-front sorting fails).

Fix A: renderOrder

// Force specific rendering order
backgroundMesh.renderOrder = 0;
transparentMesh.renderOrder = 1;
frontMesh.renderOrder = 2;

Fix B: depthWrite

const material = new THREE.MeshStandardMaterial({
  transparent: true,
  opacity: 0.5,
  depthWrite: false // prevents transparent objects from writing to depth buffer
});

Fix C: alphaTest instead of transparency

For textures with hard alpha edges (foliage, fences):

const material = new THREE.MeshStandardMaterial({
  map: leafTexture,
  alphaTest: 0.5, // discards fragments below threshold
  side: THREE.DoubleSide
  // NEVER set transparent: true for hard-edge alpha -- use alphaTest instead
});

---

Common Console Warnings

WarningCauseFix
THREE.WebGLRenderer: Texture is not power of twoNPOT texture with repeat wrappingUse power-of-two textures or ClampToEdgeWrapping
THREE.WebGLProgram: shader errorGLSL compilation failureCheck custom shader code for syntax errors
THREE.PropertyBinding: Can not bind to...Animation targets missing propertyEnsure skeleton/morph targets match the animation clip
THREE.BufferGeometry: .addAttribute() removedUsing deprecated APIUse setAttribute() instead
GL_INVALID_OPERATION: Feedback loopReading from a texture that is also a render targetUse separate textures for reading and writing

---

Reference Links

  • references/methods.md -- Fix-related API signatures
  • references/examples.md -- Complete fix patterns
  • references/anti-patterns.md -- What NOT to do

Official Sources

  • https://threejs.org/docs/#api/en/renderers/WebGLRenderer
  • https://threejs.org/docs/#api/en/cameras/PerspectiveCamera
  • https://threejs.org/docs/#api/en/materials/Material
  • https://threejs.org/docs/#api/en/core/Object3D
  • https://threejs.org/docs/#api/en/core/BufferAttribute

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.