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

web-integration.mddocs/

Web Integration

Web-specific components for HTML overlays, browser integration, and user interface elements. These components bridge the gap between 3D scenes and traditional HTML/DOM elements.

Capabilities

Html

HTML overlay integration with 3D positioning, occlusion, and transform options.

/**
 * HTML overlay integration with 3D positioning
 * @param props - HTML overlay configuration
 * @returns JSX element for HTML content in 3D space
 */
function Html(props: HtmlProps): JSX.Element;

interface HtmlProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'ref'> {
  /** Prepend content to existing, false */
  prepend?: boolean;
  /** Center content horizontally and vertically, false */
  center?: boolean;
  /** Use CSS 3D transforms, false */
  transform?: boolean;
  /** Render as CSS 2D sprite, false */
  sprite?: boolean;
  /** Portal HTML into custom container */
  portal?: HTMLElement;
  /** Distance factor for sprites, 10 */
  distanceFactor?: number;
  /** Occlusion objects or settings */
  occlude?: React.RefObject<Object3D>[] | boolean | 'raycast' | 'blending';
  /** Occlusion blending amount, 0 */
  occlusionOpacity?: number;
  /** Z-index for HTML, 0 */
  zIndexRange?: [number, number];
  /** Calculate position function */
  calculatePosition?: CalculatePosition;
  /** As container div, false */
  as?: string;
  /** Wrapper class */
  wrapperClass?: string;
  /** Pointer events, 'auto' */
  pointerEvents?: 'auto' | 'none';
  /** Full screen, false */
  fullscreen?: boolean;
  /** Epsilon for depth testing, 0 */
  eps?: number;
}

type CalculatePosition = (
  obj: Object3D,
  camera: Camera,
  size: { width: number; height: number }
) => [number, number];

Usage Examples:

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

// Basic HTML overlay
<mesh position={[0, 0, 0]}>
  <sphereGeometry />
  <meshStandardMaterial />
  <Html position={[0, 1, 0]} center>
    <div style={{ background: 'white', padding: '10px', borderRadius: '5px' }}>
      <h1>3D Label</h1>
      <p>This HTML content follows the 3D object</p>
    </div>
  </Html>
</mesh>

// HTML with occlusion
<Html
  position={[0, 0, 0]}
  occlude={[meshRef, meshRef2]}
  center
  transform
>
  <div className="tooltip">
    This content is occluded by 3D objects
  </div>
</Html>

// Sprite-style HTML
<Html
  position={[5, 2, 0]}
  sprite
  distanceFactor={15}
  center
>
  <div className="ui-element">
    <button onClick={() => console.log('Clicked!')}>
      3D Button
    </button>
  </div>
</Html>

ScrollControls

Scroll-based camera controls with virtual scrolling and smooth interpolation.

/**
 * Scroll-based camera controls with virtual scrolling
 * @param props - Scroll controls configuration
 * @returns JSX element for scroll controls
 */
function ScrollControls(props: ScrollControlsProps): JSX.Element;

/**
 * Scroll component for accessing scroll state
 * @param props - Scroll component props
 * @returns JSX element with scroll context
 */
function Scroll(props: ScrollProps): JSX.Element;

interface ScrollControlsProps extends Omit<ThreeElements['group'], 'ref'> {
  /** Virtual scroll area height, 1 */
  pages?: number;
  /** Scroll distance factor, 1 */
  distance?: number;
  /** Smooth scrolling damping, 4 */
  damping?: number;
  /** Horizontal scrolling, false */
  horizontal?: boolean;
  /** Infinite scrolling, false */
  infinite?: boolean;
  /** Enable zoom, true */
  enabled?: boolean;
  /** Style overrides for scroll area */
  style?: React.CSSProperties;
  /** Inner scroll area style */
  innerStyle?: React.CSSProperties;
}

interface ScrollProps {
  /** HTML scroll content, false */
  html?: boolean;
}

interface ScrollControlsState {
  /** Current scroll offset [0-1] */
  offset: number;
  /** Current scroll delta */
  delta: number;
  /** Scroll progress [0-1] */
  progress: number;
  /** Scroll range [start, end] */
  range(from: number, to: number): number;
  /** Curve interpolation */
  curve(from: number, to: number, margin?: number): number;
  /** Visible range check */
  visible(from: number, to: number, margin?: number): boolean;
}

Usage Examples:

import { ScrollControls, Scroll, useScroll } from '@react-three/drei';

// Basic scroll controls
<ScrollControls pages={3} damping={4}>
  <Scroll>
    {/* 3D content that responds to scroll */}
    <AnimatedMesh />
  </Scroll>
  <Scroll html>
    {/* HTML content overlay */}
    <div style={{ position: 'absolute', top: '100vh' }}>
      <h1>Page 2</h1>
    </div>
    <div style={{ position: 'absolute', top: '200vh' }}>
      <h1>Page 3</h1>
    </div>
  </Scroll>
</ScrollControls>

// Animated content based on scroll
function AnimatedMesh() {
  const scroll = useScroll();
  const meshRef = useRef();
  
  useFrame(() => {
    if (meshRef.current) {
      meshRef.current.rotation.y = scroll.offset * Math.PI * 2;
      meshRef.current.position.y = scroll.curve(0, 1, 0.1) * 5;
    }
  });
  
  return (
    <mesh ref={meshRef}>
      <boxGeometry />
      <meshStandardMaterial />
    </mesh>
  );
}

Loader

Loading UI component with progress indicators and customizable styling.

/**
 * Loading UI component with progress indicators
 * @param props - Loader configuration
 * @returns JSX element for loading UI
 */
function Loader(props: LoaderProps): JSX.Element;

interface LoaderProps {
  /** Container class name */
  containerClassName?: string;
  /** Inner class name */
  innerClassName?: string;
  /** Bar class name */
  barClassName?: string;
  /** Data class name */
  dataClassName?: string;
  /** Data interpolation function */
  dataInterpolation?: (p: number) => string;
  /** Initial text, 'Loading...' */
  initialText?: string;
}

Usage Examples:

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

// Basic loader
function App() {
  return (
    <>
      <Canvas>
        <Suspense fallback={null}>
          <Scene />
        </Suspense>
      </Canvas>
      <Loader />
    </>
  );
}

// Custom loader
<Loader
  containerClassName="my-loader"
  barClassName="my-progress-bar"
  dataInterpolation={(p) => `Loading ${(p * 100).toFixed(0)}%`}
  initialText="Preparing 3D Scene..."
/>

useCursor

Hook for changing cursor styles based on hover state.

/**
 * Hook for changing cursor styles based on hover state
 * @param hovered - Whether element is hovered
 * @param cursor - Cursor style to apply, 'pointer'
 */
function useCursor(hovered: boolean, cursor?: string): void;

Usage Examples:

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

function InteractiveMesh() {
  const [hovered, setHovered] = useState(false);
  useCursor(hovered, 'pointer');
  
  return (
    <mesh
      onPointerEnter={() => setHovered(true)}
      onPointerLeave={() => setHovered(false)}
      onClick={() => console.log('Clicked!')}
    >
      <boxGeometry />
      <meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
    </mesh>
  );
}

// Custom cursor styles
function CustomInteractive() {
  const [hovered, setHovered] = useState(false);
  useCursor(hovered, 'grab');
  
  return (
    <mesh
      onPointerEnter={() => setHovered(true)}
      onPointerLeave={() => setHovered(false)}
    >
      <sphereGeometry />
      <meshStandardMaterial />
    </mesh>
  );
}

KeyboardControls

Keyboard input mapping and state management for 3D interactions.

/**
 * Keyboard input mapping and state management
 * @param props - Keyboard controls configuration
 * @returns JSX element for keyboard controls context
 */
function KeyboardControls<T = string>(props: KeyboardControlsProps<T>): JSX.Element;

/**
 * Hook for accessing keyboard control state
 * @returns Keyboard controls API
 */
function useKeyboardControls(): KeyboardControlsApi;

interface KeyboardControlsProps<T = string> {
  /** Key mapping configuration */
  map: KeyboardControlsEntry<T>[];
  /** Child components */
  children: React.ReactNode;
  /** DOM element to attach listeners, document */
  domElement?: HTMLElement;
}

interface KeyboardControlsEntry<T = string> {
  /** Control name */
  name: T;
  /** Key codes */
  keys: string[];
}

interface KeyboardControlsApi {
  /** Get current key state */
  forward: boolean;
  backward: boolean;
  left: boolean;
  right: boolean;
  jump: boolean;
  [key: string]: boolean;
}

Usage Examples:

import { KeyboardControls, useKeyboardControls } from '@react-three/drei';

// Keyboard controls setup
const map = [
  { name: 'forward', keys: ['ArrowUp', 'KeyW'] },
  { name: 'backward', keys: ['ArrowDown', 'KeyS'] },
  { name: 'left', keys: ['ArrowLeft', 'KeyA'] },
  { name: 'right', keys: ['ArrowRight', 'KeyD'] },
  { name: 'jump', keys: ['Space'] },
];

function App() {
  return (
    <KeyboardControls map={map}>
      <Canvas>
        <Player />
      </Canvas>
    </KeyboardControls>
  );
}

// Using keyboard input
function Player() {
  const { forward, backward, left, right, jump } = useKeyboardControls();
  const playerRef = useRef();
  
  useFrame((state, delta) => {
    if (playerRef.current) {
      const speed = 5;
      if (forward) playerRef.current.position.z -= speed * delta;
      if (backward) playerRef.current.position.z += speed * delta;
      if (left) playerRef.current.position.x -= speed * delta;
      if (right) playerRef.current.position.x += speed * delta;
      if (jump) playerRef.current.position.y += speed * delta;
    }
  });
  
  return (
    <mesh ref={playerRef}>
      <boxGeometry />
      <meshStandardMaterial />
    </mesh>
  );
}

PresentationControls

Presentation-style controls optimized for showcasing 3D models and products.

/**
 * Presentation-style controls for showcasing 3D content
 * @param props - Presentation controls configuration
 * @returns JSX element for presentation controls
 */
function PresentationControls(props: PresentationControlProps): JSX.Element;

interface PresentationControlProps extends Omit<ThreeElements['group'], 'ref'> {
  /** Enable controls, true */
  enabled?: boolean;
  /** Global rotation constraint, true */
  global?: boolean;
  /** Cursor grab, true */
  cursor?: boolean;
  /** Snap to positions */
  snap?: boolean | { mass: number; tension: number };
  /** Rotation speed, 1 */
  speed?: number;
  /** Zoom settings */
  zoom?: { min: number; max: number };
  /** Polar angle limits [min, max] */
  polar?: [number, number];
  /** Azimuth angle limits [min, max] */
  azimuth?: [number, number];
  /** Config for spring animation */
  config?: { mass: number; tension: number; friction: number };
}

Usage Examples:

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

// Basic presentation controls
<PresentationControls enabled global>
  <mesh>
    <torusGeometry />
    <meshNormalMaterial />
  </mesh>
</PresentationControls>

// Constrained presentation
<PresentationControls
  enabled
  global
  cursor
  snap={{ mass: 4, tension: 1500 }}
  rotation={[0, 0, 0]}
  polar={[-Math.PI / 3, Math.PI / 3]}
  azimuth={[-Math.PI / 1.4, Math.PI / 2]}
>
  <Model />
</PresentationControls>

Select

Object selection system with multi-select support and event handling.

/**
 * Object selection system with multi-select support
 * @param props - Select configuration
 * @returns JSX element for selection context
 */
function Select(props: SelectProps): JSX.Element;

interface SelectProps {
  /** Multiple selection, false */
  multiple?: boolean;
  /** Selection box styling */
  box?: boolean;
  /** Child components */
  children: React.ReactNode;
  /** Selection change handler */
  onChange?: (selected: Object3D[]) => void;
  /** Filter function for selectable objects */
  filter?: (objects: Object3D[]) => Object3D[];
}

Integration Patterns

HTML and 3D Interaction

function Interactive3DHTML() {
  const [selected, setSelected] = useState(null);
  
  return (
    <>
      <mesh onClick={() => setSelected('sphere')}>
        <sphereGeometry />
        <meshStandardMaterial color={selected === 'sphere' ? 'red' : 'blue'} />
        <Html position={[0, 1.5, 0]} center occlude>
          <div className="label">
            <h3>Interactive Sphere</h3>
            <button onClick={() => setSelected(null)}>Reset</button>
          </div>
        </Html>
      </mesh>
    </>
  );
}

Scroll-Driven Animation

function ScrollDrivenScene() {
  return (
    <ScrollControls pages={4} damping={0.1}>
      <Scroll>
        <ScrollAnimatedContent />
      </Scroll>
      <Scroll html>
        <div className="scroll-content">
          {/* HTML content synchronized with 3D */}
        </div>
      </Scroll>
    </ScrollControls>
  );
}

function ScrollAnimatedContent() {
  const data = useScroll();
  const meshRef = useRef();
  
  useFrame(() => {
    if (meshRef.current && data) {
      // Animate based on scroll position
      meshRef.current.rotation.y = data.offset * Math.PI * 2;
      meshRef.current.scale.setScalar(1 + data.range(0, 1/4) * 2);
    }
  });
  
  return (
    <mesh ref={meshRef}>
      <boxGeometry />
      <meshNormalMaterial />
    </mesh>
  );
}

Loading States

function App() {
  return (
    <>
      <Canvas>
        <Suspense fallback={<LoadingFallback />}>
          <Scene />
        </Suspense>
      </Canvas>
      <Loader />
    </>
  );
}

function LoadingFallback() {
  return (
    <Html center>
      <div className="loading-3d">
        <div className="spinner"></div>
        <p>Loading 3D assets...</p>
      </div>
    </Html>
  );
}

CycleRaycast

Component for keyboard-based cycling through raycasted objects.

/**
 * Provides keyboard-based cycling through raycasted objects
 * @param props - CycleRaycast configuration props
 * @returns JSX element for raycasting controls
 */
function CycleRaycast(props: CycleRaycastProps): JSX.Element;

interface CycleRaycastProps {
  /** Callback when selection changes */
  onChanged?: (hits: THREE.Intersection[], cycle: number) => null;
  /** Prevent default key behavior, true */
  preventDefault?: boolean;
  /** Enable scroll cycling, true */
  scroll?: boolean;
  /** Key code for cycling, 9 (Tab) */
  keyCode?: number;
  /** Portal element reference */
  portal?: React.RefObject<HTMLElement>;
}

View

Component for creating multiple viewports within a single canvas.

/**
 * Creates multiple viewports within a single canvas
 * @param props - View configuration props
 * @returns JSX element for viewport rendering
 */
function View(props: ViewProps): JSX.Element;

interface ViewProps {
  /** Viewport index */
  index?: number;
  /** Child components */
  children?: React.ReactNode;
  /** Viewport tracking element */
  track?: React.RefObject<HTMLElement>;
}

PresentationControls

Touch and mouse controls for object presentation and interaction.

/**
 * Touch and mouse controls for object presentation
 * @param props - PresentationControls configuration props
 * @returns JSX element for presentation controls
 */
function PresentationControls(props: PresentationControlProps): JSX.Element;

interface PresentationControlProps {
  /** Snap behavior, false */
  snap?: boolean | number;
  /** Global controls, false */
  global?: boolean;
  /** Show cursor, true */
  cursor?: boolean;
  /** Control speed, 1 */
  speed?: number;
  /** Zoom factor, 1 */
  zoom?: number;
  /** Rotation limits */
  rotation?: [number, number, number];
  /** Polar angle limits */
  polar?: [number, number];
  /** Azimuth angle limits */
  azimuth?: [number, number];
  /** Damping factor, 0.05 */
  damping?: number;
  /** Enable controls, true */
  enabled?: boolean;
  /** Child components */
  children?: React.ReactNode;
  /** DOM element for events */
  domElement?: HTMLElement;
}

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