PositionComposer
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
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:
- no Aim, for a fixed rotation,
RotateWithFollowTarget,RotationComposerwith the samescreenPosition, and a non-zerodeadZoneon both.
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 });
import { PositionComposerBodyThree } from '@pmndrs/klipp/three';
camera.body = new PositionComposerBodyThree(player, { cameraDistance: 12, deadZone: [0.3, 0.2], damping: 0.3 });
For meshes, the target's size is measured from its geometry. If the shape changes (an animated skinned mesh, for example), call recalculateSize() to measure it again.
Lookahead
camera.body = new PositionComposerBodyThree(player, { lookaheadTime: 0.4, lookaheadIgnoreY: true });
<VirtualCamera name="platformer" priority={10}>
<Body.PositionComposer target={playerRef} cameraDistance={12} deadZone={[0.3, 0.2]} damping={0.3} />
</VirtualCamera>
For meshes, the target's size is measured from its geometry. ref gives you the PositionComposerBodyThree: if the shape changes (an animated skinned mesh, for example), call recalculateSize() to measure it again.
Lookahead
<Body.PositionComposer target={playerRef} lookaheadTime={0.4} lookaheadIgnoreY />