makepad/skills/makepad-aaa-graphics-builder/references/lighting-and-materials.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

79 lines
4.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Lighting and materials
## The three-part model
**Key (sun).** `SunConfig`, `sun.rs`, `DrawGameSky`. Direction and colour. Elevation 1525° gives long shadows and modelled forms; noon light flattens everything and is what an unconsidered scene looks like. Commit to a time of day.
**Ambient (hemispheric).** `sun_sky` above, `sun_ground` bounce below, interpolated by the normal's Y. Grey ambient is the flatness default. Colour the two ends: a warm key with cool sky ambient (or the reverse at sunset) is most of the distance between "rendered" and "lit".
**Fog.** `fog_color`, `fog_density`. Provides depth ordering and aerial perspective. **Fog colour must agree with the sky at the horizon**, or distant geometry sits on a visibly different backdrop.
All four are shader **uniforms**, not instance data (see `shader-cookbook.md`). `fog_density` is the one per-instance exception, because shadow draws switch it off individually.
## Consistency
`light_dir` must be identical across `draw_cube`, `draw_alpha`, `draw_terrain`, `draw_skinned`, `draw_models`. Set them together in one `script_mod!` block. Inconsistent light direction is the most-missed defect in this engine because each surface looks fine alone.
## Shadows
`shadow.rs`, `shadow_mesh.rs`, `set_shadow_budget(n)`, `shadow_budget()`. Shadow meshes use the same 6-float packed vertex.
Budget by importance:
1. The player — always.
2. Anything moving within the player's immediate area.
3. Tall objects whose silhouette defines the space.
4. Everything else — baked AO instead.
Shadowing everything kills the frame; shadowing nothing makes props float. Adaptive quality lowers the budget automatically under load — read `quality_reason()` before concluding your shadows "stopped working".
## Baked AO
`bake.rs`, `ao.rs`, `BakeSettings`, `bake_settings()` / `set_bake_settings()`, `dynamic_shade(pos)`.
**Contact darkening is the cheapest large upgrade to perceived quality.** It is specifically what stops props reading as stickers laid on the ground. Bake it for static props; use `dynamic_shade` for moving ones.
The `ao_render` dev example software-rasterises props so baked AO can be judged by eye without a `Cx` or the app — use it, because AO is a judgement call that a number does not settle. That example is why the crate carries a `jpeg-encoder` dev-dependency and no more.
## Materials without a PBR pipeline
There is no material graph here. Differentiation comes from four levers:
**Tint.** `ModelInstance::with_tint(vec4)`. Drive from `Palette` / `Spread` / `VarietyParams` in `makepad-game-assets`, or `find_palette` on the script route. Five palette-consistent tints across a crowd reads as authored; one tint reads as placeholder.
**Texture.** `with_texture(idx)` and `DrawGameTexture`. Generate tiling detail with `makepad-game-gen::texgen` when the library has nothing — procedural texture is free of download weight and is deterministic from a seed.
**Jitter.** Seeded, small: ±10% scale, full yaw rotation, slight position offset. This destroys the grid-stamped look at zero cost. Seeded, so it replicates.
**Cast variety.** For characters, use different members of ONE cast (`find_cast`) — same skeleton, so animation is shared, but the crowd is not clones.
## Palette
Three dominant + two accent. Rules that hold across genres:
- **Reserve accents for gameplay meaning.** If pickups are the only saturated orange in the game, the player learns orange without being told.
- **Separate by value, not only hue.** A screenshot converted to greyscale should still show foreground, midground, background as distinct bands. This is the test most scenes fail.
- **Desaturate with distance** toward the fog colour — aerial perspective, free depth.
- The CC0 library is shared, so out-of-the-box colours look like every other Kenney project. Tint discipline is what makes it yours.
## Skinned characters
`skin.rs``SkinnedModel`, `PoseBuffer`, `SkinnedBatch`, `SkinnedDraw`.
Skinning is **CPU-side**, so the whole skinned vertex buffer re-uploads every frame. That makes skinned characters the most expensive visual thing in the scene by bandwidth: the Knight is 3716 verts, 238 KB/frame unpacked, 89 KB packed. Consequences:
- Cap the number of on-screen skinned characters and prove the cap holds in the worst wave.
- Distant characters do not need full skinning — swap to a static or lower-rate pose.
- Share one cast per scene so one animation set serves everyone.
## Checklist before scoring
- [ ] Sun elevation committed and not noon
- [ ] `light_dir` identical across every draw type
- [ ] Sky ambient and ground bounce coloured, not grey
- [ ] Fog colour matches the sky at the horizon
- [ ] Player always casts a shadow
- [ ] Contact AO under every static prop
- [ ] No two adjacent props identical in tint, scale and yaw
- [ ] Greyscale screenshot still separates fore/mid/background
- [ ] Accent colour reserved for gameplay-relevant objects