Token导航 LogoToken导航TokenDH.com
前端设计权限需确认github未标认证来源可访问clear审计通过

r3f-shadersr3f 着色器

Agent Skill

用于辅助前端页面、组件、样式和交互逻辑的开发与维护。它适合让 Agent 生成或审查 React、Next.js、Vue、Tailwind、CSS 等相关代码,整理组件结构,或定位布局和性能问题。使用时需要结合项目现有设计系统、路由和构建方式,避免只生成孤立片段;涉及页面改动时,应配合本地预览和构建检查确认视觉效果。

总安装

10,608

周安装

451

GitHub Stars

79

下载量

3,716
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

3

许可证

MIT

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:r3f-shaders(r3f 着色器)
来源仓库:https://github.com/enzed/r3f-skills
仓库路径:skills/r3f-shaders
安装命令:
npx skills add https://github.com/enzed/r3f-skills --skill r3f-shaders
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/enzed/r3f-skills --skill r3f-shaders

简介

r3f-shaders 用于辅助前端页面、组件和交互逻辑的开发与维护,适合生成或审查 React 相关代码。

  • 适用于前端设计类任务,可帮助整理组件结构或定位布局问题。
  • 使用时需结合项目现有设计系统和构建方式,避免生成孤立片段。
  • 涉及页面改动时应配合本地预览和构建检查确认视觉效果。
  • 适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

SKILL.md

React Three Fiber Shaders

Quick Start

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

// Create custom shader material
const ColorShiftMaterial = shaderMaterial(
  // Uniforms
  { time: 0, color: new THREE.Color(0.2, 0.0, 0.1) },
  // Vertex shader
  `
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  // Fragment shader
  `
    uniform float time;
    uniform vec3 color;
    varying vec2 vUv;
    void main() {
      gl_FragColor = vec4(vUv.x + sin(time), vUv.y + cos(time), color.b, 1.0);
    }
  `
)

// Extend so it can be used as JSX
extend({ ColorShiftMaterial })

function ShaderMesh() {
  const materialRef = useRef()

  useFrame(({ clock }) => {
    materialRef.current.time = clock.elapsedTime
  })

  return (
    <mesh>
      <planeGeometry args={[2, 2]} />
      {/* key={Material.key} enables HMR for shader development */}
      <colorShiftMaterial ref={materialRef} key={ColorShiftMaterial.key} />
    </mesh>
  )
}

export default function App() {
  return (
    <Canvas>
      <ShaderMesh />
    </Canvas>
  )
}

shaderMaterial (Drei)

The recommended way to create shader materials in R3F.

Basic Pattern

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

// 1. Define the material
const MyShaderMaterial = shaderMaterial(
  // Uniforms object
  {
    time: 0,
    color: new THREE.Color(1, 0, 0),
    opacity: 1,
    map: null,
  },
  // Vertex shader (GLSL)
  `
    varying vec2 vUv;
    varying vec3 vPosition;

    void main() {
      vUv = uv;
      vPosition = position;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  // Fragment shader (GLSL)
  `
    uniform float time;
    uniform vec3 color;
    uniform float opacity;
    uniform sampler2D map;
    varying vec2 vUv;

    void main() {
      vec4 texColor = texture2D(map, vUv);
      gl_FragColor = vec4(color * texColor.rgb, opacity);
    }
  `
)

// 2. Extend R3F
extend({ MyShaderMaterial })

// 3. Use in component
function MyMesh() {
  const materialRef = useRef()

  useFrame(({ clock }) => {
    materialRef.current.time = clock.elapsedTime
  })

  return (
    <mesh>
      <boxGeometry />
      {/* key prop enables Hot Module Replacement during development */}
      <myShaderMaterial
        ref={materialRef}
        key={MyShaderMaterial.key}
        color="hotpink"
        transparent
        opacity={0.8}
      />
    </mesh>
  )
}

Hot Module Replacement (HMR)

The key prop on shaderMaterial enables live shader editing without page refresh:

const MyMaterial = shaderMaterial(
  { time: 0 },
  vertexShader,
  fragmentShader
)

extend({ MyMaterial })

// MyMaterial.key changes when shader code changes
<myMaterial key={MyMaterial.key} />

When you edit shader code, the material automatically updates. Without key, you'd need to refresh the page to see changes.

TypeScript Support

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

// Define uniform types
type WaveMaterialUniforms = {
  time: number
  amplitude: number
  color: THREE.Color
}

const WaveMaterial = shaderMaterial(
  {
    time: 0,
    amplitude: 0.5,
    color: new THREE.Color('hotpink'),
  } as WaveMaterialUniforms,
  // vertex shader
  `...`,
  // fragment shader
  `...`
)

// Extend with proper types
extend({ WaveMaterial })

// Declare for TypeScript
declare module '@react-three/fiber' {
  interface ThreeElements {
    waveMaterial: Object3DNode<
      typeof WaveMaterial & THREE.ShaderMaterial,
      typeof WaveMaterial
    >
  }
}

Raw THREE.ShaderMaterial

For full control without Drei helper.

import { useFrame } from '@react-three/fiber'
import { useMemo, useRef } from 'react'
import * as THREE from 'three'

function CustomShaderMesh() {
  const materialRef = useRef()

  const shaderMaterial = useMemo(() => {
    return new THREE.ShaderMaterial({
      uniforms: {
        time: { value: 0 },
        color: { value: new THREE.Color('cyan') },
        resolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
      },
      vertexShader: `
        varying vec2 vUv;
        void main() {
          vUv = uv;
          gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
        }
      `,
      fragmentShader: `
        uniform float time;
        uniform vec3 color;
        uniform vec2 resolution;
        varying vec2 vUv;

        void main() {
          vec2 st = gl_FragCoord.xy / resolution;
          float pattern = sin(st.x * 20.0 + time) * sin(st.y * 20.0 + time);
          gl_FragColor = vec4(color * pattern, 1.0);
        }
      `,
      side: THREE.DoubleSide,
      transparent: true,
    })
  }, [])

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

  return (
    <mesh material={shaderMaterial}>
      <planeGeometry args={[4, 4, 32, 32]} />
    </mesh>
  )
}

Uniforms

Common Uniform Types

const MyMaterial = shaderMaterial(
  {
    // Numbers
    time: 0,
    intensity: 1.5,

    // Vectors
    resolution: new THREE.Vector2(1920, 1080),
    lightPosition: new THREE.Vector3(5, 10, 5),
    bounds: new THREE.Vector4(0, 0, 1, 1),

    // Color (becomes vec3)
    color: new THREE.Color('#ff0000'),

    // Matrices
    customMatrix: new THREE.Matrix4(),

    // Textures
    map: null,        // sampler2D
    cubeMap: null,    // samplerCube

    // Arrays
    positions: [new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()],
  },
  vertexShader,
  fragmentShader
)

GLSL Declarations

// In shader code
uniform float time;
uniform float intensity;
uniform vec2 resolution;
uniform vec3 lightPosition;
uniform vec3 color;  // THREE.Color becomes vec3
uniform vec4 bounds;
uniform mat4 customMatrix;
uniform sampler2D map;
uniform samplerCube cubeMap;
uniform vec3 positions[3];

Updating Uniforms

function AnimatedShader() {
  const materialRef = useRef()

  useFrame(({ clock, mouse, viewport }) => {
    // Direct value update
    materialRef.current.time = clock.elapsedTime

    // Vector update
    materialRef.current.resolution.set(viewport.width, viewport.height)

    // Color update
    materialRef.current.color.setHSL((clock.elapsedTime * 0.1) % 1, 1, 0.5)

    // Or via uniforms object (for THREE.ShaderMaterial)
    // materialRef.current.uniforms.time.value = clock.elapsedTime
  })

  return (
    <mesh>
      <boxGeometry />
      <myShaderMaterial ref={materialRef} />
    </mesh>
  )
}

Varyings

Pass data from vertex to fragment shader.

// Vertex shader
varying vec2 vUv;
varying vec3 vNormal;
varying vec3 vPosition;
varying vec3 vWorldPosition;

void main() {
  vUv = uv;
  vNormal = normalize(normalMatrix * normal);
  vPosition = position;
  vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;

  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

// Fragment shader
varying vec2 vUv;
varying vec3 vNormal;
varying vec3 vPosition;
varying vec3 vWorldPosition;

void main() {
  // Use interpolated values
  gl_FragColor = vec4(vNormal * 0.5 + 0.5, 1.0);
}

Common Shader Patterns

Texture Sampling

import { useTexture } from '@react-three/drei'

function TexturedShaderMesh() {
  const texture = useTexture('/textures/color.jpg')
  const materialRef = useRef()

  return (
    <mesh>
      <planeGeometry args={[2, 2]} />
      <myShaderMaterial ref={materialRef} map={texture} />
    </mesh>
  )
}

// Shader
const TextureMaterial = shaderMaterial(
  { map: null },
  `
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  `
    uniform sampler2D map;
    varying vec2 vUv;

    void main() {
      vec4 texColor = texture2D(map, vUv);
      gl_FragColor = texColor;
    }
  `
)

Vertex Displacement

const WaveMaterial = shaderMaterial(
  { time: 0, amplitude: 0.5, frequency: 2.0 },
  `
    uniform float time;
    uniform float amplitude;
    uniform float frequency;
    varying vec2 vUv;

    void main() {
      vUv = uv;
      vec3 pos = position;

      // Wave displacement
      pos.z += sin(pos.x * frequency + time) * amplitude;
      pos.z += sin(pos.y * frequency + time) * amplitude;

      gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
    }
  `,
  `
    varying vec2 vUv;
    void main() {
      gl_FragColor = vec4(vUv, 1.0, 1.0);
    }
  `
)

extend({ WaveMaterial })

function WavePlane() {
  const ref = useRef()

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

  return (
    <mesh rotation={[-Math.PI / 2, 0, 0]}>
      <planeGeometry args={[10, 10, 64, 64]} />
      <waveMaterial ref={ref} />
    </mesh>
  )
}

Fresnel Effect

const FresnelMaterial = shaderMaterial(
  { fresnelColor: new THREE.Color('cyan'), baseColor: new THREE.Color('navy') },
  `
    varying vec3 vNormal;
    varying vec3 vWorldPosition;

    void main() {
      vNormal = normalize(normalMatrix * normal);
      vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  `
    uniform vec3 fresnelColor;
    uniform vec3 baseColor;
    varying vec3 vNormal;
    varying vec3 vWorldPosition;

    void main() {
      vec3 viewDirection = normalize(cameraPosition - vWorldPosition);
      float fresnel = pow(1.0 - dot(viewDirection, vNormal), 3.0);

      gl_FragColor = vec4(mix(baseColor, fresnelColor, fresnel), 1.0);
    }
  `
)

Noise Functions

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

// Value noise
float noise(vec2 st) {
  vec2 i = floor(st);
  vec2 f = fract(st);

  float a = random(i);
  float b = random(i + vec2(1.0, 0.0));
  float c = random(i + vec2(0.0, 1.0));
  float d = random(i + vec2(1.0, 1.0));

  vec2 u = f * f * (3.0 - 2.0 * f);

  return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}

// FBM (Fractal Brownian Motion)
float fbm(vec2 st) {
  float value = 0.0;
  float amplitude = 0.5;

  for (int i = 0; i < 5; i++) {
    value += amplitude * noise(st);
    st *= 2.0;
    amplitude *= 0.5;
  }

  return value;
}

Gradient

// Linear gradient
vec3 gradient = mix(colorA, colorB, vUv.y);

// Radial gradient
float dist = distance(vUv, vec2(0.5));
vec3 radial = mix(centerColor, edgeColor, dist * 2.0);

// Smooth gradient
float t = smoothstep(0.0, 1.0, vUv.y);
vec3 smooth = mix(colorA, colorB, t);

Dissolve Effect

const DissolveMaterial = shaderMaterial(
  { progress: 0, noiseScale: 10.0, edgeColor: new THREE.Color('orange') },
  `
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  `
    uniform float progress;
    uniform float noiseScale;
    uniform vec3 edgeColor;
    varying vec2 vUv;

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

    float noise(vec2 st) {
      vec2 i = floor(st);
      vec2 f = fract(st);
      float a = random(i);
      float b = random(i + vec2(1.0, 0.0));
      float c = random(i + vec2(0.0, 1.0));
      float d = random(i + vec2(1.0, 1.0));
      vec2 u = f * f * (3.0 - 2.0 * f);
      return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
    }

    void main() {
      float n = noise(vUv * noiseScale);

      if (n < progress) {
        discard;
      }

      float edge = smoothstep(progress, progress + 0.1, n);
      vec3 baseColor = vec3(0.5);

      gl_FragColor = vec4(mix(edgeColor, baseColor, edge), 1.0);
    }
  `
)

Extending Built-in Materials

onBeforeCompile

Modify existing material shaders.

import { useRef, useEffect } from 'react'
import { useFrame } from '@react-three/fiber'
import * as THREE from 'three'

function ModifiedStandardMaterial() {
  const materialRef = useRef()
  const shaderRef = useRef()

  useEffect(() => {
    if (materialRef.current) {
      materialRef.current.onBeforeCompile = (shader) => {
        // Add custom uniform
        shader.uniforms.time = { value: 0 }
        shaderRef.current = shader

        // Add uniform declaration
        shader.vertexShader = 'uniform float time;\n' + shader.vertexShader

        // Modify vertex shader
        shader.vertexShader = shader.vertexShader.replace(
          '#include <begin_vertex>',
          `
            #include <begin_vertex>
            transformed.y += sin(position.x * 10.0 + time) * 0.1;
          `
        )
      }
    }
  }, [])

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

  return (
    <mesh>
      <planeGeometry args={[5, 5, 32, 32]} />
      <meshStandardMaterial ref={materialRef} color="green" />
    </mesh>
  )
}

Common Injection Points

// Vertex shader chunks
'#include <begin_vertex>'       // After position is calculated
'#include <project_vertex>'     // After gl_Position
'#include <beginnormal_vertex>' // Normal calculation start

// Fragment shader chunks
'#include <color_fragment>'     // After diffuse color
'#include <output_fragment>'    // Final output
'#include <fog_fragment>'       // After fog applied

GLSL Built-in Functions

Math Functions

// Basic
abs(x), sign(x), floor(x), ceil(x), fract(x)
mod(x, y), min(x, y), max(x, y), clamp(x, min, max)
mix(a, b, t), step(edge, x), smoothstep(edge0, edge1, x)

// Trigonometry
sin(x), cos(x), tan(x)
asin(x), acos(x), atan(y, x), atan(x)

// Exponential
pow(x, y), exp(x), log(x), sqrt(x)

Vector Functions

length(v), distance(p0, p1), dot(x, y), cross(x, y)
normalize(v), reflect(I, N), refract(I, N, eta)

Instanced Shaders

import { useRef, useMemo } from 'react'
import { useFrame } from '@react-three/fiber'
import * as THREE from 'three'

function InstancedShaderMesh({ count = 1000 }) {
  const meshRef = useRef()

  // Create instance attributes
  const { offsets, colors } = useMemo(() => {
    const offsets = new Float32Array(count * 3)
    const colors = new Float32Array(count * 3)

    for (let i = 0; i < count; i++) {
      offsets[i * 3] = (Math.random() - 0.5) * 20
      offsets[i * 3 + 1] = (Math.random() - 0.5) * 20
      offsets[i * 3 + 2] = (Math.random() - 0.5) * 20

      colors[i * 3] = Math.random()
      colors[i * 3 + 1] = Math.random()
      colors[i * 3 + 2] = Math.random()
    }

    return { offsets, colors }
  }, [count])

  const shaderMaterial = useMemo(() => {
    return new THREE.ShaderMaterial({
      uniforms: {
        time: { value: 0 }
      },
      vertexShader: `
        attribute vec3 offset;
        attribute vec3 instanceColor;
        varying vec3 vColor;

        void main() {
          vColor = instanceColor;
          vec3 pos = position + offset;
          gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
        }
      `,
      fragmentShader: `
        varying vec3 vColor;

        void main() {
          gl_FragColor = vec4(vColor, 1.0);
        }
      `
    })
  }, [])

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

  return (
    <instancedMesh ref={meshRef} args={[null, null, count]} material={shaderMaterial}>
      <boxGeometry args={[0.5, 0.5, 0.5]}>
        <instancedBufferAttribute attach="attributes-offset" args={[offsets, 3]} />
        <instancedBufferAttribute attach="attributes-instanceColor" args={[colors, 3]} />
      </boxGeometry>
    </instancedMesh>
  )
}

External Shader Files

With Vite/Webpack

// shaders/vertex.glsl
varying vec2 vUv;
void main() {
  vUv = uv;
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

// shaders/fragment.glsl
uniform float time;
varying vec2 vUv;
void main() {
  gl_FragColor = vec4(vUv, sin(time), 1.0);
}

// Component.tsx
import vertexShader from './shaders/vertex.glsl?raw'
import fragmentShader from './shaders/fragment.glsl?raw'

const MyMaterial = shaderMaterial(
  { time: 0 },
  vertexShader,
  fragmentShader
)

Vite Config for GLSL

// vite.config.js
import glsl from 'vite-plugin-glsl'

export default {
  plugins: [glsl()]
}

Material Properties

<myShaderMaterial
  // Rendering
  transparent={true}
  opacity={1.0}
  side={THREE.DoubleSide}
  depthTest={true}
  depthWrite={true}

  // Blending
  blending={THREE.NormalBlending}
  // NormalBlending, AdditiveBlending, SubtractiveBlending, MultiplyBlending

  // Wireframe
  wireframe={false}

  // Custom uniforms
  time={0}
  color="hotpink"
/>

Debugging Shaders

function DebugShaderMesh() {
  const materialRef = useRef()

  useEffect(() => {
    // Log compiled shaders
    if (materialRef.current) {
      console.log('Vertex:', materialRef.current.vertexShader)
      console.log('Fragment:', materialRef.current.fragmentShader)
    }
  }, [])

  return (
    <mesh>
      <boxGeometry />
      {/* Debug with visual output */}
      <shaderMaterial
        ref={materialRef}
        fragmentShader={`
          varying vec2 vUv;
          void main() {
            // Debug UV
            gl_FragColor = vec4(vUv, 0.0, 1.0);

            // Debug normals (in vertex: vNormal = normal)
            // gl_FragColor = vec4(vNormal * 0.5 + 0.5, 1.0);
          }
        `}
        vertexShader={`
          varying vec2 vUv;
          void main() {
            vUv = uv;
            gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
          }
        `}
      />
    </mesh>
  )
}

Performance Tips

  1. Minimize uniforms: Group related values into vectors
  2. Avoid conditionals: Use mix/step instead of if/else
  3. Precalculate in JS: Move static calculations out of shaders
  4. Use textures for lookup: Complex functions as texture lookups
  5. Limit overdraw: Avoid unnecessary transparent objects
// Instead of:
if (value > 0.5) {
  color = colorA;
} else {
  color = colorB;
}

// Use:
color = mix(colorB, colorA, step(0.5, value));

See Also

  • r3f-materials - Built-in material types
  • r3f-postprocessing - Full-screen shader effects
  • r3f-textures - Texture sampling in shaders

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

04

需要参考平台分布和安装热度时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

补充不同宿主或平台的使用分布数据

能力 5

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Claude Code

28.03%
按下载量换算1,042

Cursor

22.2%
按下载量换算825

Codex

20.2%
按下载量换算751

Gemini CLI

12.1%
按下载量换算450

Antigravity

8.95%
按下载量换算333

OpenCode

3.58%
按下载量换算133

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

权限需确认

当前来源未能明确判断权限范围,默认进入异常复核队列。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。

来源信息

继续浏览同类 Skills