Gradient Mesh Background

Organic, slowly morphing color blobs that blend like oil paint

backgroundgradientmeshanimationorganic
Install dependencies
$npm install framer-motion
Preview

Source Code

"use client";

import { motion } from "framer-motion";

interface GradientMeshBackgroundProps {
  children?: React.ReactNode;
  colors?: string[];
  className?: string;
}

const blobAnimations = [
  {
    x: ["-10%", "30%", "10%", "-10%"],
    y: ["-10%", "20%", "-15%", "-10%"],
    scale: [1, 1.2, 0.9, 1],
  },
  {
    x: ["60%", "20%", "50%", "60%"],
    y: ["10%", "-20%", "30%", "10%"],
    scale: [1.1, 0.8, 1.15, 1.1],
  },
  {
    x: ["30%", "-10%", "40%", "30%"],
    y: ["50%", "30%", "10%", "50%"],
    scale: [0.9, 1.3, 1, 0.9],
  },
  {
    x: ["-20%", "50%", "0%", "-20%"],
    y: ["30%", "60%", "20%", "30%"],
    scale: [1.2, 0.9, 1.1, 1.2],
  },
];

export default function GradientMeshBackground({
  children,
  colors = ["#06b6d4", "#7c3aed", "#f43f5e", "#34d399"],
  className = "",
}: GradientMeshBackgroundProps) {
  return (
    <div className={`relative overflow-hidden bg-[#050510] ${className}`}>
      <div className="absolute inset-0" style={{ filter: "blur(90px) saturate(1.8)" }}>
        {colors.map((color, i) => (
          <motion.div
            key={i}
            animate={blobAnimations[i % blobAnimations.length]}
            transition={{
              duration: 12 + i * 3,
              repeat: Infinity,
              ease: "easeInOut",
            }}
            className="absolute h-[60%] w-[60%] rounded-full opacity-70"
            style={{
              background: `radial-gradient(circle, ${color} 0%, transparent 70%)`,
            }}
          />
        ))}
      </div>
      <div className="absolute inset-0 bg-[#050510]/10" />
      <div className="relative z-10">{children}</div>
    </div>
  );
}