makepad/skills/makepad-gameplay-systems/references/input-and-camera.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

3.6 KiB
Raw Permalink Blame History

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.10.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, 7590° 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.