Skip to main content
GSAP Animation TutorialArticle 21

GSAP ScrollTrigger Project: Build an Interactive Scroll Storytelling Website

Combine the series into one production-minded project: a four-stage “From Idea to Launch” story driven by a single timeline, scrubbed progress, desktop pinning and meaningful snap points.

GSAP ScrollTrigger project from idea to launch with Discover, Design, Develop and Launch stages

This capstone turns separate GSAP concepts into one coherent experience. The page begins as readable HTML, enhances to a pinned story on wide screens, follows native scroll with scrub, and settles at four named timeline states. Mobile and reduced-motion visitors get the same information without a long pinned sequence.

1. Project Preview

Scroll through the project on a desktop-sized viewport. The stage pins, the normalized timeline follows your scroll position, progress selects one of four states, and snap gently completes the nearest directional transition. After Launch, the pin releases and the article continues normally.

From idea to launch01

Discover

Research the audience, business goal and strongest story direction.

01 Discover

Research the audience, business goal and story direction.

02 Design

Shape the content hierarchy, interface and motion language.

03 Develop

Build a resilient semantic and responsive implementation.

04 Launch

Test, optimize, release and measure the experience.

Stage 1 of 4: Discover

2. What We Are Building

The experience explains a real delivery process in four stages: Discover, Design, Develop and Launch. Each stage has content, a distinct CSS illustration and an exact point on one GSAP timeline. ScrollTrigger owns only the relationship between page scroll and that timeline.

01 Discover

Research, evidence and direction.

02 Design

Structure, systems and prototypes.

03 Develop

Semantic, responsive implementation.

04 Launch

Testing, release and iteration.

3. Project HTML Structure

Keep the content layer boring—in the best sense. Use a section root, a copy region, progress UI, four buttons, four visual panels and a mobile stage list. Data attributes form the JavaScript contract while classes remain available for presentation.

Semantic project shell
<section data-story-project aria-label="From Idea to Launch">
  <div data-stage-number>01</div>
  <h3 data-stage-title>Discover</h3>
  <p data-stage-description>...</p>
  <span data-project-progress></span>
  <button data-project-dot>1</button>
  <div data-project-stage>...</div>
</section>

4. Story Data

Store stage names and descriptions in arrays or objects. The active-stage function reads this small model and updates the view. Centralized data prevents headings, status messages and navigation labels from drifting apart.

const stages = [
  { title: "Discover", number: "01" },
  { title: "Design",   number: "02" },
  { title: "Develop",  number: "03" },
  { title: "Launch",   number: "04" }
];

5. Original Visuals for Each Stage

The live demo uses lightweight CSS-native visuals: a research radar, interface wireframes, a code window and a launch orbit. They reinforce meaning without downloading extra photographs or hiding essential content inside a canvas.

ScrollTrigger story architecture from trigger and pin through timeline, scrub, snap and release
The complete interaction pipeline and the four story states.

6. Basic Layout CSS

The desktop shell is a two-column grid. Copy occupies the left; the contained artwork occupies the right. A breakpoint removes the artwork panel and displays the semantic stage list so a narrow screen never depends on pinning.

.story-project__shell {
  min-height: 620px;
  display: grid;
  grid-template-columns: .85fr 1.15fr;
}
@media (max-width: 899px) {
  .story-project__shell { grid-template-columns: 1fr; }
  .story-stage-list { display: grid; }
}

7. First Non-Animated Version

Before loading GSAP, confirm the heading, four stages and continuation content are understandable. This baseline is your SEO, accessibility and failure-safe version. Animation should improve orientation—not manufacture the information.

8. Register ScrollTrigger

Load GSAP core first, then ScrollTrigger, and register the plugin once after both globals exist. The project script checks for missing dependencies before enhancement.

if (window.gsap && window.ScrollTrigger) {
  gsap.registerPlugin(ScrollTrigger);
}

9. Create the Project Timeline

One master timeline makes progress deterministic. It contains three equal transition intervals with labels at time 0, 1, 2 and 3. ScrollTrigger then normalizes the entire duration into progress from zero through one.

const story = gsap.timeline({
  scrollTrigger: {
    trigger: project,
    start: "top top",
    end: "+=2400",
    scrub: 1,
    pin: true,
    snap: { snapTo: "labelsDirectional" }
  }
});

10. Why 1 / 3 Snap?

Four story states create three gaps: Discover→Design, Design→Develop and Develop→Launch. Equal normalized points therefore sit at 0, 1/3, 2/3 and 1. Labels express the same idea more clearly when the timeline later gains unequal timing.

11. Build Stage 1: Discover

Discover is the stable initial state. It should exist before JavaScript changes anything. That removes a flash of blank content and gives the timeline a reliable origin.

12. Transition Discover → Design

Animate the radar out while the wireframe enters during the first timeline unit. Cross-fading with transforms avoids abrupt layout work and makes the handoff feel continuous.

13. Stage 2: Design

Design replaces uncertainty with a visible system. The purple wireframe panels use the same bounded artboard, so the stage change does not shift document layout.

14. Transition Design → Develop

Move from broad interface blocks to the focused code window. Because both panels occupy the same absolute layer, only opacity and transform need to change.

15. Stage 3: Develop

Develop represents implementation. The code graphic is decorative, while the adjacent HTML heading and paragraph preserve the actual meaning for every visitor.

16. Transition Develop → Launch

The final interval can lift the code panel and bring the orbit forward. Keep the easing quiet under scrub because scroll velocity already supplies a strong motion signal.

17. Stage 4: Launch

Launch is the final stable state at progress one. The pin releases only after this stage has enough scroll distance to be seen, then the rest of the document continues.

18. Timeline Position Parameters

Position parameters such as "<", ">" and relative offsets coordinate stage layers without arbitrary delays. Use them inside an interval while retaining equal label boundaries.

19. Timeline Labels

Labels name the intended states: discover, design, develop and launch. Named timing survives refactoring better than unexplained decimal values.

story.addLabel("discover", 0)
  .to({}, { duration: 1 })
  .addLabel("design", 1)
  .to({}, { duration: 1 })
  .addLabel("develop", 2)
  .to({}, { duration: 1 })
  .addLabel("launch", 3);

20. Align Snap with Story States

labelsDirectional settles toward a named stage in the current travel direction. If labels are not available, use snapTo: 1 / 3. Do not mix equal snap math with unequal stage timing unless the mismatch is intentional.

21. Progress Bar

Normalized ScrollTrigger progress maps directly to a bar from 0% through 100%. Transform scaling is ideal for animated bars, while this project updates width only when a discrete stage changes to minimize writes.

22. Stage Counter

The large 01–04 counter gives immediate orientation. It is visible text, not a pseudo-element, so the interface remains meaningful when styles are unavailable.

23. Navigation Dots

Use real buttons with stage-specific accessible names. On desktop, selecting a dot scrolls to the matching position inside the existing trigger range; it does not replace or trap native scrolling.

24. Active Stage State

One function updates title, description, counter, art, dot state and live status. It returns immediately when the index has not changed, preventing needless DOM work during continuous scroll updates.

function updateStage(index) {
  index = Math.max(0, Math.min(3, index));
  if (index === activeIndex) return;
  activeIndex = index;
  // Update the small set of stage-dependent nodes.
}

25. Visual Stage Changes

Only the active artwork is exposed visually. The panels share one positioned container, preventing document reflow. The complete text stage list remains separate for mobile and reduced motion.

26. Scrub Configuration

scrub: 1 lets the timeline catch up over roughly one second, softening wheel and touchpad input. scrub: true creates a more direct mapping. Test both on real hardware.

27. Snap Configuration

Use a short min/max duration, small delay and calm ease. Long snap animations feel like the page has taken control away from the visitor.

snap: {
  snapTo: "labelsDirectional",
  duration: { min: 0.18, max: 0.55 },
  delay: 0.08,
  ease: "power1.inOut"
}

28. Pin Configuration

pin: true pins the trigger element and lets ScrollTrigger manage spacing. Avoid manually animating the pinned wrapper itself; animate children inside it instead.

29. End Range

The example uses end: "+=2400" on desktop. That creates 800 pixels per transition, but it is a design choice—not a universal constant. Shorter content and smaller screens require less distance.

30. Project Progress Mental Model

PAGE SCROLL0–1 PROGRESS0–3 TIMELINEACTIVE STAGESNAP + RELEASE

31. Desktop Experience

Desktop gets the full two-column pinned narrative because it has enough viewport space to preserve context and show the artwork without covering the copy.

32. Tablet Experience

At intermediate widths, test both orientations. This implementation uses 900 pixels as the enhancement boundary; below it, the story becomes a fast vertical reading experience.

33. Mobile Experience

Mobile keeps every stage in normal flow and omits pin, snap and decorative stage switching. That preserves touch momentum, browser controls and predictable back/forward navigation.

Responsive ScrollTrigger strategy showing desktop pin scrub snap and mobile normal flow with reduced motion
Progressive enhancement: richer desktop choreography, simpler mobile and reduced-motion reading.

34. gsap.matchMedia()

gsap.matchMedia() creates breakpoint-specific animation context and can revert it cleanly. Put the pinned trigger inside the desktop query instead of building it everywhere and trying to disable pieces later.

const mm = gsap.matchMedia();
mm.add("(min-width: 900px)", () => {
  const timeline = buildDesktopStory();
  return () => timeline.kill();
});

35. Reduced Motion

If prefers-reduced-motion: reduce matches, do not build the pinned timeline. Display the four static stage cards, stop smooth programmatic scrolling and remove nonessential transition effects.

36. Project Accessibility

Use semantic headings, visible focus, labelled buttons and a quiet live status. Never place essential explanations only inside artwork. Keyboard users must be able to pass through the project without extra keystrokes.

37. No Scroll Hijacking

The browser remains the scroller. We do not cancel wheel events, simulate momentum or lock the viewport. ScrollTrigger reads and maps native scroll position; snap is short, interruptible and disabled on small screens.

38. Project Performance

Animate transform and opacity, bound large decorative layers, avoid layout reads inside onUpdate, and do not initialize the same project twice. The heaviest assets on this article are lazy-loaded below the featured image.

39. Cache DOM References

Query the root once and cache counter, title, description, progress, dots and panels. Repeating selectors during every scroll update creates avoidable work and makes ownership less clear.

40. Avoid Rebuilding While Scrolling

Build at initialization, breakpoint changes or an explicit control-panel submission—not inside onUpdate. Updating state is cheap; recreating triggers is not.

41. Refresh Strategy

Call ScrollTrigger.refresh() after the layout is ready or after a real geometry change. Do not call it on every scroll. If web fonts or dynamically sized media alter the page, refresh once they settle.

42. Project Code Architecture

The implementation separates content, presentation and behavior. PHP emits semantic HTML and metadata, the dedicated stylesheet owns the project design, and one dedicated JavaScript file owns only this interaction.

Project code architecture with HTML CSS JavaScript GSAP timeline ScrollTrigger and responsive cleanup
A small layered architecture makes the project easier to audit, debug and remove.

43. Main Project Initialization

Wait for the DOM, find the project root, cache nodes, paint the first stage and exit safely if GSAP is missing. Defensive initialization keeps the rest of the page functional.

44. Timeline Construction

Create one timeline inside the desktop media context. Attach one ScrollTrigger to it. Store the reference on the project root only if external navigation needs access to its calculated range.

45. Equal Stage Timing

Three duration-one placeholders give the timeline a duration of exactly three. In a production motion pass, each placeholder can become a coordinated transition while the boundaries stay at 0, 1, 2 and 3.

46. Scroll Story Timeline Diagram

0.00
Discover
0.33
Design
0.67
Develop
1.00
Launch

47. Active Stage Calculation

Multiply normalized progress by the last index and round: Math.round(progress * 3). Clamping to 0–3 protects against floating-point edge cases.

48. Update Content Efficiently

Update only after the rounded index changes. This turns potentially hundreds of scroll callbacks into at most four meaningful interface state changes across the story.

49. Decorative Motion

Radar sweeps, wireframe lines and launch orbits may animate independently, but keep them subtle and scoped to the active panel. They should pause or disappear when reduced motion is requested.

50. Stage Transition Easing

Use ease: "none" for the timeline under scrub so the scroll-to-progress mapping remains honest. Use a gentle ease for the brief snap settling action.

51. Debug Mode

During development, add markers: true, outline the trigger and pin spacer, and log label times. Remove markers before publishing because they are development UI.

52. Project Control Panel

This compact lab rebuilds only the project trigger. Change scrub smoothing or disable snapping, then apply the settings. The controls appear in normal flow and do not mutate global ScrollTriggers.

53. Project Code Preview

Core configuration
const timeline = gsap.timeline({
  defaults: { ease: "none" },
  scrollTrigger: {
    trigger: project,
    start: "top top",
    end: "+=2400",
    scrub: 1,
    pin: true,
    snap: { snapTo: "labelsDirectional" },
    onUpdate: self => setStage(Math.round(self.progress * 3))
  }
});

54. Full Project Breakdown

Content layer

SEO-friendly headings, paragraphs, stage cards and navigation.

Motion layer

One timeline, one trigger and four labels.

Resilience layer

Media-query cleanup, reduced motion and no-JS readability.

55. Common Project Mistakes

  • Creating a separate competing ScrollTrigger for every stage.
  • Using four intervals for four states instead of three.
  • Pinning long content on a narrow touch viewport.
  • Hiding the entire story until JavaScript runs.
  • Refreshing or querying the DOM continuously during scroll.
  • Killing unrelated triggers during cleanup.

56. Debugging Checklist

  • GSAP core loads before ScrollTrigger.
  • The plugin is registered once.
  • The trigger exists and has stable height.
  • Labels match the four intended states.
  • Start and end markers appear where expected.
  • Only desktop creates the pin.
  • Resize cleanup removes the old trigger.
  • Content after the project remains reachable.

57. Testing the Project

Test wheel, touchpad, keyboard, touch and scrollbar dragging. Resize across 900 pixels repeatedly, toggle reduced motion, navigate the dots, interrupt a snap and confirm the article continues after release. Also test with JavaScript blocked.

58. SEO/Content Value

Search engines receive a canonical, indexable article with one H1, descriptive headings, structured BlogPosting and FAQ data, internal series links and visible text for every stage. The interaction is enhancement, so indexing does not depend on animation execution.

59. Mini Challenge

Add a fifth “Measure” stage. Update the model, navigation, accessible list, timeline label and artwork. Then recalculate equal snapping: five states create four intervals, so the numeric alternative becomes 1 / 4.

60. QUICK REFERENCE

Desktop

matchMedia, one timeline, pin, scrub 1, labelsDirectional snap, +2400 end.

Mobile / reduced motion

Normal document flow, all stages visible, no pin, no snap, no essential animated content.

61. PROJECT ARCHITECTURE GRAPHIC

The three original supporting designs in this article cover interaction flow, responsive strategy and code ownership. Together with the featured thumbnail, they form a consistent visual set for the post and social sharing.

62. FINAL MENTAL MODEL

Build content first. Organize motion in one labelled timeline. Let ScrollTrigger map native scroll to that timeline. Use pin to preserve context, scrub to follow progress and snap to settle at meaningful states. Remove the enhancement when screen size or motion preference says it is not helpful.

63. CONTINUE TO BLOG #22

Continue with GSAP ScrollSmoother Tutorial: Create Smooth Scrolling Experiences to add controlled visual catch-up while keeping ScrollTrigger integrated with native page scrolling.

Frequently Asked Questions

How do I build a ScrollTrigger project with GSAP?

Start with semantic HTML and a complete non-animated layout, build one GSAP timeline for the story, then connect that timeline to ScrollTrigger with deliberate start, end, scrub, pin and snap settings.

How do I combine pin, scrub and snap?

Add them to the ScrollTrigger configuration attached to the main timeline. Pin holds the stage, scrub maps scroll progress to timeline progress, and snap settles the playhead at a meaningful stage.

How many snap intervals do four stages need?

Four stages create three intervals, so equally spaced stages use a normalized increment of 1 / 3.

How do I align snap points with timeline stages?

Give every stage equal timeline time or add timeline labels at the exact stage boundaries and use labelsDirectional for snapTo.

Should I use one timeline for a scroll storytelling project?

Usually yes. One timeline provides a single source of truth for sequence, progress, labels and cleanup while small independent decorative effects can remain separate.

How do I update a progress bar with ScrollTrigger?

Read the normalized progress in onUpdate and scale or resize the progress indicator. Avoid rewriting the DOM when the displayed state has not changed.

How do I update the active stage while scrolling?

Convert normalized progress into an index with Math.round(progress times the final stage index), clamp it, and update the interface only when that index changes.

Should I pin storytelling sections on mobile?

Not automatically. This project keeps normal content flow below 900 pixels because a long pinned touch experience can feel restrictive and consume valuable screen space.

How do I make ScrollTrigger projects responsive?

Use gsap.matchMedia to create desktop-only triggers, provide a readable mobile layout, and return cleanup logic for every breakpoint-specific animation.

How do I respect prefers-reduced-motion?

Detect the preference before building the scroll timeline, remove nonessential motion, avoid pin and snap, and expose all information in the normal document flow.

How do I prevent horizontal overflow?

Animate transforms instead of layout properties, keep art inside bounded containers, test at narrow widths, and avoid applying overflow rules globally.

How do I debug a pinned ScrollTrigger project?

Temporarily enable markers, verify the trigger and scroller, inspect start and end values, test without snap, and refresh after fonts and layout-dependent assets settle.

Can I use ScrollTrigger with a static PHP website?

Yes. PHP produces the HTML on the server and GSAP runs in the browser. No framework or build process is required.

Should essential content depend on GSAP?

No. Keep the complete story in semantic HTML so it remains available to search engines, assistive technology, reduced-motion users and visitors when JavaScript fails.

Is ScrollTrigger good for portfolio storytelling?

Yes, when motion clarifies a sequence and the experience remains fast, navigable and readable without the animation layer.