Related lab bench

Start from a visible ShaderMaterial

Use the shader starter when you want a small baseline that proves uniforms, UVs, and animation time are flowing.

Open Shader Starter Check before publishing

The point of a starter shader

ShaderMaterial is powerful because you control the vertex and fragment programs directly. That power also makes it easy to lose an hour to a black screen. A starter shader should prove that the geometry renders, uniforms update, UVs exist, and animation time is flowing. Only after those facts are visible should you add texture sampling, procedural patterns, or lighting math.

The best starter is not visually impressive. It is intentionally obvious. Use UV coordinates to create a gradient, mix in a color uniform, and animate a narrow band with uTime. If the band moves, JavaScript is updating the uniform. If the gradient appears, varyings are flowing from vertex to fragment. That gives you a stable base for more ambitious work.

Treat uniforms as a contract

A uniform is the small API between JavaScript and GLSL. Name it clearly and update it in one place. `uTime`, `uColor`, `uScale`, and `uResolution` are easier to reason about than a dozen anonymous values. When a shader becomes part of a tool, this contract lets sliders and presets change the shader without rewriting GLSL.

Avoid starting with too many uniforms. Three or four are enough for a reusable starter. Add values when the visual problem requires them. A shader page that teaches the contract is often more valuable than one that dumps a giant code block with no explanation.

Know what Three.js gives you

ShaderMaterial still runs inside the Three.js rendering pipeline. Built-in attributes such as position, normal, and uv are available when the geometry provides them. Projection and model-view matrices are also available. That means a beginner can start from a normal mesh and material swap rather than writing raw WebGL setup code.

The edge case is geometry without UV coordinates. A box, plane, or sphere from Three.js has usable UVs. Some imported models may not. If your shader depends on UVs, show a fallback color or document that the material expects UVs. This kind of plain warning saves future debugging.

Debug in layers

When the output is black, remove complexity. First set the fragment color to solid red. Then display `vUv.x` and `vUv.y` as colors. Then add the uniform color. Then add time. This layered method is boring, but it quickly tells you whether the problem is geometry, varyings, uniforms, or the final formula.

For a public guide, include the debugging sequence, not just the final shader. People do not search for ShaderMaterial because everything is already working; they search because the material is invisible, static, or different from an example.

When this guide is the right tool

Use this guide when the problem is specific enough that a broad Three.js tutorial would waste time. The focus here is ShaderMaterial in a real browser page: what to check first, what to measure, and what to avoid before the scene becomes harder to reason about.

The practical rule is simple: Keep the first shader visibly simple: UV color, a time wave, and one color uniform. If that sentence describes the scene in front of you, treat the article as a checklist. Read the explanation, copy the smallest useful code pattern, then test the result in a narrow mobile viewport and a wide desktop viewport before adding more polish.

Common mistake to avoid

The common mistake is treating A practical ShaderMaterial starter for Three.js as a visual tweak instead of a scene-system decision. Three.js problems often look like one broken line of code, but the actual issue is usually a chain: asset assumptions, renderer settings, camera math, material setup, interaction state, and page layout all meet inside the canvas.

That is why the safest fix is incremental. Start from a known-good scene, change one variable, and keep a visible diagnostic while testing. Name uniforms like an API because the JavaScript side will depend on them. When the scene works, remove temporary helpers and leave behind only the checks that make sense for users.

Publishing check

Before publishing, run the scene through three questions. Does the page remain useful if WebGL fails or the asset loads slowly? Does the same scene still read clearly on a phone? Can another developer understand the important settings without reverse-engineering the whole file?

The last pass should be boring on purpose: verify canvas size, console errors, mobile performance, source links, internal links, and the related guide path. Debug with known colors before adding noise, lighting, or texture sampling. If any answer is fuzzy, fix that before introducing a new effect or a larger asset.

Visible animated shader

const material = new THREE.ShaderMaterial({
  uniforms: {
    uTime: { value: 0 },
    uColor: { value: new THREE.Color('#65d8c2') }
  },
  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() {
      float band = 0.5 + 0.5 * sin((vUv.x + uTime * 0.2) * 12.0);
      vec3 color = mix(vec3(vUv, 0.35), uColor, band);
      gl_FragColor = vec4(color, 1.0);
    }
  `
});

FAQ

When should I use A practical ShaderMaterial starter for Three.js?

Use it when your Three.js scene has a focused ShaderMaterial problem and you need a practical checklist before adding more visual polish.

Is the code snippet production-ready?

Treat the snippet as a clear starting point. Test it in your scene, adapt naming and paths, and verify behavior on mobile hardware before publishing.

What should I check after applying this guide?

Run the scene through mobile sizing, console errors, loading states, source links, and related guide paths so the page remains useful even when assets or WebGL fail.

Sources and further reading

Related guides