<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pattern Memory Game</title>
<style>
:root {
--primary-color: #4f46e5;
--primary-hover-color: #4338ca;
--secondary-color: #6366f1;
--background-color: #f9fafb;
--text-color: #1f2937;
--gray-light: #e5e7eb;
--gray-medium: #9ca3af;
--gray-dark: #4b5563;
--success-color: #10b981;
--error-color: #ef4444;
--warning-color: #f59e0b;
--radius: 0.5rem;
}
* { margin:0; padding:0; box-sizing: border-box; font-family: -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif; }
body { background-color: var(--background-color); color: var(--text-color); min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; transition: background-color 0.3s, color 0.3s;}
.dark-mode {
--background-color: #1f2937;
--text-color: #f9fafb;
--gray-light: #4b5563;
--gray-medium: #6b7280;
--gray-dark: #9ca3af;
}
.game-container {
background-color: white; border-radius: var(--radius); box-shadow: 0 4px 6px rgba(0,0,0,.1);
padding: 2rem; width: 100%; max-width: 800px; margin: 2rem auto; min-height: 500px;
}
.dark-mode .game-container { background-color: #111827; }
.header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 2rem;}
h1, h2, h3 { color: var(--primary-color); margin-bottom:1rem;}
button { cursor:pointer;border:none;border-radius:var(--radius);font-weight:500;transition:all .2s;}
button:focus { outline:2px solid var(--primary-color); outline-offset:2px;}
.btn-primary { background-color: var(--primary-color); color:white; padding:.75rem 1.5rem; font-size:1rem;}
.btn-primary:hover { background-color: var(--primary-hover-color);}
.btn-secondary { background-color: var(--gray-light); color:var(--text-color); padding:.75rem 1.5rem; font-size:1rem;}
.btn-secondary:hover { background-color: var(--gray-medium);}
.tabs { display:flex; border-bottom:1px solid var(--gray-light); margin-bottom:1.5rem;}
.tab { padding:.75rem 1.5rem; border-bottom:2px solid transparent; cursor:pointer;}
.tab.active { border-bottom-color:var(--primary-color); color:var(--primary-color); font-weight:500;}
.score-display { display:flex; justify-content:space-between; align-items:center; margin-bottom:2rem; gap:1rem;}
.score-box { background-color:var(--gray-light); border-radius:var(--radius); padding:1rem; flex:1; text-align:center;}
.score-value { font-size:2rem; font-weight:bold; color:var(--primary-color);}
.message { text-align:center; font-size:1.25rem; margin:1rem 0; min-height:2rem;}
.controls { display:flex; justify-content:center; gap:1rem; margin-top:2rem;}
.game-buttons-container { position:relative; width:300px; height:300px; margin:0 auto;}
.game-button { position:absolute; width:80px; height:80px; border-radius:50%; box-shadow:0 4px 8px rgba(0,0,0,0.2); transform-origin:center; will-change:transform; transform:none;}
.game-button:hover { transform:scale(1.1);}
.game-button.active { transform:none; filter:brightness(0.8); box-shadow:0 0 15px rgba(255,255,255,0.7),0 4px 8px rgba(0,0,0,0.2);}
.red { background-color:#ef4444; top:0; left:50%; transform:translateX(-50%);}
.red:hover { transform:translateX(-50%) scale(1.1);}
.red.active { transform:translateX(-50%);}
.green { background-color:#10b981; right:0; top:50%; transform:translateY(-50%);}
.green:hover { transform:translateY(-50%) scale(1.1);}
.green.active { transform:translateY(-50%);}
.blue { background-color:#3b82f6; bottom:0; left:50%; transform:translateX(-50%);}
.blue:hover { transform:translateX(-50%) scale(1.1);}
.blue.active { transform:translateX(-50%);}
.yellow { background-color:#f59e0b; left:0; top:50%; transform:translateY(-50%);}
.yellow:hover { transform:translateY(-50%) scale(1.1);}
.yellow.active { transform:translateY(-50%);}
.pattern-dots { display:flex; justify-content:center; gap:.5rem; margin:1.5rem 0;}
.pattern-dot { width:12px; height:12px; border-radius:50%; background-color:var(--gray-light);}
.pattern-dot.active { background-color:var(--primary-color);}
.stats-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(200px,1fr)); gap:1rem; margin-bottom:2rem;}
.stat-card { background-color:var(--gray-light); border-radius:var(--radius); padding:1.5rem; text-align:center;}
.stat-value { font-size:2.5rem; font-weight:bold; color:var(--primary-color); margin-bottom:.5rem;}
.stat-label { color:var(--gray-dark); font-size:.875rem;}
.chart-container { margin-top:2rem; background-color:white; border-radius:var(--radius); padding:1.5rem; box-shadow:0 1px 3px rgba(0,0,0,0.1);}
.dark-mode .chart-container { background-color:#111827;}
.chart { height:200px; display:flex; align-items:flex-end; gap:.5rem; padding-bottom:1.5rem; position:relative;}
.chart::after { content:''; position:absolute; left:0; right:0; bottom:0; height:1px; background-color:var(--gray-light);}
.chart-bar { flex:1; background-color:var(--primary-color); border:2px solid var(--primary-hover-color); border-radius:4px 4px 0 0; min-width:20px; transition:height .5s;}
.chart-labels { display:flex; justify-content:space-around; margin-top:.5rem; color:var(--gray-dark); font-size:.75rem;}
#badges-container { display:grid; grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); gap:1rem; margin-top:1.5rem;}
.badge { background-color:white; border-radius:var(--radius); padding:1rem; text-align:center; box-shadow:0 1px 3px rgba(0,0,0,0.1); transition:transform .2s;}
.dark-mode .badge { background-color:#111827;}
.badge:hover { transform:translateY(-5px);}
.badge-icon { width:60px; height:60px; border-radius:50%; background-color:var(--primary-color); color:white; display:flex; justify-content:center; align-items:center; margin:0 auto 1rem; font-size:1.5rem;}
.locked .badge-icon { background-color:var(--gray-medium); opacity:0.5;}
.badge-name { font-weight:600; margin-bottom:.5rem;}
.badge-desc { font-size:.75rem; color:var(--gray-dark);}
.locked .badge-name, .locked .badge-desc { opacity:0.6;}
@media (max-width: 768px) {
.game-container { padding:1rem; margin:1rem auto;}
.header { flex-direction:column; gap:1rem; text-align:center;}
.header h1 { font-size:1.5rem;}
.game-buttons-container { width:280px; height:280px;}
.game-button { width:70px; height:70px;}
.controls { flex-direction:column;}
.stats-grid { grid-template-columns:1fr 1fr;}
.score-display { flex-direction:column;}
}
@media (min-width: 1024px) {
.game-container { max-width:1000px;}
.game-buttons-container { width:350px; height:350px;}
.game-button { width:90px; height:90px;}
}
</style>
</head>
<body>
<div id="app" class="app-container">
<div id="game-outer-container">
<div id="game-container" class="game-container">
<div class="header">
<h1>Pattern Memory Game</h1>
<div class="flex gap-2 items-center">
<h2>Memory Pattern Game</h2>
</div>
</div>
<div class="tabs">
<div class="tab active" data-tab="play">Play</div>
<div class="tab" data-tab="stats">Stats</div>
<div class="tab" data-tab="badges">Badges</div>
<div class="tab" data-tab="time">Time</div>
<div class="tab" data-tab="settings">Settings</div>
</div>
<!-- Settings Content -->
<div id="settings-content" class="tab-content" style="display: none;">
<h2>Game Settings</h2>
<div class="settings-option">
<span>Dark Mode</span>
<button id="settings-darkmode" class="p-2 rounded-lg transition-colors bg-gray-light">OFF</button>
</div>
<div class="settings-option">
<span>Sound Effects</span>
<button id="settings-sound" class="p-2 rounded-lg transition-colors bg-primary text-white">ON</button>
</div>
<div class="settings-option">
<span>Background Music</span>
<button id="settings-music" class="p-2 rounded-lg transition-colors bg-gray-light">OFF</button>
</div>
<div class="settings-option">
<span>Difficulty</span>
<select id="settings-difficulty" class="p-2 border rounded-lg">
<option value="easy">Easy</option>
<option value="medium" selected>Medium</option>
<option value="hard">Hard</option>
</select>
</div>
</div>
<!-- Play Content -->
<div id="play-content" class="tab-content">
<div class="score-display">
<div class="score-box">
<div class="text-sm text-gray-dark mb-1">Current Score</div>
<div id="current-score" class="score-value">0</div>
</div>
<div class="score-box">
<div class="text-sm text-gray-dark mb-1">High Score</div>
<div id="high-score" class="score-value">0</div>
</div>
<div class="score-box">
<div class="text-sm text-gray-dark mb-1">Level</div>
<div id="level" class="score-value">1</div>
</div>
</div>
<div id="message" class="message">Press Start to play</div>
<div id="pattern-dots" class="pattern-dots"></div>
<div class="game-buttons-container">
<button id="red-btn" class="game-button red" disabled></button>
<button id="green-btn" class="game-button green" disabled></button>
<button id="blue-btn" class="game-button blue" disabled></button>
<button id="yellow-btn" class="game-button yellow" disabled></button>
</div>
<div class="controls">
<button id="start-btn" class="btn-primary">Start Game</button>
<button id="reset-btn" class="btn-secondary">Reset</button>
</div>
</div>
<!-- Stats Content -->
<div id="stats-content" class="tab-content" style="display: none;">
<h2>Your Statistics</h2>
<div class="stats-grid">
<div class="stat-card">
<div id="games-played" class="stat-value">0</div>
<div class="stat-label">Games Played</div>
</div>
<div class="stat-card">
<div id="highest-score" class="stat-value">0</div>
<div class="stat-label">Highest Score</div>
</div>
<div class="stat-card">
<div id="max-level" class="stat-value">0</div>
<div class="stat-label">Max Level</div>
</div>
<div class="stat-card">
<div id="total-patterns" class="stat-value">0</div>
<div class="stat-label">Total Patterns</div>
</div>
</div>
<div class="chart-container">
<h3>Score History</h3>
<div id="score-chart" class="chart"></div>
<div id="chart-labels" class="chart-labels"></div>
</div>
</div>
<!-- Badges Content -->
<div id="badges-content" class="tab-content" style="display: none;">
<h2>Your Achievements</h2>
<p class="text-gray-dark mb-6">
Unlock badges by completing challenges and improving your memory skills!
</p>
<div id="badges-container"></div>
</div>
<!-- Time Content -->
<div id="time-content" class="tab-content" style="display: none;">
<h2>Current Time & Date</h2>
<div style="text-align:center; margin:2rem 0;">
<div id="clock" style="font-size:2.5rem; font-weight:bold; margin-bottom: 1rem;">--:--:--</div>
<div id="date" style="font-size:1.25rem; color: var(--gray-dark);">--/--/----</div>
</div>
</div>
</div>
</div>
</div>
<script>
// -- Game Logic --
const COLORS = ["red", "green", "blue", "yellow"];
const DIFFICULTY_SETTINGS = {
easy: { patternDisplayTime: 800, patternPauseTime: 400 },
medium: { patternDisplayTime: 600, patternPauseTime: 300 },
hard: { patternDisplayTime: 400, patternPauseTime: 200 }
};
let audioContext = null, oscillator = null, backgroundMusic = null, musicGainNode = null;
const gameState = {
isPlaying: false, isShowingPattern: false,
currentScore: 0, highScore: 0, level: 1, message: "Press Start to play",
currentPattern: [], userPattern: [], patternIndex: -1, consecutiveCorrect: 0,
settings: { darkMode: false, soundEnabled: true, musicEnabled: false, difficulty: "medium" },
stats: { gamesPlayed: 0, highestScore: 0, maxLevel: 0, totalPatterns: 0, scoreHistory: [] },
badges: [
{ name: "First Win", description: "Complete your first game", icon: "🎯", unlocked: false, condition: s=>s.gamesPlayed>=1 },
{ name: "Memory Master", description: "Reach level 10", icon: "🧠", unlocked: false, condition: s=>s.maxLevel>=10 },
{ name: "Champion", description: "Score 20+ points", icon: "🏆", unlocked: false, condition: s=>s.highestScore>=20 },
{ name: "Pattern Expert", description: "Complete 50 total patterns", icon: "📊", unlocked: false, condition: s=>s.totalPatterns>=50 },
{ name: "Dedicated Player", description: "Play 10 or more games", icon: "🎮", unlocked: false, condition: s=>s.gamesPlayed>=10 }
]
};
const elements = {
app: document.getElementById('app'),
gameOuterContainer: document.getElementById('game-outer-container'),
gameContainer: document.getElementById('game-container'),
tabs: document.querySelectorAll('.tab'),
playContent: document.getElementById('play-content'),
statsContent: document.getElementById('stats-content'),
badgesContent: document.getElementById('badges-content'),
timeContent: document.getElementById('time-content'),
settingsContent: document.getElementById('settings-content'),
currentScore: document.getElementById('current-score'),
highScore: document.getElementById('high-score'),
level: document.getElementById('level'),
message: document.getElementById('message'),
patternDots: document.getElementById('pattern-dots'),
redBtn: document.getElementById('red-btn'),
greenBtn: document.getElementById('green-btn'),
blueBtn: document.getElementById('blue-btn'),
yellowBtn: document.getElementById('yellow-btn'),
startBtn: document.getElementById('start-btn'),
resetBtn: document.getElementById('reset-btn'),
gamesPlayed: document.getElementById('games-played'),
highestScore: document.getElementById('highest-score'),
maxLevel: document.getElementById('max-level'),
totalPatterns: document.getElementById('total-patterns'),
scoreChart: document.getElementById('score-chart'),
chartLabels: document.getElementById('chart-labels'),
badgesContainer: document.getElementById('badges-container'),
clock: document.getElementById('clock'),
date: document.getElementById('date'),
settingsDarkmode: document.getElementById('settings-darkmode'),
settingsSound: document.getElementById('settings-sound'),
settingsMusic: document.getElementById('settings-music'),
settingsDifficulty: document.getElementById('settings-difficulty')
};
function updateStatsDisplay() {
elements.gamesPlayed.textContent = gameState.stats.gamesPlayed;
elements.highestScore.textContent = gameState.stats.highestScore;
elements.maxLevel.textContent = gameState.stats.maxLevel;
elements.totalPatterns.textContent = gameState.stats.totalPatterns;
elements.scoreChart.innerHTML = '';
elements.chartLabels.innerHTML = '';
if (gameState.stats.scoreHistory.length === 0) {
const emptyMessage = document.createElement('div');
emptyMessage.textContent = 'No score history yet. Play some games!';
emptyMessage.style.textAlign = 'center';
emptyMessage.style.width = '100%';
emptyMessage.style.padding = '2rem 0';
emptyMessage.style.color = 'var(--gray-dark)';
elements.scoreChart.appendChild(emptyMessage);
return;
}
const maxScore = Math.max(...gameState.stats.scoreHistory, 1);
gameState.stats.scoreHistory.forEach((score, index) => {
const bar = document.createElement('div');
bar.className = 'chart-bar';
bar.style.height = `${(score / maxScore) * 100}%`;
elements.scoreChart.appendChild(bar);
const label = document.createElement('span');
label.textContent = `Game ${index + 1}`;
elements.chartLabels.appendChild(label);
});
}
function updateBadgesDisplay() {
elements.badgesContainer.innerHTML = '';
gameState.badges.forEach((badge) => {
const badgeElement = document.createElement('div');
badgeElement.className = `badge ${badge.unlocked ? '' : 'locked'}`;
badgeElement.innerHTML = `
<div class="badge-icon">${badge.icon}</div>
<div class="badge-name">${badge.name}</div>
<div class="badge-desc">${badge.description}</div>
`;
elements.badgesContainer.appendChild(badgeElement);
});
}
function updateGameDisplay() {
elements.currentScore.textContent = gameState.currentScore;
elements.highScore.textContent = gameState.highScore;
elements.level.textContent = gameState.level;
elements.message.textContent = gameState.message;
updatePatternDots();
const buttonsDisabled = gameState.isShowingPattern || !gameState.isPlaying;
elements.redBtn.disabled = buttonsDisabled;
elements.greenBtn.disabled = buttonsDisabled;
elements.blueBtn.disabled = buttonsDisabled;
elements.yellowBtn.disabled = buttonsDisabled;
elements.startBtn.disabled = gameState.isPlaying || gameState.isShowingPattern;
elements.resetBtn.disabled = gameState.isShowingPattern;
elements.redBtn.classList.toggle('active', gameState.isShowingPattern && gameState.currentPattern[gameState.patternIndex] === 'red');
elements.greenBtn.classList.toggle('active', gameState.isShowingPattern && gameState.currentPattern[gameState.patternIndex] === 'green');
elements.blueBtn.classList.toggle('active', gameState.isShowingPattern && gameState.currentPattern[gameState.patternIndex] === 'blue');
elements.yellowBtn.classList.toggle('active', gameState.isShowingPattern && gameState.currentPattern[gameState.patternIndex] === 'yellow');
}
function updatePatternDots() {
elements.patternDots.innerHTML = '';
for (let i = 0; i < gameState.currentPattern.length; i++) {
const dot = document.createElement('div');
dot.className = `pattern-dot ${i === gameState.patternIndex && gameState.isShowingPattern ? 'active' : ''}`;
elements.patternDots.appendChild(dot);
}
}
function getRandomColor() { return COLORS[Math.floor(Math.random() * COLORS.length)]; }
function showPattern(pattern) {
const { patternDisplayTime, patternPauseTime } = DIFFICULTY_SETTINGS[gameState.settings.difficulty];
gameState.isShowingPattern = true;
gameState.message = "Watch the pattern...";
gameState.patternIndex = 0;
updateGameDisplay();
let index = 0;
const intervalId = setInterval(() => {
gameState.patternIndex = index;
playSound(pattern[index]);
updateGameDisplay();
setTimeout(() => {
if (index < pattern.length - 1) { index++; }
else {
clearInterval(intervalId);
gameState.isShowingPattern = false;
gameState.patternIndex = -1;
gameState.message = "Your turn! Repeat the pattern.";
updateGameDisplay();
}
}, patternPauseTime);
}, patternDisplayTime);
}
function startGame() {
initAudio();
gameState.isPlaying = true;
gameState.currentScore = 0; gameState.level = 1; gameState.userPattern = [];
gameState.consecutiveCorrect = 0;
const newPattern = [getRandomColor()];
gameState.currentPattern = newPattern;
gameState.message = "Get ready...";
gameState.stats.gamesPlayed += 1;
updateGameDisplay();
playSound('success');
setTimeout(() => { showPattern(newPattern); }, 1000);
}
function resetGame() {
gameState.isPlaying = false; gameState.isShowingPattern = false;
gameState.currentScore = 0; gameState.level = 1;
gameState.message = "Press Start to play";
gameState.currentPattern = []; gameState.userPattern = [];
gameState.patternIndex = -1; gameState.consecutiveCorrect = 0;
updateGameDisplay();
}
function handleLevelComplete() {
gameState.stats.totalPatterns += 1;
gameState.stats.maxLevel = Math.max(gameState.stats.maxLevel, gameState.level + 1);
checkBadges(gameState.stats);
gameState.currentScore += gameState.level;
if (gameState.currentScore > gameState.highScore) { gameState.highScore = gameState.currentScore; }
gameState.consecutiveCorrect += 1;
gameState.level += 1;
playSound('levelUp');
const newPattern = [...gameState.currentPattern, getRandomColor()];
gameState.currentPattern = newPattern;
gameState.userPattern = [];
gameState.message = `Level ${gameState.level - 1} complete! Next level: ${gameState.level}`;
updateGameDisplay();
setTimeout(() => { showPattern(newPattern); }, 1500);
}
function handleGameOver() {
gameState.isPlaying = false; gameState.isShowingPattern = false;
gameState.message = `Game Over! Final Score: ${gameState.currentScore}`;
playSound('error');
gameState.stats.highestScore = Math.max(gameState.stats.highestScore, gameState.currentScore);
gameState.stats.scoreHistory.push(gameState.currentScore);
if (gameState.stats.scoreHistory.length > 10) {
gameState.stats.scoreHistory = gameState.stats.scoreHistory.slice(-10);
}
checkBadges(gameState.stats);
updateGameDisplay();
updateStatsDisplay();
}
function handleButtonClick(color) {
if (!gameState.isPlaying || gameState.isShowingPattern) return;
gameState.userPattern.push(color);
playSound(color);
const currentIndex = gameState.userPattern.length - 1;
if (color !== gameState.currentPattern[currentIndex]) {
gameState.consecutiveCorrect = 0;
setTimeout(() => { handleGameOver(); }, 100);
return;
}
if (gameState.userPattern.length === gameState.currentPattern.length) {
handleLevelComplete();
}
}
function activateButton(button, color) {
button.classList.add('active'); playSound(color);
setTimeout(() => { button.classList.remove('active'); }, 300);
}
function checkBadges(updatedStats) {
let newBadgeUnlocked = false, unlockedBadge = null;
gameState.badges.forEach((badge, index) => {
if (!badge.unlocked && badge.condition(updatedStats)) {
gameState.badges[index].unlocked = true;
newBadgeUnlocked = true;
unlockedBadge = badge;
}
});
if (newBadgeUnlocked && unlockedBadge) {
updateBadgesDisplay();
alert(`🎉 Achievement Unlocked: ${unlockedBadge.name}\n${unlockedBadge.description}`);
}
}
function applySettings() {
if (gameState.settings.darkMode) {
document.body.classList.add('dark-mode'); elements.app.classList.add('dark-mode');
elements.settingsDarkmode.textContent = 'ON';
elements.settingsDarkmode.classList.add('bg-primary', 'text-white');
elements.settingsDarkmode.classList.remove('bg-gray-light');
} else {
document.body.classList.remove('dark-mode'); elements.app.classList.remove('dark-mode');
elements.settingsDarkmode.textContent = 'OFF';
elements.settingsDarkmode.classList.remove('bg-primary', 'text-white');
elements.settingsDarkmode.classList.add('bg-gray-light');
}
if (gameState.settings.soundEnabled) {
elements.settingsSound.textContent = 'ON';
elements.settingsSound.classList.add('bg-primary', 'text-white');
elements.settingsSound.classList.remove('bg-gray-light');
} else {
elements.settingsSound.textContent = 'OFF';
elements.settingsSound.classList.remove('bg-primary', 'text-white');
elements.settingsSound.classList.add('bg-gray-light');
}
if (gameState.settings.musicEnabled) {
elements.settingsMusic.textContent = 'ON';
elements.settingsMusic.classList.add('bg-primary', 'text-white');
elements.settingsMusic.classList.remove('bg-gray-light');
startBackgroundMusic();
} else {
elements.settingsMusic.textContent = 'OFF';
elements.settingsMusic.classList.remove('bg-primary', 'text-white');
elements.settingsMusic.classList.add('bg-gray-light');
stopBackgroundMusic();
}
elements.settingsDifficulty.value = gameState.settings.difficulty;
}
function toggleDarkMode() { gameState.settings.darkMode = !gameState.settings.darkMode; applySettings();}
function toggleSound() { gameState.settings.soundEnabled = !gameState.settings.soundEnabled; applySettings();}
function toggleMusic() { gameState.settings.musicEnabled = !gameState.settings.musicEnabled; applySettings();}
function setDifficulty(difficulty) { gameState.settings.difficulty = difficulty;}
function initAudio() {
if (!audioContext) {
try { audioContext = new (window.AudioContext || window.webkitAudioContext)(); }
catch (error) { console.error('Web Audio API is not supported in this browser:', error);}
}
}
function playSound(color) {
if (!gameState.settings.soundEnabled || !audioContext) return;
try {
if (oscillator) { oscillator.stop(); oscillator.disconnect(); }
oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
switch (color) {
case 'red': oscillator.frequency.value = 261.63; break;
case 'green': oscillator.frequency.value = 329.63; break;
case 'blue': oscillator.frequency.value = 392.00; break;
case 'yellow': oscillator.frequency.value = 493.88; break;
case 'success': oscillator.frequency.value = 523.25; break;
case 'error': oscillator.frequency.value = 220.00; break;
case 'levelUp': oscillator.frequency.value = 659.25; break;
default: oscillator.frequency.value = 440.00;
}
oscillator.connect(gainNode); gainNode.connect(audioContext.destination);
oscillator.start(); gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
setTimeout(() => {
if (oscillator) {
gainNode.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 0.1);
setTimeout(() => {
oscillator.stop(); oscillator.disconnect(); oscillator = null;
}, 100);
}
}, 150);
} catch (error) { console.error('Error playing sound:', error);}
}
function startBackgroundMusic() {
if (!gameState.settings.musicEnabled || !audioContext) return;
try {
stopBackgroundMusic();
backgroundMusic = audioContext.createOscillator();
musicGainNode = audioContext.createGain();
backgroundMusic.type = 'sine';
backgroundMusic.frequency.value = 146.83;
backgroundMusic.connect(musicGainNode); musicGainNode.connect(audioContext.destination);
musicGainNode.gain.setValueAtTime(0, audioContext.currentTime);
musicGainNode.gain.linearRampToValueAtTime(0.03, audioContext.currentTime + 2);
backgroundMusic.start();
const lfo = audioContext.createOscillator();
const lfoGain = audioContext.createGain();
lfo.frequency.value = 0.1;
lfoGain.gain.value = 5;
lfo.connect(lfoGain); lfoGain.connect(backgroundMusic.frequency);
lfo.start();
} catch (error) { console.error('Error starting background music:', error);}
}
function stopBackgroundMusic() {
if (backgroundMusic) {
try {
musicGainNode.gain.linearRampToValueAtTime(0, audioContext.currentTime + 1);
setTimeout(() => {
backgroundMusic.stop(); backgroundMusic.disconnect(); backgroundMusic = null; musicGainNode = null;
}, 1000);
} catch (error) { console.error('Error stopping background music:', error);}
}
}
// Time tab clock logic
function updateClockAndDate() {
const now = new Date();
const pad = n => n.toString().padStart(2, '0');
const timeStr = `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;
const dateStr = now.toLocaleDateString(undefined, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
elements.clock.textContent = timeStr;
elements.date.textContent = dateStr;
}
setInterval(updateClockAndDate, 1000);
updateClockAndDate();
function handleTabClick(tabName) {
elements.playContent.style.display = 'none';
elements.statsContent.style.display = 'none';
elements.badgesContent.style.display = 'none';
elements.timeContent.style.display = 'none';
elements.settingsContent.style.display = 'none';
elements.tabs.forEach(tab => tab.classList.remove('active'));
switch (tabName) {
case 'play':
elements.playContent.style.display = 'block';
document.querySelector('[data-tab="play"]').classList.add('active');
break;
case 'stats':
elements.statsContent.style.display = 'block';
document.querySelector('[data-tab="stats"]').classList.add('active');
updateStatsDisplay();
break;
case 'badges':
elements.badgesContent.style.display = 'block';
document.querySelector('[data-tab="badges"]').classList.add('active');
updateBadgesDisplay();
break;
case 'time':
elements.timeContent.style.display = 'block';
document.querySelector('[data-tab="time"]').classList.add('active');
break;
case 'settings':
elements.settingsContent.style.display = 'block';
document.querySelector('[data-tab="settings"]').classList.add('active');
break;
}
}
function initGame() {
updateGameDisplay();
updateStatsDisplay();
updateBadgesDisplay();
elements.redBtn.addEventListener('click', () => { activateButton(elements.redBtn, 'red'); handleButtonClick('red'); });
elements.greenBtn.addEventListener('click', () => { activateButton(elements.greenBtn, 'green'); handleButtonClick('green'); });
elements.blueBtn.addEventListener('click', () => { activateButton(elements.blueBtn, 'blue'); handleButtonClick('blue'); });
elements.yellowBtn.addEventListener('click', () => { activateButton(elements.yellowBtn, 'yellow'); handleButtonClick('yellow'); });
elements.startBtn.addEventListener('click', startGame);
elements.resetBtn.addEventListener('click', resetGame);
elements.tabs.forEach(tab => {
tab.addEventListener('click', () => { handleTabClick(tab.getAttribute('data-tab')); });
});
elements.settingsDarkmode.addEventListener('click', toggleDarkMode);
elements.settingsSound.addEventListener('click', toggleSound);
elements.settingsMusic.addEventListener('click', toggleMusic);
elements.settingsDifficulty.addEventListener('change', (e) => { setDifficulty(e.target.value); });
document.addEventListener('keydown', (e) => {
if (!gameState.isPlaying || gameState.isShowingPattern) return;
switch (e.key) {
case 'ArrowUp': case 'w': activateButton(elements.redBtn, 'red'); handleButtonClick('red'); break;
case 'ArrowRight': case 'd': activateButton(elements.greenBtn, 'green'); handleButtonClick('green'); break;
case 'ArrowDown': case 's': activateButton(elements.blueBtn, 'blue'); handleButtonClick('blue'); break;
case 'ArrowLeft': case 'a': activateButton(elements.yellowBtn, 'yellow'); handleButtonClick('yellow'); break;
}
});
applySettings();
}
document.addEventListener('DOMContentLoaded', () => {
initGame();
document.addEventListener('click', () => {
if (!audioContext) {
initAudio();
if (gameState.settings.musicEnabled) { startBackgroundMusic(); }
}
}, { once: true });
});
</script>
</body>
</html>