FLASHING
FRAGMENT SHADERS

Program a flashing, pulsing fragment shader on a 3D cube in the browser with Three.js — a single time uniform drives the whole animated glow.

Three.js flashing fragment shader effect on a 3D cube

LIVE DEMO

The pulsing, color-shifting cube behind this page is the live demo — a single fragment shader driven by a time uniform. Click and drag with the mouse to orbit. Scroll to keep reading — on mobile just swipe to scroll.

Introduction

A fragment shader is a tiny GLSL program that runs on the GPU once for every pixel of a surface. Because it runs per-pixel in parallel, it can produce smooth animated effects — glows, gradients, pulses — that would be far too slow to compute in JavaScript.

In this free tutorial you'll build a flashing effect: a cube whose color pulses over time. The trick is a single time uniform you increment every frame, fed into sin() and cos() inside the shader. Copy it, paste it, and it runs.

Frequently Asked Questions

What is a fragment shader in Three.js?

A fragment shader (also called a pixel shader) is a GLSL program that runs on the GPU for every pixel of a rendered object. It determines the final color of each pixel. In Three.js, you use it via ShaderMaterial with a fragmentShader string property.

How do I create a flashing effect with a fragment shader?

Pass a uniform float for time, updated each frame, then use sin(time) in the fragment shader to oscillate color or brightness. For example vec3 color = 0.5 + 0.5 * sin(time) makes the color pulse smoothly between dark and bright, creating a flashing effect.

What are uniforms in Three.js shaders?

Uniforms are variables passed from JavaScript to the shader that stay constant for all pixels in a single draw call. Common uniforms include time (for animation), resolution, mouse position, and colors. Update them each frame with material.uniforms.time.value += 0.05.

How do I use ShaderMaterial in Three.js?

Create a new THREE.ShaderMaterial with uniforms, a vertexShader, and a fragmentShader written in GLSL as template strings. Apply the material to any mesh geometry, then update the uniforms in your animation loop to animate the effect.

Is this Three.js shader tutorial free?

Yes. This is a completely free tutorial. The full source code is on the page, you can copy it, and the flashing shader cube behind this page is the live demo. No sign-in or membership is required.

How It Works

  1. 1Scene, camera, renderer. Standard Three.js setup with a transparent renderer pinned behind the page content.
  2. 2Add a time uniform. Create a ShaderMaterial with uniforms: { time: { value: 0 } }.
  3. 3Vertex shader. Pass the surface normal to the fragment shader as a varying and position the vertex.
  4. 4Fragment shader. Build a color from sin(time) / cos(time) so it pulses, then multiply by the normal for a shaded, glowing look.
  5. 5Animate. Each frame bump material.uniforms.time.value and spin the cube.
  6. 6Render. Draw inside requestAnimationFrame for a smooth 60fps flash.

The Full Code

Paste this into a file named index.html and open it in any modern browser.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Three.js Flashing Fragment Shader</title>
  <style> body { margin: 0; background: #000; } </style>
  <script type="importmap">
  {
    "imports": {
      "three": "https://cdn.jsdelivr.net/npm/three@0.160/build/three.module.js",
      "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160/examples/jsm/"
    }
  }
  </script>
</head>
<body>
<script type="module">
  import * as THREE from 'three';
  import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera(
    75, window.innerWidth / window.innerHeight, 0.1, 1000);
  camera.position.z = 2;

  const renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.setClearColor(0x000000);
  document.body.appendChild(renderer.domElement);

  new OrbitControls(camera, renderer.domElement);

  // --- Flashing shader material ---
  const material = new THREE.ShaderMaterial({
    uniforms: { time: { value: 0.0 } },
    vertexShader: `
      varying vec3 vNormal;
      void main() {
        vNormal = normal;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
    `,
    fragmentShader: `
      uniform float time;
      varying vec3 vNormal;
      void main() {
        // pulse each channel with sin/cos of time -> flashing effect
        vec3 color = vec3(
          0.5 + 0.5 * sin(time),
          0.5 + 0.5 * cos(time),
          0.5 + 0.5 * cos(time)
        );
        // abs(vNormal) keeps ALL six faces lit; raw normals go negative on the
        // -X/-Y/-Z faces and clamp to black (only some sides would show color)
        gl_FragColor = vec4(color * (0.35 + 0.65 * abs(vNormal)), 1.0);
      }
    `
  });

  const cube = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), material);
  scene.add(cube);

  // --- Animate ---
  function animate() {
    requestAnimationFrame(animate);
    material.uniforms.time.value += 0.05;   // drive the flash
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    renderer.render(scene, camera);
  }
  animate();

  window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
  });
</script>
</body>
</html>

What To Try Next

SEE 3D AND 2D BROWSER GAMES IN ACTION

More Tutorials