Antaram's picture
Upload 26 files
35a92dd verified
import React, { useRef, useEffect, useState, useMemo } from 'react';
interface HeroOverlayProps {
visible: boolean;
smoothScrollRef: React.MutableRefObject<number>;
shiftRef: React.MutableRefObject<number>;
shapeMode: string;
isMobile: boolean;
}
// --- OPTIMIZED ANIMATION COMPONENT ---
// Memoized to prevent unnecessary re-renders when parent state changes (like the clock)
const CinematicReveal = React.memo(({ text, delay = 0, visible, className }: { text: string; delay?: number; visible: boolean; className?: string }) => {
return (
<span className={`inline-block whitespace-nowrap ${className}`}>
{text.split('').map((char, i) => (
<span
key={i}
style={{
transitionDelay: `${delay + (i * 35)}ms`,
transitionDuration: '1000ms',
transitionTimingFunction: 'cubic-bezier(0.2, 0.65, 0.3, 0.9)',
}}
className={`inline-block transition-all will-change-transform ${
visible
? 'opacity-100 translate-y-0 filter-none scale-100'
: 'opacity-0 translate-y-[100%] blur-sm scale-110'
}`}
>
{char === " " ? "\u00A0" : char}
</span>
))}
</span>
);
});
export const HeroOverlay: React.FC<HeroOverlayProps> = ({ visible, smoothScrollRef, shiftRef, shapeMode, isMobile }) => {
// Refs for direct DOM manipulation (High Performance)
const contentRef = useRef<HTMLDivElement>(null);
const blurRef = useRef<HTMLDivElement>(null);
// State for Live Date
const [dateTime, setDateTime] = useState({ day: '', date: '' });
// --- LIVE DATE LOGIC ---
useEffect(() => {
const updateTime = () => {
const now = new Date();
// Format: "SATURDAY"
const day = now.toLocaleDateString('en-US', { weekday: 'long' }).toUpperCase();
// Format: "DEC 20 2025"
const date = now.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }).toUpperCase().replace(',', '');
setDateTime({ day, date });
};
updateTime();
// Update every minute (efficient, no need for second-by-second ticking here)
const timer = setInterval(updateTime, 60000);
return () => clearInterval(timer);
}, []);
const getStatus = () => {
if (shapeMode === 'triangle') return 'AWAITING INPUT...';
if (shapeMode === 'explode') return 'PROCESSING DATA...';
return 'SYSTEM ONLINE';
};
const getStatusColor = () => {
if (shapeMode === 'triangle') return 'text-red-500';
if (shapeMode === 'explode') return 'text-blue-400';
return 'text-emerald-500';
};
// --- SCROLL LOOP (GPU OPTIMIZED) ---
useEffect(() => {
let frameId: number;
const update = () => {
if (!visible) return;
const y = smoothScrollRef.current;
const h = window.innerHeight;
const processItem = (ref: React.RefObject<HTMLDivElement>, type: 'text' | 'bg', start: number, fade: number = 200) => {
if (!ref.current) return;
let opacity = 0;
let transY = 0;
let scale = 1;
// Logic: Everything fades out as you scroll down
if (y < start + fade) {
opacity = 1 - (y / (start + fade));
// Only move/scale the text layer, keep the background fixed so it just fades
if (type === 'text') {
transY = -y * 0.5;
scale = 1 - (y / (start + fade)) * 0.05;
}
} else {
opacity = 0;
}
ref.current.style.opacity = Math.max(0, opacity).toFixed(3);
if (type === 'text') {
ref.current.style.transform = `translate3d(0, ${transY.toFixed(3)}px, 0) scale(${scale.toFixed(3)})`;
}
};
// Apply to Content (Text): Fades and moves up
processItem(contentRef, 'text', 0, 0.8 * h);
// Apply to Blur Layer: Fades out slightly faster to reveal content below
processItem(blurRef, 'bg', 0, 0.7 * h);
// Globe Lateral Shifts Logic
const SHIFT = isMobile ? 0 : 5.5;
let tx = 0;
if (!isMobile) {
if (y > 0.8 * h && y < 2.0 * h) tx = SHIFT;
}
if (shiftRef) shiftRef.current = tx;
frameId = requestAnimationFrame(update);
};
update();
return () => cancelAnimationFrame(frameId);
}, [visible, smoothScrollRef, shiftRef, isMobile]);
return (
<div className={`fixed inset-0 z-20 pointer-events-none transition-opacity duration-1000 ${visible ? 'opacity-100' : 'opacity-0'}`}>
{/*
FULL SCREEN BLUR LAYER
- inset-0: Covers the whole screen.
- backdrop-blur-[2px]: Subtle glass effect.
- bg-black/5: Slight tint for readability.
- Fades out on scroll via blurRef.
*/}
<div
ref={blurRef}
className="absolute inset-0 bg-black/5 backdrop-blur-[2px] -z-10"
/>
{/* Hero Content Wrapper */}
<div ref={contentRef} className="absolute inset-0 flex flex-col justify-center px-6 md:px-12 pointer-events-none">
{/* Content Container - Left Aligned */}
<div className="w-full max-w-[95%] md:max-w-4xl mr-auto relative z-10 text-left">
{/* Live Date & Day Tags */}
<div className={`flex flex-row items-start justify-start gap-3 mb-8 md:mb-6 transition-opacity duration-1000 delay-500 ${visible ? 'opacity-50' : 'opacity-0'}`}>
<span className="text-[9px] md:text-[10px] font-mono border border-white/30 px-2 py-0.5 rounded-full uppercase tracking-widest text-white">
{dateTime.day || "LOADING..."}
</span>
<span className="text-[9px] md:text-[10px] font-mono border border-white/30 px-2 py-0.5 rounded-full uppercase tracking-widest text-white">
{dateTime.date || "..."}
</span>
</div>
{/* Main Headline */}
<h1 className="flex flex-col gap-1 md:gap-2 text-white/90 leading-[1.0] md:leading-[0.85]">
<span className="text-[11vw] md:text-[8rem] lg:text-[9rem] font-bold md:font-medium tracking-tighter mix-blend-screen overflow-hidden text-left">
<CinematicReveal text="DESIGNING" visible={visible} delay={100} />
</span>
<span className="text-[11vw] md:text-[8rem] lg:text-[9rem] font-serif italic text-red-500 mix-blend-screen -mt-2 md:-mt-4 overflow-hidden text-left">
<CinematicReveal text="INTELLIGENCE" visible={visible} delay={400} />
</span>
</h1>
{/* Subtext */}
<div className={`mt-8 md:mt-12 flex flex-col md:flex-row items-start justify-start gap-8 transition-all duration-1000 delay-[900ms] ${visible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}>
<div className="h-[1px] w-12 md:w-24 bg-red-500/50 block mt-3"></div>
<p className="text-white/60 max-w-[85%] md:max-w-md font-mono text-xs md:text-sm leading-relaxed text-left mx-0">
We are an advanced R&D collective specializing in high-frequency neural networks and generative interface design.
<span className="block mt-4 text-white/40">
Building the cognitive architecture for the next web.
</span>
</p>
</div>
</div>
</div>
{/* Bottom Status Bar */}
<div className="absolute bottom-0 left-0 w-full p-6 md:p-12 z-40 transition-opacity duration-1000 delay-[1200ms]" style={{ opacity: visible ? 1 : 0 }}>
<div className="w-full border-t border-white/10 pt-4 flex flex-col md:flex-row justify-between items-end gap-4">
<div className="font-mono text-[9px] md:text-[10px] text-white/60 tracking-wider flex items-center gap-2">
<span className="text-red-500"></span>
<span>{shapeMode === 'triangle' ? 'EXEC: NEURAL_VOICE_PROTOCOL' : 'EXEC: TRIANGLE_MAIN_LOOP'}</span>
<span className="w-1.5 h-3 bg-red-500/80 animate-pulse ml-1"></span>
</div>
<div className="flex gap-6 font-mono text-[9px] text-white/30 tracking-widest uppercase md:pr-12">
<div>
<span className="block text-white/10 mb-1">System</span>
<span className={getStatusColor() + " animate-pulse"}>{getStatus()}</span>
</div>
<div className="hidden md:block">
<span className="block text-white/10 mb-1">Latency</span>
<span>12ms</span>
</div>
<div className="hidden md:block">
<span className="block text-white/10 mb-1">Build</span>
<span>v2.0.4-RC</span>
</div>
</div>
</div>
</div>
</div>
)
}