Terminal
1npm install next-transition-router gsap
Morphing effect using CSS clip-path. Overlay expands as a circle from the center of the screen, covering the page, then shrinks to reveal new content. Portal effect.
npm install next-transition-router gsapclip-path: circle() for circular mask150% radius ensures full coverage on all screens1npm 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 MorphProvider({ children }: { children: React.ReactNode }) {8 const overlayRef = useRef<HTMLDivElement>(null)9 const wrapperRef = useRef<HTMLDivElement>(null)1011 return (12 <>13 <TransitionRouter14 auto15 leave={(next) => {16 const tl = gsap.timeline({ onComplete: next })17 const content = wrapperRef.current?.querySelectorAll('h1, p, .btn, .demo-badge')1819 // Content scales down toward center20 tl.to(content, {21 scale: 0.9,22 opacity: 0,23 stagger: 0.03,24 duration: 0.3,25 ease: 'power2.in',26 })2728 // Circle morph expands from center29 tl.fromTo(30 overlayRef.current,31 { clipPath: 'circle(0% at 50% 50%)' },32 {33 clipPath: 'circle(150% at 50% 50%)',34 duration: 0.6,35 ease: 'power4.inOut',36 },37 '-=0.15'38 )39 }}40 enter={(next) => {41 const tl = gsap.timeline({ onComplete: next })42 const content = wrapperRef.current?.querySelectorAll('h1, p, .btn, .demo-badge')4344 // Set initial states45 gsap.set(content, { scale: 0.9, opacity: 0 })4647 // Circle morph shrinks to reveal48 tl.fromTo(49 overlayRef.current,50 { clipPath: 'circle(150% at 50% 50%)' },51 {52 clipPath: 'circle(0% at 50% 50%)',53 duration: 0.6,54 ease: 'power4.inOut',55 }56 )5758 // Content scales up and fades in59 tl.to(content, {60 scale: 1,61 opacity: 1,62 stagger: 0.05,63 duration: 0.45,64 ease: 'power3.out',65 }, '-=0.25')66 }}67 >68 <div ref={wrapperRef}>{children}</div>69 </TransitionRouter>7071 <div72 ref={overlayRef}73 style={{74 position: 'fixed',75 inset: 0,76 background: '#0a0a0a',77 zIndex: 9999,78 clipPath: 'circle(0% at 50% 50%)',79 }}80 />81 </>82 )83}