React Three Fiber Geometry Quick Start import { Canvas } from '@react-three/fiber'
function Scene() { return ( ) }
Built-in Geometries
All Three.js geometries are available as JSX elements. The args prop passes constructor arguments.
Basic Shapes
// BoxGeometry(width, height, depth, widthSegments, heightSegments, depthSegments)
// SphereGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength)
// PlaneGeometry(width, height, widthSegments, heightSegments)
// CircleGeometry(radius, segments, thetaStart, thetaLength)
// CylinderGeometry(radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded)
// ConeGeometry(radius, height, radialSegments, heightSegments, openEnded)
// TorusGeometry(radius, tube, radialSegments, tubularSegments, arc)
// TorusKnotGeometry(radius, tube, tubularSegments, radialSegments, p, q)
// RingGeometry(innerRadius, outerRadius, thetaSegments, phiSegments)
Advanced Shapes
// CapsuleGeometry(radius, length, capSegments, radialSegments)
// Polyhedrons
// Higher detail = more subdivisions
Path-Based Shapes import * as THREE from 'three'
// LatheGeometry - revolve points around Y axis function LatheShape() { const points = [ new THREE.Vector2(0, 0), new THREE.Vector2(0.5, 0), new THREE.Vector2(0.5, 0.5), new THREE.Vector2(0.3, 1), new THREE.Vector2(0, 1), ]
return (
// TubeGeometry - extrude along a curve function TubeShape() { const curve = new THREE.CatmullRomCurve3([ new THREE.Vector3(-2, 0, 0), new THREE.Vector3(-1, 1, 0), new THREE.Vector3(1, -1, 0), new THREE.Vector3(2, 0, 0), ])
return (
// ExtrudeGeometry - extrude a 2D shape function ExtrudedShape() { const shape = new THREE.Shape() shape.moveTo(0, 0) shape.lineTo(1, 0) shape.lineTo(1, 1) shape.lineTo(0, 1) shape.lineTo(0, 0)
const extrudeSettings = { steps: 2, depth: 0.5, bevelEnabled: true, bevelThickness: 0.1, bevelSize: 0.1, bevelSegments: 3, }
return (
Drei Shape Helpers
@react-three/drei provides convenient shape components.
import { Box, Sphere, Plane, Circle, Cylinder, Cone, Torus, TorusKnot, Ring, Capsule, Dodecahedron, Icosahedron, Octahedron, Tetrahedron, RoundedBox } from '@react-three/drei'
function DreiShapes() {
return (
<>
{/ All shapes accept mesh props directly /}
<Sphere args={[0.5, 32, 32]} position={[-1, 0, 0]}>
<meshStandardMaterial color="blue" />
</Sphere>
<Cylinder args={[0.5, 0.5, 1, 32]} position={[1, 0, 0]}>
<meshStandardMaterial color="green" />
</Cylinder>
{/* RoundedBox - box with rounded edges */}
<RoundedBox
args={[1, 1, 1]} // width, height, depth
radius={0.1} // border radius
smoothness={4} // smoothness of rounded edges
position={[3, 0, 0]}
>
<meshStandardMaterial color="orange" />
</RoundedBox>
</>
) }
Custom BufferGeometry Basic Custom Geometry import { useMemo, useRef } from 'react' import * as THREE from 'three'
function CustomTriangle() { const geometry = useMemo(() => { const geo = new THREE.BufferGeometry()
// Vertices (3 floats per vertex: x, y, z)
const vertices = new Float32Array([
-1, -1, 0, // vertex 0
1, -1, 0, // vertex 1
0, 1, 0, // vertex 2
])
// Normals (pointing toward camera)
const normals = new Float32Array([
0, 0, 1,
0, 0, 1,
0, 0, 1,
])
// UVs
const uvs = new Float32Array([
0, 0,
1, 0,
0.5, 1,
])
geo.setAttribute('position', new THREE.BufferAttribute(vertices, 3))
geo.setAttribute('normal', new THREE.BufferAttribute(normals, 3))
geo.setAttribute('uv', new THREE.BufferAttribute(uvs, 2))
return geo
}, [])
return (
Indexed Geometry function CustomQuad() { const geometry = useMemo(() => { const geo = new THREE.BufferGeometry()
// 4 vertices for a quad
const vertices = new Float32Array([
-1, -1, 0, // 0: bottom-left
1, -1, 0, // 1: bottom-right
1, 1, 0, // 2: top-right
-1, 1, 0, // 3: top-left
])
// Indices to form 2 triangles
const indices = new Uint16Array([
0, 1, 2, // triangle 1
0, 2, 3, // triangle 2
])
const normals = new Float32Array([
0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
])
const uvs = new Float32Array([
0, 0, 1, 0, 1, 1, 0, 1,
])
geo.setAttribute('position', new THREE.BufferAttribute(vertices, 3))
geo.setAttribute('normal', new THREE.BufferAttribute(normals, 3))
geo.setAttribute('uv', new THREE.BufferAttribute(uvs, 2))
geo.setIndex(new THREE.BufferAttribute(indices, 1))
return geo
}, [])
return (
Dynamic Geometry import { useRef } from 'react' import { useFrame } from '@react-three/fiber'
function WavyPlane() { const meshRef = useRef()
useFrame(({ clock }) => { const positions = meshRef.current.geometry.attributes.position const time = clock.elapsedTime
for (let i = 0; i < positions.count; i++) {
const x = positions.getX(i)
const y = positions.getY(i)
positions.setZ(i, Math.sin(x * 2 + time) * Math.cos(y * 2 + time) * 0.5)
}
positions.needsUpdate = true
meshRef.current.geometry.computeVertexNormals()
})
return (
Drei Instancing
Efficient rendering of many identical objects.
Instances Component import { Instances, Instance } from '@react-three/drei' import { useFrame } from '@react-three/fiber' import { useRef } from 'react'
function InstancedBoxes() { const count = 1000
return (
{Array.from({ length: count }, (_, i) => (
<AnimatedInstance key={i} index={i} />
))}
</Instances>
) }
function AnimatedInstance({ index }) { const ref = useRef()
// Random initial position const position = useMemo(() => [ (Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20, ], [])
const color = useMemo(() => ['red', 'blue', 'green', 'yellow', 'purple'][index % 5], [index])
useFrame(({ clock }) => { const t = clock.elapsedTime ref.current.rotation.x = t + index ref.current.rotation.y = t * 0.5 + index })
return (
Merged Geometry
For static instances, merge geometry for best performance:
import { Merged } from '@react-three/drei' import { useMemo } from 'react' import * as THREE from 'three'
function MergedMeshes() { // Create geometries to merge const meshes = useMemo(() => ({ Sphere: new THREE.SphereGeometry(0.5, 32, 32), Box: new THREE.BoxGeometry(1, 1, 1), Cone: new THREE.ConeGeometry(0.5, 1, 32), }), [])
return (
Points (Particle Systems) Basic Points import { Points, Point, PointMaterial } from '@react-three/drei'
function ParticleField() { const count = 5000
return (
Buffer-Based Points (High Performance) import { useMemo, useRef } from 'react' import { useFrame } from '@react-three/fiber' import * as THREE from 'three'
function BufferParticles() { const count = 10000 const pointsRef = useRef()
const { positions, colors } = useMemo(() => { const positions = new Float32Array(count * 3) const colors = new Float32Array(count * 3)
for (let i = 0; i < count; i++) {
positions[i * 3] = (Math.random() - 0.5) * 10
positions[i * 3 + 1] = (Math.random() - 0.5) * 10
positions[i * 3 + 2] = (Math.random() - 0.5) * 10
colors[i * 3] = Math.random()
colors[i * 3 + 1] = Math.random()
colors[i * 3 + 2] = Math.random()
}
return { positions, colors }
}, [])
useFrame(({ clock }) => { pointsRef.current.rotation.y = clock.elapsedTime * 0.1 })
return (
Lines Basic Line import { Line } from '@react-three/drei'
function BasicLine() { const points = [ [0, 0, 0], [1, 1, 0], [2, 0, 0], [3, 1, 0], ]
return (
Curved Line import { CatmullRomLine, QuadraticBezierLine, CubicBezierLine } from '@react-three/drei'
function CurvedLines() {
return (
<>
{/ Smooth curve through points /}
{/* Quadratic bezier */}
<QuadraticBezierLine
start={[0, 0, 0]}
mid={[1, 2, 0]}
end={[2, 0, 0]}
color="green"
lineWidth={2}
/>
{/* Cubic bezier */}
<CubicBezierLine
start={[0, 0, 0]}
midA={[0.5, 2, 0]}
midB={[1.5, -1, 0]}
end={[2, 0, 0]}
color="purple"
lineWidth={2}
/>
</>
) }
Dashed Line
Edges and Wireframe import { Edges } from '@react-three/drei'
function BoxWithEdges() {
return (
// Wireframe material
function WireframeBox() {
return (
Text Geometry Using Drei Text3D import { Text3D, Center } from '@react-three/drei'
function Text3DExample() { return (
Geometry Utilities Center Geometry import { Center } from '@react-three/drei'
function CenteredModel() { return (
// With options
// Get bounding info
Compute Bounds import { useBounds, Bounds } from '@react-three/drei'
function FitToView() {
return (
function SelectToZoom() { const bounds = useBounds()
return (
Performance Tips
Reuse geometries: Same geometry instance = better batching
Use Instances: For many identical objects
Merge static meshes: Use
// Reuse geometry const sharedGeometry = useMemo(() => new THREE.BoxGeometry(), [])
See Also r3f-fundamentals - JSX elements and refs r3f-materials - Materials for meshes r3f-shaders - Custom vertex manipulation