# game.camera.shots
The six moments the camera takes itself off the crane.
```luau
local Shots = require("game.camera.shots")
local ctx = Shots.context() -- the live world, read once
local pose = Shots.eval("ring", 0.72, ctx) -- { px, py, pz, ax, ay, az, fov, roll }
```
| Beat | Seconds | What it does |
|---|---|---|
| `opening` | 6.2 | Starts under the fog sea, turned nearly a radian off the crane's side of the tower, and climbs through the fog line past the rooftops onto exactly the station the follow takes over. The aim lands a beat before the position, so the last stretch reads as arriving rather than as being swung into place. |
| `hoist` | 4.6 | An orbit that leaves and returns — turn, radius and lift are all one half-sine, so it ends on the follow station exactly. The aim is on the bell itself, read live, so the shot carries the bell up the outside of the tower and in over the last course. |
| `ring` | 2.6 | The shot the whole game is pointed at. Swings round to the side the sun is not on and pushes in along the sun's own bearing, so the bell is between the lens and the light. Holds. |
| `won` | 7.0 | Rises and pulls back until the shot is no longer the tower but the place: the aim comes down onto the roofs, the lens widens, and the town the warning was for arrives under the new light. Holds. |
| `fell` | 5.0 | Does not cut away. Falls with the courses, ends low on the stump, held a few degrees off level. Holds. |
| `sunrise` | 5.0 | Turns off the unfinished tower and onto the light: round to the sun's bearing, down toward the fog, the stump dark against a sky that has already won. Holds. |
## Pure functions of a clock
Every beat is a function of a normalised clock and a `Ctx` of live readings.
Nothing here reads the world during a beat, holds state or writes an entity —
`game.camera.director` runs the clock and applies the pose. Two things follow,
and both are why it is written this way: a hot reload cannot lose a beat
mid-play, and **any frame of any beat can be looked at without playing it**,
which is how the framing was judged.
```luau
local p = Shots.eval("opening", 0.35, Shots.context())
-- capture { source = "position", position = {p.px,p.py,p.pz},
-- lookAt = {p.ax,p.ay,p.az}, fov = p.fov }
```
Every beat is written in the terms `game.camera.framing` hands back — a turn
around the tower, a scale on the solved radius, a lift off the solved height —
never in absolute metres, so a beat stays framed on a phone held upright and on
a television alike.
## The bell and the sun in one frame
`ring` is the one beat that has to hold two things at once, and only one of them
can be moved to, because the sun is at infinity. What decides the frame is the
ANGLE between them, and the only free variable is how far above or below the
bell the camera stands — so the shot is solved from the sun's own elevation,
read live off the directional light, rather than from a height that happens to
work at one hour. The bell lands at 0.33 up the frame and the sun at 0.80,
whatever elevation the dawn has reached. Where the sun sits so high that holding
both would put the camera under the fog, the bell keeps its place and the sun
rides up the frame.
## Handing the camera back
Every beat ends on the follow pose, or on a pose the follow can damp out of in
a few tenths, so the hand-off is a continuation rather than a cut. `ring` and
the three ending beats are the exception: they HOLD their last frame. The ring
push-in has to stay on the bell while the player waits for the top of the
swing, and an end card wants a composed frame behind it rather than a camera
drifting back to a tower nobody is building any more.
# core
One-paragraph description of what this module provides and who consumes
it.
## Exports
- `M.exampleFn(arg) -> result` — what it does and when to call it.
- `M.exampleValue: type` — what value it carries.
## Usage
Replace `<identity>` with the string `asset.create` returned — this
module's source path with `/` written as `.` and each segment's type
suffix dropped, the way a module at `/source/lib/thing.module` is
`lib.thing` and one at `/source/kit.package/thing.module` is
`kit.thing`.
```luau
local M = require("<identity>")
M.exampleFn("foo")
```
## Notes
- Anything callers need to know about THIS module: required runtime
ordering, state ownership, side effects.
# game.camera.director
The one thing that decides where the camera is.
```luau
local Director = require("game.camera.director")
Director.play("opening", { onEnd = function() ... end })
Director.kick(1.2) -- a course seated badly
Director.punch(2.0) -- a perfect seat: a snap on the lens
Director.shake(1.05, 1.35) -- the tower went
local p = Director.pose() -- what the rig should be this frame
```
`TowerCamera` applies what this hands back and `Staging` tells it what to play.
Neither of them works out a pose. Everything that can move the view — the
follow, a staged beat, the jolt when a course seats, the tremor on a tocsin
beat, the shake when the tower goes, the breath under all of it — is summed
here, in one place, so two of them can never fight over the same entity.
## One clock, however many rigs
The camera rig is `OwnerOnly` on the player prototype, so every peer has one of
their own and the editor sees the prototype's. All of them apply the SAME pose
— a round is local to a peer and they are all watching one tower — but the
clock must only advance once a frame, or a beat runs at N times speed with N
players in the world. The first rig to register is the primary and is the only
one that ticks; the rest read. `Staging` ticks it instead when no rig is alive
at all, so a scene being authored with no player in it still finishes its
beats.
The same care applies to a single rig: an editing session with the simulation
running calls both `update` and `editorUpdate` on the same frame, so `update`
owns the clock wherever it runs and `editorUpdate` only takes over once a
couple of frames have gone by without one.
## Holds
`ring`, `won` and the two losses hold their last frame rather than handing the
camera back — the ring push-in has to stay on the bell while the player waits
for the top of the swing, and an end card wants a composed frame behind it. A
held beat keeps a slow drift, a few degrees of orbit and a couple of degrees of
lens over six seconds, so the frame is alive without being a move.
## Freezing a frame
```luau
Director.freeze("ring", 0.72) -- park exactly there
-- ... capture ...
Director.release()
```
`freeze` parks the camera on one frame of a beat and leaves it: the clock does
not run and the held frame does not drift, so the pose is exactly
`Shots.eval(name, t, ctx)` for as long as it is held. It is what makes a
capture of a moment inside a move repeatable, instead of a race against the
seconds between asking for the shot and the shutter. Authoring only — nothing
in a round calls it.
## Reading it
`Director.snapshot()` reports the beat and its clock, whether it is holding,
how many rigs are registered, the damped top course, and the whole solved frame
— aspect, lens, distance, aim, and how much of each slide axis reads as lateral
movement at the current bearing.