Design in-game interfaces: HUD zoning and hierarchy, meters and numerals, menu and overlay states, touch targets and safe areas, for Phaser, Three.js or DOM.
Build a game interface, not a web dashboard. The defining failure of
prompt-built game UI: nested cards, marketing-hero title screens, generic
dashboard styling, and web-app typography wrapped around a canvas.
Anti-patterns to reject on sight: stat cards in rounded boxes inside boxes,
a hero section with a tagline over the game, <h1>-styled headings in a HUD,
one-note purple/blue gradient panels.
Hierarchy follows gameplay priority: survival/status first, objective/progress
second, immediate feedback third, flavor last. Prefer meters, icons, cooldown
rings, badges, and compact clusters over labeled stat cards — a meter is read
at glance-speed mid-dodge; a card is not.
Center: reserved for transient banners (wave start, combo, warnings) —
never persistent chrome, never stacked banners over the play path.
In-world (diegetic) where possible: target markers, off-screen threat
indicators, damage numbers, prompts anchored to the thing itself.
Keep all UI out of the play path — away from the player, threats, pickups,
and the next decision.
No control instructions during play. "M to mute", "WASD to move" and
standing hint bars belong on the initial screen only. Allowed in play:
pause/game-over/match-end modals (keep "P to resume"), just-in-time prompts
gated on a transient state, ability-bar keycap glyphs, ?editor= /
?gallery= scenes. Mute renders icon-only with an aria-label. If
stripping a hint leaves it untaught, build a start screen.
Numbers that don't dance
Fixed-width numeric containers for score, timer, ammo, speed, health:
tabular numerals (font-variant-numeric: tabular-nums) or a monospace face.
Changing values must never shift layout.
Test the longest likely value: max score, MM:SS timer, multi-digit
combo. No clipping, no wrap, no neighbor displacement.
Animate value changes briefly (count-up, meter fill, pulse) — a silently
incrementing corner number reads as broken (see game-feel).
Color roles
One color = one meaning, everywhere: danger (damage, low health), reward
(score, pickups), shield/defense, boost/power, objective, disabled. A limited
status palette over neutral surfaces beats a rainbow. Critical states get two
channels (color + shape/motion/sound) — never color alone.
Menus & overlays
Required states beyond the HUD: pause/resume, fail/retry, win/next when
relevant. Primary action first and biggest (resume, retry); secondary
actions (settings, quit) smaller.
Buttons have stable dimensions plus hover/pressed/focus/disabled states.
Overlays pause underneath, act in one input, and never look like a landing
page. Debug/tuning UI gates behind a dev flag or query param — it never
ships as player UI.
UI reads from the game state (single source of truth) and dispatches
intents; check for stale values after restart.
Nothing before start. Gate HUD, thumb pads and restart on a started
state; camera panels fold to one pill until a stream is live. Sound toggle
the M binding live on the pause shell (games boot muted; phones still
need an unmute path) — never on the touch cluster, which is pause-only.
Start overlay over a live sim: dismiss on key/pointer RELEASE
(keyboard.once("keyup")) — keydown lets the same SPACE also fire. The
overlay covers the canvas, so attach the pointer listener to the overlay
element. A pause hook that no-ops before started makes a start-screen
pause button a dead control — hide it until it works.
Trap: .x button { display: grid } beats the UA [hidden] rule, so
el.hidden = true silently no-ops. Add button[hidden] { display: none }.
Touch controls (mobile)
~44 CSS px minimum touch targets, with enough separation that adjacent
controls can't be fat-fingered.
Safe-area insets: pad edge controls with env(safe-area-inset-*);
nothing interactive under the notch or home indicator.
Release paths: handle pointerup, pointercancel,
lostpointercapture, window blur, and visibility change — a stuck
virtual button is a stuck key. Controls emit the same game intents as
keyboard. preventDefault() on pointerup does not stop the compat
click that follows touchend ~1 ms later — cancel touchend.
The touch cluster is pause-only; every other action lives on the pause
overlay.
touch-action: none only on the game surface and control regions, so page
scroll/zoom can't steal input.
Don't scale text with viewport width; use clamp() with sane floors.
Verify portrait and landscape if both are supported.
Ship checklist
First screen is the game (or a deliberate modal), not a landing page.
No nested cards / dashboard styling / marketing-hero layout.
HUD zones match the map above; center is transient-only.
Score/timer/ammo use fixed-width numerals; longest value tested.
Alert colors consistent; critical states have ≥2 feedback channels.
Pause, fail/retry (one input, <2s), win states exist and work.
No control hints in play; start screen teaches them; mute is icon-only.
Text legible over bright, dark, and moving backgrounds.
Mobile: 44px targets, safe-area insets, release-path handling, no
overlap between controls and HUD warnings.
No layout shift, clipping, or overlap at desktop / narrow / phone
widths.
Debug UI gated; no stale HUD values after restart.
Related skills: game-feel (juice on value changes), onboarding (first-30s
and control hints), design-lenses (Feedback/Accessibility lenses),
gamepad (physical controller labels/glyphs).
1---2name: game-ui3description: Design in-game interfaces: HUD zoning and hierarchy, meters and numerals, menu and overlay states, touch targets and safe areas, for Phaser, Three.js or DOM.4---56# Game UI78Build a game interface, not a web dashboard. The defining failure of9prompt-built game UI: nested cards, marketing-hero title screens, generic10dashboard styling, and web-app typography wrapped around a canvas.11Anti-patterns to reject on sight: stat cards in rounded boxes inside boxes,12a hero section with a tagline over the game, `<h1>`-styled headings in a HUD,13one-note purple/blue gradient panels.1415Hierarchy follows gameplay priority: survival/status first, objective/progress16second, immediate feedback third, flavor last. Prefer meters, icons, cooldown17rings, badges, and compact clusters over labeled stat cards — a meter is read18at glance-speed mid-dodge; a card is not.1920## HUD zoning2122- **Top-left**: objective, wave, distance, timer, progress.23- **Top-right**: score, currency, combo, pause.24- **Bottom-left/right**: touch movement/action controls (mobile).25- **Center**: reserved for transient banners (wave start, combo, warnings) —26 never persistent chrome, never stacked banners over the play path.27- **In-world (diegetic) where possible**: target markers, off-screen threat28 indicators, damage numbers, prompts anchored to the thing itself.29- Keep all UI out of the play path — away from the player, threats, pickups,30 and the next decision.31- **No control instructions during play.** "M to mute", "WASD to move" and32 standing hint bars belong on the initial screen only. Allowed in play:33 pause/game-over/match-end modals (keep "P to resume"), just-in-time prompts34 gated on a transient state, ability-bar keycap glyphs, `?editor=` /35 `?gallery=` scenes. Mute renders icon-only with an `aria-label`. If36 stripping a hint leaves it untaught, build a start screen.3738## Numbers that don't dance3940- **Fixed-width numeric containers** for score, timer, ammo, speed, health:41 tabular numerals (`font-variant-numeric: tabular-nums`) or a monospace face.42 Changing values must never shift layout.43- **Test the longest likely value**: max score, `MM:SS` timer, multi-digit44 combo. No clipping, no wrap, no neighbor displacement.45- Animate value changes briefly (count-up, meter fill, pulse) — a silently46 incrementing corner number reads as broken (see `game-feel`).4748## Color roles4950One color = one meaning, everywhere: danger (damage, low health), reward51(score, pickups), shield/defense, boost/power, objective, disabled. A limited52status palette over neutral surfaces beats a rainbow. Critical states get two53channels (color + shape/motion/sound) — never color alone.5455## Menus & overlays5657- Required states beyond the HUD: pause/resume, fail/retry, win/next when58 relevant. Primary action first and biggest (resume, retry); secondary59 actions (settings, quit) smaller.60- Buttons have stable dimensions plus hover/pressed/focus/disabled states.61- Overlays pause underneath, act in one input, and never look like a landing62 page. Debug/tuning UI gates behind a dev flag or query param — it never63 ships as player UI.64- UI reads from the game state (single source of truth) and dispatches65 intents; check for stale values after restart.66- **Nothing before start.** Gate HUD, thumb pads and restart on a `started`67 state; camera panels fold to one pill until a stream is live. Sound toggle68 - the M binding live on the pause shell (games boot muted; phones still69 need an unmute path) — never on the touch cluster, which is pause-only.70- **Start overlay over a live sim**: dismiss on key/pointer RELEASE71 (`keyboard.once("keyup")`) — keydown lets the same SPACE also fire. The72 overlay covers the canvas, so attach the pointer listener to the overlay73 element. A pause hook that no-ops before `started` makes a start-screen74 pause button a dead control — hide it until it works.75- Trap: `.x button { display: grid }` beats the UA `[hidden]` rule, so76 `el.hidden = true` silently no-ops. Add `button[hidden] { display: none }`.7778## Touch controls (mobile)7980- **~44 CSS px minimum touch targets**, with enough separation that adjacent81 controls can't be fat-fingered.82- **Safe-area insets**: pad edge controls with `env(safe-area-inset-*)`;83 nothing interactive under the notch or home indicator.84- **Release paths**: handle `pointerup`, `pointercancel`,85 `lostpointercapture`, window `blur`, and visibility change — a stuck86 virtual button is a stuck key. Controls emit the same game intents as87 keyboard. `preventDefault()` on `pointerup` does not stop the compat88 `click` that follows `touchend` ~1 ms later — cancel `touchend`.89- The touch cluster is pause-only; every other action lives on the pause90 overlay.91- `touch-action: none` only on the game surface and control regions, so page92 scroll/zoom can't steal input.93- Don't scale text with viewport width; use `clamp()` with sane floors.94 Verify portrait and landscape if both are supported.9596## Ship checklist9798- [ ] First screen is the game (or a deliberate modal), not a landing page.99- [ ] No nested cards / dashboard styling / marketing-hero layout.100- [ ] HUD zones match the map above; center is transient-only.101- [ ] Score/timer/ammo use fixed-width numerals; longest value tested.102- [ ] Alert colors consistent; critical states have ≥2 feedback channels.103- [ ] Pause, fail/retry (one input, <2s), win states exist and work.104- [ ] No control hints in play; start screen teaches them; mute is icon-only.105- [ ] Text legible over bright, dark, and moving backgrounds.106- [ ] Mobile: 44px targets, safe-area insets, release-path handling, no107 overlap between controls and HUD warnings.108- [ ] No layout shift, clipping, or overlap at desktop / narrow / phone109 widths.110- [ ] Debug UI gated; no stale HUD values after restart.111112Related skills: `game-feel` (juice on value changes), `onboarding` (first-30s113and control hints), `design-lenses` (Feedback/Accessibility lenses),114`gamepad` (physical controller labels/glyphs).
Run npx skillmds@latest add kyh/game-ui in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
Design in-game interfaces: HUD zoning and hierarchy, meters and numerals, menu and overlay states, touch targets and safe areas, for Phaser, Three.js or DOM. It is listed under Coding & Dev Tools on SkillMD.
This skill has not completed SkillMD's automated safety review yet. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
kyh (@kyh) published this skill. Their other Agent Skills are listed on their SkillMD profile.