GRV-Summit-Site/components/brand/RiftPulseField.tsx
kirukib cb404ec079
Some checks failed
Deploy to Cloudflare Workers (OpenNext) / deploy (push) Has been cancelled
Align site colors with GRV brand book palette.
Centralize primary, secondary, tertiary, and neutral tokens and apply them across theme variables and UI components.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 14:45:22 +03:00

77 lines
2.5 KiB
TypeScript

"use client";
import { useMemo } from "react";
import { mixHex } from "@/lib/rift-colors";
import { cn } from "@/lib/utils";
import { BRAND_COLORS } from "@/content/brand-colors";
const GREEN: string = BRAND_COLORS.primary;
const GOLD: string = BRAND_COLORS.secondary;
const BLUE: string = BRAND_COLORS.tertiary;
/** Long curved paths that pulse across the page background */
const PULSE_CURVES = [
"M -80 120 Q 280 80, 520 140 T 1040 100 T 1400 160",
"M -60 280 Q 320 240, 580 300 T 1100 260 T 1500 320",
"M -100 440 Q 260 400, 500 460 T 980 420 T 1380 480",
"M -40 600 Q 300 560, 620 620 T 1080 580 T 1520 640",
"M -120 180 Q 200 220, 480 160 T 920 200 T 1320 140",
"M -80 520 Q 340 480, 640 540 T 1020 500 T 1480 560",
"M -60 720 Q 400 680, 720 740 T 1140 700 T 1600 760",
"M -100 860 Q 280 820, 560 880 T 1000 840 T 1440 900",
] as const;
type Props = {
progress: number;
scrollY: number;
reduceMotion: boolean;
};
export function RiftPulseField({ progress, scrollY, reduceMotion }: Props) {
const t = Math.max(0, Math.min(1, progress));
const wave = 0.5 - 0.5 * Math.cos(t * Math.PI * 2);
const primary = useMemo(() => {
if (t < 0.33) return mixHex(GREEN, GOLD, t / 0.33);
if (t < 0.66) return mixHex(GOLD, BLUE, (t - 0.33) / 0.33);
return mixHex(BLUE, GREEN, (t - 0.66) / 0.34);
}, [t]);
const accent = useMemo(() => mixHex(GOLD, primary, 0.35 + wave * 0.2), [primary, wave]);
const yShift = reduceMotion ? 0 : scrollY * 0.04;
const drawOffset = reduceMotion ? 0 : Math.max(0, 0.92 - progress * 1.1);
return (
<svg
className="rift-pulse-field pointer-events-none absolute inset-0 h-full w-full"
viewBox="0 0 1280 1000"
preserveAspectRatio="xMidYMid slice"
aria-hidden
style={{
transform: `translate3d(0, ${yShift}px, 0)`,
opacity: 0.35 + progress * 0.4,
}}
>
<g fill="none" strokeLinecap="round">
{PULSE_CURVES.map((d, i) => (
<path
key={i}
pathLength={1}
d={d}
stroke={i % 2 === 0 ? primary : accent}
strokeWidth={0.8 + (i % 3) * 0.2}
className={cn("rift-pulse-line", !reduceMotion && "rift-pulse-animate")}
style={{
animationDelay: `${i * 0.55}s`,
strokeDasharray: 1,
strokeDashoffset: drawOffset,
transition: "stroke 0.85s ease, stroke-dashoffset 0.3s ease-out",
}}
/>
))}
</g>
</svg>
);
}