threejs-syntax-controls
Quick Reference
Control Selection Decision Tree
| Use Case | Control | Why | |----------|---------|-----| | Inspect a 3D model from all angles | OrbitControls | Orbit/pan/zoom around a target point | | Top-down map or 2D-style navigation | MapControls | Left-drag pans, right-drag rotates | | Free-flight editor or space scene | FlyControls | Six degrees of freedom, WASD + mouse | | First-person game with pointer lock | PointerLockControls | Hides cursor, captures mouse movement | | First-person without pointer lock | FirstPersonControls | Mouse-look without browser lock API | | Move/rotate/scale objects via gizmo | TransformControls | Interactive translate/rotate/scale handles | | Drag objects along a plane | DragControls | Click-and-drag object repositioning | | Unconstrained rotation (no gimbal lock) | ArcballControls | Full spherical rotation with animation | | Unconstrained rotation (simpler) | TrackballControls | Like OrbitControls but no pole constraint |
Import Paths (Three.js r160+)
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { MapControls } from 'three/addons/controls/MapControls.js';
import { FlyControls } from 'three/addons/controls/FlyControls.js';
import { FirstPersonControls } from 'three/addons/controls/FirstPersonControls.js';
import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js';
import { TransformControls } from 'three/addons/controls/TransformControls.js';
import { TrackballControls } from 'three/addons/controls/TrackballControls.js';
import { ArcballControls } from 'three/addons/controls/ArcballControls.js';
import { DragControls } from 'three/addons/controls/DragControls.js';
ALWAYS use 'three/addons/controls/...' for r160+. The legacy path 'three/examples/jsm/controls/...' still works but is deprecated.
Critical Warnings
ALWAYS call controls.update() in the animation loop when enableDamping or autoRotate is true. Failing to do so causes the camera to freeze after user interaction ends.
ALWAYS call controls.dispose() when removing controls. Failing to do so leaks DOM event listeners (pointermove, wheel, keydown) that cause memory leaks and ghost interactions.
NEVER attach two camera-control classes to the same camera simultaneously without disabling one. OrbitControls + FlyControls on the same camera causes erratic movement.
ALWAYS disable OrbitControls while TransformControls is dragging. Listen to the dragging-changed event and toggle orbitControls.enabled.
ALWAYS call PointerLockControls.lock() from a user gesture (click handler). Browsers reject pointer lock requests without user interaction.
ALWAYS pass delta time to FlyControls.update(delta). Passing no argument or passing elapsed time causes speed to depend on frame rate.
Controls Lifecycle
Every control follows the same lifecycle pattern:
construct --> configure --> attach to loop --> dispose on cleanup
Step 1: Construct
const controls = new OrbitControls(camera, renderer.domElement);
ALWAYS pass renderer.domElement as the second argument. Passing document or document.body causes controls to capture events globally, breaking UI overlays.
Step 2: Configure
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.minDistance = 2;
controls.maxDistance = 50;
controls.target.set(0, 1, 0);
Step 3: Update in Render Loop
function animate() {
requestAnimationFrame(animate);
controls.update(); // REQUIRED when enableDamping or autoRotate is true
renderer.render(scene, camera);
}
animate();
Step 4: Dispose on Cleanup
controls.dispose();
OrbitControls
The most commonly used control. Orbits, pans, and zooms around a target point.
Constructor
new OrbitControls(camera: THREE.Camera, domElement: HTMLElement)
Key Properties
| Property | Type | Default | Description | |----------|------|---------|-------------| | enabled | boolean | true | Enable/disable all interaction | | target | Vector3 | (0,0,0) | Orbit focus point | | enableDamping | boolean | false | Smooth inertial movement | | dampingFactor | number | 0.05 | Inertia strength (0-1) | | autoRotate | boolean | false | Auto-rotate around target | | autoRotateSpeed | number | 2.0 | Degrees/sec at 60fps | | enablePan | boolean | true | Allow panning | | enableRotate | boolean | true | Allow rotation | | enableZoom | boolean | true | Allow zooming | | minDistance | number | 0 | Min zoom distance (PerspectiveCamera) | | maxDistance | number | Infinity | Max zoom distance (PerspectiveCamera) | | minZoom | number | 0 | Min zoom (OrthographicCamera) | | maxZoom | number | Infinity | Max zoom (OrthographicCamera) | | minPolarAngle | number | 0 | Min vertical angle (radians) | | maxPolarAngle | number | Math.PI | Max vertical angle (radians) | | minAzimuthAngle | number | -Infinity | Min horizontal angle (radians) | | maxAzimuthAngle | number | Infinity | Max horizontal angle (radians) | | screenSpacePanning | boolean | true | Pan in screen plane (true) or horizontal plane (false) | | zoomToCursor | boolean | false | Zoom towards cursor position | | panSpeed | number | 1.0 | Pan speed multiplier | | rotateSpeed | number | 1.0 | Rotation speed multiplier | | zoomSpeed | number | 1.0 | Zoom speed multiplier | | mouseButtons | object | {LEFT: ROTATE, MIDDLE: DOLLY, RIGHT: PAN} | Mouse button mapping | | touches | object | {ONE: ROTATE, TWO: DOLLY_PAN} | Touch gesture mapping | | keys | object | {LEFT, UP, RIGHT, BOTTOM} | Arrow key codes for panning |
Methods
| Method | Signature | Description | |--------|-----------|-------------| | update(deltaTime?) | (number?) => boolean | Update controls state. MUST call every frame with damping/autoRotate | | dispose() | () => void | Remove all event listeners | | saveState() | () => void | Save current camera position/target/zoom | | reset() | () => void | Restore to last saved state | | getDistance() | () => number | Distance from camera to target | | getPolarAngle() | () => number | Vertical angle in radians | | getAzimuthalAngle() | () => number | Horizontal angle in radians | | listenToKeyEvents(el) | (HTMLElement) => void | Enable keyboard panning | | stopListenToKeyEvents() | () => void | Disable keyboard panning |
Events
| Event | Trigger | |-------|---------| | change | Camera position or target changed | | start | User interaction began (pointerdown) | | end | User interaction ended (pointerup) |
MapControls
Subclass of OrbitControls optimized for top-down map navigation.
| Button | OrbitControls | MapControls | |--------|--------------|-------------| | Left mouse | Rotate | Pan | | Middle mouse | Dolly | Dolly | | Right mouse | Pan | Rotate |
All properties, methods, and events are identical to OrbitControls. The ONLY differences are the default mouseButtons mapping and screenSpacePanning defaulting to true.
FlyControls
Six-degrees-of-freedom flight camera. WASD for movement, QE for roll, RF for up/down.
Key Properties
| Property | Type | Default | Description | |----------|------|---------|-------------| | movementSpeed | number | 1.0 | Translation speed | | rollSpeed | number | 0.005 | Roll rotation speed | | dragToLook | boolean | false | Require mouse drag to rotate (vs. always follow mouse) | | autoForward | boolean | false | Move forward automatically |
Methods
update(delta)-- ALWAYS passdeltatime from the clock. NEVER omit this argument.dispose()-- Remove event listeners.
PointerLockControls
First-person camera using the Pointer L