NYC
skills/smithery/ai/r3f-shaders

r3f-shaders

SKILL.md

React Three Fiber Shaders

shaderMaterial (Drei)

import { shaderMaterial } from '@react-three/drei'
import { extend, useFrame } from '@react-three/fiber'
import * as THREE from 'three'

const WaveMaterial = shaderMaterial(
  // Uniforms
  { time: 0, color: new THREE.Color('hotpink') },
  // Vertex shader
  `uniform float time;
   varying vec2 vUv;
   void main() {
     vUv = uv;
     vec3 pos = position;
     pos.z += sin(pos.x * 10.0 + time) * 0.1;
     gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
   }`,
  // Fragment shader
  `uniform vec3 color;
   varying vec2 vUv;
   void main() {
     gl_FragColor = vec4(color * vUv.y, 1.0);
   }`
)

extend({ WaveMaterial })

function WaveMesh() {
  const ref = useRef()
  useFrame(({ clock }) => {
    ref.current.time = clock.elapsedTime
  })
  return (
    <mesh>
      <planeGeometry args={[5, 5, 32, 32]} />
      <waveMaterial ref={ref} key={WaveMaterial.key} />
    </mesh>
  )
}

Raw ShaderMaterial

function CustomShader() {
  const ref = useRef()

  useFrame(({ clock }) => {
    ref.current.uniforms.time.value = clock.elapsedTime
  })

  return (
    <mesh>
      <boxGeometry />
      <shaderMaterial
        ref={ref}
        uniforms={{
          time: { value: 0 },
          color: { value: new THREE.Color('cyan') },
        }}
        vertexShader={`
          varying vec2 vUv;
          void main() {
            vUv = uv;
            gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
          }
        `}
        fragmentShader={`
          uniform float time;
          uniform vec3 color;
          varying vec2 vUv;
          void main() {
            float strength = sin(vUv.x * 10.0 + time) * 0.5 + 0.5;
            gl_FragColor = vec4(color * strength, 1.0);
          }
        `}
      />
    </mesh>
  )
}

Common Patterns

Fresnel

vec3 viewDir = normalize(cameraPosition - vWorldPosition);
float fresnel = pow(1.0 - dot(viewDir, vNormal), 3.0);

Noise

float random(vec2 st) {
  return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453);
}

Gradient

vec3 color = mix(colorA, colorB, vUv.y);

Dissolve

float noise = texture2D(noiseMap, vUv).r;
if (noise < progress) discard;

Extending Built-in Materials

const material = new THREE.MeshStandardMaterial({ color: 'green' })

material.onBeforeCompile = (shader) => {
  shader.uniforms.time = { value: 0 }
  material.userData.shader = shader

  shader.vertexShader = 'uniform float time;\n' + shader.vertexShader
  shader.vertexShader = shader.vertexShader.replace(
    '#include <begin_vertex>',
    `#include <begin_vertex>
     transformed.y += sin(position.x * 10.0 + time) * 0.1;`
  )
}

// Update in useFrame
if (material.userData.shader) {
  material.userData.shader.uniforms.time.value = clock.elapsedTime
}

TypeScript

declare global {
  namespace JSX {
    interface IntrinsicElements {
      waveMaterial: ReactThreeFiber.MaterialNode<
        THREE.ShaderMaterial & { time: number; color: THREE.Color },
        typeof WaveMaterial
      >
    }
  }
}

Performance Tips

  • Use mix/step instead of conditionals
  • Precalculate values in JS when possible
  • Use textures for complex functions
  • Minimize texture lookups
Weekly Installs
1
Repository
smithery/ai
First Seen
Feb 5, 2026
Installed on
claude-code1