hud
Turns a board snapshot into the four widget trees of the mission HUD. Pure presentation: it holds no game state, reads `game.core` for the grid, palette and monk records, and is driven by the `Hud` component.
game.ui.hud.hud — the in-mission interface
Turns a board snapshot into the four widget trees of the mission HUD. Pure
presentation: it holds no game state, reads game.core for the grid, palette
and monk records, and is driven by the Hud component.
local Hud = require("game.ui.hud.hud")
The frame
The screen is 1080 x 1440 — portrait. The interface stacks down it and leaves the middle band to the board:
| band | y | screen | what it holds |
|---|---|---|---|
| queue | 0 – 206 | hud_queue | the initiative order as painted portraits, the round, the blight meter |
| board | 206 – 1040 | hud_board | floating numbers, the destination chip, the phase banner — never takes pointer input |
| inspector | 1040 – 1252 | hud_inspect | the tile plate and its next growth stage, or the itemised hit chance |
| actions | 1252 – 1440 | hud_actions | the active monk, AP pips, end turn, and eight ability tiles |
Hud.W, Hud.H, Hud.QUEUE_H, Hud.BOARD_TOP, Hud.BOARD_H,
Hud.INSPECT_TOP, Hud.INSPECT_H, Hud.ACTIONS_TOP, Hud.ACTIONS_H and
Hud.SCREENS publish those numbers so another slice can stay clear of them.
Building the trees
Hud.queueTree(view) Hud.boardTree(view) Hud.inspectTree(view) Hud.actionsTree(view)
Each takes one view table and returns a widget tree whose root is an area.
The Hud component assembles the view; its shape:
view = {
snapshot = { units, order, activeUnit, round, phase, blightShare, tiles },
dividerAt = number, -- how many queue entries belong to this round
tile = tile?, -- the hovered tile, for the inspector
hit = hit?, -- an aimed shot; wins over `tile`
dest = dest?, -- { tx, ty, x, y, ap, cover, warn } the destination chip
floaters = { … }, -- { x, y, text, kind, sub, age, life }
banner = banner?, -- { title, sub, tone, age, life }
selectedAction= string,
actionHint = string?,
actionStates = { [actionId] = { usable = boolean, reason = string? } },
hoverHint = string?,
}
A hit is what the rules slice's hitChance() returns, plus the target's
name and crest:
hit = { chance, modifiers = { { label, value, note } … }, damage, crit,
reason, targetName, targetKind, targetSub, attackerName }
Art
Every glyph, portrait, crest, botanical plate and ornament is authored as SVG
in this module and installed as a .svg asset under
/source/game/ui/hud/art/. Hud.installArt() writes them (idempotent; the
Hud component calls it in awake), and the trees place them with image
widgets by name.
Hud.art() -- every piece, keyed by asset name
Hud.installArt(force?) -- write them out; returns how many were written
Hud.portraitOf(kind) -- hud_portrait_anselm … hud_portrait_blight (170x148)
Hud.crestOf(kind) -- hud_crest_anselm … hud_crest_blight (32x32 roundel)
Hud.plateOf(kind) -- hud_plate_creepvine … hud_plate_stone (118x118)
Hud.glyphOf(id) -- hud_glyph_move … hud_glyph_endturn (44x44)
Each .svg declares the exact pixel size it is placed at, because the importer
bakes at the declared size with nearest-neighbour filtering.
Pieces another slice can reuse
Hud.apPips(ap, maxAp) -- a row of gold action-point rosettes
Hud.coverChip(level, compact) -- shield + EXPOSED / HALF COVER / FULL COVER
Hud.hitArea(id, callbackId) -- a transparent click surface over a styled box
Hud.actions(monkId) -- the eight action records for the bar
Hud.roman(n) -- I, II, III … for round counters
Hud.tileName(x, y) -- "D-6"
Hud.C, Hud.T, Hud.merge -- the colour tokens, the type styles, a style merge
Hud.demoSnapshot() and Hud.demoHit() are a worked mid-mission board and a
worked breakdown, drawn whenever no Director is answering so the interface is
never a blank frame.
Typography
Georgia for the illuminated display line and the rubrics, Liberation Serif for
the body, monospace for anything the player counts. Colours come from
Core.PALETTE, converted to CSS once in Hud.C.
Scoped to this part · feeds back into the world's score.