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

3.8 KiB

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.