Getting Started
Components
Search for a command to run...
import { ScrollSvgStroke } from "@/registry/tween/scroll-svg-stroke"
const PAGE = "#0a0a0b"
const PANEL = "#161619"
const INK = "#f4f4f5"
const STROKE = "#5B8CFF"
const img = (id: string) =>
`https://images.unsplash.com/photo-${id}?q=80&w=1000&h=1000&fit=crop&crop=faces,center&auto=format`
const heroSection =
"@container/sss relative flex w-full items-center justify-center overflow-hidden px-[clamp(1rem,4cqi,3rem)]"
const heroStyle = { height: "var(--preview-h, 100vh)" }
const bigHeading =
"w-[min(92%,42ch)] text-center font-medium uppercase leading-[1.05] [letter-spacing:-0.025em] text-[clamp(1.5rem,6cqi,4.5rem)]"
const subHeading =
"font-medium uppercase leading-[1.1] [letter-spacing:-0.015em] text-[clamp(1.1rem,3.6cqi,2.25rem)]"
const bodyText =
"font-medium leading-[1.45] text-[clamp(0.85rem,1.7cqi,1.125rem)] opacity-80"
const captionText =
"font-medium uppercase tracking-[0.25em] text-[clamp(0.65rem,1cqi,0.8rem)] opacity-60"
export function ScrollSvgStrokeDemo() {
return (
<div
className="@container/sss w-full"
style={{ backgroundColor: PAGE, color: INK }}
>
<section className={heroSection} style={heroStyle}>
<div className="flex flex-col items-center gap-[clamp(0.75rem,2cqi,1.5rem)]">
<p className={captionText}>Chapter 01 · Motion</p>
<h1 className={bigHeading}>Draw every story one stroke at a time</h1>
</div>
</section>
<ScrollSvgStroke
className="@container/sss px-[clamp(0.75rem,3cqi,2rem)] py-[clamp(2.5rem,8cqi,8rem)]"
stroke={STROKE}
strokeWidth={180}
>
<div className="flex flex-col gap-[clamp(2.5rem,8cqi,8rem)]">
<div className="flex justify-center">
<div className="aspect-square w-[min(60%,22rem)] overflow-hidden rounded-2xl">
<img
src={img("1536180838057-b604200e6f36")}
alt=""
className="size-full object-cover"
/>
</div>
</div>
<div className="grid grid-cols-1 items-center gap-[clamp(1.5rem,4cqi,3rem)] @[640px]/sss:grid-cols-2">
<div className="flex items-center justify-center">
<div
className="flex w-full max-w-md flex-col gap-3 rounded-2xl p-[clamp(1.25rem,3cqi,2.5rem)]"
style={{ backgroundColor: PANEL }}
>
<p
className={captionText}
style={{ color: STROKE, opacity: 1 }}
>
Chapter 01
</p>
<h2 className={subHeading}>Lines that follow your scroll</h2>
<p className={bodyText}>
Every path is drawn in sync with the viewport, so the artwork
feels alive the moment it enters the frame. Pacing, easing and
length are tuned to keep motion smooth — never distracting.
</p>
</div>
</div>
<div className="flex items-center justify-center @[640px]/sss:order-last">
<div className="aspect-square w-[min(80%,20rem)] overflow-hidden rounded-2xl">
<img
src={img("1618754580230-dc55ba127aa2")}
alt=""
className="size-full object-cover"
/>
</div>
</div>
</div>
<div className="grid grid-cols-1 items-center gap-[clamp(1.5rem,4cqi,3rem)] @[640px]/sss:grid-cols-2">
<div className="flex items-center justify-center @[640px]/sss:order-first">
<div className="aspect-square w-[min(80%,20rem)] overflow-hidden rounded-2xl">
<img
src={img("1768809249580-12899b96330d")}
alt=""
className="size-full object-cover"
/>
</div>
</div>
<div className="flex items-center justify-center">
<div
className="flex w-full max-w-md flex-col gap-3 rounded-2xl p-[clamp(1.25rem,3cqi,2.5rem)]"
style={{ backgroundColor: PANEL }}
>
<p
className={captionText}
style={{ color: STROKE, opacity: 1 }}
>
Chapter 02
</p>
<h2 className={subHeading}>Built for any layout</h2>
<p className={bodyText}>
Wrap a heading, an image or a full section and the stroke
adapts to the shape it travels through. Drop it into a hero, a
feature grid or a closing statement — it just works.
</p>
</div>
</div>
</div>
<div className="flex justify-center">
<div className="aspect-square w-[min(60%,22rem)] overflow-hidden rounded-2xl">
<img
src={img("1685703206731-0bcd26546754")}
alt=""
className="size-full object-cover"
/>
</div>
</div>
</div>
</ScrollSvgStroke>
<section className={heroSection} style={heroStyle}>
<div className="flex flex-col items-center gap-[clamp(0.75rem,2cqi,1.5rem)]">
<p className={captionText} style={{ color: STROKE, opacity: 1 }}>
Chapter 02 · Finale
</p>
<h1 className={bigHeading}>
Leave a line that lingers after the scroll
</h1>
</div>
</section>
</div>
)
}
import { ScrollSvgStroke } from "@/components/ui/scroll-svg-stroke"<ScrollSvgStroke
stroke="#FF5F0A"
strokeWidth={200}
viewBox="0 0 1378 2760"
path="M639 100C639 100 ..."
>
<div className="flex flex-col gap-32">{/* your spotlight content */}</div>
</ScrollSvgStroke>The path's stroke-dasharray and stroke-dashoffset are tied to a ScrollTrigger running between start and end, so the line draws on as the section scrolls into view and rewinds when scrolled back. Pass any path and viewBox to trace a custom shape behind your children, and adjust scrub to control how tightly the drawing follows the scroll position.
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Section content; rendered above the SVG. |
path | string | Default decorative path | The d attribute of the SVG path to draw. |
viewBox | string | "0 0 1378 2760" | The SVG viewBox. |
stroke | string | "#FF5F0A" | Stroke color. |
strokeWidth | number | 200 | Stroke width (in viewBox units). |
strokeLinecap | "butt" | "round" | "square" | "round" | Stroke line cap. |
strokeOpacity | number | 1 | Stroke opacity. |
start | string | "top top" | ScrollTrigger start value. |
end | string | "bottom bottom" | ScrollTrigger end value. |
scrub | boolean | number | true | ScrollTrigger scrub value. |
scroller | HTMLElement | string | null | — | Optional ScrollTrigger scroller; defaults to the ambient preview scroller. |
className | string | — | Extra classes on the outer section. |
svgClassName | string | — | Extra classes on the SVG wrapper (use to override top). |
pathClassName | string | — | Extra classes on the path element. |