diff --git a/Js/script.js b/Js/script.js index 3e0dcd4..e233a80 100644 --- a/Js/script.js +++ b/Js/script.js @@ -19,6 +19,9 @@ const resultsElement = document.getElementById("results"); const endScoreElement = document.getElementById("end-score"); const endHighScoreElement = document.getElementById("end-high-score"); const restartTextElement = document.getElementById("restart-text"); +const instructionsMenuElement = document.getElementById("instructions-menu"); +const openInstructionsBtn = document.getElementById("open-instructions"); +const closeInstructionsBtn = document.getElementById("close-instructions"); // High score const HIGH_SCORE_KEY = "stackerHighScore"; @@ -67,6 +70,15 @@ function saveHighScore(value) { // Initialize the game init(); +// Initialize menu state after DOM is loaded +document.addEventListener('DOMContentLoaded', () => { + // Update menu theme buttons to match current theme + updateMenuThemeButtons(); + + // Update menu audio button to match current mute state + updateMenuAudioButton(); +}); + // Determines how precise the game is on autopilot function setRobotPrecision() { robotPrecision = Math.random() - 0.5; @@ -473,6 +485,93 @@ function missedTheSpot() { playFailSound(); } +// ----- Instructions Menu ----- +function toggleInstructionsMenu() { + if (instructionsMenuElement) { + const isHidden = instructionsMenuElement.style.display === "none" || !instructionsMenuElement.style.display; + instructionsMenuElement.style.display = isHidden ? "flex" : "none"; + } +} + +// Open instructions menu button +if (openInstructionsBtn) { + openInstructionsBtn.addEventListener("click", (e) => { + e.preventDefault(); + e.stopPropagation(); + toggleInstructionsMenu(); + }); +} + +// Close instructions menu button +if (closeInstructionsBtn) { + closeInstructionsBtn.addEventListener("click", (e) => { + e.preventDefault(); + e.stopPropagation(); + if (instructionsMenuElement) { + instructionsMenuElement.style.display = "none"; + } + }); +} + +// Menu theme buttons +const menuThemeButtons = { + default: document.getElementById("menu-theme-default"), + night: document.getElementById("menu-theme-night"), + sunset: document.getElementById("menu-theme-sunset") +}; + +// Menu audio button +const menuMuteBtn = document.getElementById("menu-mute-btn"); +const menuAudioIcon = menuMuteBtn?.querySelector(".audio-icon"); +const menuAudioText = menuMuteBtn?.querySelector(".audio-text"); + +// Update menu theme buttons to match current theme +function updateMenuThemeButtons() { + const currentTheme = window.themeManager?.getCurrentTheme() || "default"; + for (const [theme, button] of Object.entries(menuThemeButtons)) { + if (button) { + button.classList.toggle("active", theme === currentTheme); + } + } +} + +// Update menu audio button to match current mute state +function updateMenuAudioButton() { + if (menuAudioIcon && menuAudioText) { + menuAudioIcon.textContent = muted ? "🔇" : "🔊"; + menuAudioText.textContent = muted ? "Sound Off" : "Sound On"; + } +} + +// Add event listeners for menu theme buttons +for (const [theme, button] of Object.entries(menuThemeButtons)) { + if (button) { + button.addEventListener("click", (e) => { + e.preventDefault(); + e.stopPropagation(); + if (window.themeManager) { + window.themeManager.setTheme(theme); + updateMenuThemeButtons(); + } + }); + } +} + +// Add event listener for menu audio button +if (menuMuteBtn) { + menuMuteBtn.addEventListener("click", (e) => { + e.preventDefault(); + e.stopPropagation(); + muted = !muted; + sounds.bgm.muted = muted; + updateMenuAudioButton(); + // Also update the main mute button + if (muteBtn) { + muteBtn.textContent = muted ? "🔇" : "🔊"; + } + }); +} + // ----- Audio Controls ----- const muteBtn = document.createElement("button"); muteBtn.id = "muteBtn"; @@ -527,6 +626,16 @@ document.addEventListener("keydown", (e) => { startGame(); } } + if (e.key === "m" || e.key === "M") { + e.preventDefault(); + muted = !muted; + sounds.bgm.muted = muted; + muteBtn.textContent = muted ? "🔇" : "🔊"; + } + if (e.key === "h" || e.key === "H") { + e.preventDefault(); + toggleInstructionsMenu(); + } }, true); window.addEventListener( "touchstart", @@ -534,8 +643,10 @@ window.addEventListener( if ( e.target.closest(".twitter-link") || // The Twitter link e.target.closest("#muteBtn") || // The mute button - e.target.closest("#theme-controls") || // The theme buttons container - e.target.closest("#close-results") + e.target.closest("#instructions-menu") || // The instructions menu + e.target.closest("#open-instructions") || // The instructions button + e.target.closest("#close-results") || // The close results button + e.target.closest("#close-instructions") // The close instructions button ) { // If it was, do nothing and let the browser handle the 'click' event return; diff --git a/css/style.css b/css/style.css index 5b4ea15..b368dc5 100644 --- a/css/style.css +++ b/css/style.css @@ -74,6 +74,256 @@ body { } } +/* Instructions/Controls Menu */ +#instructions-menu { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + display: none; + padding: 0; + background: var(--ui-panel-bg); + border-radius: 20px; + box-shadow: 0 20px 60px var(--ui-shadow-color), + 0 0 0 1px var(--ui-border-color), + inset 0 1px 0 rgba(255, 220, 150, 0.15); + backdrop-filter: blur(10px); + width: 90%; + max-width: 600px; + min-width: 320px; + max-height: 80vh; + overflow-y: auto; + animation: resultsFadeIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); + z-index: 1000; +} + +#instructions-menu .content { + padding: 2rem 2rem; + width: 100%; +} + +#instructions-menu h2 { + margin: 0 0 2rem 0; + font-size: clamp(1.5rem, 4vw, 2rem); + font-weight: 900; + background: var(--ui-gradient-primary); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + text-align: center; +} + +.menu-section { + margin-bottom: 2rem; +} + +.menu-section h3 { + margin: 0 0 1rem 0; + font-size: clamp(1.1rem, 3vw, 1.3rem); + font-weight: 700; + color: rgba(255, 255, 255, 0.9); + display: flex; + align-items: center; + gap: 0.5rem; +} + +.instruction-content { + background: rgba(60, 50, 40, 0.3); + border: 1px solid var(--ui-border-color); + border-radius: 12px; + padding: 1.25rem; +} + +.instruction-content p { + margin: 0 0 1rem 0; + color: rgba(255, 255, 255, 0.9); + font-size: clamp(0.9rem, 2.2vw, 1rem); + line-height: 1.5; +} + +.instruction-content ul { + margin: 0; + padding-left: 1.5rem; + color: rgba(255, 255, 255, 0.8); + font-size: clamp(0.85rem, 2vw, 0.95rem); + line-height: 1.6; +} + +.instruction-content li { + margin-bottom: 0.5rem; +} + +.blue-text { + color: #4facfe; + font-weight: 600; +} + +.controls-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 1rem; + margin-bottom: 1rem; +} + +.control-item { + display: flex; + align-items: center; + justify-content: space-between; + background: rgba(60, 50, 40, 0.4); + border: 1px solid var(--ui-border-color); + border-radius: 8px; + padding: 1rem 1.25rem; + transition: all 0.3s ease; +} + +.control-item:hover { + background: rgba(80, 65, 50, 0.5); + transform: translateX(4px); + border-color: rgba(255, 200, 100, 0.3); +} + +.control-item kbd { + background: var(--ui-gradient-button); + border: 2px solid var(--ui-border-color); + border-radius: 6px; + padding: 0.4rem 0.8rem; + font-family: 'Courier New', monospace; + font-weight: 700; + font-size: clamp(0.85rem, 2vw, 1rem); + box-shadow: 0 2px 0 rgba(0, 0, 0, 0.3), + inset 0 1px 0 rgba(255, 220, 150, 0.2); + color: #ffcc00; + min-width: 60px; + text-align: center; +} + +.control-item span { + color: rgba(255, 255, 255, 0.9); + font-size: clamp(0.9rem, 2.2vw, 1.1rem); + font-weight: 500; +} + +.controls-note { + text-align: center; + color: rgba(255, 255, 255, 0.6); + font-size: clamp(0.8rem, 2vw, 0.9rem); + font-style: italic; + margin: 0; +} + +.setting-group { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 1.5rem; + padding: 1rem; + background: rgba(60, 50, 40, 0.3); + border: 1px solid var(--ui-border-color); + border-radius: 12px; +} + +.setting-group label { + color: rgba(255, 255, 255, 0.9); + font-size: clamp(0.9rem, 2.2vw, 1rem); + font-weight: 600; + margin: 0; +} + +.theme-buttons { + display: flex; + gap: 0.75rem; +} + +.theme-buttons .theme-btn { + background: rgba(255, 255, 255, 0.2); + border: 2px solid rgba(255, 255, 255, 0.3); + border-radius: 12px; + padding: 8px 12px; + cursor: pointer; + font-size: 1.2rem; + transition: all 0.3s ease; + backdrop-filter: blur(10px); +} + +.theme-buttons .theme-btn:hover { + background: rgba(255, 255, 255, 0.3); + border-color: rgba(255, 255, 255, 0.6); + transform: scale(1.1); +} + +.theme-buttons .theme-btn.active { + background: rgba(255, 200, 100, 0.4); + border-color: rgba(255, 200, 100, 0.8); + box-shadow: 0 0 15px rgba(255, 200, 100, 0.3); +} + +.audio-btn { + display: flex; + align-items: center; + gap: 0.5rem; + background: rgba(255, 255, 255, 0.2); + border: 2px solid rgba(255, 255, 255, 0.3); + border-radius: 12px; + padding: 0.5rem 1rem; + cursor: pointer; + transition: all 0.3s ease; + backdrop-filter: blur(10px); + color: rgba(255, 255, 255, 0.9); + font-size: clamp(0.85rem, 2vw, 0.95rem); +} + +.audio-btn:hover { + background: rgba(255, 255, 255, 0.3); + border-color: rgba(255, 255, 255, 0.6); + transform: scale(1.05); +} + +.audio-icon { + font-size: 1.1em; +} + +.menu-footer { + text-align: center; + color: rgba(255, 255, 255, 0.6); + font-size: clamp(0.85rem, 2vw, 0.95rem); + margin: 0; + padding-top: 1rem; + border-top: 1px solid var(--ui-border-color); +} + +/* Instructions Button */ +#instructions-button { + position: absolute; + top: clamp(8px, 2.5vh, 20px); + left: clamp(12px, 2.5vw, 24px); + z-index: 11; +} + +.instructions-btn { + background: linear-gradient(145deg, rgba(255, 255, 255, 0.25), rgba(255, 255, 255, 0.1)); + border: none; + border-radius: 12px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2), inset 0 1px 1px rgba(255, 255, 255, 0.3); + text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + font-size: clamp(1.5rem, 4vw, 2.5rem); + font-weight: 900; + padding: 0.5rem 1.25rem; + cursor: pointer; + transition: transform 0.3s ease, box-shadow 0.3s ease; + color: white; + line-height: 1; + display: flex; + align-items: center; + justify-content: center; +} + +.instructions-btn:hover { + transform: scale(1.05); + box-shadow: 0 6px 25px rgba(0, 0, 0, 0.3), inset 0 1px 1px rgba(255, 255, 255, 0.3); +} + #results .content { padding: 2rem 2rem; width: 100%; @@ -530,6 +780,84 @@ a:visited { padding: 1.5rem 1.25rem; } + #instructions-menu { + min-width: 280px; + max-width: 92vw; + width: 90%; + max-height: 85vh; + } + + #instructions-menu .content { + padding: 1.5rem 1.25rem; + } + + #instructions-menu h2 { + font-size: 1.5rem; + margin-bottom: 1.5rem; + } + + .menu-section { + margin-bottom: 1.5rem; + } + + .menu-section h3 { + font-size: 1rem; + margin-bottom: 0.75rem; + } + + .instruction-content { + padding: 1rem; + } + + .instruction-content p { + font-size: 0.85rem; + } + + .instruction-content ul { + font-size: 0.8rem; + padding-left: 1.25rem; + } + + .controls-grid { + grid-template-columns: 1fr; + gap: 0.75rem; + } + + .control-item { + padding: 0.75rem 1rem; + } + + .control-item kbd { + font-size: 0.8rem; + padding: 0.3rem 0.6rem; + min-width: 50px; + } + + .control-item span { + font-size: 0.85rem; + } + + .setting-group { + flex-direction: column; + align-items: flex-start; + gap: 0.75rem; + padding: 0.75rem; + } + + .theme-buttons { + gap: 0.5rem; + } + + .theme-buttons .theme-btn { + padding: 6px 10px; + font-size: 1rem; + } + + .audio-btn { + padding: 0.4rem 0.8rem; + font-size: 0.8rem; + } + .score-container { flex-direction: column; gap: 1.5rem; diff --git a/index.html b/index.html index 70849f5..2ed6139 100644 --- a/index.html +++ b/index.html @@ -27,6 +27,81 @@ + +
+ +
+

Instructions & Controls

+ + + + + + + + + + + +
+
+
@@ -101,6 +176,11 @@

Game Over!

+ +
+ +
+