Follow-up to windowed particle pagination: adapt the stream UI now that the
loaded set is a window rather than the whole stream.
Progress indicator: drop the absolute "{n} / {total}" counter (the true count
is unknown when paginated) in favour of a streaming, count-free scrubber. It
renders a sliding window of segments around the current position (newest on
the right); the edge stubs page through the loaded window and pull in older
history via onLoadOlder when scrubbing past the oldest loaded segment.
Stream list sidebar: auto-fetch older particles via an IntersectionObserver
sentinel as the user scrolls toward the top, with viewport scroll-anchoring so
prepended history doesn't jolt the view. Auto-scroll-to-current is now gated on
genuine selection changes (not index shifts from prepends). Header count gains
a "+" while more history exists, and a spinner shows while paging.
ScrollArea gains an optional `viewportRef` to expose the scroll viewport for
anchoring and observers.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V8gsmdVd7R8PJtn4UFnC4J
Streams previously prefetched every particle through an unbounded Firestore
subscription. This adds a windowed source that anchors a `created_at desc`
limit query at the newest particle and grows it backward on demand, so the
already-seen history before a viewer's playback marker is no longer loaded.
- `useWindowedStreamParticles`: tail-anchored live window that grows backward
to cover the resume marker and to service `loadOlder()` (list scroll-up).
Because the window always includes the newest particle, new arrivals stream
in and forward playback never needs a fetch. Includes anti-eviction growth
so a new tail particle never pushes loaded particles out of the window.
- `useStreamPlayback`: consumes the windowed source instead of loading all
children. New-tail and removal handling are derived from the children array
(Firestore change events can't tell a genuine arrival from pagination
backfill). Resume-from-marker waits for backward growth to reach an older
marker; `prev` at the window edge pulls in older history.
Playback resume, forward-only marker persistence, auto-advance-on-new, and
removal fallback are all preserved. List view and progress indicator continue
to render off the (now windowed) children; their pagination UX is a follow-up.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V8gsmdVd7R8PJtn4UFnC4J