# HL
The shared spine of *Helsinki Life*: constants, the board graph (43 tiles with
positions, kinds, districts and successors), landmark anchors, camera framing
numbers, the game state container, the event bus the slices talk over, the
`HL.actions` table the rules fill in, the pacing (`HL.TIMING`) and the sound
names (`HL.SFX`).
```lua
local HL = require("game.core.HL")
HL.tile(6).next -- { 7, 101 }: the fork at Pasila station
HL.pawnSlot(22, 2) -- where pawn 2 stands on the Cathedral tile
HL.on("moveStep", function(ev) ... end)
HL.emit("sfx", { name = "hop" })
HL.state().players[1].money
```
# camera
The board camera's own wheel, in *Helsinki Life*. One control, `zoomWheel`:
the mouse wheel, counted in notches, positive into the board.
The `Stage` component activates it beside `play.inputMap`, whose `overview`,
`pan` and `zoom` it also holds. A pad and a finger reach the same camera through
`play`'s own `zoom`, so this map declares neither class rather than binding them
twice.
It joins the `play` group, so a card standing the board's controls down stands
the wheel down with it.
# Director
The camera brain of *Helsinki Life*. One shared table every camera in the world
reads, so each player's own `BoardCam` clone puts its rig on the same shot.
```lua
local Director = require("game.stage.Director")
Director.setViewport(w, h) -- the live frame, every frame
Director.tick(dt) -- advance (only the first caller of a frame does work)
local p = Director.pose() -- { eye = {x,y,z}, look = {x,y,z}, fov }
```
Four framings own the frame, in this order of authority:
| | What it is | Who cues it |
|---|---|---|
| beat | a keyframed cinematic: the opening flyover, the wedding at the Cathedral, the arrival at Suomenlinna, the end card's pull-back | `Director.beat(name, payload)`, the `Stage` component, from `HL.emit("beat", …)` |
| overview | the whole peninsula from above, with pan and zoom | `Director.toggleOverview()` / `HL.actions.toggleOverview()` |
| attract | a slow arc over the sea while no game is running | automatic while there is no state, or the phase is `title` / `setup` |
| follow | south of and above `HL.state().focus`, looking north up the board | the default |
Every framing derives from the **live screen shape**. The follow shot keeps a
fixed ground radius around the pawn inside the frame on both axes, so a 3:4
phone stands further back than a 21:9 television does. Where in the frame the
pawn sits follows the same reading: a tall screen spends its top on the turn
banner and the player column and its bottom on the caption strip, so the pawn
is placed in the clear band between them, a little below centre; a wide screen
gives the column a side instead and wants the pawn nearly centred. The overview
fits the extent the game is actually played over, every tile and every
landmark, to whichever axis the shape makes scarce.
Pan reads its device the way that device means it. A key or a stick reports how
hard it is held, so the reading is integrated over time at `panSpeed`; a finger
or a mouse reports how far it moved this frame, so the reading is spent at once
against what a pixel is worth on the ground, and the map comes with the finger.
`Director.report()` returns the mode, the running beat, the aspect and the pose
- what a test reads to prove where the camera is.
# play
<!-- zero:scaffolded-readme -->
<!-- Replace the line below with what this inputMap provides and who
consumes it, then delete both comment lines. -->
TODO: describe this inputMap.
# zoomWheel
The mouse wheel, as an `axis1` counted in notches. Positive is into the board:
it brings the overview closer, and in the follow shot it nudges the follow
distance inside a small comfort range.
Read by the `Stage` component of *Helsinki Life*, which hands each reading to
`game.stage.Director`.
# act
<!-- zero:scaffolded-readme -->
<!-- Replace the line below with what this inputBinding provides and who
consumes it, then delete both comment lines. -->
TODO: describe this inputBinding.
# back
<!-- zero:scaffolded-readme -->
<!-- Replace the line below with what this inputBinding provides and who
consumes it, then delete both comment lines. -->
TODO: describe this inputBinding.
# navigate
<!-- zero:scaffolded-readme -->
<!-- Replace the line below with what this inputBinding provides and who
consumes it, then delete both comment lines. -->
TODO: describe this inputBinding.
# overview
<!-- zero:scaffolded-readme -->
<!-- Replace the line below with what this inputBinding provides and who
consumes it, then delete both comment lines. -->
TODO: describe this inputBinding.
# pan
<!-- zero:scaffolded-readme -->
<!-- Replace the line below with what this inputBinding provides and who
consumes it, then delete both comment lines. -->
TODO: describe this inputBinding.
# pause
<!-- zero:scaffolded-readme -->
<!-- Replace the line below with what this inputBinding provides and who
consumes it, then delete both comment lines. -->
TODO: describe this inputBinding.
# zoom
<!-- zero:scaffolded-readme -->
<!-- Replace the line below with what this inputBinding provides and who
consumes it, then delete both comment lines. -->
TODO: describe this inputBinding.