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.
123 lines
6.8 KiB
Markdown
123 lines
6.8 KiB
Markdown
---
|
|
name: makepad-debug-profiler
|
|
description: "Diagnose and fix Makepad game defects: black or empty viewport, missing models, broken shaders, wrong lighting, input that does nothing, stutter and frame spikes, memory growth, netplay desync, script errors, and mobile/XR-specific failures. Use for 'nothing renders', 'it compiles but crashes on launch', 'assets don't appear', 'it's slow', and profiling work."
|
|
---
|
|
|
|
# Makepad Debug Profiler
|
|
|
|
Find the actual cause. The most expensive debugging in this codebase comes from fixing a symptom one layer above the fault.
|
|
|
|
## Method
|
|
|
|
1. **Reproduce deterministically.** Fix the seed, fix the tick count, note the platform and build profile. An intermittent bug you cannot reproduce is a bug you cannot verify fixed.
|
|
2. **Bisect the pipeline**, not the source file. The layers are: sim state → scene state → instance data → draw call → shader → pass composite. Find the last layer where the data is right.
|
|
3. **Print the data, not the code.** Assert what the values actually are at that boundary.
|
|
4. **Fix the cause, then add the test that would have caught it.**
|
|
|
|
## Layer bisection for "nothing renders"
|
|
|
|
Work down; the first failing check is your bug.
|
|
|
|
```rust
|
|
// 1. does the sim have anything?
|
|
println!("entities: {}", world.entities.len());
|
|
|
|
// 2. is it where you think?
|
|
println!("player pos: {:?}", player.pos);
|
|
|
|
// 3. is the camera looking at it?
|
|
println!("cam: {:?} target {:?}", rig.pos, rig.target);
|
|
|
|
// 4. did instances reach the renderer?
|
|
println!("models: {} particles: {}", models.len(), particles.len());
|
|
|
|
// 5. did the model actually load?
|
|
println!("loaded: {}", renderer.model_is_loaded("kenney/racing/vehicle-truck-yellow"));
|
|
println!("bounds: {:?}", renderer.model_bounds(id));
|
|
|
|
// 6. is quality having silently dropped things?
|
|
println!("q{} because {}", renderer.quality_level(), renderer.quality_reason());
|
|
```
|
|
|
|
Most common causes, in the order they actually occur:
|
|
|
|
| Symptom | Usual cause |
|
|
| --- | --- |
|
|
| Black viewport | camera inside geometry, or near/far plane wrong, or the pass never composited |
|
|
| Everything invisible but HUD fine | camera target not updated from the sim; rig at origin |
|
|
| Model missing, no error | **wrong asset id — it degrades to a primitive silently.** Assert `model_is_loaded` |
|
|
| Model present but tiny/huge | scale mismatch between the kit and the player capsule |
|
|
| Model at origin | transform not applied; `ModelInstance::new(.., transform)` got identity |
|
|
| Flat/wrong lighting | `light_dir` set on some draw types and not others |
|
|
| Shadows vanished under load | adaptive quality dropped the budget — read `quality_reason()` |
|
|
| Fine in `cargo check`, broken on launch | the splash DSL resolves **at runtime** |
|
|
|
|
That last row is the most important fact in this skill: **`cargo check` cannot validate the DSL.** A malformed style, a missing widget id, or a bad inheritance path fails only when the app runs. Any UI or style change must be launched.
|
|
|
|
## Silent asset fallback
|
|
|
|
The library is designed to degrade gracefully — with no assets downloaded the game runs on primitives and asset-dependent tests skip. Convenient for CI, dangerous when debugging: a typo'd id looks like a design choice.
|
|
|
|
```bash
|
|
bash skills/makepad-game-director/scripts/probe_assets.sh
|
|
```
|
|
|
|
Then assert, don't eyeball:
|
|
|
|
```rust
|
|
for id in scene_model_ids { assert!(renderer.model_is_loaded(id), "missing {id}"); }
|
|
```
|
|
|
|
## Input that does nothing
|
|
|
|
Bisect the same way: does the platform event arrive → does the mapping layer produce an action → does the sim consume it → does the entity respond?
|
|
|
|
Specific traps: a radial deadzone applied per-axis; a ground raycast that hits the player's own capsule (so `on_floor` is always false, so jump never fires); an input buffer that is never cleared (double jumps); touch handled only as mouse (so nothing works on device); XR controller pose read as gamepad axes.
|
|
|
|
## Performance
|
|
|
|
**Measure before changing anything, in `--release`.**
|
|
|
|
```rust
|
|
renderer.frame_p90_ms(); // report p90, not mean
|
|
renderer.quality_level();
|
|
renderer.quality_reason();
|
|
stats.instance_floats;
|
|
```
|
|
|
|
```bash
|
|
cargo run -p makepad-arcade --example bigworld_probe --release
|
|
```
|
|
|
|
Given the sim is ~0.2% of frame time, a slow frame is almost never gameplay code. Check, in order: skinned character count (CPU skinning re-uploads every vertex every frame), draw-call count, shadow casters, particle pool size, instance stream width, and only then fragment work.
|
|
|
|
**Stutter is not the same as low framerate.** A 16 ms mean with a 40 ms p90 is a stutter problem: look for per-frame allocation, model loading during play, terrain regeneration, or a `HashMap` rehash in the step loop. Preload and pool.
|
|
|
|
Two systems fighting is a classic here: if quality oscillates, check you have not added a frame pacer beside `GameRenderer`'s adaptive controller.
|
|
|
|
## Netplay desync
|
|
|
|
Host-authoritative, so a divergence means a client simulated something it should not have, or the sim is not deterministic. Check: variable `dt` anywhere; `std` float transcendentals instead of `makepad-game-math`; unseeded RNG instead of the seeded `rng`; `HashMap` iteration order inside `step`; clients sending state instead of input; content replicated as vertex data instead of `(preset, seed, position)`.
|
|
|
|
Bisect by logging a per-tick state hash on host and client and finding the first differing tick.
|
|
|
|
## Script route
|
|
|
|
Errors surface in `EvalReport`. Constraints that present as bugs: the **500k-instruction cumulative pool per tick** shared by `on_tick` + timers + touch (symptom: handlers silently stop running late in a tick), and **typo-guarded option keys** (symptom: a verb rejects a key — the key is wrong, do not work around it). Untrusted scripts must pass `strip_capabilities` with a `Trust` level; a capability failure is the sandbox working.
|
|
|
|
## Memory
|
|
|
|
Growth over time comes from unbounded `Vec`s: particle instances, decals (`BulletDecal` — cap and recycle), log buffers, model cache (`makepad-game-gen::cache`), or per-frame allocations never reused. Pool anything created per frame.
|
|
|
|
## Tooling
|
|
|
|
`cargo check -p <crate>` for the fast loop; `cargo test -p <crate>` for Cx-free logic; `cargo clippy` (the repo has `clippy.toml`); `makepad-test` for driving the real app with `widget_dump()`, `widget_snapshot()`, `screenshot()`, `wait_for_log_contains()`; `RUST_BACKTRACE=1` for panics; the `ao_render` probe to judge baked AO by eye.
|
|
|
|
## When stuck
|
|
|
|
Re-read the actual API rather than guessing at a signature — `makepad_game_script::api_text()` prints the authoritative verb list, and the crate sources are in the tree. State what you have ruled out. Say plainly what you could not reproduce; an unverified fix reported as fixed is worse than an open bug.
|
|
|
|
## Required reading
|
|
|
|
- `references/debug-playbook.md` — symptom→cause tables and bisection recipes.
|
|
- `references/profiling.md` — measuring, budgets, what to cut.
|