073D Flip

3D Flip

GSAP3DPlayfulPerspective

3D rotation effect around the Y-axis using CSS perspective. Page 'rotates' like a card, revealing new content. Ideal for flashcards, quizzes, and before/after comparisons.

Quick Start

  • 📦npm install next-transition-router gsap
  • 🃏Wrap in container with perspective: 1500px
  • 🔄Use rotateY for horizontal card flip
  • ✨transformStyle: 'preserve-3d' for child depth

Installation

Terminal
1npm install next-transition-router gsap

Provider Setup

app/providers.tsx
1'use client'
2
3import { useRef } from 'react'
4import { TransitionRouter } from 'next-transition-router'
5import gsap from 'gsap'
6
7export default function FlipProvider({ children }: { children: React.ReactNode }) {
8 const wrapperRef = useRef<HTMLDivElement>(null)
9
10 return (
11 <div style={{ perspective: '1500px', perspectiveOrigin: 'center center' }}>
12 <TransitionRouter
13 auto
14 leave={(next) => {
15 const tl = gsap.timeline({ onComplete: next })
16 const wrapper = wrapperRef.current
17 const content = wrapper?.querySelectorAll('h1, p, .btn, .demo-badge')
18
19 tl.to(content, {
20 opacity: 0,
21 rotateY: -10,
22 z: -50,
23 stagger: 0.03,
24 duration: 0.3,
25 ease: 'power2.in',
26 })
27
28 tl.to(wrapper, {
29 rotateY: -95,
30 scale: 0.95,
31 opacity: 0,
32 duration: 0.5,
33 ease: 'power4.in',
34 transformOrigin: 'center center',
35 }, '-=0.15')
36 }}
37 enter={(next) => {
38 const tl = gsap.timeline({ onComplete: next })
39 const wrapper = wrapperRef.current
40 const content = wrapper?.querySelectorAll('h1, p, .btn, .demo-badge')
41
42 gsap.set(wrapper, { rotateY: 95, scale: 0.95, opacity: 0 })
43 gsap.set(content, { opacity: 0, rotateY: 15, z: -30 })
44
45 tl.to(wrapper, {
46 rotateY: 0,
47 scale: 1,
48 opacity: 1,
49 duration: 0.55,
50 ease: 'power4.out',
51 transformOrigin: 'center center',
52 })
53
54 tl.to(content, {
55 opacity: 1,
56 rotateY: 0,
57 z: 0,
58 stagger: 0.05,
59 duration: 0.4,
60 ease: 'power3.out',
61 }, '-=0.3')
62 }}
63 >
64 <div ref={wrapperRef} style={{ transformStyle: 'preserve-3d' }}>
65 {children}
66 </div>
67 </TransitionRouter>
68 </div>
69 )
70}