{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "wordmark-footer",
  "type": "registry:ui",
  "title": "Wordmark Footer",
  "description": "A Rauno-craft half-cut wordmark footer — giant brand text on a full-width dark surface with luminance gradient and hairline divider.",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "registry/ruixenui/wordmark-footer.tsx",
      "content": "\"use client\";\n\nimport { useState, useRef, useEffect, useCallback } from \"react\";\nimport { motion } from \"motion/react\";\n\n/**\n * Wordmark Footer — Rauno Freiberg craft, Ruixen UI edition.\n *\n * Centered giant wordmark on a full-width dark surface with a subtle\n * bottom clip. Move your cursor and the metallic shine follows —\n * a radial gradient spotlight tracks the pointer with lerped\n * smoothing at 60fps via direct DOM writes, zero re-renders.\n * A vertical mask handles the half-cut fade independently.\n * cursor: pointer. The light IS the interaction.\n */\n\n/* ── Types ── */\n\ninterface WordmarkFooterProps {\n  brandName?: string;\n}\n\n/* ── Scoped CSS ── */\n\nconst STYLE = `\n.wf{\n  --wf-bg:#161618;\n  --wf-line:rgba(255,255,255,.07)\n}\n.dark .wf,[data-theme=\"dark\"] .wf{\n  --wf-bg:#111113;\n  --wf-line:rgba(255,255,255,.08)\n}\n`.replace(/\\n/g, \"\");\n\n/* ── Radial shine gradient — follows cursor ── */\n\nfunction makeShine(x: number, y: number): string {\n  return `radial-gradient(ellipse 100% 100% at ${x.toFixed(1)}% ${y.toFixed(1)}%, rgba(255,255,255,.88) 0%, rgba(255,255,255,.62) 24%, rgba(255,255,255,.34) 50%, rgba(255,255,255,.16) 100%)`;\n}\n\n/* ── Vertical mask — dims bottom for the half-cut, independent of shine ── */\n\nconst VMASK =\n  \"linear-gradient(to bottom, black 0%, black 38%, rgba(0,0,0,.55) 76%, rgba(0,0,0,.30) 100%)\";\n\n/* ── Main component ── */\n\nexport function WordmarkFooter({\n  brandName = \"Ruixen UI\",\n}: WordmarkFooterProps) {\n  const [inView, setInView] = useState(false);\n  const sectionRef = useRef<HTMLElement>(null);\n  const textRef = useRef<HTMLSpanElement>(null);\n\n  /* ── Cursor-tracking state — refs only, zero re-renders ── */\n\n  const hovering = useRef(false);\n  const curX = useRef(50);\n  const curY = useRef(30);\n  const tgtX = useRef(50);\n  const tgtY = useRef(30);\n  const raf = useRef(0);\n\n  /* ── Per-frame lerp loop — direct DOM writes ── */\n\n  const paint = useCallback(() => {\n    curX.current += (tgtX.current - curX.current) * 0.1;\n    curY.current += (tgtY.current - curY.current) * 0.1;\n\n    const grad = makeShine(curX.current, curY.current);\n\n    if (textRef.current) {\n      textRef.current.style.backgroundImage = grad;\n    }\n\n    const dx = Math.abs(tgtX.current - curX.current);\n    const dy = Math.abs(tgtY.current - curY.current);\n\n    if (hovering.current || dx > 0.05 || dy > 0.05) {\n      raf.current = requestAnimationFrame(paint);\n    }\n  }, []);\n\n  const onMove = useCallback(\n    (e: React.MouseEvent) => {\n      const r = sectionRef.current?.getBoundingClientRect();\n      if (!r) return;\n      tgtX.current = ((e.clientX - r.left) / r.width) * 100;\n      tgtY.current = ((e.clientY - r.top) / r.height) * 100;\n\n      if (!hovering.current) {\n        hovering.current = true;\n        raf.current = requestAnimationFrame(paint);\n      }\n    },\n    [paint],\n  );\n\n  const onLeave = useCallback(() => {\n    hovering.current = false;\n    tgtX.current = 50;\n    tgtY.current = 30;\n    raf.current = requestAnimationFrame(paint);\n  }, [paint]);\n\n  /* ── Cleanup ── */\n\n  useEffect(() => () => cancelAnimationFrame(raf.current), []);\n\n  /* ── IntersectionObserver ── */\n\n  useEffect(() => {\n    const el = sectionRef.current;\n    if (!el || typeof IntersectionObserver === \"undefined\") {\n      setInView(true);\n      return;\n    }\n    const obs = new IntersectionObserver(\n      ([entry]) => {\n        if (entry.isIntersecting) {\n          setInView(true);\n          obs.disconnect();\n        }\n      },\n      { threshold: 0.1 },\n    );\n    obs.observe(el);\n    return () => obs.disconnect();\n  }, []);\n\n  return (\n    <section\n      ref={sectionRef}\n      className=\"wf\"\n      onMouseMove={onMove}\n      onMouseLeave={onLeave}\n      style={{\n        position: \"relative\",\n        width: \"100%\",\n        overflow: \"hidden\",\n        background: \"var(--wf-bg)\",\n        height: \"clamp(100px, 15.5vw, 215px)\",\n        fontFamily:\n          '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n        cursor: \"pointer\",\n      }}\n    >\n      <style dangerouslySetInnerHTML={{ __html: STYLE }} />\n\n      {/* ── Wordmark — absolute, centered, pointer-events off ── */}\n      <motion.div\n        initial={{ opacity: 0, y: 16 }}\n        animate={inView ? { opacity: 1, y: 0 } : {}}\n        transition={{ type: \"spring\", stiffness: 260, damping: 28 }}\n        style={{\n          position: \"absolute\",\n          top: 0,\n          left: 0,\n          right: 0,\n          display: \"flex\",\n          alignItems: \"center\",\n          justifyContent: \"center\",\n          gap: \"clamp(10px, 2vw, 24px)\",\n          padding: \"clamp(20px, 3vw, 40px) clamp(24px, 4vw, 56px)\",\n          pointerEvents: \"none\",\n        }}\n      >\n        {/* Brand text */}\n        <span\n          ref={textRef}\n          style={{\n            fontSize: \"clamp(64px, 17vw, 240px)\",\n            fontWeight: 700,\n            letterSpacing: \"-0.05em\",\n            lineHeight: 1,\n            backgroundImage: makeShine(50, 30),\n            WebkitBackgroundClip: \"text\",\n            backgroundClip: \"text\",\n            WebkitTextFillColor: \"transparent\",\n            maskImage: VMASK,\n            WebkitMaskImage: VMASK,\n            userSelect: \"none\",\n            whiteSpace: \"nowrap\",\n          }}\n        >\n          {brandName}\n        </span>\n      </motion.div>\n\n      {/* ── Hairline — just above the clip edge ── */}\n      <div\n        style={{\n          position: \"absolute\",\n          left: 0,\n          right: 0,\n          bottom: \"clamp(10px, 1.5vw, 22px)\",\n          height: 0.5,\n          background: \"var(--wf-line)\",\n          pointerEvents: \"none\",\n        }}\n      />\n    </section>\n  );\n}\n\nexport default WordmarkFooter;\n",
      "type": "registry:ui",
      "target": "components/ruixen/wordmark-footer.tsx"
    }
  ]
}