main ← dev/smoother-post-stream-scroll
opened 01:36AM - 13 Feb 26 UTC
## Summary
- Improves scroll position stability when loading posts above the vi…ewport by using `scrollBy`-based compensation instead of `scrollTo` + `offsetCalculator`
- Dynamically hides banners, notices, and footer content when the user is in the middle of a long topic via a new `scrollState` service and `{{hideScrollableContent}}` helper
- Triggers loading more posts when navigating to boundary posts via keyboard (`j`/`k` keys)
- Prevents load-more sentinel from re-triggering during scroll compensation with a `suppressLoadAbove` flag
## Details
### Scroll compensation
When new posts are prepended above the viewport, the component captures the anchor post's position via `getBoundingClientRect()` before DOM insertion (using a `beforePrepend` callback in `prependMore()`), then compensates with `window.scrollBy()` after insertion. This keeps the reading position visually stable.
### Content hiding
A `scrollState` service tracks ref-counted hide requests. The `{{hideScrollableContent}}` class-based helper registers with the service and automatically cleans up via `registerDestructor`. The `application.gjs` and `topic.gjs` templates wrap scrollable content in `{{#unless shouldHideScrollableContentAbove/Below}}` blocks.
The helper invocations live in `topic.gjs` outside the `{{#unless loadingFilter}}` guard so content stays hidden during timeline jumps that temporarily unmount `<PostStream>`.
### Keyboard navigation
`updateKeyboardSelectedPostNumber` now checks if the selected post is at a loaded boundary (`firstAvailablePost` / `lastAvailablePost`) and triggers `loadMoreAbove` / `loadMoreBelow`. Double-loading is prevented by existing `canPrependMore` / `canAppendMore` guards.