diff --git a/public/earthquake.mp3 b/public/earthquake.mp3 new file mode 100644 index 0000000..fab783c Binary files /dev/null and b/public/earthquake.mp3 differ diff --git a/src/app/contact-us/page.tsx b/src/app/contact-us/page.tsx index 68e9abd..33167f7 100644 --- a/src/app/contact-us/page.tsx +++ b/src/app/contact-us/page.tsx @@ -248,7 +248,7 @@ const ContactUs = () => { style={{ cursor: "pointer" }} > Instagram - Logo + Logo {/* Facebook: Pulsating Map */} (null); - // LinkedIn easter egg + // Instagram sound + const earthquakeAudio = useRef(null); + + // LinkedIn Shake Easter Egg const [shaking, setShaking] = useState(false); const shakeTimeout = useRef(null); - // x easter egg + // X Logo Full-Page Crack & Spin Easter Egg const [showCracks, setShowCracks] = useState(false); - const [collapse, setCollapse] = useState(false); - const crackTimeout = useRef(null); + const [crackOverlayActive, setCrackOverlayActive] = useState(false); - // Lava flood handler (top-down flood) + // Lava flood & sound handler const handleInstagramClick = useCallback((e: React.MouseEvent) => { e.preventDefault(); setLavaActive(true); + // Play earthquake sound + if (earthquakeAudio.current) { + earthquakeAudio.current.currentTime = 0; + earthquakeAudio.current.play(); + } clearTimeout(lavaTimeout.current); lavaTimeout.current = setTimeout(() => setLavaActive(false), 2000); }, []); // LinkedIn shake handler - const handleLinkedInClick = useCallback((e: React.MouseEvent) => { - e.preventDefault(); - if (shaking) return; // prevent stacking - setShaking(true); - const body = document.body; - body.classList.remove("shake-screen"); - void body.offsetWidth; - body.classList.add("shake-screen"); - shakeTimeout.current = setTimeout(() => { - setShaking(false); + const handleLinkedInClick = useCallback( + (e: React.MouseEvent) => { + e.preventDefault(); + if (shaking) return; // prevent stacking + setShaking(true); + const body = document.body; body.classList.remove("shake-screen"); - }, 1000); - }, [shaking]); + void body.offsetWidth; + body.classList.add("shake-screen"); + shakeTimeout.current = setTimeout(() => { + setShaking(false); + body.classList.remove("shake-screen"); + }, 1000); + }, + [shaking] + ); - // X (crack and collapse) handler - const handleXClick = useCallback((e: React.MouseEvent) => { - e.preventDefault(); - setShowCracks(true); - crackTimeout.current = setTimeout(() => { - setCollapse(true); + // X click = crack, spin page, then reset after 2s + const handleXClick = useCallback( + (e: React.MouseEvent) => { + e.preventDefault(); + if (crackOverlayActive) return; + setShowCracks(true); + setCrackOverlayActive(true); + document.body.classList.remove("body-spin-back"); + document.body.classList.add("body-cracked"); setTimeout(() => { - setShowCracks(false); - setCollapse(false); - }, 1500); - }, 1000); - }, []); + document.body.classList.remove("body-cracked"); + document.body.classList.add("body-spin-back"); + setTimeout(() => { + setShowCracks(false); + setCrackOverlayActive(false); + document.body.classList.remove("body-spin-back"); + }, 200); + }, 2000); + }, + [crackOverlayActive] + ); + // Clean up classes and timeouts on unmount React.useEffect(() => { return () => { clearTimeout(lavaTimeout.current); clearTimeout(shakeTimeout.current); - clearTimeout(crackTimeout.current); document.body.classList.remove("shake-screen"); + document.body.classList.remove("body-cracked"); + document.body.classList.remove("body-spin-back"); }; }, []); return ( <> + {/* Hidden audio element */} +
-
- TremorTracker logo -
+
+ TremorTracker logo +
© TremorTracker 2025 @@ -167,7 +186,14 @@ export default function BottomFooter() { style={{ cursor: "pointer" }} aria-label="X Crack Easter egg" > - X + + X +