Wensity Labs

Morphing Shape Background

Heroes

About

An animated blob background where soft gradient shapes morph and drift like a lava lamp, with optional film grain. Drop it behind hero sections, landing pages and auth screens.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Morphing Shape Background to your project and fits it to your theme.

Code

How Morphing Shape Background is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

"use client";

import * as React from "react";
import { MorphingShapeBackground, type MorphingShapeBlob } from "@/components/ui/morphing-shape-background";

const PREVIEW_MATTE_NOISE = `url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.65 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>")`;

/* ───────────────────────── Morphing Shape Background, playground ──────────
 * Lava-lamp blobs are synthesised on the fly from a palette + count + scale
 * + speed, so users can sweep across totally different moods (chili → violet
 * → emerald) without every prop needing its own slider.
 * ────────────────────────────────────────────────────────────────────────── */

type PaletteId =
  | "chili"
  | "violet"
  | "sky"
  | "emerald"
  | "amber"
  | "mono";

interface MorphingState {
  palette: PaletteId;
  blobCount: number;
  scale: number; // 0..2 multiplier on blob size
  speedFactor: number; // 0.4..2 inverse multiplier on duration
  blur: number; // 30..140
  grain: boolean;
}

const settings = {
  palette: "chili",
  blobCount: 4,
  scale: 1,
  speedFactor: 1,
  blur: 80,
  grain: true,
};

/* Palette gradients, each entry is paired (start, end) so blobs read as
 * "atmospheric depth" rather than flat slabs. Ordered loosely warm → cool. */
const PALETTES: Record<
  PaletteId,
  { name: string; gradients: string[]; swatch: string }
> = {
  chili: {
    name: "Wensity Red",
    swatch: "linear-gradient(135deg, #cd1c18, #ff8a73)",
    gradients: [
      "linear-gradient(135deg, #cd1c18 0%, #ff8a73 100%)",
      "linear-gradient(135deg, #9b1313 0%, #38000a 100%)",
      "linear-gradient(135deg, #ff8a73 0%, #ffe2db 100%)",
      "linear-gradient(135deg, #ffa896 0%, #cd1c18 100%)",
    ],
  },
  violet: {
    name: "Violet",
    swatch: "linear-gradient(135deg, #4c1d95, #a78bfa)",
    gradients: [
      "linear-gradient(135deg, #6d28d9 0%, #c4b5fd 100%)",
      "linear-gradient(135deg, #4c1d95 0%, #1e1b4b 100%)",
      "linear-gradient(135deg, #a78bfa 0%, #ede9fe 100%)",
      "linear-gradient(135deg, #7c3aed 0%, #4c1d95 100%)",
    ],
  },
  sky: {
    name: "Sky",
    swatch: "linear-gradient(135deg, #0369a1, #7dd3fc)",
    gradients: [
      "linear-gradient(135deg, #0284c7 0%, #7dd3fc 100%)",
      "linear-gradient(135deg, #0c4a6e 0%, #082f49 100%)",
      "linear-gradient(135deg, #38bdf8 0%, #e0f2fe 100%)",
      "linear-gradient(135deg, #0ea5e9 0%, #0369a1 100%)",
    ],
  },
  emerald: {
    name: "Emerald",
    swatch: "linear-gradient(135deg, #047857, #6ee7b7)",
    gradients: [
      "linear-gradient(135deg, #059669 0%, #6ee7b7 100%)",
      "linear-gradient(135deg, #064e3b 0%, #022c22 100%)",
      "linear-gradient(135deg, #34d399 0%, #d1fae5 100%)",
      "linear-gradient(135deg, #10b981 0%, #047857 100%)",
    ],
  },
  amber: {
    name: "Amber",
    swatch: "linear-gradient(135deg, #b45309, #fcd34d)",
    gradients: [
      "linear-gradient(135deg, #d97706 0%, #fcd34d 100%)",
      "linear-gradient(135deg, #92400e 0%, #451a03 100%)",
      "linear-gradient(135deg, #f59e0b 0%, #fef3c7 100%)",
      "linear-gradient(135deg, #fbbf24 0%, #b45309 100%)",
    ],
  },
  mono: {
    name: "Mono",
    swatch: "linear-gradient(135deg, #1f2937, #6b7280)",
    gradients: [
      "linear-gradient(135deg, #374151 0%, #9ca3af 100%)",
      "linear-gradient(135deg, #111827 0%, #030712 100%)",
      "linear-gradient(135deg, #6b7280 0%, #f3f4f6 100%)",
      "linear-gradient(135deg, #4b5563 0%, #1f2937 100%)",
    ],
  },
};

/* Layout templates, anchor positions, opacity, durations. These never
 * change with the palette so the user gets a consistent "rhythm" across
 * palette swaps. */
const BLOB_TEMPLATES: ReadonlyArray<
  Omit<MorphingShapeBlob, "color"> & { sizeBase: number }
> = [
  { sizeBase: 0.85, top: 10, left: 8, blur: 80, opacity: 0.55, duration: 28 },
  { sizeBase: 0.7, top: 35, left: 55, blur: 90, opacity: 0.6, duration: 36, reverse: true, delay: -8 },
  { sizeBase: 0.55, top: 60, left: 20, blur: 70, opacity: 0.4, duration: 32, delay: -14 },
  { sizeBase: 0.45, top: 5, left: 65, blur: 60, opacity: 0.45, duration: 24, reverse: true, delay: -4 },
  { sizeBase: 0.6, top: 45, left: 78, blur: 75, opacity: 0.42, duration: 30, delay: -10 },
  { sizeBase: 0.5, top: 78, left: 70, blur: 65, opacity: 0.38, duration: 26, reverse: true, delay: -2 },
];

function buildBlobs(state: MorphingState): MorphingShapeBlob[] {
  const palette = PALETTES[state.palette];
  const count = Math.min(Math.max(state.blobCount, 1), BLOB_TEMPLATES.length);
  return BLOB_TEMPLATES.slice(0, count).map((tpl, i) => ({
    color: palette.gradients[i % palette.gradients.length],
    size: (tpl.sizeBase ?? 0.7) * state.scale,
    top: tpl.top,
    left: tpl.left,
    blur: state.blur,
    opacity: tpl.opacity,
    duration: (tpl.duration ?? 30) / state.speedFactor,
    delay: tpl.delay,
    reverse: tpl.reverse,
  }));
}

/* ───────────────────────── Preview ───────────────────────── */

export function MorphingShapeBackgroundPreview(props: Partial<typeof settings> = {}) {
  const state = { ...settings, ...props };
  const blobs = React.useMemo(() => buildBlobs(state), [state]);

  return (
    <div className="relative isolate w-full max-w-6xl overflow-hidden rounded-[1.35rem] border border-black/[0.08] bg-[radial-gradient(ellipse_90%_70%_at_50%_-10%,#ffffff_0%,#f4f4f5_72%)] shadow-[0_1px_2px_rgba(0,0,0,.06),0_18px_46px_-28px_rgba(0,0,0,.26)] dark:border-white/[0.06] dark:bg-[radial-gradient(ellipse_90%_70%_at_50%_-10%,#15151b_0%,#0a0a0b_72%)] dark:shadow-[0_1px_2px_rgba(0,0,0,.4),0_18px_46px_-28px_rgba(0,0,0,.72)]">
      <div
        aria-hidden
        className="pointer-events-none absolute inset-0 opacity-[0.04] mix-blend-overlay dark:opacity-[0.055]"
        style={{ backgroundImage: PREVIEW_MATTE_NOISE, backgroundSize: "240px 240px" }}
      />
      <div
        aria-hidden
        className="pointer-events-none absolute inset-0 bg-[linear-gradient(to_bottom,rgba(0,0,0,0.035)_0%,transparent_28%,transparent_74%,rgba(0,0,0,0.06)_100%)] dark:bg-[linear-gradient(to_bottom,rgba(0,0,0,0.18)_0%,transparent_26%,transparent_74%,rgba(0,0,0,0.32)_100%)]"
      />
      <MorphingShapeBackground
        blobs={blobs}
        grain={state.grain}
        className="relative h-[600px]"
      >
        <div className="flex h-[600px] flex-col items-center justify-center gap-4 px-8 text-center">
          <h2 className="font-display text-5xl font-extrabold leading-[1.02] tracking-tight text-white sm:text-6xl">
            Wensity<span className="ml-1 inline-block h-2.5 w-2.5 self-end bg-red-600 align-baseline" />
          </h2>
          <p className="max-w-md text-[14px] leading-relaxed text-white/75">
            Blobs morph their border-radius and rotate slowly. Grain on top kills banding and adds matte texture.
          </p>
        </div>
      </MorphingShapeBackground>
    </div>
  );
}

/* ───────────────────────── Controls ───────────────────────── */

/* ───────────────────────── Hero variant ───────────────────────── */

export default function Demo(props: Partial<typeof settings>) {
  return <MorphingShapeBackgroundPreview {...props} />;
}

Dependencies

More by Wensity Labs

View all
  • Sidebar

    Sidebar

    235
  • Calendar

    Calendar

    173
  • Button

    Button

    76
  • Color Picker

    Color Picker

    64
  • Image Comparison Slider

    Image Comparison Slider

    55
  • AI Prompt Input

    AI Prompt Input

    50
  • Text Morphing

    Text Morphing

    37
  • Navigation Menu

    Navigation Menu

    36

More in Heroes

View all
  • SaaS Template

    SaaS Template

    2.4K
  • Responsive Hero Banner

    Responsive Hero Banner

    2K
  • Hero

    Hero

    1.2K
  • Centered Hero with Image Fan

    Centered Hero with Image Fan

    931
  • Editorial Collage Hero

    Editorial Collage Hero

    430
  • Glass Fold

    Glass Fold

    212
  • Minimalist Hero Fashion

    Minimalist Hero Fashion

    285
  • HeroSectionWithGradient

    HeroSectionWithGradient

    336