Some checks are pending
Deploy to Cloudflare Workers (OpenNext) / deploy (push) Waiting to run
Use mainwhite.svg on white sections with curvy green transitions into flat green bands, improve text and button contrast, and deploy via OpenNext on Cloudflare Workers. Co-authored-by: Cursor <cursoragent@cursor.com>
75 lines
2.4 KiB
TypeScript
75 lines
2.4 KiB
TypeScript
"use client";
|
|
|
|
import { useMemo } from "react";
|
|
import { mixHex } from "@/lib/rift-colors";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
const GREEN = "#1a5c38";
|
|
const GOLD = "#ffb300";
|
|
const BLUE = "#1f3d7e";
|
|
|
|
/** 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>
|
|
);
|
|
}
|