Position, Rotation, and Scale

The three fundamental transforms

Transforming Objects in 3D Space

Every object in Three.js has three fundamental properties that control where it is and how it appears: position, rotation, and scale. These are all inherited from Object3D, so they work the same way for meshes, groups, lights, and cameras.

Position

Position is a Vector3 that defines where an object sits in 3D space. The three axes are:

  • X - Left/Right (positive = right)
  • Y - Up/Down (positive = up)
  • Z - Forward/Back (positive = toward camera)
typescript
// Set position properties individually
mesh.position.x = 2;
mesh.position.y = 1;
mesh.position.z = -3;

// Or use the set() method
mesh.position.set(2, 1, -3);

// Position is a Vector3, so you can use vector methods
mesh.position.copy(otherMesh.position);
mesh.position.add(new THREE.Vector3(1, 0, 0));
mesh.position.multiplyScalar(2);

// Get distance from another point
const distance = mesh.position.distanceTo(camera.position);

// Get length (distance from origin)
const length = mesh.position.length();

Rotation

Rotation uses Euler angles by default - three values representing rotation around each axis, measured in radians (not degrees). A full rotation is Math.PI * 2 (approximately 6.28).

typescript
// Rotate around each axis (in radians)
mesh.rotation.x = Math.PI / 4;  // 45 degrees
mesh.rotation.y = Math.PI / 2;  // 90 degrees
mesh.rotation.z = Math.PI;      // 180 degrees

// Use set() for all at once
mesh.rotation.set(0, Math.PI / 4, 0);

// Convert degrees to radians
const degrees = 45;
mesh.rotation.y = THREE.MathUtils.degToRad(degrees);

// Rotation order matters! Default is 'XYZ'
mesh.rotation.order = 'YXZ'; // Rotate Y first, then X, then Z

The order that rotations are applied matters. If you're getting unexpected results, try changing rotation.order. For character controllers, 'YXZ' is often more intuitive.

Quaternions

For complex rotations or smooth interpolation, use quaternions instead of Euler angles. They avoid "gimbal lock" (where axes align and you lose a degree of freedom):

typescript
// Set rotation using quaternion
mesh.quaternion.setFromAxisAngle(
  new THREE.Vector3(0, 1, 0),  // axis to rotate around
  Math.PI / 4                   // angle in radians
);

// Smoothly interpolate between rotations
mesh.quaternion.slerp(targetQuaternion, 0.1);

// Look at a point (uses quaternion internally)
mesh.lookAt(0, 0, 0);
mesh.lookAt(targetMesh.position);

Scale

Scale multiplies the size of an object along each axis. A scale of 1 is the original size, 2 is double, 0.5 is half.

typescript
// Scale each axis independently
mesh.scale.x = 2;   // Stretch horizontally
mesh.scale.y = 0.5; // Squash vertically
mesh.scale.z = 1;   // Keep depth the same

// Uniform scaling (same on all axes)
mesh.scale.set(1.5, 1.5, 1.5);
// or
mesh.scale.setScalar(1.5);

// Scale is also a Vector3
mesh.scale.multiplyScalar(2); // Double the current scale

Combining Transforms

You can combine all three transforms on a single object. Internally, Three.js combines these into a transformation matrix:

typescript
// All transforms together
mesh.position.set(2, 0, 0);
mesh.rotation.set(0, Math.PI / 4, 0);
mesh.scale.set(1, 2, 1);

// The order of operations is always:
// 1. Scale
// 2. Rotate
// 3. Translate (position)

// Force matrix update (usually automatic)
mesh.updateMatrix();

// Access the combined transformation matrix
console.log(mesh.matrix);

Helper Methods

Three.js provides convenient methods for relative transforms:

typescript
// Translate relative to current position
mesh.translateX(1);  // Move 1 unit along local X axis
mesh.translateY(2);  // Move 2 units along local Y axis
mesh.translateZ(-1); // Move 1 unit along local Z axis

// These respect the object's rotation!
// translateZ moves forward relative to where the object is facing

// Rotate relative to current rotation
mesh.rotateX(0.1);
mesh.rotateY(0.1);
mesh.rotateZ(0.1);

// Rotate around world axis (not local)
mesh.rotateOnWorldAxis(new THREE.Vector3(0, 1, 0), 0.1);

// Point at something
mesh.lookAt(target.position);
camera.lookAt(scene.position);

Local vs World Space

Remember that transforms are relative to the parent. To get or set world-space values:

typescript
// Get world position (accounting for all parents)
const worldPos = new THREE.Vector3();
mesh.getWorldPosition(worldPos);

// Get world rotation
const worldQuat = new THREE.Quaternion();
mesh.getWorldQuaternion(worldQuat);

// Get world scale
const worldScale = new THREE.Vector3();
mesh.getWorldScale(worldScale);

// Convert between local and world
const localPoint = new THREE.Vector3(1, 0, 0);
const worldPoint = mesh.localToWorld(localPoint.clone());
const backToLocal = mesh.worldToLocal(worldPoint.clone());
←   Parent-Child RelationshipsGeometries   →