Capture
Every signal from your stack lands in one replayable timeline.
A scroll-driven card stack: each card pins at a sticky offset while the next scrolls over it, receding with a slight scale-down, dim, and blur driven by per-card useScroll/useTransform against ordinary page scroll (no hijack). Under prefers-reduced-motion the depth transforms are dropped and cards render as a plain, static, legible stack.
Inspired by Componentry — Sticky Scroll Cards — independently built, not affiliated. Attribution policy
npx shadcn@latest add https://parable-three.vercel.app/r/sticky-scroll-cards.jsonRuns the shadcn CLI — the component source is copied intocomponents/parable/sticky-scroll-cards.tsx. You own it from there.
The exact code rendering the preview above.
<div className="h-[440px] w-full max-w-md overflow-y-auto rounded-2xl border border-white/10 bg-[#0b0b0d] p-5 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
<StickyScrollCards
stickyTop={20}
items={[
{
title: "Capture",
body: "Every signal from your stack lands in one replayable timeline.",
content: (
<div className="inline-flex items-center gap-2 rounded-full bg-white/5 px-3 py-1 text-xs text-white/60">
<Sparkles className="size-3.5" /> Real-time ingest
</div>
),
},
{
title: "Compose",
body: "Drag primitives into flows. Branch, merge, and preview on one canvas.",
accent: "#22d3ee",
},
{
title: "Ship",
body: "One click promotes a draft to production with instant rollback baked in.",
accent: "#f5a623",
},
]}
/>
<div className="h-28" />
</div>StickyScrollCardsProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "children">
| Prop | Type | Default | Description |
|---|---|---|---|
| items* | StickyScrollItem[] | — | Ordered cards. Each sticks in turn while the next scrolls over it. |
| cardClassName | string | — | Extra classes merged onto every card face. |
| stickyTop | number | 96 | Distance in px from the viewport top where each card pins. Defaults to 96. |