Useful add-ons for react-three-fiber providing 100+ components for 3D web applications
—
Optimization components for efficient rendering of large datasets and complex scenes. These components provide various strategies for maintaining smooth framerates while handling demanding 3D content.
Instanced mesh rendering for efficiently displaying large numbers of identical objects with individual transforms.
/**
* Instanced mesh rendering for identical objects
* @param props - Instances configuration
* @returns JSX element for instanced mesh
*/
function Instances(props: InstancesProps): JSX.Element;
/**
* Individual instance within an Instances component
* @param props - Instance configuration
* @returns JSX element for single instance
*/
function Instance(props: InstanceProps): JSX.Element;
interface InstancesProps extends Omit<ThreeElements['instancedMesh'], 'ref' | 'args'> {
/** Maximum number of instances */
limit?: number;
/** Instance range [start, count] */
range?: [number, number];
/** Frustum culling, true */
frustumCulled?: boolean;
/** Render order */
renderOrder?: number;
}
interface InstanceProps {
/** Instance position */
position?: [number, number, number];
/** Instance rotation */
rotation?: [number, number, number];
/** Instance scale */
scale?: [number, number, number] | number;
/** Instance color */
color?: ReactThreeFiber.Color;
/** Instance matrix */
matrix?: Matrix4;
}Usage Examples:
import { Instances, Instance } from '@react-three/drei';
// Basic instancing
<Instances limit={1000} frustumCulled>
<boxGeometry />
<meshStandardMaterial />
{Array.from({ length: 1000 }, (_, i) => (
<Instance
key={i}
position={[
(Math.random() - 0.5) * 100,
(Math.random() - 0.5) * 100,
(Math.random() - 0.5) * 100
]}
rotation={[Math.random(), Math.random(), Math.random()]}
scale={Math.random() * 0.5 + 0.5}
color={`hsl(${Math.random() * 360}, 50%, 50%)`}
/>
))}
</Instances>
// Animated instances
function AnimatedInstances() {
return (
<Instances limit={100}>
<sphereGeometry />
<meshNormalMaterial />
{Array.from({ length: 100 }, (_, i) => (
<AnimatedInstance key={i} index={i} />
))}
</Instances>
);
}
function AnimatedInstance({ index }) {
const ref = useRef();
useFrame((state) => {
const time = state.clock.elapsedTime;
const angle = (index / 100) * Math.PI * 2;
ref.current.position.set(
Math.cos(angle + time) * 10,
Math.sin(time) * 2,
Math.sin(angle + time) * 10
);
});
return <Instance ref={ref} />;
}Efficient point cloud rendering using GPU-based point systems for large datasets.
/**
* Efficient point cloud rendering with GPU processing
* @param props - Points configuration
* @returns JSX element for point cloud
*/
function Points(props: PointsProps): JSX.Element;
interface PointsProps extends Omit<ThreeElements['points'], 'ref'> {
/** Point positions array */
positions?: Float32Array | number[];
/** Point colors array */
colors?: Float32Array | number[];
/** Point sizes array */
sizes?: Float32Array | number[];
/** Point count limit */
limit?: number;
/** Frustum culling, true */
frustumCulled?: boolean;
}
interface PointsInstancesProps extends PointsProps {
/** Instanced rendering, false */
instances?: boolean;
/** Instance limit, 1000 */
instanceLimit?: number;
}
interface PointsBuffersProps extends PointsProps {
/** Use buffer geometry, true */
buffer?: boolean;
/** Buffer update frequency */
updateFrequency?: number;
}Usage Examples:
import { Points } from '@react-three/drei';
// Basic point cloud
function PointCloud() {
const pointCount = 10000;
const positions = new Float32Array(pointCount * 3);
const colors = new Float32Array(pointCount * 3);
for (let i = 0; i < pointCount; i++) {
// Random positions
positions[i * 3] = (Math.random() - 0.5) * 100;
positions[i * 3 + 1] = (Math.random() - 0.5) * 100;
positions[i * 3 + 2] = (Math.random() - 0.5) * 100;
// Random colors
colors[i * 3] = Math.random();
colors[i * 3 + 1] = Math.random();
colors[i * 3 + 2] = Math.random();
}
return (
<Points positions={positions} colors={colors} limit={pointCount}>
<pointsMaterial size={0.1} vertexColors />
</Points>
);
}
// Animated point cloud
function AnimatedPoints() {
const pointsRef = useRef();
const pointCount = 5000;
useFrame((state) => {
if (pointsRef.current?.geometry?.attributes?.position) {
const positions = pointsRef.current.geometry.attributes.position.array;
const time = state.clock.elapsedTime;
for (let i = 0; i < pointCount; i++) {
const i3 = i * 3;
positions[i3 + 1] += Math.sin(time + i * 0.01) * 0.01;
}
pointsRef.current.geometry.attributes.position.needsUpdate = true;
}
});
return (
<Points ref={pointsRef} limit={pointCount}>
<pointsMaterial size={0.05} color="hotpink" />
</Points>
);
}Level-of-detail (LOD) rendering component that switches between different representations based on distance.
/**
* Level-of-detail rendering based on distance
* @param props - LOD configuration
* @returns JSX element for LOD system
*/
function Detailed(props: DetailedProps): JSX.Element;
interface DetailedProps extends Omit<ThreeElements['group'], 'ref'> {
/** LOD distances array */
distances: number[];
/** Hysteresis factor, 0 */
hysteresis?: number;
}Usage Examples:
import { Detailed } from '@react-three/drei';
// LOD with multiple detail levels
<Detailed distances={[0, 10, 20, 35, 60]}>
{/* High detail - close up */}
<mesh>
<sphereGeometry args={[1, 64, 64]} />
<meshStandardMaterial />
</mesh>
{/* Medium detail */}
<mesh>
<sphereGeometry args={[1, 32, 32]} />
<meshStandardMaterial />
</mesh>
{/* Low detail */}
<mesh>
<sphereGeometry args={[1, 16, 16]} />
<meshStandardMaterial />
</mesh>
{/* Very low detail */}
<mesh>
<sphereGeometry args={[1, 8, 8]} />
<meshBasicMaterial />
</mesh>
{/* Billboard for far distances */}
<sprite>
<spriteMaterial map={billboardTexture} />
</sprite>
</Detailed>Performance monitoring system with automatic quality degradation and frame rate tracking.
/**
* Performance monitoring with automatic degradation
* @param props - Performance monitor configuration
* @returns JSX element for performance monitoring
*/
function PerformanceMonitor(props: PerformanceMonitorProps): JSX.Element;
interface PerformanceMonitorProps {
/** Target FPS, 60 */
fps?: number;
/** Performance factor [0-1], 1 */
factor?: number;
/** Flip performance, false */
flipflops?: number;
/** Step size for adjustments, 1 */
step?: number;
/** Monitor enabled, true */
enabled?: boolean;
/** Performance change callback */
onIncline?: (api: PerformanceMonitorApi) => void;
/** Performance decline callback */
onDecline?: (api: PerformanceMonitorApi) => void;
/** Frame drop callback */
onFallback?: (api: PerformanceMonitorApi) => void;
}
interface PerformanceMonitorApi {
/** Current performance factor */
factor: number;
/** Current FPS */
fps: number;
/** Render count */
frames: number;
/** Performance monitor enabled */
enabled: boolean;
}Usage Examples:
import { PerformanceMonitor } from '@react-three/drei';
function AdaptiveScene() {
const [dpr, setDpr] = useState(1);
const [quality, setQuality] = useState(1);
return (
<>
<PerformanceMonitor
onIncline={() => {
setDpr(Math.min(2, dpr + 0.1));
setQuality(Math.min(1, quality + 0.1));
}}
onDecline={() => {
setDpr(Math.max(0.5, dpr - 0.1));
setQuality(Math.max(0.3, quality - 0.1));
}}
onFallback={() => {
setDpr(0.5);
setQuality(0.3);
}}
/>
<Canvas dpr={dpr}>
<AdaptiveContent quality={quality} />
</Canvas>
</>
);
}Asset preloading system for improving loading performance and user experience.
/**
* Asset preloading system for better performance
* @param props - Preload configuration
* @returns JSX element for preloading assets
*/
function Preload(props: PreloadProps): JSX.Element;
interface PreloadProps {
/** Preload all assets, true */
all?: boolean;
/** Asset scenes to preload */
scene?: Object3D | Object3D[];
/** Preload cameras, false */
camera?: boolean;
/** Include invisible objects, false */
includeInvisible?: boolean;
}Usage Examples:
import { Preload } from '@react-three/drei';
// Preload all scene assets
<Canvas>
<Suspense fallback={<Loader />}>
<Scene />
<Preload all />
</Suspense>
</Canvas>
// Selective preloading
<Preload scene={sceneRef.current} includeInvisible />Adaptive device pixel ratio component for dynamic resolution scaling based on performance.
/**
* Adaptive device pixel ratio for performance scaling
* @param props - Adaptive DPR configuration
* @returns JSX element for adaptive DPR
*/
function AdaptiveDpr(props: AdaptiveDprProps): JSX.Element;
interface AdaptiveDprProps {
/** Lower DPR bound, 1 */
pixelated?: number;
/** Upper DPR bound, 2 */
dpr?: number;
}Adaptive event handling that reduces event frequency based on performance needs.
/**
* Adaptive event handling for performance optimization
* @param props - Adaptive events configuration
* @returns JSX element for adaptive events
*/
function AdaptiveEvents(props: AdaptiveEventsProps): JSX.Element;
interface AdaptiveEventsProps {
/** Event enabled, true */
enabled?: boolean;
}Shadow map baking utility for static lighting performance optimization.
/**
* Shadow map baking for static lighting optimization
* @param props - Bake shadows configuration
* @returns JSX element for shadow baking
*/
function BakeShadows(props: BakeShadowsProps): JSX.Element;
interface BakeShadowsProps {
/** Baking enabled, true */
enabled?: boolean;
}Efficient mesh bounds calculation for optimized raycasting and collision detection.
/**
* Efficient mesh bounds calculation for raycasting optimization
* @param mesh - Target mesh for bounds calculation
* @returns Bounds helper functions
*/
function meshBounds(mesh: Mesh): {
raycast: (raycaster: Raycaster, intersects: Intersection[]) => void;
};Usage Examples:
import { meshBounds } from '@react-three/drei';
function OptimizedMesh() {
const meshRef = useRef();
useLayoutEffect(() => {
if (meshRef.current) {
// Use efficient bounds-based raycasting
meshRef.current.raycast = meshBounds(meshRef.current).raycast;
}
}, []);
return (
<mesh ref={meshRef}>
<complexGeometry /> {/* Complex geometry with optimized raycasting */}
<meshStandardMaterial />
</mesh>
);
}function AdaptiveScene() {
const [performanceLevel, setPerformanceLevel] = useState(1);
return (
<>
<PerformanceMonitor
onDecline={(api) => {
if (api.factor < 0.5) setPerformanceLevel(0.3);
else if (api.factor < 0.8) setPerformanceLevel(0.6);
}}
onIncline={(api) => {
if (api.factor > 0.9) setPerformanceLevel(1);
else if (api.factor > 0.7) setPerformanceLevel(0.8);
}}
/>
<AdaptiveDpr pixelated={performanceLevel} />
<AdaptiveEvents enabled={performanceLevel > 0.5} />
{/* Render based on performance level */}
{performanceLevel > 0.8 ? (
<HighQualityContent />
) : performanceLevel > 0.5 ? (
<MediumQualityContent />
) : (
<LowQualityContent />
)}
</>
);
}function Forest() {
const treeCount = 1000;
const trees = useMemo(() => {
return Array.from({ length: treeCount }, (_, i) => ({
position: [
(Math.random() - 0.5) * 200,
0,
(Math.random() - 0.5) * 200
],
rotation: [0, Math.random() * Math.PI * 2, 0],
scale: Math.random() * 0.5 + 0.5,
}));
}, []);
return (
<Instances limit={treeCount} frustumCulled>
<cylinderGeometry args={[0.1, 0.3, 3]} />
<meshStandardMaterial color="brown" />
{trees.map((tree, i) => (
<Instance
key={i}
position={tree.position}
rotation={tree.rotation}
scale={tree.scale}
/>
))}
</Instances>
);
}function DynamicLOD({ position }) {
const { camera } = useThree();
const [distance, setDistance] = useState(0);
useFrame(() => {
const dist = camera.position.distanceTo(new Vector3(...position));
setDistance(dist);
});
return (
<Detailed distances={[0, 10, 25, 50]} hysteresis={2}>
{/* Ultra high detail */}
<ComplexModel vertices={50000} />
{/* High detail */}
<ComplexModel vertices={10000} />
{/* Medium detail */}
<SimpleModel vertices={1000} />
{/* Low detail - billboard */}
<Billboard>
<Image url="/billboard.png" />
</Billboard>
</Detailed>
);
}function MemoryEfficientScene() {
// Dispose of unused assets
useEffect(() => {
return () => {
// Clean up geometries
geometries.forEach(geo => geo.dispose());
// Clean up materials
materials.forEach(mat => mat.dispose());
// Clean up textures
textures.forEach(tex => tex.dispose());
};
}, []);
// Use object pooling for frequently created/destroyed objects
const objectPool = useMemo(() => new ObjectPool(), []);
return (
<>
<BakeShadows /> {/* Bake static shadows */}
<PooledObjects pool={objectPool} />
</>
);
}Component that bakes static shadows for performance optimization.
/**
* Bakes static shadows to improve rendering performance
* @returns JSX element that disables shadow auto-update
*/
function BakeShadows(): JSX.Element;Component for preloading and compiling shaders and materials.
/**
* Preloads and compiles shaders and materials for smoother performance
* @param props - Preload configuration props
* @returns JSX element for preloading
*/
function Preload(props: PreloadProps): JSX.Element;
interface PreloadProps {
/** Preload all objects, false */
all?: boolean;
/** Scene to preload */
scene?: Object3D;
/** Camera for preloading */
camera?: Camera;
}Utility function for efficient mesh bounds calculation.
/**
* Efficient mesh bounds calculation for culling and optimization
* @param mesh - Mesh to calculate bounds for
* @returns Bounds helper
*/
function meshBounds(mesh: Mesh): BoundsApi;
interface BoundsApi {
/** Get bounding box */
getBox(): Box3;
/** Get bounding sphere */
getSphere(): Sphere;
/** Check if point is inside bounds */
containsPoint(point: Vector3): boolean;
}Install with Tessl CLI
npx tessl i tessl/npm-react-three--drei