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.
3.6 KiB
Input and camera
One action enum
Branch on device at the mapping layer only. Gameplay code must never ask which device is connected.
enum Action { MoveX(f32), MoveY(f32), Jump, Fire, Interact, Pause }
Sources: RawInput and ControlSource in makepad-game-blocks; GameInputState / GamepadState from makepad_platform::event::game_input; DriveInput for vehicles, with drive_input_for(world, player) in makepad-game-session for the networked case.
Per-device rules
Keyboard — normalise diagonals ((1,1) normalised, or diagonal movement is 41% faster; this ships more often than it should). Support held keys via state, not key-repeat events.
Gamepad — radial deadzone ~0.15 (not per-axis, which produces a square deadzone and cross-shaped drift), rescale the remainder to full range so the first degree past the deadzone is not a jump to 0.15. Triggers are analog; use the range.
Touch — no hover, no right-click, and the thumb covers what it presses. Virtual sticks are relative to first-touch, not to a fixed screen point. Minimum 44 px targets. Every action needs a touch path or a mobile claim is false.
XR — see apps/arcade/src/xr_input.rs and xr/. Controller pose is not a gamepad axis: motion comes from the rig, aim from the hand. Snap-turn by default (smooth turning causes sickness); never move the camera without player input; keep HUD off the near plane — world- or wrist-anchored, not face-locked.
Buffering and forgiveness
Store timestamps, not booleans:
if action_pressed(Action::Jump) { jump_pressed_at = now; }
let buffered = now - jump_pressed_at < 0.12;
let coyote = now - left_ground_at < 0.10;
if buffered && (on_floor || coyote) { do_jump(); jump_pressed_at = -1.0; }
Clear the buffer on use, or one press yields two jumps.
Camera
CameraRig in makepad-game-render owns camera state; scene_state(..) builds the SceneState3D and set_pass_camera(cx, &pass, &scene) applies it. Script route: camera, cam_dist, cam_yaw, cam_pitch, cam_fov, cam_shake, cam_dragging, chase, face.
| Rig | Use | Notes |
|---|---|---|
| Chase | vehicles, third-person action | lag on position, lead on velocity |
| Orbit | sandbox, inspection | drag to orbit, wheel to zoom (the arcade_view pattern) |
| Fixed / isometric | strategy, puzzle | no lag; readability over drama |
| First person | shooter, XR | no smoothing on look, ever |
Lag and lookahead. Position lags the target by ~0.1–0.2 s; the look point leads by velocity × ~0.3 s. Lag alone feels sluggish, lookahead alone feels twitchy; together they feel intentional.
FOV. 60° desktop third-person, 75–90° first-person. Widen with speed (a few degrees) for a sense of acceleration — this is nearly free and very effective. In XR, FOV belongs to the headset: never set it.
Collision. Sphere-cast from target to camera and pull in on a hit, then ease back out slowly. Snapping out is more noticeable than snapping in.
Shake. Trauma-based: add trauma on impact, decay it, and use trauma² for amplitude so small hits stay subtle. Cap total displacement, and never shake in XR.
Screen-space aiming
Convert a pointer to a world ray through the scene camera, then cast_ray with raycast_filter(). Filter out the player's own capsule.
Testing input
makepad-test drives the real thing: press_key, press_key_with_modifiers, type_text, touch_down, plus wait_for_log_contains to synchronise. Test the mapping layer's output (the action stream) in a unit test, and the end-to-end path in one driven test — not every action end-to-end, which is slow and proves the same thing repeatedly.