← back to Nineoh Guide

apps/web/components/HeroArt.tsx

73 lines

/**
 * Original hero artwork — a stylized Beverly Hills dusk (art-deco sun, palm
 * silhouettes, stars). Entirely our own vector art: no show imagery, logos, or
 * key art. Motion comes from the .palm / .star CSS keyframes in globals.css.
 */
export function HeroArt() {
  return (
    <svg
      className="art"
      viewBox="0 0 1000 500"
      preserveAspectRatio="xMidYMax slice"
      aria-hidden="true"
    >
      <defs>
        <radialGradient id="sun" cx="50%" cy="72%" r="42%">
          <stop offset="0%" stopColor="#ffe6a8" />
          <stop offset="45%" stopColor="#ffcf72" />
          <stop offset="100%" stopColor="#ff9a63" stopOpacity="0" />
        </radialGradient>
        <linearGradient id="palm" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor="#2a1526" />
          <stop offset="100%" stopColor="#120a12" />
        </linearGradient>
      </defs>

      {/* sun disc + deco rays */}
      <g>
        <circle cx="500" cy="360" r="150" fill="url(#sun)" />
        <g stroke="#ffd27a" strokeOpacity="0.35" strokeWidth="2">
          {Array.from({ length: 13 }).map((_, i) => {
            const a = (Math.PI / 12) * i;
            const x = 500 + Math.cos(a) * 175;
            const y = 360 - Math.sin(a) * 175;
            const x2 = 500 + Math.cos(a) * 230;
            const y2 = 360 - Math.sin(a) * 230;
            return <line key={i} x1={x} y1={y} x2={x2} y2={y2} />;
          })}
        </g>
      </g>

      {/* stars */}
      {[
        [120, 70], [230, 40], [360, 90], [700, 55], [820, 95], [900, 45], [60, 130],
      ].map(([cx, cy], i) => (
        <circle key={i} className="star" cx={cx} cy={cy} r="2.2" fill="#fff3d6" style={{ animationDelay: `${i * 0.5}s` }} />
      ))}

      {/* palm silhouettes */}
      <PalmLeft />
      <PalmRight />

      {/* horizon ground */}
      <rect x="0" y="470" width="1000" height="30" fill="#120a12" />
    </svg>
  );
}

function PalmLeft() {
  return (
    <g className="palm" style={{ transformBox: "fill-box", transformOrigin: "bottom" }}>
      <path d="M120 480 C126 400 132 330 128 300 C150 320 150 300 118 292 C150 280 150 262 120 286 C146 254 130 244 112 282 C120 246 96 250 106 290 C86 264 74 286 108 300 C78 300 78 322 112 302 C104 360 110 420 108 480 Z" fill="url(#palm)" />
    </g>
  );
}

function PalmRight() {
  return (
    <g className="palm" style={{ transformBox: "fill-box", transformOrigin: "bottom", animationDelay: "1.5s" }}>
      <path d="M885 480 C879 400 873 330 877 300 C855 320 855 300 887 292 C855 280 855 262 885 286 C859 254 875 244 893 282 C885 246 909 250 899 290 C919 264 931 286 897 300 C927 300 927 322 893 302 C901 360 895 420 897 480 Z" fill="url(#palm)" />
    </g>
  );
}