Components
Signed-distance-field blobs grow, warp and merge to carry one screen into the next, with five variants and a duration you control. Respects prefers-reduced-motion.

"use client";
import { useEffect, useState } from "react";
import Component from "@/components/ui/sdf-blob-transition";
const SLIDES = [
{ background: "bg-[radial-gradient(120%_120%_at_15%_10%,#ff9a8b_0%,#ff3d7f_45%,#3a1c71_100%)]", index: "01", title: "Aurora" },
{ background: "bg-[radial-gradient(120%_120%_at_85%_10%,#8ec5fc_0%,#4f6bed_45%,#0b1e63_100%)]", index: "02", title: "Meridian" },
{ background: "bg-[radial-gradient(120%_120%_at_50%_0%,#ffd76e_0%,#ff8a3d_50%,#a01d4c_100%)]", index: "03", title: "Solstice" },
{ background: "bg-[radial-gradient(120%_120%_at_25%_90%,#7ef7c5_0%,#12b39a_45%,#053b4d_100%)]", index: "04", title: "Cascade" },
];
const VARIANTS = ["circle", "warped", "merge", "radial", "final"] as const;
const STEP_MS = 2100;
const SWEEP_MS = 2000;
export default function DemoOne() {
const [index, setIndex] = useState(0);
useEffect(() => {
const id = setInterval(
() => setIndex((current) => (current + 1) % (SLIDES.length * VARIANTS.length)),
STEP_MS
);
return () => clearInterval(id);
}, []);
const slide = SLIDES[index % SLIDES.length];
const variant = VARIANTS[index % VARIANTS.length];
return (
<div className="flex min-h-[760px] w-full flex-col items-center justify-center gap-6 bg-background p-6">
<div className="flex w-full max-w-5xl items-baseline justify-between gap-6">
<div>
<p className="font-medium text-muted-foreground text-xs uppercase tracking-[0.18em]">
SDF Blob Transition
</p>
<p className="mt-2 max-w-2xl text-muted-foreground text-sm leading-relaxed">
Signed-distance-field blobs grow, warp and merge to carry one screen into the next.
</p>
</div>
<span className="shrink-0 rounded-full border px-3 py-1 font-mono text-muted-foreground text-xs">
{variant}
</span>
</div>
<Component
className="w-full max-w-5xl overflow-hidden rounded-3xl"
duration={SWEEP_MS}
variant={variant}
transitionKey={index}
>
<div
className={`flex h-[560px] w-full flex-col justify-between p-10 ${slide.background}`}
>
<div className="flex items-center justify-between text-white/80">
<span className="font-mono text-sm tabular-nums">{slide.index}</span>
<span className="font-mono text-xs uppercase tracking-[0.2em]">
WebGL
</span>
</div>
<div>
<p className="font-semibold text-6xl text-white tracking-tight">
{slide.title}
</p>
<p className="mt-3 max-w-md text-base text-white/80 leading-relaxed">
The shader runs on the compositor and falls back to an instant
swap when prefers-reduced-motion is set.
</p>
</div>
</div>
</Component>
</div>
);
}