File size: 8,945 Bytes
35a92dd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
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>
  )
}