Flow

Effects / CSS

Liquid morph

A soft gradient blob that slowly wobbles and reshapes like a drop of liquid.

Prompt to build it

Build a liquid morph blob: a violet-to-blue gradient shape whose outline keeps reshaping organically. Animate an 8-value border-radius through 4 keyframes over ~8s with ease-in-out, rotate slowly, and add a subtle inner highlight. Make it responsive, cap devicePixelRatio at 2, pause when off-screen, and show a still frame when prefers-reduced-motion is set. No external libraries.

Tested code

One self-contained HTML file with no libraries: the same code that runs above. Your AI gets it from Flow's get_effect tool.

Show the code
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Liquid morph | Flow effect</title> <!-- Flow effect: Liquid morph (https://flow.donta.io/effects/liquid-morph) Self-contained: no libraries. Copy the .fx-stage element, the CSS and the script into your project and size .fx-stage however you like. --> <style> :root { --display: "Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif; --body: ui-sans-serif, system-ui, sans-serif; } html, body { margin: 0; min-height: 100%; background: #0e0e10; display: grid; place-items: center; } .fx-stage { width: min(100vw, 960px); } /* Stage that every effect fills. Container units (cqw/cqmin) size the art. */ .fx-stage { position: relative; aspect-ratio: 4 / 3; overflow: hidden; border-radius: 16px; container-type: size; background: #111; isolation: isolate; } .fx-fill { position: absolute; inset: 0; } .fx-fallback { position: absolute; inset: 0; } .fx-center { display: grid; place-items: center; } /* ── Liquid morph ─────────────────────────────── */ .fx-liquid { background: radial-gradient(circle at 50% 60%, #1d1438, #0b0816 70%); } .fx-liquid i { width: 52cqmin; aspect-ratio: 1; background: linear-gradient(135deg, #d36bff, #7a5cff 55%, #4f8dff); border-radius: 42% 58% 63% 37% / 41% 44% 56% 59%; animation: fx-morph 9s ease-in-out infinite, fx-spin 24s linear infinite; box-shadow: inset -6cqmin -6cqmin 12cqmin rgba(40, 0, 90, 0.35), inset 4cqmin 4cqmin 8cqmin rgba(255, 255, 255, 0.25), 0 0 14cqmin rgba(160, 90, 255, 0.35); } @keyframes fx-morph { 0%, 100% { border-radius: 42% 58% 63% 37% / 41% 44% 56% 59%; } 25% { border-radius: 63% 37% 41% 59% / 58% 34% 66% 42%; } 50% { border-radius: 36% 64% 52% 48% / 66% 56% 44% 34%; } 75% { border-radius: 55% 45% 32% 68% / 39% 63% 37% 61%; } } @keyframes fx-spin { to { rotate: 360deg; } } @media (prefers-reduced-motion: reduce) { .fx-stage *, .fx-stage *::before, .fx-stage *::after { animation-play-state: paused !important; } } </style> </head> <body> <div class="fx-stage"> <div class="fx-fill fx-center fx-liquid"><i></i></div> </div> </body> </html>

How it works

Animate an element's eight-value border-radius between several organic shapes while slowly rotating it, with a two-color gradient fill and a light blur for softness.

Guardrails

  • Keep the cycle slow (6s or more); fast morphing reads as nervous.
  • Respect prefers-reduced-motion: show a still frame instead of the animation.
  • Pause when off-screen or when the tab is hidden (IntersectionObserver + visibilitychange).
  • Keep text off busy animated areas, or give it a solid backing that passes WCAG contrast.
  • One showpiece effect per page. If everything moves, nothing stands out.