0
# Loaders
1
2
Asset loading utilities for textures, models, and media with automatic caching, disposal, and format support. These components provide efficient loading strategies for various 3D assets.
3
4
## Capabilities
5
6
### useGLTF
7
8
GLTF model loading hook with automatic disposal, Draco compression, and type safety.
9
10
```typescript { .api }
11
/**
12
* GLTF model loading hook with automatic disposal
13
* @param path - Path to GLTF/GLB file
14
* @param useDraco - Enable Draco compression support, true
15
* @param useMeshOpt - Enable MeshOpt compression support, true
16
* @returns GLTF object with nodes, materials, and animations
17
*/
18
function useGLTF(path: string, useDraco?: boolean, useMeshOpt?: boolean): GLTF & ObjectMap;
19
20
interface GLTF {
21
/** Animation clips from the model */
22
animations: AnimationClip[];
23
/** Root scene group */
24
scene: Group;
25
/** All scenes in the file */
26
scenes: Group[];
27
/** Cameras from the model */
28
cameras: Camera[];
29
/** Asset metadata */
30
asset: object;
31
/** Parser used */
32
parser: GLTFParser;
33
/** User data */
34
userData: any;
35
}
36
37
interface ObjectMap {
38
/** Named nodes from the model */
39
nodes: { [name: string]: Object3D };
40
/** Named materials from the model */
41
materials: { [name: string]: Material };
42
}
43
44
// Static methods
45
function useGLTF.preload(path: string): void;
46
function useGLTF.clear(input: string | string[]): void;
47
```
48
49
**Usage Examples:**
50
51
```typescript
52
import { useGLTF } from '@react-three/drei';
53
54
// Basic GLTF loading
55
function Model({ path }) {
56
const { nodes, materials, scene } = useGLTF(path);
57
58
return <primitive object={scene} />;
59
}
60
61
// Accessing specific nodes and materials
62
function DetailedModel() {
63
const { nodes, materials } = useGLTF('/models/character.glb');
64
65
return (
66
<group>
67
<mesh
68
geometry={nodes.Head.geometry}
69
material={materials.SkinMaterial}
70
/>
71
<mesh
72
geometry={nodes.Body.geometry}
73
material={materials.ClothMaterial}
74
/>
75
<skinnedMesh
76
geometry={nodes.Character.geometry}
77
material={materials.CharacterMaterial}
78
skeleton={nodes.Character.skeleton}
79
/>
80
</group>
81
);
82
}
83
84
// With animations
85
function AnimatedModel() {
86
const group = useRef();
87
const { nodes, materials, animations } = useGLTF('/models/animated.glb');
88
const { actions } = useAnimations(animations, group);
89
90
useEffect(() => {
91
actions['Walk']?.play();
92
}, [actions]);
93
94
return (
95
<group ref={group}>
96
<primitive object={nodes.Scene} />
97
</group>
98
);
99
}
100
101
// Preload models for better performance
102
useGLTF.preload('/models/important.glb');
103
104
// Clear cache when needed
105
useGLTF.clear('/models/old.glb');
106
```
107
108
### useTexture
109
110
Texture loading hook with multiple format support, automatic disposal, and batch loading.
111
112
```typescript { .api }
113
/**
114
* Texture loading hook with format support
115
* @param input - Texture path or array of paths
116
* @param onLoad - Load callback function
117
* @returns Texture or array of textures
118
*/
119
function useTexture(
120
input: string | string[],
121
onLoad?: (texture: Texture | Texture[]) => void
122
): Texture | Texture[];
123
124
// Static methods
125
function useTexture.preload(input: string | string[]): void;
126
function useTexture.clear(input: string | string[]): void;
127
```
128
129
**Usage Examples:**
130
131
```typescript
132
import { useTexture } from '@react-three/drei';
133
134
// Single texture
135
function TexturedMesh() {
136
const texture = useTexture('/textures/diffuse.jpg');
137
138
return (
139
<mesh>
140
<planeGeometry />
141
<meshStandardMaterial map={texture} />
142
</mesh>
143
);
144
}
145
146
// Multiple textures
147
function PBRMaterial() {
148
const [colorMap, normalMap, roughnessMap, metalnessMap] = useTexture([
149
'/textures/color.jpg',
150
'/textures/normal.jpg',
151
'/textures/roughness.jpg',
152
'/textures/metalness.jpg'
153
]);
154
155
return (
156
<meshStandardMaterial
157
map={colorMap}
158
normalMap={normalMap}
159
roughnessMap={roughnessMap}
160
metalnessMap={metalnessMap}
161
/>
162
);
163
}
164
165
// Object syntax for named textures
166
function NamedTextures() {
167
const textures = useTexture({
168
diffuse: '/textures/diffuse.jpg',
169
normal: '/textures/normal.jpg',
170
roughness: '/textures/roughness.jpg'
171
});
172
173
return (
174
<meshStandardMaterial
175
map={textures.diffuse}
176
normalMap={textures.normal}
177
roughnessMap={textures.roughness}
178
/>
179
);
180
}
181
182
// Texture configuration callback
183
function ConfiguredTexture() {
184
const texture = useTexture('/textures/tile.jpg', (texture) => {
185
texture.wrapS = texture.wrapT = RepeatWrapping;
186
texture.repeat.set(4, 4);
187
texture.minFilter = NearestFilter;
188
texture.magFilter = NearestFilter;
189
});
190
191
return (
192
<mesh>
193
<planeGeometry args={[10, 10]} />
194
<meshBasicMaterial map={texture} />
195
</mesh>
196
);
197
}
198
199
// Preload critical textures
200
useTexture.preload([
201
'/textures/hero-diffuse.jpg',
202
'/textures/hero-normal.jpg'
203
]);
204
```
205
206
### useFont
207
208
Font loading hook for text rendering with caching and format support.
209
210
```typescript { .api }
211
/**
212
* Font loading hook for text rendering
213
* @param path - Path to font JSON file
214
* @returns Font data object with glyphs
215
*/
216
function useFont(path: string): FontData;
217
218
interface FontData {
219
/** Font data object */
220
data: any;
221
/** Character glyph definitions */
222
glyphs: { [key: string]: Glyph };
223
}
224
225
interface Glyph {
226
/** Glyph X position in font atlas */
227
x: number;
228
/** Glyph Y position in font atlas */
229
y: number;
230
/** Glyph width */
231
width: number;
232
/** Glyph height */
233
height: number;
234
/** X advance for character spacing */
235
xAdvance?: number;
236
/** X rendering offset */
237
xOffset?: number;
238
/** Y rendering offset */
239
yOffset?: number;
240
}
241
242
// Static methods
243
function useFont.preload(path: string): void;
244
function useFont.clear(path: string): void;
245
```
246
247
**Usage Examples:**
248
249
```typescript
250
import { useFont, Text3D } from '@react-three/drei';
251
252
// Basic font usage
253
function StyledText() {
254
const font = useFont('/fonts/helvetiker_regular.json');
255
256
return (
257
<Text3D font={font} size={1} height={0.2}>
258
Hello World
259
<meshNormalMaterial />
260
</Text3D>
261
);
262
}
263
264
// Multiple fonts
265
function MultiFontText() {
266
const regularFont = useFont('/fonts/helvetiker_regular.json');
267
const boldFont = useFont('/fonts/helvetiker_bold.json');
268
269
return (
270
<group>
271
<Text3D font={regularFont} position={[0, 1, 0]}>
272
Regular Text
273
<meshStandardMaterial color="blue" />
274
</Text3D>
275
<Text3D font={boldFont} position={[0, -1, 0]}>
276
Bold Text
277
<meshStandardMaterial color="red" />
278
</Text3D>
279
</group>
280
);
281
}
282
283
// Preload fonts
284
useFont.preload('/fonts/main.json');
285
```
286
287
### useEnvironment
288
289
Environment texture loading hook with presets, HDRI support, and configuration options.
290
291
```typescript { .api }
292
/**
293
* Environment texture loading hook with presets
294
* @param props - Environment loader configuration
295
* @returns Environment cube texture
296
*/
297
function useEnvironment(props?: EnvironmentLoaderProps): Texture;
298
299
interface EnvironmentLoaderProps {
300
/** Environment preset name */
301
preset?: PresetsType;
302
/** Custom environment files (single HDR or 6 cube faces) */
303
files?: string | string[];
304
/** Base path for environment files */
305
path?: string;
306
/** Texture encoding, sRGBEncoding */
307
encoding?: TextureEncoding;
308
}
309
310
type PresetsType =
311
| 'apartment' | 'city' | 'dawn' | 'forest' | 'lobby'
312
| 'night' | 'park' | 'studio' | 'sunset' | 'warehouse';
313
```
314
315
**Usage Examples:**
316
317
```typescript
318
import { useEnvironment } from '@react-three/drei';
319
320
// Environment preset
321
function ReflectiveSphere() {
322
const envMap = useEnvironment({ preset: 'sunset' });
323
324
return (
325
<mesh>
326
<sphereGeometry />
327
<meshStandardMaterial
328
envMap={envMap}
329
metalness={1}
330
roughness={0}
331
/>
332
</mesh>
333
);
334
}
335
336
// Custom HDRI environment
337
function CustomEnvironment() {
338
const envMap = useEnvironment({
339
files: '/hdri/studio_small_03_1k.hdr',
340
encoding: RGBEEncoding
341
});
342
343
return (
344
<mesh>
345
<torusGeometry />
346
<meshStandardMaterial envMap={envMap} />
347
</mesh>
348
);
349
}
350
351
// Cube map environment (6 faces)
352
function CubeEnvironment() {
353
const envMap = useEnvironment({
354
files: [
355
'/cubemap/px.jpg', '/cubemap/nx.jpg',
356
'/cubemap/py.jpg', '/cubemap/ny.jpg',
357
'/cubemap/pz.jpg', '/cubemap/nz.jpg'
358
],
359
path: '/environments/'
360
});
361
362
return (
363
<mesh>
364
<boxGeometry />
365
<meshStandardMaterial envMap={envMap} />
366
</mesh>
367
);
368
}
369
```
370
371
### useFBX
372
373
FBX model loading hook with animation support and material handling.
374
375
```typescript { .api }
376
/**
377
* FBX model loading hook
378
* @param path - Path to FBX file
379
* @returns FBX group with animations
380
*/
381
function useFBX(path: string): Group & { animations: AnimationClip[] };
382
383
// Static methods
384
function useFBX.preload(path: string): void;
385
function useFBX.clear(path: string): void;
386
```
387
388
**Usage Examples:**
389
390
```typescript
391
import { useFBX } from '@react-three/drei';
392
393
function FBXModel() {
394
const fbx = useFBX('/models/character.fbx');
395
396
return <primitive object={fbx} />;
397
}
398
399
// With animations
400
function AnimatedFBX() {
401
const group = useRef();
402
const fbx = useFBX('/models/animated.fbx');
403
const { actions } = useAnimations(fbx.animations, group);
404
405
useEffect(() => {
406
actions['Take 001']?.play();
407
}, [actions]);
408
409
return (
410
<group ref={group}>
411
<primitive object={fbx} />
412
</group>
413
);
414
}
415
```
416
417
### useKTX2
418
419
KTX2 texture loading hook for GPU-compressed textures.
420
421
```typescript { .api }
422
/**
423
* KTX2 texture loading hook for GPU compression
424
* @param path - Path to KTX2 file
425
* @returns KTX2 texture
426
*/
427
function useKTX2(path: string): CompressedTexture;
428
429
// Static methods
430
function useKTX2.preload(path: string): void;
431
function useKTX2.clear(path: string): void;
432
```
433
434
### useVideoTexture
435
436
Video texture loading hook with playback control and format support.
437
438
```typescript { .api }
439
/**
440
* Video texture loading hook with playback control
441
* @param src - Video source URL or HTMLVideoElement
442
* @param props - Video texture configuration
443
* @returns Video texture
444
*/
445
function useVideoTexture(
446
src: string | HTMLVideoElement,
447
props?: Partial<VideoTextureProps>
448
): VideoTexture;
449
450
interface VideoTextureProps extends Omit<ThreeElements['videoTexture'], 'ref' | 'args'> {
451
/** Auto-play video, true */
452
autoplay?: boolean;
453
/** Loop video, true */
454
loop?: boolean;
455
/** Video crossOrigin, 'anonymous' */
456
crossOrigin?: string;
457
/** Muted playback, true */
458
muted?: boolean;
459
/** Video playback rate, 1 */
460
playbackRate?: number;
461
/** Video volume, 1 */
462
volume?: number;
463
/** Load start callback */
464
onLoadStart?: () => void;
465
/** Load callback */
466
onLoad?: (video: HTMLVideoElement) => void;
467
/** Progress callback */
468
onProgress?: (event: ProgressEvent) => void;
469
/** Error callback */
470
onError?: (error: ErrorEvent) => void;
471
}
472
```
473
474
**Usage Examples:**
475
476
```typescript
477
import { useVideoTexture } from '@react-three/drei';
478
479
// Basic video texture
480
function VideoScreen() {
481
const texture = useVideoTexture('/videos/demo.mp4');
482
483
return (
484
<mesh>
485
<planeGeometry args={[16, 9]} />
486
<meshBasicMaterial map={texture} />
487
</mesh>
488
);
489
}
490
491
// Video with controls
492
function InteractiveVideo() {
493
const texture = useVideoTexture('/videos/interactive.mp4', {
494
autoplay: false,
495
loop: false,
496
muted: false,
497
onLoad: (video) => {
498
console.log('Video loaded:', video.duration);
499
}
500
});
501
502
const playPause = () => {
503
const video = texture.image;
504
video.paused ? video.play() : video.pause();
505
};
506
507
return (
508
<group>
509
<mesh onClick={playPause}>
510
<planeGeometry args={[4, 3]} />
511
<meshBasicMaterial map={texture} />
512
</mesh>
513
</group>
514
);
515
}
516
```
517
518
### useCubeTexture
519
520
Cube texture loading hook for skyboxes and environment mapping.
521
522
```typescript { .api }
523
/**
524
* Cube texture loading hook for skyboxes
525
* @param files - Array of 6 image paths [px, nx, py, ny, pz, nz]
526
* @param options - Cube texture options
527
* @returns Cube texture
528
*/
529
function useCubeTexture(
530
files: [string, string, string, string, string, string],
531
options?: CubeTextureOptions
532
): CubeTexture;
533
534
interface CubeTextureOptions {
535
/** Base path for files */
536
path?: string;
537
/** Texture encoding */
538
encoding?: TextureEncoding;
539
}
540
541
// Static methods
542
function useCubeTexture.preload(files: string[], path?: string): void;
543
```
544
545
**Usage Examples:**
546
547
```typescript
548
import { useCubeTexture } from '@react-three/drei';
549
550
function Skybox() {
551
const texture = useCubeTexture([
552
'px.jpg', 'nx.jpg',
553
'py.jpg', 'ny.jpg',
554
'pz.jpg', 'nz.jpg'
555
], { path: '/skybox/' });
556
557
const { scene } = useThree();
558
scene.background = texture;
559
560
return null;
561
}
562
```
563
564
## Integration Patterns
565
566
### Progressive Loading
567
568
```typescript
569
function ProgressiveAssets() {
570
const [loadHigh, setLoadHigh] = useState(false);
571
572
// Load low-res first
573
const lowTexture = useTexture('/textures/low-res.jpg');
574
575
// Load high-res after delay
576
const highTexture = useTexture(
577
loadHigh ? '/textures/high-res.jpg' : null
578
);
579
580
useEffect(() => {
581
const timer = setTimeout(() => setLoadHigh(true), 1000);
582
return () => clearTimeout(timer);
583
}, []);
584
585
return (
586
<mesh>
587
<planeGeometry />
588
<meshStandardMaterial map={highTexture || lowTexture} />
589
</mesh>
590
);
591
}
592
```
593
594
### Asset Preloading Strategy
595
596
```typescript
597
// Preload critical assets during app initialization
598
const preloadCriticalAssets = () => {
599
// Models
600
useGLTF.preload('/models/hero.glb');
601
useGLTF.preload('/models/environment.glb');
602
603
// Textures
604
useTexture.preload([
605
'/textures/hero-diffuse.jpg',
606
'/textures/hero-normal.jpg',
607
'/textures/environment.jpg'
608
]);
609
610
// Fonts
611
useFont.preload('/fonts/main.json');
612
613
// Environment
614
useEnvironment.preload({ preset: 'studio' });
615
};
616
617
// Call during app startup
618
useEffect(preloadCriticalAssets, []);
619
```
620
621
### Memory Management
622
623
```typescript
624
function MemoryEfficientLoader() {
625
const [currentModel, setCurrentModel] = useState('model1');
626
627
// Clear previous model from cache when switching
628
useEffect(() => {
629
return () => {
630
// Clean up unused assets
631
if (currentModel !== 'model1') {
632
useGLTF.clear('/models/model1.glb');
633
}
634
if (currentModel !== 'model2') {
635
useGLTF.clear('/models/model2.glb');
636
}
637
};
638
}, [currentModel]);
639
640
const model = useGLTF(`/models/${currentModel}.glb`);
641
642
return <primitive object={model.scene} />;
643
}
644
```
645
646
### Error Handling
647
648
```typescript
649
function RobustAssetLoader() {
650
const [error, setError] = useState(null);
651
const [loading, setLoading] = useState(true);
652
653
try {
654
const model = useGLTF('/models/complex.glb');
655
const texture = useTexture('/textures/diffuse.jpg', () => {
656
setLoading(false);
657
});
658
659
if (error) return <ErrorFallback error={error} />;
660
if (loading) return <LoadingSpinner />;
661
662
return (
663
<mesh>
664
<primitive object={model.scene} />
665
<meshStandardMaterial map={texture} />
666
</mesh>
667
);
668
} catch (err) {
669
setError(err);
670
return <ErrorFallback error={err} />;
671
}
672
}
673
674
function ErrorFallback({ error }) {
675
return (
676
<mesh>
677
<boxGeometry />
678
<meshBasicMaterial color="red" />
679
<Html center>
680
<div>Failed to load: {error.message}</div>
681
</Html>
682
</mesh>
683
);
684
}
685
```
686
687
### Conditional Loading
688
689
```typescript
690
function ConditionalAssets() {
691
const { viewport } = useThree();
692
const isMobile = viewport.width < 768;
693
const [quality, setQuality] = useState('medium');
694
695
// Load appropriate quality assets
696
const modelPath = `/models/character-${isMobile ? 'low' : quality}.glb`;
697
const texturePath = `/textures/diffuse-${isMobile ? '512' : '2048'}.jpg`;
698
699
const model = useGLTF(modelPath);
700
const texture = useTexture(texturePath);
701
702
return (
703
<group>
704
<primitive object={model.scene} />
705
<meshStandardMaterial map={texture} />
706
</group>
707
);
708
}
709
```
710
711
### Batch Loading with Progress
712
713
```typescript
714
function BatchLoader({ onProgress }) {
715
const [loaded, setLoaded] = useState(0);
716
const totalAssets = 10;
717
718
const handleLoad = useCallback(() => {
719
setLoaded(prev => {
720
const newLoaded = prev + 1;
721
onProgress?.(newLoaded / totalAssets);
722
return newLoaded;
723
});
724
}, [onProgress, totalAssets]);
725
726
// Load multiple assets with progress tracking
727
const textures = useTexture([
728
'/tex1.jpg', '/tex2.jpg', '/tex3.jpg',
729
'/tex4.jpg', '/tex5.jpg'
730
], handleLoad);
731
732
const models = [
733
useGLTF('/model1.glb'),
734
useGLTF('/model2.glb'),
735
useGLTF('/model3.glb'),
736
useGLTF('/model4.glb'),
737
useGLTF('/model5.glb')
738
];
739
740
return (
741
<group>
742
{models.map((model, i) => (
743
<primitive key={i} object={model.scene} />
744
))}
745
</group>
746
);
747
}
748
```