0
# Gizmos
1
2
Interactive tools and visual helpers for development and user interaction. These components provide intuitive interfaces for object manipulation, scene navigation, and visual debugging.
3
4
## Capabilities
5
6
### PivotControls
7
8
Interactive pivot controls for object transformation with visual feedback and constraint options.
9
10
```typescript { .api }
11
/**
12
* Interactive pivot controls for object transformation
13
* @param props - Pivot controls configuration
14
* @returns JSX element for pivot controls
15
*/
16
function PivotControls(props: PivotControlsProps): JSX.Element;
17
18
interface PivotControlsProps {
19
/** Enable/disable controls, true */
20
enabled?: boolean;
21
/** Gizmo scale, 1 */
22
scale?: number;
23
/** Line width for control handles, 2.5 */
24
lineWidth?: number;
25
/** Fixed screen size (pixels), false */
26
fixed?: boolean;
27
/** Position offset from object */
28
offset?: [number, number, number];
29
/** Starting rotation */
30
rotation?: [number, number, number];
31
/** Transform matrix */
32
matrix?: Matrix4;
33
/** Anchor point for transformations */
34
anchor?: [number, number, number];
35
/** Display mode flags */
36
displayValues?: boolean;
37
/** Disable X axis, false */
38
disableAxisX?: boolean;
39
/** Disable Y axis, false */
40
disableAxisY?: boolean;
41
/** Disable Z axis, false */
42
disableAxisZ?: boolean;
43
/** Disable rotation, false */
44
disableRotations?: boolean;
45
/** Disable scaling, false */
46
disableScaling?: boolean;
47
/** Disable sliders, false */
48
disableSliders?: boolean;
49
/** Active axes color */
50
activeAxes?: [boolean, boolean, boolean];
51
/** Translation limits */
52
translationLimits?: [[number, number], [number, number], [number, number]];
53
/** Rotation limits */
54
rotationLimits?: [[number, number], [number, number], [number, number]];
55
/** Scale limits */
56
scaleLimits?: [[number, number], [number, number], [number, number]];
57
/** Drag start callback */
58
onDragStart?: () => void;
59
/** Drag callback */
60
onDrag?: (local: Matrix4, deltaL: Matrix4, world: Matrix4, deltaW: Matrix4) => void;
61
/** Drag end callback */
62
onDragEnd?: () => void;
63
}
64
```
65
66
**Usage Examples:**
67
68
```typescript
69
import { PivotControls } from '@react-three/drei';
70
71
// Basic pivot controls
72
<PivotControls>
73
<mesh>
74
<boxGeometry />
75
<meshStandardMaterial />
76
</mesh>
77
</PivotControls>
78
79
// Advanced pivot controls with constraints
80
<PivotControls
81
scale={100}
82
lineWidth={3}
83
fixed
84
anchor={[0, 0, 0]}
85
disableRotations
86
translationLimits={[[-5, 5], [0, 10], [-5, 5]]}
87
onDragStart={() => console.log('Drag started')}
88
onDrag={(local, deltaL, world, deltaW) => {
89
// Handle transformation
90
console.log('Local matrix:', local);
91
console.log('World matrix:', world);
92
}}
93
onDragEnd={() => console.log('Drag ended')}
94
>
95
<mesh>
96
<sphereGeometry />
97
<meshStandardMaterial color="orange" />
98
</mesh>
99
</PivotControls>
100
101
// Multiple constrained pivot controls
102
function ConstrainedObject() {
103
const [position, setPosition] = useState([0, 0, 0]);
104
105
return (
106
<PivotControls
107
anchor={[0, 0, 0]}
108
disableAxisY
109
onDrag={(local) => {
110
const pos = new Vector3().setFromMatrixPosition(local);
111
setPosition([pos.x, 0, pos.z]); // Constrain to ground plane
112
}}
113
>
114
<mesh position={position}>
115
<cylinderGeometry />
116
<meshStandardMaterial />
117
</mesh>
118
</PivotControls>
119
);
120
}
121
```
122
123
### DragControls
124
125
Drag controls for intuitive object manipulation with 3D mouse interaction.
126
127
```typescript { .api }
128
/**
129
* Drag controls for object manipulation
130
* @param props - Drag controls configuration
131
* @returns JSX element for drag controls
132
*/
133
function DragControls(props: DragControlsProps): JSX.Element;
134
135
interface DragControlsProps {
136
/** Child objects to make draggable */
137
children: React.ReactNode;
138
/** Axis constraints: 'x' | 'y' | 'z' | 'xy' | 'xz' | 'yz' */
139
axisLock?: 'x' | 'y' | 'z' | 'xy' | 'xz' | 'yz';
140
/** Auto transform objects, true */
141
autoTransform?: boolean;
142
/** Transform matrix */
143
matrix?: Matrix4;
144
/** Drag start callback */
145
onDragStart?: (event: { object: Object3D; pointerId: number; point: Vector3 }) => void;
146
/** Drag callback */
147
onDrag?: (event: { object: Object3D; pointerId: number; point: Vector3; delta: Vector3 }) => void;
148
/** Drag end callback */
149
onDragEnd?: (event: { object: Object3D; pointerId: number }) => void;
150
/** Hover start callback */
151
onHoverStart?: (event: { object: Object3D }) => void;
152
/** Hover end callback */
153
onHoverEnd?: (event: { object: Object3D }) => void;
154
}
155
```
156
157
**Usage Examples:**
158
159
```typescript
160
import { DragControls } from '@react-three/drei';
161
162
// Basic drag controls
163
<DragControls>
164
<mesh>
165
<boxGeometry />
166
<meshStandardMaterial />
167
</mesh>
168
<mesh position={[2, 0, 0]}>
169
<sphereGeometry />
170
<meshStandardMaterial />
171
</mesh>
172
</DragControls>
173
174
// Constrained dragging
175
<DragControls
176
axisLock="y"
177
onDragStart={(e) => console.log('Dragging:', e.object.name)}
178
onDrag={(e) => {
179
// Custom drag behavior
180
e.object.rotation.y += e.delta.x * 0.01;
181
}}
182
>
183
<mesh name="draggable-box">
184
<boxGeometry />
185
<meshStandardMaterial color="red" />
186
</mesh>
187
</DragControls>
188
189
// Advanced drag system
190
function DraggableSystem() {
191
const [draggedObject, setDraggedObject] = useState(null);
192
193
return (
194
<DragControls
195
onDragStart={(e) => {
196
setDraggedObject(e.object);
197
e.object.material.emissive.setHex(0x444444);
198
}}
199
onDragEnd={(e) => {
200
setDraggedObject(null);
201
e.object.material.emissive.setHex(0x000000);
202
}}
203
onHoverStart={(e) => {
204
document.body.style.cursor = 'grab';
205
}}
206
onHoverEnd={(e) => {
207
document.body.style.cursor = 'auto';
208
}}
209
>
210
{objects.map((obj, i) => (
211
<DraggableObject key={i} {...obj} />
212
))}
213
</DragControls>
214
);
215
}
216
```
217
218
### Grid
219
220
3D grid helper for spatial reference and scene organization.
221
222
```typescript { .api }
223
/**
224
* 3D grid helper for spatial reference
225
* @param props - Grid configuration
226
* @returns JSX element for grid display
227
*/
228
function Grid(props: GridProps): JSX.Element;
229
230
interface GridProps extends Omit<ThreeElements['gridHelper'], 'ref'> {
231
/** Grid cell size, 1 */
232
cellSize?: number;
233
/** Grid section size, 10 */
234
sectionSize?: number;
235
/** Grid color, #999999 */
236
cellColor?: ReactThreeFiber.Color;
237
/** Section color, #555555 */
238
sectionColor?: ReactThreeFiber.Color;
239
/** Grid size, 100 */
240
args?: [number, number];
241
/** Infinite grid, false */
242
infiniteGrid?: boolean;
243
/** Fade distance, 100 */
244
fadeDistance?: number;
245
/** Fade strength, 1 */
246
fadeStrength?: number;
247
/** Follow camera, false */
248
followCamera?: boolean;
249
/** Side to render, DoubleSide */
250
side?: Side;
251
}
252
253
type GridMaterialType = {
254
cellSize: number;
255
sectionSize: number;
256
cellColor: Color;
257
sectionColor: Color;
258
fadeDistance: number;
259
fadeStrength: number;
260
};
261
```
262
263
**Usage Examples:**
264
265
```typescript
266
import { Grid } from '@react-three/drei';
267
268
// Basic grid
269
<Grid args={[100, 100]} />
270
271
// Customized grid
272
<Grid
273
cellSize={0.5}
274
sectionSize={5}
275
cellColor={'#ff0000'}
276
sectionColor={'#0000ff'}
277
args={[50, 50]}
278
position={[0, -1, 0]}
279
/>
280
281
// Infinite grid that follows camera
282
<Grid
283
infiniteGrid
284
fadeDistance={50}
285
fadeStrength={2}
286
followCamera
287
cellSize={1}
288
sectionSize={10}
289
/>
290
```
291
292
### GizmoHelper
293
294
Container for 3D gizmos with positioning and interaction management.
295
296
```typescript { .api }
297
/**
298
* Container for 3D gizmos with positioning
299
* @param props - Gizmo helper configuration
300
* @returns JSX element for gizmo container
301
*/
302
function GizmoHelper(props: GizmoHelperProps): JSX.Element;
303
304
interface GizmoHelperProps {
305
/** Gizmo alignment, 'bottom-right' */
306
alignment?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
307
/** Gizmo margin, [80, 80] */
308
margin?: [number, number];
309
/** Render on top, false */
310
onTop?: boolean;
311
/** Auto update, false */
312
onUpdate?: () => void;
313
/** Render priority, 1 */
314
renderPriority?: number;
315
/** Child gizmos */
316
children: React.ReactNode;
317
}
318
```
319
320
**Usage Examples:**
321
322
```typescript
323
import { GizmoHelper, GizmoViewport } from '@react-three/drei';
324
325
// Basic gizmo helper
326
<GizmoHelper alignment="bottom-right" margin={[80, 80]}>
327
<GizmoViewport
328
axisColors={['red', 'green', 'blue']}
329
labelColor="black"
330
/>
331
</GizmoHelper>
332
```
333
334
### GizmoViewport
335
336
3D viewport gizmo for camera orientation display and interaction.
337
338
```typescript { .api }
339
/**
340
* 3D viewport gizmo for camera orientation
341
* @param props - Gizmo viewport configuration
342
* @returns JSX element for viewport gizmo
343
*/
344
function GizmoViewport(props: GizmoViewportProps): JSX.Element;
345
346
interface GizmoViewportProps {
347
/** Axis colors [x, y, z], ['red', 'green', 'blue'] */
348
axisColors?: [string, string, string];
349
/** Axis head scale, 1 */
350
axisHeadScale?: number;
351
/** Label color, 'black' */
352
labelColor?: string;
353
/** Axis scale, [0.8, 0.05, 0.8] */
354
axisScale?: [number, number, number];
355
/** Labels ['X', 'Y', 'Z'] */
356
labels?: [string, string, string];
357
/** Font size, 16 */
358
fontSize?: number;
359
/** Font family, 'Inter' */
360
font?: string;
361
}
362
```
363
364
### GizmoViewcube
365
366
3D viewcube gizmo for camera navigation and preset views.
367
368
```typescript { .api }
369
/**
370
* 3D viewcube gizmo for camera navigation
371
* @param props - Gizmo viewcube configuration
372
* @returns JSX element for viewcube gizmo
373
*/
374
function GizmoViewcube(props: GizmoViewcubeProps): JSX.Element;
375
376
interface GizmoViewcubeProps {
377
/** Face text color, 'white' */
378
textColor?: string;
379
/** Face background color, '#f0f0f0' */
380
color?: string;
381
/** Hover color, '#999' */
382
hoverColor?: string;
383
/** Edge color, 'black' */
384
strokeColor?: string;
385
/** Font size, 0.5 */
386
fontSize?: number;
387
/** Font family, 'Inter' */
388
font?: string;
389
/** Face labels */
390
faces?: string[];
391
/** Corner radius, 0.1 */
392
cornerRadius?: number;
393
/** Opacity, 1 */
394
opacity?: number;
395
}
396
```
397
398
**Usage Examples:**
399
400
```typescript
401
import { GizmoHelper, GizmoViewcube, GizmoViewport } from '@react-three/drei';
402
403
// Complete gizmo system
404
<GizmoHelper alignment="bottom-right" margin={[100, 100]}>
405
<GizmoViewcube
406
faces={['Right', 'Left', 'Top', 'Bottom', 'Front', 'Back']}
407
color="#f8f8f8"
408
hoverColor="#ddd"
409
strokeColor="#666"
410
textColor="#333"
411
fontSize={0.6}
412
/>
413
</GizmoHelper>
414
415
// Combined viewport and viewcube
416
<GizmoHelper alignment="top-left" margin={[80, 80]}>
417
<group>
418
<GizmoViewcube />
419
<GizmoViewport
420
axisColors={['#ff3653', '#8adb00', '#2c8fff']}
421
labelColor="white"
422
/>
423
</group>
424
</GizmoHelper>
425
```
426
427
### TransformControls
428
429
Advanced transformation gizmo with multiple modes and precise control.
430
431
```typescript { .api }
432
/**
433
* Advanced transformation gizmo (from core controls)
434
* @param props - Transform controls configuration
435
* @returns JSX element for transformation gizmo
436
*/
437
function TransformControls(props: TransformControlsProps): JSX.Element;
438
439
interface TransformControlsProps extends Omit<ThreeElement<TransformControlsImpl>, 'ref' | 'args'> {
440
/** Object to transform */
441
object?: Object3D;
442
/** Camera to use */
443
camera?: Camera;
444
/** DOM element for events */
445
domElement?: HTMLElement;
446
/** Control mode: 'translate' | 'rotate' | 'scale' */
447
mode?: 'translate' | 'rotate' | 'scale';
448
/** Transform space: 'world' | 'local' */
449
space?: 'world' | 'local';
450
/** Gizmo size, 1 */
451
size?: number;
452
/** Show X axis, true */
453
showX?: boolean;
454
/** Show Y axis, true */
455
showY?: boolean;
456
/** Show Z axis, true */
457
showZ?: boolean;
458
/** Translation snap */
459
translationSnap?: number;
460
/** Rotation snap */
461
rotationSnap?: number;
462
/** Scale snap */
463
scaleSnap?: number;
464
/** Dragging change callback */
465
onDragging?: (dragging: boolean) => void;
466
/** Object change callback */
467
onChange?: () => void;
468
}
469
```
470
471
## Integration Patterns
472
473
### Multi-Gizmo Scene
474
475
```typescript
476
function EditorScene() {
477
const [selectedObject, setSelectedObject] = useState(null);
478
const [transformMode, setTransformMode] = useState('translate');
479
const [showGrid, setShowGrid] = useState(true);
480
481
return (
482
<>
483
{/* Scene grid */}
484
{showGrid && (
485
<Grid
486
cellSize={1}
487
sectionSize={10}
488
args={[100, 100]}
489
position={[0, -0.01, 0]}
490
/>
491
)}
492
493
{/* Draggable objects */}
494
<DragControls
495
onDragStart={(e) => setSelectedObject(e.object)}
496
onDragEnd={() => setSelectedObject(null)}
497
>
498
<SceneObjects />
499
</DragControls>
500
501
{/* Transform controls for selected object */}
502
{selectedObject && (
503
<TransformControls
504
object={selectedObject}
505
mode={transformMode}
506
onDragging={(dragging) => {
507
// Disable orbit controls while transforming
508
orbitControlsRef.current.enabled = !dragging;
509
}}
510
/>
511
)}
512
513
{/* Camera gizmos */}
514
<GizmoHelper alignment="bottom-right" margin={[80, 80]}>
515
<GizmoViewcube />
516
<GizmoViewport />
517
</GizmoHelper>
518
519
{/* UI Controls */}
520
<Html fullscreen>
521
<div className="editor-ui">
522
<button onClick={() => setTransformMode('translate')}>
523
Translate
524
</button>
525
<button onClick={() => setTransformMode('rotate')}>
526
Rotate
527
</button>
528
<button onClick={() => setTransformMode('scale')}>
529
Scale
530
</button>
531
<button onClick={() => setShowGrid(!showGrid)}>
532
Toggle Grid
533
</button>
534
</div>
535
</Html>
536
</>
537
);
538
}
539
```
540
541
### Constrained Manipulation
542
543
```typescript
544
function ConstrainedEditor() {
545
return (
546
<>
547
{/* Ground-constrained dragging */}
548
<DragControls axisLock="xz">
549
<GroundObjects />
550
</DragControls>
551
552
{/* Y-axis only movement */}
553
<PivotControls
554
disableAxisX
555
disableAxisZ
556
disableRotations
557
disableScaling
558
translationLimits={[null, [0, 10], null]}
559
>
560
<ElevatorPlatform />
561
</PivotControls>
562
563
{/* Rotation-only controls */}
564
<PivotControls
565
anchor={[0, 0, 0]}
566
disableSliders
567
disableScaling
568
rotationLimits={[null, [-Math.PI, Math.PI], null]}
569
>
570
<RotatingDoor />
571
</PivotControls>
572
</>
573
);
574
}
575
```
576
577
### Gizmo State Management
578
579
```typescript
580
function GizmoSystem() {
581
const [gizmoVisible, setGizmoVisible] = useState(true);
582
const [gizmoMode, setGizmoMode] = useState('translate');
583
const [activeObject, setActiveObject] = useState(null);
584
585
// Keyboard shortcuts
586
useEffect(() => {
587
const handleKeyDown = (e) => {
588
switch (e.key) {
589
case 'g':
590
setGizmoMode('translate');
591
break;
592
case 'r':
593
setGizmoMode('rotate');
594
break;
595
case 's':
596
setGizmoMode('scale');
597
break;
598
case 'h':
599
setGizmoVisible(!gizmoVisible);
600
break;
601
}
602
};
603
604
window.addEventListener('keydown', handleKeyDown);
605
return () => window.removeEventListener('keydown', handleKeyDown);
606
}, [gizmoVisible]);
607
608
return (
609
<>
610
{gizmoVisible && (
611
<>
612
<Grid infiniteGrid fadeDistance={100} />
613
614
<PivotControls
615
enabled={activeObject !== null}
616
scale={gizmoMode === 'scale' ? 150 : 100}
617
onDragStart={() => console.log(`${gizmoMode} started`)}
618
onDragEnd={() => console.log(`${gizmoMode} ended`)}
619
>
620
{activeObject && <primitive object={activeObject} />}
621
</PivotControls>
622
623
<GizmoHelper alignment="bottom-right">
624
<GizmoViewcube />
625
</GizmoHelper>
626
</>
627
)}
628
</>
629
);
630
}
631
```
632
633
### Performance-Optimized Gizmos
634
635
```typescript
636
function OptimizedGizmos() {
637
// Only render gizmos when needed
638
const [showGizmos, setShowGizmos] = useState(false);
639
const [selectedObjects, setSelectedObjects] = useState([]);
640
641
// Throttle gizmo updates
642
const throttledUpdate = useCallback(
643
throttle((matrix) => {
644
// Update object transform
645
updateObjectTransform(matrix);
646
}, 16), // 60 FPS
647
[]
648
);
649
650
return (
651
<>
652
{/* Conditional gizmo rendering */}
653
{showGizmos && selectedObjects.length > 0 && (
654
<PivotControls
655
onDrag={throttledUpdate}
656
lineWidth={window.devicePixelRatio > 1 ? 1 : 2}
657
>
658
{selectedObjects.map(obj => (
659
<primitive key={obj.uuid} object={obj} />
660
))}
661
</PivotControls>
662
)}
663
664
{/* Low-impact grid */}
665
<Grid
666
infiniteGrid
667
fadeDistance={50}
668
cellSize={1}
669
args={[20, 20]} // Smaller grid for performance
670
/>
671
</>
672
);
673
}
674
```
675
676
### RoundedBox
677
678
Shape utility for creating rounded box geometries.
679
680
```typescript { .api }
681
/**
682
* Creates rounded box geometry with configurable corner radius
683
* @param props - RoundedBox configuration props
684
* @returns JSX element for rounded box mesh
685
*/
686
function RoundedBox(props: RoundedBoxProps): JSX.Element;
687
688
interface RoundedBoxProps extends Omit<ThreeElements['mesh'], 'ref' | 'args'> {
689
/** Box dimensions [width, height, depth] */
690
args?: [number?, number?, number?];
691
/** Corner radius, 0.05 */
692
radius?: number;
693
/** Surface smoothness, 4 */
694
smoothness?: number;
695
/** Bevel segments for corners, 3 */
696
bevelSegments?: number;
697
/** Extrude steps, 1 */
698
steps?: number;
699
/** Crease angle for sharp edges, 0.4 */
700
creaseAngle?: number;
701
}
702
```
703
704
### ScreenQuad
705
706
Utility component for creating screen-aligned quad geometries.
707
708
```typescript { .api }
709
/**
710
* Creates screen-aligned quad geometry for post-processing effects
711
* @param props - ScreenQuad configuration props
712
* @returns JSX element for screen quad mesh
713
*/
714
function ScreenQuad(props: ScreenQuadProps): JSX.Element;
715
716
interface ScreenQuadProps extends Omit<ThreeElements['mesh'], 'ref'> {
717
/** Material for the quad */
718
material?: Material;
719
}
720
```