15Liquid Morph

Liquid Morph

GSAPSVGOrganicArtistic

Organic flowing transition using SVG displacement filters. Content melts and reforms creating a surreal, dream-like effect. Perfect for artistic experiences.

Quick Start

  • 📦npm install next-transition-router gsap
  • 🌊SVG feTurbulence + feDisplacementMap
  • 🎚️Animate scale attribute: 0 → 50 → 0
  • ✨Creates organic, fluid distortion effect

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 LiquidProvider({ children }: { children: React.ReactNode }) {
8 const wrapperRef = useRef<HTMLDivElement>(null)
9 const overlayRef = useRef<HTMLDivElement>(null)
10
11 return (
12 <>
13 {/* SVG Filter for liquid effect */}
14 <svg style={{ position: 'absolute', width: 0, height: 0 }}>
15 <defs>
16 <filter id="liquid-filter">
17 <feTurbulence
18 type="fractalNoise"
19 baseFrequency="0.01"
20 numOctaves="1"
21 result="noise"
22 />
23 <feDisplacementMap
24 in="SourceGraphic"
25 in2="noise"
26 scale="0"
27 xChannelSelector="R"
28 yChannelSelector="G"
29 />
30 </filter>
31 </defs>
32 </svg>
33
34 <TransitionRouter
35 auto
36 leave={(next) => {
37 const tl = gsap.timeline({ onComplete: next })
38 const displacementMap = document.querySelector('#liquid-filter feDisplacementMap')
39
40 // Animate displacement for liquid distortion
41 tl.to(displacementMap, {
42 attr: { scale: 50 },
43 duration: 0.4,
44 ease: 'power2.in',
45 })
46
47 tl.to(overlayRef.current, {
48 opacity: 1,
49 duration: 0.3,
50 }, '-=0.2')
51 }}
52 enter={(next) => {
53 const tl = gsap.timeline({ onComplete: next })
54 const displacementMap = document.querySelector('#liquid-filter feDisplacementMap')
55
56 gsap.set(displacementMap, { attr: { scale: 50 } })
57
58 tl.to(overlayRef.current, {
59 opacity: 0,
60 duration: 0.3,
61 })
62
63 tl.to(displacementMap, {
64 attr: { scale: 0 },
65 duration: 0.4,
66 ease: 'power2.out',
67 }, '-=0.2')
68 }}
69 >
70 <div ref={wrapperRef} style={{ filter: 'url(#liquid-filter)' }}>
71 {children}
72 </div>
73 </TransitionRouter>
74
75 <div ref={overlayRef} style={{
76 position: 'fixed',
77 inset: 0,
78 background: '#0a0a0a',
79 zIndex: 9999,
80 opacity: 0,
81 pointerEvents: 'none',
82 }} />
83 </>
84 )
85}