ToolHop.

ADVERT

🌀 Scroll Animation Builder

Design scroll-driven reveal effects, map scroll ranges, and export modern @scroll-timeline CSS alongside IntersectionObserver fallbacks for wider browser support.

Scroll Animation Builder

Configure a scroll-driven reveal animation and export either the modern @scroll-timeline powered CSS snippet or a backwards-compatible IntersectionObserver boilerplate. Adjust the animation range, transforms, easing, and selectors — then copy the ready-to-paste code.

Timeline & selectors

Choose the elements that should animate and how the scroll range is mapped to progress.

Preview & keyframes

Adjust start and end states to see how the element should move as scroll progress increases.

Scroll me

Start (0%)

End (100%)

IntersectionObserver fallback

Configure a class toggling strategy for browsers that do not yet support animation-timeline.

CSS scroll-linked snippet

Requires Chromium 115+, Safari 17+, or Firefox Nightly with the Scroll-driven Animations flag.

/* CSS Scroll-linked Animation */
@supports (animation-timeline: scroll()) {
  @scroll-timeline scroll-animate {
    source: auto;
    orientation: block;
    scroll-offsets: entry 0%, cover 65%;
  }

  .animate-on-scroll {
    animation-name: reveal-on-scroll;
    animation-duration: 1s;
    animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
    animation-fill-mode: both;
    animation-iteration-count: 1;
    animation-timeline: scroll-animate;
    animation-range: entry 0% cover 65%;
  }

  @keyframes reveal-on-scroll {
    from {
      transform: translate3d(0px, 48px, 0) rotate(0deg) scale(0.96);
      opacity: 0;
    }
    to {
      transform: translate3d(0px, 0px, 0) rotate(0deg) scale(1);
      opacity: 1;
    }
  }
}

IntersectionObserver fallback

Use alongside the CSS above to support browsers without animation-timeline.

/* IntersectionObserver Scroll Animation */
const observer = new IntersectionObserver((entries, observer) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      entry.target.classList.add("is-visible");
      observer.unobserve(entry.target);
    }
  });
}, {
  root: null,
  rootMargin: "0px 0px -25%",
  threshold: 0.35,
});

document.querySelectorAll(".animate-on-scroll").forEach((el) => {
  observer.observe(el);
});

/* CSS pairing */
.animate-on-scroll {
  transform: translate3d(0px, 48px, 0) rotate(0deg) scale(0.96);
  opacity: 0;
  transition: transform 650ms cubic-bezier(0.33, 1, 0.68, 1) 0ms,
    opacity 650ms cubic-bezier(0.33, 1, 0.68, 1) 0ms;
  will-change: transform, opacity;
}

.animate-on-scroll.is-visible {
  transform: translate3d(0px, 0px, 0) rotate(0deg) scale(1);
  opacity: 1;
}

ADVERT

ADVERT

Scroll Animation Builder - CSS @scroll-timeline & IntersectionObserver Generator