threejs-syntax-shaders

Installation
SKILL.md

threejs-syntax-shaders

Quick Reference

ShaderMaterial vs RawShaderMaterial

Aspect ShaderMaterial RawShaderMaterial
Built-in uniforms Automatically injected NONE -- you MUST declare everything
Built-in attributes Automatically declared NONE -- you MUST declare everything
#include <chunk> Supported NOT supported
Precision declaration Automatic You MUST add precision mediump float;
Use case Extend Three.js rendering Full shader control, porting external shaders
Performance Slight overhead from unused built-ins Minimal shader overhead

Uniform Type Map

GLSL Type JavaScript Value
float { value: 1.0 }
int { value: 1 }
bool { value: true }
vec2 { value: new THREE.Vector2() }
vec3 { value: new THREE.Vector3() } or { value: new THREE.Color() }
vec4 { value: new THREE.Vector4() }
mat3 { value: new THREE.Matrix3() }
mat4 { value: new THREE.Matrix4() }
sampler2D { value: texture } (a THREE.Texture instance)
samplerCube { value: cubeTexture }
float[] { value: [1.0, 2.0, 3.0] }
vec3[] { value: [new THREE.Vector3(), ...] }

Critical Warnings

NEVER pass a bare value as a uniform -- ALWAYS wrap it in { value: ... }. Writing uniforms: { uTime: 0.0 } silently fails; ALWAYS write uniforms: { uTime: { value: 0.0 } }.

NEVER declare built-in uniforms or attributes in a ShaderMaterial shader -- Three.js injects them automatically. Redeclaring causes a GLSL compilation error.

ALWAYS declare ALL uniforms, attributes, and precision in RawShaderMaterial shaders -- nothing is injected for you.

NEVER use gl_FragColor or texture2D() when glslVersion is THREE.GLSL3 -- use a declared out vec4 variable and texture() instead.

ALWAYS call material.needsUpdate = true after changing defines -- defines are compiled into the shader, so changes require recompilation.


ShaderMaterial

Constructor

import * as THREE from 'three';

const material = new THREE.ShaderMaterial({
  uniforms: {
    uTime: { value: 0.0 },
    uColor: { value: new THREE.Color(0x00ff00) },
    uTexture: { value: someTexture },
  },
  vertexShader: `
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    uniform float uTime;
    uniform vec3 uColor;
    varying vec2 vUv;
    void main() {
      gl_FragColor = vec4(uColor * vUv.x, 1.0);
    }
  `,
  transparent: false,
  wireframe: false,
  side: THREE.FrontSide,
});

Properties

Property Type Default Description
uniforms Object {} { name: { value: ... } } format
uniformsGroups Array [] Uniform buffer objects (UBO)
vertexShader string -- GLSL vertex shader source
fragmentShader string -- GLSL fragment shader source
defines Object {} Preprocessor #define directives
extensions Object {} GLSL extensions to enable
wireframe boolean false Wireframe rendering
lights boolean false Pass light uniforms to shader
fog boolean false Pass fog uniforms to shader
clipping boolean false Enable clipping planes
glslVersion string | null null null for GLSL1, THREE.GLSL3 for GLSL 3.0 ES
defaultAttributeValues Object -- Fallback values for missing attributes

Built-in Uniforms (ShaderMaterial Only)

These are injected automatically. NEVER declare them yourself.

// Transform matrices
uniform mat4 modelMatrix;           // Object -> World
uniform mat4 modelViewMatrix;       // Object -> Camera
uniform mat4 projectionMatrix;      // Camera -> Clip
uniform mat4 viewMatrix;            // World -> Camera
uniform mat3 normalMatrix;          // Transpose inverse of modelViewMatrix

// Camera
uniform vec3 cameraPosition;        // Camera world position

// When lights: true
uniform vec3 ambientLightColor;
// Plus structured arrays for directional, point, spot, hemisphere lights

Built-in Attributes (ShaderMaterial Only)

These are injected automatically. NEVER declare them yourself.

attribute vec3 position;    // Vertex position
attribute vec3 normal;      // Vertex normal
attribute vec2 uv;          // Primary UV coordinates
attribute vec2 uv2;         // Secondary UV (for aoMap, lightMap)
attribute vec4 tangent;     // Tangent vector (if computeTangents was called)
attribute vec3 color;       // Vertex color (if geometry has color attribute)

RawShaderMaterial

Use when you need full control over the shader source. NOTHING is injected.

const material = new THREE.RawShaderMaterial({
  uniforms: {
    uModelViewMatrix: { value: new THREE.Matrix4() },
    uProjectionMatrix: { value: new THREE.Matrix4() },
  },
  vertexShader: `
    precision highp float;
    attribute vec3 position;
    uniform mat4 uModelViewMatrix;
    uniform mat4 uProjectionMatrix;
    void main() {
      gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    precision highp float;
    void main() {
      gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }
  `,
});

ALWAYS add precision highp float; (or mediump) at the top of both shaders in RawShaderMaterial. Omitting precision causes a GLSL compilation error on mobile and some desktop drivers.


ShaderChunk -- Reusing Three.js Shader Code

THREE.ShaderChunk contains all internal shader fragments. Use #include <chunk_name> in ShaderMaterial (NOT RawShaderMaterial).

Common Chunks

Chunk Purpose
<common> Shared constants and functions (PI, saturate, etc.)
<fog_pars_vertex> / <fog_vertex> Fog support (vertex)
<fog_pars_fragment> / <fog_fragment> Fog support (fragment)
<shadowmap_pars_vertex> / <shadowmap_vertex> Shadow support (vertex)
<shadowmap_pars_fragment> / <shadowmap_fragment> Shadow support (fragment)
<lights_pars_begin> Light structure declarations
<begin_vertex> Initializes transformed variable from position
<project_vertex> Applies modelViewMatrix and projectionMatrix
<normal_fragment_begin> Normal mapping setup
<color_pars_vertex> / <color_vertex> Vertex color support

Accessing Chunks Programmatically

// Read the source of any chunk
console.log(THREE.ShaderChunk.common);
console.log(THREE.ShaderChunk.fog_pars_vertex);

onBeforeCompile -- Patching Built-in Materials

Modify an existing material's shader at compile time. This preserves PBR lighting, shadows, and all built-in features.

const material = new THREE.MeshStandardMaterial({ color: 0xff0000 });

material.onBeforeCompile = (shader) => {
  shader.uniforms.uTime = { value: 0.0 };

  shader.vertexShader = shader.vertexShader.replace(
    '#include <begin_vertex>',
    `
    #include <begin_vertex>
    transformed.y += sin(transformed.x * 5.0 + uTime) * 0.5;
    `
  );

  // Store reference for uniform updates
  material.userData.shader = shader;
};

// ALWAYS override customProgramCacheKey when using onBeforeCompile
material.customProgramCacheKey = () => 'my-wavy-material';

// In animation loop
if (material.userData.shader) {
  material.userData.shader.uniforms.uTime.value = clock.getElapsedTime();
}

ALWAYS override customProgramCacheKey() when using onBeforeCompile -- without it, Three.js may reuse a cached unpatched shader program, causing your modifications to silently disappear.

ALWAYS check material.userData.shader exists before accessing uniforms -- the shader object is created lazily on first render and can be recreated when material.needsUpdate = true.


Defines -- Preprocessor Directives

const material = new THREE.ShaderMaterial({
  defines: {
    USE_FOG: '',           // #define USE_FOG
    MAX_LIGHTS: 4,         // #define MAX_LIGHTS 4
    EPSILON: '0.001',      // #define EPSILON 0.001
  },
  // ...shaders
});

Changing defines at runtime:

material.defines.MAX_LIGHTS = 8;
material.needsUpdate = true;  // REQUIRED -- triggers recompilation

GLSL3 Mode

const material = new THREE.ShaderMaterial({
  glslVersion: THREE.GLSL3,
  vertexShader: `
    in vec3 position;           // 'attribute' becomes 'in'
    uniform mat4 modelViewMatrix;
    uniform mat4 projectionMatrix;
    out vec3 vPosition;         // 'varying' becomes 'out'

    void main() {
      vPosition = position;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    precision highp float;
    in vec3 vPosition;          // 'varying' becomes 'in'
    out vec4 fragColor;         // replaces gl_FragColor

    void main() {
      fragColor = vec4(vPosition * 0.5 + 0.5, 1.0);
    }
  `,
});

GLSL1 vs GLSL3 Syntax

GLSL1 GLSL3 Context
attribute in Vertex shader inputs
varying (vertex) out Vertex shader outputs
varying (fragment) in Fragment shader inputs
gl_FragColor Declared out vec4 Fragment shader output
texture2D() texture() Texture sampling
textureCube() texture() Cube texture sampling

Uniform Update Pattern

// At creation
const material = new THREE.ShaderMaterial({
  uniforms: {
    uTime: { value: 0.0 },
    uResolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
    uMouse: { value: new THREE.Vector2() },
  },
  vertexShader: '...',
  fragmentShader: '...',
});

// In animation loop -- update the .value property directly
function animate() {
  material.uniforms.uTime.value = performance.now() / 1000;
  material.uniforms.uMouse.value.set(mouseX, mouseY);
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

NEVER replace the uniform object itself (e.g., material.uniforms.uTime = { value: 5 }). ALWAYS mutate the existing .value property. Replacing the object breaks the internal reference.


Reference Links

Official Sources

Related skills
Installs
8
GitHub Stars
1
First Seen
Apr 1, 2026