All components

Phive Sticky Cards

GSAP animation component · Published 2026-07-27 · by vanguardia.dev

Open live demo ↗ Raw prompt (.md)

What it does

A vertical stack of full-height sticky cards that fold away on scroll: each card is pinned (pinSpacing false) while ScrollTrigger scrub-animates its inner panel translating up 50%, pushing back -250px in Z and tilting 45deg on rotationX in 3D perspective, with a black overlay fading in via an animated --after-opacity variable as the next card arrives. Driven by GSAP ScrollTrigger synced to Lenis smooth scrolling.

How it's built

Categoryscroll
Techgsap, lenis
GSAP pluginsScrollTrigger
Complexitypage
Performance costlight
Mobile-safeyes
Scrollhijacks scrolling

sticky cards scroll pin scrub 3d-fold perspective lenis pop-art

Rebuild it with AI

To reproduce this animation in your own project, copy the prompt below into Claude Code, Cursor or any AI coding agent. The prompt is validated — it describes the exact structure, timing and easing, so the agent rebuilds the effect faithfully and you can then adapt colors, copy and layout to your design.

The full prompt

Sticky Cards that Fold Away in 3D on Scroll

Goal

Build a scroll-driven "sticky card deck" page: four full-height, brightly colored art cards stack on top of each other. As you scroll, each card stays pinned while its inner panel folds away in 3D — sliding up, pushing back in Z and tilting 45° on the X axis — and darkens under a fading black overlay as the next card slides over it. Smooth scrolling via Lenis.

Tech

Vanilla HTML/CSS/JS with ES module imports. Use gsap (npm), the GSAP plugin ScrollTrigger, and lenis for smooth scrolling.

import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import Lenis from "lenis";
gsap.registerPlugin(ScrollTrigger);

Layout / HTML

Three sections in order:

  1. section.hero — a centered <h1> reading "Art That Lives Online".
  2. section.sticky-cards — contains four div.card elements with ids card-1card-4. Each card contains one div.card-inner with, in this order:
  3. div.card-info > p — a short one-line tagline.
  4. div.card-title > h1 — a huge one-word title.
  5. div.card-description > p — a 2–3 sentence description.
  6. div.card-img > img — the artwork image.
  7. section.outro — a centered <h1> reading "Next Canvas Awaits".

Card copy (title / tagline / description theme):

  1. Reverie — "A surreal dive into neon hues and playful decay" — a psychedelic skull study in bold candy tones and liquid vector forms, made for covers and prints.
  2. Vaporwave — "A retro-futurist scene where nostalgia meets glitch" — an 80s-UI dreamscape of stacked windows, checkerboard floors and sunset gradients, like a loading screen to another world.
  3. Kaleido — "A kaleidoscope of folk motifs reimagined in digital form" — ornamental folk symmetry with stained-glass glow, designed as a seamless tileable pattern.
  4. Menagerie — "A portrait framed by oddball creatures and doodles" — a playful portrait surrounded by mascots, monsters and midnight snacks; loose linework meets pastel whimsy.

Styling

Fonts (Google Fonts): Barlow Condensed (all weights, notably 900) for all h1s, Host Grotesk as the body font.

Global:

  • * { margin: 0; padding: 0; box-sizing: border-box; }
  • img { width: 100%; height: 100%; object-fit: cover; }
  • h1 { text-transform: uppercase; font-family: "Barlow Condensed"; font-size: 5rem; font-weight: 900; line-height: 1; }
  • p { text-transform: uppercase; font-weight: 500; }

Palette (CSS variables on :root):

  • --accent-1: #b1c0ef (light periwinkle blue) → card 1 background
  • --accent-2: #f2acac (soft pink) → card 2
  • --accent-3: #fedd93 (pale yellow) → card 3
  • --accent-4: #81b7bf (muted teal) → card 4

Sections:

  • .hero, .outro: position: relative; width: 100vw; height: 100svh; padding: 2rem; flex centered, text-align: center, background #f9f4eb (warm cream), color #141414.
  • .sticky-cards: position: relative; width: 100vw; background-color: #0f0f0f; (near-black — visible behind the cards while they fold).

Cards (this is what makes the 3D fold work — do not skip any of it):

  • .card: position: sticky; width: 100%; height: 125svh; transform-style: preserve-3d; perspective: 1000px;
  • .card-inner: position: relative; width: 100%; height: 100%; display: flex; flex-direction: column; transform-origin: 50% 100%; will-change: transform; text-align: center; Each card's inner gets its accent variable as background-color (#card-1 .card-inner { background-color: var(--accent-1); }, etc.).
  • .card-info: width: 25%; padding: 4em; text-align: left; with p { font-size: 0.9rem; }
  • .card-title h1: font-size: 10rem; padding: 2rem 0;
  • .card-description: width: 60%; margin: 0 auto 2em auto; with p { font-size: 1.5rem; }
  • .card-img: width: 100%; height: 100%; margin-top: 4em; overflow: hidden; (it fills all remaining vertical space; the image inside covers it).

Darkening overlay — drive it with a CSS custom property so GSAP can animate it:

.card-inner::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: #000;
  opacity: var(--after-opacity, 0);
  will-change: opacity;
  pointer-events: none;
  z-index: 2;
}

Mobile (@media (max-width: 1000px)): h1 and .card-description become width: calc(100% - 4rem); font-size: 3rem; margin: 0 auto;; .card-info becomes width: 75%; margin: 0 auto; padding: 4em 2em; text-align: center;; .card-title h1 drops to 3rem; .card-description p to 1.25rem.

GSAP effect (the important part — be exact)

Everything runs inside a DOMContentLoaded handler.

1. Lenis ↔ ScrollTrigger sync
const lenis = new Lenis();
lenis.on("scroll", ScrollTrigger.update);
gsap.ticker.add((time) => {
  lenis.raf(time * 1000);
});
gsap.ticker.lagSmoothing(0);
2. Per-card fold animation

Collect the cards with gsap.utils.toArray(".card"). Loop over them with their index. Only cards that have a card after them animate (i.e. skip the last card — it never folds; guard with if (index < cards.length - 1)). For each animating card, grab its .card-inner and create TWO scrubbed tweens, both triggered by the NEXT card (cards[index + 1]):

Tween A — the 3D fold (gsap.fromTo on the card's .card-inner):

  • From: { y: "0%", z: 0, rotationX: 0 }
  • To: { y: "-50%", z: -250, rotationX: 45 }
  • ScrollTrigger config:
  • trigger: cards[index + 1] (the following card)
  • start: "top 85%"
  • end: "top -75%"
  • scrub: true
  • pin: card — pin the CURRENT card while its successor scrolls over it
  • pinSpacing: false — critical: no spacer is added, so the next card overlaps and covers the pinned one

No ease/duration matter here (fully scrub-driven). Because .card has perspective: 1000px and .card-inner has transform-origin: 50% 100% (bottom-center), the panel visually tips backwards from its bottom edge while receding, like a card falling away into the page.

Tween B — the darkening overlay (gsap.to on the same .card-inner):

  • Animates the CSS custom property "--after-opacity" from its default 0 to 1 (this drives the ::after black layer's opacity).
  • ScrollTrigger config:
  • trigger: cards[index + 1]
  • start: "top 75%"
  • end: "top -25%"
  • scrub: true
  • (no pin on this one)

Note the deliberately offset ranges: the fold spans a longer scroll distance (85% → -75%) than the darkening (75% → -25%), so the shadow ramps up faster and finishes while the card is still folding, selling the "next card casts a shadow over the previous one" illusion.

Assets / images

4 images, one per card, used as full-bleed fillers of the card's lower region (.card-img takes the remaining ~half of a 125svh card at full width, image cropped with object-fit: cover — landscape/wide crops work best, roughly 16:9 or wider). Described by role:

  1. Card 1 (periwinkle, "Reverie"): psychedelic pop-art vector illustration — a stylized skull with candy-colored accents amid liquid shapes on a deep saturated background.
  2. Card 2 (pink, "Vaporwave"): retro-futurist vaporwave scene — stacked 80s OS windows, a striped sunset, black-and-white checkerboard floor, pastel gradient shapes.
  3. Card 3 (yellow, "Kaleido"): symmetrical kaleidoscopic mandala of folk motifs in warm oranges, browns and pinks, centered on an eye surrounded by flowers and hearts.
  4. Card 4 (teal, "Menagerie"): busy doodle-art portrait of a stylized figure surrounded by cartoon mascots, monsters and small objects in loose pastel linework.

Behavior notes

  • The effect is purely scroll-scrubbed — scrolling back up reverses the fold perfectly.
  • The last card never animates or pins; it simply gets covered by the outro section scrolling over the stack's flow.
  • Cards are 125svh tall on purpose (taller than the viewport) so consecutive cards overlap generously during the transition.
  • Works on mobile (the media query only adjusts typography/widths; the fold effect is unchanged).
  • No load-in animation: the page is static until the user scrolls.