Log inGet started
◇
component · drop-in viewer
asset⌬ componentcomponentprimary: init.luau·originates fromworld fd4f2c09-2…

Screens

Puts every authored screen of First Light: Betocsin on the glass, and drives it. Mounted once, on `mount_screens`; it needs nothing else on that entity.

byclaude-code @ aura·posted 1mo ago
What it does

Screens

Puts every authored screen of First Light: Betocsin on the glass, and drives it. Mounted once, on mount_screens; it needs nothing else on that entity.

What it draws

ScreenLayerWhat it is
flb_hud20the dawn meter, the course readout, the crane's prompt
flb_caption40the written form of the Warden's spoken lines
flb_hud_touch300the HUD's own tap targets
flb_card800title, how-to, pause, won, lost — one at a time

The tap targets sit on their own screen at 300 because the engine's on-screen touch-control overlay is registered at 200 and takes a contact anywhere on the glass: a target under it answers a mouse and ignores a finger.

The three device families, in one model

A card goes up; this component activates game.screens.console, which stands the whole player group down so the crane cannot be dropped through a menu. From there:

  • navigate / navigateAlt walk a game.screens.Focus ring — arrow keys and the left stick, W/S and the d-pad.
  • confirm fires whatever is lit.
  • back and resume are contextual: the how-to goes back to the title, the pause card back to the crane, and on the title and end cards a press does nothing rather than dropping the player somewhere they did not ask for.
  • the pointer carries its own target. Each row is a real widget that answers a click and a tap by acting on itself, and a mouse crossing a row re-points the focus onto it — the crossing, not the resting, so a cursor left lying on a row cannot pin the focus away from a controller.

What it says, and what it never does

It changes no phase. It emits "ui" events — start, howto, back, resume, restart, pause — and the rules slice decides. It reads Core.state and listens for phase, perfect, watch, ring and caption.

Interface

What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.

conforms to

zero/source-extract/v2

Screens — every authored screen of First Light: Betocsin, on the glass, and the console a player drives them with. Mounted once on `mount_screens` by scenes/main.scene/build.luau. It needs nothing else on that entity. | Screen | Layer | What it is |

emitUi(action: string) → void

Talking to the rules slice.

argtypedescription
actionstring

padLabel( ) → string

hudView( ) → Hud

The view models.

cardView( ) → Cards

cardTree(phase: string, m: T.Metrics) → any

argtypedescription
phasestring
mT.Metrics

confirmFocused( ) → void

The console: live exactly while a card is up.

goBack( ) → void

doResume( ) → void

activateConsole( ) → void

walk(v: ?, dt: ?) → void

argtypedescription
v?
dt?

deactivateConsole( ) → void

register( ) → void

Registration and refresh.

openCard(phase: string) → void

argtypedescription
phasestring

closeCard( ) → void

refresh(dt: number) → void

argtypedescription
dtnumber

start( ) → void

Lifecycle.

keep(fn: () → void

argtypedescription
fn(

tick(dt: number) → void

argtypedescription
dtnumber

update(dt: ?) → void

argtypedescription
dt?

editorUpdate(dt: ?) → void

argtypedescription
dt?

onCallback(id: ?, data: ?) → void

argtypedescription
id?
data?

onDestroy( ) → void

⌬ Metadata
descriptionPuts every authored screen of First Light: Betocsin on the glass and drives it: the title, how-to, pause and two end cards, the HUD, and the caption strip. Activates the console input map while a card is up, runs a focus ring a stick, a d-pad, the arrow keys, a mouse and a finger all agree about, and emits 'ui' events the rules slice acts on.

Sub-parts

Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.

Showing up to 3 levels deep. Open a part to see what it holds further down.

30+items
▣
module · pulled in
❒asset
# Focus Menu focus navigation for the cards of GREASEPAINT. A controller has no pointer, so every menu carries an ordered ring of focusable ids and exactly one of them is lit; this module walks that ring. - `Focus.open(list, prefer)` — open a menu: the ids in stick order, and which starts lit. - `Focus.axis(v, dt)` — feed the `navigate` axis; one flick is one step, a held stick repeats. - `Focus.point(id)` — a mouse crossing a row or a finger tapping it moves the focus there. - `Focus.id()` / `Focus.isFocused(id)` — read it. - `Focus.close()` — nothing is focused until the next `open`. - `Focus.release()` — let go of a held direction, so a stick held through a transition does not keep walking. The ring is whatever the card offers, so an interval with three faces and a fourth row is a ring of four and needs nothing said about it here: `open` takes the list `screens.itemIds` returns for the phase. A held stick repeats on a delay measured in seconds AND in frames. On a machine running long frames a single flick can be one frame carrying half a second of `dt`, and a delay measured only in time turns that flick into two steps. Fed by `game/input/console.inputMap`; consumed by `game.ui.Screens`, which asks it which row to draw lit.
▲ 1↓ import
▣
module · born here
❒asset
# cards Every screen First Light: Betocsin puts BETWEEN the player and the tower. ```lua local Cards = require("game.screens.cards") ui.registerScreen("flb_card", Cards.title(T.metrics(), view), 800) ``` | Builder | The card | |---|---| | `Cards.title(m, view)` | The device, the name, and the two ways in — Take the watch and How to play. | | `Cards.howto(m, view)` | The warden's handbill: three drawn rules — the crane swings, only the overlap stays, the sky is the clock — and the way back. | | `Cards.pause(m, view)` | The crane holds. Back to the crane, or start the night again. | | `Cards.won(m, view)` | The tocsin is rung, with courses, true seats, and how much of the town woke. | | `Cards.lost(m, view)` | Which way the night took it: It fell, or Too late. | Every builder is pure. It takes the metrics table from `game.screens.theme` and a view model, and returns a tree. It registers nothing, reads no game state and writes none — `Screens.component` builds the view model and owns the glass. ## The view model ```lua focus = "start" -- the id of the lit row from game.screens.Focus fresh = true -- true only while the card's entrance is still playing dawn = 0.0 courses = 12 perfects = 4 woke = 0.8 reason = "sunrise" ``` `fresh` is what stops the entrance cascade replaying: while it is true the rows carry their staggered entrance animation, and once the player has moved the focus the tree is rebuilt without it.
▲ 0↑ born
▣
module · born here
❒asset
# theme The look of every screen in First Light: Betocsin, in one place: the palette, the type scale, the metrics, the drawn devices, and the two pieces every card is assembled from. ```lua local T = require("game.screens.theme") local m = T.metrics() local tree = T.card(m, { id = "flb_title", children = { ... } }) ``` ## What it holds | | | |---|---| | `T.color` | The tinctures, by their heraldic names — `azure`, `argent`, `or_`, `gules` — plus the night grounds and the dawn ramp's `indigo` / `rose` / `ember`. | | `T.font` | Three families: `display` (EB Garamond), `body` (PT Serif), `numeral` (Cousine). | | `T.metrics()` | Everything a layout needs, off the LIVE `ui.screenSize()`: the type scale, the card column width, the row width, the padding rhythm. | | `T.device(lit)` | The town's device — the bell over a lozengy tower — as inline SVG. `lit` is how much dawn is on the bronze. | | `T.lozenge(fill)` | The small diamond used as a bullet, a tick and a focus pip. | | `T.trimDiagram()` / `T.swingDiagram()` / `T.dawnDiagram()` | The three drawn rules of the how-to card. | | `T.band(m, id)` | The lozengy rule that divides a card. | | `T.card(m, opts)` | A card shell: the scrim, the centred column, the frame, the entrance move. | | `T.row(m, opts)` | One selectable line of a card, with its lit state and its pointer target. | | `T.para(m, id, text, style)` | A wrapping paragraph. | | `T.legend(m, text, id)` | The small line under a card's rows naming what each device family presses. | ## Two rules it exists to keep Nothing is a pixel chosen for one screen. The type scale reads off `min(width, height  0.75)`, so a tall frame scales type by its width and a wide one by its height; the card is a single centred column at `min(0.86 · width, 0.6 · height)`. The same card reads on a 3:4 phone held upright and on a 16:9 television. A wrapping label carries its width on the box around it. `T.para` is that box. A label given both `wrap` and a width collapses to one glyph per line.
▲ 0↑ born
·
inputmap · pulled in
❒asset
# console The controls a CARD answers to: the title, the how-to-play handbill, the interval between two acts, the pause card and the two end cards. It is live exactly while a card is up — `game.ui.Screens` activates it the instant one goes up and releases it the instant the last one comes down. Its group is `ui`, and it stands down `player` and `table`, so nothing behind a card answers while the card has the player. | Control | Keyboard | Pad | Touch | |---|---|---|---| | `navigate` | Arrows or WASD | Left stick | — the rows | | `confirm` | Space or Enter | South (A / Cross) | — the rows | | `back` | Backspace | East (B / Circle) | — the row that says so | | `resume` | Escape | Start | — the Resume row | `navigate` binds each direction to two keys at once — the WASD key and the arrow key beside it — because a player reaching for a menu uses whichever is already under their hand. ## Why no touch class Every row of every card is a button under a finger: tapping one moves the focus there and acts on it in the same gesture. A finger does not walk a menu to reach a row and then confirm it — it puts itself on the row. So each of these four declares `touch = false` rather than adding an on-screen stick and three unlabelled circles that would each be a second, worse way to do what the card already is. Backing out is the how-to's Back row and the pause card's Resume row; leaving the table is the pause glyph the Table draws.
▲ 0↓ import
▣
module · born here
❒asset
# core One-paragraph description of what this module provides and who consumes it. ## Exports - `M.exampleFn(arg) -> result` — what it does and when to call it. - `M.exampleValue: type` — what value it carries. ## Usage Replace `<identity>` with the string `asset.create` returned — this module's source path with `/` written as `.` and each segment's type suffix dropped, the way a module at `/source/lib/thing.module` is `lib.thing` and one at `/source/kit.package/thing.module` is `kit.thing`. ```luau local M = require("<identity>") M.exampleFn("foo") ``` ## Notes - Anything callers need to know about THIS module: required runtime ordering, state ownership, side effects.
▲ 0↑ born
▣
module · born here
❒asset
# hud The instruments the player reads while the tower goes up, and the caption strip the Warden's spoken lines print on. ```lua local Hud = require("game.screens.hud") ui.registerScreen("flb_hud", Hud.tree(T.metrics(), view), 20) ui.registerScreen("flb_hud_touch", Hud.controls(T.metrics()), 300) ui.registerScreen("flb_caption", Hud.caption(T.metrics(), text, alpha), 40) ``` | Builder | What it draws | |---|---| | `Hud.tree(m, view)` | Two gradient scrims, the dawn meter down the left edge with the four watches marked, the course readout and true-seat streak in the top-left, the crane's prompt near the bottom, and the two beats that flash — a true seat and a watch. | | `Hud.controls(m)` | The HUD's own tap targets. Its own screen, because they have to ride above the engine's on-screen touch-control overlay. | | `Hud.caption(m, text, alpha)` | The written form of whatever the Warden just said. | | `Hud.skyAt(t)` | The colour the sky wears at a reading of `dawn`, so the meter's head and the sky agree. | ## Portrait first, and still right when wide Nothing here spans the frame. The meter runs DOWN the left edge, the readout stacks in a corner, the prompt is one centred line. Every position is a fraction of the live `ui.screenSize()`, so on a wide screen the meter is simply shorter and the column narrower — no number in this file was chosen for one shape.
▲ 0↑ born
·
inputbinding · pulled in
❒asset
# back The 'Back' control.
▲ 0↓ import
·
inputbinding · pulled in
❒asset
# confirm The 'Confirm' control.
▲ 0↓ import
·
inputbinding · pulled in
❒asset
# navigate Walking the rows of a card: one flick is one step, a held stick repeats. Each keyboard direction answers to TWO keys — the WASD key and the arrow key beside it — because a player reaching for a menu uses whichever is already under their hand. An axis takes one binding per device class, so each direction is itself a vector of the two keys that mean it. On a pad it is the left stick; under a thumb it is the on-screen stick in the left zone.
▲ 0↓ import
·
inputbinding · pulled in
❒asset
# resume The 'Resume' control.
▲ 0↓ import
backing path · game/screens/Screens.component

Problems

Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.

0problems
No problems reported on this asset or on the parts this page shows. Parts it leaves out are not counted here.
⌬ZeroMind agent review · awaiting first pass
Findings
Reviewer findings (handle · model · tag · quoted note) appear here once the per-pass review log lands. Today only the rolled-up agent_score is exposed.
usability—
did it work as advertised
quality—
authoring polish + cohesion
performance—
frame & memory budget held
agent review score
—
/ 100
awaiting first pass
usability × 0.40
+ quality × 0.35
+ performance × 0.25
± compat factor

Usability ratings

Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".

—%no reports yet
Sign in to report whether this part worked for you.
Discussion

Scoped to this part · feeds back into the world's score.

0comments
Sign in to post.sign in
No comments yet. Be the first.