makepad/skills/makepad-game-ui-designer/SKILL.md
Arena Agent fe21c07d84 skills: add Makepad game skills pack ported from threejs-game-skills
Nine agent skills for building Makepad/Rust games, ported from
majidmanzarpour/threejs-game-skills. Same director-routed workflow and
premium bar; runtime rewritten for this fork's game crates.

- makepad-game-director        entrypoint, routing, continuity, asset probe
- makepad-gameplay-systems     loop, movers vs rigid bodies, input, camera, netplay
- makepad-aaa-graphics-builder lighting, shaders, budget, visual scorecard
- makepad-game-ui-designer     HUD, menus, touch and XR UI
- makepad-debug-profiler       defect bisection and profiling
- makepad-qa-release           verification ladder, evidence, packaging
- makepad-3d-generator         CC0 model search, casts, procedural geometry
- makepad-image-generator      texgen textures, palettes, sky, icons
- makepad-audio-generator      sample bank, mixer, material impacts, 3D audio

Written against the real APIs in libs/game/*, libs/sim and apps/arcade:
the game.* verb table, GameRenderer adaptive quality, the packed 6-float
GameMeshVertex layout, script_mod! splash styling, makepad-test driving,
and the BUDGETS.md numbers. No paid generation API is required - the CC0
library plus seeded makepad-game-gen replaces them.

Includes install.sh (Codex/Claude), validate-skills.sh and a repo-aware
probe_assets.sh; both scripts verified against this checkout.
2026-09-05 21:18:58 +00:00

105 lines
5.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: makepad-game-ui-designer
description: "Design and build Makepad game UI: HUD, menus, pause and win/lose overlays, settings, responsive and touch layout, XR-safe interfaces, and splash-DSL styling. Use for HUD, menu, overlay, scoreboard, minimap, prompt, controls screen, mobile layout, and UI polish work in makepad-widgets and makepad-game-render's hud module."
---
# Makepad Game UI Designer
Game UI is not app UI. It is read in peripheral vision, during motion, while the player is doing something else. Legibility and latency beat elegance.
## Two surfaces
**In-world / overlay HUD** — drawn by the renderer, inside the 3D pass: `makepad-game-render::hud` (`draw_hud_overlay`, `draw_billboard_labels`, `thermometer`), with sim-side HUD state in `makepad-game-sim::hud`. Script verbs: `text`, `bar`, `crosshair`, `label`, `label_text`.
Use this for anything that must sit *with* the world: damage numbers, billboard nameplates, interaction prompts, crosshair, world-anchored markers. It is also the only correct choice in XR.
**Widget UI** — ordinary `makepad-widgets` composed in `script_mod!`. Use for menus, settings, pause, results screens, chat, and anything with real interaction and focus.
Do not put a health bar in a widget layer that must update every frame if the HUD path already does it — you will pay a layout pass for a number.
## Styling with `script_mod!`
```rust
script_mod! {
use mod.prelude.widgets_internal.*
use mod.widgets.*
mod.widgets.GameHudBase = #(GameHud::register_widget(vm))
mod.widgets.GameHud = set_type_default() do mod.widgets.GameHudBase {
width: Fill
height: Fill
draw_bg += { /* look only */ }
}
}
```
Look lives in the DSL, structure and behaviour in Rust. Inheritance (`+=` / `do`) is how a variant is made — copy-pasting a whole widget definition to change one colour is how a theme becomes unmaintainable.
The splash DSL resolves **at runtime**: a malformed style or a missing widget id survives `cargo check` and fails on launch. Always run the app after a UI change.
## The states that must exist
Every one needs a visible surface. Missing states are the most common UI gap in a game that "works".
| State | Must show |
| --- | --- |
| Boot / loading | that something is happening, and progress if it takes > 1 s |
| Menu | start, and how to control the game |
| Playing | the HUD, and nothing else |
| Paused | that it is paused, resume, restart, quit |
| Win | the outcome, the score, what to do next |
| Lose | the outcome, why, retry |
| Settings | audio, controls, quality |
Two recurring bugs: pause that does not stop the sim step, and retry that leaves the previous run's score, timers or audio voices alive. Reset through one `reset()` and test by winning twice in a row.
## HUD principles
- **Only what changes the next decision.** Everything else is clutter. A stat card of nine numbers is a placeholder, not a HUD.
- **Position by urgency.** Critical and instantaneous → near the centre or the crosshair. Ambient → corners.
- **Readable in motion.** High contrast against the *busiest* frame in the game, not the menu background. Outline or shadow text over the world — a thin light font on a bright sky is invisible exactly when it matters.
- **Animate value changes.** A health bar that jumps is missed; one that drains over ~0.2 s with a lagging damage ghost is felt.
- **Diegetic where it fits** — a speedometer on the dashboard beats a corner number in a driving game.
- **Nothing decorative that moves.** Motion in the periphery reads as a threat; spend that signal on real events.
## Responsive and touch
Layout with `Fill`, `Fit` and fractional sizing; the fork's turtle layout also has `Grid` (added in recent upstream `work`). Do not hardcode pixel positions for anything that must survive an aspect-ratio change.
- Test at 16:9, 4:3, and a tall phone ratio at minimum. Anchor to edges, not to absolute coordinates.
- **Safe area**: keep essential UI out of the outer ~5%, and away from notches and rounded corners.
- **Touch targets ≥ 44 px** at the real device DPI. Thumbs occlude what they touch — put virtual controls where the hand already is (lower corners), and make virtual sticks relative to first touch, not fixed.
- No hover states on touch. If information only appears on hover, it does not exist on mobile.
## XR
`xr/` and `apps/arcade/src/xr_input.rs`. Rules that are not optional:
- **Never face-lock UI.** Head-locked panels cause sickness. Anchor to the world, to the wrist, or to a comfortable body-relative position that lags the head.
- Keep panels ~12 m away; nearer than ~0.5 m cannot be focused.
- Text must be far larger than a screen equivalent; thin fonts vanish.
- Pointing is coarse — targets need to be much bigger than on desktop.
- No shake, no rapid full-field flashes.
## Accessibility
Cheap, and it improves the game for everyone: never encode meaning in hue alone (pair with shape/icon/position); keep body text ≥ 16 px equivalent; provide a way to reduce shake and flashes; make control prompts show the *active* device's glyphs, not a hardcoded keyboard key.
## Verification
`makepad-test` drives the real UI:
```rust
app.widget_dump(); // the tree, for finding ids
app.widget_snapshot(); // Vec<WidgetSnapshot> - assert structure/state
app.screenshot(); // look at it
app.press_key(KeyCode::Escape);
app.touch_down(x, y);
```
Capture every state at the target aspect ratio and inspect the images. A UI change verified only by `cargo check` is unverified — the DSL resolves at runtime.
## Required reading
- `references/hud-patterns.md` — layouts per genre, anti-patterns, animation timings.
- `references/menus-and-flow.md` — state machine, focus, settings, results screens.