makepad/skills/makepad-debug-profiler/references/debug-playbook.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

87 lines
4.6 KiB
Markdown

# 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:
1. Assert the value at the midpoint (instance data handed to the renderer).
2. Right there? The fault is downstream (draw/shader/pass).
3. Wrong there? Move up (scene state, then sim).
4. 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.