Members' faces on two arcs around a critique circle's sign-up, at night. Hold one to see who and where.
registry/demos/throughline-community-demo.tsx
"use client";
import * as React from "react";
import { Throughline, type ThroughlineItem, type ThroughlineLine } from "@/components/ui/throughline";
const face = (id: string) =>
`https://images.unsplash.com/photo-${id}?auto=format&fit=crop&crop=faces&w=160&h=160&q=80`;
const MEMBERS = [
{ name: "Inés Duarte", city: "Porto", photo: "1438761681033-6461ffad8d80" },
{ name: "Rafa Ortiz", city: "Mexico City", photo: "1507003211169-0a1dd7228f2d" },
{ name: "Mei Lin", city: "Taipei", photo: "1534528741775-53994a69daeb" },
{ name: "Luca Ferri", city: "Turin", photo: "1500648767791-00dcc994a43e" },
{ name: "Adaeze Obi", city: "Lagos", photo: "1531123897727-8f129e1688ce" },
{ name: "Jonas Berg", city: "Oslo", photo: "1539571696357-5a69c17a67c6" },
{ name: "Sofia Marin", city: "Bucharest", photo: "1494790108377-be9c29b29330" },
{ name: "Tom Hale", city: "Leeds", photo: "1506794778202-cad84cf45f1d" },
];
// Two long arcs, one over the copy and one under it, so a face never sits on a word.
const LINES: ThroughlineLine[] = [
{ from: [3, 34], to: [97, 8], bend: -0.2 },
{ from: [97, 70], to: [3, 94], bend: -0.2 },
];
const ITEMS: ThroughlineItem[] = MEMBERS.map((m) => ({
label: `${m.name} · ${m.city}`,
icon: <span className="block rounded-full bg-zinc-800 bg-cover bg-center" style={{ backgroundImage: `url(${face(m.photo)})` }} />,
className:
"[--throughline-icon:100%] rounded-full border-0 bg-transparent p-[3px] backdrop-blur-none shadow-[0_0_0_1.5px_rgb(198_255_61/0.9),0_14px_28px_-12px_rgb(0_0_0/0.8)] dark:bg-transparent dark:shadow-[0_0_0_1.5px_rgb(198_255_61/0.9),0_14px_28px_-12px_rgb(0_0_0/0.8)]",
}));
export function ThroughlineCommunityDemo() {
const [sent, setSent] = React.useState(false);
return (
<section className="w-full overflow-hidden rounded-[28px] bg-[#0b0b12] text-white">
<Throughline lines={LINES} items={ITEMS} duration={30} className="text-[#c6ff3d]">
<div className="flex flex-col items-center px-6 py-[max(7rem,15cqi)] text-center text-white">
<p className="rounded-full border border-white/10 px-3 py-1 text-xs font-medium text-zinc-300">
Kiln · a critique circle for product designers
</p>
<h2 className="mt-5 max-w-[30rem] text-balance text-[clamp(1.9rem,5cqi,3.25rem)] font-semibold leading-[1.04] tracking-[-0.04em]">
Post one shot a week. Get three honest notes back.
</h2>
<p className="mt-4 max-w-[24rem] text-pretty text-[15px] leading-relaxed text-zinc-400">
2,431 designers in 64 cities. No likes, no followers, just notes by Sunday.
</p>
<form
className="mt-7 flex w-full max-w-[22rem] items-center gap-1.5 rounded-full border border-white/10 bg-white/[0.06] p-1.5 transition-colors duration-150 focus-within:border-[#c6ff3d]/60"
onSubmit={(e) => {
e.preventDefault();
setSent(true);
}}
>
<label htmlFor="kiln-email" className="sr-only">
Email
</label>
<input
id="kiln-email"
type="email"
required
placeholder="you@studio.com"
className="h-10 min-w-0 flex-1 bg-transparent px-3.5 text-sm text-white outline-none placeholder:text-zinc-500"
/>
<button
type="submit"
className="h-10 shrink-0 rounded-full bg-[#c6ff3d] px-4 text-sm font-semibold text-zinc-950 transition-transform duration-150 ease-out active:scale-[0.97] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#c6ff3d]"
>
{sent ? "You're in" : "Join the circle"}
</button>
</form>
</div>
</Throughline>
</section>
);
}
Live preview, examples and props: https://keyframeui.com/components/throughline#throughline-community-demo