Documentation

Props & Reactivity

Every shader component accepts props that control its appearance and behavior. These props are fully reactive—change a value in your component state, and the shader updates instantly.

Basic Props

Props work exactly like standard component props. Pass them directly to configure your shaders:

Static props like these are perfect for fixed effects. But the real power comes from reactive props.

Reactive Props

Bind props to your component's state, and the shader updates automatically when the state changes. This happens efficiently—prop changes update GPU uniforms directly without recompiling shaders.

Click the buttons, and the gradient rotates inside the circle instantly. No lag, no stutter—just smooth, real-time updates.

The angle updates immediately because props are reactive. Change any prop—color, position, intensity—and the GPU responds instantly.

Common Reactive Props

Different components accept different props. Here are patterns you'll use frequently:

Position and Size:

<Circle :radius="size" :center="{ x: posX, y: posY }" />

Colors:

<LinearGradient :colorA="startColor" :colorB="endColor" />

Intensity and Strength:

<Blur :intensity="blurAmount" />
<Glow :strength="glowPower" />

Angles and Rotation:

<LinearGradient :angle="rotation" />

Every numerical prop, color prop, and position prop can be reactive. Bind them to sliders, scroll position, mouse coordinates, or any other dynamic value.

Animating Props

Props aren't just for user interactions—they're perfect for animations too. Animation libraries like Motion make it easy to create smooth, choreographed transitions.

Note: Motion supports React and Vue, as well as plain JavaScript. You can use any animation library you like for Svelte/Solid.

import { useState } from 'react'
import { animate } from 'motion'
import { Shader, LinearGradient, Circle } from 'shaders/react'

function MyComponent() {
  const [radius, setRadius] = useState(0.6)

  async function pulse() {
    // Grow then shrink with smooth easing
    await animate(radius, 1, {
      duration: 0.5,
      easing: 'ease-out',
      onUpdate: (latest) => setRadius(latest)
    })
    await animate(1, 0.6, {
      duration: 0.5,
      easing: 'ease-in',
      onUpdate: (latest) => setRadius(latest)
    })
  }

  return (
    <>
      <button onClick={pulse}>Pulse</button>

      <Shader>
        <Circle id="mask" radius={radius} visible={false} />
        <LinearGradient maskSource="mask" />
      </Shader>
    </>
  )
}

Motion handles the tweening automatically, giving you smooth animations with minimal code. Because prop updates are efficient, you can animate multiple properties simultaneously without performance concerns.

Performance Notes

Reactive props update GPU uniforms directly. This means:

  • No shader recompilation: Changing a prop doesn't rebuild the shader
  • GPU-efficient: Updates happen on the graphics card, not the CPU
  • Frame-rate friendly: Animate as many props as you need

You can safely update props every frame, tie them to scroll position, or respond to mouse movement without worrying about performance.