Camera

Pure 2D camera settings for world-space drawing.

Cameras are pure values passed to Draw.with_camera!; they hold no host resource.

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({})
})?

Constructors are total. Non-finite positions and rotations become 0; zero or non-finite zoom becomes fallback_zoom, preserving a negative sign for mirrored cameras. Other finite values are unchanged.

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.

Settings : {
    target : Vec2,
    offset : Vec2,
    rotation : F32,
    zoom : F32,
}

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

Camera2D

Camera.Camera2D :: # (opaque)

Immutable camera value accepted by drawing and coordinate transforms. Draw.Camera2D names this same type.

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.

target : Camera2D -> Vec2

World-space point placed at the camera offset.

offset : Camera2D -> Vec2

Logical screen-space offset of the target.

rotation : Camera2D -> F32

Clockwise camera rotation in degrees.

zoom : Camera2D -> F32

Non-zero camera zoom factor. Negative values intentionally mirror axes.

with_target : Camera2D, Vec2 -> Camera2D

Return a copy focused on new_target.

Total: a component of new_target that is not finite becomes 0, and every finite coordinate is kept exactly.

with_offset : Camera2D, Vec2 -> Camera2D

Return a copy with new_offset as its logical screen-space offset.

Total: a component of new_offset that is not finite becomes 0, and every finite coordinate is kept exactly.

with_rotation : Camera2D, F32 -> Camera2D

Return a copy rotated new_rotation degrees clockwise.

Total: a new_rotation that is not finite becomes 0. Any finite angle is kept exactly, including one outside 0 to 360 -- degrees wrap through the sine and cosine, so there is no range to clamp to.

with_zoom : Camera2D, F32 -> Camera2D

Return a copy zoomed by new_zoom.

Total: a new_zoom of zero has no inverse and one that is not finite has no meaning, so either becomes fallback_zoom with the same sign. Every other zoom is kept exactly, so a negative zoom still mirrors both axes.

clamp_zoom : Camera2D, { min : F32, max : F32 } -> Camera2D

Clamp zoom to inclusive limits.

Total: limits that produce a zero or non-finite zoom fall back to fallback_zoom, exactly as with_zoom does.

world_to_screen : Camera2D, Vec2 -> Vec2

Convert a world-space point to logical screen coordinates. Rotation uses degrees, matching raylib and Draw.with_camera!.

screen_to_world : Camera2D, Vec2 -> Vec2

Convert logical screen coordinates back to world space. Every Camera2D is invertible because no constructor lets a zoom of zero through.

viewport : Camera2D, Vec2 -> Rect

World-space axis-aligned bounds visible through this camera. This handles non-centered offsets, rotation, and mirrored (negative) zoom.