{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "depth-headline",
  "title": "Depth Headline",
  "description": "A huge serif headline sits behind a gradient sphere that slides through it for depth.",
  "dependencies": ["remotion", "@remotion/google-fonts"],
  "files": [
    {
      "path": "registry/remocn/depth-headline/index.tsx",
      "content": "\"use client\";\n\nimport { loadFont as loadDisplay } from \"@remotion/google-fonts/Fraunces\";\nimport { loadFont as loadManrope } from \"@remotion/google-fonts/Manrope\";\nimport {\n  AbsoluteFill,\n  Easing,\n  Img,\n  interpolate,\n  useCurrentFrame,\n  useVideoConfig,\n} from \"remotion\";\n\nconst { fontFamily: display } = loadDisplay(\"normal\", {\n  weights: [\"300\", \"400\"],\n  subsets: [\"latin\"],\n});\nconst manrope = loadManrope(\"normal\", {\n  weights: [\"500\", \"600\"],\n  subsets: [\"latin\"],\n});\nconst sans = manrope.fontFamily;\n\nexport interface DepthHeadlineProps {\n  /** Huge headline set behind the subject. One short word reads best. */\n  title?: string;\n  /** Transparent-PNG cutout that rises in front of the headline. */\n  src?: string;\n  /** Small line at the foot of the frame, after the logo. Pass \"\" to hide. */\n  caption?: string;\n  /** Show the remocn logo at the foot of the frame. */\n  showLogo?: boolean;\n  accent?: string;\n  /** Playback multiplier. */\n  speed?: number;\n  theme?: \"dark\" | \"light\";\n}\n\nconst THEMES = {\n  dark: {\n    bg: \"#0A0A0B\",\n    fg: \"#F5F4F0\",\n    muted: \"#8A8984\",\n    shadow: \"rgba(0,0,0,0.55)\",\n  },\n  light: {\n    bg: \"#F5F4F0\",\n    fg: \"#0A0A0B\",\n    muted: \"#6E6C67\",\n    shadow: \"rgba(40,32,20,0.22)\",\n  },\n} as const;\n\nconst EASE_OUT = Easing.bezier(0.22, 1, 0.36, 1);\nconst EASE_IO = Easing.bezier(0.65, 0, 0.35, 1);\nconst CLAMP = {\n  extrapolateLeft: \"clamp\",\n  extrapolateRight: \"clamp\",\n} as const;\n\n/** Fraunces 400 advance per character at display tracking, in em. */\nconst ADVANCE = 0.48;\n\n/** gradients.sh \"mesh\": lilac, periwinkle and deep blue blobs on ink. */\nconst MESH = {\n  bg: \"#0a0d24\",\n  colors: [\"#ecdcf2\", \"#8796ee\", \"#2e45b7\", \"#0e1645\"],\n} as const;\n\n/**\n * The mesh palette as a flat poster orb: deep blue at the crown, lilac light\n * pooling at the base, two blobs drifting a few percent. Lit from below so it\n * reads as colour, not as a shaded ball.\n */\nfunction meshFill(t: number, accent: string) {\n  const [c0, c1, , c3] = MESH.colors;\n  const c2 = accent;\n  const d = Math.sin(t * Math.PI) * 5;\n  return [\n    `radial-gradient(70% 55% at ${38 + d}% 100%, ${c0} 0%, color-mix(in oklab, ${c0} 0%, transparent) 70%)`,\n    `radial-gradient(60% 70% at ${82 - d}% ${62 - d * 0.5}%, color-mix(in oklab, ${c1} 85%, transparent) 0%, transparent 70%)`,\n    `radial-gradient(90% 70% at ${30 + d * 0.6}% 0%, color-mix(in oklab, ${c3} 70%, transparent) 0%, transparent 72%)`,\n    `linear-gradient(180deg, ${c2} 0%, ${c1} 64%, ${c0} 100%)`,\n  ].join(\", \");\n}\n\nconst REMOCN_R_PATH =\n  \"M 0.01 0.81 C 0.01 1.73, 0.36 2.79, 1.09 4.13 C 4.91 11.04, 13.45 17.16, 21.7 18.9 C 22.94 19.16, 23.18 19.16, 51.39 19.27 C 76.07 19.36, 80.02 19.4, 81.32 19.57 C 89.89 20.69, 96.2 24.68, 99.38 31.01 C 103.19 38.56, 102.53 50.1, 97.91 57.07 C 94.66 61.96, 89.68 64.99, 83.26 66 C 82.81 66.07, 70.18 66.83, 55.2 67.69 C 24.82 69.43, 27.03 69.23, 24.18 70.4 C 19.9 72.15, 14.84 75.7, 10.65 79.89 C 4.86 85.68, 1.3 91.91, 0.25 98.13 C 0.12 98.85, 0.08 103.13, 0.04 116.66 L 0 134.26 9.5 134.26 L 19 134.26 19.05 119.41 C 19.1 103.27, 19.08 103.82, 19.82 101.04 C 21.79 93.65, 27.86 88.75, 36.45 87.63 C 37.23 87.53, 39.41 87.5, 43.57 87.53 C 50.12 87.59, 50.75 87.65, 53.22 88.45 C 56.61 89.56, 59.67 91.86, 62.02 95.07 C 62.52 95.76, 69.35 103.85, 77.2 113.07 C 85.04 122.28, 91.63 130.04, 91.85 130.32 C 92.07 130.59, 92.5 131.34, 92.82 131.97 C 93.52 133.35, 94.11 133.93, 95.06 134.13 C 95.5 134.23, 98.97 134.26, 106.36 134.23 L 117.01 134.19 100.82 113.07 C 91.91 101.45, 84.52 91.78, 84.39 91.57 C 83.36 89.89, 83.66 87.53, 85.09 86 C 85.79 85.25, 86.36 84.94, 88.07 84.38 C 96.18 81.72, 104.15 76.62, 109.97 70.36 C 120.59 58.93, 124.06 44.32, 119.44 30.43 C 114.59 15.81, 101.93 4.02, 87.64 0.83 C 83.93 0.01, 88.09 0.08, 41.85 0.04 L 0.01 0 0.01 0.81 Z\";\n\n/** Full logo as on remocn.dev: R mark (0.76em tall, baseline-aligned) + \"emocn\" in Manrope 600, tracking-tight. */\nfunction RemocnLogo({ fontSize, color }: { fontSize: number; color: string }) {\n  return (\n    <div\n      style={{\n        display: \"flex\",\n        alignItems: \"baseline\",\n        color,\n        fontFamily: manrope.fontFamily,\n        fontWeight: 600,\n        fontSize,\n        letterSpacing: \"-0.025em\",\n        lineHeight: 1,\n      }}\n    >\n      <svg\n        viewBox=\"0 0 124.06 134.26\"\n        style={{ height: \"0.76em\", width: \"auto\" }}\n        aria-hidden\n      >\n        <path fill=\"currentColor\" d={REMOCN_R_PATH} />\n      </svg>\n      <span style={{ marginLeft: \"0.04em\" }}>emocn</span>\n    </div>\n  );\n}\n\nexport function DepthHeadline({\n  title = \"Studio\",\n  src,\n  caption = \"Studio\",\n  showLogo = true,\n  accent = \"#3B5BFD\",\n  speed = 1,\n  theme = \"dark\",\n}: DepthHeadlineProps) {\n  const frame = useCurrentFrame() * speed;\n  const { width: W, height: H } = useVideoConfig();\n  const c = THEMES[theme];\n\n  const size = Math.min(\n    H * 0.56,\n    (W * 0.9) / Math.max(1, title.length * ADVANCE),\n  );\n\n  // Far plane: the headline tracks open and drifts a short distance.\n  const open = interpolate(frame, [0, 54], [0, 1], {\n    ...CLAMP,\n    easing: EASE_OUT,\n  });\n  const tracking = -0.07 + open * 0.035;\n  const headX = (1 - open) * W * 0.045;\n  const headY = (1 - open) * H * 0.035;\n\n  // Near plane: the subject rises from below and covers much more ground.\n  const rise = interpolate(frame, [4, 48], [0, 1], {\n    ...CLAMP,\n    easing: EASE_OUT,\n  });\n  const subjectY = (1 - rise) * H * 0.78;\n\n  // A slow push after the rise: near plane grows more than far plane.\n  const push = interpolate(frame, [30, 96], [0, 1], {\n    ...CLAMP,\n    easing: EASE_IO,\n  });\n  const headScale = 1 + push * 0.014;\n  const subjectScale = 1 + push * 0.04;\n\n  const captionIn = interpolate(frame, [46, 62], [0, 1], {\n    ...CLAMP,\n    easing: EASE_OUT,\n  });\n\n  const disc = H * 0.48;\n  const headTop = H * 0.42;\n  // Disc top lands in the lower x-height so the word stays legible.\n  const discTop = headTop + size * 0.15;\n\n  return (\n    <AbsoluteFill style={{ backgroundColor: c.bg, overflow: \"hidden\" }}>\n      <div\n        style={{\n          position: \"absolute\",\n          left: 0,\n          right: 0,\n          top: headTop,\n          textAlign: \"center\",\n          fontFamily: display,\n          fontWeight: 400,\n          fontSize: size,\n          lineHeight: 1,\n          letterSpacing: `${tracking}em`,\n          color: c.fg,\n          whiteSpace: \"nowrap\",\n          transform: `translate(${headX}px, calc(-50% + ${headY}px)) scale(${headScale})`,\n          transformOrigin: \"50% 60%\",\n        }}\n      >\n        {title}\n      </div>\n\n      {src ? (\n        <Img\n          src={src}\n          style={{\n            position: \"absolute\",\n            left: \"50%\",\n            bottom: 0,\n            height: H * 0.84,\n            objectFit: \"contain\",\n            transform: `translate(-50%, ${subjectY}px) scale(${subjectScale})`,\n            transformOrigin: \"50% 100%\",\n            filter: `drop-shadow(0 ${H * 0.03}px ${H * 0.05}px ${c.shadow})`,\n          }}\n        />\n      ) : (\n        <div\n          style={{\n            position: \"absolute\",\n            left: (W - disc) / 2,\n            top: discTop,\n            width: disc,\n            height: disc,\n            borderRadius: \"50%\",\n            background: meshFill(frame / 120, accent),\n            transform: `translateY(${subjectY}px) scale(${subjectScale})`,\n            transformOrigin: \"50% 40%\",\n          }}\n        />\n      )}\n\n      {showLogo || caption ? (\n        <div\n          style={{\n            position: \"absolute\",\n            left: H * 0.08,\n            bottom: H * 0.07,\n            display: \"flex\",\n            alignItems: \"baseline\",\n            gap: H * 0.018,\n            opacity: captionIn,\n            transform: `translateY(${(1 - captionIn) * H * 0.01}px)`,\n          }}\n        >\n          {showLogo ? <RemocnLogo fontSize={H * 0.032} color={c.fg} /> : null}\n          {showLogo && caption ? (\n            <div\n              style={{\n                width: 1,\n                height: H * 0.024,\n                alignSelf: \"center\",\n                backgroundColor: c.muted,\n                opacity: 0.6,\n              }}\n            />\n          ) : null}\n          {caption ? (\n            <div\n              style={{\n                fontFamily: sans,\n                fontWeight: 500,\n                fontSize: H * 0.028,\n                letterSpacing: \"-0.01em\",\n                lineHeight: 1,\n                color: c.muted,\n              }}\n            >\n              {caption}\n            </div>\n          ) : null}\n        </div>\n      ) : null}\n    </AbsoluteFill>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/depth-headline.tsx"
    }
  ],
  "type": "registry:component"
}
