ui/screens/cards.module — every full-screen card KESSREL LINE puts in front
of the player: the title, the how-to-play handbill, the pause card, the
credits, and the two endings.
Every builder here is PURE: it takes the metrics and a view model and
returns a widget tree. Nothing registers a screen, reads the bus, or writes
game state — `ui.screens.Screens` does all of that and hands the result in.
That is what lets one card be rebuilt every frame from the live focus, and
what lets a capture of a card be reproduced from a table.
local Cards = require("ui.screens.cards")
local m = Cards.metrics()
ui.registerScreen("kl.card", Cards.title(m, { focus = Focus.id() }), 1200)
LAYOUT RULE: nothing in this file carries a number chosen for 810x1080.
`metrics()` derives every size from the live `ui.screenSize()`, so the same
card composes on a phone held either way, a laptop and a television.
metrics( ) → Metrics
The live layout metrics, derived from ui.screenSize() every time a card is built.
tick(m: Metrics, lit: boolean) → void
Pieces
| arg | type | description |
|---|
| m | Metrics | |
| lit | boolean | |
row(m: Metrics, id: string, text: string, lit: boolean) →
One slab of the menu language: a dark glass bar, bracket ticks, and the amber fill when it holds the focus.
| arg | type | description |
|---|
| m | Metrics | The metrics. |
| id | string | The element id, which is also the focus id and the callback id. |
| text | string | The label. |
| lit | boolean | Whether this row holds the focus. |
rowStack(m: Metrics, rows: { { id: string, text: string } }, focus: string?) → void
A stack of rows, each carrying its own focus state.
| arg | type | description |
|---|
| m | Metrics | |
| rows | { { id: string, text: string } } | |
| focus | string? | |
rule(m: Metrics, widthFraction: number) → void
The thin amber rule under the wordmark.
| arg | type | description |
|---|
| m | Metrics | |
| widthFraction | number | |
scrim(stops: string) → void
The scrim that sits between the painted plate and the type, so bone-white
reads over a bright sun and the slabs read over a lit trooper.
| arg | type | description |
|---|
| stops | string | |
shell(m: Metrics, opts: { plate: string?, scrim: string, dim: number? }, content: { any }) → void
Every card is this shell: a painted plate, a scrim over it, and a padded
content column that never leaves a 16-point gutter at any width.
| arg | type | description |
|---|
| m | Metrics | |
| opts | { plate: string?, scrim: string, dim: number? } | |
| content | { any } | |
column(m: Metrics, children: { any }, justify: string?) → void
| arg | type | description |
|---|
| m | Metrics | |
| children | { any } | |
| justify | string? | |
wordmark(m: Metrics) → void
The wordmark: KESSREL over LINE, bone-white with a worn amber edge.
| arg | type | description |
|---|
| m | Metrics | |
heading(m: Metrics, kicker: string, head: string, headColor: string?) → void
A card heading: an amber kicker over a bone-white stencil headline.
| arg | type | description |
|---|
| m | Metrics | |
| kicker | string | |
| head | string | |
| headColor | string? | |
panel(m: Metrics, children: { any }) → void
A panel of smoked glass — what every body of text sits on.
| arg | type | description |
|---|
| m | Metrics | |
| children | { any } | |
controlRow(m: Metrics, action: string, control: string) → void
One action row of the control table: the action, then the control for the
chosen device.
| arg | type | description |
|---|
| m | Metrics | |
| action | string | |
| control | string | |
controls(device: string, g: PadGlyphs) → void
| arg | type | description |
|---|
| device | string | |
| g | PadGlyphs | |
title(m: Metrics, view: TitleView) → void
The title card: the wordmark over the painted battle, and the three slabs.
| arg | type | description |
|---|
| m | Metrics | |
| view | TitleView | |
howto(m: Metrics, view: HowToView) → void
The how-to-play handbill: the control table for one device family, with a tab per family.
| arg | type | description |
|---|
| m | Metrics | |
| view | HowToView | |
pause(m: Metrics, view: PauseView) → void
The pause card.
| arg | type | description |
|---|
| m | Metrics | |
| view | PauseView | |
ending(m: Metrics, view: EndView) → void
The victory or defeat card, with the tally.
| arg | type | description |
|---|
| m | Metrics | |
| view | EndView | |
credits(m: Metrics, view: CreditsView) → void
The credits card.
| arg | type | description |
|---|
| m | Metrics | |
| view | CreditsView | |
stage(m: Metrics, view: StageView) → void
The cinematic overlay: the letterbox bars, the SKIP row, and the beat banner.
| arg | type | description |
|---|
| m | Metrics | |
| view | StageView | |
subtitle(m: Metrics, view: SubtitleView) → void
The subtitle strip: every spoken line, in text, over the bottom of the frame.
| arg | type | description |
|---|
| m | Metrics | |
| view | SubtitleView | |
⌬ Types
Metrics = {PadGlyphs = { south: string, east: string, west: string, north: string, start: string }TitleView = { focus: string?, plate: string? }HowToView = { focus: string?, device: string, glyphs: PadGlyphs, backLabel: string, plate: string? }PauseView = { focus: string?, wave: number, waveTotal: number, gate: number }EndView = {CreditsView = { focus: string?, backLabel: string, plate: string? }StageView = {SubtitleView = { speaker: string, text: string, alpha: number, raise: number }