Terminal
1npm install next-transition-router gsap
Theatrical curtain effect. Two panels close from the sides, covering content, then open to reveal the new page. Dramatic effect ideal for events and product launches.
npm install next-transition-router gsapposition: fixed'<' marker for synchronized curtain movement1npm install next-transition-router gsap
1'use client'23import { useRef } from 'react'4import { TransitionRouter } from 'next-transition-router'5import gsap from 'gsap'67export default function CurtainProvider({ children }: { children: React.ReactNode }) {8 const leftCurtainRef = useRef<HTMLDivElement>(null)9 const rightCurtainRef = useRef<HTMLDivElement>(null)10 const wrapperRef = useRef<HTMLDivElement>(null)1112 return (13 <>14 <TransitionRouter15 auto16 leave={(next) => {17 const tl = gsap.timeline({ onComplete: next })18 const content = wrapperRef.current?.querySelectorAll('h1, p, .btn, .demo-badge')1920 // Content fades first21 tl.to(content, {22 opacity: 0,23 scale: 0.95,24 stagger: 0.03,25 duration: 0.25,26 ease: 'power2.in',27 })2829 // Curtains close from sides30 tl.to(leftCurtainRef.current, {31 x: '0%',32 duration: 0.45,33 ease: 'power4.inOut',34 }, '-=0.1')35 tl.to(rightCurtainRef.current, {36 x: '0%',37 duration: 0.45,38 ease: 'power4.inOut',39 }, '<') // '<' = start at same time40 }}41 enter={(next) => {42 const tl = gsap.timeline({ onComplete: next })43 const content = wrapperRef.current?.querySelectorAll('h1, p, .btn, .demo-badge')4445 // Set initial content state46 gsap.set(content, { opacity: 0, scale: 0.95, y: 30 })4748 // Curtains open49 tl.to(leftCurtainRef.current, {50 x: '-100%',51 duration: 0.5,52 ease: 'power4.inOut',53 })54 tl.to(rightCurtainRef.current, {55 x: '100%',56 duration: 0.5,57 ease: 'power4.inOut',58 }, '<')5960 // Content reveals61 tl.to(content, {62 opacity: 1,63 scale: 1,64 y: 0,65 stagger: 0.06,66 duration: 0.45,67 ease: 'power3.out',68 }, '-=0.25')69 }}70 >71 <div ref={wrapperRef}>{children}</div>72 </TransitionRouter>7374 {/* Left Curtain */}75 <div76 ref={leftCurtainRef}77 style={{78 position: 'fixed',79 top: 0,80 left: 0,81 width: '50%',82 height: '100%',83 background: '#0a0a0a',84 zIndex: 9999,85 transform: 'translateX(-100%)',86 }}87 />8889 {/* Right Curtain */}90 <div91 ref={rightCurtainRef}92 style={{93 position: 'fixed',94 top: 0,95 right: 0,96 width: '50%',97 height: '100%',98 background: '#0a0a0a',99 zIndex: 9999,100 transform: 'translateX(100%)',101 }}102 />103 </>104 )105}