CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-three--drei

Useful add-ons for react-three-fiber providing 100+ components for 3D web applications

Pending
Overview
Eval results
Files

hooks.mddocs/

Hooks

React hooks for animations, state management, and Three.js integration. These hooks provide seamless integration between React patterns and Three.js functionality, enabling declarative 3D programming.

Capabilities

useAnimations

Animation control hook for managing GLTF animations with play, pause, and crossfading capabilities.

/**
 * Animation control hook for GLTF animations
 * @param clips - Animation clips from GLTF loader
 * @param root - Target object for animations
 * @returns Animation API with controls and state
 */
function useAnimations<T extends AnimationClip>(
  clips: T[],
  root?: React.RefObject<Object3D>
): Api<T>;

interface Api<T extends AnimationClip> {
  /** Reference to the animated object */
  ref: React.RefObject<Object3D | undefined | null>;
  /** Animation clips array */
  clips: AnimationClip[];
  /** Three.js animation mixer */
  mixer: AnimationMixer;
  /** Animation clip names */
  names: T['name'][];
  /** Animation actions mapped by name */
  actions: { [key in T['name']]: AnimationAction | null };
}

Usage Examples:

import { useAnimations, useGLTF } from '@react-three/drei';

function AnimatedModel() {
  const group = useRef();
  const { nodes, materials, animations } = useGLTF('/model.glb');
  const { actions, names } = useAnimations(animations, group);
  
  // Play animation on mount
  useEffect(() => {
    actions['Walk']?.play();
  }, [actions]);
  
  // Control animations
  const switchAnimation = (name) => {
    // Crossfade between animations
    actions[name]?.reset().fadeIn(0.5).play();
    Object.keys(actions).forEach((key) => {
      if (key !== name) {
        actions[key]?.fadeOut(0.5);
      }
    });
  };
  
  return (
    <group ref={group}>
      <primitive object={nodes.Scene} />
      {/* Animation controls */}
      <Html>
        {names.map((name) => (
          <button key={name} onClick={() => switchAnimation(name)}>
            {name}
          </button>
        ))}
      </Html>
    </group>
  );
}

useGLTF

GLTF model loading hook with automatic disposal and type safety.

/**
 * GLTF model loading hook with automatic disposal
 * @param path - Path to GLTF file
 * @param useDraco - Use Draco compression, true
 * @param useMeshOpt - Use MeshOpt compression, true
 * @returns GLTF object with nodes, materials, and animations
 */
function useGLTF(path: string, useDraco?: boolean, useMeshOpt?: boolean): GLTF & ObjectMap;

interface GLTF {
  animations: AnimationClip[];
  scene: Group;
  scenes: Group[];
  cameras: Camera[];
  asset: object;
}

interface ObjectMap {
  nodes: { [name: string]: Object3D };
  materials: { [name: string]: Material };
}

Usage Examples:

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

function Model({ path }) {
  const { nodes, materials } = useGLTF(path);
  
  return (
    <group>
      <mesh 
        geometry={nodes.Mesh.geometry} 
        material={materials.Material} 
      />
    </group>
  );
}

// Preload models
useGLTF.preload('/model.glb');

useTexture

Texture loading hook with multiple format support and automatic disposal.

/**
 * Texture loading hook with format support
 * @param input - Texture path or array of paths
 * @returns Texture or array of textures
 */
function useTexture(input: string | string[]): Texture | Texture[];

Usage Examples:

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

function TexturedMesh() {
  const texture = useTexture('/texture.jpg');
  
  return (
    <mesh>
      <planeGeometry />
      <meshStandardMaterial map={texture} />
    </mesh>
  );
}

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

// Preload textures
useTexture.preload('/texture.jpg');

useFont

Font loading hook for text rendering with caching support.

/**
 * Font loading hook for text rendering
 * @param path - Path to font JSON file
 * @returns Font data object
 */
function useFont(path: string): FontData;

interface FontData {
  data: any;
  glyphs: { [key: string]: Glyph };
}

interface Glyph {
  x: number;
  y: number;  
  width: number;
  height: number;
  xAdvance?: number;
  xOffset?: number;
  yOffset?: number;
}

Usage Examples:

import { useFont, Text3D } from '@react-three/drei';

function StyledText() {
  const font = useFont('/fonts/helvetiker_regular.json');
  
  return (
    <Text3D font={font} size={1} height={0.2}>
      3D Text
      <meshNormalMaterial />
    </Text3D>
  );
}

// Preload fonts
useFont.preload('/fonts/helvetiker_regular.json');

useEnvironment

Environment texture loading hook with preset support and HDRI loading.

/**
 * Environment texture loading hook with presets
 * @param props - Environment loader configuration
 * @returns Environment texture
 */
function useEnvironment(props: EnvironmentLoaderProps): Texture;

interface EnvironmentLoaderProps {
  /** Environment preset name */
  preset?: PresetsType;
  /** Custom environment files */
  files?: string | string[];
  /** Environment path */
  path?: string;
  /** Texture encoding */
  encoding?: TextureEncoding;
}

Usage Examples:

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

function ReflectiveSphere() {
  const envMap = useEnvironment({ preset: 'sunset' });
  
  return (
    <mesh>
      <sphereGeometry />
      <meshStandardMaterial 
        envMap={envMap}
        metalness={1}
        roughness={0}
      />
    </mesh>
  );
}

// Custom HDRI environment
function CustomEnvironment() {
  const envMap = useEnvironment({ 
    files: '/hdri/studio.hdr',
    encoding: RGBEEncoding
  });
  
  return (
    <mesh>
      <torusGeometry />
      <meshStandardMaterial envMap={envMap} />
    </mesh>
  );
}

useAspect

Aspect ratio calculation hook for responsive design and viewport adaptation.

/**
 * Aspect ratio calculation hook for responsive design
 * @param width - Target width
 * @param height - Target height  
 * @param factor - Scale factor, 1
 * @returns Scaled dimensions [width, height, 1]
 */
function useAspect(width: number, height: number, factor?: number): [number, number, number];

Usage Examples:

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

function ResponsivePlane() {
  const scale = useAspect(1920, 1080, 0.5);
  
  return (
    <mesh scale={scale}>
      <planeGeometry />
      <meshBasicMaterial />
    </mesh>
  );
}

// Dynamic aspect ratio
function DynamicAspect() {
  const { viewport } = useThree();
  const scale = useAspect(viewport.width, viewport.height, 0.8);
  
  return (
    <mesh scale={scale}>
      <planeGeometry />
      <meshBasicMaterial />
    </mesh>
  );
}

useCamera

Camera access hook for getting the current scene camera.

/**
 * Camera access hook for getting current camera
 * @returns Current camera object
 */
function useCamera(): Camera;

Usage Examples:

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

function CameraInfo() {
  const camera = useCamera();
  
  useFrame(() => {
    console.log('Camera position:', camera.position);
    console.log('Camera rotation:', camera.rotation);
  });
  
  return null;
}

useIntersect

Intersection detection hook for visibility and hover effects.

/**
 * Intersection detection hook for visibility effects
 * @param onChange - Callback when visibility changes
 * @returns Ref to attach to target object
 */
function useIntersect<T extends Object3D>(
  onChange: (visible: boolean) => void
): React.RefObject<T>;

Usage Examples:

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

function VisibilityDetector() {
  const [visible, setVisible] = useState(false);
  const ref = useIntersect((isVisible) => setVisible(isVisible));
  
  return (
    <mesh ref={ref}>
      <boxGeometry />
      <meshStandardMaterial 
        color={visible ? 'green' : 'red'} 
        emissive={visible ? 'darkgreen' : 'darkred'}
      />
    </mesh>
  );
}

useDepthBuffer

Depth buffer hook for accessing scene depth information.

/**
 * Depth buffer hook for accessing depth information
 * @param options - Depth buffer configuration
 * @returns Depth buffer texture and controls
 */
function useDepthBuffer(options?: {
  size?: number;
  frames?: number;
}): {
  buffer: WebGLRenderTarget;
  camera: Camera;
}

useContextBridge

Context bridging hook for sharing React context across R3F boundaries.

/**
 * Context bridging hook for sharing React context
 * @param contexts - Array of React contexts to bridge
 * @returns Bridge component
 */
function useContextBridge(...contexts: React.Context<any>[]): React.ComponentType<{ children: React.ReactNode }>;

Usage Examples:

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

const ThemeContext = React.createContext();
const UserContext = React.createContext();

function Scene() {
  const ContextBridge = useContextBridge(ThemeContext, UserContext);
  
  return (
    <ContextBridge>
      <mesh>
        <ThemedMaterial />
      </mesh>
    </ContextBridge>
  );
}

useBoxProjectedEnv

Box-projected environment mapping hook for realistic interior reflections.

/**
 * Box-projected environment mapping hook
 * @param envMap - Environment map texture
 * @param position - Box position
 * @param size - Box size
 * @returns Box-projected environment uniforms
 */
function useBoxProjectedEnv(
  envMap: Texture,
  position: [number, number, number],
  size: [number, number, number]
): {
  envMap: Texture;
  cubeMapSize: Vector3;
  cubeMapPos: Vector3;
};

Integration Patterns

Animation Sequencing

function AnimationSequence() {
  const group = useRef();
  const { actions } = useAnimations(animations, group);
  const [currentAnimation, setCurrentAnimation] = useState('idle');
  
  const playSequence = async () => {
    await playAnimation('walk', 2000);
    await playAnimation('run', 3000);
    await playAnimation('idle', 1000);
  };
  
  const playAnimation = (name, duration) => {
    return new Promise((resolve) => {
      actions[name]?.reset().play();
      setTimeout(resolve, duration);
    });
  };
  
  return (
    <group ref={group}>
      <primitive object={scene} />
    </group>
  );
}

Responsive Textures

function ResponsiveTexture() {
  const { viewport } = useThree();
  const isMobile = viewport.width < 768;
  
  const texture = useTexture(
    isMobile ? '/textures/low-res.jpg' : '/textures/high-res.jpg'
  );
  
  return (
    <mesh>
      <planeGeometry />
      <meshStandardMaterial map={texture} />
    </mesh>
  );
}

Dynamic Environment Loading

function DynamicEnvironment() {
  const [preset, setPreset] = useState('sunset');
  const envMap = useEnvironment({ preset });
  
  useEffect(() => {
    const handleTimeChange = () => {
      const hour = new Date().getHours();
      if (hour < 6) setPreset('night');
      else if (hour < 12) setPreset('dawn');
      else if (hour < 18) setPreset('city');
      else setPreset('sunset');
    };
    
    handleTimeChange();
    const interval = setInterval(handleTimeChange, 60000);
    return () => clearInterval(interval);
  }, []);
  
  return (
    <mesh>
      <sphereGeometry />
      <meshStandardMaterial envMap={envMap} />
    </mesh>
  );
}

Performance Optimization

// Preload assets for better performance
const preloadAssets = () => {
  useGLTF.preload('/models/character.glb');
  useTexture.preload(['/textures/diffuse.jpg', '/textures/normal.jpg']);
  useFont.preload('/fonts/roboto.json');
};

// Call during app initialization
useEffect(preloadAssets, []);

// Automatic cleanup
function Model({ url }) {
  const gltf = useGLTF(url);
  
  // Automatic disposal on unmount
  useEffect(() => {
    return () => gltf.dispose?.();
  }, [gltf]);
  
  return <primitive object={gltf.scene} />;
}

useDepthBuffer

Hook for creating and managing depth buffer textures.

/**
 * Creates and manages depth buffer textures for depth-based effects
 * @param config - Depth buffer configuration
 * @returns Depth texture
 */
function useDepthBuffer(config?: DepthBufferConfig): DepthTexture;

interface DepthBufferConfig {
  /** Buffer size, 256 */
  size?: number;
  /** Update frames, Infinity */
  frames?: number;
}

useContextBridge

Hook for bridging React contexts across portals and different render trees.

/**
 * Bridges React contexts across portals and render trees
 * @param contexts - React contexts to bridge
 * @returns Context bridge component
 */
function useContextBridge(...contexts: Array<React.Context<any>>): React.ComponentType<{children: React.ReactNode}>;

useBoxProjectedEnv

Hook for box-projected environment mapping on materials.

/**
 * Applies box-projected environment mapping to materials
 * @param envMap - Environment map texture
 * @param config - Box projection configuration
 * @returns Box projection utilities
 */
function useBoxProjectedEnv(
  envMap: Texture,
  config: BoxProjectedEnvConfig
): BoxProjectedEnvResult;

interface BoxProjectedEnvConfig {
  /** Environment map size */
  envMapSize: [number, number, number];
  /** Environment map position */
  envMapPosition: [number, number, number];
}

interface BoxProjectedEnvResult {
  /** Apply to material */
  apply: (material: Material) => void;
}

Install with Tessl CLI

npx tessl i tessl/npm-react-three--drei

docs

abstractions.md

cameras.md

controls.md

gizmos.md

hooks.md

index.md

loaders.md

materials.md

performance.md

staging.md

web-integration.md

tile.json