Log inGet started
World

Blockbuster 767

Branchmain
Branchesmain
Commit8e9b87fcce

README.md

theme

The look of BLOCKBUSTER 767's screens, in one place: the palette, the typefaces, the metrics every screen sizes itself from, and the style fragments the cards share.

local Theme = require("game.ui.theme")
local m = Theme.metrics()
{ type = "label", style = { fontSize = m.fs.title, fontFamily = Theme.font.display, color = Theme.color.cream } }

The metrics rule

Nothing is a pixel number chosen for one screen. Theme.metrics() reads the live ui.screenSize() and derives everything from it:

  • Type and rhythm are a share of the SHORTER side, so a phone held either way and a television read the same.
  • Both are additionally capped against the HEIGHT. A card is a column, and a wide screen is also a short one; without that cap the card that fits a 3:4 frame runs off the bottom of a 16:9 one.
  • The two big pictures — hero (the toy on a card) and strip (the skyline along its foot) — are budgeted straight out of the height they have to fit in.
  • cardW caps a card to a readable single column instead of letting it stretch across a wide monitor.

Theme.metricsFor(w, h) computes the same table for a shape the engine is not currently running at — which is how a card is laid out and looked at for a screen other than the one in front of you.

The palette

Warm shadow, painted wood, poster paint on the toy, crayon accents, and the gold of a sticker star. Theme.color names them; Theme.font names the four voices (a poster face for the logo, a heavy face for headings, a plain face for reading, a mono for numbers, and the round childlike face the Kid speaks in).

The fragments

cardBackdrop (the playroom wash a card is printed on; its see argument is the share of the ROOM that shows through, and the scrim's opacity is 1 - see), panel (a raised surface with a lit top rim), row (a menu row at rest or with the focus on it), chip (the small rounded plastic label a keycap, a pad glyph and a touch hint are all made of), stat (a number with its name under it), and the three motions: enterDrop, enterRise, pulse.

Nothing here animates for ever, and pulse breathes on opacity alone. A keyframe that animates transform: scale re-measures the widget's box every frame, which relays out the whole tree it sits in; two HUD widgets each held one of those permanently and one frame in ten was over budget because of it. pulse(iterations) counts — eight breaths by default — so even the opacity animation ends.

No entrance starts from nothing. An entrance holds its first keyframe until its delay elapses and the UI clock is the game clock, so a card opened while something is holding engine.timeScale down would sit on that first frame. They start dimmed and slightly displaced instead, so the worst a stalled clock can do is leave a card looking a shade soft.