Introduction
Summary
Describe the shots you want. Klipp picks the right one and smoothly blends between them.
pnpm add @pmndrs/klippEarly-stage and experimental. The API may still change.
See it in action on the examples site.
Why Klipp?
Most 3D projects rebuild the same camera code: an offset that follows the player, damping, a dead zone, a cutscene camera and a smooth way back. Klipp brings the virtual camera model from engines like Unity to the web: each shot is described on its own, the one with the highest priority is on screen, and switching between shots is a blend.
One system, any renderer
The core is a complete camera system with no renderer or framework attached. Integrations are thin layers on top of it: three.js and React Three Fiber today, with more to come, like TresJS. Each page shows the core and every integration in tabs.
What it looks like
A follow camera, and a cutscene camera that takes over when it turns on. Turning it off blends back.
import { vec3 } from 'math';
import { Klipp, FollowBody, HardLockToTargetBody, HardLookAtAim, targetPose, VirtualCamera } from '@pmndrs/klipp';
const klipp = new Klipp();
const player = targetPose.create(); // keep player.position up to date
const spot = targetPose.create();
vec3.set(spot.position, 10, 2, 0);
const follow = new VirtualCamera('follow', { priority: 10 });
klipp.add(follow);
follow.body = new FollowBody(player, { offset: [0, 3, 8], damping: 0.5 });
follow.aim = new HardLookAtAim(player);
const cutscene = new VirtualCamera('cutscene', { priority: 20, active: false });
klipp.add(cutscene);
cutscene.body = new HardLockToTargetBody(spot);
cutscene.aim = new HardLookAtAim(player);
// every frame
klipp.update(dt);
engineCamera.setPosition(klipp.shot.position);
engineCamera.setRotation(klipp.shot.quaternion);
import { Vector3 } from 'three';
import { KlippThree, FollowBodyThree, HardLockToTargetBodyThree, HardLookAtAimThree, VirtualCameraThree } from '@pmndrs/klipp/three';
const klipp = new KlippThree(camera);
const follow = new VirtualCameraThree('follow', { priority: 10 });
klipp.add(follow);
follow.body = new FollowBodyThree(player, { offset: new Vector3(0, 3, 8), damping: 0.5 });
follow.aim = new HardLookAtAimThree(player);
const cutscene = new VirtualCameraThree('cutscene', { priority: 20, active: false });
klipp.add(cutscene);
cutscene.body = new HardLockToTargetBodyThree(new Vector3(10, 2, 0));
cutscene.aim = new HardLookAtAimThree(player);
// every frame, before rendering
klipp.update(dt);
import { Klipp, VirtualCamera, Body, Aim } from '@pmndrs/klipp/react';
<Klipp>
<VirtualCamera name="follow" priority={10}>
<Body.Follow target={playerRef} offset={[0, 3, 8]} damping={0.5} />
<Aim.HardLookAt target={playerRef} />
</VirtualCamera>
<VirtualCamera name="cutscene" priority={20} active={isCutscene}>
<Body.HardLockToTarget target={[10, 2, 0]} />
<Aim.HardLookAt target={playerRef} />
</VirtualCamera>
</Klipp>
Next steps
- Installation
- Core concepts
- Your first camera
- Building on the core, for your own integration or for data and functions