Repository navigation
Follow the live end when the end is what moved - #33
Merged
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.comwith both chats joined the feed sat 11223pxbehind 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:
offer the way back.
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-sizeis 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:
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