diff --git a/2048.css b/2048.css index aeb30ff..96c835d 100644 --- a/2048.css +++ b/2048.css @@ -534,16 +534,56 @@ h1 { } /* Tile Colors */ -.tile-2 { background: #00eaff55; box-shadow: 0 0 12px #00eaff; } -.tile-4 { background: #00ff9955; box-shadow: 0 0 12px #00ff99; } -.tile-8 { background: #ff00ff55; box-shadow: 0 0 12px #ff00ff; } -.tile-16 { background: #ff006655; box-shadow: 0 0 12px #ff0066; } -.tile-32 { background: #ffaa0055; box-shadow: 0 0 12px #ffaa00; } -.tile-64 { background: #ff000055; box-shadow: 0 0 12px #ff0000; } -.tile-128 { background: #5f00ff55; box-shadow: 0 0 12px #5f00ff; } -.tile-256 { background: #00ffea55; box-shadow: 0 0 12px #00ffea; } -.tile-512 { background: #ff00aa55; box-shadow: 0 0 12px #ff00aa; } -.tile-1024 { background: #00ffaa55; box-shadow: 0 0 12px #00ffaa; } +.tile-2 { + background: #00eaff55; + box-shadow: 0 0 12px #00eaff; +} + +.tile-4 { + background: #00ff9955; + box-shadow: 0 0 12px #00ff99; +} + +.tile-8 { + background: #ff00ff55; + box-shadow: 0 0 12px #ff00ff; +} + +.tile-16 { + background: #ff006655; + box-shadow: 0 0 12px #ff0066; +} + +.tile-32 { + background: #ffaa0055; + box-shadow: 0 0 12px #ffaa00; +} + +.tile-64 { + background: #ff000055; + box-shadow: 0 0 12px #ff0000; +} + +.tile-128 { + background: #5f00ff55; + box-shadow: 0 0 12px #5f00ff; +} + +.tile-256 { + background: #00ffea55; + box-shadow: 0 0 12px #00ffea; +} + +.tile-512 { + background: #ff00aa55; + box-shadow: 0 0 12px #ff00aa; +} + +.tile-1024 { + background: #00ffaa55; + box-shadow: 0 0 12px #00ffaa; +} + .tile-2048 { background: #ffd70066; box-shadow: 0 0 18px #ffd700; @@ -881,10 +921,6 @@ h1 { /* ========================== GAME OVER MODAL - WITH ICON BUTTONS ========================== */ -/* ========================== - GAME OVER MODAL - REVISED VERSION - Copy bagian ini dan replace yang lama di 2048.css -========================== */ .game-over-overlay { position: fixed; @@ -1237,219 +1273,6 @@ h1 { height: clamp(28px, 6vw, 34px); } } -/* ========================== - BACKGROUND EFFECTS -========================== */ -.particles { - position: fixed; - inset: 0; - pointer-events: none; - z-index: 0; - background: - radial-gradient(circle at 20% 30%, rgba(0,234,255,0.2), transparent 48%), - radial-gradient(circle at 80% 70%, rgba(255,0,90,0.2), transparent 48%), - radial-gradient(circle at 50% 50%, rgba(140,0,255,0.16), transparent 58%), - radial-gradient(circle at 10% 85%, rgba(0,255,200,0.14), transparent 58%), - radial-gradient(circle at 90% 15%, rgba(255,0,255,0.17), transparent 48%); - filter: blur(60px) brightness(125%) saturate(135%); - animation: particlesFloat 20s ease-in-out infinite alternate; -} - -@keyframes particlesFloat { - 0% { transform: translateY(0px) translateX(0px); } - 50% { transform: translateY(-30px) translateX(12px); } - 100% { transform: translateY(-45px) translateX(-18px); } -} - -/* Floating Particles from Bottom */ -.floating-particles { - position: fixed; - inset: 0; - overflow: hidden; - pointer-events: none; - z-index: 0; /* Di bawah semua elemen game */ -} - -.floating-particle { - position: absolute; - bottom: -20px; - width: 8px; - height: 8px; - background: rgba(0, 234, 255, 0.6); - border-radius: 50%; - filter: blur(1px); - box-shadow: 0 0 15px currentColor; - animation: floatUp linear infinite; -} - -@keyframes floatUp { - 0% { - transform: translateY(0) translateX(0) scale(0.5); - opacity: 0; - } - 10% { - opacity: 1; - } - 90% { - opacity: 0.6; - } - 100% { - transform: translateY(-100vh) translateX(var(--drift, 0)) scale(1.2); - opacity: 0; - } -} - -/* Different particle colors */ -.floating-particle.cyan { - background: rgba(0, 234, 255, 0.7); - box-shadow: 0 0 20px rgba(0, 234, 255, 0.8); -} - -.floating-particle.pink { - background: rgba(255, 0, 255, 0.6); - box-shadow: 0 0 20px rgba(255, 0, 255, 0.7); -} - -.floating-particle.purple { - background: rgba(200, 100, 255, 0.6); - box-shadow: 0 0 20px rgba(200, 100, 255, 0.7); -} - -.floating-particle.green { - background: rgba(0, 255, 200, 0.6); - box-shadow: 0 0 20px rgba(0, 255, 200, 0.7); -} - -.floating-particle.orange { - background: rgba(255, 170, 0, 0.6); - box-shadow: 0 0 20px rgba(255, 170, 0, 0.7); -} - -.starfield { - position: fixed; - inset: 0; - overflow: hidden; - pointer-events: none; - z-index: 1; -} - -.starfield span { - position: absolute; - width: 4px; - height: 4px; - background: rgba(0,255,255,0.85); - border-radius: 50%; - filter: blur(2px); - animation: starMove linear infinite; -} - -@keyframes starMove { - 0% { transform: translateY(0); opacity: 0.85; } - 100% { transform: translateY(-750px); opacity: 0; } -} - -.cursor-light { - position: absolute; - width: 250px; - height: 250px; - background: radial-gradient(circle, rgba(0,255,255,0.28), transparent 72%); - border-radius: 50%; - pointer-events: none; - transform: translate(-50%, -50%); - filter: blur(45px); - mix-blend-mode: screen; - opacity: 0.65; -} - -.merge-particle { - position: absolute; - width: 8px; - height: 8px; - border-radius: 50%; - pointer-events: none; - opacity: 0.95; - will-change: transform, opacity; - filter: blur(1px) drop-shadow(0 0 8px rgba(255,255,255,0.1)); -} -/* ========================== - ENHANCED BACKGROUND EFFECTS - -/* Update .particles styling */ -.particles { - position: fixed; - inset: 0; - pointer-events: none; - z-index: 0; - background: - radial-gradient(circle at 20% 30%, rgba(0,234,255,0.15), transparent 40%), - radial-gradient(circle at 80% 70%, rgba(255,0,90,0.15), transparent 40%), - radial-gradient(circle at 50% 50%, rgba(140,0,255,0.12), transparent 50%), - radial-gradient(circle at 10% 85%, rgba(0,255,200,0.1), transparent 50%), - radial-gradient(circle at 90% 15%, rgba(255,0,255,0.13), transparent 40%); - filter: blur(50px) brightness(110%); - animation: particlesFloat 18s ease-in-out infinite alternate; -} - -@keyframes particlesFloat { - 0% { - transform: translateY(0px) translateX(0px); - opacity: 0.8; - } - 50% { - transform: translateY(-25px) translateX(15px); - opacity: 1; - } - 100% { - transform: translateY(-40px) translateX(-20px); - opacity: 0.8; - } -} - -/* Enhanced Starfield */ -.starfield { - position: fixed; - inset: 0; - overflow: hidden; - pointer-events: none; - z-index: 1; -} - -.starfield span { - position: absolute; - width: 3px; - height: 3px; - background: rgba(0,255,255,0.7); - border-radius: 50%; - filter: blur(1.5px); - box-shadow: 0 0 8px rgba(0, 234, 255, 0.6); - animation: starMove linear infinite; -} - -@keyframes starMove { - 0% { - transform: translateY(0); - opacity: 0.7; - } - 100% { - transform: translateY(-750px); - opacity: 0; - } -} - -/* Enhanced Cursor Light */ -.cursor-light { - position: absolute; - width: 280px; - height: 280px; - background: radial-gradient(circle, rgba(0,255,255,0.2), rgba(255,0,255,0.15) 50%, transparent 70%); - border-radius: 50%; - pointer-events: none; - transform: translate(-50%, -50%); - filter: blur(50px); - mix-blend-mode: screen; - opacity: 0.5; - transition: opacity 0.3s ease; -} /* ========================== RESPONSIVE DESIGN diff --git a/2048.html b/2048.html index 594b472..fd1c92d 100644 --- a/2048.html +++ b/2048.html @@ -4,6 +4,13 @@ 2048 + + + + + + + @@ -320,5 +327,6 @@ + \ No newline at end of file diff --git a/2048_Background_Effects.css b/2048_Background_Effects.css new file mode 100644 index 0000000..e0b6d0a --- /dev/null +++ b/2048_Background_Effects.css @@ -0,0 +1,147 @@ +/* ========================== + BACKGROUND EFFECTS +========================== */ +.particles { + position: fixed; + inset: 0; + pointer-events: none; + z-index: 0; + background: + radial-gradient(circle at 20% 30%, rgba(0,234,255,0.2), transparent 48%), + radial-gradient(circle at 80% 70%, rgba(255,0,90,0.2), transparent 48%), + radial-gradient(circle at 50% 50%, rgba(140,0,255,0.16), transparent 58%), + radial-gradient(circle at 10% 85%, rgba(0,255,200,0.14), transparent 58%), + radial-gradient(circle at 90% 15%, rgba(255,0,255,0.17), transparent 48%); + filter: blur(60px) brightness(125%) saturate(135%); + animation: particlesFloat 20s ease-in-out infinite alternate; +} + +@keyframes particlesFloat { + 0% { transform: translateY(0px) translateX(0px); } + 50% { transform: translateY(-30px) translateX(12px); } + 100% { transform: translateY(-45px) translateX(-18px); } +} + +.starfield { + position: fixed; + inset: 0; + overflow: hidden; + pointer-events: none; + z-index: 1; +} + +.starfield span { + position: absolute; + width: 4px; + height: 4px; + background: rgba(0,255,255,0.85); + border-radius: 50%; + filter: blur(2px); + animation: starMove linear infinite; +} + +@keyframes starMove { + 0% { transform: translateY(0); opacity: 0.85; } + 100% { transform: translateY(-750px); opacity: 0; } +} + +.cursor-light { + position: absolute; + width: 250px; + height: 250px; + background: radial-gradient(circle, rgba(0,255,255,0.28), transparent 72%); + border-radius: 50%; + pointer-events: none; + transform: translate(-50%, -50%); + filter: blur(45px); + mix-blend-mode: screen; + opacity: 0.65; +} + +.merge-particle { + position: absolute; + width: 8px; + height: 8px; + border-radius: 50%; + pointer-events: none; + opacity: 0.95; + will-change: transform, opacity; + filter: blur(1px) drop-shadow(0 0 8px rgba(255,255,255,0.1)); +} +/* ENHANCED BACKGROUND EFFECTS */ +/* Update .particles styling */ +.particles { + position: fixed; + inset: 0; + pointer-events: none; + z-index: 0; + background: + radial-gradient(circle at 20% 30%, rgba(0,234,255,0.15), transparent 40%), + radial-gradient(circle at 80% 70%, rgba(255,0,90,0.15), transparent 40%), + radial-gradient(circle at 50% 50%, rgba(140,0,255,0.12), transparent 50%), + radial-gradient(circle at 10% 85%, rgba(0,255,200,0.1), transparent 50%), + radial-gradient(circle at 90% 15%, rgba(255,0,255,0.13), transparent 40%); + filter: blur(50px) brightness(110%); + animation: particlesFloat 18s ease-in-out infinite alternate; +} + +@keyframes particlesFloat { + 0% { + transform: translateY(0px) translateX(0px); + opacity: 0.8; + } + 50% { + transform: translateY(-25px) translateX(15px); + opacity: 1; + } + 100% { + transform: translateY(-40px) translateX(-20px); + opacity: 0.8; + } +} + +/* Enhanced Starfield */ +.starfield { + position: fixed; + inset: 0; + overflow: hidden; + pointer-events: none; + z-index: 1; +} + +.starfield span { + position: absolute; + width: 3px; + height: 3px; + background: rgba(0,255,255,0.7); + border-radius: 50%; + filter: blur(1.5px); + box-shadow: 0 0 8px rgba(0, 234, 255, 0.6); + animation: starMove linear infinite; +} + +@keyframes starMove { + 0% { + transform: translateY(0); + opacity: 0.7; + } + 100% { + transform: translateY(-750px); + opacity: 0; + } +} + +/* Enhanced Cursor Light */ +.cursor-light { + position: absolute; + width: 280px; + height: 280px; + background: radial-gradient(circle, rgba(0,255,255,0.2), rgba(255,0,255,0.15) 50%, transparent 70%); + border-radius: 50%; + pointer-events: none; + transform: translate(-50%, -50%); + filter: blur(50px); + mix-blend-mode: screen; + opacity: 0.5; + transition: opacity 0.3s ease; +} \ No newline at end of file diff --git a/2048_Floating_Particles.css b/2048_Floating_Particles.css new file mode 100644 index 0000000..e808223 --- /dev/null +++ b/2048_Floating_Particles.css @@ -0,0 +1,63 @@ +/* Floating Particles from Bottom */ +.floating-particles { + position: fixed; + inset: 0; + overflow: hidden; + pointer-events: none; + z-index: 0; /* Di bawah semua elemen game */ +} + +.floating-particle { + position: absolute; + bottom: -20px; + width: 8px; + height: 8px; + background: rgba(0, 234, 255, 0.6); + border-radius: 50%; + filter: blur(1px); + box-shadow: 0 0 15px currentColor; + animation: floatUp linear infinite; +} + +@keyframes floatUp { + 0% { + transform: translateY(0) translateX(0) scale(0.5); + opacity: 0; + } + 10% { + opacity: 1; + } + 90% { + opacity: 0.6; + } + 100% { + transform: translateY(-100vh) translateX(var(--drift, 0)) scale(1.2); + opacity: 0; + } +} + +/* Different particle colors */ +.floating-particle.cyan { + background: rgba(0, 234, 255, 0.7); + box-shadow: 0 0 20px rgba(0, 234, 255, 0.8); +} + +.floating-particle.pink { + background: rgba(255, 0, 255, 0.6); + box-shadow: 0 0 20px rgba(255, 0, 255, 0.7); +} + +.floating-particle.purple { + background: rgba(200, 100, 255, 0.6); + box-shadow: 0 0 20px rgba(200, 100, 255, 0.7); +} + +.floating-particle.green { + background: rgba(0, 255, 200, 0.6); + box-shadow: 0 0 20px rgba(0, 255, 200, 0.7); +} + +.floating-particle.orange { + background: rgba(255, 170, 0, 0.6); + box-shadow: 0 0 20px rgba(255, 170, 0, 0.7); +} \ No newline at end of file diff --git a/Leaderboard.css b/Leaderboard.css index 0daa4d3..b35c1ea 100644 --- a/Leaderboard.css +++ b/Leaderboard.css @@ -2,6 +2,7 @@ /* Main Container */ .container { + margin-top: 70px; position: relative; z-index: 2; background: rgba(20, 0, 40, 0.65); diff --git a/Leaderboard_Components.css b/Leaderboard_Components.css index ca3e29d..46b191a 100644 --- a/Leaderboard_Components.css +++ b/Leaderboard_Components.css @@ -3,8 +3,8 @@ /* Back Button */ .btn-back { position: fixed; - top: 30px; - left: 30px; + top: 20px; + left: 20px; z-index: 100; width: 50px; height: 50px; diff --git a/Register.css b/Register.css index 853c38d..f9ceef5 100644 --- a/Register.css +++ b/Register.css @@ -1,4 +1,3 @@ -/* register-form.css */ .input-group { margin-bottom: 25px; } @@ -28,19 +27,15 @@ input::placeholder { width: 100%; padding: 15px; margin-top: 10px; - background: linear-gradient(90deg, #00eaff, #ff00ff); border: none; border-radius: 12px; - color: #fff; font-weight: bold; text-transform: uppercase; font-size: 18px; - letter-spacing: 2px; cursor: pointer; - box-shadow: 0 5px 25px rgba(0, 217, 255, 0.4); transition: all 0.25s ease; } diff --git a/Register.js b/Register.js index dcb1d10..0f51ab4 100644 --- a/Register.js +++ b/Register.js @@ -37,24 +37,44 @@ document.getElementById("registerForm").addEventListener("submit", async functio // 1. Tampilkan modal sukses showModal("success", "Register Successful!", data.message); - // 🔥 PERBAIKAN: SAVE SCORE & REDIRECT 🔥 - - // Coba simpan skor jika variable 'score' atau 'gameScore' tersedia di global scope - // Atau jika kamu menyimpan skor sementara di localStorage - const pendingScore = localStorage.getItem('lastScore'); // Contoh jika pakai localStorage - + // 2. Simpan Score (Logic Anda) + const pendingScore = localStorage.getItem('lastScore'); if (pendingScore && typeof saveScore === "function") { console.log("Menyimpan skor pending: " + pendingScore); saveScore(pendingScore); } else if (typeof score !== 'undefined') { - // Jika variabel global 'score' ada (dari file game logic) saveScore(score); } - // Redirect ke halaman utama setelah 1.5 detik - setTimeout(() => { - window.location.href = "index.html"; // Ubah sesuai halaman game/menu kamu - }, 1500); + // --- 🔥 PERUBAHAN DI SINI 🔥 --- + + // Cari tombol OK pada modal. + // PENTING: Pastikan ID ini ("modalOkBtn") sesuai dengan ID tombol OK di HTML/Modal Anda. + // Jika ID-nya beda, ganti string di bawah ini. + + // --- 🔥 TAMBAHKAN KODE DI SINI (Bagian Tombol OK) 🔥 --- + + const okBtn = document.getElementById("modalOkBtn"); + + if (okBtn) { + okBtn.addEventListener("click", function() { + // [BARU] Simpan username ke sessionStorage AGAR TUTORIAL MUNCUL + // Ini penting supaya logic di 2048.js tahu ini user baru + sessionStorage.setItem("loggedInUser", username); + + // Setelah disimpan, baru pindah ke Homepage + window.location.href = "Homepage.html"; + }, { once: true }); + + } else { + // Fallback jika tombol error + console.warn("Tombol OK tidak ditemukan, redirect otomatis."); + setTimeout(() => { + // [BARU] Simpan juga disini buat jaga-jaga + sessionStorage.setItem("loggedInUser", username); + window.location.href = "Homepage.html"; + }, 2000); + } } else { showModal("error", "Register Failed!", data.message || "An error occurred."); diff --git a/Register_Modal.css b/Register_Modal.css index d0b2bc4..3a18be3 100644 --- a/Register_Modal.css +++ b/Register_Modal.css @@ -1,4 +1,3 @@ -/* register-modal.css */ .modal { display: none; position: fixed; diff --git a/Register_Responsive.css b/Register_Responsive.css index 9043052..2b75329 100644 --- a/Register_Responsive.css +++ b/Register_Responsive.css @@ -1,4 +1,3 @@ -/* register-responsive.css */ @media (max-width: 480px) { .container { padding: 30px 25px; diff --git a/Tutorial_Logic.js b/Tutorial_Logic.js new file mode 100644 index 0000000..f13bbce --- /dev/null +++ b/Tutorial_Logic.js @@ -0,0 +1,52 @@ +/* ---------------------------------------------------- + FILE: Tutorial_Logic.js + ---------------------------------------------------- */ + +// Kita buat fungsi agar bisa dipanggil manual jika perlu +function checkAndShowTutorial() { + // 1. Ambil user terbaru saat fungsi dijalankan + const currentUser = sessionStorage.getItem("loggedInUser") || "guest"; + const tutorialKey = 'tutorialSeen_' + currentUser; + + // DEBUG: Cek di Console browser (tekan F12 -> Console) + console.log(`[Tutorial Check] User: ${currentUser}`); + console.log(`[Tutorial Check] Key: ${tutorialKey}`); + + // 2. Cek status di LocalStorage + const hasSeenTutorial = localStorage.getItem(tutorialKey); + console.log(`[Tutorial Check] Status Seen: ${hasSeenTutorial}`); + + const tutorialOverlay = document.getElementById('tutorial-overlay'); + + // 3. Logic: Jika belum pernah lihat (null) -> Tampilkan + if (!hasSeenTutorial && tutorialOverlay) { + console.log("-> Menampilkan Tutorial untuk user baru."); + tutorialOverlay.style.display = 'flex'; + } else { + console.log("-> User ini sudah pernah lihat tutorial (atau overlay tidak ketemu)."); + } +} + +// Jalankan otomatis saat halaman selesai loading +document.addEventListener('DOMContentLoaded', () => { + checkAndShowTutorial(); + + // Setup tombol close hanya sekali + const closeTutorialBtn = document.getElementById('close-tutorial'); + const tutorialOverlay = document.getElementById('tutorial-overlay'); + + if (closeTutorialBtn) { + closeTutorialBtn.addEventListener('click', () => { + // Ambil user SAAT INI (penting jika user berubah tanpa reload) + const currentUser = sessionStorage.getItem("loggedInUser") || "guest"; + const tutorialKey = 'tutorialSeen_' + currentUser; + + if(tutorialOverlay) tutorialOverlay.style.display = 'none'; + localStorage.setItem(tutorialKey, 'true'); + console.log(`[Tutorial Check] Disimpan: ${tutorialKey} = true`); + }); + } +}); + +// (Opsional) Bikin global biar bisa dipanggil dari file lain/console +window.checkTutorial = checkAndShowTutorial; \ No newline at end of file