npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ggabcd-camera-controls

v1.34.2

Published

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

Downloads

9

Readme

camera-controls

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

Latest NPM release

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 |

Usage

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:

CameraControls.install( { THREE: THREE } );

You can then proceed to use CameraControls.

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

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

const subsetOfTHREE = {
	MOUSE     : MOUSE,
	Vector2   : Vector2,
	Vector3   : Vector3,
	Vector4   : Vector4,
	Quaternion: Quaternion,
	Matrix4   : Matrix4,
	Spherical : Spherical,
	Box3      : Box3,
	Sphere    : Sphere,
	Raycaster : Raycaster,
	MathUtils : {
		DEG2RAD: MathUtils.DEG2RAD,
		clamp: MathUtils.clamp,
	},
};

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.

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.

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

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 | 0 | 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. | | .dampingFactor | number | 0.05 | The damping inertia. The value must be between Math.EPSILON to 1 inclusive. Setting 1 to disable smooth transitions. | | .draggingDampingFactor | number | 0.25 | The damping inertia while dragging. The value must be between Math.EPSILON to 1 inclusive. Setting 1 to disable smooth transitions. | | .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. | | .verticalDragToForward | boolean | false | The same as .screenSpacePanning in three.js's OrbitControls. | | .dollyToCursor | boolean | false | true to enable Dolly-in to the mouse cursor coords. | | .colliderMeshes | array | [] | An array of Meshes to collide with camera ². | | .infinityDolly | boolean | false | true to enable Infinity Dolly ³. | | .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?
  2. Be aware colliderMeshes may decrease performance. The collision test uses 4 raycasters from the camera since the near plane has 4 corners.
  3. When the Dolly distance is less than the minDistance, radius of the sphere will be set minDistance automatically.

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.

User input config

Working example: user input config

| button to assign | behavior | | --------------------- | -------- | | mouseButtons.left | CameraControls.ACTION.ROTATE* | CameraControls.ACTION.TRUCK | CameraControls.ACTION.OFFSET | CameraControls.ACTION.DOLLY | CameraControls.ACTION.ZOOM | CameraControls.ACTION.NONE | | mouseButtons.right | CameraControls.ACTION.ROTATE | CameraControls.ACTION.TRUCK* | CameraControls.ACTION.OFFSET | CameraControls.ACTION.DOLLY | CameraControls.ACTION.ZOOM | CameraControls.ACTION.NONE | | mouseButtons.shiftLeft | CameraControls.ACTION.ROTATE | CameraControls.ACTION.TRUCK | CameraControls.ACTION.OFFSET | CameraControls.ACTION.DOLLY | CameraControls.ACTION.ZOOM | CameraControls.ACTION.NONE* | | mouseButtons.wheel ¹ | CameraControls.ACTION.ROTATE | CameraControls.ACTION.TRUCK | CameraControls.ACTION.OFFSET | CameraControls.ACTION.DOLLY | CameraControls.ACTION.ZOOM | CameraControls.ACTION.NONE | | mouseButtons.middle ² | CameraControls.ACTION.ROTATE | CameraControls.ACTION.TRUCK | 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_OFFSET | CameraControls.ACTION.DOLLY | CameraControls.ACTION.ZOOM | CameraControls.ACTION.NONE | | touches.two | ACTION.TOUCH_DOLLY_TRUCK | ACTION.TOUCH_DOLLY_OFFSET | ACTION.TOUCH_ZOOM_TRUCK | ACTION.TOUCH_ZOOM_OFFSET | ACTION.TOUCH_DOLLY | ACTION.TOUCH_ZOOM | CameraControls.ACTION.TOUCH_ROTATE | CameraControls.ACTION.TOUCH_TRUCK | CameraControls.ACTION.TOUCH_OFFSET | CameraControls.ACTION.NONE | | touches.three | ACTION.TOUCH_DOLLY_TRUCK | ACTION.TOUCH_DOLLY_OFFSET | ACTION.TOUCH_ZOOM_TRUCK | ACTION.TOUCH_ZOOM_OFFSET | CameraControls.ACTION.TOUCH_ROTATE | CameraControls.ACTION.TOUCH_TRUCK | 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.

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

      0º
      |
90º -- -- -90º
      |
     180º

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


Polar angle

     180º
      |
      90º
      |
      0º

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 |


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.

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 |


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 |


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.

| 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.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 )

Make an orbit with given points.

| 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 )

setLookAt without target, 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 )

setLookAt without position, Stay still at the 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
Returns its current position.

| 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 feature at the same time.

See: THREE.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 ), 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. |


getPosition( out )

Returns its current position.

| Name | Type | Description | | ----- | --------------- | ----------- | | out | THREE.Vector3 | The receiving vector |


getTarget( out )

Returns its current gazing target, which is the center position of the orbit.

| Name | Type | Description | | ----- | --------------- | ----------- | | out | THREE.Vector3 | The receiving vector |


getFocalOffset( out )

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

| Name | Type | Description | | ----- | --------------- | ----------- | | out | THREE.Vector3 | The receiving vector |


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.


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.


dispose()

Dispose the cameraControls instance itself, remove all eventListeners.


Tips

Normalize accumulated azimuth angle:

If you need a normalized accumulated azimuth angle (between 0 and 360 deg), compute with THREE.MathUtils.euclideanModulo e.g.:

const normalizedAzimuthAngle = THREE.MathUtils.euclideanModulo( cameraControls.azimuthAngle, 360 * THREE.MathUtils.DEG2RAD );

Creating Complex Transitions

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

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 .dampingFactor.

If enableTransition is false, the promise will resolve immediately:

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

Breaking changes

@1.16.0 dolly() will take opposite value. e.g. dolly-in to dolly( 1 ) (used be dolly-in to dolly( -1 ))

Contributors

This project exists thanks to all the people who contribute.