@evitcastudio/lens
v4.4.1
Published
A modular camera system for 2D games with specialized camera types (Follow, Spectate, Pan, Influence, Transition) and rich effects including shake, zoom, and seamless transitions.
Maintainers
Readme
Features
- Specialized Camera Types:
FollowCamera: Smooth target tracking with customizable 3D offsets (x,y,zheight) and deadzones.SpectateCamera: Cinematic target spectating with instant snap or smooth easing.PanCamera: Directed camera pans to positions or entities with configurable hold duration and auto pan-back.InfluenceCamera: Multi-target weighted focus camera dynamically interpolating between multiple entities.TransitionCamera: Seamless camera-to-camera or point-to-point blending with zero visual pop and live dynamic target tracking.
- Screen Shake System: 29 built-in professionally calibrated shake presets plus fully customizable amplitude, frequency, decay curves, and multi-axis parameters.
- Smooth Zoom & Easing: Independent X/Y zoom animations with 30+ easing equations (
linear,easeOutCubic,easeInOutQuad, etc.). - Time Scale Awareness: Seamless integration with bullet-time / slow-motion mechanics, with flags to allow effects to ignore global game speed.
- Debug Gizmos & Guides: Built-in PIXI debug visualization and crosshair alignment guides.
- Autonomous or Manual Lifecycle: Run via internal
requestAnimationFrameloop or step manually inside your game's render loop (cameraManager.update(elapsedMs)).
Installation
# Using bun
bun add @evitcastudio/lens
# Using npm
npm install @evitcastudio/lens
# Using yarn / pnpm
yarn add @evitcastudio/lens
pnpm add @evitcastudio/lensChoosing Your Setup: Standalone vs. Kit
Lens is designed for games built with the Vylocity Game Engine:
Using the
@evitcastudio/kitframework (>= 3.4.0)? You do not need to install@evitcastudio/lensdirectly! Lens is already bundled and prepackaged directly inside Kit as a built-inCameraplugin. You can access it immediately via Kit:import { Kit, Camera } from '@evitcastudio/kit'; // Camera is already prepackaged in Kit (>= 3.4.0) const camera = Kit.getPlugin<Camera>('Camera'); camera.shakePreset('explosion-large');Standalone Vylocity (without Kit)? Install
@evitcastudio/lensand instantiateCameraManagerdirectly:import { CameraManager } from '@evitcastudio/lens'; const cameraManager = new CameraManager();
Quickstart (Standalone CameraManager)
import { CameraManager } from '@evitcastudio/lens';
// Auto-starts internal RAF loop by default
const cameraManager = new CameraManager();
// Or for manual control in your own game loop:
// const cameraManager = new CameraManager({ autoStart: false });
// In your tick/render loop: cameraManager.update(elapsedMs);1. Follow Camera (Main Player Tracking)
// Create and bind to player
const followCam = cameraManager.createFollowCamera();
cameraManager.setMainFollowCamera(followCam, player, { x: 0, y: 0, z: 0 }, true);
// Set smooth tracking transition settings
followCam.setSettings({
duration: 400,
ease: 'easeOutCubic'
});2. Seamless Camera Transitions
Switch smoothly between cameras or targets with dynamic Hermite spline interpolation and spring-damping (zero visual pop):
// Seamlessly blend from current camera to a boss camera
await cameraManager.switchTo(bossCamera, {
duration: 800,
smoothing: 'smoothDamp', // or 'cubicSpline'
springTension: 170,
springFriction: 26
});3. Screen Shake
// Trigger any of the 29 built-in presets
cameraManager.shakePreset('explosion-large');
cameraManager.shakePreset('gunshot');
cameraManager.shakePreset('handheld-soft', undefined, true); // infinite handheld camera
// Stop shaking
cameraManager.stopShake();
// Or define a custom shake
cameraManager.shake({
strength: { x: 6, y: 6 },
duration: { x: 350, y: 350 },
vibrato: 15,
curve: 0.5
});4. Smooth Zoom
// Zoom in 2x over 500ms with easeOutCubic
cameraManager.zoom(2, 500, 'easeOutCubic');
// Different zoom per axis
cameraManager.zoom({ x: 1.5, y: 1.5 }, 300);
// Reset zoom
cameraManager.zoom(1, 400, 'easeInOutQuad');5. Panning & Spectating
// Pan to a point of interest, pause for 1 second, then pan back to player
await cameraManager.panTo({ x: 1200, y: 800 }, {
duration: 800,
pauseDuration: 1000,
panBack: true,
ease: 'easeInOutCubic'
});
// Spectate another entity
await cameraManager.spectateTarget(bossEntity, {
duration: 600,
ease: 'easeOutQuad'
});Camera Event System
The camera system emits lifecycle events across its lifecycle. When used with @evitcastudio/kit, all events are automatically dispatched through Kit's global event bus (Kit.on), allowing audio, gamepad rumble, or UI systems to decouple from the camera:
// Listen globally via Kit
Kit.on('Camera', 'shake-start', (event) => {
console.log('Camera started shaking:', event.data.preset);
// Example: trigger gamepad vibration
});
Kit.on('Camera', 'shake-end', () => {
// Example: stop gamepad vibration
});
Kit.on('Camera', 'transition-start', (event) => {
// Example: animate letterbox cinematic bars
});
Kit.on('Camera', 'transition-end', () => {
// Example: restore gameplay HUD
});Standalone users can also subscribe directly on CameraManager (or CameraPlugin):
const unsubscribe = cameraManager.on('view-eye-changed', ({ camera, previousCamera }) => {
console.log('Active camera changed to:', camera.id);
});
// Later, unsubscribe:
unsubscribe();Available Events
| Event | Trigger | Payload |
| :--- | :--- | :--- |
| shake-start | Shake effect begins | { preset, strength, duration, infinite, rotation } |
| shake-end | Shake effect ends / stopped | { preset } |
| zoom-start | Zoom animation begins | { destination, duration, ease } |
| zoom-end | Zoom animation finishes | { zoom } |
| transition-start | switchTo transition begins | { fromCamera, toCamera, duration } |
| transition-end | switchTo transition finishes | { activeCamera } |
| pan-start | Directed pan begins | { target, duration, panBack } |
| pan-end | Directed pan completes | { target } |
| spectate-start | Spectating starts | { target, duration } |
| spectate-end | Spectating ends | { target } |
| view-eye-changed | Active view eye changes | { previousCamera, camera, cameraType } |
Native Debug Overlay & Gizmos
Lens includes a built-in, lightweight 2D canvas overlay for debugging cameras and viewing spatial relationships with zero WebGL scene graph overhead.
// Enable debug overlay with full feature set
cameraManager.setDebugMode({
enabled: true,
canvas: '#gizmo-canvas', // or omit to auto-create an overlay
showCameraMarkers: true,
showTargetLines: true,
showBounds: true,
showCenterCrosshair: true,
bounds: { minX: 50, maxX: 1230, minY: 50, maxY: 670 },
// Optional custom render hook for game-specific badges, reticles, or nameplates
onCustomRender: (ctx, worldToScreen, width, height) => {
// Custom game rendering here
}
});
// Or dynamically adjust options:
cameraManager.setDebugOptions({ showTargetLines: false });Shake Presets
| Category | Presets |
| :--- | :--- |
| Combat & Explosions | gunshot, recoil, explosion-small, explosion-large, impact, impact-light, impact-heavy, crash |
| Environmental | earthquake-soft, earthquake-hard, rumble, tremor, thunder, wind, wave |
| Atmospheric & Camera | handheld-soft, handheld-hard, breathing, heartbeat, pulse, sway, dizzy, nervous, jitter, vibration |
| Movement & Actions | footstep, landing, door-slam, bounce |
License
MIT © Evitca Studio & doubleactii
