Camera Systems
The @web-engine-dev/camera package provides a flexible camera system supporting 2D follow cams, 3D perspective/orthographic cameras, smooth transitions, screen shake, zoom, and multi-player split-screen.
Setting Up a 2D Camera
The camera package is not component-based - it provides plain TypeScript classes. Create a CameraController, set a follow target, and call update() each frame:
import { CameraController } from '@web-engine-dev/camera';
const player = { position: { x: 0, y: 0 } }; // any object with { position: Vec2 }
const camera = new CameraController()
.setFollowTarget(player)
.setSmoothing(5) // higher = smoother/slower follow
.setOffset({ x: 0, y: -50 })
.setBounds({ minX: 0, minY: 0, maxX: 4096, maxY: 2048 });
// Every frame:
function update(deltaTime: number): void {
camera.update(deltaTime);
const { position, zoom, rotation } = camera.getState();
// Apply position/zoom/rotation to your renderer
}Any object that has a position: { x: number; y: number } property can serve as the follow target.
Camera Zones
For boss rooms or vertical-scroll sections you can temporarily override the target or bounds:
// Lock camera in place for a boss room
camera.setBounds({ minX: 2000, minY: 500, maxX: 3280, maxY: 1220 });
// Restore world bounds after boss is defeated
camera.setBounds({ minX: 0, minY: 0, maxX: 4096, maxY: 2048 });Zoom
Zoom is a property on the camera state. Set it via the controller:
// Instant change
camera.setZoom(1.5);
// Read current state
const { zoom } = camera.getState();Screen Shake
CameraController has built-in shake support. Trigger it directly:
// Trigger a one-shot shake
camera.triggerShake({ intensity: 10, duration: 0.3 });
// Preset shakes for common events
import { ShakePresets } from '@web-engine-dev/camera';
camera.triggerShake(ShakePresets.lightImpact()); // light hit
camera.triggerShake(ShakePresets.heavyImpact()); // explosion
camera.triggerShake(ShakePresets.earthquake()); // continuous
camera.triggerShake(ShakePresets.recoil()); // weapon recoilFor a standalone shake without a follow camera, use CameraShake:
import { CameraShake } from '@web-engine-dev/camera';
const shake = new CameraShake();
// shake.update(deltaTime);
// share shake.offset with your rendererCinematic Sequences
The CinematicCamera follows a list of waypoints with easing:
import { CinematicCamera } from '@web-engine-dev/camera';
const cutscene = new CinematicCamera()
.addWaypoint({ position: { x: 0, y: 0 }, duration: 0 })
.addWaypoint({ position: { x: 100, y: 50 }, duration: 2, zoom: 1.5 })
.addWaypoint({ position: { x: 200, y: 0 }, duration: 1.5, pause: 1 })
.onComplete(() => resumeGameplay())
.setLoop(false)
.play();
// Call every frame while it plays:
cutscene.update(deltaTime);
const { position, zoom } = cutscene.getState();3D Cameras
The package provides TypeScript config/state interfaces for 3D cameras, not concrete component classes. Use factory functions to create configs with sensible defaults:
import {
createOrbitControllerConfig,
createFlyControllerConfig,
createFollow3DControllerConfig,
createPerspectiveProjection,
createCamera3DState,
} from '@web-engine-dev/camera';
// Orbit camera
const orbitConfig = createOrbitControllerConfig({ distance: 20 });
// Free-fly FPS camera
const flyConfig = createFlyControllerConfig({ invertY: true });
// Third-person spring follow
const followConfig = createFollow3DControllerConfig({ mode: 'spring' });
// Perspective projection
const projection = createPerspectiveProjection({ fov: Math.PI / 3 });
// Initial camera state
const state = createCamera3DState({ position: { x: 0, y: 5, z: 10 } });Wire these into your renderer directly.
Presets
import { CameraPresets } from '@web-engine-dev/camera';
CameraPresets.fps(); // first-person shooter
CameraPresets.thirdPerson(); // third-person action
CameraPresets.rts(); // real-time strategy
CameraPresets.topDown(); // top-down view
CameraPresets.sideScroller(); // side-scrolling platformerMulti-Target Camera
The MultiTargetCamera automatically frames multiple targets:
import { MultiTargetCamera } from '@web-engine-dev/camera';
const camera = new MultiTargetCamera({
targets: [player1, player2],
padding: 100,
screenSize: { x: 800, y: 600 },
minZoom: 0.5,
maxZoom: 2,
});
// Every frame:
camera.update(deltaTime);
const { position, zoom } = camera.getState();Easing
import { CameraEasing } from '@web-engine-dev/camera';
CameraEasing.linear;
CameraEasing.easeOut;
CameraEasing.easeInOut;
CameraEasing.smoothstep;Next Steps
- Physics, physical cameras with collision
- Visual Effects, post-processing effects attached to the camera
- UI & HUD, screen-space overlay on top of the camera view