Skip to content

Fix frame pacing once and for all#135

Merged
philpax merged 4 commits into
mainfrom
fix-frame-pacing-once-and-for-all
May 13, 2026
Merged

Fix frame pacing once and for all#135
philpax merged 4 commits into
mainfrom
fix-frame-pacing-once-and-for-all

Conversation

@philpax
Copy link
Copy Markdown
Contributor

@philpax philpax commented May 13, 2026

Fixes #113. Makes the frame pacing algorithm more intelligent (i.e. targeting an EMA of time between received batches) to improve smoothness of presentation and to cope with being capped better.

once and for all

philpax added 2 commits May 13, 2026 23:23
Temporal-compression batching used to surface as frames spooled at regular
intervals, but timing predicted from the server's reported gen_ms doesn't
account for wire-side jitter or per-batch overhead — small drifts between
predicted and actual cadence translated directly into visible timing
variance.

Server now bundles all T sub-frames of an inference pass into one binary
WS message (PROTOCOL_VERSION bumped to 4). Client maintains an EMA of
inter-batch arrival intervals and schedules each sub-frame's display at
receivedAt + (arrivalEMA / T) * i, so they spread evenly across the
predicted next-batch interval. Drop-on-overlap and hold-on-underrun cover
the EMA-misprediction edges; both surface as HUD metrics for tuning.
A multi-second pause/resume or scene-edit interval would surface to the
pacer as a single batch arrival with `arrivalInterval = pause_duration`.
At α=0.2 the EMA blended 20% of that gap into the prediction, blowing
`step_s` up to hundreds of ms per sub-frame for ~20 recovery batches
(~1.5s at typical cadence) before decaying back — visible as a noticeable
slowdown for the first few seconds after every resume.

Treat any gap > 500ms (absolute) or > 5× current EMA (relative) as a
discontinuity and snap the EMA to `header.gen_ms` instead of blending.
Same branch also skips overlap/hold accounting for the stale outgoing
batch, since those metrics only mean anything when we expected continuous
flow.
@philpax philpax requested a review from Clydingus May 13, 2026 21:48
Comment thread server-components/server/session/connection.py Outdated
Copy link
Copy Markdown
Collaborator

@Clydingus Clydingus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we end up reworking this in the future i'm relinking this "once and for all" issue and we better title that issue "once and for all (again (for sure this time))"

philpax added 2 commits May 14, 2026 01:26
Added in the initial pacing redesign as "lets the client distinguish
server-side timing from network jitter," but the pacer ended up using
performance.now() at receive exclusively — nothing reads the field.
@philpax philpax merged commit d79cc90 into main May 13, 2026
12 checks passed
@philpax philpax deleted the fix-frame-pacing-once-and-for-all branch May 13, 2026 23:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Revisit frame pacing again

2 participants