006

Liquid Morph Hover Effect

£5

A GSAP liquid morph hover effect: images and headlines melt into viscous liquid, then reform. SVG filters, an optional WebGL shader, and a whole-page melt.

ScrollTriggerPixiJS advanced
5 more details
svg-filtersmorphinghover-effectscroll-revealwebgl-shader
Liquid Morph Hover Effect - GSAP animation effect preview

This demo reads better at your own screen size than in the frame below:

About this effect

A viscous liquid distortion effect that melts images, cards and text, then lets them reform. The gallery path uses SVG turbulence and displacement filters, so it works in every modern browser with no WebGL requirement; the headline path adds an optional PixiJS shader for GPU-smooth distortion on display type.

Read the full effect overview

The demo is a studio index: hover any frame and it dissolves along its own axis, or press the melt control and the entire page, shader headline included, flows continuously until you settle it again.

What's included

8 items
  • SVG filter-based distortion that works in all modern browsers
  • Optional PixiJS WebGL shader for display type, with an HTML fallback
  • Hover, tap, focus, scroll-into-view and scroll-scrubbed triggers
  • Per-element intensity, duration, turbulence and axis control
  • data-liquid-trigger-all melts every element at once and mirrors state in aria-pressed
  • Continuous ripple mode driven by layered sine waves on the GSAP ticker
  • Asymmetric timing (fast to distort, slow to reform) so it reads as viscous
  • Degrades to static, visible images if GSAP or ScrollTrigger fails to load

Perfect for

5 use cases
  • Creative agency portfolio image hovers
  • Product reveal animations on e-commerce sites
  • Artistic hero sections with liquid transitions
  • Gallery items with fluid hover interactions
  • Experimental typography and headline effects

How it works

2 sections

Every morphing element gets its own SVG filter: an feTurbulence node generates fractal noise, and an feDisplacementMap pushes the element's pixels along it. GSAP animates the turbulence baseFrequency and the displacement scale, and the xChannelSelector / yChannelSelector pair decides whether the distortion runs horizontally, vertically or on both axes.

Continuous ripple runs on the GSAP ticker instead of a tween, offsetting frequency and scale with three sine waves at different rates so the flow never visibly loops. The WebGL path swaps that for a PixiJS DisplacementFilter driven by a generated value-noise texture, which the ticker drifts across the type.

Plugins ScrollTrigger, PixiJS
Difficulty Advanced
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Lighthouse, as measured

Google Lighthouse on this effect's demo, 15 September 2026. A measurement of the demo as shipped, not a promise for your page.

Accessibility
100
Best practices
100

No performance score, on purpose. That figure depends on how you deploy: your server's compression and caching, your CDN, the connection and the device doing the test, none of which the code controls. The same page can score very differently on two consecutive runs, so measure it where it will live.

Paid effect

Purchase to unlock the code.

Buying Liquid Morph Hover Effect opens the HTML, CSS and JavaScript source, the full documentation, an AI setup prompt for your editor, and every update we ship to it. Standard license: unlimited personal and commercial projects.

£5 Standard license, unlimited projects

Browse free effects

Documentation

Quick Start

1. Add to your HTML <head>:

Code snippet omitted: it ships with the download.

2. Add before closing </body> tag:

Code snippet omitted: it ships with the download.

3. Add the effect HTML anywhere in your <body>:

Code snippet omitted: it ships with the download.

Optional: Add an empty SVG container for filters (created automatically if missing):

Code snippet omitted: it ships with the download.

Using It With Your Own Design

What the effect requires of your markup: an element with the class liquid-morph. That is the whole contract. The filter is applied to that element, so whatever is inside it — an image, a card, a heading, a whole grid — distorts as one. Nothing inside is queried by name, and no particular child structure is expected.

What is only the demo's CSS. Everything under "Studio index composition" in style.css, plus .showcase-*, .melt-button and .index-*, is dressing for the demo page. Delete it. What the effect needs from the stylesheet is:

  • .svg-filters — must be present and take no space (position: absolute; width: 0; height: 0). If it is missing entirely the script creates its own, but if it is present and visible you get a stray empty box on the page.
  • .liquid-morph { position: relative; overflow: hidden }overflow: hidden is what keeps the distorted edges inside the frame's rounded corners. Drop it and the melt spills past the border radius, which is a look worth having but should be a decision.
  • The .liquid-morph-js .liquid-morph[data-trigger="scroll"] { opacity: 0 } pre-hide gate and its .liquid-morph--revealed release. The gate is scoped to a class the script only adds once GSAP and ScrollTrigger are both present, so a CDN failure leaves your images visible instead of blank. Keep both halves or neither.

The non-obvious parts:

  • The filter region is -20% to 140% of the element box. At high data-intensity the displacement can reach past that and clip; lower the intensity or widen the filter's x/y/width/height in createFilter.
  • The effect makes hover elements focusable (tabindex="0", role="button") and adds its own aria-label if you have not set one. Set a better one.
  • On coarse pointers, hover elements become tap-to-toggle. There is no hover-only dead end.
  • The WebGL headline is a separate optional script. .liquid-title needs both a .liquid-title__text child and a .liquid-title__canvas child, and the container should be width: fit-content so the canvas centres over the word rather than over the whole column.

Options

Attribute Values Default Description
data-trigger hover, scroll, auto hover What triggers the distortion effect
data-intensity 0.1 - 1 0.5 Distortion strength (higher = more warping)
data-direction horizontal, vertical, both both Axis of distortion movement
data-duration seconds 0.8 Animation duration
data-turbulence 0.01 - 0.1 0.03 Noise frequency (lower = larger waves)
data-infinite true, false false Continuous rippling while hovering (hover trigger only)
data-scrub true, false false Tie animation to scroll position (scroll trigger only)
data-repeat true, false true Replay animation when scrolling back (scroll trigger only)

How It Works

The effect uses SVG filters with two primitives:

  1. feTurbulence - Generates fractal noise pattern
  2. feDisplacementMap - Uses the noise to displace pixels

GSAP animates the filter attributes:

  • baseFrequency on turbulence (controls wave size)
  • scale on displacement (controls distortion amount)

Each element gets its own unique filter to avoid conflicts.

Accessibility

  • Reduced motion: Effect is completely disabled for users who prefer reduced motion. Images display normally without filters.
  • Keyboard navigation:
    • Tab to focus on interactive elements
    • Focus triggers the morph effect (same as hover)
    • Press Enter or Space to toggle the effect on/off
    • Effect resets when focus leaves the element
  • Focus visible: Clear accent outline ring when navigating with keyboard
  • ARIA support: Interactive elements have role="button" and descriptive aria-label
  • Touch devices: Tap to toggle the distortion effect

Browser Support

Works in all modern browsers that support SVG filters:

  • Chrome 49+
  • Firefox 52+
  • Safari 10.1+
  • Edge 79+

Falls back gracefully in older browsers (images display normally).

Performance Notes

  • Each element creates its own SVG filter (necessary for independent animation)
  • Filters are removed from DOM on cleanup
  • Scroll-triggered elements only animate once (no repeated processing)
  • Use data-intensity values below 0.8 for smoother performance on mobile

Demo Images

The 18 photographs on the demo page ship bundled in assets/img/ as optimised WebP derivatives. Nothing is hotlinked, so the demo keeps working offline, behind a firewall, and after any third party reorganises their CDN. Total image weight is about 249 KB across 18 files, with the largest single file around 46 KB.

These are placeholder images for the demo only. The effect itself has no opinion about your images: it reads whatever <img> you put inside .liquid-morph and applies the SVG displacement filter to the container.

How the effect uses them

Plain <img> elements, nothing more. The distortion is an SVG feTurbulence + feDisplacementMap filter applied to the wrapping .liquid-morph element via style.filter = url(#...), so the images are never uploaded as WebGL or canvas textures and their format, dimensions, and colour profile do not affect the animation. The PixiJS path (see below) renders text only and does not touch these files. Any format the browser can decode works, WebP included.

Each image is sized to the box it fills: 400×500 for the 280×350 row tiles and 400×400 for the square grid tiles, giving roughly 1.4× for high-density screens. Every one carries alt, width, height, and loading="lazy", and .liquid-morph has a background beneath the photo, so a missing or still-loading file shows the surface colour rather than a white hole.

Files

Files Used by
img/hover-01…03.webp Example 02, basic hover distortion (400×500)
img/scrub-01…03.webp Example 03, scroll-scrubbed reveal (400×500)
img/intensity-01…03.webp Example 04, intensity variations (400×500)
img/direction-01…03.webp Example 05, direction control (400×500)
img/grid-01…06.webp Example 06, gallery grid with stagger (400×400)

Swapping a photograph

Drop your own file in. Replace the matching file in assets/img/ keeping the same filename and roughly the same aspect ratio (4:5 for the row tiles, 1:1 for the grid tiles). Nothing else needs editing. Or point the src in index.html at any path you like: the effect only needs an <img> inside .liquid-morph.

The grade is baked into the pixels, not applied with a CSS filter, so there is no filter declaration to fight when you drop your own pictures in. (The only filter on these elements is the displacement filter the script sets at runtime.)

assets/img-manifest.json records the source URL, output name, dimensions, WebP quality, and grade for every image, so the set can be regenerated from source. It is kept for provenance and future regeneration; the build script that consumes it is part of the GSAP Vault repository and is not included in your download, so regenerating from the manifest is not something you can run as a buyer. Replacing the files directly, as above, is the supported route.

The baked grade is a light uniform treatment (saturation 0.95, gamma 1.02), deliberately restrained: these images exist to demonstrate a geometric distortion, so anything heavier would have restyled the demo rather than art-directed it.

Credits

Placeholder photographs are royalty-free images from Unsplash, used here as altered, art-directed derivatives (cropped, downscaled, graded, and re-encoded). Replace them with your own imagery before launch.

WebGL Liquid Title (Optional)

For silky smooth 60fps liquid animation on text, use the WebGL shader approach with PixiJS.

Setup

Add before closing </body> tag:

Code snippet omitted: it ships with the download.

Usage

HTML: Code snippet omitted: it ships with the download.

How It Works

  1. Creates a PixiJS WebGL canvas over the text
  2. Renders matching text with displacement filter
  3. Animates a noise texture position for smooth fluid motion
  4. GPU-accelerated - runs at 60fps without frame drops

CSS Required

CSS: Code snippet omitted: it ships with the download.

The original <h1> remains in the DOM (visually hidden) for accessibility and SEO. The canvas word is drawn in the <h1>'s own computed font family, size and --accent, so restyling the heading in CSS restyles the shader text with it.

Dependencies

  • GSAP 3.12+
  • ScrollTrigger plugin (only needed for data-trigger="scroll")
  • PixiJS 8.x (only needed for WebGL liquid title)

Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.

Your cart

Your cart is empty

The Vault £99

The Vault library, plus future additions to the library.