Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
5c4ccdc
Update dependency lint-staged to v16.3.2 (#787)
renovate[bot] Mar 4, 2026
98bca43
Update dependency posthog-js to v1.358.0 (#786)
renovate[bot] Mar 4, 2026
7316e71
Update dependency framer-motion to v12.35.0 (#789)
renovate[bot] Mar 4, 2026
7332ae2
Update dependency lucide-react to ^0.577.0 (#790)
renovate[bot] Mar 4, 2026
0f2e6a7
Update dependency posthog-js to v1.358.1 (#791)
renovate[bot] Mar 5, 2026
ea8103b
Update dependency posthog-node to v5.27.1 (#792)
renovate[bot] Mar 5, 2026
edce22f
Update dependency posthog-node to v5.28.0 (#793)
renovate[bot] Mar 5, 2026
93a79db
Update dependency posthog-js to v1.359.0 (#794)
renovate[bot] Mar 6, 2026
7b6159f
Update dependency @types/node to v24.12.0 (#795)
renovate[bot] Mar 6, 2026
fcb66d1
Update dependency posthog-js to v1.359.1 (#796)
renovate[bot] Mar 6, 2026
0250ccd
Update dependency eslint to v9.39.4 (#797)
renovate[bot] Mar 7, 2026
1ee4c56
Update dependency knip to v5.86.0 (#798)
renovate[bot] Mar 7, 2026
04418fd
Update dependency framer-motion to v12.35.1 (#799)
renovate[bot] Mar 7, 2026
b679756
Added konami code easter egg + retheme memory game to match current t…
Prakhar6 Mar 8, 2026
f5d3ba4
Added accidently removed imports back
Prakhar6 Mar 8, 2026
9d8076c
Update dependency framer-motion to v12.35.2 (#801)
renovate[bot] Mar 9, 2026
355e0b3
Update dependency posthog-js to v1.360.0 (#802)
renovate[bot] Mar 9, 2026
0fba545
Update dependency lint-staged to v16.3.3 (#803)
renovate[bot] Mar 10, 2026
a281023
Update dependency @posthog/nextjs-config to v1.8.20 (#806)
renovate[bot] Mar 11, 2026
d3f3eb9
Update dependency posthog-js to v1.360.1 (#807)
renovate[bot] Mar 11, 2026
71cfbbc
Update dependency posthog-node to v5.28.1 (#808)
renovate[bot] Mar 12, 2026
2a7ae80
Update dependency framer-motion to v12.36.0 (#809)
renovate[bot] Mar 12, 2026
d0988c7
Merge pull request #800 from Hack-PSU/konami_easter_egg
joeboppell Mar 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"@mui/icons-material": "^6.0.0",
"@mui/material": "^6.4.4",
"@next/third-parties": "^16.0.0",
"@posthog/nextjs-config": "1.8.19",
"@posthog/nextjs-config": "1.8.20",
"@radix-ui/react-avatar": "^1.1.10",
"@radix-ui/react-checkbox": "^1.3.2",
"@radix-ui/react-dialog": "^1.1.14",
Expand All @@ -45,15 +45,15 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"eslint": "9.39.3",
"eslint": "9.39.4",
"eslint-config-next": "16.1.6",
"firebase": "^12.0.0",
"form-data": "^4.0.0",
"framer-motion": "^12.0.0",
"ics": "^3.8.1",
"jwt-decode": "^4.0.0",
"lint-staged": "^16.0.0",
"lucide-react": "^0.576.0",
"lucide-react": "^0.577.0",
"luxon": "^3.4.2",
"next": "16.1.6",
"posthog-js": "^1.257.0",
Expand Down
46 changes: 44 additions & 2 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client";
import { useEffect, useState } from "react";
import { motion, useScroll, useTransform } from "framer-motion";
import { useEffect, useState, useRef } from "react";
import Hero from "@/components/Hero";
import Schedule from "@/components/Schedule";
import FAQRules from "@/components/FAQRules";
Expand All @@ -11,9 +10,25 @@ import Sponsors from "@/components/Sponsors";
import Footer from "@/components/Footer";
import InfoSections from "@/components/InfoSections";
import PhotoGallery from "@/components/PhotoGallery";
import MemoryGame from "@/components/MemoryGame";

const KONAMI_SEQUENCE = [
"ArrowUp",
"ArrowUp",
"ArrowDown",
"ArrowDown",
"ArrowLeft",
"ArrowRight",
"ArrowLeft",
"ArrowRight",
"b",
"a",
];

export default function Home() {
const [isMobile, setIsMobile] = useState(false);
const [showMemoryGame, setShowMemoryGame] = useState(false);
const konamiIndexRef = useRef(0);

useEffect(() => {
const checkMobile = () => {
Expand All @@ -25,8 +40,35 @@ export default function Home() {
return () => window.removeEventListener("resize", checkMobile);
}, []);

// ↑↑↓↓←→←→BA to open the memory game
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
const target = e.target as HTMLElement;
if (target?.closest?.("input, textarea") || target?.getAttribute?.("contenteditable") === "true") {
return;
}
const expected = KONAMI_SEQUENCE[konamiIndexRef.current];
const key = e.key;
if (key === expected) {
konamiIndexRef.current += 1;
if (konamiIndexRef.current === KONAMI_SEQUENCE.length) {
setShowMemoryGame(true);
konamiIndexRef.current = 0;
}
} else {
konamiIndexRef.current = 0;
}
};
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
}, []);

return (
<>
<MemoryGame
isOpen={showMemoryGame}
onClose={() => setShowMemoryGame(false)}
/>
<main className="flex flex-col items-center w-full">
<section className="hero-bg w-full">
<Hero />
Expand Down
87 changes: 63 additions & 24 deletions src/components/MemoryGame/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,14 +168,17 @@ const MemoryGame: React.FC<MemoryGameProps> = ({ isOpen, onClose }) => {
return (
<AnimatePresence>
<motion.div
className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-75 p-4 overflow-hidden"
className="fixed inset-0 z-50 flex items-center justify-center bg-[#1a0f2e]/90 p-4 overflow-hidden backdrop-blur-sm"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
>
<motion.div
className="relative w-full max-w-6xl max-h-full bg-gradient-to-b from-[#B1E8FF] to-[#84cefe] rounded-3xl shadow-2xl overflow-hidden flex flex-col"
className="relative w-full max-w-6xl max-h-full rounded-3xl overflow-hidden flex flex-col border-[3px] border-[#ff88e9] shadow-[0_0_20px_rgba(255,136,233,0.4),inset_0_0_20px_rgba(255,136,233,0.05)]"
style={{
backgroundColor: "#2f234b",
}}
initial={{ scale: 0.5, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.5, opacity: 0 }}
Expand All @@ -186,14 +189,17 @@ const MemoryGame: React.FC<MemoryGameProps> = ({ isOpen, onClose }) => {
{/* Header */}
<div className="flex justify-between items-center mb-6">
<h2
className="text-3xl font-bold text-[#215172]"
style={{ fontFamily: "Orbitron, monospace" }}
className="text-3xl font-bold text-white"
style={{
fontFamily: "Orbitron, monospace",
textShadow: "0 0 10px rgba(255,136,233,0.6)",
}}
>
Memory Match
</h2>
<button
onClick={onClose}
className="text-[#215172] hover:text-[#00DAB7] text-2xl font-bold"
className="text-[#ff88e9] hover:text-[#00DAB7] text-2xl font-bold transition-colors"
>
</button>
Expand All @@ -202,7 +208,10 @@ const MemoryGame: React.FC<MemoryGameProps> = ({ isOpen, onClose }) => {
{!isGameStarted ? (
/* Difficulty Selection */
<div className="text-center">
<h3 className="text-xl font-bold text-[#215172] mb-4">
<h3
className="text-xl font-bold text-white/90 mb-4"
style={{ fontFamily: "Orbitron, monospace" }}
>
Choose your difficulty:
</h3>
<div className="grid grid-cols-2 gap-4 mb-6">
Expand All @@ -215,19 +224,21 @@ const MemoryGame: React.FC<MemoryGameProps> = ({ isOpen, onClose }) => {
<button
key={pairs}
onClick={() => setDifficulty(pairs as 12 | 24 | 36 | 100)}
className={`p-4 rounded-xl font-bold transition-all duration-200 ${
className={`p-4 rounded-xl font-bold transition-all duration-200 border-2 ${
difficulty === pairs
? "bg-[#00DAB7] text-white shadow-lg"
: "bg-white text-[#215172] hover:bg-[#00DAB7] hover:text-white"
? "bg-[#ff88e9] text-[#2f234b] border-[#ff88e9] shadow-[0_0_12px_rgba(255,136,233,0.6)]"
: "bg-transparent text-[#ff88e9] border-[#ff88e9]/60 hover:bg-[#ff88e9]/20 hover:border-[#ff88e9]"
}`}
style={{ fontFamily: "Orbitron, monospace" }}
>
{label}
</button>
))}
</div>
<button
onClick={initializeGame}
className="px-8 py-3 bg-[#ff6b35] text-white font-bold rounded-xl hover:scale-105 transition-transform duration-200"
className="px-8 py-3 bg-[#00DAB7] text-[#2f234b] font-bold rounded-xl hover:scale-105 transition-transform duration-200 shadow-[0_0_12px_rgba(0,218,183,0.5)]"
style={{ fontFamily: "Orbitron, monospace" }}
>
Start Game!
</button>
Expand All @@ -237,10 +248,16 @@ const MemoryGame: React.FC<MemoryGameProps> = ({ isOpen, onClose }) => {
<div>
{/* Game Stats */}
<div className="flex justify-between items-center mb-6">
<div className="text-[#215172] font-bold">Moves: {moves}</div>
<div
className="text-[#ff88e9] font-bold"
style={{ fontFamily: "Orbitron, monospace" }}
>
Moves: {moves}
</div>
<button
onClick={resetGame}
className="px-4 py-2 bg-[#ff6b35] text-white font-bold rounded-lg hover:scale-105 transition-transform duration-200"
className="px-4 py-2 bg-[#00DAB7] text-[#2f234b] font-bold rounded-lg hover:scale-105 transition-transform duration-200"
style={{ fontFamily: "Orbitron, monospace" }}
>
New Game
</button>
Expand All @@ -267,28 +284,32 @@ const MemoryGame: React.FC<MemoryGameProps> = ({ isOpen, onClose }) => {
<div className="w-full h-full relative">
{/* Card Back */}
<motion.div
className={`absolute inset-0 bg-[#215172] flex items-center justify-center shadow-lg ${
className={`absolute inset-0 flex items-center justify-center border-2 border-[#ff88e9]/80 shadow-[0_0_8px_rgba(255,136,233,0.3)] ${
difficulty === 100 ? "rounded-md" : "rounded-xl"
}`}
animate={{
rotateY: card.isFlipped || card.isMatched ? 180 : 0,
}}
transition={{ duration: 0.3 }}
style={{
backgroundColor: "#2f234b",
boxShadow: "inset 0 0 12px rgba(255,136,233,0.15)",
backfaceVisibility: "hidden",
zIndex: card.isFlipped || card.isMatched ? 1 : 2,
}}
animate={{
rotateY: card.isFlipped || card.isMatched ? 180 : 0,
}}
transition={{ duration: 0.3 }}
>
<div
className={`${
difficulty === 100 ? "text-xs" : "text-4xl"
}`}
></div>
} text-[#ff88e9]/40`}
>
?
</div>
</motion.div>

{/* Card Front */}
<motion.div
className={`absolute inset-0 bg-white shadow-lg ${
className={`absolute inset-0 bg-white/95 shadow-lg border border-[#ff88e9]/30 ${
difficulty === 100
? "rounded-md p-0.5"
: "rounded-xl p-2"
Expand Down Expand Up @@ -320,16 +341,34 @@ const MemoryGame: React.FC<MemoryGameProps> = ({ isOpen, onClose }) => {
{/* Win Message */}
{gameWon && (
<motion.div
className="text-center p-6 bg-[#00DAB7] text-white rounded-xl"
className="text-center p-6 rounded-xl border-2 border-[#ff88e9] shadow-[0_0_20px_rgba(255,136,233,0.4)]"
style={{
backgroundColor: "rgba(255,136,233,0.2)",
color: "#fff",
}}
initial={{ scale: 0 }}
animate={{ scale: 1 }}
transition={{ type: "spring", stiffness: 300 }}
>
<h3 className="text-2xl font-bold mb-2">🎉 You Won! 🎉</h3>
<p className="text-lg">Completed in {moves} moves!</p>
<h3
className="text-2xl font-bold mb-2"
style={{
fontFamily: "Orbitron, monospace",
textShadow: "0 0 10px rgba(255,136,233,0.8)",
}}
>
🎉 You Won! 🎉
</h3>
<p
className="text-lg text-white/90"
style={{ fontFamily: "Orbitron, monospace" }}
>
Completed in {moves} moves!
</p>
<button
onClick={resetGame}
className="mt-4 px-6 py-2 bg-white text-[#00DAB7] font-bold rounded-lg hover:scale-105 transition-transform duration-200"
className="mt-4 px-6 py-2 bg-[#00DAB7] text-[#2f234b] font-bold rounded-lg hover:scale-105 transition-transform duration-200"
style={{ fontFamily: "Orbitron, monospace" }}
>
Play Again
</button>
Expand Down
Loading
Loading