Liquid Ripple Image
A liquid image hover effect: dragging the cursor over an image distorts the pixels like water, rippling from the pointer and settling back to a crisp, calm pool.
About This Effect
A liquid distortion effect that turns any image into water under the cursor. An inline SVG feTurbulence and feDisplacementMap warp the pixels, and GSAP feeds the filter from pointer velocity, so a slow drag ripples gently while a fast flick spikes a big watery splash.
The disturbance eases back to a perfectly crisp rest with no snap, and a cyan glow tracks the pointer so the ripple reads localised over a global displacement. The filter is wired up only by JavaScript, so with no script or under reduced motion the image renders sharp and undistorted.
What's Included
- SVG feTurbulence + feDisplacementMap distortion driven entirely by GSAP, no canvas or WebGL
- Displacement scale tracks cursor speed: slow drag ripples softly, fast flick spikes a splash
- Turbulence baseFrequency shifts under speed so the ripple texture gets busier as you move faster
- Pointer-tracking cyan glow and a subtle image swell layer over the same input for depth
- Smooth power-style settle back to a crisp scale-zero rest, so calm and disturbed read as opposites
- Pointer events cover mouse, pen and touch; a tap drops a one-shot splash that calms on its own
- Filter is gated behind JavaScript, so no-JS and reduced-motion visitors get the sharp original image
- Data-attribute config for splash strength, resting frequency, gain and an optional idle micro-ripple
Perfect For
- Hero and portfolio images that reward the visitor for touching them
- Product or artwork showcases where a tactile, watery hover adds a premium feel
- Photography and agency sites wanting an award-style interaction on a single key image
- Landing-page feature images that invite play with a clear "drag to ripple" prompt
- Event or music pages where a liquid, reactive visual matches the mood
How It Works
An inline SVG filter pairs feTurbulence (fractalNoise) with a feDisplacementMap whose scale attribute starts at zero, so the image is crisp until JavaScript runs. Pointer velocity is measured on pointermove and fed into a decaying energy value; a GSAP ticker writes that value onto the displacement scale and the turbulence baseFrequency each frame with setAttribute, never rebuilding the filter.
The energy decays smoothly toward zero so the water calms rather than snapping, a tap injects a one-shot impulse, and gsap.matchMedia skips the whole wiring under reduced motion so the un-filtered image is the fallback.