Reference Updated June 2026 · Three.js r160 · WebGL 2

WebGL & Three.js Cheatsheet

Quick-reference tables for Three.js r160 and raw WebGL 2. Renderer flags, geometry attributes, texture formats, hardware limits, common patterns, and useful extensions — all on one page.

🖥 Renderer Flags

Pass these options to the WebGLRenderer constructor. Most have performance implications.

Option Default Purpose & notes
antialias false MSAA anti-aliasing. Free on desktop GPU. Expensive on mobile — use FXAA post-process instead.
alpha false Transparent <canvas> background. Requires premultipliedAlpha: true to avoid edge fringing.
premultipliedAlpha true WebGL default. Keep true unless compositing over CSS backgrounds.
stencil true Allocates a stencil buffer. Set false if you never use it to save VRAM.
depth true Depth buffer. Always needed for 3D.
logarithmicDepthBuffer false Fixes z-fighting at extreme near/far ranges (e.g. space scenes). Disables gl_FragDepth in shaders.
powerPreference "default" "high-performance" requests the discrete GPU on laptops. Use it for heavy sims.
failIfMajorPerformanceCaveat false Returns null context if hardware acceleration is missing.

Renderer properties to set after construction

Property / method Recommended value Why
setPixelRatio(Math.min(devicePixelRatio,2)) Caps at 2× DPR; 4× screens get no visual boost but 4× fill cost.
outputColorSpace THREE.SRGBColorSpace Required for physically correct colour output (default since r152).
shadowMap.enabled true only if needed Each shadow-casting light adds a full render pass.
shadowMap.type THREE.PCFSoftShadowMap Smoother edges than default PCF.
toneMapping THREE.ACESFilmicToneMapping HDR → LDR mapping for realistic sky/environment light.
toneMappingExposure 1.0 Adjust for scene brightness.

🔗 Three.js → Raw WebGL Equivalents

Three.js wraps every WebGL concept. This table maps Three classes to their underlying GL calls — useful when writing custom shader passes or debugging.

Three.js Raw WebGL 2 Notes
WebGLRenderer WebGL2RenderingContext Obtained via canvas.getContext('webgl2')
BufferGeometry VAO + VBOs gl.createVertexArray() + gl.createBuffer()
BufferAttribute VBO gl.bufferData(gl.ARRAY_BUFFER, …)
ShaderMaterial WebGLProgram gl.createShader() + gl.createProgram()
uniform in ShaderMaterial gl.uniform*() Three auto-uploads each frame if marked dirty
DataTexture WebGLTexture gl.texImage2D(gl.TEXTURE_2D, …)
WebGLRenderTarget FBO (WebGLFramebuffer) gl.createFramebuffer() + gl.framebufferTexture2D()
Points gl.drawArrays(gl.POINTS, …) One draw call, gl_PointSize in vertex shader
InstancedMesh gl.drawElementsInstanced() Requires gl_InstanceID in vertex shader

📐 BufferGeometry Attributes

Built-in attribute names recognised by Three.js standard materials. Custom shaders can use any name — wire them with geometry.setAttribute('name', attr).

Attribute name itemSize GLSL name Notes
position 3 attribute vec3 position Required. World-space vertex positions.
normal 3 attribute vec3 normal Required for lighting. Auto-computed by geometry.computeVertexNormals().
uv 2 attribute vec2 uv Texture coordinates for map channel 0.
uv1 2 attribute vec2 uv1 Second UV set (lightmap, AO map).
color 3 attribute vec3 color Per-vertex colour. Enable with material.vertexColors = true.
tangent 4 attribute vec4 tangent For normal mapping. Auto via geometry.computeTangents() (needs UVs + normals).
index 1 Set via geometry.setIndex(attr). Reduces vertex count by sharing verts.
needsUpdate

After modifying a BufferAttribute's .array in JS, always set attribute.needsUpdate = true. Without it the GPU continues reading the old data from its buffer.

🖼 Texture Formats

Three constant GL internal format Use case
THREE.RGBAFormat gl.RGBA8 Default colour textures (8 bpc).
THREE.RGBFormat gl.RGB8 Opaque colour (no alpha). Slightly less VRAM.
THREE.RedFormat gl.R8 Single-channel masks, heightmaps.
THREE.RGBAFormat + HalfFloatType gl.RGBA16F HDR render targets, bloom ping-pong.
THREE.RGBAFormat + FloatType gl.RGBA32F High-precision position / velocity GPGPU textures.
THREE.DepthFormat gl.DEPTH_COMPONENT24 Depth attachment on render targets.
RGBA_S3TC_DXT5_EXT Compressed Compressed RGBA — requires EXT_texture_compression_s3tc.

Texture parameters

const tex = new THREE.TextureLoader().load('diffuse.webp');

tex.colorSpace  = THREE.SRGBColorSpace;       // only for colour maps
tex.wrapS       = THREE.RepeatWrapping;        // horizontal repeat
tex.wrapT       = THREE.RepeatWrapping;        // vertical repeat
tex.repeat.set(4, 4);                       // tile 4×4
tex.minFilter   = THREE.LinearMipmapLinearFilter;
tex.magFilter   = THREE.LinearFilter;
tex.anisotropy  = renderer.capabilities.maxAnisotropy; // sharpness at angles

⚙ Hardware Limits

Query these at runtime with renderer.capabilities or raw gl.getParameter():

16
max texture units (fragment)
8 k–16 k
max texture size (px)
65 535
max index (Uint16) → use Uint32
256
max vertex attribs
255
max draw buffers (MRT)
16 384+
max varying vectors
Parameter Query
Max texture size renderer.capabilities.maxTextureSize
Max anisotropy renderer.capabilities.maxAnisotropy
WebGL 2 available renderer.capabilities.isWebGL2
Max vertex uniforms gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS)
Max fragment uniforms gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS)
Max draw buffers gl.getParameter(gl.MAX_DRAW_BUFFERS)

🔌 Useful WebGL Extensions

Extensions are opt-in capabilities. In WebGL 2 many former extensions are now core, but some still require explicit enablement.

Extension Status What it enables
EXT_color_buffer_float WGL2 Render to float textures (RGBA32F). Required for GPGPU compute.
EXT_color_buffer_half_float WGL2 Render to half-float textures — bloom, HDR.
OES_texture_float_linear opt-in Bilinear filtering on float textures. Not guaranteed on mobile.
EXT_texture_filter_anisotropic opt-in Anisotropic filtering — sharper ground textures at grazing angles.
WEBGL_multi_draw opt-in Issue multiple draw calls in one GL call. Reduces CPU overhead.
EXT_texture_compression_s3tc opt-in DXT1/3/5 compressed textures (desktop only).
WEBGL_compressed_texture_astc opt-in ASTC compressed textures (mobile / Apple Silicon).
KHR_parallel_shader_compile opt-in Non-blocking shader compilation — check with getParameter(COMPLETION_STATUS_KHR).

Check availability:

const ext = renderer.extensions.get('EXT_color_buffer_float');
if (!ext) console.warn('Float render targets not supported');

💡 Common Patterns

Render target (off-screen framebuffer)

const rt = new THREE.WebGLRenderTarget(width, height, {
  type: THREE.HalfFloatType,
  format: THREE.RGBAFormat,
  minFilter: THREE.LinearFilter,
  magFilter: THREE.LinearFilter,
  depthBuffer: false,   // skip if no depth test needed
});

renderer.setRenderTarget(rt);
renderer.render(scene, camera);
renderer.setRenderTarget(null); // restore default framebuffer

GPGPU ping-pong (particle physics on GPU)

// Two render targets — swap each frame
let [rtA, rtB] = [makeRT(), makeRT()];

function compute() {
  // rtA = read (previous positions), rtB = write (new positions)
  computeMaterial.uniforms.tPrev.value = rtA.texture;
  renderer.setRenderTarget(rtB);
  renderer.render(quadScene, orthoCamera);
  renderer.setRenderTarget(null);
  [rtA, rtB] = [rtB, rtA]; // swap
}

InstancedMesh — 100k objects, one draw call

const mesh = new THREE.InstancedMesh(geometry, material, COUNT);
const matrix = new THREE.Matrix4();

for (let i = 0; i < COUNT; i++) {
  matrix.setPosition(positions[i]);
  mesh.setMatrixAt(i, matrix);
}
mesh.instanceMatrix.needsUpdate = true;
scene.add(mesh);

Dispose to free GPU memory

// Always dispose when removing objects from the scene
geometry.dispose();
material.dispose();
texture.dispose();
renderTarget.dispose();
renderer.dispose(); // when tearing down the whole renderer
Memory leaks are common

Three.js objects that are removed from the scene but not dispose()d keep their GPU buffers alive. Always dispose geometry, materials and textures you no longer need.

Check WebGL version at runtime

const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2');
if (!gl) {
  console.warn('WebGL 2 unavailable — falling back to WebGL 1');
}
// OR use Three's abstraction:
const renderer = new THREE.WebGLRenderer();
console.log(renderer.capabilities.isWebGL2); // true / false