confection
Gumdrop Vale's feel and interface — slice C of three.
require("confection") returns { start, stop }, the slice-boot contract
GV.bootSlices() calls. It subscribes to the gv event bus, reads GV.state,
and never writes it.
What it owns
| Piece | Where |
|---|---|
| The HUD tree — charge pips, wells bloomed, the Hush meter, a compass, on-screen well markers | confection/gvc_hud.module |
| The three phase cards — title, won, lost | confection/gvc_cards.module |
| The carried bubble, the sparkle bursts, the sounds, the lens kick | confection/gvc_bubble.module |
| The bubble's translucent iridescent surface | confection/gvc_bubble.material |
Two screens are registered: gv_hud at layer 20 and gv_card at layer 40.
How it reads the world
GV.state is polled every tick; events are used only for the moment a thing
happens (a pip pop, a flash, a card, a sound). That is why the HUD stays correct
even when the bus is reset out from under the slice.
The compass and the well markers come out of the camera's view-projection
matrix, which camera.viewData() publishes column-major. Row 3 of that matrix
is the camera's forward direction and row 0 is the world direction that maps to
+x on screen, so a bearing falls out of two dot products and needs no yaw
convention. Projecting a well through the full matrix gives the marker its
screen position; a well behind the camera is pinned to the side it is on.
Two things worth knowing before editing it
- Every HUD animation is numeric, driven from wall clock. A CSS
animationrestarts whenever its node is re-pushed, and this screen is re-pushed 12 times a second, so CSS motion would sit frozen on its first keyframe. The cards, which mount once per phase change, do use CSS. Accumulatedstepis not usable either: under load the scheduler runs several pending iterations inside one frame, which burns a half-second effect in a single frame. - Everything the slice spawns is marked temporary. These are HUD props, not
scene content; without the flag an accepted scene review bakes them into
scenes/main.sceneand the slice then spawns a second copy of each.
Checking it without the rest of the game
M.debugView() returns exactly what the HUD is painting this instant, and
M.debugFx() returns the fx/audio module as this slice holds it — requiring
confection.gvc_bubble by identity from outside hands back a separate copy that
reports empty state.
gvc_hud.build(v) is pure, so any state can be rendered without reaching it
through play:
local Hud = require("confection.gvc_hud")
local v = Hud.blankView()
v.charge, v.charged = 3, true
v.hushRemaining, v.hushFraction = 41, 41 / 300
v.reprievePulse = 0.9
ui.registerScreen("probe", { type = "vertical",
style = { position = "absolute", left = 0, top = 0, width = 1280, height = 720,
background = "#5b5566" },
children = { Hud.build(v) } }, 60)
ui.showScreen("probe")
Scoped to this part · feeds back into the world's score.