Public: anyone can read this; the crew can change it.

forked from trevato/cs

Players read as people when they move: a gait you can see across the room, at no cost to the frame #395

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

Players now visibly walk, run and land. I went with the cheap version: the same one-piece player mesh, moved by a few numbers in `src/client/scene.ts`. Nothing in the simulation changed, and a player standing still is drawn exactly as before.

shipped production is serving it deploy ae07c2d

opened this

Players now visibly walk, run and land. I went with the cheap version: the same one-piece player mesh, moved by a few numbers in src/client/scene.ts. Nothing in the simulation changed, and a player standing still is drawn exactly as before.

What it does (worked out in stand() and walk() from the players' own position, velocity and on-ground flag):

  • Bob: a running player's body rises once per footfall, up to 2.5 units at a full 250 u/s run. It also twists its hips up to 4° either way. Both are timed by distance walked (one footfall every 44 units), not by the clock. So a player at the same point on the floor is at the same point in their stride at any frame rate, and a player pushing into a wall doesn't walk on the spot.
  • Lean: up to 7° forward when running, backward when backpedalling, none when strafing. It uses the tilt field the corpses already use, and pivots at the feet.
  • Landing: a player coming down after at least 0.15 s in the air sinks by up to 12% of their height and springs back over 0.22 s. A single-tick hop off a stair edge doesn't count as a landing.
  • Untouched: a standing player, ducking, and dead players. Corpses were already done in #389: they go down once and stay down.
  • Memory: what the gait remembers between frames lives in scene.keep, one entry per seat, the same way corpse falls are tracked. A jump of more than 128 units in one frame (a respawn, a replay seek) doesn't count as walking.
  • Velocity and on-ground already go over the wire, so it works online too.

What I chose not to do: separate instances for legs and arms. The cheap version reads, so the instance pool stays at 48 (it was 32 when the issue was written) and each player is still one draw call. I also left out any read of health or hit reaction, which belongs to #137.

Frame cost, measured: at ten running players, building the scene takes 6.58 µs per frame against 5.25 µs on main — about 1.3 µs more (best of five runs of 200,000 frames each). There are no new instances or draw calls. A leaning player's matrix is built by fallenMatrix instead of modelMatrix, which costs the same.

Tests:

  • New tests in src/client/scene.test.ts:

- a standing player gets exactly today's matrix; - a running player bobs and leans, and lands on the same numbers at 30 fps and at 144 fps; - no bob against a wall; - a backpedal leans back and a strafe doesn't lean; - a landing squashes, a stair-edge hop doesn't; - a respawn doesn't count as a stride.

  • src/frames.test.ts now runs 200 frames with everyone running, jumping and landing, and still allocates nothing.
  • The existing check that drawing frames leaves the round's digest unchanged still passes.
  • The full check (bun run test, typecheck plus 1639 tests) passes. The README says what the gait is.

To try it: in the preview, die early in a round and spectate. Teammates running bob and lean, stop dead when they stop, and sink briefly when they land from a jump.

🤖 Generated with Claude Code

Closes #155

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs