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

forked from trevato/cs

The round you just played can be watched back: a match records its inputs, and the simulation replays them #93

open not picked up yet opened this
opened this

This repository already proves, twice a pull, that the simulation is exactly reproducible: src/client/replay.ts steps a seeded world through a fixed script of inputs and hashes every tick, and createWorld(rules, name, team, size, seed) has taken a seed since the day it was written. A player gets none of that. The payoff of a deterministic simulation is that the round you just lost can be watched again — and it costs a seed and a few bytes a tick, not a video.

Done looks like

  • [ ] A match records what it needs to replay itself and nothing more: the seed, the rules, the teams, and one compact record per tick of what the player asked for — the same Input the world already takes, encoded as a bitfield and two angles rather than an object per tick. A 1:55 round at 64 Hz is a few tens of kilobytes; the pull states the real number.
  • [ ] Playing it back is the same code path, not a second one: the recorded seed makes the same world, the recorded inputs are handed to the same update, and the frame draws it through the same buildScene and the same renderer. If anything has to be special-cased for playback, that is a finding about the simulation and the pull says so.
  • [ ] The player reaches it where they already are: after a round ends, watch the round back — playback at normal speed with a way to stop and return, the HUD saying plainly that this is a replay and not a live round, and no input of yours reaching the world while it runs.
  • [ ] It is proved to be a replay, not an approximation: a test records a scripted round, replays it, and asserts the two runs hash identically tick for tick with replay.ts's own digest machinery — which is exactly the test that fails the day someone makes the simulation depend on the wall clock.
  • [ ] Memory is bounded and nothing is written to a server: the last round only, in the page, dropped when a new one starts. Nothing is posted, nothing is stored server-side, and the recording costs the live frame nothing measurable — the pull says what it measured.
  • [ ] src/client/main.test.ts drives the whole thing through the stub page: play a scripted round, end it, click watch, and the frames that follow step a world that is not the live one; stop, and the menu is back.
  • [ ] bun test green, both golden digests unmoved, and the app bundle stated against its ceiling.

Files I expect to change

src/client/recording.ts (new: the encoding and the playback), src/client/recording.test.ts (new), src/client/main.ts, src/client/main.test.ts, src/client/hud.ts and hud.test.ts (the replay marker), src/pages/game.ts (the button), README.md, src/games.ts if the ceiling moves.

Risks

The honest risk is that the simulation turns out not to be as deterministic as the golden digest suggests — the digest runs one seeded round with no bots buying on a clock, and a live match has more moving parts. If a replay diverges, the divergence is the finding: name the first tick it happens on, open the issue, and do not paper over it with a resync. The second risk is bytes: an object per tick and a naive JSON is megabytes, which is why the encoding is a bitfield. The third is scope — this is watch the last round at one speed, not a demo format, not scrubbing, not a camera you fly. Waits for #74, which gives the frame the states a playback has to slot into.

Suggested: Torque — the determinism, the digest machinery and the encoding are theirs.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs