Files
watching/src/App.tsx
T
2026-05-19 02:14:56 +00:00

330 lines
12 KiB
TypeScript

import { useEffect, useRef, useState } from "react";
import type { JSX } from "react";
const REDIRECT_URL: string = "https://meet.google.com";
interface ScheduleFn {
(): number;
}
interface Refs {
eyeRef: React.RefObject<HTMLDivElement | null>;
pupilRef: React.RefObject<SVGGElement | null>;
}
export default function WatchingYou(): JSX.Element {
const eyeRef = useRef<HTMLDivElement | null>(null);
const pupilRef = useRef<SVGGElement | null>(null);
const [blinking, setBlinking] = useState<boolean>(false);
const [glitching, setGlitching] = useState<boolean>(false);
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
if (!eyeRef.current || !pupilRef.current) return;
const rect = eyeRef.current.getBoundingClientRect();
const cx = rect.left + rect.width / 2;
const cy = rect.top + rect.height / 2;
const dx = e.clientX - cx;
const dy = e.clientY - cy;
const angle = Math.atan2(dy, dx);
const dist = Math.min(Math.hypot(dx, dy), 28);
pupilRef.current.style.transform = `translate(${Math.cos(angle) * dist}px, ${Math.sin(angle) * dist}px)`;
};
window.addEventListener("mousemove", handleMouseMove);
return () => window.removeEventListener("mousemove", handleMouseMove);
}, []);
useEffect(() => {
const scheduleBlink: ScheduleFn = () => {
const delay: number = 2500 + Math.random() * 3000;
return window.setTimeout(() => {
setBlinking(true);
setTimeout(() => {
setBlinking(false);
blink = scheduleBlink();
}, 180);
}, delay);
};
let blink: number = scheduleBlink();
return () => clearTimeout(blink);
}, []);
useEffect(() => {
const scheduleGlitch: ScheduleFn = () => {
const delay: number = 4000 + Math.random() * 6000;
return window.setTimeout(() => {
setGlitching(true);
setTimeout(() => {
setGlitching(false);
glitch = scheduleGlitch();
}, 400);
}, delay);
};
let glitch: number = scheduleGlitch();
return () => clearTimeout(glitch);
}, []);
const handleRedirect = (): void => {
window.location.href = REDIRECT_URL;
};
return (
<div style={{ minHeight: "100vh", background: "#080808", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", overflow: "hidden", position: "relative", userSelect: "none" }}>
<style>{`
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&family=Merriweather:wght@300;400;700&display=swap');
/* Use readable, modern fonts */
.font-fraktur { font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; }
.font-fell { font-family: 'Merriweather', Georgia, 'Times New Roman', serif; }
.scanlines::after {
content: '';
position: absolute;
inset: 0;
background: repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(0,0,0,0.08) 2px,
rgba(0,0,0,0.08) 4px
);
pointer-events: none;
}
@keyframes flicker {
0%, 95%, 100% { opacity: 1; }
96% { opacity: 0.85; }
97% { opacity: 1; }
98% { opacity: 0.9; }
}
@keyframes pulse-red {
0%, 100% { filter: drop-shadow(0 0 12px #cc0000aa); }
50% { filter: drop-shadow(0 0 28px #ff0000cc) drop-shadow(0 0 60px #cc000066); }
}
@keyframes glitch-shift {
0% { transform: translateX(0); clip-path: inset(0 0 100% 0); }
20% { transform: translateX(-4px); clip-path: inset(20% 0 60% 0); }
40% { transform: translateX(4px); clip-path: inset(60% 0 20% 0); }
60% { transform: translateX(-2px); clip-path: inset(40% 0 40% 0); }
80% { transform: translateX(0); clip-path: inset(10% 0 80% 0); }
100% { transform: translateX(0); clip-path: inset(0 0 100% 0); }
}
@keyframes vignette-pulse {
0%, 100% { opacity: 0.7; }
50% { opacity: 1; }
}
.eye-container {
animation: pulse-red 3s ease-in-out infinite, flicker 8s linear infinite;
}
.upper-lid {
transform-box: fill-box;
transform-origin: center bottom;
transition: transform 0.1s ease-in-out;
}
.lower-lid {
transform-box: fill-box;
transform-origin: center top;
transition: transform 0.1s ease-in-out;
}
.glitch-text::before,
.glitch-text::after {
content: attr(data-text);
position: absolute;
top: 0; left: 0;
width: 100%;
}
.glitch-text::before {
color: #ff0000;
animation: glitch-shift 0.4s steps(1) forwards;
}
.glitch-text::after {
color: #00ffff22;
animation: glitch-shift 0.4s steps(1) reverse forwards;
}
.btn-horror {
position: relative;
overflow: hidden;
background: transparent;
letter-spacing: 0.15em;
transition: all 0.2s ease;
cursor: pointer;
}
.btn-horror::before {
content: '';
position: absolute;
inset: 0;
background: #cc0000;
transform: scaleX(0);
transform-origin: left;
transition: transform 0.25s ease;
z-index: 0;
}
.btn-horror span {
position: relative;
z-index: 1;
}
.btn-horror:hover::before { transform: scaleX(1); }
.btn-horror:hover { color: #fff !important; border-color: #cc0000 !important; }
.btn-horror:active { transform: scale(0.97); }
@keyframes float-in {
from { opacity: 0; transform: translateY(30px); }
to { opacity: 1; transform: translateY(0); }
}
.animate-float-in { animation: float-in 1.2s ease forwards; }
.delay-1 { animation-delay: 0.4s; opacity: 0; }
.delay-2 { animation-delay: 0.8s; opacity: 0; }
.delay-3 { animation-delay: 1.2s; opacity: 0; }
.delay-4 { animation-delay: 1.6s; opacity: 0; }
`}</style>
{/* Vignette overlay */}
<div
style={{
pointerEvents: "none", position: "fixed", inset: 0, zIndex: 10,
background: "radial-gradient(ellipse at center, transparent 30%, rgba(0,0,0,0.85) 100%)",
animation: "vignette-pulse 4s ease-in-out infinite",
}}
/>
{/* Scanlines overlay */}
<div className="scanlines" style={{ pointerEvents: "none", position: "fixed", inset: 0, zIndex: 10 }} />
{/* Content */}
<div style={{ position: "relative", zIndex: 20, display: "flex", flexDirection: "column", alignItems: "center", gap: "1.25rem", padding: "2rem 2rem", textAlign: "center" }}>
{/* Eye SVG */}
<div className="eye-container animate-float-in" ref={eyeRef}>
<svg width="180" height="120" viewBox="-90 -60 180 120" xmlns="http://www.w3.org/2000/svg">
<defs>
<radialGradient id="irisGrad" cx="40%" cy="35%">
<stop offset="0%" stopColor="#ff3333" />
<stop offset="50%" stopColor="#8b0000" />
<stop offset="100%" stopColor="#2a0000" />
</radialGradient>
<radialGradient id="scleraGrad" cx="50%" cy="40%">
<stop offset="0%" stopColor="#f5e6e6" />
<stop offset="100%" stopColor="#c9b0b0" />
</radialGradient>
<clipPath id="eyeClip">
<path d="M-80,0 Q-40,-55 0,-55 Q40,-55 80,0 Q40,55 0,55 Q-40,55 -80,0 Z" />
</clipPath>
</defs>
{/* Sclera */}
<path
d="M-80,0 Q-40,-55 0,-55 Q40,-55 80,0 Q40,55 0,55 Q-40,55 -80,0 Z"
fill="url(#scleraGrad)"
/>
{/* Iris + pupil group (mouse-tracked) */}
<g clipPath="url(#eyeClip)">
<g ref={pupilRef} style={{ transition: "transform 0.08s ease-out" }}>
<circle cx="0" cy="0" r="32" fill="url(#irisGrad)" />
{/* Iris detail rings */}
<circle cx="0" cy="0" r="28" fill="none" stroke="#6b000088" strokeWidth="1.5" />
<circle cx="0" cy="0" r="22" fill="none" stroke="#9b000066" strokeWidth="1" />
{/* Pupil */}
<circle cx="0" cy="0" r="14" fill="#050000" />
{/* Catchlight */}
<circle cx="-7" cy="-7" r="4" fill="rgba(255,255,255,0.35)" />
</g>
</g>
{/* Eyelids (blink) — filled half-shapes scale from center line */}
<path
className="upper-lid"
d="M-80,0 Q-40,-55 0,-55 Q40,-55 80,0 Z"
fill="#080808"
style={{ transform: blinking ? "scaleY(1)" : "scaleY(0)" }}
/>
<path
className="lower-lid"
d="M-80,0 Q-40,55 0,55 Q40,55 80,0 Z"
fill="#080808"
style={{ transform: blinking ? "scaleY(1)" : "scaleY(0)" }}
/>
{/* Eyelash hints */}
<path
d="M-80,0 Q-40,-55 0,-55 Q40,-55 80,0"
fill="none"
stroke="#1a0a0a"
strokeWidth="4"
strokeLinecap="round"
/>
<path
d="M-80,0 Q-40,55 0,55 Q40,55 80,0"
fill="none"
stroke="#1a0a0a"
strokeWidth="4"
strokeLinecap="round"
/>
</svg>
</div>
{/* Main heading */}
<div
className={`relative animate-float-in delay-1 ${glitching ? "glitch-text" : ""}`}
data-text="I'm Watching You,"
>
<h1 className="font-fraktur leading-tight" style={{ fontSize: "clamp(2.2rem, 6vw, 4rem)", color: "#ff4444" }}>
I'm Watching You,
</h1>
</div>
{/* Name */}
<div
className={`relative animate-float-in delay-2 ${glitching ? "glitch-text" : ""}`}
style={{ marginTop: "-0.5rem" }}
data-text="Aariz."
>
<h2
className="font-fraktur"
style={{ fontSize: "clamp(3rem, 10vw, 6.5rem)", lineHeight: 1, color: "#ff2222", textShadow: "0 0 40px #cc000099" }}
>
Aariz.
</h2>
</div>
{/* Subtitle */}
<p
className="font-fell uppercase animate-float-in delay-3"
style={{ letterSpacing: "0.3em", fontSize: "0.8rem", color: "#cc6666" }}
>
Every move. Every click. Every breath.
</p>
{/* Buttons */}
<div style={{ display: "flex", flexWrap: "wrap", gap: "1rem", marginTop: "0.5rem", justifyContent: "center" }} className="animate-float-in delay-4">
<button
onClick={handleRedirect}
className="btn-horror font-fell"
style={{ color: "#ff4444", border: "1px solid #cc0000", padding: "0.75rem 2rem", fontSize: "0.8rem", textTransform: "uppercase", letterSpacing: "0.15em" }}
>
<span>Beg for Forgiveness</span>
</button>
<button
onClick={handleRedirect}
className="btn-horror font-fell"
style={{ color: "#cc4444", border: "1px solid #6b1515", padding: "0.75rem 2rem", fontSize: "0.8rem", textTransform: "uppercase", letterSpacing: "0.15em" }}
>
<span>Accept Your Fate</span>
</button>
</div>
{/* Footer whisper */}
<p className="font-fell animate-float-in delay-4" style={{ letterSpacing: "0.2em", fontSize: "0.75rem", color: "#884444", marginTop: "0.5rem" }}>
There is no escape.
</p>
</div>
</div>
);
}