diff --git a/src/App.tsx b/src/App.tsx index 4605fa9..6d598eb 100755 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useRef, useState, useEffect } from 'react'; import { Terminal } from 'lucide-react'; import TerminalButton from './components/TerminalButton'; import ProfileContent from './components/ProfileContent'; @@ -8,15 +8,31 @@ import SkillsContent from './components/SkillsContent'; import ResumeContent from './components/ResumeContent'; import PostsContent from './components/PostsContent'; +import './styles/sliders.css'; // Import the new sliders CSS + +type SliderRefType = React.RefObject; + function App() { const [activeSection, setActiveSection] = React.useState('about'); const [isBooting, setIsBooting] = React.useState(true); const [bootPhase, setBootPhase] = React.useState(0); + + // New state for sliders + const [greenIntensity, setGreenIntensity] = useState(50); // 0 to 100 + const [glitchIntensity, setGlitchIntensity] = useState(25); // 0 to 100 + + // New state for glitch effects + const [flickerOpacity, setFlickerOpacity] = useState(1); // 1 is normal, less than 1 creates flicker + const [showScanline, setShowScanline] = useState(false); // Controls the high-contrast scanline + const [scanlinePosition, setScanlinePosition] = useState(0); // Position of scanline (0-100%) + + // Refs for the slider thumbs + const greenSliderRef = useRef(null); + const glitchSliderRef = useRef(null); // TV Boot-up sequence React.useEffect(() => { if (!isBooting) return; - // Phase 0: Initial black screen (0ms) // Phase 1: Quick white flash (100ms) // Phase 2: Static noise (600ms) @@ -40,10 +56,188 @@ function App() { }; }, [isBooting]); + // Screen flickering effect based on glitch intensity + useEffect(() => { + if (glitchIntensity <= 30) { + setFlickerOpacity(1); // No flickering + return; + } + + let flickerInterval: number; + const flickerEffect = () => { + // The higher the glitch intensity, the more frequent the flickers + const flickerFrequency = Math.max(300, 1500 - (glitchIntensity * 10)); + + flickerInterval = window.setInterval(() => { + // Intensity affects how dim the screen gets during flickers + const minOpacity = Math.max(0.7, 0.95 - (glitchIntensity / 100) * 0.5); + + // Create random flickering effect + const randomFlicker = Math.random() * (1 - minOpacity) + minOpacity; + setFlickerOpacity(randomFlicker); + + // Reset back to normal after a short delay + setTimeout(() => { + setFlickerOpacity(1); + }, 50 + Math.random() * 100); + }, flickerFrequency); + }; + + flickerEffect(); + + return () => { + clearInterval(flickerInterval); + }; + }, [glitchIntensity]); + + // Horizontal scanline effect for higher glitch intensity + useEffect(() => { + if (glitchIntensity <= 50) { + setShowScanline(false); + return; + } + + let scanlineInterval: number; + const scanlineEffect = () => { + // The higher the intensity, the more frequent the scanline appears + const scanlineFrequency = Math.max(1000, 5000 - (glitchIntensity * 40)); + + scanlineInterval = window.setInterval(() => { + // Show the scanline + setShowScanline(true); + + // Animate the scanline movement + const duration = 300 + Math.random() * 700; // 300-1000ms + const startTime = Date.now(); + + const animateScanline = () => { + const elapsed = Date.now() - startTime; + const progress = Math.min(1, elapsed / duration); + + setScanlinePosition(progress * 100); + + if (progress < 1) { + requestAnimationFrame(animateScanline); + } else { + // Hide the scanline when animation completes + setShowScanline(false); + } + }; + + requestAnimationFrame(animateScanline); + }, scanlineFrequency); + }; + + scanlineEffect(); + + return () => { + clearInterval(scanlineInterval); + }; + }, [glitchIntensity]); + + // Function to handle slider dragging + const handleSliderDrag = ( + event: React.MouseEvent, + sliderRef: SliderRefType, + setValueFn: React.Dispatch> + ) => { + event.preventDefault(); + + if (!sliderRef.current) return; + + const track = sliderRef.current.parentElement; + if (!track) return; + + const trackRect = track.getBoundingClientRect(); + const trackHeight = trackRect.height; + const trackTop = trackRect.top; + + const handleMouseMove = (moveEvent: MouseEvent) => { + const y = moveEvent.clientY; + let percentage = 100 - (((y - trackTop) / trackHeight) * 100); + + // Clamp value between 0 and 100 + percentage = Math.min(100, Math.max(0, percentage)); + + setValueFn(percentage); + }; + + const handleMouseUp = () => { + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', handleMouseUp); + }; + + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', handleMouseUp); + }; + + // Calculate green color based on intensity + const calculateGreenBackground = () => { + // Map the intensity from 0-100 to appropriate color values + const baseIntensity = Math.floor((greenIntensity / 100) * 35); // Max 35 + return { + backgroundColor: `rgba(0, ${baseIntensity}, 0, 0.95)`, + backgroundImage: ` + linear-gradient(0deg, + rgba(0, ${Math.max(5, baseIntensity + 3)}, 0, 1) 0%, + rgba(0, ${Math.max(15, baseIntensity + 10)}, 0, 1) 100%), + radial-gradient( + circle at center, + rgba(0, ${Math.max(20, baseIntensity + 20)}, 0, 1) 0%, + rgba(0, ${baseIntensity}, 0, 1) 100% + ) + ` + }; + }; + + // Calculate glitch effects based on intensity + const calculateGlitchEffects = () => { + const whiteNoiseOpacity = 0.02 + (glitchIntensity / 100) * 0.2; + const chromaticAberrationAmount = (glitchIntensity / 100) * 1; + const scanLinesOpacity = 0.1 + (glitchIntensity / 100) * 1; + + return { + whiteNoiseOpacity, + chromaticAberrationAmount, + scanLinesOpacity + }; + }; + + const glitchEffects = calculateGlitchEffects(); + return (
{/* TV Container with fixed proportions */}
+ {/* Vertical Sliders - Moved outside the TV frame */} +
+ {/* Green Intensity Slider */} +
+
+
handleSliderDrag(e, greenSliderRef, setGreenIntensity)} + >
+
+ Green +
+ + {/* Glitch Intensity Slider */} +
+
+
handleSliderDrag(e, glitchSliderRef, setGlitchIntensity)} + >
+
+ Glitch +
+
+ {/* TV Frame */}
{/* TV frame texture overlay */} @@ -87,16 +281,48 @@ function App() { )} - {/* Static noise texture underlay */} -
- - {/* Screen Content with fixed height */} -
+ {/* Static noise texture underlay - controlled by glitch slider */} +
+ + {/* Screen opacity flicker effect */} +
+ + {/* High-contrast horizontal scanline for high glitch intensity */} + {showScanline && ( +
+ )} + + {/* Screen Content with fixed height - controlled by green slider */} +
echo "Hey there!"
- {/* Split Screen Container with fixed height */}
{/* Left Column - Navigation */} @@ -138,10 +364,8 @@ function App() { SHELL
- {/* Vertical Separator with embossed effect */}
- {/* Right Column - Content with scrolling */}
{activeSection === 'about' && } @@ -155,30 +379,45 @@ function App() {
- - {/* Enhanced Scan Lines Effect */} -
- - {/* Chromatic Aberration Effect */} -
- + {/* Enhanced Scan Lines Effect - controlled by glitch slider */} +
+ + {/* Chromatic Aberration Effect - controlled by glitch slider */} +
+ {/* Multiple Glass Reflection Layers */}
- {/* Screen Glare - Moving reflection */}
- {/* TV Controls - Skeuomorphic Knobs */}
- {/* TV Speaker Grills - Enhanced */}
{[...Array(10)].map((_, i) => ( @@ -191,7 +430,6 @@ function App() { >
))}
- {/* TV Brand Label */}
- {/* Power indicator light */}