Camera

Pure 2D camera settings for world-space drawing.

A camera is a value, not a host-owned resource. Build the camera you want for the current frame and pass it to Draw.with_camera!, which applies it for the duration of a nested scope.

camera = Camera.centered(model.player, Math.vec2(800, 600))
frame.with_camera!(camera, |world| {
    world.circle!({ center: model.player, radius: 12, style: Draw.filled(Color.white) })
    Ok({})
})?

Every constructor and builder here is total: it answers with a Camera2D rather than a Try. A camera has exactly two invariants -- every transform field is finite, and the zoom is non-zero so screen_to_world can invert it -- and the only inputs that can break them are inputs no caller means to pass. Rather than make every app carry an unreachable Err branch for those, they are sanitized on the way in. A target or offset component that is not finite becomes 0, as does a rotation that is not finite; a zoom that is zero or not finite becomes fallback_zoom, keeping its sign so a mirrored camera stays mirrored.

Nothing else is touched. Sanitizing only ever rewrites a value a validating API would have refused outright, so a camera built from ordinary numbers comes back with its fields unchanged -- negative, axis-mirroring zooms included.

These types live in the companion roc-ray-types package and are re-exported here, so a value passes between the two spellings freely and a library can depend on the package without depending on this platform.

fallback_zoom : F32

The zoom substituted for a zoom that cannot be used, meaning zero (which has no inverse) or a non-finite one (which has no meaning).

Deliberately tiny rather than 1: a camera that had to be rescued collapses the world to a dot at its offset, which reads on screen as the mistake it is, instead of quietly looking plausible.

default : Camera2D

Identity camera: no offset or rotation, with unit zoom.

new : Settings -> Camera2D

Construct a camera from explicit settings.

Total: non-finite target, offset, and rotation components become 0, and a zoom of zero or one that is not finite becomes fallback_zoom with the same sign. Every usable setting is kept exactly.

centered : Vec2, Vec2 -> Camera2D

Place target at the center of a screen with unit zoom.

Total: a non-finite component of either vector becomes 0.

follow : Vec2, { screen : Vec2, zoom : F32 } -> Camera2D

A common player-follow camera with a configurable zoom.

Total: a non-finite target or screen component becomes 0, and a zoom of zero or one that is not finite becomes fallback_zoom with the same sign.

Camera2D : Camera2D

Immutable camera value accepted by drawing and coordinate transforms. Camera.Camera2D and Draw.CameraMode on the platform are this same type, re-exported.

Its representation is opaque so non-finite transform fields, or a zero zoom that has no inverse, cannot bypass the sanitizing every constructor applies. The module header states what is rewritten and what is left alone.

Settings : Settings

Target, screen offset, clockwise rotation in degrees, and zoom factor.