{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "hero-6",
  "title": "Hero 6: gradient mesh with floating cards",
  "author": "Ballmac <https://ui.ballmac.com>",
  "description": "Centered hero over a slowly drifting colour mesh, with gradient headline words and product cards that bob and follow the pointer. Cards stack below the buttons on phones.",
  "dependencies": [
    "lucide-react",
    "motion@^12"
  ],
  "registryDependencies": [
    "utils",
    "https://ui.ballmac.com/r/badge.json",
    "https://ui.ballmac.com/r/button.json",
    "https://ui.ballmac.com/r/gradient-text.json",
    "https://ui.ballmac.com/r/sparkline.json"
  ],
  "files": [
    {
      "path": "registry/ballmac/components/blocks/hero-6/hero-6.tsx",
      "content": "// Ballmac UI: Hero 6. https://ui.ballmac.com/blocks/hero-6\n\"use client\"\n\nimport * as React from \"react\"\nimport { ArrowRight, Check, CreditCard } from \"lucide-react\"\nimport { motion, useMotionValue, useReducedMotion, useSpring, useTransform, type MotionValue } from \"motion/react\"\n\nimport { Badge } from \"@/components/ballmac/badge\"\nimport { buttonVariants } from \"@/components/ballmac/button\"\nimport { GradientText } from \"@/components/ballmac/gradient-text\"\nimport { Sparkline } from \"@/components/ballmac/sparkline\"\nimport { cn } from \"@/lib/utils\"\n\ntype Action = { label: string; href: string }\n\ntype Hero6Props = Omit<React.ComponentProps<\"section\">, \"title\"> & {\n  /** Short label above the headline. */\n  eyebrow?: string\n  /** The headline, before the highlighted words. */\n  title?: string\n  /** Words at the end of the headline that get the gradient. */\n  highlight?: string\n  /** One or two sentences under the headline. */\n  description?: string\n  /** Main call to action. */\n  primaryAction?: Action\n  /** Secondary call to action. */\n  secondaryAction?: Action\n  /** Short proof points under the buttons. */\n  highlights?: string[]\n  /**\n   * Replaces the three floating cards. Wrap each in `<Hero6Float>` to give it a position and parallax depth.\n   * Below the `xl` breakpoint they stack under the buttons.\n   */\n  cards?: React.ReactNode\n}\n\ntype PointerContext = { x: MotionValue<number>; y: MotionValue<number>; reduce: boolean }\nconst PointerCtx = React.createContext<PointerContext | null>(null)\n\ntype Hero6FloatProps = React.ComponentProps<\"div\"> & {\n  /** How far the card travels with the pointer, in pixels at full tilt. Larger feels closer. */\n  depth?: number\n  /** Seconds for one bob up and down. */\n  bob?: number\n  /** Seconds to wait before the bob starts, so cards drift out of step. */\n  delay?: number\n}\n\n/** A card that follows the pointer a little and bobs gently. On small screens it is an ordinary block. */\nfunction Hero6Float({ depth = 18, bob = 6, delay = 0, className, children, ...props }: Hero6FloatProps) {\n  const ctx = React.useContext(PointerCtx)\n  const fallback = useMotionValue(0)\n  const x = useTransform(ctx?.x ?? fallback, (v) => v * depth)\n  const y = useTransform(ctx?.y ?? fallback, (v) => v * depth)\n  const reduce = ctx?.reduce ?? true\n  return (\n    <div data-slot=\"hero-6-float\" className={cn(\"xl:absolute\", className)} {...props}>\n      <motion.div style={reduce ? undefined : { x, y }}>\n        <motion.div\n          animate={reduce ? undefined : { y: [0, -9, 0] }}\n          transition={{ duration: bob, delay, repeat: Infinity, ease: \"easeInOut\" }}\n        >\n          {children}\n        </motion.div>\n      </motion.div>\n    </div>\n  )\n}\n\nconst cardClass = \"text-start rounded-2xl border bg-card/90 p-4 shadow-[0_24px_60px_-30px_rgb(0_0_0/0.4)] backdrop-blur-xl\"\n\nfunction DefaultCards() {\n  return (\n    <>\n      <Hero6Float depth={22} bob={6.5} className=\"xl:top-[50%] xl:start-0 2xl:start-[3%]\">\n        <div className={cn(cardClass, \"flex w-full items-center gap-3 xl:w-64\")}>\n          <span className=\"flex size-10 shrink-0 items-center justify-center rounded-xl bg-chart-2/15 text-chart-2\" aria-hidden=\"true\">\n            <CreditCard className=\"size-5\" />\n          </span>\n          <div className=\"min-w-0\">\n            <p className=\"truncate text-sm font-medium\">Payment received</p>\n            <p className=\"text-muted-foreground truncate text-xs\">Northwind Studio · $4,200.00</p>\n          </div>\n        </div>\n      </Hero6Float>\n      <Hero6Float depth={34} bob={7.5} delay={1.2} className=\"xl:top-[44%] xl:end-0 2xl:end-[3%]\">\n        <div className={cn(cardClass, \"w-full xl:w-60\")}>\n          <div className=\"flex items-start justify-between gap-3\">\n            <div>\n              <p className=\"text-muted-foreground text-xs\">Revenue</p>\n              <p className=\"mt-1 text-2xl font-semibold tracking-tight\">$48.2k</p>\n            </div>\n            <Badge status=\"success\">+12.4%</Badge>\n          </div>\n          <Sparkline values={[12, 18, 15, 24, 22, 31, 29, 38, 44]} label=\"Revenue, last 9 weeks\" height={44} className=\"text-chart-1 mt-3 w-full\" />\n        </div>\n      </Hero6Float>\n      <Hero6Float depth={14} bob={8} delay={0.6} className=\"xl:end-[5%] xl:bottom-[8%] 2xl:end-[9%]\">\n        <div className={cn(cardClass, \"flex w-full items-center gap-3 xl:w-64\")}>\n          <div className=\"flex -space-x-2\" aria-hidden=\"true\">\n            {[\"bg-chart-1/25\", \"bg-chart-3/25\", \"bg-chart-5/25\"].map((c, i) => (\n              <span key={c} className={cn(\"text-foreground ring-card flex size-8 items-center justify-center rounded-full text-[11px] font-semibold ring-2\", c)}>\n                {[\"MK\", \"JO\", \"AS\"][i]}\n              </span>\n            ))}\n          </div>\n          <p className=\"text-sm leading-snug\">\n            <span className=\"font-medium\">3 teammates</span> <span className=\"text-muted-foreground\">are reviewing</span>\n          </p>\n        </div>\n      </Hero6Float>\n      <Hero6Float depth={26} bob={7} delay={2} className=\"hidden xl:bottom-[10%] xl:start-[5%] xl:block 2xl:start-[9%]\">\n        <div className={cn(cardClass, \"flex w-64 items-center gap-3\")}>\n          <span className=\"bg-chart-1 relative flex size-2.5 shrink-0 rounded-full\" aria-hidden=\"true\" />\n          <p className=\"text-sm\">\n            Deployed <span className=\"font-medium\">checkout-v2</span> <span className=\"text-muted-foreground\">in 41s</span>\n          </p>\n        </div>\n      </Hero6Float>\n    </>\n  )\n}\n\nfunction Hero6({\n  eyebrow = \"Now with live collaboration\",\n  title = \"The finance workspace your whole team\",\n  highlight = \"actually enjoys.\",\n  description = \"Invoices, approvals and reporting in one calm place. Everything updates in real time, so nobody waits on a spreadsheet again.\",\n  primaryAction = { label: \"Start for free\", href: \"#\" },\n  secondaryAction = { label: \"See how it works\", href: \"#\" },\n  highlights = [\"Free for 3 people\", \"Set up in minutes\", \"Cancel anytime\"],\n  cards,\n  className,\n  ...props\n}: Hero6Props) {\n  const reduce = useReducedMotion()\n  const rawX = useMotionValue(0)\n  const rawY = useMotionValue(0)\n  const x = useSpring(rawX, { stiffness: 90, damping: 22, mass: 0.6 })\n  const y = useSpring(rawY, { stiffness: 90, damping: 22, mass: 0.6 })\n  const ctx = React.useMemo<PointerContext>(() => ({ x, y, reduce: !!reduce }), [x, y, reduce])\n\n  function onPointerMove(e: React.PointerEvent<HTMLElement>) {\n    if (reduce || e.pointerType === \"touch\") return\n    const rect = e.currentTarget.getBoundingClientRect()\n    rawX.set((e.clientX - rect.left) / rect.width - 0.5)\n    rawY.set((e.clientY - rect.top) / rect.height - 0.5)\n  }\n  function onPointerLeave() {\n    rawX.set(0)\n    rawY.set(0)\n  }\n\n  return (\n    <PointerCtx.Provider value={ctx}>\n      <section data-slot=\"hero-6\" onPointerMove={onPointerMove} onPointerLeave={onPointerLeave} className={cn(\"relative isolate overflow-hidden\", className)} {...props}>\n        {/* Mesh: soft colour blobs from the chart tokens, so it follows any theme. */}\n        <div aria-hidden=\"true\" className=\"pointer-events-none absolute inset-0 -z-10\">\n          <motion.div\n            className=\"absolute -top-40 start-[8%] size-[34rem] rounded-full bg-chart-1/25 blur-[100px] dark:bg-chart-1/20\"\n            animate={reduce ? undefined : { x: [0, 40, 0], y: [0, 24, 0] }}\n            transition={{ duration: 18, repeat: Infinity, ease: \"easeInOut\" }}\n          />\n          <motion.div\n            className=\"absolute top-20 end-[6%] size-[30rem] rounded-full bg-chart-3/25 blur-[100px] dark:bg-chart-3/20\"\n            animate={reduce ? undefined : { x: [0, -36, 0], y: [0, 30, 0] }}\n            transition={{ duration: 22, repeat: Infinity, ease: \"easeInOut\" }}\n          />\n          <motion.div\n            className=\"absolute -bottom-48 start-[38%] size-[28rem] rounded-full bg-chart-5/20 blur-[100px] dark:bg-chart-5/15\"\n            animate={reduce ? undefined : { x: [0, 28, 0], y: [0, -26, 0] }}\n            transition={{ duration: 20, repeat: Infinity, ease: \"easeInOut\" }}\n          />\n          <div className=\"absolute inset-0 bg-[linear-gradient(to_bottom,transparent_60%,var(--background))]\" />\n        </div>\n\n        <div className=\"relative mx-auto flex max-w-6xl flex-col items-center px-4 pt-20 pb-16 text-center sm:px-6 md:pt-28 md:pb-24 xl:min-h-[46rem] xl:justify-center\">\n          <Badge variant=\"outline\" className=\"bg-background/60 gap-2 rounded-full px-3 py-1 backdrop-blur\">\n            <span className=\"bg-chart-2 size-1.5 rounded-full\" aria-hidden=\"true\" />\n            {eyebrow}\n          </Badge>\n          <h1 className=\"mt-7 max-w-3xl text-4xl font-semibold tracking-[-0.045em] text-balance sm:text-5xl lg:text-6xl xl:text-7xl xl:leading-[1.02]\">\n            {title} <GradientText>{highlight}</GradientText>\n          </h1>\n          <p className=\"text-muted-foreground mt-6 max-w-xl text-lg leading-relaxed text-pretty\">{description}</p>\n          <div className=\"mt-9 flex flex-wrap justify-center gap-3\">\n            <a className={buttonVariants({ size: \"lg\", shape: \"pill\" })} href={primaryAction.href}>\n              {primaryAction.label} <ArrowRight  className=\"rtl:rotate-180\"/>\n            </a>\n            <a className={buttonVariants({ variant: \"outline\", size: \"lg\", shape: \"pill\", className: \"bg-background/60 backdrop-blur\" })} href={secondaryAction.href}>\n              {secondaryAction.label}\n            </a>\n          </div>\n          <ul className=\"text-muted-foreground mt-8 flex flex-wrap justify-center gap-x-6 gap-y-2 text-sm\">\n            {highlights.map((h) => (\n              <li key={h} className=\"flex items-center gap-2\">\n                <Check className=\"text-foreground size-4\" aria-hidden=\"true\" />\n                {h}\n              </li>\n            ))}\n          </ul>\n          <div className=\"mt-12 grid w-full max-w-sm gap-3 sm:max-w-2xl sm:grid-cols-2 lg:max-w-4xl lg:grid-cols-3 xl:contents\">{cards ?? <DefaultCards />}</div>\n        </div>\n      </section>\n    </PointerCtx.Provider>\n  )\n}\n\nexport { Hero6, Hero6Float, type Hero6Props, type Hero6FloatProps }\n",
      "type": "registry:component",
      "target": "@components/ballmac/blocks/hero-6/hero-6.tsx"
    }
  ],
  "meta": {
    "schema": 1,
    "tier": "free",
    "tags": [
      "hero",
      "gradient",
      "mesh",
      "parallax",
      "floating cards",
      "saas"
    ],
    "version": "1.0.0",
    "updated": "2026-10-01",
    "ai": {
      "summary": "A bold, friendly landing hero. Edit eyebrow, title, highlight (the gradient words), description, actions and highlights; pass `cards` to replace the floating cards.",
      "whenToUse": [
        "Consumer and prosumer SaaS landing pages",
        "Launches that want a memorable first screen"
      ],
      "whenNotToUse": [
        "Dense developer tools (use hero-2)",
        "Pages that must stay completely static"
      ],
      "composesWith": [
        "header-1",
        "logo-cloud-1",
        "features-2",
        "pricing-1"
      ],
      "a11y": [
        {
          "keys": "Pointer only",
          "action": "The parallax and bobbing are decorative; they stop for reduced motion and on touch"
        }
      ],
      "customization": [
        "cards: wrap each card in <Hero6Float depth bob delay className=positions> to place it",
        "The mesh uses --chart-1, --chart-3 and --chart-5, so it follows your theme"
      ]
    },
    "examples": [
      "hero-6-demo",
      "hero-6-custom"
    ],
    "url": "https://ui.ballmac.com/components/hero-6"
  },
  "categories": [
    "blocks",
    "hero"
  ],
  "type": "registry:block"
}