PositionComposer

Moves the camera to keep a target at a spot on screen.

Moves the camera, without rotating it, so the target stays at screenPosition and cameraDistance away. With a deadZone the target can move freely inside it before the camera reacts.

It's made for cameras that keep a fixed rotation, like top-down or side-scrolling games, so it's usually used without an Aim. The rotation then comes from the camera's initialState.

It works with an orthographic camera too. The screen then spans orthographicSize at any distance, so cameraDistance only sets how far back the camera sits.

The zones react to the target's edge, not just its center, so its size matters. klipp.setSize keeps the screen proportions in sync with your viewport.

Settings

SettingDescriptionDefault
targetWhat to frame. See Targets.
targetOffsetOffset from the target, in the target's own space. Use it to frame a head instead of the feet.[0, 0, 0]
cameraDistanceDistance from the camera to the target, along the view direction.10
screenPositionWhere the target should be on screen. [0, 0] is the center, ±1 the edges, with +y up.[0, 0]
deadZoneHow far the target can drift from screenPosition to each side before the camera reacts, in the same units: [0.2, 0.1] is a box 0.4 wide and 0.2 tall.[0, 0]
hardLimitHow far the target can ever drift from screenPosition to each side, even while damping is catching up. [0, 0] turns it off.[0, 0]
depthDeadZoneHow far the target can move toward or away from the camera before it reacts, in world units.0
dampingSeconds to catch up once the target leaves the dead zone. See Damping.0
maxSpeedMaximum catch-up speed, in units per second.Infinity
lookaheadTimeSeconds to look ahead of a moving target. See below.0
lookaheadSmoothingSeconds used to smooth the target's measured speed for lookahead.1
lookaheadIgnoreYOnly look ahead horizontally, handy for jumping characters.false
radiusthree.js and React. The target's radius. On the core, set the target's extent.
sizethree.js and React. The target's box size, used instead of radius.measured for meshes
debugReact only. Draws the zones on screen. See Debugging.false

Lookahead

With lookaheadTime, the camera frames where the target is going to be instead of where it is, so fast targets get room in front of them.

Combining with an Aim

Avoid Aims that recenter the target every frame, like HardLookAt: they cancel out the dead zone and screenPosition. Use one of these instead:

Usage

import { PositionComposerBody, targetPose } from '@pmndrs/klipp';

const player = targetPose.create(); // keep player.position up to date
player.extent.radius = 0.5; // so the zones react to its edge
camera.body = new PositionComposerBody(player, { cameraDistance: 12, deadZone: [0.3, 0.2], damping: 0.3 });

The target's size comes from player.extent: a radius, or a box size with hasSize set. Its rotation is only used for targetOffset.

Lookahead

camera.body = new PositionComposerBody(player, { lookaheadTime: 0.4, lookaheadIgnoreY: true });