Skip to content

Follow the live end when the end is what moved - #33

Merged
JRBlaze merged 1 commit into
mainfrom
feed-keeps-following
Sep 4, 2026
Merged

JRBlaze merged 1 commit into
mainfrom
feed-keeps-following

Conversation

@JRBlaze

@JRBlaze JRBlaze commented Sep 4, 2026

Copy link
Copy Markdown
Owner

Fixes a regression in v1.18.2.

Reported as: on a fast chat the feed stops scrolling, shows N new messages, and the button has
to be pressed again and again — each press buying a moment before it strands you once more.

What went wrong

1.18.2 let the browser skip rows scrolled out of view, and a row it has not drawn yet only has an
assumed height. So scrolling to the end of the feed is only as good as the height the feed has
at that instant: the rows just attached get measured for real straight afterwards, the end drops
a few hundred pixels below where it was, and the scroll that had just landed on it is short.

Measured on a live channel: scroll to the end, and 400ms later the feed is 409px short of it.
With the rule turned off it lands at 0 and stays there. The assumed height was 30px too small as
well — 24px came from the harness's simple rows; real rows on a live channel are 29px at the
median and 47px at the 90th percentile.

That alone would have been a flicker. What made it a wall is older than 1.18.2: following the
live end was decided fresh on every flush, from the distance to the bottom. Being short read as
the viewer has scrolled up, so the feed stopped following — and nothing scrolled again while it
was behind, so the gap only ever grew. On kick.com with both chats joined the feed sat 11223px
behind
after a couple of minutes.

The fix

Following the live end is now what the viewer asked for, not what a measurement says. A feed that
is following and finds itself away from the end got there one of two ways, and the scroll position
tells them apart:

  • it moved → the viewer moved, because content settling below them cannot move it. Hold still,
    offer the way back.
  • it did not move at all → the end moved. Go after it.

So growth below a viewer who has not touched anything can no longer be read as a gesture, and a
single bad measurement can no longer strand anyone. The way back still needs no gesture: being at
the end is being at the end, however you got there.

A flush also takes one more look on the next frame, for growth that lands after the flush that
caused it, and contain-intrinsic-size is now 30px, measured rather than guessed.

Verified against the live page

The new logic run against real Kick traffic, both chats joined, 2259 messages through a full
400-row feed, nobody touching the scrollbar:

distance from the live end before after
median — 0px
90th percentile — 21px
worst 11223px and climbing 21px

Tests

node tests/run.js — 1727 passed, 0 failed. The 5 new assertions fail against the shipped code,
which is what makes them regression tests: they cover the end growing under a still viewer, the
viewer's own scroll still being honoured, held position while reading back, returning to the end
by hand, and a collapsed panel's zero-height measurements not being mistaken for anything.

🤖 Generated with Claude Code

1.18.2 let the browser skip rows scrolled out of view, and a row it has
not drawn yet only has an assumed height. Scrolling to the end of the
feed is therefore only as good as the height the feed has at that moment:
the rows just attached are measured for real straight afterwards, the end
drops a few hundred pixels below where it was, and the scroll that had
just landed on it is short.

That alone would have been a flicker. What made it a wall was the way
following the live end was decided: fresh on every flush, from the
distance to the bottom. Being short read as "the viewer has scrolled up",
so the feed stopped following — and nothing scrolled again while it was
behind, so the gap only ever grew. The only way back was the jump button,
and a fast chat stranded them again a moment later. On a live channel the
feed sat eleven thousand pixels behind after a couple of minutes.

Following is now what the viewer asked for rather than what a measurement
says. A feed that is following and finds itself away from the end got
there one of two ways, and the scroll position tells them apart: if it
moved, the viewer moved, so hold still and offer the way back; if it did
not move at all, the end moved, so go after it. Growth below a viewer who
has not touched anything can no longer be read as a gesture, which means a
single bad measurement can no longer strand anybody — and the way back
still needs no gesture, because being at the end is being at the end
however you got there.

A flush also takes one more look on the next frame, for the growth that
lands after the flush that caused it, and the assumed row height is now
30px: measured on a live channel rather than guessed from the harness's
simpler rows, where 24px came from.

Measured against live Kick traffic with both chats joined, 2259 messages
through a full feed: the end stays 0px away at the median and 21px at the
worst, where before it was 11223px and climbing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@JRBlaze
JRBlaze merged commit 2c52762 into main Sep 4, 2026
3 checks passed
@JRBlaze
JRBlaze deleted the feed-keeps-following branch September 4, 2026 03:11
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.

1 participant