06Zoom + Blur

Zoom + Blur

GSAPImmersiveGalleryDepth-of-Field

Depth of field effect known from photography and film. Page 'moves away' and loses focus, new page 'approaches' with focus effect. Ideal for photo galleries and immersive experiences.

Quick Start

  • 📦npm install next-transition-router gsap
  • 📷Combine scale + filter: blur() for depth-of-field
  • 🎯transformOrigin: 'center center' for zoom from center
  • ✨Exit: scale down + blur | Enter: scale from larger + focus

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 ZoomProvider({ children }: { children: React.ReactNode }) {
8 const wrapperRef = useRef<HTMLDivElement>(null)
9
10 return (
11 <TransitionRouter
12 auto
13 leave={(next) => {
14 const tl = gsap.timeline({ onComplete: next })
15 const wrapper = wrapperRef.current
16 const content = wrapper?.querySelectorAll('h1, p, .btn, .demo-badge')
17
18 tl.to(content, {
19 scale: 0.95,
20 opacity: 0,
21 stagger: 0.03,
22 duration: 0.3,
23 ease: 'power2.in',
24 })
25
26 tl.to(wrapper, {
27 scale: 0.92,
28 opacity: 0,
29 filter: 'blur(8px)',
30 duration: 0.4,
31 ease: 'power3.in',
32 }, '-=0.2')
33 }}
34 enter={(next) => {
35 const tl = gsap.timeline({ onComplete: next })
36 const wrapper = wrapperRef.current
37 const content = wrapper?.querySelectorAll('h1, p, .btn, .demo-badge')
38
39 gsap.set(wrapper, { scale: 1.15, opacity: 0, filter: 'blur(12px)' })
40 gsap.set(content, { scale: 1.1, opacity: 0 })
41
42 tl.to(wrapper, {
43 scale: 1,
44 opacity: 1,
45 filter: 'blur(0px)',
46 duration: 0.5,
47 ease: 'power3.out',
48 })
49
50 tl.to(content, {
51 scale: 1,
52 opacity: 1,
53 stagger: 0.05,
54 duration: 0.4,
55 ease: 'power2.out',
56 }, '-=0.3')
57 }}
58 >
59 <div ref={wrapperRef} style={{ transformOrigin: 'center center' }}>
60 {children}
61 </div>
62 </TransitionRouter>
63 )
64}