Spaces:
Running
Running
| <html lang="pt-BR"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Forca Mágica</title> | |
| <link rel="icon" type="image/x-icon" href="http://static.photos/gaming/64x64/42"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/animejs/lib/anime.iife.min.js"></script> | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Fredoka:wght@400;600;700&display=swap'); | |
| body { font-family: 'Fredoka', sans-serif; } | |
| .glow { box-shadow: 0 0 20px rgba(255,255,255,.35); } | |
| .btn-key { transition: transform .15s ease, background .2s ease; } | |
| .btn-key:hover { transform: translateY(-3px); } | |
| .btn-key:active { transform: translateY(0); } | |
| .shake { animation: shake .4s ease; } | |
| @keyframes shake { 0%,100%{transform:translateX(0)} 25%{transform:translateX(-6px)} 75%{transform:translateX(6px)} } | |
| .fade-in { animation: fadeIn .6s ease forwards; } | |
| @keyframes fadeIn { from{opacity:0;transform:translateY(20px)} to{opacity:1;transform:translateY(0)} } | |
| </style> | |
| </head> | |
| <body class="bg-gradient-to-br from-purple-900 via-indigo-900 to-black min-h-screen text-white flex items-center justify-center p-4"> | |
| <!-- Background Vanta Globe --> | |
| <div id="vanta" class="absolute inset-0 z-0"></div> | |
| <!-- Main Card --> | |
| <main class="relative z-10 w-full max-w-3xl bg-white/10 backdrop-blur-xl rounded-3xl shadow-2xl glow p-6 md:p-10 fade-in"> | |
| <!-- Header --> | |
| <header class="flex items-center justify-between mb-6"> | |
| <h1 class="text-2xl md:text-4xl font-bold tracking-wide flex items-center gap-3"> | |
| <i data-feather="zap" class="text-yellow-300"></i> | |
| Forca Mágica | |
| </h1> | |
| <button id="infoBtn" class="btn-icon text-indigo-200 hover:text-white transition"> | |
| <i data-feather="info"></i> | |
| </button> | |
| </header> | |
| <!-- Game Board --> | |
| <section class="grid md:grid-cols-2 gap-6"> | |
| <!-- Left: Gallows & Word --> | |
| <div class="flex flex-col items-center justify-center"> | |
| <canvas id="gallows" width="220" height="220" class="mb-4"></canvas> | |
| <div id="wordDisplay" class="text-3xl md:text-4xl font-bold tracking-widest select-none"></div> | |
| <p id="errors" class="mt-3 text-sm text-indigo-200">Erros: <span id="errCount">0</span> / 6</p> | |
| </div> | |
| <!-- Right: Keyboard & Actions --> | |
| <div class="flex flex-col gap-4"> | |
| <div id="keyboard" class="grid grid-cols-9 gap-2"></div> | |
| <div class="flex gap-3 mt-2"> | |
| <button id="newGame" class="flex-1 bg-gradient-to-r from-green-400 to-teal-400 text-black font-semibold py-3 rounded-xl shadow hover:shadow-lg transition transform hover:-translate-y-1"> | |
| 🎮 Nova Partida | |
| </button> | |
| <button id="hintBtn" class="bg-yellow-400 text-black font-semibold px-4 py-3 rounded-xl shadow hover:shadow-lg transition transform hover:-translate-y-1"> | |
| <i data-feather="lightbulb"></i> | |
| </button> | |
| </div> | |
| <p id="message" class="text-center text-sm text-indigo-200">Novo jogo iniciado! Tente adivinhar a palavra.</p> | |
| </div> | |
| </section> | |
| </main> | |
| <!-- Modal Info --> | |
| <div id="infoModal" class="fixed inset-0 bg-black/60 backdrop-blur-sm hidden items-center justify-center z-20"> | |
| <div class="bg-white/10 backdrop-blur-xl rounded-2xl p-6 max-w-md mx-4 text-center glow"> | |
| <h2 class="text-xl font-bold mb-2">Como jogar</h2> | |
| <p class="text-sm text-indigo-200 mb-4">Clique nas letras para adivinhar a palavra antes de completar a forca. Use a lâmpada para dicas!</p> | |
| <button id="closeModal" class="bg-indigo-500 hover:bg-indigo-600 px-4 py-2 rounded-lg transition">Entendi</button> | |
| </div> | |
| </div> | |
| <!-- Scripts --> | |
| <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.globe.min.js"></script> | |
| <script> | |
| VANTA.GLOBE({ el: "#vanta", mouseControls: true, touchControls: true, gyroControls: false, minHeight: 200.00, minWidth: 200.00, scale: 1.00, scaleMobile: 1.00, color: 0x3b82f6, backgroundColor: 0x111827 }) | |
| </script> | |
| <script> | |
| feather.replace(); | |
| const words = [ | |
| { w: "JAVASCRIPT", h: "Linguagem da web" }, | |
| { w: "TAILWIND", h: "Framework CSS utilitário" }, | |
| { w: "REACT", h: "Biblioteca para interfaces" }, | |
| { w: "DESIGN", h: "Arte de criar experiências" }, | |
| { w: "RESPONSIVE", h: "Adapta-se a qualquer tela" }, | |
| { w: "ANIMATION", h: "Dá vida à interface" }, | |
| { w: "GITHUB", h: "Rede de repositórios" }, | |
| { w: "CODING", h: "Escrever programas" } | |
| ]; | |
| let secret, display, errors, guessed, hint, canvas, ctx; | |
| function init() { | |
| canvas = document.getElementById("gallows"); | |
| ctx = canvas.getContext("2d"); | |
| ctx.strokeStyle = "#fff"; | |
| ctx.lineWidth = 3; | |
| newGame(); | |
| buildKeyboard(); | |
| } | |
| function newGame() { | |
| const pick = words[Math.floor(Math.random() * words.length)]; | |
| secret = pick.w; | |
| hint = pick.h; | |
| display = Array(secret.length).fill("_"); | |
| errors = 0; | |
| guessed = new Set(); | |
| updateWord(); | |
| drawGallows(); | |
| document.getElementById("errCount").textContent = errors; | |
| document.getElementById("message").textContent = "Novo jogo iniciado! Tente adivinhar a palavra."; | |
| document.querySelectorAll(".btn-key").forEach(b => b.disabled = false); | |
| } | |
| function buildKeyboard() { | |
| const kb = document.getElementById("keyboard"); | |
| kb.innerHTML = ""; | |
| "QWERTYUIOPASDFGHJKLZXCVBNM".split("").forEach(l => { | |
| const btn = document.createElement("button"); | |
| btn.className = "btn-key bg-indigo-500 hover:bg-indigo-600 text-white font-semibold rounded-lg h-10"; | |
| btn.textContent = l; | |
| btn.onclick = () => guess(l, btn); | |
| kb.appendChild(btn); | |
| }); | |
| } | |
| function guess(letter, btn) { | |
| if (guessed.has(letter) || errors >= 6 || !display.includes("_")) return; | |
| guessed.add(letter); | |
| btn.disabled = true; | |
| btn.classList.remove("bg-indigo-500", "hover:bg-indigo-600"); | |
| if (secret.includes(letter)) { | |
| btn.classList.add("bg-green-500"); | |
| for (let i = 0; i < secret.length; i++) if (secret[i] === letter) display[i] = letter; | |
| updateWord(); | |
| if (!display.includes("_")) endGame(true); | |
| } else { | |
| btn.classList.add("bg-red-500"); | |
| errors++; | |
| document.getElementById("errCount").textContent = errors; | |
| drawMan(); | |
| if (errors === 6) endGame(false); | |
| } | |
| } | |
| function updateWord() { | |
| document.getElementById("wordDisplay").textContent = display.join(" "); | |
| } | |
| function drawGallows() { | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| ctx.beginPath(); | |
| ctx.moveTo(20, 200); | |
| ctx.lineTo(120, 200); | |
| ctx.moveTo(70, 200); | |
| ctx.lineTo(70, 20); | |
| ctx.lineTo(150, 20); | |
| ctx.lineTo(150, 40); | |
| ctx.stroke(); | |
| } | |
| function drawMan() { | |
| ctx.beginPath(); | |
| if (errors === 1) { ctx.arc(150, 50, 10, 0, Math.PI * 2); ctx.stroke(); } // head | |
| if (errors === 2) { ctx.moveTo(150, 60); ctx.lineTo(150, 120); ctx.stroke(); } // body | |
| if (errors === 3) { ctx.moveTo(150, 80); ctx.lineTo(120, 100); ctx.stroke(); } // left arm | |
| if (errors === 4) { ctx.moveTo(150, 80); ctx.lineTo(180, 100); ctx.stroke(); } // right arm | |
| if (errors === 5) { ctx.moveTo(150, 120); ctx.lineTo(120, 160); ctx.stroke(); } // left leg | |
| if (errors === 6) { ctx.moveTo(150, 120); ctx.lineTo(180, 160); ctx.stroke(); } // right leg | |
| } | |
| function endGame(won) { | |
| const msg = won ? "🎉 Parabéns, você venceu!" : `😢 Game Over! A palavra era ${secret}`; | |
| document.getElementById("message").textContent = msg; | |
| document.querySelector("main").classList.add("shake"); | |
| setTimeout(() => document.querySelector("main").classList.remove("shake"), 400); | |
| } | |
| document.getElementById("newGame").onclick = newGame; | |
| document.getElementById("hintBtn").onclick = () => { | |
| if (hint) { | |
| document.getElementById("message").textContent = `💡 Dica: ${hint}`; | |
| anime({ targets: "#message", scale: [1, 1.05, 1], duration: 300 }); | |
| } | |
| }; | |
| document.getElementById("infoBtn").onclick = () => document.getElementById("infoModal").classList.remove("hidden"); | |
| document.getElementById("closeModal").onclick = () => document.getElementById("infoModal").classList.add("hidden"); | |
| init(); | |
| </script> | |
| </body> | |
| </html> | |