diff --git a/Js/script.js b/Js/script.js index b8af3de..52b7b07 100644 --- a/Js/script.js +++ b/Js/script.js @@ -19,6 +19,8 @@ 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 shortcutsHelpElement = document.getElementById("shortcuts-help"); +const closeShortcutsButton = document.getElementById("close-shortcuts"); // High score const HIGH_SCORE_KEY = "stackerHighScore"; @@ -184,7 +186,7 @@ function init() { 0, // near plane 100 // far plane ); - + /* // If you want to use perspective camera instead, uncomment these lines camera = new THREE.PerspectiveCamera( @@ -412,6 +414,9 @@ function splitBlockAndAddNextOneIfOverlaps() { const overhangSize = Math.abs(delta); const overlap = size - overhangSize; + const overlapPercent = Math.max(0, Math.round((overlap / size) * 100)); + showOverlapPopup(overlapPercent); + const overlapPercent = Math.max(0,Math.round((overlap / size) * 100)); showOverlapPopup(overlapPercent); @@ -437,7 +442,7 @@ function splitBlockAndAddNextOneIfOverlaps() { scoreElement.classList.add("score-updated"); setTimeout(() => { scoreElement.classList.remove("score-updated"); - }, 400); // Remove class after animation duration + }, 400); } } else { missedTheSpot(); @@ -451,6 +456,11 @@ function showOverlapPopup(percent) { // Color feedback if (percent >= 90) { + popup.style.background = "rgba(0, 128, 0, 0.8)"; + } else if (percent >= 60) { + popup.style.background = "rgba(255, 165, 0, 0.8)"; + } else { + popup.style.background = "rgba(178, 34, 34, 0.8)"; popup.style.background = "rgba(0, 128, 0, 0.8)"; // green } else if (percent >= 60) { popup.style.background = "rgba(255, 165, 0, 0.8)"; // orange @@ -481,7 +491,7 @@ function missedTheSpot() { gameEnded = true; // Evaluate and update high score - const currentScore = Math.max(0, stack.length - 2); // Exclude foundation and first moving layer + const currentScore = Math.max(0, stack.length - 2); if (currentScore > highScore) { highScore = currentScore; @@ -490,7 +500,7 @@ function missedTheSpot() { if (endScoreElement) endScoreElement.innerText = `${currentScore} ◆`; if (endHighScoreElement) endHighScoreElement.innerText = `${highScore} ◆`; updateRestartMessage(); - // Show results dialog when game ends + if (resultsElement) { setTimeout(() => { resultsElement.style.display = "flex"; @@ -505,11 +515,14 @@ const muteBtn = document.createElement("button"); muteBtn.id = "muteBtn"; muteBtn.textContent = "🔊"; document.body.appendChild(muteBtn); -muteBtn.addEventListener("click", () => { + +function toggleMute() { muted = !muted; sounds.bgm.muted = muted; muteBtn.textContent = muted ? "🔇" : "🔊"; -}); +} + +muteBtn.addEventListener("click", toggleMute); function enableBackgroundMusic() { sounds.bgm.play().catch(() => { }); @@ -525,6 +538,7 @@ function playPlaceSound() { s.play().catch(() => { }); } } + function playFailSound() { if (!muted) { const s = sounds.fail.cloneNode(); @@ -533,6 +547,24 @@ function playFailSound() { } } +// ----- Shortcuts Modal ----- +function openShortcuts() { + if (shortcutsHelpElement) shortcutsHelpElement.style.display = "flex"; +} + +function closeShortcuts() { + if (shortcutsHelpElement) shortcutsHelpElement.style.display = "none"; +} + +function toggleShortcuts() { + if (!shortcutsHelpElement) return; + if (shortcutsHelpElement.style.display === "flex") { + closeShortcuts(); + } else { + openShortcuts(); + } +} + // ----- Event Handlers ----- function eventHandler() { autopilot ? startGame() : splitBlockAndAddNextOneIfOverlaps(); @@ -554,21 +586,37 @@ document.addEventListener("keydown", (e) => { startGame(); } } -}, true); + if (e.key === "m" || e.key === "M") { + e.preventDefault(); + toggleMute(); + } + if (e.key === "h" || e.key === "H") { + e.preventDefault(); + toggleShortcuts(); + } + if (e.key === "Escape") { + e.preventDefault(); + if (shortcutsHelpElement && shortcutsHelpElement.style.display === "flex") { + closeShortcuts(); + } else if (resultsElement && resultsElement.style.display === "flex") { + resultsElement.style.display = "none"; + } + } +}, false); + window.addEventListener( "touchstart", (e) => { 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(".twitter-link") || + e.target.closest("#muteBtn") || + e.target.closest("#theme-controls") || + e.target.closest("#shortcuts-help") || e.target.closest("#close-results") ) { - // If it was, do nothing and let the browser handle the 'click' event return; } - // Otherwise, it's a tap for the game e.preventDefault(); gameEnded ? startGame() : eventHandler(); }, @@ -585,6 +633,13 @@ if (closeResultsBtn) { }); } +// Close shortcuts dialog button +if (closeShortcutsButton) { + closeShortcutsButton.addEventListener("click", () => { + closeShortcuts(); + }); +} + window.addEventListener("resize", () => { setResponsiveBoxSize(); const aspect = window.innerWidth / window.innerHeight; diff --git a/css/style.css b/css/style.css index 2c593c2..6e65bc8 100644 --- a/css/style.css +++ b/css/style.css @@ -54,12 +54,10 @@ body { inset 0 1px 0 rgba(255, 220, 150, 0.15); backdrop-filter: blur(10px); width: 90%; - /* take most of the screen */ max-width: 700px; - /* limit on large screens */ min-width: 280px; - /* minimum size on small devices */ animation: resultsFadeIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); + position: fixed; } @keyframes resultsFadeIn { @@ -146,10 +144,10 @@ body { margin: 2.3rem 0; align-items: stretch; justify-content: center; - animation: slideUp 0.5s ease-out 0.2s backwards; + animation: slideUpAnim 0.5s ease-out 0.2s backwards; } -@keyframes slideUp { +@keyframes slideUpAnim { from { opacity: 0; transform: translateY(20px); @@ -226,7 +224,6 @@ body { } @keyframes pulse { - 0%, 100% { transform: scale(1); @@ -253,7 +250,7 @@ body { margin: 2rem 0 1rem; color: rgba(255, 255, 255, 0.8); font-size: clamp(0.85rem, 2.2vw, 1rem); - animation: slideUp 0.5s ease-out 0.4s backwards; + animation: slideUpAnim 0.5s ease-out 0.4s backwards; } .restart-icon { @@ -295,7 +292,7 @@ body { border-top: 1px solid rgba(255, 200, 100, 0.15); color: rgba(255, 255, 255, 0.7); font-size: clamp(0.85rem, 2.2vw, 0.95rem); - animation: slideUp 0.5s ease-out 0.6s backwards; + animation: slideUpAnim 0.5s ease-out 0.6s backwards; } .twitter-link { @@ -347,7 +344,6 @@ body { position: absolute; top: clamp(8px, 2.5vh, 20px); left: clamp(12px, 2.5vw, 24px); - /* Changed from 'right' */ font-family: "Montserrat", sans-serif; font-size: clamp(1.5rem, 4vw, 2.5rem); font-weight: 900; @@ -362,19 +358,13 @@ body { display: flex; align-items: center; justify-content: center; - /* Added to center the icon */ transition: transform 0.3s ease, box-shadow 0.3s ease; color: white; - /* Added to make sure icon is visible */ border: none; - /* Added from JS */ cursor: pointer; - /* Added from JS */ line-height: 1; - /* Helps center the icon */ } -/* Optional: Add a matching hover effect */ #muteBtn: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); @@ -412,6 +402,7 @@ body { animation: score-pop 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); } +/* Overlap feedback styles */ /* Overlop feedback styles */ #overlap-popup { position: absolute; @@ -430,14 +421,13 @@ body { opacity: 0; transition: opacity 0.3s ease, transform 0.3s ease; } + #overlap-popup.show { display: block; opacity: 1; transform: translateX(-50%) scale(1.05); } - - #youtube { position: absolute; bottom: 10px; @@ -470,7 +460,7 @@ a:visited { color: inherit; } -/* Add diamond icon after score */ +/* Add diamond icon after score value */ .score-value::after { content: '◆'; display: inline-block; @@ -479,41 +469,17 @@ a:visited { transform: translateY(-0.1em); } -/* Theme Controls */ -.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-btn:hover { - background: rgba(255, 255, 255, 0.3); - border-color: rgba(255, 255, 255, 0.6); - transform: scale(1.1); -} - -.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); -} - /* Close Button */ .close-btn { position: absolute; - top: 10px; - right: 10px; - background: rgba(255, 200, 100, 0.2); - border: 2px solid rgba(255, 200, 100, 0.4); - color: rgba(255, 200, 100, 0.8); - font-size: 2rem; - width: 40px; - height: 40px; + top: 15px; + right: 15px; + background: rgba(255, 100, 100, 0.3); + border: 2px solid rgba(255, 100, 100, 0.5); + color: #fff; + font-size: 1.8rem; + width: 45px; + height: 45px; border-radius: 50%; cursor: pointer; display: flex; @@ -523,13 +489,161 @@ a:visited { z-index: 100; padding: 0; line-height: 1; + font-weight: 300; } .close-btn:hover { - background: rgba(255, 200, 100, 0.4); - border-color: rgba(255, 200, 100, 0.8); + background: rgba(255, 100, 100, 0.6); + border-color: rgba(255, 100, 100, 0.9); + color: #fff; + transform: scale(1.1) rotate(90deg); +} + +/* Keyboard Shortcuts Help Overlay */ +#shortcuts-help { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.7); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + display: none; + align-items: center; + justify-content: center; + z-index: 1000; + animation: fadeIn 0.3s ease; +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +.shortcuts-content { + position: relative; + background: linear-gradient(135deg, rgba(50, 40, 30, 0.95), rgba(40, 35, 25, 0.95)); + border-radius: 20px; + padding: 2rem; + max-width: 500px; + width: 90%; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5), + 0 0 0 1px rgba(255, 200, 100, 0.2), + inset 0 1px 0 rgba(255, 220, 150, 0.15); + animation: slideUp 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); +} + +@keyframes slideUp { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.shortcuts-header { + display: flex; + align-items: center; + gap: 1rem; + margin-bottom: 2rem; + padding-bottom: 1rem; + border-bottom: 1px solid rgba(255, 200, 100, 0.2); +} + +.keyboard-icon { + width: 2rem; + height: 2rem; + color: #ffd700; + filter: drop-shadow(0 0 8px rgba(255, 215, 0, 0.5)); +} + +.shortcuts-header h2 { + margin: 0; + font-size: clamp(1.5rem, 4vw, 2rem); + font-weight: 900; + background: linear-gradient(135deg, #ffd93d, #ffb84d); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} + +.shortcuts-list { + display: flex; + flex-direction: column; + gap: 1rem; + margin-bottom: 1.5rem; +} + +.shortcut-item { + display: flex; + align-items: center; + gap: 1.5rem; + padding: 0.75rem 1rem; + background: rgba(60, 50, 40, 0.4); + border: 1px solid rgba(255, 200, 100, 0.1); + border-radius: 12px; + transition: all 0.3s ease; +} + +.shortcut-item:hover { + background: rgba(80, 65, 50, 0.5); + border-color: rgba(255, 200, 100, 0.25); + transform: translateX(5px); +} + +.shortcut-item kbd { + min-width: 60px; + text-align: center; + background: linear-gradient(135deg, rgba(80, 60, 40, 0.6), rgba(60, 45, 30, 0.6)); + border: 1px solid rgba(255, 200, 100, 0.3); + border-radius: 8px; + padding: 0.5rem 1rem; + font-family: 'Courier New', monospace; + font-weight: 700; + font-size: 1rem; + box-shadow: 0 2px 0 rgba(0, 0, 0, 0.3), + inset 0 1px 0 rgba(255, 220, 150, 0.2); + color: #ffcc00; +} + +.shortcut-desc { + flex: 1; + color: rgba(255, 255, 255, 0.9); + font-size: 1rem; + font-weight: 500; +} + +.shortcuts-footer { + padding-top: 1rem; + border-top: 1px solid rgba(255, 200, 100, 0.15); + text-align: center; +} + +.shortcuts-footer p { + margin: 0; + color: rgba(255, 255, 255, 0.7); + font-size: 0.9rem; +} + +.shortcuts-footer kbd { + background: linear-gradient(135deg, rgba(80, 60, 40, 0.6), rgba(60, 45, 30, 0.6)); + border: 1px solid rgba(255, 200, 100, 0.3); + border-radius: 6px; + padding: 0.2rem 0.5rem; + font-family: 'Courier New', monospace; + font-weight: 700; + font-size: 0.85rem; + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), + inset 0 1px 0 rgba(255, 220, 150, 0.15); color: #ffcc00; - transform: scale(1.1); } /* Responsive tweaks for small screens */ @@ -539,7 +653,6 @@ a:visited { margin: 0.25rem 0; } - /* Make instructions more compact on mobile */ #instructions { top: clamp(8px, 2vh, 16px); padding: 0.5rem 0.8rem; @@ -609,7 +722,6 @@ a:visited { right: clamp(8px, 2vw, 16px); } - /* Improve touch targets */ .restart-hint { font-size: 0.9rem; padding: 0.4rem; @@ -640,11 +752,48 @@ a:visited { height: 0.85rem; } - /* Make restart message more prominent on mobile */ .restart-hint kbd { font-size: 0.9rem; padding: 0.35rem 0.65rem; } + + /* Shortcuts overlay responsive */ + .shortcuts-content { + padding: 1.5rem; + max-width: 90vw; + } + + .shortcuts-header { + margin-bottom: 1.5rem; + } + + .keyboard-icon { + width: 1.5rem; + height: 1.5rem; + } + + .shortcuts-header h2 { + font-size: 1.5rem; + } + + .shortcuts-list { + gap: 0.75rem; + } + + .shortcut-item { + gap: 1rem; + padding: 0.6rem 0.8rem; + } + + .shortcut-item kbd { + min-width: 50px; + padding: 0.4rem 0.8rem; + font-size: 0.9rem; + } + + .shortcut-desc { + font-size: 0.9rem; + } } /* Add landscape mobile optimization */ @@ -708,16 +857,13 @@ a:visited { body { -webkit-tap-highlight-color: rgba(255, 200, 100, 0.1); touch-action: none; - /* Prevent unwanted touch gestures during gameplay */ } - /* Make tappable areas more obvious */ #results, #instructions { touch-action: manipulation; } - /* Ensure minimum touch target sizes (44x44px recommended) */ .score-card { min-height: 80px; padding: 1.2rem 1rem; @@ -769,6 +915,20 @@ a:visited { .social-follow { font-size: 0.8rem; } + + .shortcuts-content { + padding: 1.25rem; + } + + .shortcut-item { + flex-direction: column; + gap: 0.5rem; + text-align: center; + } + + .shortcut-item kbd { + width: 100%; + } } @media (min-width: 1200px) { diff --git a/index.html b/index.html index 9378d28..6a57beb 100644 --- a/index.html +++ b/index.html @@ -93,10 +93,64 @@

Game Over!

+ +
+ +
+
+ + + + + + + + + + + +

Keyboard Shortcuts

+
+ +
+
+ Space + Drop/Stack Block +
+ +
+ R + Restart Game +
+ +
+ M + Mute/Unmute Audio +
+ +
+ H + Toggle This Help +
+ +
+ Esc + Close Dialogs +
+
+ + +
+
+
0
+
100%
100%
@@ -107,6 +161,12 @@

Game Over!

+ +
+ + + +