Skip to content
Plinth

Original by Plinth · MIT

Backgrounds

Grain Gradient

A drifting four-colour mesh under real generated film grain — no noise texture to ship, no repeat seam.

#background#gradient#grain#noise#svg-filter

Install

npx shadcn@latest add https://plinthui.com/r/grain-gradient.json
Open in v0
// No hooks or handlers here, so this stays a server component — the whole
// thing is CSS and one SVG filter. The filter, blend mode and keyframes are
// outside what Tailwind can express, so they live in the style element below.
const css = `
.grain {
  position: relative;
  min-height: 300px;
  overflow: hidden;
  background: #0a0912;
  /* isolate, or mix-blend-mode on the grain reaches past this component and
     composites against whatever is behind it on the page. */
  isolation: isolate;
}

/* Four blobs drifting at different periods. Oversized and blurred hard, so
   what you see is the overlap rather than four distinct shapes. */
.grain__mesh {
  position: absolute;
  inset: -25%;
  filter: blur(58px);
  background:
    radial-gradient(28% 34% at 26% 28%, #ff7a4d 0%, transparent 70%),
    radial-gradient(30% 32% at 74% 24%, #7d5cff 0%, transparent 70%),
    radial-gradient(32% 36% at 68% 76%, #16b3c4 0%, transparent 70%),
    radial-gradient(26% 30% at 24% 74%, #e5397e 0%, transparent 70%);
  animation: grain-drift 22s ease-in-out infinite alternate;
}

.grain__noise {
  position: absolute;
  inset: 0;
  filter: url(#grain-noise);
  opacity: 0.42;
  /* overlay rather than a flat alpha: grain should darken the lights and lift
     the shadows, not fog the whole frame evenly. */
  mix-blend-mode: overlay;
  pointer-events: none;
}

.grain__def { position: absolute; width: 0; height: 0; }

@keyframes grain-drift {
  0%   { transform: translate3d(-3%, -2%, 0) scale(1.06); }
  50%  { transform: translate3d(2%, 3%, 0) scale(1.14); }
  100% { transform: translate3d(3%, -3%, 0) scale(1.04); }
}

@media (prefers-reduced-motion: reduce) {
  .grain__mesh { animation: none; }
}
`;

export function GrainGradient() {
  return (
    <>
      <style>{css}</style>
      <div className="grain">
        <div className="grain__mesh" />
        <div className="grain__noise" />
        <svg className="grain__def" aria-hidden="true">
          {/* Generated noise rather than a tiled PNG: no asset to ship, and it
              never shows a repeat seam at any size. */}
          <filter id="grain-noise">
            <feTurbulence
              type="fractalNoise"
              baseFrequency="0.82"
              numOctaves={3}
              stitchTiles="stitch"
            />
            <feColorMatrix type="saturate" values="0" />
          </filter>
        </svg>
      </div>
    </>
  );
}

More in Backgrounds

Similar tags