Wave Background

A morphing SVG wave divider with scroll-driven morphing and ambient looping animation. Use it between page sections, as a card accent, or as a full-width transition.

Installation

Pro components require registry authentication. Add your Unlumen UI Pro key as UNLUMEN_LICENSE_KEY in your .env.local file and follow the setup guide.

File Structure

wave-background.tsx

Usage

import { WaveBackground } from "@/components/unlumen-ui/wave-background";
{
  /* Scroll-driven section divider */
}
<WaveBackground fill="var(--background)" background="var(--muted)" />;

{
  /* Ambient looping wave */
}
<WaveBackground
  variant="ambient"
  fill="var(--accent)"
  speed={1.5}
  amplitude={32}
/>;

{
  /* Upward-facing wave */
}
<WaveBackground direction="up" fill="var(--foreground)" height={80} />;

Examples

Section divider

<section className="relative bg-muted py-24">
  <h2>Features</h2>
  {/* Wave at the bottom of this section reveals the next background */}
  <WaveBackground
    fill="var(--background)"
    background="var(--muted)"
    direction="down"
    className="absolute bottom-0 inset-x-0"
  />
</section>

Wave inside a card

<div className="overflow-hidden rounded-2xl bg-foreground">
  {/* Card hero image / gradient */}
  <div className="h-48 bg-gradient-to-br from-foreground to-foreground/70" />

  {/* Wave morphs the gradient into the card body */}
  <WaveBackground
    variant="ambient"
    fill="var(--accent)"
    background="var(--foreground)"
    direction="down"
    height={72}
    speed={0.8}
    amplitude={20}
  />

  <div className="bg-accent/20 px-8 py-6">
    <h3>Card title</h3>
    <p>Card body content.</p>
  </div>
</div>

Ambient looping hero

<div className="relative h-screen bg-foreground">
  <WaveBackground
    variant="ambient"
    fill="var(--background)"
    background="var(--foreground)"
    direction="down"
    height={140}
    speed={1.2}
    amplitude={36}
    className="absolute bottom-0 inset-x-0"
  />
</div>

API Reference

WaveBackground

fill?
string
"var(--foreground)"

Fill color of the SVG wave shape. Accepts any CSS color or custom property.

background?
string
"transparent"

Background color of the container behind the wave.

direction?
"down" | "up"
"down"

Whether the wave crest faces down (fills the bottom of the container) or up (fills the top, useful for closing a section).

variant?
"scroll" | "ambient"
"scroll"

`"scroll"` morphs the wave as the element enters the viewport. `"ambient"` runs a continuous sine-wave loop.

height?
number
120

Height of the wave container in pixels.

speed?
number
1

Ambient mode only — speed multiplier for the looping animation. 1 = ~4 s cycle.

amplitude?
number
28

Ambient mode only — peak-to-trough amplitude of the wave in pixels.

...props?
React.ComponentProps<"div">

All other props are forwarded to the root div.

Notes

  • In "scroll" mode the wave uses useScroll with spring smoothing (stiffness: 140, damping: 28) to track the element's position between "start end" and "end start" — place the component at a section boundary and it will respond naturally.
  • In "ambient" mode an IntersectionObserver pauses the requestAnimationFrame loop when the element is off-screen, preventing wasted CPU time.
  • Both modes respect prefers-reduced-motion — the animation is skipped and a static mid-morph or mid-cycle shape is displayed instead.
  • The scroll variant reuses the same SVG path morphing technique as HeroWaveTransition.
  • Set direction="up" and position the component at the bottom of a colored section to create a "closing wave" that reveals the next background color.

Credits

Built by leo.

Keep in mind

Most components on this site are inspired by or recreated from existing work across the web. I'm not here to take credit; just to learn, experiment, and sometimes push things a bit further. If something looks familiar and I forgot to mention you, reach out and I'll fix that right away.