tool / scroll triggerstart · end · progress

Scroll trigger visualizer

start: 'top 85%' is two words: an edge of the element, and a line across the viewport. Pick both for start and end, scroll the preview, and watch where progress is 0, where it is 1, and the arithmetic in between. Then copy the trigger.

Element edges
3
Viewport lines
3 + %
Defaults compared
8
Library
2.23.3
start: ‘top 85%’ · end: ‘top 40%’viewport0%50%100%85%scrolling downelementbelow the foldend · top 40%progress 1‘top’element edge‘85%’viewport linestart · top 85%progress 0: they meet
Fig. 1 — ‘top 85%’: the first word is an edge of the element, the second a line across the viewport, counted from its top. Progress is 0 at the scroll position where they meet, and 1 where the end pair does.
01The tool

Set a start and an end

The box below is a small viewport. Scroll it, drag the slider or press Play: the element moves past the two lines, and the drawing inside it is scrollDraw itself, given your trigger and told to watch the box instead of the window.

Presets
Start · progress 0
End · progress 1
Element height · of the viewport

Starts when its top reaches 85% down the viewport; done when its top reaches 40% down the viewport.

Viewport · 300px tall · scroll it

#drawingstart + end edge
Progress0.00

Before the start line: nothing has happened yet.

Viewport
300px tall: the scroll box
Element
top 375px down the content, 120px tall
Start
'top 85%': 375 − 255 = 120pxelement top at 375 · 85% of 300 = 255
End
'top 40%': 375 − 120 = 255pxelement top at 375 · 40% of 300 = 120
Scroll
0px
Progress
(0 − 120) ÷ (255 − 120) = -0.89, clamped to 0
main.js7 lines
import { scrollDraw } from 'svg-scroll-draw';

// starts when its top reaches 85% down the viewport,
// done when its top reaches 40% down the viewport.
scrollDraw('#drawing', {
  trigger: { start: 'top 85%', end: 'top 40%' },
});

Anything that matches scrollDraw’s own default window (top bottom → bottom top) is left out of the code.

02The arithmetic

How start and end become progress

Each pair becomes one scroll position: the place on the page where the element’s edge sits on the viewport’s line. That is the edge’s distance down the page minus the line’s distance down the viewport (fig. 1). An edge other than top adds part of the element’s height, half for center and all of it for bottom, so bottom bottom is the moment the element’s bottom edge comes into view: for an element shorter than the viewport, the moment all of it is on screen.

Progress is how far the scroll has got from the start position to the end one, clamped to 0–1. Scroll back and it goes back down, unless the function keeps what it has reached (once).

progress.js13 lines
// One element, worked by hand: a 900px-tall window,
// and the element's top 2000px down the page.
const vh = 900;
const top = 2000;

// start: 'top 85%' — its top meets the line 85% down the window.
const startAt = top - 0.85 * vh;   // 1235

// end: 'top 40%' — the same edge meets the line 40% down.
const endAt = top - 0.40 * vh;     // 1640

// In between, progress follows the scroll in a straight line.
const progress = Math.min(1, Math.max(0, (scrollY - startAt) / (endAt - startAt)));
Speed
scrollDraw, scrollAnimate, scrollProgress and useScrollDrawProgress multiply the fraction by speed before clamping, 1 by default: at speed: 2 the animation is done half way through the window. scrollText, scrollReveal, scrollCounter and scrollVideo have no speed.
Measured
The two positions are measured when the animation is created and again when the window resizes or the page’s layout changes (useScrollDrawProgress: on a window resize only). After moving the element some other way, call refresh() on a scrollDraw instance.
Native path
Only the default window, top bottom to bottom top, lets scrollDraw and scrollAnimate hand the work to the browser’s own scroll timeline. Any other trigger keeps them on their JavaScript loop, which follows the same arithmetic.
0313 forms

Every form the trigger accepts

The parser reads the first two words, split on spaces. The element’s word is top, center or bottom, and anything else is read as top. The viewport’s word is one of the same three or digits followed by %, decimals allowed (85.5%, not .5% or -10%), and anything else is read as bottom. A percentage on its own is the viewport’s line, for the element’s top. The parser does not warn when a word falls back, so the “read as” column is worth a look.

WrittenRead asWhy
'top 85%''top 85%'An element edge, then a line across the viewport.
'center center''center center'The element’s middle on the viewport’s middle.
'bottom top''bottom top'The element’s bottom on the viewport’s top: it has just left.
'85.5%''top 85.5%'Decimals are fine. A percentage on its own is the viewport line; the element edge is top.
'85%''top 85%'A percentage on its own is the viewport line; the element edge is top.
'center''center bottom'One word: the viewport line defaults to bottom.
'' (empty)'top bottom'Empty, so both words take their defaults: top, bottom.
'top 100px''top bottom'Pixels are not read. “100px” is not top, center, bottom or a percentage, so the line reads as bottom.
'top bottom-=100px''top bottom'Relative offsets are not read. “bottom-=100px” is not top, center, bottom or a percentage, so the line reads as bottom.
'top+=100 center''top center'“top+=100” is not top, center or bottom, so the element edge reads as top.
'50% center''top center'The element word cannot be a percentage: “50%” reads as top.
'Top Center''top bottom'Words are case-sensitive. “Top” is not top, center or bottom, so the element edge reads as top. “Center” is not top, center, bottom or a percentage, so the line reads as bottom.
'120%''top 120%'A percentage on its own is the viewport line; the element edge is top. Over 100%, the line is below the bottom of the viewport.
Sideways
With axis: 'x' the same words measure across: top is the left edge, bottom the right. left and right are not words the parser knows, so 'left left' reads as 'top bottom': the element’s left edge on the viewport’s right.
048 functions

The default window of each function

Leave trigger out and each function uses its own window. scrollDraw, scrollAnimate and the progress ones run the whole time the element is on screen; text, reveals and counters finish while it is still well in view, where a reader is looking; scrollVideo scrubs from the moment its top reaches the top of the viewport.

FunctionImportstartendIn words
scrollDrawsvg-scroll-draw'top bottom''bottom top'Starts when its top reaches the bottom of the viewport; done when its bottom reaches the top of the viewport.
scrollAnimatesvg-scroll-draw'top bottom''bottom top'Starts when its top reaches the bottom of the viewport; done when its bottom reaches the top of the viewport.
scrollProgresssvg-scroll-draw/progress'top bottom''bottom top'Starts when its top reaches the bottom of the viewport; done when its bottom reaches the top of the viewport.
useScrollDrawProgresssvg-scroll-draw/react'top bottom''bottom top'Starts when its top reaches the bottom of the viewport; done when its bottom reaches the top of the viewport.
scrollTextsvg-scroll-draw/text'top 85%''top 40%'Starts when its top reaches 85% down the viewport; done when its top reaches 40% down the viewport.
scrollRevealsvg-scroll-draw/reveal'top 88%''top 53%'Starts when its top reaches 88% down the viewport; done when its top reaches 53% down the viewport.
scrollCountersvg-scroll-draw'top 80%''top 20%'Starts when its top reaches 80% down the viewport; done when its top reaches 20% down the viewport.
scrollVideosvg-scroll-draw/video'top top''bottom top'Starts when its top reaches the top of the viewport; done when its bottom reaches the top of the viewport.
Reveal rows
scrollReveal also staggers a row, the elements whose tops line up: each one after the first has both lines moved a further stagger (0.15 by default) of the gap between the start and end lines up the viewport, never more than that whole gap, so a row of cards arrives one after another.
05Next to GSAP

Compared with GSAP ScrollTrigger

The two-word form is ScrollTrigger’s, so a trigger written with keywords and viewport percentages means the same in both: 'top center' is 'top center'. They part over everything else ScrollTrigger accepts. Described against GSAP 3.15.0.

GSAP ScrollTriggersvg-scroll-draw
Order of the wordsThe trigger element’s edge, then the scroller’s line.The same: the element’s edge, then the viewport’s line.
Keywordstop, center, bottom, left, right.top, center, bottom. On axis: ‘x’ they measure across: top is the left edge, bottom the right.
PercentagesOn either word: ‘80% bottom’ is 80% down the element.On the viewport word only. An element percentage reads as top.
Pixels, += and -=‘top 100px’, ‘top bottom-=100px’, and an end of ‘+=500’ counted from the start.Not read: such a viewport word falls back to bottom, such an element word to top.
Other valuesA number (an exact scroll position), a function, or clamp().Strings only.
Default window‘top bottom’ → ‘bottom top’; ‘top top’ when pinning.The same for scrollDraw, scrollAnimate and scrollProgress; scrollText, scrollReveal, scrollCounter and scrollVideo have their own (section 04).
End on another elementendTrigger measures the end on a second element.No: start and end measure one element. scrollAnimate and scrollVideo can measure another with triggerElement.
What progress doesWith scrub, follows the scroll; without, start and end toggle a tween that plays on time.Always follows the scroll. scrollDraw’s autoplay: true is the timed option: it plays over its duration when the drawing comes into view, whatever the window. In 2.23.2 and earlier, autoplay left on the default window could take the browser’s native scroll timeline and follow the scroll after all (native: false avoided it); fixed in 2.23.3.
Seeing the linesmarkers: true.scrollDraw’s debug: true, in development builds. In 2.23.2 and earlier, with the default window in a browser that has native scroll timelines, it could take the native path and draw no lines (native: false avoided it); fixed in 2.23.3.
the same window, twice18 lines
// GSAP ScrollTrigger
gsap.to('#chart', {
  opacity: 1,
  scrollTrigger: {
    trigger: '#chart',
    start: 'top center',
    end: 'bottom center',
    scrub: true,
  },
});

// svg-scroll-draw: the same two words, on the element itself
import { scrollAnimate } from 'svg-scroll-draw';

scrollAnimate('#chart', {
  props: { opacity: [0, 1] },
  trigger: { start: 'top center', end: 'bottom center' },
});
Pixels
A pixel offset has no exact match here. A percentage moves with the window’s height: on a 900px window, 'top 85%' is 135px above the bottom, on a 600px one 90px.
067 questions

Scroll trigger questions

Q1

What do start and end mean in a scroll trigger?

Each is two words: an edge of the element (top, center or bottom), then a line across the viewport (top, center, bottom or a percentage, counted from the viewport's top). start: 'top 85%' is the scroll position at which the element's top reaches 85% of the way down the viewport, and there the animation's progress is 0. end names the position where progress is 1. In between, progress follows the scroll in a straight line, and the easing shapes the motion on top.

Q2

What does start: 'top center' mean?

The animation begins when the top of the element reaches the middle of the viewport. It means the same in GSAP ScrollTrigger and in svg-scroll-draw, because both read the element's word first and the viewport's second. Paired with end: 'bottom center', the animation runs while the element passes through the middle of the screen and finishes as its bottom crosses it.

Q3

What are the default start and end of a scroll trigger?

In GSAP ScrollTrigger, start is 'top bottom' ('top top' when pinning) and end is 'bottom top'. In svg-scroll-draw it depends on the function: scrollDraw, scrollAnimate and scrollProgress use 'top bottom' to 'bottom top', the whole time the element is on screen, while scrollText uses 'top 85%' to 'top 40%' and scrollReveal 'top 88%' to 'top 53%', so text and cards have arrived while they are still well in view.

Q4

Can I use pixel offsets like 'top 100px' or 'top+=100'?

Not in svg-scroll-draw. The viewport word must be top, center, bottom or a percentage such as 85%; anything else, 100px or bottom-=100px, reads as bottom. An element word other than top, center or bottom, such as top+=100 or 50%, reads as top. Use a percentage of the viewport instead, which also keeps the timing the same on every screen height. GSAP ScrollTrigger does accept pixels and += or -= offsets.

Q5

Why is my scroll animation already part way through when the page loads?

Progress comes from how far the page is scrolled, not from when the animation was created. An element on the first screen is often past its start position before anyone scrolls: with start: 'top bottom', any element whose top is above the bottom of the window at load begins part way. Move the start line up the viewport, to 'top center' or 'top top', so the element's top is still below it when the page loads, or for something on the first screen use scrollDraw's autoplay: true, which plays on a clock when it comes into view instead of following the scroll. In 2.23.2 and earlier, autoplay on the default window could take the browser's native scroll timeline and follow the scroll after all, unless you also set native: false; 2.23.3 fixes that.

Q6

Why does my scroll animation never finish?

Its end position is further down than the page can scroll. Progress reaches 1 only when the scroll gets to the end position, so an element near the bottom of the page with end: 'bottom top' would need the page to carry it right off the top of the screen, and the page runs out first. Choose an end the page can always reach, such as 'bottom bottom' (the element's bottom on the window's bottom), or leave more room below the element.

Q7

What happens if end comes before start?

The animation runs backwards. Progress is (scroll − start) ÷ (end − start), clamped to 0–1, so when the end position is the smaller one progress is 1 before the element arrives and falls to 0 as you scroll on. With once on, as it is by default for scrollText, scrollReveal and scrollCounter, progress keeps the 1 it starts at and nothing moves. If start and end are the same position, the window has no length and progress stays 0. The visualizer warns about both.

The rest of svg-scroll-draw 2.23.3: the docs, the text animation generator and the SVG path viewer.