Claude Code Plugins

Community-maintained marketplace

Feedback

Three.js materials in R3F, built-in materials (Standard, Physical, Basic, etc.), ShaderMaterial with custom GLSL, uniforms binding and animation, and material properties. Use when choosing materials, creating custom shaders, or binding dynamic uniforms.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name r3f-materials
description Three.js materials in R3F, built-in materials (Standard, Physical, Basic, etc.), ShaderMaterial with custom GLSL, uniforms binding and animation, and material properties. Use when choosing materials, creating custom shaders, or binding dynamic uniforms.

R3F Materials

Materials define surface appearance—color, texture, reflectivity, transparency, and custom shader effects.

Quick Start

// Built-in material
<mesh>
  <boxGeometry />
  <meshStandardMaterial color="hotpink" metalness={0.8} roughness={0.2} />
</mesh>

// Custom shader
<mesh>
  <planeGeometry />
  <shaderMaterial
    uniforms={{ uTime: { value: 0 } }}
    vertexShader={vertexShader}
    fragmentShader={fragmentShader}
  />
</mesh>

Built-in Materials

Material Comparison

Material Lighting Use Case Performance
MeshBasicMaterial None UI, unlit, debug Fastest
MeshStandardMaterial PBR General 3D Good
MeshPhysicalMaterial PBR+ Glass, car paint Slower
MeshLambertMaterial Diffuse Matte surfaces Fast
MeshPhongMaterial Specular Shiny plastic Fast
MeshToonMaterial Cel-shaded Stylized Good
MeshNormalMaterial None Debug normals Fastest
MeshDepthMaterial None Depth passes Fastest

MeshBasicMaterial (Unlit)

<meshBasicMaterial
  color="#ff0000"           // Base color
  map={texture}             // Color texture
  transparent={true}        // Enable transparency
  opacity={0.5}             // Transparency level
  alphaMap={alphaTexture}   // Transparency texture
  side={THREE.DoubleSide}   // Render both sides
  wireframe={true}          // Wireframe mode
  fog={false}               // Ignore scene fog
/>

MeshStandardMaterial (PBR)

<meshStandardMaterial
  // Base
  color="#ffffff"
  map={colorTexture}
  
  // PBR properties
  metalness={0.5}           // 0 = dielectric, 1 = metal
  metalnessMap={metalMap}
  roughness={0.5}           // 0 = mirror, 1 = diffuse
  roughnessMap={roughMap}
  
  // Normal mapping
  normalMap={normalTexture}
  normalScale={[1, 1]}
  
  // Ambient occlusion
  aoMap={aoTexture}
  aoMapIntensity={1}
  
  // Displacement
  displacementMap={dispMap}
  displacementScale={0.1}
  
  // Emission
  emissive="#000000"
  emissiveMap={emissiveTexture}
  emissiveIntensity={1}
  
  // Environment
  envMap={cubeTexture}
  envMapIntensity={1}
/>

MeshPhysicalMaterial (Advanced PBR)

<meshPhysicalMaterial
  // Inherits all MeshStandardMaterial props, plus:
  
  // Clearcoat (car paint, lacquer)
  clearcoat={1}
  clearcoatRoughness={0.1}
  clearcoatNormalMap={ccNormal}
  
  // Transmission (glass, water)
  transmission={0.9}        // 0 = opaque, 1 = fully transmissive
  thickness={0.5}           // Volume thickness
  ior={1.5}                 // Index of refraction
  
  // Sheen (fabric, velvet)
  sheen={1}
  sheenRoughness={0.5}
  sheenColor="#ff00ff"
  
  // Iridescence (soap bubbles, oil slicks)
  iridescence={1}
  iridescenceIOR={1.3}
  iridescenceThicknessRange={[100, 400]}
/>

MeshToonMaterial (Cel-shaded)

<meshToonMaterial
  color="#6fa8dc"
  gradientMap={gradientTexture}  // 3-5 color ramp texture
/>

// Create gradient texture
const gradientTexture = useMemo(() => {
  const canvas = document.createElement('canvas');
  canvas.width = 4;
  canvas.height = 1;
  const ctx = canvas.getContext('2d')!;
  
  // 4-step toon shading
  ctx.fillStyle = '#444'; ctx.fillRect(0, 0, 1, 1);
  ctx.fillStyle = '#888'; ctx.fillRect(1, 0, 1, 1);
  ctx.fillStyle = '#bbb'; ctx.fillRect(2, 0, 1, 1);
  ctx.fillStyle = '#fff'; ctx.fillRect(3, 0, 1, 1);
  
  const texture = new THREE.CanvasTexture(canvas);
  texture.minFilter = THREE.NearestFilter;
  texture.magFilter = THREE.NearestFilter;
  
  return texture;
}, []);

Common Properties (All Materials)

<meshStandardMaterial
  // Rendering
  transparent={false}
  opacity={1}
  alphaTest={0}           // Discard pixels below threshold
  alphaToCoverage={false} // MSAA alpha
  
  // Faces
  side={THREE.FrontSide}  // FrontSide | BackSide | DoubleSide
  
  // Depth
  depthTest={true}
  depthWrite={true}
  
  // Stencil
  stencilWrite={false}
  stencilFunc={THREE.AlwaysStencilFunc}
  
  // Blending
  blending={THREE.NormalBlending}
  
  // Other
  visible={true}
  fog={true}
  toneMapped={true}
/>

Textures

Loading Textures

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

function TexturedMesh() {
  const [colorMap, normalMap, roughnessMap] = useTexture([
    '/textures/color.jpg',
    '/textures/normal.jpg',
    '/textures/roughness.jpg'
  ]);
  
  return (
    <mesh>
      <boxGeometry />
      <meshStandardMaterial 
        map={colorMap}
        normalMap={normalMap}
        roughnessMap={roughnessMap}
      />
    </mesh>
  );
}

Texture Settings

import { useTexture } from '@react-three/drei';
import * as THREE from 'three';

const texture = useTexture('/texture.jpg', (tex) => {
  tex.wrapS = tex.wrapT = THREE.RepeatWrapping;
  tex.repeat.set(4, 4);
  tex.anisotropy = 16;  // Sharper at angles
});

ShaderMaterial

Full control via GLSL vertex and fragment shaders:

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

const vertexShader = `
  varying vec2 vUv;
  varying vec3 vNormal;
  
  void main() {
    vUv = uv;
    vNormal = normalize(normalMatrix * normal);
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  }
`;

const fragmentShader = `
  uniform float uTime;
  uniform vec3 uColor;
  varying vec2 vUv;
  varying vec3 vNormal;
  
  void main() {
    float pulse = sin(uTime * 2.0) * 0.5 + 0.5;
    vec3 color = mix(uColor, vec3(1.0), pulse * 0.3);
    
    // Simple rim lighting
    float rim = 1.0 - dot(vNormal, vec3(0.0, 0.0, 1.0));
    color += rim * 0.5;
    
    gl_FragColor = vec4(color, 1.0);
  }
`;

function CustomShaderMesh() {
  const materialRef = useRef<THREE.ShaderMaterial>(null!);
  
  useFrame(({ clock }) => {
    materialRef.current.uniforms.uTime.value = clock.elapsedTime;
  });
  
  return (
    <mesh>
      <sphereGeometry args={[1, 32, 32]} />
      <shaderMaterial
        ref={materialRef}
        vertexShader={vertexShader}
        fragmentShader={fragmentShader}
        uniforms={{
          uTime: { value: 0 },
          uColor: { value: new THREE.Color('#ff6b6b') }
        }}
      />
    </mesh>
  );
}

Uniforms

Uniform Types

uniforms={{
  // Scalars
  uFloat: { value: 1.0 },
  uInt: { value: 1 },
  uBool: { value: true },
  
  // Vectors
  uVec2: { value: new THREE.Vector2(1, 2) },
  uVec3: { value: new THREE.Vector3(1, 2, 3) },
  uVec4: { value: new THREE.Vector4(1, 2, 3, 4) },
  uColor: { value: new THREE.Color('#ff0000') },
  
  // Matrices
  uMat3: { value: new THREE.Matrix3() },
  uMat4: { value: new THREE.Matrix4() },
  
  // Textures
  uTexture: { value: texture },
  uCubeTexture: { value: cubeTexture },
  
  // Arrays
  uFloatArray: { value: [1.0, 2.0, 3.0] },
  uVec3Array: { value: [new THREE.Vector3(), new THREE.Vector3()] }
}}

Animating Uniforms

function AnimatedShader() {
  const materialRef = useRef<THREE.ShaderMaterial>(null!);
  
  useFrame(({ clock, mouse }) => {
    const uniforms = materialRef.current.uniforms;
    
    uniforms.uTime.value = clock.elapsedTime;
    uniforms.uMouse.value.set(mouse.x, mouse.y);
    uniforms.uResolution.value.set(window.innerWidth, window.innerHeight);
  });
  
  return (
    <shaderMaterial
      ref={materialRef}
      uniforms={{
        uTime: { value: 0 },
        uMouse: { value: new THREE.Vector2() },
        uResolution: { value: new THREE.Vector2() }
      }}
      // ...
    />
  );
}

Shared Uniforms

// Create shared uniform object
const globalUniforms = useMemo(() => ({
  uTime: { value: 0 },
  uGlobalColor: { value: new THREE.Color('#00ff00') }
}), []);

// Update in useFrame
useFrame(({ clock }) => {
  globalUniforms.uTime.value = clock.elapsedTime;
});

// Use in multiple materials
<mesh>
  <boxGeometry />
  <shaderMaterial uniforms={{ ...globalUniforms, uLocalProp: { value: 1 } }} />
</mesh>

<mesh position={[2, 0, 0]}>
  <sphereGeometry />
  <shaderMaterial uniforms={{ ...globalUniforms, uLocalProp: { value: 2 } }} />
</mesh>

RawShaderMaterial

No built-in uniforms/attributes—full control:

<rawShaderMaterial
  vertexShader={`
    precision highp float;
    
    // Must declare all inputs manually
    attribute vec3 position;
    attribute vec2 uv;
    
    uniform mat4 projectionMatrix;
    uniform mat4 modelViewMatrix;
    
    varying vec2 vUv;
    
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `}
  fragmentShader={`
    precision highp float;
    
    varying vec2 vUv;
    
    void main() {
      gl_FragColor = vec4(vUv, 0.0, 1.0);
    }
  `}
/>

Material Extensions

Extend Existing Materials

import { extend } from '@react-three/fiber';
import { shaderMaterial } from '@react-three/drei';

// Create extended material
const GradientMaterial = shaderMaterial(
  // Uniforms
  { uColorA: new THREE.Color('#ff0000'), uColorB: new THREE.Color('#0000ff') },
  // Vertex
  `
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  // Fragment
  `
    uniform vec3 uColorA;
    uniform vec3 uColorB;
    varying vec2 vUv;
    void main() {
      gl_FragColor = vec4(mix(uColorA, uColorB, vUv.y), 1.0);
    }
  `
);

// Register with R3F
extend({ GradientMaterial });

// Use in JSX
function Gradient() {
  return (
    <mesh>
      <planeGeometry args={[2, 2]} />
      <gradientMaterial uColorA="#ff0000" uColorB="#0000ff" />
    </mesh>
  );
}

Performance Tips

Technique When to Use
Share materials Multiple meshes, same appearance
Use cheaper materials Distant objects (Basic vs Standard)
Limit texture size Mobile, large scene
Disable unneeded features fog={false}, toneMapped={false}

Material Reuse

// Define once
const sharedMaterial = useMemo(() => (
  <meshStandardMaterial color="red" roughness={0.5} />
), []);

// Reuse (same GPU program)
{items.map((item, i) => (
  <mesh key={i} position={item.pos}>
    <boxGeometry />
    {sharedMaterial}
  </mesh>
))}

File Structure

r3f-materials/
├── SKILL.md
├── references/
│   ├── pbr-properties.md     # PBR material deep-dive
│   ├── uniform-types.md      # Complete uniform reference
│   └── shader-templates.md   # Common shader patterns
└── scripts/
    ├── materials/
    │   ├── gradient.ts       # Gradient shader material
    │   ├── fresnel.ts        # Fresnel/rim effect
    │   └── dissolve.ts       # Dissolve effect
    └── utils/
        └── uniform-helpers.ts # Uniform animation utilities

Reference

  • references/pbr-properties.md — Deep-dive into PBR material properties
  • references/uniform-types.md — All uniform types and GLSL mappings
  • references/shader-templates.md — Common shader effect patterns