feat: a wheel pulls the wall too, and the bar stays put on a desktop - #76
Merged
Conversation
The desktop half of the pull. Keep scrolling up when the wall is already at its top and it opens exactly as a finger opens it: same band, same 72px threshold, same 54px shelf, same indicator. A wheel is the same gesture through a different input, so it is the same PullState and the same feed.refresh() at the end of it. Two things are forced by what a wheel is, and they are the only differences. It reports movement rather than position, so travel accumulates instead of being measured from an origin, scaled by 0.4: one notch of a mouse wheel is 100px in chrome, and at 1:1 a stray notch at the top of the wall would arm a hundred-author fan-out. And it never says it is done, so stopping is the release: 140ms of quiet past the threshold lays the wall. The pill says "stop to lay again" rather than "let go", because telling somebody holding no button to let go is an instruction they cannot follow. A WHEEL PULL STARTS FROM REST, and that is the whole defence against momentum. A trackpad flick that reaches the top keeps delivering wheel events after the fingers have left the glass: upward, at scrollY 0, exactly the shape of a pull and nobody asked for it. What a momentum tail structurally cannot have is a gap in front of it, because it is the continuation of the scroll that just arrived, so a gesture may only begin after 200ms of quiet. A reader who means to pull always has that gap: they reach the top, the wall stops, they push again. The two inputs ask "where" differently, which is not drift. A finger grabs what is under it, so a touch pull must start inside main#wall. A wheel only points, and the cursor sits wherever it was last left, very often over the bar; refusing the gesture there would fail for a reason no reader could see. So a wheel is refused only over a screen with its own scroll, which is the switcher's panel and the scrim under it. Thirteen more vitest cases, including the momentum tail and the rule that keeps the two releases apart: a finger resting mid-drag must not lay the wall, and a touchend cannot commit a wheel pull. Four browser cases on a desktop viewport with hasTouch off. Those dispatch wheel events 16ms apart rather than driving page.mouse.wheel, because the timing IS the thing under test: every mouse.wheel call is a round trip that puts tens to hundreds of milliseconds between events, which lands on the wrong side of both timers and reads as a reader who pushed, stopped, and pushed again. The bar sticks to the top from md rather than scrolling away with the wall, so the layout picker, the switcher, refresh and settings are reachable from anywhere in an endless scroll instead of only from the top of one. It is unchanged on a phone, where it is fixed to the bottom under a thumb. z-20, so the switcher's own scrim still dims the bar its panel hangs off; the page's own colour at 80% with a blur behind it, so it reads as nothing at the top of a wall and veils the bricks that pass under it once the reader moves; and no border, because a rule across a page nobody has scrolled yet is a line for its own sake. That is the same change as the one above rather than a neighbour of it: a sticky bar moves where the top of the wall IS, and the pull indicator has to sit in the gap the wall opens rather than over the controls. So the indicator measures main#wall's own top edge when a gesture starts, which is zero on a phone and the height of the bar on a desktop. One measurement, no breakpoint named twice, and no bar height written down anywhere it could go stale. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
|
🧹 Preview wall removed. |
Merged
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.
The desktop half of the pull gesture, and the bar change that made the indicator need to think about where the wall's top is.
A wheel pulls the wall
Keep scrolling up when the wall is already at its top and it opens exactly as a finger opens it: same band, same 72px threshold, same 54px shelf, same indicator, same
feed.refresh(). Two things are forced by what a wheel is, and they are the only differences:A wheel pull starts from rest, and that is the whole defence against momentum. A trackpad flick that reaches the top keeps delivering wheel events after the fingers have left the glass: upward, at
scrollY0, exactly the shape of a pull. What a momentum tail structurally cannot have is a gap in front of it, so a gesture may only begin after 200ms of quiet. A reader who means to pull always has that gap.The two inputs ask "where" differently, and that is not drift: a finger grabs what is under it, so a touch pull must start inside
main#wall; a wheel only points, and the cursor sits wherever it was last left, very often over the bar. A wheel is refused only over a screen with its own scroll.The bar stays put on a desktop
From
mdit sticks to the top of the scroll rather than scrolling away, so the layout picker, the switcher, refresh and settings are reachable from anywhere in an endless scroll. Unchanged on a phone, where it is fixed to the bottom under a thumb.z-20so the switcher's scrim still dims the bar its panel hangs off; the page's own colour at 80% behind a blur, so it reads as nothing at the top of a wall and veils the bricks that pass under it; no border, because a rule across an unscrolled page is a line for its own sake.The two are one change rather than neighbours: a sticky bar moves where the top of the wall is, so the indicator now measures
main#wall's own top edge when a gesture starts. Zero on a phone, the height of the bar on a desktop, and no bar height written down anywhere it could go stale.Verification
just check(254 vitest, 159 cargo nextest, two tsc projects, four guards, lint, fmt) andjust test-e2e(85 browser tests, five of them new).Thirteen new vitest cases cover the momentum tail and the rule keeping the two releases apart: a finger resting mid-drag must not lay the wall, and a touchend cannot commit a wheel pull. The browser cases dispatch wheel events 16ms apart rather than driving
page.mouse.wheel, because the timing IS what is under test: everymouse.wheelcall is a round trip that puts tens to hundreds of milliseconds between events, landing on the wrong side of both timers.🤖 Generated with Claude Code