May 8, 2026 at 12:00:00 AM UTC

Timeline Scroll Reveal Fix

websitetooling

The problem

The devlog launched with 94 posts and showed none of them. Data was fine, build was fine — the scroll reveal was broken.

Entries start at opacity: 0 and get a revealed class from an IntersectionObserver when they enter the viewport. The observer variable was declared as $state, and the $effect that sets it up reads it in a guard:

let observer: IntersectionObserver | undefined = $state();

$effect(() => {
  if (!timelineEl || observer) return;
  observer = new IntersectionObserver(...);
});

Reading $state inside $effect creates a reactive dependency. Setting observer triggers a re-run — which fires the cleanup (observer.disconnect()) before the observer's async callback had a chance to run. Every entry stayed invisible.

Fix

let observer: IntersectionObserver | undefined;

observer is internal to the effect and not read anywhere in the template. It didn't need to be reactive.


all entries