Camera
world/camera.ts:119 Extends AbstractWorldComponent
The world's viewport — a "look-at point" in world space, plus an orientation and a zoom factor — that downstream presentation components (notably Scene) use to decide what part of the world ends up on screen.
Every World owns exactly one Camera, attached automatically at
construction and accessible as a typed reference via World.camera.
There is no opt-in registration, no name to remember, and no risk of the
camera being missing — engine code that reads it can treat its presence
as an invariant.
Semantics
The camera is a look-at point, not a pan offset:
- Camera.position is the world-space coordinate the camera is
currently pointed at. Scene maps that point to the centre of
the canvas — set
camera.positionto the player's position once per frame and the player stays anchored on screen as they move. - Camera.rotation is the camera's roll, in radians. Scene applies its inverse to the scene container, so increasing the value rotates the world clockwise underneath a stationary viewer.
- Camera.zoom scales the rendered view; values greater than
1zoom in (objects appear larger), values between0and1zoom out.
All three fields default to a neutral state. With the default camera, the world's origin appears at the centre of the canvas, the world's axes line up with the canvas's, and one world unit equals one screen pixel.
Shake
Camera.shake kicks off a temporary, decaying random offset
applied to the rendered view — the staple "impact" feedback for hits,
explosions, and screen-jolts. The shake lives entirely on the render
side: it adjusts Camera.shakeOffset each tick during the
camera's own onUpdate, and Scene reads that offset when it
applies the container transform. The logical Camera.position
and Camera.rotation are untouched, which means
- Mouse (and any other code routing through Scene.screenToWorld) keeps landing on the world point the player actually aimed at, not a phantom shifted by the shake.
- Game logic that reads
camera.position(e.g. a follow controller centring on the player) sees a stable value, not a jittering one.
Intensity is expressed in screen pixels so the visual magnitude is
independent of zoom. Starting a new shake while one is already in
flight replaces it — the engine does not currently stack shakes.
Why this isn't a WorldObject
The camera looks superficially like it wants to be a WorldObject — it
has a transform, it sometimes follows a moving target. But a
WorldObject is a thing inside the world (findable by tag, iterated
during update, destroyable). The camera is the lens through which the
world is observed; modelling it as a sibling of every game entity
conflates the two roles. As a world-scoped component it stays out of
findByTag, never appears in object iteration, and can't be accidentally
destroyed.
Example
// Camera-follow-player: copy the player's position into the camera once
// per frame so the player stays centred on screen. Run inside the
// player's `onUpdate` so Scene's post-update transform sync sees a
// settled camera before drawing.
class CameraFollow extends AbstractWorldObjectComponent {
public onUpdate(): void {
this.world.camera.position.copyFrom(this.host.position);
}
}// Shake the camera on every bullet impact.
onBulletHit() {
world.camera.shake(8, 250);
}// Zoom in for a cinematic close-up.
world.camera.zoom = 2;Constructors
Properties
enabled: boolean Per-component gate on the three update hooks (onPreUpdate,
onUpdate, onPostUpdate). When explicitly false, the engine skips
all three for this component during the host's tick — useful for
temporarily pausing behaviour (e.g. a freeze powerup) without removing
the component and losing its internal state.
Does not gate onAdded or onDestroy; those always fire so a host can
never end up with a half-attached component.
host: World The host this component is attached to. Stored read-only;
subclasses access it as this.host directly, or through the
tier-appropriate aliases (this.world, this.game) on the per-tier
abstract bases.
position: Point The point in world space the camera is currently looking at. Mutable in
place — game code typically writes to this every frame to follow a
target (camera.position.copyFrom(player.position)).
Scene maps this point to the centre of the canvas every frame.
With the default (0, 0), the world's origin appears centred on
screen.
rotation: number The camera's roll, in radians, measured clockwise (same convention as WorldObject.rotation and the rest of the engine). Mutable.
Scene applies the inverse of this rotation to the scene container, so increasing the value rotates the world clockwise beneath a stationary viewer.
zoom: number Uniform zoom factor applied by Scene when projecting world
coordinates to the screen. 1 (the default) is "1 world unit per 1
screen pixel"; values greater than 1 zoom in, values between 0
and 1 zoom out. Negative or zero values produce undefined visual
results — neither the engine nor Pixi clamp them — so don't.
Accessors
game: Game The Game the host world belongs to. Always non-null — the
world's game field is a mandatory construction argument, not an
option.
isShaking: boolean true if a Camera.shake is currently in flight. Goes back to
false automatically when the shake's duration elapses, or
immediately on Camera.stopShake.
shakeOffset: Readonly<Point> The current shake-induced offset, in screen pixels. Zero unless a shake is in flight. Exposed primarily so Scene can read it during the post-update transform sync; game code rarely needs to inspect it directly.
The returned Point is the camera's live internal instance — mutating it externally is a contract violation. Treat it as read-only.
world: World The World this component is attached to — identical to
AbstractComponent.host at this tier, exposed under the
world name so subclass code reads the same on every tier.
Methods
onAdded(_deps: Record): void Lifecycle hook that is called when the component is added to the host object. Should not be called directly.
Parameters
-
_depsRecord
Returns
void onDestroy(_deps: Record): void Lifecycle hook that is called when the host object is destroyed. Should not be called directly.
Parameters
-
_depsRecord
Returns
void onUpdate(update: WorldUpdate): void Advances any in-flight shake by one tick. Computes a fresh random offset inside a disc whose radius is the current (decayed) shake intensity, then writes that to Camera.shakeOffset for Scene to consume during the post-update phase.
Parameters
-
updateWorldUpdate
Returns
void shake(intensity: number, duration: number): void Starts a screen-shake effect. The shake adds a randomised offset to
Camera.shakeOffset once per tick, decaying linearly from
intensity at the start to zero at duration. Scene applies
the offset on top of the camera's logical position when it draws.
Calling shake while another shake is still running replaces the
previous one — the engine does not currently stack shakes. Passing a
non-positive intensity or duration is a no-op (treated as a
Camera.stopShake).
Parameters
-
intensitynumber -
durationnumber
Returns
void stopShake(): void Cancels any in-flight shake and snaps Camera.shakeOffset back to zero on the next frame. Safe to call when no shake is active — it's a no-op in that case.
Returns
void