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.
4.6 KiB
4.6 KiB
Debug playbook
Rendering
| Symptom | Check | Likely cause |
|---|---|---|
| Black viewport | camera pos/target, near/far | camera inside geometry; far plane too near; pass not composited |
| HUD visible, world not | scene_state output |
camera never updated from sim; rig left at origin |
| Object missing entirely | model_is_loaded(id) |
wrong id — silently degrades to a primitive |
| Object at world origin | the transform passed to ModelInstance::new |
identity matrix passed |
| Object wrong size | model_bounds(id) vs player capsule |
kit scale mismatch |
| Z-fighting | coplanar surfaces | offset decals/ground overlays slightly |
| Object visible through walls | draw order / depth | drawn in the alpha pass when it should be opaque |
| Flat lighting | light_dir on every draw type |
set on some, missed on others |
| Shadows disappeared | quality_reason() |
adaptive quality cut the shadow budget under load |
| Props look pasted on | AO | no contact darkening; bake it |
| Distant geometry on a different backdrop | fog vs sky colour | fog colour does not match the horizon |
| Sparks look like points on a sphere | firework override | missing per-spark uniform radial angle + swirl |
Fine in cargo check, broken on launch |
— | the splash DSL resolves at runtime |
Assets
| Symptom | Cause |
|---|---|
| Everything is primitives | assets never downloaded — run download_assets.sh |
| One thing is a primitive | wrong id; ids look like kenney/racing/vehicle-truck-yellow |
| Tests "pass" but prove nothing | asset-dependent tests skip without assets; check for skips |
| Crowd looks like clones | one cast member reused; vary members, tint, scale, yaw |
| Animation plays on one character, not another | members from two different casts — pick one cast per scene |
| Download fails loudly | sha256 mismatch — upstream moved or was tampered with; that is the check working |
Input
| Symptom | Cause |
|---|---|
| Nothing responds | event never reaches the mapping layer; log the action stream |
| Diagonal movement faster | keyboard vector not normalised |
| Stick drift / cross-shaped dead spot | per-axis deadzone instead of radial |
| Jump never fires | ground raycast hits the player's own capsule; filter it |
| Double jump on one press | input buffer not cleared on use |
| Works on desktop, dead on phone | touch handled only as mouse; no hover on touch |
| XR controller does nothing | pose read as gamepad axes; see apps/arcade/src/xr_input.rs |
Gameplay
| Symptom | Cause |
|---|---|
| Player floats / snags on seams | player on a rigid body; use a kinematic mover |
| Crate feels weightless | crate on a mover; use a rigid body |
| Bullet passes through walls | discrete stepping; use projectile_ccd |
| Character climbs walls | climb step height too large; walkable slope unclamped |
| Lap counts twice | no latch on the checkpoint crossing |
| Win fires repeatedly | unlatched win condition checked every tick |
| Second run behaves oddly | reset() incomplete — score, timers, emitters, audio voices |
| Pause does not pause | sim still stepping behind the overlay |
| Crowd pathing tanks perf | N individual paths to one goal; use a FlowField |
Netplay
| Symptom | Cause |
|---|---|
| Clients diverge | variable dt; std transcendentals; unseeded RNG; HashMap order in step |
| Cheating possible | client sending state instead of input — host must be authoritative |
| Huge bandwidth | replicating vertex data instead of (preset, seed, position) |
| Desync after N ticks | log a per-tick state hash both sides, find the first differing tick |
Script route
| Symptom | Cause |
|---|---|
| Verb rejects an option key | keys are typo-guarded — the key is wrong |
| Handlers stop firing late in a tick | the shared 500k-instruction pool is exhausted; batch instead of per-entity on_tick |
| Capability denied | strip_capabilities / Trust — the sandbox working as designed |
| Verb not found | check makepad_game_script::api_text(), the authoritative list |
Bisection recipe
When the layer is unclear, binary-search the pipeline rather than reading code:
- Assert the value at the midpoint (instance data handed to the renderer).
- Right there? The fault is downstream (draw/shader/pass).
- Wrong there? Move up (scene state, then sim).
- Repeat. Three or four steps localises almost anything in this engine.
After every fix
Add the test that would have caught it, in the lowest layer that can express it — a Cx-free unit test if possible, a makepad-test driven test if it genuinely needs the app. A fix without a regression test is a fix with a return date.