Skip to main content
Paper Shaders animates by advancing an internal timer (currentFrame) each requestAnimationFrame tick and passing it to the shader as the u_time uniform (in seconds). Two props — speed and frame — give you full control over how time progresses.

speed

speed is a multiplier applied to the delta time on every frame. The default is 0 (paused at construction time); named shader components typically default to 1.
ValueEffect
1Normal forward playback
0.5Half speed
2Double speed
-1Reverse playback
0Stopped
When speed is 0, the requestAnimationFrame loop is cancelled entirely. A fully stopped shader has zero recurring CPU or GPU cost — it is as cheap as a static image.

frame

frame is an offset applied to the starting u_time value, in milliseconds. It does not affect playback speed; it shifts where in the animation the shader starts. Use frame whenever you need a deterministic result:
  • Server-side rendering (SSR) — set a fixed frame so the initial HTML matches the first client render.
  • Visual regression tests — snapshot a specific point in the animation.
  • Resuming a saved state — store getCurrentFrame() and restore it later.

Tab visibility

ShaderMount listens to the document visibilitychange event. When the tab is hidden, it resets the effective speed to 0 and cancels the animation loop. When the tab becomes visible again, it restores the original speed and resumes the loop. The currentFrame value does not advance while the tab is hidden, so animations resume from where they left off rather than jumping forward.

Methods

setSpeed(newSpeed)

Change speed at any time without recreating the shader.
mount.setSpeed(0);   // pause
mount.setSpeed(-1);  // reverse
mount.setSpeed(1);   // resume
Equivalent to updating the speed prop in React.

setFrame(newFrame)

Jump to an exact point in the animation (milliseconds from time zero) and trigger an immediate re-render.
mount.setFrame(5000); // jump to the 5-second mark

getCurrentFrame()

Returns the total number of animation milliseconds played so far, not counting time when the tab was hidden or speed was 0.
const snapshot = mount.getCurrentFrame();
// … later …
mount.setFrame(snapshot); // restore

Examples

import { useState } from 'react';
import { MeshGradient } from '@paper-design/shaders-react';

export function AnimatedShader() {
  const [speed, setSpeed] = useState(1);

  return (
    <>
      <MeshGradient
        style={{ width: '100%', height: 400 }}
        speed={speed}
      />
      <button onClick={() => setSpeed(s => s === 0 ? 1 : 0)}>
        {speed === 0 ? 'Resume' : 'Pause'}
      </button>
      <button onClick={() => setSpeed(-1)}>Reverse</button>
    </>
  );
}
// Deterministic starting frame for SSR / snapshots
<MeshGradient
  style={{ width: 800, height: 400 }}
  speed={1}
  frame={3000}  // start at the 3-second mark
/>

Build docs developers (and LLMs) love