File size: 35,700 Bytes
645859a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
# camera-controls

A camera control for three.js, similar to THREE.OrbitControls yet supports smooth transitions and more features.

[![Latest NPM release](https://img.shields.io/npm/v/camera-controls.svg)](https://www.npmjs.com/package/camera-controls) [![Open in GitHub Codespaces](https://img.shields.io/static/v1?label=GitHub&message=Open%20in%20%20Codespaces&color=24292f)](https://github.com/codespaces/new?template_repository=yomotsu%2Fcamera-controls)

[documentation](https://yomotsu.github.io/camera-controls/classes/CameraControls)

## Examples

| camera move    | default user input (Configurable) |
| ---            | ---                               |
| Orbit rotation | left mouse drag / touch: one-finger move |
| Dolly          | middle mouse drag, or mousewheel / touch: two-finger pinch-in or out |
| Truck (Pan)    | right mouse drag / touch: two-finger move or three-finger move |

- [basic](https://yomotsu.github.io/camera-controls/examples/basic.html)
- [fit-and-padding](https://yomotsu.github.io/camera-controls/examples/fit-and-padding.html)
- [fit-to-rect](https://yomotsu.github.io/camera-controls/examples/fit-to-rect.html)
- [fit-to-bounding-sphere](https://yomotsu.github.io/camera-controls/examples/fit-to-bounding-sphere.html)
- [infinity dolly](https://yomotsu.github.io/camera-controls/examples/infinity-dolly.html)
- [boundary](https://yomotsu.github.io/camera-controls/examples/boundary.html)
- [focal offset](https://yomotsu.github.io/camera-controls/examples/focal-offset.html)
- [click to set orbit point](https://yomotsu.github.io/camera-controls/examples/click-to-set-orbit-point.html)
- [look in the point direction](https://yomotsu.github.io/camera-controls/examples/look-in-direction.html)
- [viewport within the canvas](https://yomotsu.github.io/camera-controls/examples/viewport.html)
- [multiple camera-controls and viewport](https://yomotsu.github.io/camera-controls/examples/multiple.html)
- [z-up camera](https://yomotsu.github.io/camera-controls/examples/camera-up.html)
- [orthographic](https://yomotsu.github.io/camera-controls/examples/orthographic.html)
- [event attach / detach](https://yomotsu.github.io/camera-controls/examples/event-attach.html)
- [user input config](https://yomotsu.github.io/camera-controls/examples/config.html)
- [mouse drag with modifier keys](https://yomotsu.github.io/camera-controls/examples/mouse-drag-with-modifier-keys.html)
- [combined gestures](https://yomotsu.github.io/camera-controls/examples/combined-gestures.html)
- [keyboard events](https://yomotsu.github.io/camera-controls/examples/keyboard.html)
- [rest and sleep events](https://yomotsu.github.io/camera-controls/examples/rest-and-sleep.html)
- [changing the cursor](https://yomotsu.github.io/camera-controls/examples/cursor.html)
- [collision](https://yomotsu.github.io/camera-controls/examples/collision.html)
- [collision (custom)](https://yomotsu.github.io/camera-controls/examples/collision-custom.html)
- [first-person](https://yomotsu.github.io/camera-controls/examples/first-person.html)
- [third-person](https://yomotsu.github.io/meshwalk/examples/5_terrain.html) (with [meshwalk](https://github.com/yomotsu/meshwalk))
- [pointer lock](https://yomotsu.github.io/camera-controls/examples/pointer-lock.html)
- [auto rotate](https://yomotsu.github.io/camera-controls/examples/auto-rotate.html)
- [view offset translate](https://yomotsu.github.io/camera-controls/examples/view-offset.html)
- [camera shake effect](https://yomotsu.github.io/camera-controls/examples/effect-shake.html)
- [rotate with time duration and easing](https://yomotsu.github.io/camera-controls/examples/easing.html) (with [gsap](https://www.npmjs.com/package/gsap))
- [path animation](https://yomotsu.github.io/camera-controls/examples/path-animation.html) (with [gsap](https://www.npmjs.com/package/gsap))
- [complex transitions with `await`](https://yomotsu.github.io/camera-controls/examples/await-transitions.html)
- [set view padding](https://yomotsu.github.io/camera-controls/examples/padding-with-view-offset.html)
- [WebWorker (OffscreenCanvas)](https://yomotsu.github.io/camera-controls/examples/worker.html)
- [outside of iframe dragging](https://yomotsu.github.io/camera-controls/examples/iframe.html)
- [in react-three-fiber (simplest)](https://codesandbox.io/s/react-three-fiber-camera-controls-4jjor?file=/src/App.tsx)
- [in react-three-fiber (drei official)](https://codesandbox.io/s/sew669) (see [doc](https://github.com/pmndrs/drei#cameracontrols))

## Usage

(The below code is for three.js users. If you use react-three-fiber (aka R3F), r3f-ready camera-controls is available on [@react-three/drei](https://github.com/pmndrs/drei#cameracontrols)

```javascript
import * as THREE from 'three';
import CameraControls from 'camera-controls';

CameraControls.install( { THREE: THREE } );

// snip ( init three scene... )
const clock = new THREE.Clock();
const camera = new THREE.PerspectiveCamera( 60, width / height, 0.01, 1000 );
const cameraControls = new CameraControls( camera, renderer.domElement );

( function anim () {

	// snip
	const delta = clock.getDelta();
	const hasControlsUpdated = cameraControls.update( delta );

	requestAnimationFrame( anim );

	// you can skip this condition to render though
	if ( hasControlsUpdated ) {

		renderer.render( scene, camera );

	}

} )();
```

### Important!

You *must install* three.js before using camera-controls. Not doing so will lead to runtime errors (undefined references to THREE).

**Before creating a new CameraControls instance, call**:
```javascript
CameraControls.install( { THREE: THREE } );
```

You can then proceed to use CameraControls.

Note: If you do not wish to use the entire three.js to reduce file size(tree-shaking for example), make a subset to install.

```js
import {
	Vector2,
	Vector3,
	Vector4,
	Quaternion,
	Matrix4,
	Spherical,
	Box3,
	Sphere,
	Raycaster,
} from 'three';

const subsetOfTHREE = {
	Vector2   : Vector2,
	Vector3   : Vector3,
	Vector4   : Vector4,
	Quaternion: Quaternion,
	Matrix4   : Matrix4,
	Spherical : Spherical,
	Box3      : Box3,
	Sphere    : Sphere,
	Raycaster : Raycaster,
};

CameraControls.install( { THREE: subsetOfTHREE } );
```

## Constructor

`CameraControls( camera, domElement )`

- `camera` is a `THREE.PerspectiveCamera` or `THREE.OrthographicCamera` to be controlled.
- `domElement` is a `HTMLElement` for draggable area. (optional. if domElement is omitted here, can be connect later with `.connect()`)

## Terms

### Orbit rotations

CameraControls uses Spherical Coordinates for orbit rotations.

If your camera is Y-up, the Azimuthal angle will be the angle for y-axis rotation and the Polar angle will be the angle for vertical position.

![](https://raw.githubusercontent.com/yomotsu/camera-controls/dev/examples/fig1.svg)


### Dolly vs Zoom

- A Zoom involves changing the lens focal length. In three.js, zooming is actually changing the camera FOV, and the camera is stationary (doesn't move).
- A Dolly involves physically moving the camera to change the composition of the image in the frame.

See [the demo](https://github.com/yomotsu/camera-movement-comparison#dolly-vs-zoom)

## Properties

| Name                      | Type      | Default     | Description |
| ------------------------- | --------- | ----------- | ----------- |
| `.camera`                 | `THREE.Perspective \| THREE.Orthographic` | N/A | The camera to be controlled |
| `.enabled`                | `boolean` | `true`      | Whether or not the controls are enabled. |
| `.active`                 | `boolean` | `false`     | Returns `true` if the controls are active updating. |
| `.currentAction`          | `ACTION`  | N/A         | Getter for the current `ACTION`. |
| `.distance`               | `number`  | N/A         | Current distance. |
| `.minDistance`            | `number`  | `Number.EPSILON` | Minimum distance for dolly. The value must be higher than `0` |
| `.maxDistance`            | `number`  | `Infinity`  | Maximum distance for dolly. |
| `.minZoom` 	              | `number`  | `0.01`      | Minimum camera zoom. |
| `.maxZoom` 	              | `number`  | `Infinity`  | Maximum camera zoom. |
| `.polarAngle`             | `number`  | N/A         | Current polarAngle in radians. |
| `.minPolarAngle`          | `number`  | `0`         | In radians. |
| `.maxPolarAngle`          | `number`  | `Math.PI`   | In radians. |
| `.azimuthAngle`           | `number`  | N/A         | current azimuthAngle in radians ¹. |
| `.minAzimuthAngle`        | `number`  | `-Infinity` | In radians. |
| `.maxAzimuthAngle`        | `number`  | `Infinity`  | In radians. |
| `.boundaryFriction`       | `number`  | `0.0`       | Friction ratio of the boundary. |
| `.boundaryEnclosesCamera` | `boolean` | `false`     | Whether camera position should be enclosed in the boundary or not. |
| `.smoothTime`             | `number`  | `0.25`      | Approximate time in seconds to reach the target. A smaller value will reach the target faster. |
| `.draggingSmoothTime`     | `number`  | `0.125`     | The smoothTime while dragging. |
| `.azimuthRotateSpeed`     | `number`  | `1.0`       | Speed of azimuth rotation. |
| `.polarRotateSpeed`       | `number`  | `1.0`       | Speed of polar rotation. |
| `.dollySpeed`             | `number`  | `1.0`       | Speed of mouse-wheel dollying. |
| `.truckSpeed`             | `number`  | `2.0`       | Speed of drag for truck and pedestal. |
| `.dollyToCursor`          | `boolean` | `false`     | `true` to enable Dolly-in to the mouse cursor coords. |
| `.dollyDragInverted`      | `boolean` | `false`     | `true` to invert direction when dollying or zooming via drag. |
| `.interactiveArea`        | `DOMRect` | N/A         | Set drag-start, touches and wheel enable area in the domElement. each values are between `0` and `1` inclusive, where `0` is left/top and `1` is right/bottom of the screen. |
| `.colliderMeshes`         | `array`   | `[]`        | An array of Meshes to collide with camera ². |
| `.infinityDolly`          | `boolean` | `false`     | `true` to enable Infinity Dolly for wheel and pinch. Use this with `minDistance` and `maxDistance` ³. |
| `.restThreshold`          | `number`  | `0.0025`    | Controls how soon the `rest` event fires as the camera slows |

1. Every 360 degrees turn is added to `.azimuthAngle` value, which is accumulative.  
  `360º = 360 * THREE.MathUtils.DEG2RAD = Math.PI * 2`, `720º = Math.PI * 4`.  
  **Tip**: [How to normalize accumulated azimuthAngle?](#tips)
2. Be aware colliderMeshes may decrease performance. The collision test uses 4 raycasters from the camera since the near plane has 4 corners.
3. If the Dolly distance is less (or over) than the `minDistance` (or `maxDistance`), `infinityDolly` will keep the distance and pushes the target position instead.

## Events

CameraControls instance emits the following events.  
To subscribe, use `cameraControl.addEventListener( 'eventname', function )`.  
To unsubscribe, use `cameraControl.removeEventListener( 'eventname', function )`.

| Event name          | Timing |
| ------------------- | ------ |
| `'controlstart'`    | When the user starts to control the camera via mouse / touches. ¹ |
| `'control'`         | When the user controls the camera (dragging). |
| `'controlend'`      | When the user ends to control the camera. ¹ |
| `'transitionstart'` | When any kind of transition starts, either user control or using a method with `enableTransition = true` |
| `'update'`          | When the camera position is updated. |
| `'wake'`            | When the camera starts moving. |
| `'rest'`            | When the camera movement is below `.restThreshold` ². |
| `'sleep'`           | When the camera end moving. |

1. `mouseButtons.wheel` (Mouse wheel control) does not emit `'controlstart'` and `'controlend'`. `mouseButtons.wheel` uses scroll-event internally, and scroll-event happens intermittently. That means "start" and "end" cannot be detected.
2. Due to damping, `sleep` will usually fire a few seconds after the camera _appears_ to have stopped moving. If you want to do something (e.g. enable UI, perform another transition) at the point when the camera has stopped, you probably want the `rest` event. This can be fine tuned using the `.restThreshold` parameter. See the [Rest and Sleep Example](https://yomotsu.github.io/camera-controls/examples/rest-and-sleep.html).

## User input config

Working example: [user input config](https://yomotsu.github.io/camera-controls/examples/config.html)

| button to assign      | behavior |
| --------------------- | -------- |
| `mouseButtons.left`   | `CameraControls.ACTION.ROTATE`* \| `CameraControls.ACTION.TRUCK` \| `CameraControls.ACTION.SCREEN_PAN` \| `CameraControls.ACTION.OFFSET` \| `CameraControls.ACTION.DOLLY` \| `CameraControls.ACTION.ZOOM` \| `CameraControls.ACTION.NONE` |
| `mouseButtons.right`  | `CameraControls.ACTION.ROTATE` \| `CameraControls.ACTION.TRUCK`* \| `CameraControls.ACTION.SCREEN_PAN` \| `CameraControls.ACTION.OFFSET` \| `CameraControls.ACTION.DOLLY` \| `CameraControls.ACTION.ZOOM` \| `CameraControls.ACTION.NONE` |
| `mouseButtons.wheel` ¹ | `CameraControls.ACTION.ROTATE` \| `CameraControls.ACTION.TRUCK` \| `CameraControls.ACTION.SCREEN_PAN` \| `CameraControls.ACTION.OFFSET` \| `CameraControls.ACTION.DOLLY` \| `CameraControls.ACTION.ZOOM` \| `CameraControls.ACTION.NONE` |
| `mouseButtons.middle` ² | `CameraControls.ACTION.ROTATE` \| `CameraControls.ACTION.TRUCK` \| `CameraControls.ACTION.SCREEN_PAN` \| `CameraControls.ACTION.OFFSET` \| `CameraControls.ACTION.DOLLY`* \| `CameraControls.ACTION.ZOOM` \| `CameraControls.ACTION.NONE` |

1. Mouse wheel event for scroll "up/down" on mac "up/down/left/right"
2. Mouse click on wheel event "button"

- \* is the default.
- The default of `mouseButtons.wheel` is:
  - `DOLLY` for Perspective camera.
  - `ZOOM` for Orthographic camera, and can't set `DOLLY`.

| fingers to assign     | behavior |
| --------------------- | -------- |
| `touches.one` | `CameraControls.ACTION.TOUCH_ROTATE`* \| `CameraControls.ACTION.TOUCH_TRUCK` \| `CameraControls.ACTION.TOUCH_SCREEN_PAN` \| `CameraControls.ACTION.TOUCH_OFFSET` \| `CameraControls.ACTION.DOLLY` | `CameraControls.ACTION.ZOOM` | `CameraControls.ACTION.NONE` |
| `touches.two` | `ACTION.TOUCH_DOLLY_TRUCK` \| `ACTION.TOUCH_DOLLY_SCREEN_PAN` \| `ACTION.TOUCH_DOLLY_OFFSET` \| `ACTION.TOUCH_DOLLY_ROTATE` \| `ACTION.TOUCH_ZOOM_TRUCK` \| `ACTION.TOUCH_ZOOM_SCREEN_PAN` \| `ACTION.TOUCH_ZOOM_OFFSET` \| `ACTION.TOUCH_ZOOM_ROTATE` \| `ACTION.TOUCH_DOLLY` \| `ACTION.TOUCH_ZOOM` \| `CameraControls.ACTION.TOUCH_ROTATE` \| `CameraControls.ACTION.TOUCH_TRUCK` \| `CameraControls.ACTION.TOUCH_SCREEN_PAN` \| `CameraControls.ACTION.TOUCH_OFFSET` \| `CameraControls.ACTION.NONE` |
| `touches.three` | `ACTION.TOUCH_DOLLY_TRUCK` \| `ACTION.TOUCH_DOLLY_SCREEN_PAN` \| `ACTION.TOUCH_DOLLY_OFFSET` \| `ACTION.TOUCH_DOLLY_ROTATE` \| `ACTION.TOUCH_ZOOM_TRUCK` \| `ACTION.TOUCH_ZOOM_SCREEN_PAN` \| `ACTION.TOUCH_ZOOM_OFFSET` \| `ACTION.TOUCH_ZOOM_ROTATE` \| `CameraControls.ACTION.TOUCH_ROTATE` \| `CameraControls.ACTION.TOUCH_TRUCK` \| `CameraControls.ACTION.TOUCH_SCREEN_PAN` \| `CameraControls.ACTION.TOUCH_OFFSET` \| `CameraControls.ACTION.NONE` |

- \* is the default.
- The default of `touches.two` and `touches.three` is:
  - `TOUCH_DOLLY_TRUCK` for Perspective camera.
  - `TOUCH_ZOOM_TRUCK` for Orthographic camera, and can't set `TOUCH_DOLLY_TRUCK` and `TOUCH_DOLLY`.

## Methods

#### `rotate( azimuthAngle, polarAngle, enableTransition )`

Rotate azimuthal angle(horizontal) and polar angle(vertical).
Every value is added to the current value.

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `azimuthAngle`     | `number`  | Azimuth rotate angle. In radian. |
| `polarAngle`       | `number`  | Polar rotate angle. In radian. |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

If you want to rotate only one axis, put a angle for the axis to rotate, and `0` for another.
``` js
rotate( 20 * THREE.MathUtils.DEG2RAD, 0, true );
```

---

#### `rotateAzimuthTo( azimuthAngle, enableTransition )`

Rotate azimuthal angle(horizontal) to the given angle and keep the same polar angle(vertical) target.

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `azimuthAngle`     | `number`  | Azimuth rotate angle. In radian. |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

---

#### `rotatePolarTo( polarAngle, enableTransition )`

Rotate polar angle(vertical) to the given angle and keep the same azimuthal angle(horizontal) target.

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `polarAngle`       | `number`  | Polar rotate angle. In radian. |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

---

#### `rotateTo( azimuthAngle, polarAngle, enableTransition )`

Rotate azimuthal angle(horizontal) and polar angle(vertical) to the given angle.
Camera view will rotate over the orbit pivot absolutely:

Azimuth angle
```

         \
 90º -----+----- -90º
           \
           180º
```
0º front, 90º (`Math.PI / 2`) left, -90º (`- Math.PI / 2`) right, 180º (`Math.PI`) back

-----

Polar angle
```
     180º
      |
      90º
      |

```

180º (`Math.PI`) top/sky, 90º (`Math.PI / 2`) horizontal from view, 0º bottom/floor

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `azimuthAngle`     | `number`  | Azimuth rotate angle to. In radian. |
| `polarAngle`       | `number`  | Polar rotate angle to. In radian. |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

---

#### `dolly( distance, enableTransition )`

Dolly in/out camera position.

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `distance`         | `number`  | Distance of dollyIn |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

---

#### `dollyTo( distance, enableTransition )`

Dolly in/out camera position to given distance.

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `distance`         | `number`  | Distance of dollyIn |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

---

#### `dollyInFixed( distance, enableTransition )`

Dolly in, but does not change the distance between the target and the camera, and moves the target position instead.
Specify a negative value for dolly out.

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `distance`         | `number`  | Distance of dollyIn |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

---

#### `zoom( zoomStep, enableTransition )`

Zoom in/out camera. The value is added to camera zoom.  
Limits set with `.minZoom` and `.maxZoom`

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `zoomStep`         | `number`  | zoom scale |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

You can also make zoomIn function using `camera.zoom` property.
e.g.
``` js
const zoomIn  = () => cameraControls.zoom(   camera.zoom / 2, true );
const zoomOut = () => cameraControls.zoom( - camera.zoom / 2, true );
```

---

#### `zoomTo( zoom, enableTransition )`

Zoom in/out camera to given scale. The value overwrites camera zoom.  
Limits set with `.minZoom` and `.maxZoom`

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `zoom`             | `number`  | zoom scale |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |


---

#### `truck( x, y, enableTransition )`

Truck and pedestal camera using current azimuthal angle.

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `x`                | `number`  | Horizontal translate amount |
| `y`                | `number`  | Vertical translate amount |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

---

#### `lookInDirectionOf( x, y, z, enableTransition )`

Look in the given point direction.

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `x`                | `number`  | point x |
| `y`                | `number`  | point y |
| `z`                | `number`  | point z |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

#### `setFocalOffset( x, y, z, enableTransition )`

Set focal offset using the screen parallel coordinates.
`z` doesn't affect in Orthographic as with Dolly.

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `x`                | `number`  | Horizontal offset amount |
| `y`                | `number`  | Vertical offset amount |
| `z`                | `number`  | Depth offset amount. The result is the same as Dolly but unaffected by `minDistance` and `maxDistance` |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

---

#### `setOrbitPoint( targetX, targetY, targetZ )`

Set orbit point without moving the camera.

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `targetX`          | `number`  | Orbit center position x |
| `targetY`          | `number`  | Orbit center position y |
| `targetZ`          | `number`  | Orbit center position z |

---

#### `forward( distance, enableTransition )`

Move forward / backward.

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `distance`         | `number`  | Amount to move forward / backward. Negative value to move backward |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

---

#### `moveTo( x, y, z, enableTransition )`

Move `target` position to given point.

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `x`                | `number`  | x coord to move center position |
| `y`                | `number`  | y coord to move center position |
| `z`                | `number`  | z coord to move center position |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

---

#### `elevate( height, enableTransition )`

Move up / down.

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `height`           | `number`  | Amount to move up / down. Negative value to move down |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

---

#### `fitToBox( box3OrMesh, enableTransition, { paddingTop, paddingLeft, paddingBottom, paddingRight } )`

Fit the viewport to the box or the bounding box of the object, using the nearest axis. paddings are in unit.
set `cover: true` to fill enter screen.

| Name                    | Type                         | Description |
| ----------------------- | ---------------------------- | ----------- |
| `box3OrMesh`            | `THREE.Box3` \| `THREE.Mesh` | Axis aligned bounding box to fit the view. |
| `enableTransition`      | `boolean`                    | Whether to move smoothly or immediately |
| `options`               | `object`                     | Options |
| `options.cover`         | `boolean`                    | Whether fill enter screen or not. Default is `false` |
| `options.paddingTop`    | `number`                     | Padding top. Default is `0` |
| `options.paddingRight`  | `number`                     | Padding right. Default is `0` |
| `options.paddingBottom` | `number`                     | Padding bottom. Default is `0` |
| `options.paddingLeft`   | `number`                     | Padding left. Default is `0` |

---

#### `fitToSphere( sphereOrMesh, enableTransition )`

Fit the viewport to the sphere or the bounding sphere of the object.

| Name               | Type                           | Description |
| ------------------ | ------------------------------ | ----------- |
| `sphereOrMesh`     | `THREE.Sphere` \| `THREE.Mesh` | bounding sphere to fit the view. |
| `enableTransition` | `boolean`                      | Whether to move smoothly or immediately |

---

#### `setLookAt( positionX, positionY, positionZ, targetX, targetY, targetZ, enableTransition )`

Look at the `target` from the `position`.

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `positionX`        | `number`  | Camera position x. |
| `positionY`        | `number`  | Camera position y. |
| `positionZ`        | `number`  | Camera position z. |
| `targetX`          | `number`  | Orbit center position x. |
| `targetY`          | `number`  | Orbit center position y. |
| `targetZ`          | `number`  | Orbit center position z. |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

---

#### `lerpLookAt( positionAX, positionAY, positionAZ, targetAX, targetAY, targetAZ, positionBX, positionBY, positionBZ, targetBX, targetBY, targetBZ, t, enableTransition )`

Similar to `setLookAt`, but it interpolates between two states.

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `positionAX`       | `number`  | The starting position x of look at from. |
| `positionAY`       | `number`  | The starting position y of look at from. |
| `positionAZ`       | `number`  | The starting position z of look at from. |
| `targetAX`         | `number`  | The starting position x of look at. |
| `targetAY`         | `number`  | The starting position y of look at. |
| `targetAZ`         | `number`  | The starting position z of look at. |
| `positionBX`       | `number`  | Look at from position x to interpolate towards. |
| `positionBY`       | `number`  | Look at from position y to interpolate towards. |
| `positionBZ`       | `number`  | Look at from position z to interpolate towards. |
| `targetBX`         | `number`  | look at position x to interpolate towards. |
| `targetBY`         | `number`  | look at position y to interpolate towards. |
| `targetBZ`         | `number`  | look at position z to interpolate towards. |
| `t`                | `number`  | Interpolation factor in the closed interval. The value must be a number between `0` to `1` inclusive, where `1` is 100% |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

---

#### `setPosition( positionX, positionY, positionZ, enableTransition )`

Set angle and distance by given position.
An alias of `setLookAt()`, without target change. Thus keep gazing at the current target

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `positionX`        | `number`  | Position x of look at from. |
| `positionY`        | `number`  | Position y of look at from. |
| `positionZ`        | `number`  | Position z of look at from. |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

---

#### `setTarget( targetX, targetY, targetZ, enableTransition )`

Set the target position where gaze at.
An alias of `setLookAt()`, without position change. Thus keep the same position.

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `targetX`          | `number`  | Position x of look at. |
| `targetY`          | `number`  | Position y of look at. |
| `targetZ`          | `number`  | Position z of look at. |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

---

#### `setBoundary( box3? )`

Set the boundary box that encloses the target of the camera. `box3` is in `THREE.Box3`

| Name   | Type          | Description |
| ------ | ------------- | ----------- |
| `box3` | `THREE.Box3?` | Boundary area. No argument to remove the boundary. |

---

#### `setViewport( vector4? )`

Set (or unset) the current viewport.  
Set this when you want to use renderer viewport and [`.dollyToCursor`](#properties) feature at the same time.

See: [THREE.WebGLRenderer.setViewport()](https://threejs.org/docs/#api/en/renderers/WebGLRenderer.setViewport)

| Name      | Type             | Description |
| --------- | ---------------- | ----------- |
| `vector4` | `THREE.Vector4?` | Vector4 that represents the viewport, or `undefined` for unsetting this. |

#### `setViewport( x, y, width, height )`

Same as [`setViewport( vector4 )`](#setviewport-vector4-|-null-), but you can give it four numbers that represents a viewport instead:

| Name     | Type     | Description |
| -------- | -------- | ----------- |
| `x`      | `number` | Leftmost of the viewport. |
| `y`      | `number` | Bottommost of the viewport. |
| `width`  | `number` | Width of the viewport. |
| `height` | `number` | Height of the viewport. |

---

#### `getTarget( out, receiveEndValue )`

Returns the orbit center position, where the camera looking at.

| Name              | Type            | Description |
| ----------------- | --------------- | ----------- |
| `out`             | `THREE.Vector3` | The receiving Vector3 instance to copy the result |
| `receiveEndValue` | `boolean`       | Whether receive the transition end coords or current. default is `true` |

---

#### `getPosition( out, receiveEndValue )`

Returns the camera position.

| Name              | Type            | Description |
| ----------------- | --------------- | ----------- |
| `out`             | `THREE.Vector3` | The receiving Vector3 instance to copy the result |
| `receiveEndValue` | `boolean`       | Whether receive the transition end coords or current. default is `true` |

---

#### `getSpherical( out, receiveEndValue )`

Returns the spherical coordinates of the orbit.

| Name              | Type            | Description |
| ----------------- | --------------- | ----------- |
| `out`             | `THREE.Spherical` | The receiving Spherical instance to copy the result |
| `receiveEndValue` | `boolean`       | Whether receive the transition end coords or current. default is `true` |

---

#### `getFocalOffset( out, receiveEndValue )`

Returns the focal offset, which is how much the camera appears to be translated in screen parallel coordinates.

| Name              | Type            | Description |
| ----------------- | --------------- | ----------- |
| `out`             | `THREE.Vector3` | The receiving Vector3 instance to copy the result |
| `receiveEndValue` | `boolean`       | Whether receive the transition end coords or current. default is `true` |

---

#### `stop()`

stop all transitions.

---

#### `saveState()`

Set current camera position as the default position

---

#### `normalizeRotations()`

Normalize camera azimuth angle rotation between 0 and 360 degrees.

#### `reset( enableTransition )`

Reset all rotation and position to default.

| Name               | Type      | Description |
| ------------------ | --------- | ----------- |
| `enableTransition` | `boolean` | Whether to move smoothly or immediately |

---

#### `update( delta ): boolean`

Update camera position and directions. This should be called in your tick loop and returns `true` if re-rendering is needed.

| Name    | Type     | Description |
| ------- | -------- | ----------- |
| `delta` | `number` | Delta time between previous update call |

---

#### `updateCameraUp()`

When you change camera-up vector, run `.updateCameraUp()` to sync.

---

#### `applyCameraUp()`

Apply current camera-up direction to the camera.  
The orbit system will be re-initialized with the current position.

---

#### `connect()`

Attach all internal event handlers to enable drag control.

---

#### `disconnect()`

Detach all internal event handlers to disable drag control.

---

#### `dispose()`

Dispose the cameraControls instance itself, remove all eventListeners.

---

#### `addEventListener( type: string, listener: function )`

Adds the specified event listener.

---

#### `removeEventListener( type: string, listener: function )`

Removes the specified event listener.

---

#### `removeAllEventListeners( type: string )`

Removes all listeners for the specified type.

---

#### `toJSON()`

Get all state in JSON string

---

#### `fromJSON( json, enableTransition )`

Reproduce the control state with JSON. `enableTransition` is where anim or not in a boolean.

---

## Tips

### Normalize accumulated azimuth angle:
If you need a normalized accumulated azimuth angle (between 0 and 360 deg), compute with [THREE.MathUtils.euclideanModulo](https://threejs.org/docs/#api/en/math/MathUtils)
e.g.:
``` js
const TAU = Math.PI * 2;

function normalizeAngle( angle ) {

	return THREE.MathUtils.euclideanModulo( angle, TAU );

}

const normalizedAzimuthAngle = normalizeAngle( cameraControls.azimuthAngle );
```

---
### Find the absolute angle to shortest azimuth rotatation:
You may rotate 380deg but actually, you expect to rotate -20deg.  
To get the absolute angle, use the below:

```js
const TAU = Math.PI * 2;

function absoluteAngle( targetAngle, sourceAngle ){

  const angle = targetAngle - sourceAngle
  return THREE.MathUtils.euclideanModulo( angle + Math.PI, TAU ) - Math.PI;

}

console.log( absoluteAngle( 380 * THREE.MathUtils.DEG2RAD, 0 ) * THREE.MathUtils.RAD2DEG ); // -20deg
console.log( absoluteAngle( -1000 * THREE.MathUtils.DEG2RAD, 0 ) * THREE.MathUtils.RAD2DEG ); // 80deg
```

---
### Creating Complex Transitions

All methods that take the `enableTransition` parameter return a `Promise` can be used to create complex animations, for example:

``` js
async function complexTransition() {
	await cameraControls.rotateTo( Math.PI / 2, Math.PI / 4, true );
	await cameraControls.dollyTo( 3, true );
	await cameraControls.fitToSphere( mesh, true );
}
```

This will rotate the camera, then dolly, and finally fit to the bounding sphere of the `mesh`.

The speed and timing of transitions can be tuned using `.restThreshold` and `.smoothTime`.

If `enableTransition` is `false`, the promise will resolve immediately:

``` js
// will resolve immediately
await cameraControls.dollyTo( 3, false );
```

---

## V2 Migration Guide

camera-controls used to use simple damping for its smooth transition. camera-controls v2 now uses [SmoothDamp](https://docs.unity3d.com/ScriptReference/Mathf.SmoothDamp.html).
one of the benefits of using SmoothDamp is, SmoothDamp transition can be controlled with smoothTime which is approximately the time it will take to reach the end position.
Also, the Maximum speed of the transition can be set with `max speed`.

Due to the change, the following are needed.
(if you haven't changed `dampingFactor` and `draggingDampingFactor` in v1.x, nothing is needed)

deprecated
- `dampingFactor` (use smoothTime instead)
- `draggingDampingFactor` (use draggingSmoothTime instead)

added
- `smoothTime`
- `draggingSmoothTime`
- `maxSpeed`

...That's it!

## Contributors

This project exists thanks to all the people who contribute.

![](https://contributors-img.web.app/image?repo=yomotsu/camera-controls)


## Release

Pre-requisites:
1. a npm registry up and running with a [`NPM_TOKEN`](https://docs.npmjs.com/creating-and-viewing-access-tokens)
   ```sh
	$ export NPM_TOKEN=npm_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
	 ```
2. a Github [PAT](https://github.com/semantic-release/github#github-authentication)
   ```sh
	 $ export GITHUB_TOKEN=github_pat_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
	 ```

```sh
$ npm run release -- --dry-run
```