{
+ const nextFocusedElement = event.relatedTarget;
+
+ if (
+ nextFocusedElement instanceof Node &&
+ event.currentTarget.contains(nextFocusedElement)
+ ) {
+ return;
+ }
+
+ focusedRef.current = false;
+ startAutoAdvance();
+ }}
+ onFocusCapture={() => {
+ focusedRef.current = true;
+ stopAutoAdvance();
+ }}
+ onMouseEnter={() => {
+ hoveredRef.current = true;
+ stopAutoAdvance();
+ }}
+ onMouseLeave={() => {
+ hoveredRef.current = false;
+ startAutoAdvance();
+ }}
+ >
+
+
+ {heroCarouselCards.map((card, index) => (
+
+ ))}
+
+
+
+
+ {heroCarouselCards.map((card, index) => (
+
+ ))}
+
+
+ );
+}
diff --git a/landing/src/components/hero-carousel-data.ts b/landing/src/components/hero-carousel-data.ts
new file mode 100644
index 000000000..597d60b16
--- /dev/null
+++ b/landing/src/components/hero-carousel-data.ts
@@ -0,0 +1,108 @@
+import type { PixelIconName } from "@/components/pixel-icon";
+
+export type HeroCarouselCardStatus = "done" | "pending" | "error";
+
+export type HeroCarouselCardData = {
+ id: string;
+ eyebrow: string;
+ title: string;
+ icon: PixelIconName;
+ status: HeroCarouselCardStatus;
+ action?: {
+ href: string;
+ label: string;
+ };
+ rows: Array<{
+ icon: PixelIconName;
+ label: string;
+ value: string;
+ }>;
+};
+
+export const heroCarouselCards: HeroCarouselCardData[] = [
+ {
+ id: "gateway",
+ eyebrow: "01 Gateway",
+ title: "Task intake",
+ icon: "run",
+ status: "pending",
+ action: { href: "#get-started", label: "Start agent run" },
+ rows: [
+ { icon: "comment", label: "Prompt", value: "Implement feature #2137" },
+ { icon: "gauge", label: "Mode", value: "Make no mistakes" },
+ { icon: "check", label: "Verify", value: "Required" },
+ { icon: "device", label: "Target", value: "iOS Simulator" },
+ ],
+ },
+ {
+ id: "code-agent-implementation",
+ eyebrow: "02 Code Agent",
+ title: "Implementation",
+ icon: "braces",
+ status: "done",
+ rows: [
+ { icon: "shuffle", label: "Branch", value: "feature/2137" },
+ { icon: "list", label: "Files modified", value: "4" },
+ { icon: "check", label: "Tests updated", value: "2" },
+ {
+ icon: "bookmark-check",
+ label: "Skill",
+ value: "React Native best practices",
+ },
+ ],
+ },
+ {
+ id: "reviewer",
+ eyebrow: "03 Reviewer",
+ title: "Self review",
+ icon: "search",
+ status: "pending",
+ rows: [
+ { icon: "list", label: "Changes", value: "4 files modified" },
+ { icon: "search", label: "Issues found", value: "1" },
+ { icon: "clock", label: "Status", value: "Needs mobile check" },
+ { icon: "gauge", label: "Risk", value: "Feature X flow" },
+ ],
+ },
+ {
+ id: "agent-device-mobile",
+ eyebrow: "04 Agent Device",
+ title: "Mobile execution",
+ icon: "device",
+ status: "error",
+ action: { href: "#capture", label: "Watch recording 00:42" },
+ rows: [
+ { icon: "snapshot", label: "Snapshot", value: "Captured" },
+ { icon: "cursor", label: "Action", value: "Swipe + tap" },
+ { icon: "video", label: "Recording", value: "Saved" },
+ { icon: "list", label: "Result", value: "Crash found" },
+ ],
+ },
+ {
+ id: "agent-device-debug",
+ eyebrow: "05 Agent Device",
+ title: "Debug output",
+ icon: "terminal",
+ status: "error",
+ rows: [
+ { icon: "list", label: "Logs", value: "Last 200 lines" },
+ { icon: "terminal", label: "Trace", value: "Captured" },
+ { icon: "download", label: "Device state", value: "Saved" },
+ { icon: "gauge", label: "Error", value: "Out of memory" },
+ ],
+ },
+ {
+ id: "code-agent-remediation",
+ eyebrow: "06 Code Agent",
+ title: "Remediation",
+ icon: "braces",
+ status: "done",
+ action: { href: "#get-started", label: "Open pull request" },
+ rows: [
+ { icon: "check", label: "Fix", value: "Limit image cache" },
+ { icon: "list", label: "Files modified", value: "1" },
+ { icon: "bookmark-check", label: "Tests", value: "Passed" },
+ { icon: "github", label: "PR", value: "Ready for review" },
+ ],
+ },
+];
diff --git a/landing/src/components/hero-workflow-card.tsx b/landing/src/components/hero-workflow-card.tsx
new file mode 100644
index 000000000..f9db7f070
--- /dev/null
+++ b/landing/src/components/hero-workflow-card.tsx
@@ -0,0 +1,125 @@
+import Link from "next/link";
+import { memo } from "react";
+
+import type { HeroCarouselCardData, HeroCarouselCardStatus } from "@/components/hero-carousel-data";
+import { PixelIcon, type PixelIconName } from "@/components/pixel-icon";
+import { cn } from "@/lib/utils";
+
+const statusMeta = {
+ done: {
+ icon: "check",
+ label: "Done",
+ className: "bg-[#a6e34a]/30 text-[#a6e34a]",
+ },
+ pending: {
+ icon: "clock",
+ label: "Queued",
+ className: "bg-white/10 text-white/45",
+ },
+ error: {
+ icon: "terminal",
+ label: "Needs attention",
+ className: "bg-[#ff5a3d]/20 text-[#ff8f7a]",
+ },
+} satisfies Record<
+ HeroCarouselCardStatus,
+ { icon: PixelIconName; label: string; className: string }
+>;
+
+type HeroWorkflowCardProps = {
+ active: boolean;
+ card: HeroCarouselCardData;
+ index: number;
+};
+
+export const HeroWorkflowCard = memo(function HeroWorkflowCard({
+ active,
+ card,
+ index,
+}: HeroWorkflowCardProps) {
+ const status = statusMeta[card.status];
+
+ return (
+