# game.core
The one table every slice of *First Light: Lucina* reads.
```luau
local Core = require("game.core")
```
| What | Where |
|---|---|
| The plate grid, cell ↔ world conversions | `Core.GRID`, `Core.PLATE`, `Core.cellToWorld`, `Core.worldToCell`, `Core.cellIndex` |
| The five piece shapes and the placement rules | `Core.SHAPES`, `Core.SHAPE_ORDER`, `Core.footprint`, `Core.canPlace`, `Core.pieceAt` |
| The exposure and dose numbers | `Core.EXPOSURE`, `Core.DOSE` |
| The phases and the level shape | `Core.PHASES`, `Core.LEVEL_COUNT`, the `Level` type |
| The live game state, held across hot reloads | `Core.state` — the `State` type says which slice writes each field |
| The signal bus | `Core.on(name, fn)`, `Core.off`, `Core.emit(name, ...)` — the signal list and its senders are in the source |
| The three shorthands | `Core.request(action)`, `Core.sfx(name, opts?)`, `Core.say(lineId)` |
| Which component mounts where | `Core.MOUNTS`, `Core.mount()` — the scene entrypoint calls it on every load |
Subscribe in `awake`, subscribe again from `onModuleReload` (a duplicate is
dropped), release in `onDestroy`. The rules of the game are stated in
`design/spec.md`; this module carries the numbers and the shapes they share.
# theme
The design system every authored screen of *First Light: Lucina* is drawn from.
It builds widget nodes and returns them: it registers no screen, reads no phase
and spawns nothing.
## What is in it
- **Type** — three faces: `DISPLAY` (EB Garamond, the lighthouse's own
lettering), `BODY` (PT Serif, the Keeper's logbook) and `MONO` (Berkeley
Mono, every number on the glass), each with real fallbacks behind it.
- **Colour** — `C`, the whole palette: near-black basalt and iron, brass as the
material the interface itself is made of, and the two accent lights the art
direction allows — the betafite's green-gold and the dawn.
- **Measure** — `u(f)` is `f` of the SHORT axis, `wf`/`hf` fractions of the
width and the height, `T` the type scale in short-axis fractions with `TMIN`
as a physical floor, `TAP` the smallest side of anything a thumb presses, and
`cardWidth()` the reading column. `previewSize` lays a tree out against a
stated shape instead of the live screen, which is how a set of screens
composed in a 3:4 frame is proved to hold on a 16:9 one.
- **Atoms** — `text`, `num`, `display`, `para`, `eyebrow`, `spacer`.
- **Motion** — `entrance(delay, fromY)` and `breathe(from, to, seconds)`.
- **Ornament** — `svg`, `diamond`, `rule`.
- **Plates** — `panel` (the dark card), `page` (the logbook paper), `scrim`.
- **Controls** — `item` (the one control shape every card uses, with the focus
ring a controller needs), `cap` / `capInk` (a keycap, a pad button, a touch
target) and `noteChip`.
- **Meters** — `dawnRail` (the sky rising, four keys) and `doseRail` (betafite
green until the warning mark, rust past it).
- **The plate** — `plateFigure(cells, width)`: the 7x10 plate as it stands,
clear glass pale and exposure driving it to black, a brass outline on every
cell the target asked to be dark and a rust ring on every cell that reads
wrong. The result card's whole argument.
- **Marks** — `lensMark`, `crystalMark`, `frisketMark`, `pauseMark`,
`dawnMark`, `tubeMark`, `diagramMark`, each sized from the screen.
Every size is a fraction of the live screen. No pixel constant is written here
apart from the physical floors, so one tree composes at 1080x1440, at 1920x1080
and on a phone held either way.
`theme.live` is the one table that outlives a hot reload: a component's
module-level locals belong to the chunk that declared them, so the claim on an
input scheme is stamped here where the next chunk can find it.