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.
105 lines
5.7 KiB
Markdown
105 lines
5.7 KiB
Markdown
---
|
||
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 ~1–2 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.
|