Core concepts

Virtual cameras, priority, the pieces that build a shot, and targets.

Virtual cameras

A virtual camera is a shot you might want to show. You can have as many as you like. Klipp decides which one is on screen:

  • the active camera with the highest priority wins,
  • an inactive camera is out of the running completely,
  • when the winner changes, Klipp blends from the old shot to the new one.

Building a shot

Each camera is made of up to four kinds of pieces, which run in this order every frame:

PieceWhat it doesHow manyExamples
BodyMoves the cameraoneFollow, OrbitFollow, PositionComposer
AimRotates the cameraoneHardLookAt, RotationComposer
ExtensionAdjusts the shotanyGroupFraming, Lens
NoiseAdds shake on topanyBasicMultiChannelPerlin, ImpulseListener

A few Extensions run earlier, because the Body or Aim works with what they set: Lens runs first, and FollowZoom and Confiner right after the Body. See Extensions.

Body and Aim are independent, so a camera can follow one object while looking at another. Every piece is optional: a camera without an Aim keeps its starting rotation.

One piece in every integration

Every piece is a core class. Integrations adapt it to their world: in three.js, FollowBodyThree is FollowBody reading Object3D targets, and the React <Body.Follow> creates one for you. Settings have the same names everywhere.

Targets

Pieces follow and look at targets:

  • Core: the core doesn't know about your scene. A target is a TargetPose you keep up to date from wherever your data lives: position, and rotation with hasRotation. Pieces that frame by size, like the composers, also read its extent.
  • three.js and React Three Fiber: a target is an Object3D, a ref to one, or a fixed point: a Vector3 or [x, y, z]. Objects are tracked live, including their rotation.

A target of null, or a ref that is still empty, is ignored until it resolves.

Damping

Most pieces take a damping setting that makes them ease toward their goal instead of snapping to it. It's a time in seconds: 0 is instant, 0.5 feels smooth, 2 feels heavy.

Pass { into, from } to ease differently while the gap is growing (into) and while it's closing again (from).

Next to damping you'll usually find maxSpeed, which caps how fast the camera may move while catching up.

Changing settings while running

Settings are plain fields, so you can change them at any time, even every frame. Vector fields are always [x, y, z] arrays. In React, ref gives you the piece itself, so you can change it without re-rendering.

Usage

Feeding a target:

import { quat, vec3 } from 'math';
import { targetPose } from '@pmndrs/klipp';

const player = targetPose.create();
player.extent.radius = 0.5; // for pieces that frame by size

// every frame, before klipp.update
vec3.copy(player.position, playerPosition);
quat.copy(player.rotation, playerRotation);
player.hasRotation = true;

Ready to build one? Continue with Your first camera.