HUD patterns
A HUD lives on one full-viewport, transparent page drawn over gameplay. The examples below use the framework-free classes from @static-bloom/css in the Blackout flavor, over a busy stand-in for game imagery. The Vue package has the same pieces as components: SbHudPanel, SbStatBar, SbKeyHint, SbKbd, and SbToast, whose provider is part of SbProvider.
Vitals
Objective
Meet the courier at the night market. 1.2 km
On a real page the widgets sit in the corners of the viewport with fixed positioning; <html> and <body> stay transparent so the game shows everywhere else. The whole HUD is one page: see Performance.
HUD panel
Section titled “HUD panel”sb-hud-panel is a glass frame with a tube hairline, corner brackets and a mono title in the accent color. Add sb-scanlines for texture.
<section class="sb-hud-panel sb-scanlines"> <header class="sb-hud-panel-header"> <h3 class="sb-hud-panel-title">Vitals</h3> <div class="sb-hud-panel-actions">…</div> </header> <div class="sb-hud-panel-body">…</div> <footer class="sb-hud-panel-footer">…</footer></section>| Modifier | Effect |
|---|---|
sb-hud-panel-{secondary,info,success,warning,danger,neutral} |
Accent of the hairline, brackets and title |
sb-hud-panel-compact |
Tighter padding and smaller brackets |
sb-hud-panel-solid |
Opaque canvas-sunken fill instead of glass, no blur |
sb-hud-panel-no-brackets |
Drops the corner brackets |
sb-hud-panel-alarm |
Pulses the glow; static under reduced motion |
Stat bars
Section titled “Stat bars”sb-stat is a labelled, segmented bar. --sb-value (0 to 100) sets the fill, --sb-segments the number of segments (10 by default). Keep role="meter" and the aria-value* attributes in sync with the value so assistive technology reads it.
<div class="sb-stat sb-stat-success" role="meter" aria-label="Health" aria-valuemin="0" aria-valuemax="100" aria-valuenow="72" style="--sb-value: 72"> <span class="sb-stat-label">HP</span> <span class="sb-meter"><span class="sb-meter-fill"></span></span> <span class="sb-stat-value">72</span></div>Intents (sb-stat-primary, -secondary, -neutral, -info, -success, -warning, -danger) color the fill. sb-stat-critical turns it to danger and pulses it; sb-stat-sm and sb-stat-lg change the size, sb-stat-stacked puts the bar under the label, and sb-meter-continuous drops the segments. The fill animates its width when the value changes.
4/5
Key hints
Section titled “Key hints”sb-key-hint pairs a keycap with a label. Mark the prompt the player can use right now with data-active, and an unavailable one with aria-disabled="true". Group them in sb-key-hints (or sb-key-hints-vertical).
<div class="sb-key-hints"> <span class="sb-key-hint" data-active ><kbd class="sb-kbd">F</kbd><span class="sb-key-hint-label">Interact</span></span > <span class="sb-key-hint" aria-disabled="true" ><kbd class="sb-kbd">R</kbd><span class="sb-key-hint-label">Reload</span></span ></div>Show the key the player actually bound, not a hard-coded default: the client script knows the mapping and can send it with the HUD state.
Toasts
Section titled “Toasts”sb-toast styles a notification: glass, an intent bar on the leading edge, an optional icon, title, description, action and close button. It slides in on mount. Place toasts in a sb-toast-region (-top-right, -bottom-left, -top-center, …), which is fixed to the viewport and stacks them.
<div class="sb-toast-region sb-toast-region-top-right" role="region" aria-label="Notifications"> <div class="sb-toast sb-toast-success" role="status"> <div class="sb-toast-title">Job accepted</div> <div class="sb-toast-description">Courier run · 4,500 credits</div> </div></div>Toasts tell the player something without taking focus, so they never need page:setFocus. Keep them short and remove them after a few seconds.
Legibility over the game
Section titled “Legibility over the game”The scene behind a HUD can be anything: a white sky, neon signs, an explosion. Contrast guarantees hold only for solid colors, so:
- Use Blackout, the flavor with the darkest neutrals.
- Put every piece of text on a panel: glass for most widgets,
sb-hud-panel-solidorsb-cardfor dense text and over very bright scenes. Never set bare text on the game, which is why the key hints above sit on a glass strip. - Keep text at 0.875rem (
text-sm) or larger, use the display face for short labels only, and show numbers in the mono face with tabular figures, assb-stat-valuedoes. - Reserve glow for state: a critical stat, an alarm, the active prompt. A glowing HUD has no hierarchy.
Measured over a bright day scene, a night scene and a neon scene, Blackout keeps every HUD text at 4.5:1 or more on the 88% glass. In Midnight, accent-colored titles, values, badges and buttons dip to 4.0:1 over very bright scenes, and in Dusk to 3.3:1; sb-hud-panel-solid brings panel text back above 4.5:1 in both. Daybreak is a website flavor: its HUD panel titles stay near 3.6:1 even on a solid panel.
Glass
Solid
Performance
Section titled “Performance”- One page for the HUD. Every WebUI page is a separate browser with its own GPU memory, and a client allows 32 pages for all of a server’s resources. Stat bars, key hints, toasts and the minimap frame belong on the same page (budget).
- Keep it still when nothing changes. A page repaints for every animation frame. Use the looping effects (
sb-hud-panel-alarm,sb-stat-critical,animate-pulse-glow,animate-flicker) for real alerts and remove them when the alert ends. Pages render at 30 frames per second unlessWebUI.createsets anotherfps. - Few glass panels.
backdrop-filterblurs the game behind the panel on every repaint. A handful of small panels is fine; for a large or always-visible surface, prefersb-hud-panel-solid. - Animate cheap properties. Transitions on
transformandopacitystay on the compositor; the stat fill animates its width only when the value changes. - Batch state. Send one
hud:stateevent with every value rather than one event per widget, and update the DOM once per event.