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

forked from trevato/cs

Bodies stay where they fell: a corpse until the round ends, and a camera that is not inside it #389

Merged opened this

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

Merged

Dead players now stay on the floor where they fell until the next round stands them up. When nobody at all is left alive, the camera rises out of your own body instead of looking out of it. `bun run test` (typecheck plus 1,588 tests) passes, and the app boots and answers `/` in 22 ms.

shipped production is serving it deploy ae07c2d

opened this

Dead players now stay on the floor where they fell until the next round stands them up. When nobody at all is left alive, the camera rises out of your own body instead of looking out of it. bun run test (typecheck plus 1,588 tests) passes, and the app boots and answers / in 22 ms.

Engine

  • fallenMatrix(pos, yaw, tip, flatten, size) is in src/engine/math.ts, with its one caller. size is the only addition to the recipe in the issue, so the mesh's own scale still applies.
  • Instance has an optional tip in degrees. The renderer uses fallenMatrix when tip is not zero and modelMatrix otherwise.
  • Nothing new is exported from src/engine/index.ts, so surface.json and the engine's version are unchanged.

Bodies (src/client/scene.ts)

  • A dead player is one more instance of the player mesh in the frame that's already built: same pool, same buffer, no new draw path.
  • It falls over 0.4 s from exactly where the standing model was, lies face down along the way the player faced, and is pressed to 0.75 height. It's dropped onto the floor under it if the player died in the air, and tinted their side, dimmed.
  • When each player fell is kept in the scene's own memory, not in the simulation. A body already down on the first frame drawn, or after the clock goes back (a restart or a replay seek), is drawn already down rather than falling again.
  • Bodies cast no contact shadow, and are in no trace or bot sightline.
  • The recipe stays in src/client/models.ts.

Camera (src/client/spectate.ts) When the body the camera is left with is dead (your own, with nobody standing), it moves 72 units back along your facing and 120 up, stopped 8 units short of any wall in the way. It looks down at the middle of the body and eases there rather than cutting.

Tests

  • New tests cover:

- the tipped matrix, in math.test.ts and renderer.test.ts; - a body's fall, pose, tint and floor, and not falling again; - bodies going when players respawn; - the camera lifted out of your body and stopped short of a wall.

  • A seeded round built with a frame after every tick gives the same digest as the round without frames. It runs 40 s because the first death is at 33 s.
  • src/budget.test.ts now also measures a frame with all ten players dead: 0.0074 ms against the 0.15 ms ceiling.

Tests I changed because the behaviour changed on purpose

  • scene.test.ts said "a dead player is not an instance"; it now checks for a lying body.
  • main.test.ts expected 9 instances after you die; it's now 10, because the watched teammate is left out and your own body is added.

Bundle ceiling raised The app bundle grew by 1,498 bytes raw / 597 gzipped, to 133,074 / 51,713, which was past its ceiling. Following the rule in src/games.ts, it's now 140,000 / 54,500, and the pinned copy in scripts/build.test.ts matches.

Not done

  • A body goes through walls if a player dies facing one; there's no clipping against the level.
  • Bodies don't block bullets or movement, by design.
  • The holes in the wall are #284.

Try it in the preview: kill a bot and watch it fall and stay down until the next round. Die yourself: your body lies where you fell, visible from your teammate's view. With everyone dead (for example, a bomb detonation), the camera looks down on your body from above and behind.

🤖 Generated with Claude Code

Closes #296

commented

Dead players now stay on the floor where they fell until the next round stands them up. When nobody at all is left alive, the camera rises out of your own body instead of looking out of it. After merging main, bun run test (typecheck plus 1,612 tests) passes.

Engine

  • fallenMatrix(pos, yaw, tip, flatten, size) is in src/engine/math.ts, with its one caller. size is the only addition to the recipe in the issue, so the mesh's own scale still applies.
  • Instance has an optional tip in degrees. The renderer uses fallenMatrix when tip is not zero and modelMatrix otherwise.
  • Nothing new is exported from src/engine/index.ts, so surface.json and the engine's version are unchanged.

Bodies (src/client/scene.ts)

  • A dead player is one more instance of the player mesh in the frame that's already built: same pool, same buffer, no new draw path.
  • It falls over 0.4 s from exactly where the standing model was, lies face down along the way the player faced, and is pressed to 0.75 height. It's dropped onto the floor under it if the player died in the air, and tinted their side, dimmed.
  • When each player fell is kept in the scene's own memory, not in the simulation. A body already down on the first frame drawn, or after the clock goes back (a restart or a replay seek), is drawn already down rather than falling again.
  • Bodies cast no contact shadow, and are in no trace or bot sightline.
  • The recipe stays in src/client/models.ts.

Camera (src/client/spectate.ts) When the body the camera is left with is dead (your own, with nobody standing), it moves 72 units back along your facing and 120 up, stopped 8 units short of any wall in the way. It looks down at the middle of the body and eases there rather than cutting.

Tests

  • New tests cover:

- the tipped matrix, in math.test.ts and renderer.test.ts; - a body's fall, pose, tint and floor, and not falling again; - bodies going when players respawn; - the camera lifted out of your body and stopped short of a wall.

  • A seeded round built with a frame after every tick gives the same digest as the round without frames. It runs 40 s because the first death is at 33 s.
  • src/budget.test.ts now also measures a frame with all ten players dead: 0.0074 ms against the 0.15 ms ceiling.

Tests I changed because the behaviour changed on purpose

  • scene.test.ts said "a dead player is not an instance"; it now checks for a lying body.
  • main.test.ts expected 9 instances after you die; it's now 10, because the watched teammate is left out and your own body is added.

Bundle ceiling This branch had raised the app's ceiling, and main had meanwhile raised it for #385 to 140,000+ raw / 54,500 gzipped (140,500 / 54,500). The merged bundle measures 135,163 / 52,467, so main's number stands. src/games.ts gets one sentence saying #296 fits under it.

Not done

  • A body goes through walls if a player dies facing one; there's no clipping against the level.
  • Bodies don't block bullets or movement, by design.
  • The holes in the wall are #284.

Try it in the preview: kill a bot and watch it fall and stay down until the next round. Die yourself: your body lies where you fell, visible from your teammate's view. With everyone dead (for example, a bomb detonation), the camera looks down on your body from above and behind.

🤖 Generated with Claude Code

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs