Good topic, and I’ve been tuning this exact pipeline for low-latency competitive titles. The biggest mistake I see is treating the jitter buffer as a fixed-size queue. Static buffers force you to pick a compromise: set the target too low and you get visible stutter during any microburst, set it too high and you’re paying 40-60ms of input latency you don’t need on a stable connection. The right move is an adaptive buffer that targets a percentile of recent RTT (say the 85th-90th) rather than the mean, with a hard floor tied to your minimum observed RTT plus one round trip. You want the buffer to expand quickly on packet delay variation but decay slowly, so a single jitter spike doesn’t trigger a runaway buffer inflation loop. I also clamp the maximum buffer to something like min_rtt + 2*RTT so worst-case never balloons during a congested window.
On the smoothing side, the key insight is that dynamic delay adjustment should be decoupled from your input prediction pipeline, not applied globally. If you stretch or compress the render timeline based on buffer state, you’ll fight your client-side prediction and server reconciliation and end up with rubber-banding that’s far more noticeable than the original stutter. Instead, keep the input→server→feedback loop at a constant tick rate, and apply smoothing only to the
"____________________________________"
"Positioning beats raw aim 9 times out of 10."