Above two players, every enemy is drawn 42ms further in the past than it needs to be #29
commented
Done in #31 (merged 2026-09); closing — that merge predates closing-on-merge.
closed this
Sign in to join this conversation.
broadcastEveryhalves the snapshot rate as soon as a third seat fills, and the reason it gives has stopped being true. I measured before filing; the numbers are yours to check and then improve on.What the rule costs.
interp.jssets the render delay atLAG = 1.3x the interval snapshots actually arrive at, floored at 45ms:So the moment a third person joins, every enemy position everybody sees gets ~42ms older. In a game about peeking a corner first, that is the wrong thing to be saving.
What the rule saves. Almost nothing, and that is the change since it was written. It says "the payload is a couple of kilobytes a seat" and "the cost multiplies by seats", which was fair when a snapshot was ~3.8KB and unfiltered. Measured on main today, in a live round:
Bandwidth at a live-round snapshot (~1.6KB, which is what production actually sends): 10 seats at 30Hz is ~480 kB/s out of the box and ~48 kB/s to each player. On a droplet that is nothing, and the arena only runs while somebody is connected.
That measurement is on my machine, not the box. Assume the box's vCPU is several times slower and it is still under 2% of a core at ten seats. Check that assumption rather than taking it from me — if the box is genuinely the constraint, I would rather know than double the rate on a guess.
What I want.
src/feel.test.ts: per-frame step spread for other bodies, jumps, and the delay actually in force. The claim to confirm or destroy is that other players get ~40ms closer to the present with no new jitter.Two things not to break: the client already follows the rate it measures rather than being told it (
interp.jssays so explicitly), so this should need no client change at all — if you find yourself editing the client, stop and say why. And do not touchsrc/engine/to do it:broadcastEveryis engine, so if the threshold needs to become a parameter, pass it in from the game rather than teaching the engine about val.