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.
8.2 KiB
| name | description |
|---|---|
| makepad-aaa-graphics-builder | Raise Makepad game visuals to a premium bar: meshes, materials, shader overrides in the splash DSL, lighting and sun, shadows, baked AO, skinning, particles and fireworks, sky and fog, post look, render budget and the visual scorecard. Use for premium, AAA, polished, high-fidelity, showcase, 'less basic', art direction, and performance-versus-quality work on makepad-game-render. |
Makepad AAA Graphics Builder
Make it look authored. The bar is not "3D objects appear" — it is that every visible surface was decided by someone.
Where the seam is
makepad-game-render owns structure; the splash DSL owns look. The engine shader decides where a spark is and how long it lives; a script_mod! override decides what it looks like. Keep gameplay-relevant constants out of the DSL and look constants out of Rust. This is what lets a generated game restyle the sky without being able to break the simulation.
script_mod! {
mod.widgets.MyView = set_type_default() do mod.widgets.MyViewBase {
draw_cube += { light_dir: vec3(0.35, 0.8, 0.45) }
draw_terrain += { light_dir: vec3(0.35, 0.8, 0.45) }
draw_skinned += { light_dir: vec3(0.35, 0.8, 0.45) }
draw_firework += { /* pixel/shape override for the look only */ }
}
}
Set light_dir consistently across every draw type. A skinned character lit from a different direction than the terrain it stands on is the single most common "this looks wrong and I can't say why" defect in this engine.
The renderer
Modules in libs/game/render: renderer, scene, stage, shaders, geometry, model, skin, shadow, shadow_mesh, particles, firework, sun, bake, ao, hud, thermometer.
Draw types: DrawGameCube, DrawGameAlpha, DrawGameTerrain, DrawGameSkinned, DrawGameSky, DrawGameShadow, DrawGameFirework, DrawGameTexture, collected in GameDraws.
Frame shape:
let scene = scene_state(&world, &rig, /* .. */);
set_pass_camera(cx, &self.pass, &scene);
renderer.set_models(models); // Vec<ModelInstance>
renderer.set_particles(particles);
renderer.set_fireworks(fireworks);
renderer.draw_scene_full(cx, &mut draws, &world, &scene /* .. */);
Adaptive quality is already built in — do not write a second one:
let changed = renderer.report_frame_ms(ms);
renderer.set_refresh_hz(72.0);
renderer.set_shadow_budget(24);
renderer.quality(); renderer.quality_level(); renderer.quality_reason();
renderer.frame_p90_ms();
renderer.set_stage(Stage::/* .. */); // StageMode
Models: load_model(..), model_is_loaded(id), model_bounds(id), model_triangles(id), model_collider_parts(id). ModelInstance::new(key, vertices, indices, transform) with .with_tint(..) and .with_texture(..).
Art direction first
Decide these four before authoring anything, and write them into artifacts/game-progress.md. Changing them later invalidates every asset choice made under the old ones.
- Palette — 3 dominant + 2 accent colours.
makepad-game-assetsgivesPalette,Spread,VarietyParams; the script route hasfind_palette. - Key light — direction, colour, and time of day. Low sun (15–25° elevation) produces long shadows and reads as authored; noon light is the default-looking default.
- Sky and fog —
SkyConfig,SunConfig,DrawGameSky. Fog colour must agree with the sky at the horizon or the world looks pasted onto a backdrop. - Scale — player height in world units, decided in gameplay, obeyed here. Kit pieces at inconsistent scale are instantly legible as wrong.
Lighting
sun.rs and SunConfig. The engine's cube/terrain/skinned shaders take sun_color, sun_sky, sun_ground and fog_color as uniforms, not instance data — they are identical across a batch and were moved off the instance stream for a 27% saving. Do not push them back per-instance.
Three-part model: directional key (the sun), hemispheric ambient (sun_sky above / sun_ground bounce below), and fog for depth. Colour them separately — a warm key with a cool sky ambient is most of the difference between "rendered" and "lit". Grey ambient flattens everything.
Shadows: shadow, shadow_mesh, set_shadow_budget(n). Shadow meshes use the same packed 6-float vertex. Budget casters — shadow every object and the frame dies; shadow only the hero and it floats. Prioritise: player, anything moving near the player, tall silhouettes.
Baked AO: bake.rs, ao.rs, BakeSettings, bake_settings() / set_bake_settings(), dynamic_shade(p). AO in contact regions is the cheapest single upgrade to perceived quality — it is what stops props reading as stickers on the ground. The ao_render dev example software-rasterises props so baked AO can be judged by eye.
Materials and variety
The library is CC0 and shared, so out-of-the-box scenes look like everyone else's. Differentiate with:
- Tint —
ModelInstance::with_tint, driven byPalette/VarietyParams/Spread. A crowd of one prop in five palette-consistent tints reads as authored; a crowd of identical props reads as a placeholder. - Different members of one cast — never clone the same character across a crowd (
find_cast). - Procedural texture —
makepad-game-gen::texgenfor tiling detail, withDrawGameTexture. - Scale and rotation jitter — seeded, small (±10% scale, full yaw). Free, and it destroys the grid-stamped look.
Particles and VFX
particles.rs (ParticleSystem, ParticleInstance), sim-side ParticleKind / ParticleRequest / ParticleSpec / EmitterAnchor, and firework.rs (FireworkSystem, FireworkInstance). Script verbs: particles, burst, particles_stop, dust, beam.
Effects read when they are short, bright, and layered: a flash (1–2 frames), a burst (0.2 s), a lingering trace (0.5–1 s). One long uniform puff reads as fog. Drive emission from real events — take_mover_impacts() — not from a polling timer.
The firework shader override in arcade_view.rs is the house precedent for a look override: real fireworks are symmetric, so pick one uniform radial angle per spark, then add swirl and fizzle so sparks look like burning matter rather than points on a sphere.
Budgets
apps/arcade/BUDGETS.md is authoritative. What actually costs:
- Not the sim. 100 movers + 50 bodies + 65×65 terrain = 0.038 ms/tick against a 16.6 ms budget.
- Draw calls and CPU skinning are. Skinning is CPU-side, so the whole skinned buffer re-uploads every frame. The Knight at 3716 verts was 238 KB/frame at 64 B/vertex, and 89 KB at the packed 24 B.
- Vertex attributes here are f32-only — no u8/u16/i16 attribute types. Compression means bit-packing into f32 lanes and unpacking in-shader with the
unpack2f16/unpack4u8builtins (available on Metal/GLSL/HLSL/WGSL). geom.GameMeshVertexis the shared packed layout: position 3 exact floats, octahedral normal in 1 lane, uv as 2×f16 in 1 lane, colour as 4×unorm8 in 1 lane = 6 floats / 24 B. Use it.- Quest is bandwidth-bound before ALU-bound. Cut bytes per frame first, shader instructions second.
- Measure from
RenderStats::instance_floats, not by counting fields by hand.
Order of visual return
When time is limited, this order gives the most visible improvement per hour:
- Key light direction + colour (low sun)
- Contact shadows / baked AO
- Palette discipline and tint variety
- Sky/fog agreement at the horizon
- Silhouette clarity of the hero
- Ground detail — texture or geometry, not flat colour
- Impact VFX on every hit
- Post look and grading
Verification
Screenshot every state at target aspect ratio and look at them. Score with references/visual-scorecard.md: premium means nothing below 2 and an average ≥ 2.3. Read frame_p90_ms() before and after any performance claim. cargo run -p makepad-arcade --example bigworld_probe --release gives headless render evidence.
Required reading
references/visual-scorecard.md— the 10 categories, anchors, and how to score.references/shader-cookbook.md— DSL overrides, packing, the builtins.references/lighting-and-materials.md— sun, ambient, fog, AO, tint variety.references/render-budget.md— what costs, how to measure, what to cut first.