
3D Extruded Buildings & Urban Footprints
Real-world 3D building extrusions with dynamic sunlight shadows, terrain DEM elevations, and pitch/bearing camera controls.
Horizontal three-step explainer with numbered markers on a connector rail, per-step icon, body copy, and a time estimate, closing on a primary + ghost CTA row.
Also available for Vue ->$pnpm dlx shadcn@latest add https://uipkge.dev/r/react/how-it-works-steps.json$npx shadcn@latest add https://uipkge.dev/r/react/how-it-works-steps.json$yarn dlx shadcn@latest add https://uipkge.dev/r/react/how-it-works-steps.json$bunx shadcn@latest add https://uipkge.dev/r/react/how-it-works-steps.jsonnpx shadcn@latest add @uipkge-react/how-it-works-stepsInstalls to:components/blocks/'use client'
import { CloudUpload, Plug, Rocket } from 'lucide-react'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
const steps = [
{
icon: Plug,
title: 'Connect your stack',
body: 'Point us at Postgres, Snowflake, or a CSV drop. Read-only credentials, no agent to install.',
detail: '~4 min',
},
{
icon: CloudUpload,
title: 'Map your metrics',
body: 'Pick the columns that matter. We infer types, generate the schema, and flag anything ambiguous.',
detail: '~10 min',
},
{
icon: Rocket,
title: 'Ship the dashboard',
body: 'Publish to your team with row-level permissions already applied. Iterate without a redeploy.',
detail: 'Same day',
},
]
export function HowItWorksSteps() {
return (
<section data-slot="how-it-works-steps" className="bg-background">
<div className="mx-auto max-w-6xl px-6 py-20 lg:py-28">
<div className="max-w-2xl">
<Badge variant="secondary">How it works</Badge>
<h2 className="mt-4 text-3xl font-semibold tracking-tight sm:text-4xl">
Three steps from credentials to dashboard
</h2>
<p className="text-muted-foreground mt-3 text-lg">
No migration, no rewrite. Most teams finish the whole path in an afternoon.
</p>
</div>
<div className="relative mt-14">
{/* Connector rail: decorative, so it lives outside the <ol> rather than
adding a phantom list item for screen readers. */}
<div
className="bg-border pointer-events-none absolute top-6 right-[16.67%] left-[16.67%] hidden h-px md:block"
aria-hidden="true"
/>
<ol className="grid gap-10 md:grid-cols-3 md:gap-8">
{steps.map((step, index) => (
<li key={step.title} className="relative flex flex-col items-start md:items-center">
<div className="border-border bg-card text-foreground relative z-10 flex size-12 items-center justify-center rounded-full border font-mono text-sm font-semibold">
{String(index + 1).padStart(2, '0')}
</div>
<div className="mt-5 md:text-center">
<step.icon className="text-muted-foreground mb-3 size-5 md:mx-auto" aria-hidden="true" />
<h3 className="text-base font-semibold">{step.title}</h3>
<p className="text-muted-foreground mt-2 max-w-xs text-sm leading-relaxed md:mx-auto">{step.body}</p>
<p className="text-muted-foreground/80 mt-3 font-mono text-xs tracking-wide uppercase">
{step.detail}
</p>
</div>
</li>
))}
</ol>
</div>
<div className="border-border mt-14 flex flex-wrap items-center gap-4 border-t pt-8">
<Button>Start the walkthrough</Button>
<Button variant="ghost">Read the setup guide</Button>
</div>
</div>
</section>
)
}
Raw manifest:https://uipkge.dev/r/react/how-it-works-steps.json