Scroll 3D Cards — Free GSAP ScrollTrigger 3D Flip-Up Cards
Scroll 3D Cards · Scroll · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Scroll 3D Cards — Cards That Flip Up Into Place on Scroll

Scroll 3D cards is the entrance where each card lies tilted back in 3D space and rotates upright as it scrolls toward the center of the screen, like pages standing up — a depth-rich alternative to a flat fade-in. This snippet builds it with GSAP and ScrollTrigger (from a CDN) and CSS 3D, with each card animated by its own scrubbed trigger.
Perspective creates the depth
The list container sets perspective: 1100px, which is what turns the cards' rotateX into genuine 3D foreshortening rather than a flat vertical squash. Each card also gets transform-style: preserve-3d. Without the perspective on the parent, a rotateX would just look like the card getting shorter; with it, the top edge appears to lean away and swing toward you as it rights itself.
Per-card scrubbed tween
Every card gets its own gsap.fromTo tied to a ScrollTrigger on that card. It animates from rotateX: -55, pushed down (y: 80) and transparent, to flat, in place, and opaque — with the trigger running from start: 'top 88%' to end: 'top 45%' and scrub: true. So each card rotates upright precisely as it travels from the lower part of the viewport up toward center, and tilts back if you scroll up. Giving each card its own trigger is what lets them animate independently as they enter, rather than all at once.
transform-origin sells the hinge
The rotation uses transformOrigin: '50% 100%', so the card pivots around its bottom edge — it stands up from its base like a hinged panel, which is far more convincing than rotating around the center. This single property is the difference between "flipping up" and "spinning in place".
Scrub ties motion to position, not time
Because the trigger is scrubbed, the card's angle is a direct function of how far it has scrolled into the viewport, so it's fully reversible and never plays out of step with the scroll. Slow scrolling reveals the cards slowly; fast scrolling snaps them upright — the motion always matches the user's pace.
GPU-composited
Only transform (rotateX, y) and opacity animate, so the browser composites the cards without layout work, and will-change and the box shadow give them a floating, physical quality as they swing up. The effect stays smooth even with many cards because each trigger only animates while its card is in the active range.
Customizing it
Change the starting tilt, the rise distance, the trigger range for an earlier or later flip, or the easing; rotate on rotateY for a door-like swing instead. Pair it with a scroll reveal grid, a scroll sticky stack, or 3d card tilt.
Build with AI
Build, Understand, Optimize, and Extend It With AI
You do not have to work out the 3D math by hand. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain precisely why the parent needs perspective while each card needs transform-style preserve-3d, and why transformOrigin is set to 50% 100% rather than the default center. The same assistant is useful for optimizing it — ask whether creating one ScrollTrigger per card scales cleanly to a list of fifty items, or whether batching them with ScrollTrigger.batch would reduce overhead while keeping the same per-card entrance feel. It is just as useful for extending the effect — ask it to swap rotateX for rotateY so cards swing open like doors, stagger the y offset so cards also drift in from alternating sides, or combine the flip-up entrance with a hover-tilt effect for after the card has settled. 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:
Build a "scroll 3D cards" entrance in plain HTML, CSS, and JavaScript using GSAP and its ScrollTrigger plugin (load both from a CDN, no build step) plus CSS 3D transforms.
Requirements:
- A vertical list of card elements inside a container that sets CSS perspective (for example 1100px) so child rotations produce real foreshortening, with each card given transform-style: preserve-3d.
- For every card, register its own independent gsap.fromTo animation tied to a ScrollTrigger scoped to that specific card element (not one shared trigger for the whole list), so each card animates on its own schedule as it individually enters the viewport.
- Each card's animation must start tilted back (a negative rotateX around 55 degrees), offset downward, and fully transparent, and animate to rotateX 0, no offset, and fully opaque, using only transform and opacity properties (no properties that trigger layout, like top/margin/height).
- Set each card's transformOrigin to the bottom center (50% 100%) so the rotation pivots like a hinged panel standing up from its base, not spinning around its own center.
- Configure each card's ScrollTrigger with scrub enabled (not a one-shot autoplay animation) and a start/end range tied to the card's own position, so the tilt angle is a continuous function of how far the card has scrolled into view and reverses cleanly when the user scrolls back up.
- Do not animate any card via a shared global timeline keyed to overall page scroll — each card's entrance must be driven by its own trigger so cards animate independently as they individually cross into the visible viewport range.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
- 1Add the GSAP CDNsInclude gsap and ScrollTrigger from the CDN panel.
- 2Paste HTML, CSS, and JSA list of cards renders between spacers.
- 3Scroll downEach card flips up from a back-tilt.
- 4Scroll back upCards tilt back — motion is scrubbed.
- 5Change the tiltAdjust the starting rotateX value.
- 6Change the hingeEdit transformOrigin for a different pivot.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
The list container sets perspective: 1100px, which turns each card's rotateX into real foreshortening — the top edge leans away and swings toward you — instead of a flat vertical squash. Each card also uses transform-style: preserve-3d. Without perspective on the parent, a rotateX would just look like the card getting shorter.
A per-card fromTo tied to a trigger on that card lets every card animate independently as it enters the viewport, from start: top 88% to end: top 45%. They flip up one after another as they reach center, rather than all firing together, which is what gives the list its rolling, staggered entrance.
The tween sets transformOrigin: 50% 100%, so the rotateX pivots around the card's base. The card stands up from the bottom like a hinged panel, which is far more convincing than rotating around the center. That single origin property is the difference between flipping up and spinning in place.
With scrub: true the card's angle is a direct function of how far it has scrolled into view, so it is fully reversible and never out of step with the scroll. Slow scrolling reveals the cards slowly and fast scrolling snaps them upright — the motion always matches the user's pace rather than playing on a fixed timeline.
Render the cards, then in a mount effect register ScrollTrigger and loop the card refs to create each scrubbed fromTo (use gsap.context or a scoped selector). Return a cleanup that reverts the context so triggers are removed on unmount. Keep perspective on the list container in CSS; the markup and styles port unchanged.