Backgrounds✨ Premium

Organic Blob

Organic background animated by CSS border-radius morphing and SVG feTurbulence grain — a living blob with zero JavaScript.

SVGAnimationOrganic

You'll get access to the interactive demo with a free account.

This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Backgrounds has 50 effects, including 6 free. Explore the category →

3 usage examples

Home screen — full-screen visual intro for a creative SaaS — Organic Blob example 1

① Home screen — full-screen visual intro for a creative SaaS

WhenThe homepage of a creative tool or SaaS wants a motion-first first impression above the fold, without the weight of a video.
WhyA large centered organic blob creates immediate visual identity — the continuous deformation signals a live, polished product without overwhelming the text, thanks to a scrim.
Settings.ng-blob enlarged to 300–380 px, gradient set to brand colors, animation duration 12 s for a calm feel, feDisplacementMap scale="28" for more pronounced edge ripple.
Portfolio card — organic avatar on a bio page — Organic Blob example 2

② Portfolio card — organic avatar on a bio page

WhenThe About section of a portfolio or personal site wants to replace the classic round profile photo with a more creative signature shape.
WhyThe blob holds attention and creates a memorable effect that a static image cannot replicate — the continuous deformation makes it a visual identity element in its own right.
Settings120 × 120 px, blue-violet gradient (#3b82f6 → #8b5cf6), grain at opacity: 0.3 for more texture, animation at 6 s.
AI indicator — Waiting animation during a generative process — Organic Blob example 3

③ AI indicator — Waiting animation during a generative process

WhenA generative AI interface (text, image, audio) needs visual feedback during the few seconds of computation — without adding to the page’s JS bundle.
WhyThe <code>feDisplacementMap</code> ripples the blob’s edges unpredictably, signalling an active, living process better than a geometric spinner; the whole thing runs in pure CSS/SVG, zero JS.
Settings.ng-blob at 140 px, green-cyan gradient (#10b981 → #06b6d4), animation-duration: 10s for a slow, organic rhythm, feDisplacementMap scale="22" (default value), grain at opacity: 0.2.

How it works

The shape is a plain <div> given a linear gradient background (135°, violet → pink by default) and driven by the CSS animation ngBlobMorph (8 s, ease-in-out, infinite). It cycles through four border-radius configurations with eight independent values each — the classic CSS blob morphing technique. Each keyframe transition produces an asymmetric expansion/contraction that mimics a soft organism in motion, with no JavaScript involved.

A grain texture is layered on top via the ::after pseudo-element: an SVG encoded as a Data URI applies a <feTurbulence type="fractalNoise" baseFrequency="0.7" numOctaves="3"> filter to a full-size rectangle, rendered with mix-blend-mode: overlay at opacity: 0.15. The grain appears embedded in the blob surface without masking the underlying gradient.

The CSS also references an external SVG filter via filter: url(#ng-blob-filter). This filter — declared once in the page inside an invisible <svg> tag — chains an animated <feTurbulence> (transitioning baseFrequency via <animate>) and a <feDisplacementMap scale="22"> that ripples the blob's edges in real time, adding a second layer of organic deformation beyond the CSS morphing.

The effect is entirely driven by the browser's CSS engine and SVG pipeline: zero JavaScript, zero dependencies, zero requestAnimationFrame loop. Performance remains constant regardless of the host page's JS load.

Accessibility

  • prefers-reduced-motion not handled: the ngBlobMorph animation (8 s loop) runs regardless of the system preference. For accessible use, wrap the animation rule inside @media (prefers-reduced-motion: no-preference) { .ng-blob { animation: … } }.
  • The effect is purely decorative — add aria-hidden="true" to .ng-blob-scene and the SVG filter tag so screen readers ignore them entirely.
  • No keyboard interaction: the blob never receives focus and responds to no events. The host page's keyboard navigation is unaffected.
  • Overlaid text: the multicolor gradient can create low-contrast zones. Use a semi-opaque scrim (rgba(0,0,0,.45)) between the blob and text to ensure WCAG AA compliance (ratio ≥ 4.5:1).
  • The effect is 100% CSS/SVG: no script executes — users who block JavaScript see the blob working normally.

Browser compatibility

Requires multi-value CSS border-radius, CSS3 animations, inline SVG, and feDisplacementMap — available in all modern browsers since 2020.

Chrome 110+✓ Full
Firefox 110+✓ Full
Safari 16+✓ Full
Edge 110+✓ Full
Mobile iOS 16+✓ Full
Android Chrome✓ Full

If <code>feDisplacementMap</code> is not supported (extremely rare), the blob displays with CSS morphing and grain only — still animated, just without the SVG edge ripple. No errors, no broken dependencies.

The code

HTML structure to paste into your page (CSS + JS available with a premium account):

index.html — structure
<!-- SVG filter — place once in the page (out of flow) -->
<svg aria-hidden="true" style="position:absolute;width:0;height:0;overflow:hidden">
  <defs>
    <filter id="ng-blob-filter" x="-20%" y="-20%" width="140%" height="140%">
      <feTurbulence type="fractalNoise" baseFrequency="0.012 0.008" numOctaves="3" result="noise">
        <animate attributeName="baseFrequency"
                 values="0.012 0.008;0.016 0.012;0.012 0.008"
                 dur="8s" repeatCount="indefinite"/>
      </feTurbulence>
      <feDisplacementMap in="SourceGraphic" in2="noise" scale="22"
                         xChannelSelector="R" yChannelSelector="G"/>
    </filter>
  </defs>
</svg>

<!-- Blob -->
<div class="ng-blob-scene" aria-hidden="true">
  <div class="ng-blob"></div>
</div>
🔒 Unlock the full code — from €2.99 the first month

Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
background (CSS property on .ng-blob) linear-gradient(135deg, #8b5cf6, #ec4899) Blob colors — replace the two hex values with your brand palette. Accepts any CSS format: radial-gradient, solid color, etc.
width / height (.ng-blob) 160px × 160px Blob dimensions. Scale up to 300–400 px for a full-screen background, down to 80–120 px for a composition element.
animation-duration (animation shorthand on .ng-blob) 8s Morphing speed. 5 s = fast and organic, 14 s = slow and hypnotic.
opacity (::after) 0.15 Grain surface intensity. 0.05 = nearly invisible, 0.35 = pronounced grain with a paper texture feel.
baseFrequency (SVG grain inside .ng-blob::after) 0.7 feTurbulence grain density. Low values (0.3) = coarse grain, high values (1.2) = fine film-like grain.
scale (feDisplacementMap inside #ng-blob-filter) 22 SVG edge distortion intensity. 0 = smooth CSS-only edges, 40 = heavily rippled edges.
border-radius (keyframes ngBlobMorph — 4 steps) see keyframes Morphing shape — edit the 4 sets of border-radius values for rounder, more angular, or more asymmetric motion.

FAQ

The SVG filter #ng-blob-filter must be declared once in your page, inside an <svg aria-hidden="true" style="position:absolute;width:0;height:0"> tag. It holds an animated <feTurbulence> and a <feDisplacementMap> that ripple the blob's edges. Without it, filter: url(#ng-blob-filter) is simply ignored and the blob animates with CSS morphing alone — no error, just without the SVG edge distortion.
Duplicate the .ng-blob div as many times as needed. Add a negative animation-delay (e.g. -3s) to each instance to start mid-loop rather than waiting, and vary animation-duration so shapes don't synchronize. The SVG filter #ng-blob-filter is shared — a single declaration is enough for all instances.
Yes. Add will-change: border-radius, filter to .ng-blob so the browser allocates a dedicated composite layer — CSS morphing and the SVG filter then run on the GPU without repainting the rest of the page. On mobile, reduce the feDisplacementMap scale to 12–15 and the grain baseFrequency to 0.5 to preserve battery life.