ui.theme — the game's visual language
local T = require("ui.theme")
The palette as CSS strings, the type scale, the woodblock ornament, and the
composed primitives every screen is assembled from. Colours come from
ST.PALETTE, so the screens and the world are the same game.
Colour
T.C — sumi indigo vermillion gold bone magenta cyan acid
violet, plus the working greys (ink panel panelHi line lineSoft
dim dimmer). T.LANE[1..4] is the lane accent; T.JUDGE[id] is
{ hex, label, english } per judgement. T.pal(name, alpha?, scale?) mixes
one on the fly.
Type
T.FONT — display (Anton), heavy (ArchivoBlack), grot
(BricolageGrotesque), body (PTSerif), mono (BerkeleyMono).
Latin only. No font available to this engine carries CJK glyphs, so a kanji renders as an empty box. The screens are set in the romaji the design already carries and the Japanese reads through the ornament.
Ornament
T.ART names the baked marks under /source/ui/art/: torii toriiGold
oni mon rays raysEmber waves seal fan. Draw one with
T.art(name, w, h, style?).
They are authored as .svg files, which the importer bakes into
.texture assets. Colour is baked in, so a mark needed in two colours is two
files, and a changed mark goes to a new filename — a re-import over an
existing .texture keeps the old image.
Primitives
T.kicker T.rule T.gap T.panel T.heading T.button T.keycap
T.meter T.dataRow T.body T.backdrop T.enter.
T.body(text, opts) is the one to reach for for paragraph text: it breaks
the line in Luau and emits one label per line. Do not set props.wrap = true
on a label — a wrapping label stops every widget after it in the screen from
painting.
T.setAnimated(bool) gates the entrance animations. They advance in play and
freeze in edit, and because an entrance holds its first keyframe a screen
authored with motion is invisible in the mode an author captures in — so the
HUD slice turns them on only when the engine is actually running them.
Scoped to this part · feeds back into the world's score.