168 lines
5.2 KiB
TypeScript
168 lines
5.2 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { motion } from 'framer-motion';
|
|
|
|
interface GlitchCrashProps {
|
|
onComplete?: () => void;
|
|
}
|
|
|
|
const GlitchCrash = ({ onComplete }: GlitchCrashProps) => {
|
|
const [phase, setPhase] = useState(0);
|
|
const [glitchText, setGlitchText] = useState('');
|
|
|
|
const errorMessages = [
|
|
'BUFFER OVERFLOW DETECTED',
|
|
'STACK SMASHING DETECTED',
|
|
'SEGMENTATION FAULT',
|
|
'MEMORY CORRUPTION',
|
|
'KERNEL PANIC',
|
|
'SYSTEM HALTED',
|
|
'0xDEADBEEF',
|
|
'FATAL ERROR',
|
|
'CORE DUMPED',
|
|
];
|
|
|
|
useEffect(() => {
|
|
const interval = setInterval(() => {
|
|
const chars = '!@#$%^&*()_+-=[]{}|;:,.<>?/~`░▒▓█▀▄▌▐■□▢▣▤▥▦▧▨▩';
|
|
let text = '';
|
|
for (let i = 0; i < 100; i++) {
|
|
text += chars[Math.floor(Math.random() * chars.length)];
|
|
if (i % 20 === 19) text += '\n';
|
|
}
|
|
setGlitchText(text);
|
|
}, 50);
|
|
|
|
const phaseTimer = setInterval(() => {
|
|
setPhase(p => p + 1);
|
|
}, 800);
|
|
|
|
const endTimer = setTimeout(() => {
|
|
onComplete?.();
|
|
}, 8000);
|
|
|
|
return () => {
|
|
clearInterval(interval);
|
|
clearInterval(phaseTimer);
|
|
clearTimeout(endTimer);
|
|
};
|
|
}, [onComplete]);
|
|
|
|
return (
|
|
<motion.div
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
className="fixed inset-0 z-[9999] bg-background overflow-hidden"
|
|
style={{
|
|
animation: 'glitchShake 0.1s infinite',
|
|
}}
|
|
>
|
|
<style>{`
|
|
@keyframes glitchShake {
|
|
0% { transform: translate(0, 0) skew(0deg); }
|
|
20% { transform: translate(-5px, 3px) skew(1deg); }
|
|
40% { transform: translate(5px, -2px) skew(-1deg); }
|
|
60% { transform: translate(-3px, 5px) skew(0.5deg); }
|
|
80% { transform: translate(3px, -5px) skew(-0.5deg); }
|
|
100% { transform: translate(0, 0) skew(0deg); }
|
|
}
|
|
@keyframes glitchColor {
|
|
0% { filter: hue-rotate(0deg) saturate(2) brightness(1.5); }
|
|
25% { filter: hue-rotate(90deg) saturate(3) brightness(2); }
|
|
50% { filter: hue-rotate(180deg) saturate(2) brightness(1); }
|
|
75% { filter: hue-rotate(270deg) saturate(4) brightness(2.5); }
|
|
100% { filter: hue-rotate(360deg) saturate(2) brightness(1.5); }
|
|
}
|
|
@keyframes scanline {
|
|
0% { transform: translateY(-100%); }
|
|
100% { transform: translateY(100vh); }
|
|
}
|
|
`}</style>
|
|
|
|
{/* Glitch color overlay */}
|
|
<div
|
|
className="absolute inset-0 mix-blend-overlay"
|
|
style={{ animation: 'glitchColor 0.3s infinite' }}
|
|
/>
|
|
|
|
{/* Scanlines */}
|
|
<div
|
|
className="absolute inset-0 pointer-events-none"
|
|
style={{
|
|
background: 'repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0,0,0,0.3) 2px, rgba(0,0,0,0.3) 4px)',
|
|
animation: 'scanline 0.5s linear infinite',
|
|
}}
|
|
/>
|
|
|
|
{/* Random noise */}
|
|
<pre className="absolute inset-0 text-primary/30 text-xs overflow-hidden font-mono p-4">
|
|
{glitchText}
|
|
{glitchText}
|
|
{glitchText}
|
|
{glitchText}
|
|
{glitchText}
|
|
</pre>
|
|
|
|
{/* Error messages */}
|
|
<div className="absolute inset-0 flex flex-col items-center justify-center">
|
|
{errorMessages.slice(0, Math.min(phase + 1, errorMessages.length)).map((msg, i) => (
|
|
<motion.div
|
|
key={i}
|
|
initial={{ opacity: 0, x: Math.random() * 200 - 100 }}
|
|
animate={{
|
|
opacity: [0, 1, 1, 0.5],
|
|
x: [Math.random() * 100 - 50, 0, Math.random() * 50 - 25],
|
|
}}
|
|
transition={{ duration: 0.5 }}
|
|
className="font-minecraft text-xl md:text-3xl text-destructive mb-2"
|
|
style={{
|
|
textShadow: '0 0 10px currentColor, 0 0 20px currentColor',
|
|
transform: `rotate(${Math.random() * 10 - 5}deg)`,
|
|
}}
|
|
>
|
|
{msg}
|
|
</motion.div>
|
|
))}
|
|
</div>
|
|
|
|
{/* Final message */}
|
|
{phase > 6 && (
|
|
<motion.div
|
|
initial={{ scale: 0 }}
|
|
animate={{ scale: [0, 1.2, 1] }}
|
|
className="absolute inset-0 flex items-center justify-center"
|
|
>
|
|
<div className="text-center">
|
|
<div className="font-minecraft text-4xl md:text-6xl text-primary text-glow-strong mb-4">
|
|
SYSTEM OVERFLOW
|
|
</div>
|
|
<div className="font-pixel text-lg text-foreground/80">
|
|
You broke the matrix. Congratulations.
|
|
</div>
|
|
<div className="font-pixel text-sm text-foreground/50 mt-4">
|
|
(Refreshing in a moment...)
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
|
|
{/* Glitch bars */}
|
|
{Array.from({ length: 10 }).map((_, i) => (
|
|
<div
|
|
key={i}
|
|
className="absolute bg-primary/50"
|
|
style={{
|
|
left: `${Math.random() * 100}%`,
|
|
top: `${Math.random() * 100}%`,
|
|
width: `${Math.random() * 300 + 50}px`,
|
|
height: `${Math.random() * 20 + 2}px`,
|
|
animation: `glitchShake ${0.1 + Math.random() * 0.2}s infinite`,
|
|
opacity: Math.random(),
|
|
}}
|
|
/>
|
|
))}
|
|
</motion.div>
|
|
);
|
|
};
|
|
|
|
export default GlitchCrash;
|