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

gizmos.mddocs/

Gizmos

Interactive tools and visual helpers for development and user interaction. These components provide intuitive interfaces for object manipulation, scene navigation, and visual debugging.

Capabilities

PivotControls

Interactive pivot controls for object transformation with visual feedback and constraint options.

/**
 * Interactive pivot controls for object transformation
 * @param props - Pivot controls configuration
 * @returns JSX element for pivot controls
 */
function PivotControls(props: PivotControlsProps): JSX.Element;

interface PivotControlsProps {
  /** Enable/disable controls, true */
  enabled?: boolean;
  /** Gizmo scale, 1 */
  scale?: number;
  /** Line width for control handles, 2.5 */
  lineWidth?: number;
  /** Fixed screen size (pixels), false */
  fixed?: boolean;
  /** Position offset from object */
  offset?: [number, number, number];
  /** Starting rotation */
  rotation?: [number, number, number];
  /** Transform matrix */
  matrix?: Matrix4;
  /** Anchor point for transformations */
  anchor?: [number, number, number];
  /** Display mode flags */
  displayValues?: boolean;
  /** Disable X axis, false */
  disableAxisX?: boolean;
  /** Disable Y axis, false */
  disableAxisY?: boolean;
  /** Disable Z axis, false */
  disableAxisZ?: boolean;
  /** Disable rotation, false */
  disableRotations?: boolean;
  /** Disable scaling, false */
  disableScaling?: boolean;
  /** Disable sliders, false */
  disableSliders?: boolean;
  /** Active axes color */
  activeAxes?: [boolean, boolean, boolean];
  /** Translation limits */
  translationLimits?: [[number, number], [number, number], [number, number]];
  /** Rotation limits */
  rotationLimits?: [[number, number], [number, number], [number, number]];
  /** Scale limits */
  scaleLimits?: [[number, number], [number, number], [number, number]];
  /** Drag start callback */
  onDragStart?: () => void;
  /** Drag callback */
  onDrag?: (local: Matrix4, deltaL: Matrix4, world: Matrix4, deltaW: Matrix4) => void;
  /** Drag end callback */
  onDragEnd?: () => void;
}

Usage Examples:

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

// Basic pivot controls
<PivotControls>
  <mesh>
    <boxGeometry />
    <meshStandardMaterial />
  </mesh>
</PivotControls>

// Advanced pivot controls with constraints
<PivotControls
  scale={100}
  lineWidth={3}
  fixed
  anchor={[0, 0, 0]}
  disableRotations
  translationLimits={[[-5, 5], [0, 10], [-5, 5]]}
  onDragStart={() => console.log('Drag started')}
  onDrag={(local, deltaL, world, deltaW) => {
    // Handle transformation
    console.log('Local matrix:', local);
    console.log('World matrix:', world);
  }}
  onDragEnd={() => console.log('Drag ended')}
>
  <mesh>
    <sphereGeometry />
    <meshStandardMaterial color="orange" />
  </mesh>
</PivotControls>

// Multiple constrained pivot controls
function ConstrainedObject() {
  const [position, setPosition] = useState([0, 0, 0]);
  
  return (
    <PivotControls
      anchor={[0, 0, 0]}
      disableAxisY
      onDrag={(local) => {
        const pos = new Vector3().setFromMatrixPosition(local);
        setPosition([pos.x, 0, pos.z]); // Constrain to ground plane
      }}
    >
      <mesh position={position}>
        <cylinderGeometry />
        <meshStandardMaterial />
      </mesh>
    </PivotControls>
  );
}

DragControls

Drag controls for intuitive object manipulation with 3D mouse interaction.

/**
 * Drag controls for object manipulation
 * @param props - Drag controls configuration
 * @returns JSX element for drag controls
 */
function DragControls(props: DragControlsProps): JSX.Element;

interface DragControlsProps {
  /** Child objects to make draggable */
  children: React.ReactNode;
  /** Axis constraints: 'x' | 'y' | 'z' | 'xy' | 'xz' | 'yz' */
  axisLock?: 'x' | 'y' | 'z' | 'xy' | 'xz' | 'yz';
  /** Auto transform objects, true */
  autoTransform?: boolean;
  /** Transform matrix */
  matrix?: Matrix4;
  /** Drag start callback */
  onDragStart?: (event: { object: Object3D; pointerId: number; point: Vector3 }) => void;
  /** Drag callback */
  onDrag?: (event: { object: Object3D; pointerId: number; point: Vector3; delta: Vector3 }) => void;
  /** Drag end callback */
  onDragEnd?: (event: { object: Object3D; pointerId: number }) => void;
  /** Hover start callback */
  onHoverStart?: (event: { object: Object3D }) => void;
  /** Hover end callback */
  onHoverEnd?: (event: { object: Object3D }) => void;
}

Usage Examples:

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

// Basic drag controls
<DragControls>
  <mesh>
    <boxGeometry />
    <meshStandardMaterial />
  </mesh>
  <mesh position={[2, 0, 0]}>
    <sphereGeometry />
    <meshStandardMaterial />
  </mesh>
</DragControls>

// Constrained dragging
<DragControls 
  axisLock="y"
  onDragStart={(e) => console.log('Dragging:', e.object.name)}
  onDrag={(e) => {
    // Custom drag behavior
    e.object.rotation.y += e.delta.x * 0.01;
  }}
>
  <mesh name="draggable-box">
    <boxGeometry />
    <meshStandardMaterial color="red" />
  </mesh>
</DragControls>

// Advanced drag system
function DraggableSystem() {
  const [draggedObject, setDraggedObject] = useState(null);
  
  return (
    <DragControls
      onDragStart={(e) => {
        setDraggedObject(e.object);
        e.object.material.emissive.setHex(0x444444);
      }}
      onDragEnd={(e) => {
        setDraggedObject(null);
        e.object.material.emissive.setHex(0x000000);
      }}
      onHoverStart={(e) => {
        document.body.style.cursor = 'grab';
      }}
      onHoverEnd={(e) => {
        document.body.style.cursor = 'auto';
      }}
    >
      {objects.map((obj, i) => (
        <DraggableObject key={i} {...obj} />
      ))}
    </DragControls>
  );
}

Grid

3D grid helper for spatial reference and scene organization.

/**
 * 3D grid helper for spatial reference
 * @param props - Grid configuration
 * @returns JSX element for grid display
 */
function Grid(props: GridProps): JSX.Element;

interface GridProps extends Omit<ThreeElements['gridHelper'], 'ref'> {
  /** Grid cell size, 1 */
  cellSize?: number;
  /** Grid section size, 10 */
  sectionSize?: number;
  /** Grid color, #999999 */
  cellColor?: ReactThreeFiber.Color;
  /** Section color, #555555 */
  sectionColor?: ReactThreeFiber.Color;
  /** Grid size, 100 */
  args?: [number, number];
  /** Infinite grid, false */
  infiniteGrid?: boolean;
  /** Fade distance, 100 */
  fadeDistance?: number;
  /** Fade strength, 1 */
  fadeStrength?: number;
  /** Follow camera, false */
  followCamera?: boolean;
  /** Side to render, DoubleSide */
  side?: Side;
}

type GridMaterialType = {
  cellSize: number;
  sectionSize: number;
  cellColor: Color;
  sectionColor: Color;
  fadeDistance: number;
  fadeStrength: number;
};

Usage Examples:

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

// Basic grid
<Grid args={[100, 100]} />

// Customized grid
<Grid
  cellSize={0.5}
  sectionSize={5}
  cellColor={'#ff0000'}
  sectionColor={'#0000ff'}
  args={[50, 50]}
  position={[0, -1, 0]}
/>

// Infinite grid that follows camera
<Grid
  infiniteGrid
  fadeDistance={50}
  fadeStrength={2}
  followCamera
  cellSize={1}
  sectionSize={10}
/>

GizmoHelper

Container for 3D gizmos with positioning and interaction management.

/**
 * Container for 3D gizmos with positioning
 * @param props - Gizmo helper configuration
 * @returns JSX element for gizmo container
 */
function GizmoHelper(props: GizmoHelperProps): JSX.Element;

interface GizmoHelperProps {
  /** Gizmo alignment, 'bottom-right' */
  alignment?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
  /** Gizmo margin, [80, 80] */
  margin?: [number, number];
  /** Render on top, false */
  onTop?: boolean;
  /** Auto update, false */
  onUpdate?: () => void;
  /** Render priority, 1 */
  renderPriority?: number;
  /** Child gizmos */
  children: React.ReactNode;
}

Usage Examples:

import { GizmoHelper, GizmoViewport } from '@react-three/drei';

// Basic gizmo helper
<GizmoHelper alignment="bottom-right" margin={[80, 80]}>
  <GizmoViewport 
    axisColors={['red', 'green', 'blue']}
    labelColor="black"
  />
</GizmoHelper>

GizmoViewport

3D viewport gizmo for camera orientation display and interaction.

/**
 * 3D viewport gizmo for camera orientation
 * @param props - Gizmo viewport configuration
 * @returns JSX element for viewport gizmo
 */
function GizmoViewport(props: GizmoViewportProps): JSX.Element;

interface GizmoViewportProps {
  /** Axis colors [x, y, z], ['red', 'green', 'blue'] */
  axisColors?: [string, string, string];
  /** Axis head scale, 1 */
  axisHeadScale?: number;
  /** Label color, 'black' */
  labelColor?: string;
  /** Axis scale, [0.8, 0.05, 0.8] */
  axisScale?: [number, number, number];
  /** Labels ['X', 'Y', 'Z'] */
  labels?: [string, string, string];
  /** Font size, 16 */
  fontSize?: number;
  /** Font family, 'Inter' */
  font?: string;
}

GizmoViewcube

3D viewcube gizmo for camera navigation and preset views.

/**
 * 3D viewcube gizmo for camera navigation
 * @param props - Gizmo viewcube configuration  
 * @returns JSX element for viewcube gizmo
 */
function GizmoViewcube(props: GizmoViewcubeProps): JSX.Element;

interface GizmoViewcubeProps {
  /** Face text color, 'white' */
  textColor?: string;
  /** Face background color, '#f0f0f0' */
  color?: string;
  /** Hover color, '#999' */
  hoverColor?: string;
  /** Edge color, 'black' */
  strokeColor?: string;
  /** Font size, 0.5 */
  fontSize?: number;
  /** Font family, 'Inter' */
  font?: string;
  /** Face labels */
  faces?: string[];
  /** Corner radius, 0.1 */
  cornerRadius?: number;
  /** Opacity, 1 */
  opacity?: number;
}

Usage Examples:

import { GizmoHelper, GizmoViewcube, GizmoViewport } from '@react-three/drei';

// Complete gizmo system
<GizmoHelper alignment="bottom-right" margin={[100, 100]}>
  <GizmoViewcube 
    faces={['Right', 'Left', 'Top', 'Bottom', 'Front', 'Back']}
    color="#f8f8f8"
    hoverColor="#ddd"
    strokeColor="#666"
    textColor="#333"
    fontSize={0.6}
  />
</GizmoHelper>

// Combined viewport and viewcube
<GizmoHelper alignment="top-left" margin={[80, 80]}>
  <group>
    <GizmoViewcube />
    <GizmoViewport 
      axisColors={['#ff3653', '#8adb00', '#2c8fff']}
      labelColor="white"
    />
  </group>
</GizmoHelper>

TransformControls

Advanced transformation gizmo with multiple modes and precise control.

/**
 * Advanced transformation gizmo (from core controls)
 * @param props - Transform controls configuration
 * @returns JSX element for transformation gizmo
 */
function TransformControls(props: TransformControlsProps): JSX.Element;

interface TransformControlsProps extends Omit<ThreeElement<TransformControlsImpl>, 'ref' | 'args'> {
  /** Object to transform */
  object?: Object3D;
  /** Camera to use */
  camera?: Camera;
  /** DOM element for events */
  domElement?: HTMLElement;
  /** Control mode: 'translate' | 'rotate' | 'scale' */
  mode?: 'translate' | 'rotate' | 'scale';
  /** Transform space: 'world' | 'local' */
  space?: 'world' | 'local';
  /** Gizmo size, 1 */
  size?: number;
  /** Show X axis, true */
  showX?: boolean;
  /** Show Y axis, true */
  showY?: boolean;
  /** Show Z axis, true */
  showZ?: boolean;
  /** Translation snap */
  translationSnap?: number;
  /** Rotation snap */
  rotationSnap?: number;
  /** Scale snap */
  scaleSnap?: number;
  /** Dragging change callback */
  onDragging?: (dragging: boolean) => void;
  /** Object change callback */
  onChange?: () => void;
}

Integration Patterns

Multi-Gizmo Scene

function EditorScene() {
  const [selectedObject, setSelectedObject] = useState(null);
  const [transformMode, setTransformMode] = useState('translate');
  const [showGrid, setShowGrid] = useState(true);
  
  return (
    <>
      {/* Scene grid */}
      {showGrid && (
        <Grid 
          cellSize={1} 
          sectionSize={10} 
          args={[100, 100]} 
          position={[0, -0.01, 0]} 
        />
      )}
      
      {/* Draggable objects */}
      <DragControls
        onDragStart={(e) => setSelectedObject(e.object)}
        onDragEnd={() => setSelectedObject(null)}
      >
        <SceneObjects />
      </DragControls>
      
      {/* Transform controls for selected object */}
      {selectedObject && (
        <TransformControls
          object={selectedObject}
          mode={transformMode}
          onDragging={(dragging) => {
            // Disable orbit controls while transforming
            orbitControlsRef.current.enabled = !dragging;
          }}
        />
      )}
      
      {/* Camera gizmos */}
      <GizmoHelper alignment="bottom-right" margin={[80, 80]}>
        <GizmoViewcube />
        <GizmoViewport />
      </GizmoHelper>
      
      {/* UI Controls */}
      <Html fullscreen>
        <div className="editor-ui">
          <button onClick={() => setTransformMode('translate')}>
            Translate
          </button>
          <button onClick={() => setTransformMode('rotate')}>
            Rotate
          </button>
          <button onClick={() => setTransformMode('scale')}>
            Scale
          </button>
          <button onClick={() => setShowGrid(!showGrid)}>
            Toggle Grid
          </button>
        </div>
      </Html>
    </>
  );
}

Constrained Manipulation

function ConstrainedEditor() {
  return (
    <>
      {/* Ground-constrained dragging */}
      <DragControls axisLock="xz">
        <GroundObjects />
      </DragControls>
      
      {/* Y-axis only movement */}
      <PivotControls
        disableAxisX
        disableAxisZ
        disableRotations
        disableScaling
        translationLimits={[null, [0, 10], null]}
      >
        <ElevatorPlatform />
      </PivotControls>
      
      {/* Rotation-only controls */}
      <PivotControls
        anchor={[0, 0, 0]}
        disableSliders
        disableScaling
        rotationLimits={[null, [-Math.PI, Math.PI], null]}
      >
        <RotatingDoor />
      </PivotControls>
    </>
  );
}

Gizmo State Management

function GizmoSystem() {
  const [gizmoVisible, setGizmoVisible] = useState(true);
  const [gizmoMode, setGizmoMode] = useState('translate');
  const [activeObject, setActiveObject] = useState(null);
  
  // Keyboard shortcuts
  useEffect(() => {
    const handleKeyDown = (e) => {
      switch (e.key) {
        case 'g':
          setGizmoMode('translate');
          break;
        case 'r':
          setGizmoMode('rotate');
          break;
        case 's':
          setGizmoMode('scale');
          break;
        case 'h':
          setGizmoVisible(!gizmoVisible);
          break;
      }
    };
    
    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [gizmoVisible]);
  
  return (
    <>
      {gizmoVisible && (
        <>
          <Grid infiniteGrid fadeDistance={100} />
          
          <PivotControls
            enabled={activeObject !== null}
            scale={gizmoMode === 'scale' ? 150 : 100}
            onDragStart={() => console.log(`${gizmoMode} started`)}
            onDragEnd={() => console.log(`${gizmoMode} ended`)}
          >
            {activeObject && <primitive object={activeObject} />}
          </PivotControls>
          
          <GizmoHelper alignment="bottom-right">
            <GizmoViewcube />
          </GizmoHelper>
        </>
      )}
    </>
  );
}

Performance-Optimized Gizmos

function OptimizedGizmos() {
  // Only render gizmos when needed
  const [showGizmos, setShowGizmos] = useState(false);
  const [selectedObjects, setSelectedObjects] = useState([]);
  
  // Throttle gizmo updates
  const throttledUpdate = useCallback(
    throttle((matrix) => {
      // Update object transform
      updateObjectTransform(matrix);
    }, 16), // 60 FPS
    []
  );
  
  return (
    <>
      {/* Conditional gizmo rendering */}
      {showGizmos && selectedObjects.length > 0 && (
        <PivotControls
          onDrag={throttledUpdate}
          lineWidth={window.devicePixelRatio > 1 ? 1 : 2}
        >
          {selectedObjects.map(obj => (
            <primitive key={obj.uuid} object={obj} />
          ))}
        </PivotControls>
      )}
      
      {/* Low-impact grid */}
      <Grid 
        infiniteGrid 
        fadeDistance={50}
        cellSize={1}
        args={[20, 20]} // Smaller grid for performance
      />
    </>
  );
}

RoundedBox

Shape utility for creating rounded box geometries.

/**
 * Creates rounded box geometry with configurable corner radius
 * @param props - RoundedBox configuration props
 * @returns JSX element for rounded box mesh
 */
function RoundedBox(props: RoundedBoxProps): JSX.Element;

interface RoundedBoxProps extends Omit<ThreeElements['mesh'], 'ref' | 'args'> {
  /** Box dimensions [width, height, depth] */
  args?: [number?, number?, number?];
  /** Corner radius, 0.05 */
  radius?: number;
  /** Surface smoothness, 4 */
  smoothness?: number;
  /** Bevel segments for corners, 3 */
  bevelSegments?: number;
  /** Extrude steps, 1 */
  steps?: number;
  /** Crease angle for sharp edges, 0.4 */
  creaseAngle?: number;
}

ScreenQuad

Utility component for creating screen-aligned quad geometries.

/**
 * Creates screen-aligned quad geometry for post-processing effects
 * @param props - ScreenQuad configuration props
 * @returns JSX element for screen quad mesh
 */
function ScreenQuad(props: ScreenQuadProps): JSX.Element;

interface ScreenQuadProps extends Omit<ThreeElements['mesh'], 'ref'> {
  /** Material for the quad */
  material?: Material;
}

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