App Mockup Hero
Original · freehero with a CSS app mockup
Copy prompt gives Claude Code, Cursor or v0 a ready-to-paste prompt that recreates this exact component.
npx shadcn@latest add https://webinnoventix.com/r/herox-app-mockup.json"use client";
import { useRef, useState, type KeyboardEvent } from "react";
import { motion, useReducedMotion } from "motion/react";
type TabId = "overview" | "analytics" | "tasks";
interface Tab {
id: TabId;
label: string;
}
interface TaskItem {
id: string;
label: string;
meta: string;
done: boolean;
}
const TABS: Tab[] = [
{ id: "overview", label: "Overview" },
{ id: "analytics", label: "Analytics" },
{ id: "tasks", label: "Tasks" },
];
const WEEK_BARS: { day: string; value: number }[] = [
{ day: "M", value: 52 },
{ day: "T", value: 74 },
{ day: "W", value: 46 },
{ day: "T", value: 88 },
{ day: "F", value: 63 },
{ day: "S", value: 34 },
{ day: "S", value: 71 },
];
const INITIAL_TASKS: TaskItem[] = [
{ id: "t1", label: "Finalize Q3 launch checklist", meta: "Due today · Priya", done: true },
{ id: "t2", label: "Review onboarding copy v4", meta: "Due today · You", done: false },
{ id: "t3", label: "Ship billing retry logic", meta: "Tomorrow · Marcus", done: false },
{ id: "t4", label: "Publish changelog for 2.0", meta: "Fri · Ada", done: false },
];
export default function HeroxAppMockup() {
const prefersReduced = useReducedMotion();
const [activeTab, setActiveTab] = useState<TabId>("overview");
const [tasks, setTasks] = useState<TaskItem[]>(INITIAL_TASKS);
const tabRefs = useRef<Array<HTMLButtonElement | null>>([]);
const doneCount = tasks.filter((t) => t.done).length;
const donePct = Math.round((doneCount / tasks.length) * 100);
const toggleTask = (id: string) => {
setTasks((prev) =>
prev.map((t) => (t.id === id ? { ...t, done: !t.done } : t)),
);
};
const onTabKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {
const current = TABS.findIndex((t) => t.id === activeTab);
let next = current;
if (e.key === "ArrowRight" || e.key === "ArrowDown") next = (current + 1) % TABS.length;
else if (e.key === "ArrowLeft" || e.key === "ArrowUp") next = (current - 1 + TABS.length) % TABS.length;
else if (e.key === "Home") next = 0;
else if (e.key === "End") next = TABS.length - 1;
else return;
e.preventDefault();
setActiveTab(TABS[next].id);
tabRefs.current[next]?.focus();
};
const reveal = (delay: number) =>
prefersReduced
? { initial: { opacity: 1 }, animate: { opacity: 1 } }
: {
initial: { opacity: 0, y: 22 },
animate: { opacity: 1, y: 0 },
transition: { duration: 0.6, delay, ease: [0.16, 1, 0.3, 1] as const },
};
return (
<section className="relative w-full overflow-hidden bg-gradient-to-b from-slate-50 via-white to-slate-100 px-6 py-24 sm:py-28 lg:py-32 dark:from-slate-950 dark:via-slate-950 dark:to-black">
<style>{styles}</style>
{/* Atmosphere */}
<div aria-hidden="true" className="pointer-events-none absolute inset-0 overflow-hidden">
<div className="hax-blob absolute -left-24 -top-24 h-[28rem] w-[28rem] rounded-full bg-violet-400/25 blur-3xl dark:bg-violet-600/20" />
<div className="hax-blob-slow absolute -right-20 top-1/3 h-[26rem] w-[26rem] rounded-full bg-indigo-400/20 blur-3xl dark:bg-indigo-600/20" />
<div className="hax-blob absolute bottom-0 left-1/3 h-72 w-72 rounded-full bg-sky-300/20 blur-3xl dark:bg-sky-700/10" />
<div className="absolute inset-0 bg-[radial-gradient(circle_at_1px_1px,rgba(15,23,42,0.05)_1px,transparent_0)] bg-[length:22px_22px] dark:bg-[radial-gradient(circle_at_1px_1px,rgba(255,255,255,0.05)_1px,transparent_0)]" />
</div>
<div className="relative mx-auto grid max-w-7xl items-center gap-16 lg:grid-cols-[1.05fr_1.15fr] lg:gap-12">
{/* Copy column */}
<div className="max-w-xl">
<motion.a
href="#changelog"
{...reveal(0)}
className="group inline-flex items-center gap-2 rounded-full border border-slate-200 bg-white/70 px-3.5 py-1.5 text-xs font-medium text-slate-600 backdrop-blur transition-colors hover:border-violet-300 hover:text-violet-700 dark:border-slate-800 dark:bg-slate-900/60 dark:text-slate-300 dark:hover:border-violet-700 dark:hover:text-violet-300"
>
<span className="relative flex h-2 w-2">
<span className="hax-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75" />
<span className="relative inline-flex h-2 w-2 rounded-full bg-emerald-500" />
</span>
Beacon 2.0 is live
<svg viewBox="0 0 16 16" className="h-3.5 w-3.5 transition-transform group-hover:translate-x-0.5" fill="none" aria-hidden="true">
<path d="M6 3.5 10.5 8 6 12.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</motion.a>
<motion.h1
{...reveal(0.08)}
className="mt-6 text-4xl font-semibold leading-[1.05] tracking-tight text-slate-900 sm:text-5xl lg:text-6xl dark:text-white"
>
Turn scattered work into{" "}
<span className="relative whitespace-nowrap">
<span className="bg-gradient-to-r from-indigo-600 via-violet-600 to-sky-500 bg-clip-text text-transparent dark:from-indigo-400 dark:via-violet-400 dark:to-sky-400">
real momentum
</span>
<svg viewBox="0 0 300 12" className="absolute -bottom-1 left-0 h-2.5 w-full text-violet-400/70 dark:text-violet-500/60" fill="none" aria-hidden="true" preserveAspectRatio="none">
<path d="M2 8C60 3 240 3 298 8" stroke="currentColor" strokeWidth="3" strokeLinecap="round" />
</svg>
</span>
</motion.h1>
<motion.p
{...reveal(0.16)}
className="mt-6 text-lg leading-relaxed text-slate-600 dark:text-slate-400"
>
Beacon pulls tasks, metrics, and updates into one calm workspace. Every project gets a clear owner, a live status, and an obvious next step — so you can retire the status meeting that could have been a dashboard.
</motion.p>
<motion.div {...reveal(0.24)} className="mt-8 flex flex-col gap-3 sm:flex-row sm:items-center">
<a
href="#start"
className="inline-flex items-center justify-center gap-2 rounded-xl bg-slate-900 px-6 py-3.5 text-sm font-semibold text-white shadow-lg shadow-slate-900/20 transition-all hover:bg-slate-800 hover:shadow-xl focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-violet-500 dark:bg-white dark:text-slate-900 dark:shadow-black/40 dark:hover:bg-slate-100"
>
Start free for 14 days
<svg viewBox="0 0 16 16" className="h-4 w-4" fill="none" aria-hidden="true">
<path d="M3 8h10M9 4l4 4-4 4" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</a>
<a
href="#tour"
className="group inline-flex items-center justify-center gap-2.5 rounded-xl border border-slate-300 bg-white/70 px-6 py-3.5 text-sm font-semibold text-slate-700 backdrop-blur transition-colors hover:border-slate-400 hover:bg-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-violet-500 dark:border-slate-700 dark:bg-slate-900/50 dark:text-slate-200 dark:hover:border-slate-600 dark:hover:bg-slate-900"
>
<span className="flex h-6 w-6 items-center justify-center rounded-full bg-violet-100 text-violet-700 transition-colors group-hover:bg-violet-200 dark:bg-violet-500/20 dark:text-violet-300">
<svg viewBox="0 0 16 16" className="h-3 w-3" fill="currentColor" aria-hidden="true">
<path d="M5 3.5v9l7-4.5-7-4.5Z" />
</svg>
</span>
Watch 2-min tour
</a>
</motion.div>
<motion.dl {...reveal(0.32)} className="mt-10 grid max-w-md grid-cols-3 gap-6 border-t border-slate-200 pt-8 dark:border-slate-800">
{[
{ v: "3.2×", l: "faster status updates" },
{ v: "40%", l: "fewer sync meetings" },
{ v: "99.98%", l: "platform uptime" },
].map((s) => (
<div key={s.l}>
<dt className="text-2xl font-semibold tracking-tight text-slate-900 dark:text-white">{s.v}</dt>
<dd className="mt-1 text-xs leading-snug text-slate-500 dark:text-slate-500">{s.l}</dd>
</div>
))}
</motion.dl>
</div>
{/* App mockup column */}
<motion.div {...reveal(0.2)} className="relative">
<div
aria-hidden="true"
className="absolute -inset-4 -z-10 rounded-[2rem] bg-gradient-to-tr from-violet-500/15 via-indigo-500/10 to-sky-500/15 blur-2xl"
/>
{/* Window frame */}
<div className="hax-tilt overflow-hidden rounded-2xl border border-slate-200/80 bg-white shadow-2xl shadow-slate-900/15 ring-1 ring-black/5 dark:border-slate-800 dark:bg-slate-900 dark:shadow-black/50 dark:ring-white/5">
{/* Title bar */}
<div className="flex items-center gap-3 border-b border-slate-200 bg-slate-50/80 px-4 py-3 dark:border-slate-800 dark:bg-slate-900/80">
<div className="flex gap-1.5">
<span className="h-3 w-3 rounded-full bg-rose-400" />
<span className="h-3 w-3 rounded-full bg-amber-400" />
<span className="h-3 w-3 rounded-full bg-emerald-400" />
</div>
<div className="ml-2 flex flex-1 items-center gap-2 rounded-md bg-white px-3 py-1.5 text-[11px] text-slate-400 ring-1 ring-slate-200 dark:bg-slate-950 dark:text-slate-500 dark:ring-slate-800">
<svg viewBox="0 0 16 16" className="h-3 w-3 text-emerald-500" fill="none" aria-hidden="true">
<path d="M11 6.5V5a3 3 0 0 0-6 0v1.5M4 6.5h8v6H4v-6Z" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round" />
</svg>
app.beacon.example / workspace
</div>
</div>
{/* App body */}
<div className="flex">
{/* Sidebar */}
<nav aria-label="Workspace" className="hidden w-44 shrink-0 flex-col gap-1 border-r border-slate-200 bg-slate-50/50 p-3 sm:flex dark:border-slate-800 dark:bg-slate-950/40">
<div className="mb-3 flex items-center gap-2 px-2">
<span className="flex h-7 w-7 items-center justify-center rounded-lg bg-gradient-to-br from-violet-600 to-indigo-600 text-white">
<svg viewBox="0 0 16 16" className="h-4 w-4" fill="none" aria-hidden="true">
<path d="M8 2v12M8 2 4 6M8 2l4 4" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</span>
<span className="text-sm font-semibold text-slate-800 dark:text-slate-100">Beacon</span>
</div>
{[
{ n: "Home", icon: "M3 8l5-5 5 5M4.5 7v5h7V7" },
{ n: "Projects", icon: "M2.5 5h4l1.2 1.5h5.8v6h-11V5Z" },
{ n: "Insights", icon: "M3 12V7M6.5 12V4M10 12V8M13 12V6" },
{ n: "Team", icon: "M5.5 7a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm5 0a2 2 0 1 0 0-4 2 2 0 0 0 0 4ZM2.5 12.5c0-2 1.3-3 3-3s3 1 3 3m1-3c1.7 0 3 1 3 3" },
].map((item, i) => (
<span
key={item.n}
className={`flex items-center gap-2.5 rounded-lg px-2.5 py-2 text-[13px] font-medium ${
i === 0
? "bg-white text-slate-900 shadow-sm ring-1 ring-slate-200 dark:bg-slate-800 dark:text-white dark:ring-slate-700"
: "text-slate-500 dark:text-slate-400"
}`}
>
<svg viewBox="0 0 16 16" className="h-4 w-4" fill="none" aria-hidden="true">
<path d={item.icon} stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" />
</svg>
{item.n}
</span>
))}
<div className="mt-auto rounded-lg bg-gradient-to-br from-violet-50 to-indigo-50 p-2.5 dark:from-violet-500/10 dark:to-indigo-500/10">
<p className="text-[11px] font-medium text-slate-700 dark:text-slate-300">Trial ends in 9 days</p>
<div className="mt-1.5 h-1.5 w-full overflow-hidden rounded-full bg-slate-200 dark:bg-slate-800">
<span className="block h-full w-2/3 rounded-full bg-gradient-to-r from-violet-500 to-indigo-500" />
</div>
</div>
</nav>
{/* Main panel */}
<div className="min-w-0 flex-1 p-4 sm:p-5">
{/* Header + tabs */}
<div className="flex items-start justify-between gap-3">
<div>
<p className="text-[11px] font-medium uppercase tracking-wider text-violet-600 dark:text-violet-400">Marketing Site Relaunch</p>
<h2 className="mt-0.5 text-base font-semibold text-slate-900 dark:text-white">Good afternoon, team</h2>
</div>
<div className="flex -space-x-2">
{["from-rose-400 to-amber-400", "from-sky-400 to-indigo-400", "from-emerald-400 to-sky-400"].map((g, i) => (
<span key={i} className={`h-7 w-7 rounded-full bg-gradient-to-br ${g} ring-2 ring-white dark:ring-slate-900`} />
))}
<span className="flex h-7 w-7 items-center justify-center rounded-full bg-slate-100 text-[10px] font-semibold text-slate-500 ring-2 ring-white dark:bg-slate-800 dark:text-slate-400 dark:ring-slate-900">+6</span>
</div>
</div>
<div
role="tablist"
aria-label="Workspace views"
onKeyDown={onTabKeyDown}
className="mt-4 inline-flex gap-1 rounded-lg bg-slate-100 p-1 dark:bg-slate-800/70"
>
{TABS.map((tab, i) => {
const selected = tab.id === activeTab;
return (
<button
key={tab.id}
ref={(el) => {
tabRefs.current[i] = el;
}}
role="tab"
id={`hax-tab-${tab.id}`}
aria-selected={selected}
aria-controls={`hax-panel-${tab.id}`}
tabIndex={selected ? 0 : -1}
onClick={() => setActiveTab(tab.id)}
className={`relative rounded-md px-3.5 py-1.5 text-[13px] font-medium transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-violet-500 ${
selected
? "bg-white text-slate-900 shadow-sm dark:bg-slate-950 dark:text-white"
: "text-slate-500 hover:text-slate-800 dark:text-slate-400 dark:hover:text-slate-200"
}`}
>
{tab.label}
</button>
);
})}
</div>
{/* Overview panel */}
{activeTab === "overview" && (
<div id="hax-panel-overview" role="tabpanel" aria-labelledby="hax-tab-overview" tabIndex={0} className="mt-4 rounded-xl focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-violet-500">
<div className="grid grid-cols-3 gap-3">
{[
{ l: "On track", v: "18", d: "+3", tone: "emerald" as const },
{ l: "At risk", v: "4", d: "-1", tone: "amber" as const },
{ l: "Blocked", v: "1", d: "0", tone: "rose" as const },
].map((c) => (
<div key={c.l} className="rounded-xl border border-slate-200 bg-white p-3 dark:border-slate-800 dark:bg-slate-950/50">
<p className="text-[11px] text-slate-500 dark:text-slate-500">{c.l}</p>
<div className="mt-1 flex items-baseline gap-1.5">
<span className="text-xl font-semibold text-slate-900 dark:text-white">{c.v}</span>
<span
className={`text-[11px] font-medium ${
c.tone === "emerald"
? "text-emerald-600 dark:text-emerald-400"
: c.tone === "amber"
? "text-amber-600 dark:text-amber-400"
: "text-rose-600 dark:text-rose-400"
}`}
>
{c.d}
</span>
</div>
</div>
))}
</div>
<div className="mt-3 rounded-xl border border-slate-200 bg-white p-4 dark:border-slate-800 dark:bg-slate-950/50">
<div className="flex items-center justify-between">
<p className="text-[13px] font-medium text-slate-700 dark:text-slate-300">Weekly throughput</p>
<span className="text-[11px] text-slate-400 dark:text-slate-500">tasks shipped</span>
</div>
<div className="mt-4 flex h-28 items-end gap-2.5">
{WEEK_BARS.map((b, i) => (
<div key={i} className="flex flex-1 flex-col items-center gap-1.5">
<div className="flex w-full flex-1 items-end">
<span
className="hax-bar w-full rounded-t-md bg-gradient-to-t from-violet-500 to-indigo-400 dark:from-violet-500 dark:to-indigo-400"
style={{ height: `${b.value}%`, animationDelay: `${i * 90}ms` }}
/>
</div>
<span className="text-[10px] text-slate-400 dark:text-slate-500">{b.day}</span>
</div>
))}
</div>
</div>
</div>
)}
{/* Analytics panel */}
{activeTab === "analytics" && (
<div id="hax-panel-analytics" role="tabpanel" aria-labelledby="hax-tab-analytics" tabIndex={0} className="mt-4 rounded-xl focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-violet-500">
<div className="grid grid-cols-2 gap-3">
{[
{ l: "Cycle time", v: "2.4d", d: "-18%" },
{ l: "Review latency", v: "5.1h", d: "-32%" },
].map((c) => (
<div key={c.l} className="rounded-xl border border-slate-200 bg-white p-3 dark:border-slate-800 dark:bg-slate-950/50">
<p className="text-[11px] text-slate-500 dark:text-slate-500">{c.l}</p>
<div className="mt-1 flex items-baseline gap-1.5">
<span className="text-xl font-semibold text-slate-900 dark:text-white">{c.v}</span>
<span className="text-[11px] font-medium text-emerald-600 dark:text-emerald-400">{c.d}</span>
</div>
</div>
))}
</div>
<div className="mt-3 rounded-xl border border-slate-200 bg-white p-4 dark:border-slate-800 dark:bg-slate-950/50">
<p className="text-[13px] font-medium text-slate-700 dark:text-slate-300">Velocity trend</p>
<div className="mt-3">
<svg viewBox="0 0 320 120" className="h-32 w-full" fill="none" preserveAspectRatio="none" aria-hidden="true">
<defs>
<linearGradient id="haxArea" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="rgb(139,92,246)" stopOpacity="0.35" />
<stop offset="100%" stopColor="rgb(139,92,246)" stopOpacity="0" />
</linearGradient>
</defs>
<path d="M0 90 L45 78 L90 84 L135 55 L180 62 L225 34 L270 40 L320 18 L320 120 L0 120 Z" fill="url(#haxArea)" />
<path className="hax-line" d="M0 90 L45 78 L90 84 L135 55 L180 62 L225 34 L270 40 L320 18" stroke="rgb(124,58,237)" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" />
{[[45, 78], [135, 55], [225, 34], [320, 18]].map(([x, y]) => (
<circle key={x} cx={x} cy={y} r="3.5" fill="white" stroke="rgb(124,58,237)" strokeWidth="2" />
))}
</svg>
</div>
<div className="mt-2 flex justify-between text-[10px] text-slate-400 dark:text-slate-500">
{["W1", "W2", "W3", "W4", "W5", "W6"].map((w) => (
<span key={w}>{w}</span>
))}
</div>
</div>
</div>
)}
{/* Tasks panel */}
{activeTab === "tasks" && (
<div id="hax-panel-tasks" role="tabpanel" aria-labelledby="hax-tab-tasks" className="mt-4">
<div className="mb-3 flex items-center justify-between rounded-xl border border-slate-200 bg-white px-4 py-2.5 dark:border-slate-800 dark:bg-slate-950/50">
<p className="text-[13px] font-medium text-slate-700 dark:text-slate-300">
{doneCount} of {tasks.length} done
</p>
<div className="flex items-center gap-2">
<div className="h-1.5 w-24 overflow-hidden rounded-full bg-slate-200 dark:bg-slate-800">
<span
className="block h-full rounded-full bg-gradient-to-r from-emerald-500 to-sky-400 transition-[width] duration-500 ease-out"
style={{ width: `${donePct}%` }}
/>
</div>
<span className="text-[11px] font-medium tabular-nums text-slate-500 dark:text-slate-400">{donePct}%</span>
</div>
</div>
<ul className="space-y-2">
{tasks.map((task) => (
<li key={task.id}>
<button
type="button"
role="checkbox"
aria-checked={task.done}
aria-label={task.label}
onClick={() => toggleTask(task.id)}
className="flex w-full items-center gap-3 rounded-xl border border-slate-200 bg-white px-3.5 py-2.5 text-left transition-colors hover:border-slate-300 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-violet-500 dark:border-slate-800 dark:bg-slate-950/50 dark:hover:border-slate-700"
>
<span
className={`flex h-5 w-5 shrink-0 items-center justify-center rounded-md border transition-colors ${
task.done
? "border-emerald-500 bg-emerald-500 text-white"
: "border-slate-300 bg-transparent dark:border-slate-600"
}`}
>
{task.done && (
<svg viewBox="0 0 16 16" className="h-3.5 w-3.5" fill="none" aria-hidden="true">
<path d="M3.5 8.5 6.5 11.5 12.5 4.5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
)}
</span>
<span className="min-w-0 flex-1">
<span
className={`block truncate text-[13px] font-medium ${
task.done
? "text-slate-400 line-through dark:text-slate-600"
: "text-slate-800 dark:text-slate-200"
}`}
>
{task.label}
</span>
<span className="block truncate text-[11px] text-slate-400 dark:text-slate-500">{task.meta}</span>
</span>
</button>
</li>
))}
</ul>
</div>
)}
</div>
</div>
</div>
{/* Floating activity toast */}
<div className="hax-float absolute -bottom-5 -left-4 hidden items-center gap-3 rounded-xl border border-slate-200 bg-white/90 px-3.5 py-2.5 shadow-xl shadow-slate-900/10 backdrop-blur sm:flex dark:border-slate-800 dark:bg-slate-900/90 dark:shadow-black/40">
<span className="flex h-8 w-8 items-center justify-center rounded-lg bg-emerald-100 text-emerald-600 dark:bg-emerald-500/20 dark:text-emerald-400">
<svg viewBox="0 0 16 16" className="h-4 w-4" fill="none" aria-hidden="true">
<path d="M3.5 8.5 6.5 11.5 12.5 4.5" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</span>
<div>
<p className="text-[12px] font-semibold text-slate-800 dark:text-slate-100">Ada shipped “Q3 launch”</p>
<p className="text-[11px] text-slate-500 dark:text-slate-400">Moved to Done · just now</p>
</div>
</div>
{/* Floating metric chip */}
<div className="hax-float-slow absolute -right-3 -top-5 hidden items-center gap-2.5 rounded-xl border border-slate-200 bg-white/90 px-3.5 py-2.5 shadow-xl shadow-slate-900/10 backdrop-blur md:flex dark:border-slate-800 dark:bg-slate-900/90 dark:shadow-black/40">
<span className="relative flex h-2.5 w-2.5">
<span className="hax-ping absolute inline-flex h-full w-full rounded-full bg-violet-400 opacity-75" />
<span className="relative inline-flex h-2.5 w-2.5 rounded-full bg-violet-500" />
</span>
<div>
<p className="text-[11px] text-slate-500 dark:text-slate-400">Sprint burndown</p>
<p className="text-[13px] font-semibold text-slate-800 dark:text-slate-100">On pace · 92%</p>
</div>
</div>
</motion.div>
</div>
<style>{`
@media (prefers-reduced-motion: reduce) {
.hax-blob, .hax-blob-slow, .hax-bar, .hax-float, .hax-float-slow,
.hax-ping, .hax-line, .hax-tilt {
animation: none !important;
}
}
`}</style>
</section>
);
}
const styles = `
@keyframes hax-grow {
from { transform: scaleY(0); opacity: 0; }
to { transform: scaleY(1); opacity: 1; }
}
@keyframes hax-float-y {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-9px); }
}
@keyframes hax-float-y-2 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(7px); }
}
@keyframes hax-blob-move {
0%, 100% { transform: translate(0, 0) scale(1); }
50% { transform: translate(24px, -18px) scale(1.08); }
}
@keyframes hax-blob-move-2 {
0%, 100% { transform: translate(0, 0) scale(1); }
50% { transform: translate(-22px, 20px) scale(1.05); }
}
@keyframes hax-ping-out {
75%, 100% { transform: scale(2.1); opacity: 0; }
}
@keyframes hax-draw {
from { stroke-dashoffset: 520; }
to { stroke-dashoffset: 0; }
}
.hax-bar {
transform-origin: bottom;
animation: hax-grow 0.7s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.hax-float { animation: hax-float-y 5s ease-in-out infinite; }
.hax-float-slow { animation: hax-float-y-2 6.5s ease-in-out infinite; }
.hax-blob { animation: hax-blob-move 16s ease-in-out infinite; }
.hax-blob-slow { animation: hax-blob-move-2 20s ease-in-out infinite; }
.hax-ping { animation: hax-ping-out 1.8s cubic-bezier(0, 0, 0.2, 1) infinite; }
.hax-line { stroke-dasharray: 520; animation: hax-draw 1.6s ease-out forwards; }
`;Dependencies
Licence
Built by Web Innoventix. Free for personal and commercial use, no attribution required.
Built by Web Innoventix
Need a custom interface, a full website, or SEO that gets you cited by AI? We design, build and rank it end to end.
Get a free quoteSimilar components
Browse all →
Spotlight Hero
OriginalA centred hero with a soft radial spotlight, badge and dual call-to-action.

Split Hero
OriginalA two-column hero pairing a headline and CTAs with a product mock and social proof.

Gradient Spotlight Hero
OriginalA minimal centred hero with a soft gradient-mesh backdrop, announcement pill and dual call-to-action buttons.

App Preview Hero
OriginalA centred hero that pairs headline copy with a realistic product dashboard mock built entirely from markup, complete with browser chrome and a floating notification card.

Waitlist Capture Hero
OriginalA dark, focused hero with an inline email capture form and avatar social proof, ready for pre-launch waitlists.

Image Backdrop Hero
OriginalA cinematic full-bleed hero with a layered image-style backdrop, overlaid left-aligned copy and a trusted-by logos strip.

Gradient Mesh Hero with Staggered Text Reveal
OriginalA full-screen hero pairing a drifting animated gradient-mesh backdrop with a word-by-word staggered blur-in headline and a logo marquee under the fold.

Typewriter Rotating Words Hero
OriginalA hero whose headline cycles through rotating words with a live typewriter caret over an animated grid backdrop, degrading to a gentle word swap when reduced motion is on.

Floating UI Cards Hero with Mouse Parallax
OriginalA hero with glassy floating UI cards that drift continuously and shift on mouse-parallax depth around a staggered centre headline.

Aurora Hero with Shimmer CTA and Logo Marquee
OriginalA dark hero with animated aurora light beams, a shimmering sweep across the primary CTA, and dual-direction logo marquees beneath the fold.

Gradient Conversion Hero
MITCentered, full-screen marketing hero with a colour-accent headline word, supporting copy, and dual primary/secondary CTA buttons. Dark-mode ready and dependency-free.

Split Showcase Hero
MITTwo-column hero on a dark background with a headline, paragraph, and two buttons beside a gradient media panel. Responsive column stack on mobile.

