Observer Fullpage Sections — Free GSAP Snippet

Observer Fullpage Sections · Scroll · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Unified inputs
Wheel, touch, and drag become up/down intents.
No scrollbar
Stacked sections, zero scroll height.
Gesture gating
tolerance + lock: one gesture, one section.
Parallax hand-off
Incoming slides over a receding outgoing.
Two-plane content
Inner copy arrives after its background.
Mirrored reverse
Direction multiplies the same choreography.
Generated dots
The rail builds and syncs from section count.
Boundary stops
Deck ends are guarded, no wraparound.

About this UI Snippet

Observer Fullpage Sections — Gesture-Driven Slides Without a Scrollbar

Screenshot of the Observer Fullpage Sections snippet rendered live

Fullpage section navigation — one wheel flick or swipe advances one full-screen slide — is the awwwards-site pattern that normal scrolling can't express, because the page doesn't actually scroll. This snippet builds it with GSAP's Observer plugin: sections are absolutely stacked, the document has zero scroll height, and every input gesture is translated into a single "go up / go down" intent that plays an animated hand-off.

Observer is input normalization, not scrolling

Observer.create({ type: 'wheel,touch,pointer' }) listens to mouse wheels, trackpad gestures, touch swipes, and pointer drags, and distills them into onUp/onDown callbacks (note the inversion: swiping *up* means the user wants to go *down* the deck, so onUp advances). Wheels report line deltas, trackpads flood pixel deltas, touch is positional — Observer absorbs those differences so navigation logic is two lines. preventDefault: true stops any native scrolling or overscroll bounce from leaking through.

tolerance filters intent from noise

tolerance: 12 requires 12px of accumulated movement before a callback fires — the difference between "resting a finger" and "swiping." Combined with the animating lock, one physical gesture maps to exactly one section change: trackpads that emit dozens of momentum events after a flick can't machine-gun through the deck, because everything during the transition is ignored and the residual momentum falls below tolerance by completion.

The hand-off is layered, not a plain slide

The incoming section slides from full viewport height while the outgoing one moves only −18% and dims — a parallax depth cue that reads as the new section sliding *over* the old, like sheets of paper. The incoming section's inner content also travels 40% further with a fade, arriving slightly after its background (that 0.25 offset), which gives every transition a two-plane richness one flat slide lacks. z-index is set per transition so the mover is always on top, and visibility gates which sections exist to the compositor at all.

Direction is a parameter, so reverse is free

goto(index, dir) takes the travel direction (+1/−1) and multiplies every yPercent by it: downward navigation slides sections up from below; upward navigation replays the identical choreography mirrored. One function handles both, and the boundary guard (index < 0 || index >= length) makes the deck's ends dead-stop naturally.

Why sections are stacked, not in a scroll container

With position: absolute; inset: 0 on every section and overflow: hidden on the page, there is no scroll position to manage, no snap points to fight, and no scrollbar to distract — state is just the current integer. This differs fundamentally from CSS scroll-snap (see full page scroll): snap keeps native scrolling and its physics; Observer replaces scrolling with *staged transitions* you fully choreograph.

Dots are generated and synced

The rail builds one dot per section at init and goto() swaps the active class, stretching the current dot into a pill — the only affordance revealing deck position, echoing the scroll sticky features pattern.

Customizing it

Retheme via each section's --sb/--sa variables, swap the hand-off for crossfades or horizontal slides (change the axis), or add keyboard arrows by calling goto() from a keydown listener. Related: snap-based full page scroll, pinned deck effects in scroll fade stack, and section-travel dots in page dots nav.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to trace the Observer callback wiring and the layered timeline by hand. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why onUp triggers forward navigation while onDown goes back, or how the tolerance value combined with the animating flag stops a single trackpad flick from skipping through several sections at once. The same assistant is useful for optimizing it too — ask whether four absolutely positioned full-viewport sections stays cheap with many more slides, or whether swapping visibility for a lighter opacity-only approach changes paint cost. It is just as good for extending the deck: have it add keyboard arrow-key navigation that calls goto directly, support horizontal instead of vertical travel by swapping the yPercent axis, or generate the dot rail and section count from a data array instead of hardcoded markup. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a gesture-driven "fullpage sections" deck in plain HTML, CSS, and JavaScript using GSAP with its Observer plugin (load both from a CDN) — the page itself must never scroll.

Requirements:
- Several full-viewport sections stacked with position: absolute and inset: 0 inside a fixed-height, overflow-hidden wrapper, so there is no scroll height on the document at all. Only the first section starts visible; the rest start hidden via visibility.
- Register a single Observer with type set to wheel, touch, and pointer combined, preventDefault enabled, and a tolerance value (e.g. around 10-15px) so it takes deliberate movement, not incidental jitter, to fire a callback.
- Wire Observer's onUp callback to advance to the next section and onDown to go to the previous one, matching the natural inversion where swiping/scrolling up means moving forward through the deck.
- Write one goto(index, direction) function that guards against animating while a transition is already in progress and against navigating past the first or last section, then builds a GSAP timeline that: slides the incoming section in a full viewport height from the direction of travel, moves the outgoing section only a small fraction of the viewport height while fading it, and animates the incoming section's inner text content in on a separate, slightly delayed tween so it arrives after its background — creating a layered, two-plane parallax hand-off rather than a flat slide.
- After the transition completes, hide the outgoing section with visibility so it stops being part of layout/paint, and release the animating lock.
- Generate a small dot indicator rail with one dot per section, and toggle an active class on the current dot every time goto runs, with the active dot visually distinct (e.g. stretched into a pill) from the rest.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Add the GSAP CDNsInclude gsap and Observer from the CDN panel.
  2. 2
    Paste HTML, CSS, and JSSection 01 renders; the page has no scrollbar.
  3. 3
    Wheel or swipe downThe next section slides over with parallax.
  4. 4
    Try rapid flickingThe lock and tolerance keep it one-per-gesture.
  5. 5
    Swipe back upThe same choreography plays mirrored.
  6. 6
    Add a sectionOne more .obf-sec — dots and bounds adapt.

Real-world uses

Common Use Cases

Product launch decks
One idea per screen; the scroll-native cousin is full page scroll.
Portfolio showcases
Case studies as slides, each opened by a scroll letter stagger headline.
Onboarding flows
Swipeable app intros, like mobile onboarding at page scale.
Event and campaign sites
Chaptered storytelling; pin variants live in scroll fade stack.
Presentation mode
Web slide decks with dot progress from page dots nav.
Immersive heroes
Gate the deck behind a scroll zoom hero landing.

Got questions?

Frequently Asked Questions

Raw input events: wheel deltas, touch moves, and pointer drags. It normalizes their wildly different units and rhythms into simple directional callbacks — onUp, onDown, onLeft, onRight — with velocity and delta data attached. Since sections are absolutely stacked and the document has no scroll height, those intents drive animations directly instead of moving a scroll position.

Two mechanisms: tolerance: 12 requires meaningful accumulated movement before firing, and an animating flag makes goto() ignore every input during the 0.9s transition. Trackpad momentum keeps emitting events after the flick, but they land inside the locked window and their residual deltas fall under tolerance afterward — so one gesture, one section.

Observer names callbacks after the gesture's physical direction: swiping your finger (or wheeling) upward is how you move down a page. So onUp means "content should advance" and onDown means "travel back." It feels inverted in code and completely natural in use — the same inversion native scrolling has always had.

Three staggered movements: the incoming section travels 100% of the viewport, the outgoing one recedes only −18% while dimming (so the new sheet visibly slides over the old), and the incoming inner content moves 40% further with a fade, landing 0.25s after its own background. Different distances on different planes is parallax — applied to a transition.

Scroll-snap keeps real scrolling — native physics, a scrollbar, partial states mid-drag — and snaps the resting position. Observer replaces scrolling entirely: no scroll position exists, every transition is a choreographed timeline you author, and inputs are gated to discrete steps. Snap is better for content pages; Observer is better for staged, presentation-like decks.

Create the Observer and section refs in a mount effect — useEffect, onMounted, or ngAfterViewInit — and call observer.kill() in the cleanup so listeners and preventDefault release on unmount (critical, or the page stays scroll-locked after route changes). Keep current/animating in refs, not state — re-renders mid-transition would fight the timeline. Sections and dots render naturally from an array with Tailwind classes.