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.

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;
}

How to use this tool

  1. Configure target selectors, scroll source, axis, and animation range settings.
  2. Define start/end transform states and preview progress interactively.
  3. Copy either the `@scroll-timeline` CSS snippet or IntersectionObserver fallback code.

Dual output modes

  • Modern scroll-linked CSS for browsers supporting `animation-timeline`.
  • IntersectionObserver fallback for broader compatibility.
  • Shared transform state controls keep both snippets aligned.

Integration tips

  • Use stable selectors and class names to reduce runtime surprises.
  • Calibrate range start/end values against real content heights.
  • Keep easing and duration consistent between modern and fallback snippets.

FAQ

Does this support custom scroll containers?
Yes. You can target viewport scrolling or provide container selectors for both output modes.
Can I animate only once with the fallback?
Yes. Enable the `once` option to unobserve elements after they become visible.
Are transform and opacity both configurable?
Yes. Start and end states include opacity, translate, scale, and rotate controls.

ADVERT

ADVERT