# The camera

> How the camera follows a unit, keeps clear of rocks and dives under the sea, the lens it looks through, and how speed, the booster and crashes reach it.

In a third-person game the camera is half of how a unit feels. It decides what
you see, how fast the World seems to move, and whether a crash lands like a blow
or like a number. This page covers what Orbium's camera does today, the lens it
looks through, and the work planned to make every action felt. The repository's
own notes on it are in `CAMERA.md`.

## Over the shoulder

During a window the camera rides a boom behind your unit and a little to its
side, looking past its shoulder at what it faces
(Walker.js (`client/src/game/Walker.js`), `placeCamera`). The boom is 6.4 m
long and the vertical field of view is 62°.

*Figure: The camera boom behind a unit, pulled in short of a rock that stands between the unit and where the camera wants to be*

- **Keeping clear.** The boom never passes through the ground, a rock or the
  platform's deck. Each frame it is marched outwards from the unit's head in
  0.25 m steps, and the first blocked step is bisected, so the camera slides
  smoothly along a slope instead of jumping a step at a time (`boomReach`). It
  pulls in quickly when something comes close and lets out slowly when it
  clears, so a rock passing behind you doesn't make the view pump.
- **The shoulder.** The sideways offset is also checked, so the camera never
  slides into a rock beside the unit (`reach`).
- **Height.** The camera follows the unit's height with a small dead zone and a
  short lag. Bumps and small hops don't shake the view, but the camera never
  falls more than 0.6 m behind.
- **Looking up.** The more you look up, the shorter the boom, so the sky doesn't
  fill the screen with the unit as a speck.
- **Under the sea.** When a unit dives, the camera goes under with it, crossing
  the surface in half a second, and the underwater lens takes over. Above the
  sea, it never drops into the waves (`seaCamera`).

## The long lens

Holding zoom (right click, or LT on a gamepad) eases the field of view down to
24° and brings the camera in to the shoulder, with a heavier vignette and a
little more grain, like a long lens (Game.js (`client/src/game/Game.js`),
`lensTo`). The look slows by the same ratio, so a mouse movement turns the view
by the same distance on screen either way. A rangefinder gives the distance to
whatever the centre of the view is on.

## When you aren't driving

- **Just down**: the camera stays where it was, easing back and up from the
  wreck while it watches it, then cuts to someone still in the window.
- **Watching**: it orbits the watched unit, with the same boom that keeps clear
  of rocks. Switching units is a cut, not a swoop across the World.
- **A window's close**: the camera cranes up and over to the unit that took the
  window and circles it, keeping clear of the ground and the rocks around it.
  The last moment plays in slow motion: the World, the units and any bolt still
  in flight drop to a fifth of their pace as the window closes and are back to
  full speed within two seconds. The camera's move itself keeps real time.

## Shake and knocks

Every effect on the camera goes through one small rig
(CameraRig.js (`client/src/game/CameraRig.js`)). Whatever placed the camera
this frame leaves its pose, the rig adds its effects on top as the last thing
before the World is drawn, and takes them off again before the next frame. The
crosshair's aim is taken before the effects, so they never move it.

- **Layers.** An effect sets its own share of the field of view, roll, vignette
  and grain each frame, and the rig adds them up over the plain lens. The long
  lens is one of them.
- **Shake.** A crash, a hard landing, leaving the deck, a bolt fired or landing
  nearby, or a hit raises the camera's "trauma", between 0 and 1, which then
  falls away in under a second. The shake is trauma squared, so small bumps
  barely register and big ones hit hard. It mostly turns the camera (yaw, pitch
  and roll) rather than moving it, and it follows smooth noise rather than a new
  random offset each frame: it feels the same at 60 and 240 Hz, and the motion
  blur and the upscaler don't smear it. Zoomed in, the turn is scaled down so it
  is the same size on screen.
- **Knocks.** A spring that pushes the camera one way and lets it settle back,
  with one soft overshoot. Crashing into a wall or ramming another unit knocks
  the view away from what it hit and rolls it away from that side, as hard as
  the crash was fast.
- **Camera motion**, in the menu: Full, Reduced or Off, or Auto, which is
  Reduced when your system asks for reduced motion. It scales the shake, the
  knocks and anything else that moves the view. The long lens is your own, and
  isn't scaled.

## The lens

The camera looks through the engine's post effects
(PostFX.js (`engine/post/PostFX.js`)), several of which are about the camera
itself rather than the World:

- **Motion blur**, light on purpose: a third of the frame's time, so fast turns
  stay readable (MotionBlur.js (`engine/post/MotionBlur.js`)). It can be
  turned off in the menu.
- **Auto exposure**, adapting like an eye when you look from the shade into the
  sky.
- **Vignette and film grain**, faint, stronger on the long lens, and on the
  Medium and High presets a faint colour fringe toward the edges, as a real lens
  has. There is no barrel distortion: the name tags and the reticle are placed
  over the World by its plain projection, and a warped image would slide out
  from under them.
- **A lens flare** facing the sun, **water drops** on the lens after the camera
  comes out of the sea or a jet's spray hits it, and **dust**: a booster's blast
  or a hard landing in sand or snow close by leaves soft, glowing specks out of
  focus and a faint film, which wear off in a few seconds and wash off in the
  sea (LensDroplets.js (`engine/post/LensDroplets.js`)).
- **Heat shimmer** toward the horizon in the Desert.
- **Cuts.** When the camera jumps (a cut to another unit) or turns sharply in a
  single frame, the post effects drop what they remember of the last frame, so
  the jump doesn't smear.

## Speed, the booster, crashes and hits

What your unit does reaches the camera through the same rig
(CameraFeel.js (`client/src/game/CameraFeel.js`)), eased so nothing snaps,
and drawn on your machine alone: the server doesn't know about any of it.

- **Speed.** The field of view widens with your speed, 6° wider at running
  speed, and less while you zoom.
- **The boom.** It stretches back a little as you speed up, never into a rock
  behind you, closes in as you brake, and trails a little behind a sideways
  move, so your unit drifts off centre and settles back.
- **The booster.** Its ignition punches the field of view 8° wider, fast in and
  slow out, and drops the view with a kick as the unit shoots up. It rumbles
  while it burns, and so do the drop's thrusters. In the last of the tank it
  sputters, the jolts coming faster as it empties.
- **The water jets.** A burst surges your unit off, the view lagging behind it,
  and rumbles, harder under the water. At the surface it throws a rooster tail
  of white water, drops and mist behind you, and spatters the lens. Under it,
  the jets churn a milky plume of fine bubbles that billows, rises and thins
  away, with a stream of tiny ones and now and then a big one wobbling up,
  flattened into a cap. With Motion blur on, the burn opens the blur's shutter
  from a third of the frame to half of it.
- **A speed blur.** Boosting at speed, with Motion blur on, the view streaks
  toward its centre at the edges, the centre kept sharp: six samples a pixel
  toward the middle, jittered so they don't band, and nothing while it's off.
- **Banking.** In the air the view banks into your turns, up to about 4.6°.
- **The ground under the wheels.** A faint, fast vibration by what you roll on
  and how fast: rough on rock and shingle, lighter on grass and the deck's
  plates, faint on sand and snow, none on ice.
- **Landing.** The view dips by how far you fell, nods, and springs back.
- **The Hunter's recoil.** Each bolt kicks the view up a little and narrows it
  by a degree, settled in about a tenth of a second, long before the next one.
  The bolt still goes where the crosshair was.
- **Hit by a bolt.** The view is knocked away from the Hunter, and the lens
  pulses as it does in a crash.
- **Worn down.** As your health falls, the view slowly loses its colour and
  closes in at the edges.
- **A crash's pulse.** Besides the knock, the lens takes the blow: colour
  fringes toward the edges and a darker vignette for a moment, lit in the
  shield's light when your shield took it, washed of colour when it didn't. The
  hardest crashes muffle the sound for a moment too, through the same low-pass
  the sea uses. The fringe and the light are two uniforms in the final pass,
  skipped when they are zero: with them on, the pass measured the same.

## Close to the barrier

The barrier is meant to look like it could hurt you, more the closer you come
(Arena.js (`client/src/game/Arena.js`)):

- **The field is never quiet.** Rings ripple out over it from a unit close to
  it, cells' outlines spark at random, more and more as it closes in, and its
  light flickers unevenly. Only the lines give light: the mesh holds still and
  you see through it between them.
- **Its lines give off a shimmer.** In the final pass, each pixel's view ray is
  tested against the four walls of the barrier nearest the camera. Where it
  crosses one in front of the scene, the hex mesh is rebuilt there, and the
  image behind is pushed about just off the lines, fading toward the cells'
  middles, as if the lines were radiating. Nothing moves on a line itself, so
  the mesh stays put. It starts 45 m off the barrier and costs nothing further
  away.
- **The camera picks up interference.** From 14 m in, grain and colour fringes
  rise and the view buzzes, finer and harder up to the touch.

## Game feel: what comes next

> This part is a plan: the work below is being built and tuned in play.

The goal is that what your unit does is felt, not just shown. What is left:

### The booster

- **Heat haze** behind the nozzles.

### Polish

- **Depth of field** for the shots where nobody aims: the wreck, a window's
  close, your unit in the Hold.

### Rules the effects keep

- **Your aim stays true.** Effects move the view, never where you aim, and the
  look is never smoothed or delayed. The Hunter's shake stays small, and a
  recoil settles before the next bolt can fire.
- **Steady at any frame rate**, as above.
- **Light on the GPU.** Most effects are a setting or a few samples in the final
  pass. The ones that need a pass of their own, depth of field and heat haze,
  are measured before they ship.
