makepad/skills/makepad-gameplay-systems/references/core-loop.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

73 lines
3.8 KiB
Markdown

# Core loop, levels, difficulty
## The brief
Before code. Keep it in `artifacts/game-progress.md` and re-read it after any interruption.
```
Loop: Player drives a route, hits checkpoints, beats a lap time.
Escalate: Each lap adds traffic; the target time tightens.
Win: 3 laps under par. log "race: won"
Lose: Timer expires. log "race: lost"
Input: kb WASD+Space | pad LS+RT/LB | touch left stick + pedals
Camera: chase, 6 m back, 2.4 m up, 60 deg fov, player car 4.2 m long
Device: desktop + Quest, 72 Hz target
Art: dusk desert, warm key, long shadows, Kenney racing kit
```
Emit those exact log lines from the game. They make win/lose machine-checkable in a `makepad-test` run, which is the difference between a claim and evidence.
## Loop archetypes
| Archetype | Escalation | Ends when | Blocks to use |
| --- | --- | --- | --- |
| Race | opponents, tighter par | laps complete / time out | `Car`, `RaceKit`, `Checkpoint` |
| Arena survival | wave size and mix | player dies / wave N cleared | `Character`, `Brain`, `Npc` |
| Chase / evade | pursuer speed, spawn rate | caught / escaped | `Brain::chase`, `caught` |
| Collect | scatter distance, hazards | quota met / timer | `interactable`, `score` |
| Traversal | gap width, hazard density | goal reached / fall | mover + `deck_floor_under` |
| Flight | wind, corridor width | landed / crashed | `Plane` |
Pick one and do it well. A game that is two archetypes stapled together is usually neither.
## Level structure
Three stages, always in this order:
1. **Teach** — the mechanic in isolation, no failure possible. One idea.
2. **Test** — the same mechanic under pressure. This is most of the game.
3. **Twist** — the mechanic combined with a second one, or inverted.
Build one complete vertical slice through all three before making level 2. A slice that is wrong is cheap to fix; five levels of the same wrongness are not.
## Generating levels
`makepad-game-gen` gives `levelgen`, `kit`, `interior`, `scatter`, `terrain`, `spline`, `lsystem`, `tree`, `implicit`, `mesh`, `texgen`, all from a seeded `rng`. `makepad-game-script::compose` adds `kit_from_index`, `level_placements`, `PlacedTile`. `libs/rtsmap` is the tiled-RTS map generator shared by the importer and the sandbox.
Rules:
- A level is a **seed plus a preset**, not a vertex dump. That is what makes it replicable across the wire and cheap to store.
- Generate, then **validate**: is the goal reachable, is the spawn clear, is there a navigable path? An unvalidated generator produces unwinnable levels roughly as often as it produces good ones.
- Hand-place the things the player must notice. Scatter the rest.
## Difficulty
Tune three axes independently so a change is diagnosable: **density** (how many), **speed** (how fast), **tolerance** (how much error is forgiven — hitbox, coyote time, par time).
Widen tolerance early and narrow it late; players read tolerance as "I got better", and read density as "the game got harder". Never scale all three at once.
## State machine
Every game needs these states, and every one needs a UI surface (see `makepad-game-ui-designer`):
```
Boot -> Menu -> Playing -> Paused -> Playing
|-> Win -> Menu | Retry
|-> Lose -> Menu | Retry
```
Failure modes worth naming: pausing that does not stop the sim step; a retry that leaves score, timers, particle emitters or audio voices from the previous run alive; a win that fires twice because the condition is checked without a latch. Reset through one `reset()` that rebuilds world state, and test it by winning twice in a row.
## Scoring
Keep score in the sim (`score`, `score_of` verbs, or a sim field) — never in the widget, or it dies with the view and cannot be replicated to clients. Make it observable: log it on every change so tests can assert on it.