# orbit-camera
A third-person orbit/follow camera for action-adventure games, extracted from a
shared pattern across several games (magic-journey, bad-fates, oneira-woods,
cyborg-evolution, ruffy-wonder, open-world-minigolf).
The camera orbits a focus point that smoothly follows a target. Yaw and pitch
are set directly; the orbit distance scales with pitch and can be zoomed. Focus
and distance interpolate frame-rate independently. An optional clipping pass
pulls the camera in when geometry blocks the view.
## Design
- **No matrix dependency.** `view()` returns eye, focus, up and projection
parameters. Build the view-projection matrix with whatever the renderer uses.
- **Backend-agnostic clipping.** `clip` takes any `Clip` implementor. Enable the
`collide-mesh` feature for a ready-made impl on `collide_mesh::CollisionWorld`.
- **Fully configurable.** Every constant (pitch range, distances, smoothing,
field of view, clip margins) lives in `CameraConfig`. `Default` matches a
Zelda-style feel.
Built on `ga3::Vector<f32>`.
## Example
```rust
use ga3::Vector;
use orbit_camera::OrbitCamera;
let mut camera = OrbitCamera::new(player_position);
// per frame:
camera.rotate([stick.x * sensitivity, stick.y * sensitivity]);
camera.zoom(scroll);
camera.follow(player_position, timestep);
camera.clip(&world); // requires the `collide-mesh` feature, or impl Clip yourself
let view = camera.view();
let view_projection = perspective(view.field_of_view, aspect, view.near_plane, view.far_plane)
* look_at(view.eye, view.focus, view.up);
// move the player relative to the camera:
let basis = camera.basis();
let movement = basis.forward * input.y + basis.right * input.x;
```
## Features
- `collide-mesh` — implement `Clip` for `collide_mesh::CollisionWorld`.
## AI-coding friendliness
- Pure-function camera state: `view()`/`basis()`/`eye()` have no side effects.
- No implicit matrix convention baked in — the consumer owns the projection.
- Clipping is decoupled behind the one-method `Clip` trait, so the camera has no
hard dependency on any collision backend.