23rd

Shader Gradient

A grainy liquid gradient for landing heroes, empty states, and marketing sections — the palette flows under a film grain, follows the theme, and swirls around the pointer.

Atmosphere behind a hero, wait screen, or empty state. Four colors flow through slow, warped noise — liquid bands that never read as a loop — and blend in OKLab, so neighbours stay clean instead of going muddy. A film grain sits on top (grain, 0–1), re-rolled at 24 fps like film. Some paper or ink breathes through so it never turns into wall-to-wall color. Peach, butter, sky and lilac on paper in light mode; blue, violet, magenta and coral on ink in dark. Press d to toggle.

Preview

Landing

A first screen that already feels finished

Headline and a primary action sit on the wash. The shader stays in the back.

Props
Palette
0.14
0.70
0.95
0.35

Headline over the gradient

Swirl the flow around the pointer

Installation

pnpm dlx shadcn@latest add @23rd/shader-gradient

Or install straight from the public GitHub source registry:

pnpm dlx shadcn@latest add radiumcoders/23rd.dev/shader-gradient

Usage

Pin it behind a relatively positioned section. Keep content in a later stacking context (relative z-10). Default theme="auto" follows shadcn / next-themes (class on <html>).

"use client"

import { ShaderGradient } from "@/components/ui/shader-gradient"

export function Hero() {
  return (
    <section className="relative isolate min-h-svh overflow-hidden bg-background">
      <ShaderGradient />
      <div className="relative z-10 mx-auto flex min-h-svh max-w-xl flex-col items-center justify-center px-6 text-center">
        <p className="text-xs font-medium tracking-[0.18em] text-muted-foreground uppercase">
          New
        </p>
        <h1 className="mt-3 text-4xl font-medium tracking-tight">
          Ship the page, not the backdrop
        </h1>
        <p className="mt-3 text-muted-foreground">
          Headline, proof, and a primary action sit on the wash. The shader
          stays quiet.
        </p>
      </div>
    </section>
  )
}

Force a palette if the parent theme should not drive it:

<ShaderGradient theme="light" />
<ShaderGradient theme="dark" />

Props

PropTypeDefault
colorsstring[]theme palette — up to 4, cycled in order
speednumber0.14
blurnumber0.7 — 0–1, broader and calmer bands
intensitynumber0.95 — 0–1, lower shows more paper / ink
grainnumber0.35 — 0–1 film grain, 0 for none
interactivebooleantrue — the flow swirls around the pointer
theme"light" | "dark" | "auto"auto
classNamestringReact only
classstringSvelte only