Chotto.app
Login
Sign Up
ES
App Name
kuyawa / hangman
App Icon in SVG
<svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"> <!-- Definitions for Gradients and Shadows --> <defs> <!-- Background Gradient (Blue to Teal) --> <linearGradient id="bgGradient" x1="0%" y1="100%" x2="100%" y2="0%"> <stop offset="0%" stop-color="#213B82" /> <stop offset="100%" stop-color="#14BCC1" /> </linearGradient> <!-- Stick Figure Inner Shadow for depth --> <filter id="innerShadow" x="-20%" y="-20%" width="140%" height="140%"> <feGaussianBlur in="SourceAlpha" stdDeviation="3" result="blur"/> <feOffset dy="4" dx="0"/> <feComposite in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadow"/> <feFlood flood-color="#000000" flood-opacity="0.3"/> <feComposite in2="shadow" operator="in" result="shadow"/> <feComposite in2="SourceGraphic" operator="over"/> </filter> </defs> <!-- App Icon Rounded Background --> <rect width="512" height="512" rx="115" fill="url(#bgGradient)" /> <!-- Gallows Structure (Wooden, simplified) --> <g stroke="#E0E6ED" stroke-width="20" stroke-linecap="round" stroke-linejoin="round" fill="none"> <path d="M 120 440 L 400 440" /> <!-- Base --> <path d="M 180 440 L 180 72" /> <!-- Post --> <path d="M 180 72 L 360 72" /> <!-- Top Beam --> <path d="M 230 72 C 230 110 230 110 230 110" /> <!-- Angled Support --> </g> <!-- Rope and Coil --> <g stroke="#E0E6ED" stroke-width="20" stroke-linecap="round" stroke-linejoin="round" fill="none"> <path d="M 360 72 L 360 120" /> <!-- Rope down --> <ellipse cx="360" cy="150" rx="30" ry="30" stroke="#E0E6ED" /> <!-- Coil --> </g> <!-- Stick Figure (Friendly and Fully Formed) --> <g filter="url(#innerShadow)"> <circle cx="360" cy="190" r="40" fill="#E0E6ED" stroke="#E0E6ED" stroke-width="6"/> <!-- Head --> <line x1="360" y1="230" x2="360" y2="330" stroke="#E0E6ED" stroke-width="16" stroke-linecap="round"/> <!-- Body --> <line x1="360" y1="250" x2="300" y2="290" stroke="#E0E6ED" stroke-width="16" stroke-linecap="round"/> <!-- Left Arm --> <line x1="360" y1="250" x2="420" y2="290" stroke="#E0E6ED" stroke-width="16" stroke-linecap="round"/> <!-- Right Arm --> <line x1="360" y1="330" x2="310" y2="400" stroke="#E0E6ED" stroke-width="16" stroke-linecap="round"/> <!-- Left Leg --> <line x1="360" y1="330" x2="410" y2="400" stroke="#E0E6ED" stroke-width="16" stroke-linecap="round"/> <!-- Right Leg --> <!-- Friendly Face Details --> <circle cx="345" cy="182" r="4" fill="#333"/> <!-- Left Eye --> <circle cx="375" cy="182" r="4" fill="#333"/> <!-- Right Eye --> <path d="M 345 205 C 345 212, 375 212, 375 205" stroke="#ED1C24" stroke-width="4" fill="none" stroke-linecap="round"/> <!-- Smile --> </g> <!-- Game Interface Elements --> <!-- Top: 'H' and '?' --> <text x="360" y="55" font-family="Arial, sans-serif" font-size="60" fill="#E0E6ED" text-anchor="middle" font-weight="bold">H ?</text> <!-- Bottom: Underscore Slots and red 'X' --> <g transform="translate(160, 470)" stroke="#E0E6ED" stroke-width="8" stroke-linecap="round"> <line x1="0" y1="0" x2="30" y2="0" /> <!-- slot 1 --> <line x1="40" y1="0" x2="70" y2="0" /> <!-- slot 2 --> <line x1="80" y1="0" x2="110" y2="0" /> <!-- slot 3 --> <line x1="120" y1="0" x2="150" y2="0" /> <!-- slot 4 --> <line x1="160" y1="0" x2="190" y2="0" /> <!-- slot 5 --> </g> <text x="440" y="475" font-family="Arial, sans-serif" font-size="40" fill="#ED1C24" text-anchor="middle" font-weight="bold">X</text> </svg>
HTML Content
<!DOCTYPE html> <html lang="en" data-theme="dark"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Hangman</title> <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet"> <style> :root { --speed: 0.3s; } [data-theme="dark"] { --bg: #0c0c0c; --bg2: #161616; --fg: #ece8df; --muted: #7a7468; --accent: #e8a838; --accent-glow: rgba(232,168,56,0.12); --card: #181818; --border: #262626; --danger: #e84848; --success: #48c878; --key-bg: #1e1e1e; --key-hover: #2a2a2a; --key-border: #333; --key-correct-bg: rgba(72,200,120,0.1); --key-wrong-bg: rgba(232,72,72,0.1); --svg-stroke: #ece8df; --svg-body: #e8a838; --shadow: 0 4px 30px rgba(0,0,0,0.5); --overlay: rgba(0,0,0,0.65); } [data-theme="light"] { --bg: #f4efe5; --bg2: #eae4d6; --fg: #1a1612; --muted: #8a7e6e; --accent: #c07e18; --accent-glow: rgba(192,126,24,0.08); --card: #fff; --border: #ddd4c4; --danger: #c82828; --success: #2a9858; --key-bg: #ede7db; --key-hover: #e0d9cb; --key-border: #ccc3b3; --key-correct-bg: rgba(42,152,88,0.08); --key-wrong-bg: rgba(200,40,40,0.08); --svg-stroke: #1a1612; --svg-body: #c07e18; --shadow: 0 4px 30px rgba(0,0,0,0.06); --overlay: rgba(0,0,0,0.35); } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Space Grotesk', sans-serif; background: var(--bg); color: var(--fg); min-height: 100vh; transition: background var(--speed), color var(--speed); overflow-x: hidden; } /* Atmospheric background */ body::before { content: ''; position: fixed; inset: 0; background: radial-gradient(ellipse at 15% 50%, var(--accent-glow) 0%, transparent 55%), radial-gradient(ellipse at 85% 15%, var(--accent-glow) 0%, transparent 45%), radial-gradient(ellipse at 50% 90%, var(--accent-glow) 0%, transparent 50%); pointer-events: none; z-index: 0; } body::after { content: ''; position: fixed; inset: 0; background-image: linear-gradient(var(--border) 1px, transparent 1px), linear-gradient(90deg, var(--border) 1px, transparent 1px); background-size: 80px 80px; opacity: 0.1; pointer-events: none; z-index: 0; } .container { position: relative; z-index: 1; max-width: 920px; margin: 0 auto; padding: 16px 20px; min-height: 100vh; display: flex; flex-direction: column; } /* Header */ header { display: flex; justify-content: space-between; align-items: center; padding: 12px 0 20px; } .logo { font-size: 1.5rem; font-weight: 700; letter-spacing: -0.5px; } .logo span { color: var(--accent); } .header-right { display: flex; align-items: center; gap: 14px; } .stats { display: flex; gap: 14px; font-size: 0.82rem; color: var(--muted); font-family: 'JetBrains Mono', monospace; } .stat-val { color: var(--accent); font-weight: 700; } .btn-icon { width: 38px; height: 38px; display: flex; align-items: center; justify-content: center; background: var(--key-bg); border: 1px solid var(--border); border-radius: 10px; cursor: pointer; color: var(--fg); transition: all 0.2s; flex-shrink: 0; } .btn-icon:hover { background: var(--key-hover); transform: translateY(-1px); } .btn-icon svg { width: 18px; height: 18px; } /* Theme toggle */ .theme-toggle { position: relative; width: 50px; height: 28px; background: var(--key-bg); border: 1px solid var(--border); border-radius: 14px; cursor: pointer; transition: all var(--speed); flex-shrink: 0; } .theme-toggle::after { content: ''; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; background: var(--accent); border-radius: 50%; transition: transform var(--speed); box-shadow: 0 2px 6px rgba(0,0,0,0.2); } [data-theme="light"] .theme-toggle::after { transform: translateX(22px); } .theme-icons { position: absolute; inset: 0; display: flex; align-items: center; justify-content: space-between; padding: 0 7px; font-size: 11px; pointer-events: none; line-height: 1; } /* Main game layout */ .game-area { flex: 1; display: flex; flex-direction: column; gap: 28px; } .top-row { display: grid; grid-template-columns: 260px 1fr; gap: 28px; align-items: start; } /* Hangman panel */ .hangman-panel { background: var(--card); border: 1px solid var(--border); border-radius: 18px; padding: 20px; box-shadow: var(--shadow); transition: all var(--speed); position: relative; overflow: hidden; } .hangman-panel::after { content: ''; position: absolute; bottom: 0; left: 0; right: 0; height: 60%; background: radial-gradient(ellipse at 50% 100%, var(--accent-glow), transparent 70%); pointer-events: none; } .hangman-svg { width: 100%; display: block; position: relative; z-index: 1; } .hangman-svg .gallows { stroke: var(--svg-stroke); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; fill: none; opacity: 0.6; } .hangman-svg .gallows-main { opacity: 1; } .hangman-svg .bp { stroke: var(--svg-body); stroke-width: 2.8; stroke-linecap: round; fill: none; opacity: 0; transition: opacity 0.35s ease; } .hangman-svg .bp.show { opacity: 1; } .hangman-svg .dead-face { stroke: var(--danger); stroke-width: 2; stroke-linecap: round; fill: none; opacity: 0; transition: opacity 0.5s ease 0.2s; } .hangman-svg .dead-face.show { opacity: 1; } .wrong-counter { position: absolute; bottom: 10px; right: 14px; font-family: 'JetBrains Mono', monospace; font-size: 0.72rem; color: var(--muted); z-index: 2; } .wrong-counter b { color: var(--danger); font-weight: 700; } /* Word panel */ .word-panel { display: flex; flex-direction: column; gap: 18px; padding-top: 4px; } .category-tag { display: inline-flex; align-items: center; gap: 6px; background: var(--accent-glow); border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent); color: var(--accent); padding: 5px 14px; border-radius: 20px; font-size: 0.75rem; font-weight: 600; text-transform: uppercase; letter-spacing: 1.2px; width: fit-content; } .category-tag svg { width: 13px; height: 13px; flex-shrink: 0; } .word-slots { display: flex; flex-wrap: wrap; gap: 8px; min-height: 58px; } .slot { width: 42px; height: 54px; display: flex; align-items: center; justify-content: center; font-family: 'JetBrains Mono', monospace; font-size: 1.4rem; font-weight: 700; color: var(--fg); border-bottom: 3px solid var(--border); transition: all 0.3s ease; position: relative; } .slot.revealed { border-bottom-color: var(--accent); animation: pop 0.35s cubic-bezier(0.34,1.56,0.64,1); } .slot.revealed::after { content: ''; position: absolute; bottom: -3px; left: 0; right: 0; height: 3px; background: var(--accent); filter: blur(4px); } .slot.missed { color: var(--danger); border-bottom-color: var(--danger); opacity: 0.7; } @keyframes pop { 0% { transform: scale(1.35) translateY(-4px); opacity: 0; } 60% { transform: scale(0.95); } 100% { transform: scale(1) translateY(0); opacity: 1; } } .hint { font-size: 0.88rem; color: var(--muted); line-height: 1.6; max-width: 420px; } /* Keyboard */ .keyboard { display: flex; flex-direction: column; gap: 7px; align-items: center; margin-top: auto; padding: 16px 0 10px; } .kb-row { display: flex; gap: 5px; justify-content: center; } .key { width: 40px; height: 46px; display: flex; align-items: center; justify-content: center; font-family: 'JetBrains Mono', monospace; font-size: 0.9rem; font-weight: 600; background: var(--key-bg); color: var(--fg); border: 1px solid var(--key-border); border-radius: 10px; cursor: pointer; transition: all 0.15s ease; user-select: none; -webkit-tap-highlight-color: transparent; outline: none; } .key:focus-visible { box-shadow: 0 0 0 2px var(--accent); } .key:hover:not(.used) { background: var(--key-hover); transform: translateY(-2px); box-shadow: 0 4px 14px rgba(0,0,0,0.12); } .key:active:not(.used) { transform: translateY(0); } .key.used { cursor: default; pointer-events: none; } .key.correct { background: var(--key-correct-bg); border-color: var(--success); color: var(--success); } .key.wrong { background: var(--key-wrong-bg); border-color: color-mix(in srgb, var(--danger) 35%, transparent); color: var(--danger); opacity: 0.55; } /* Modal */ .overlay { position: fixed; inset: 0; background: var(--overlay); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); z-index: 100; display: flex; align-items: center; justify-content: center; opacity: 0; pointer-events: none; transition: opacity 0.3s ease; } .overlay.open { opacity: 1; pointer-events: all; } .modal { background: var(--card); border: 1px solid var(--border); border-radius: 22px; padding: 40px 36px 32px; max-width: 400px; width: 92%; text-align: center; box-shadow: 0 24px 80px rgba(0,0,0,0.35); transform: scale(0.92) translateY(16px); transition: transform 0.35s cubic-bezier(0.34,1.56,0.64,1); } .overlay.open .modal { transform: scale(1) translateY(0); } .modal-badge { width: 72px; height: 72px; margin: 0 auto 18px; border-radius: 50%; display: flex; align-items: center; justify-content: center; } .modal-badge.win { background: var(--key-correct-bg); border: 2px solid var(--success); } .modal-badge.lose { background: var(--key-wrong-bg); border: 2px solid var(--danger); } .modal h2 { font-size: 1.5rem; font-weight: 700; margin-bottom: 6px; } .modal .reveal-word { font-family: 'JetBrains Mono', monospace; font-size: 1.25rem; color: var(--accent); font-weight: 700; letter-spacing: 5px; margin: 14px 0; } .modal .sub { color: var(--muted); font-size: 0.88rem; margin-bottom: 26px; line-height: 1.5; } .btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; padding: 13px 30px; font-family: 'Space Grotesk', sans-serif; font-size: 0.95rem; font-weight: 600; border: none; border-radius: 12px; cursor: pointer; transition: all 0.2s ease; } .btn-accent { background: var(--accent); color: #0c0c0c; } .btn-accent:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(232,168,56,0.25); } .btn-ghost { background: var(--key-bg); color: var(--fg); border: 1px solid var(--border); } .btn-ghost:hover { background: var(--key-hover); transform: translateY(-2px); } .modal-btns { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; } /* Particles */ .particles { position: fixed; inset: 0; pointer-events: none; z-index: 0; overflow: hidden; } .dot { position: absolute; border-radius: 50%; background: var(--accent); opacity: 0; animation: drift linear infinite; } @keyframes drift { 0% { transform: translateY(105vh) scale(0); opacity: 0; } 8% { opacity: 0.12; transform: translateY(95vh) scale(1); } 92% { opacity: 0.12; } 100% { transform: translateY(-5vh) scale(0.5); opacity: 0; } } /* Shake */ @keyframes shake { 0%,100% { transform: translateX(0); } 15% { transform: translateX(-6px) rotate(-0.5deg); } 30% { transform: translateX(6px) rotate(0.5deg); } 45% { transform: translateX(-4px); } 60% { transform: translateX(4px); } 75% { transform: translateX(-2px); } } .shake { animation: shake 0.45s ease; } /* Confetti burst on win */ .confetti-piece { position: fixed; width: 8px; height: 8px; border-radius: 2px; z-index: 150; pointer-events: none; animation: confettiFall 1.2s ease-out forwards; } @keyframes confettiFall { 0% { opacity: 1; transform: translateY(0) rotate(0deg) scale(1); } 100% { opacity: 0; transform: translateY(60vh) rotate(720deg) scale(0.3); } } /* Responsive */ @media (max-width: 720px) { .top-row { grid-template-columns: 1fr; gap: 20px; } .hangman-panel { max-width: 230px; margin: 0 auto; } .word-panel { align-items: center; text-align: center; } .category-tag { margin: 0 auto; } .hint { text-align: center; } .key { width: 32px; height: 40px; font-size: 0.78rem; border-radius: 8px; } .kb-row { gap: 4px; } .slot { width: 32px; height: 44px; font-size: 1.15rem; } .word-slots { gap: 5px; } .stats { gap: 8px; font-size: 0.72rem; } header { flex-wrap: wrap; gap: 10px; justify-content: center; } .modal { padding: 30px 22px 26px; } } @media (max-width: 400px) { .key { width: 27px; height: 36px; font-size: 0.68rem; border-radius: 6px; } .kb-row { gap: 3px; } .slot { width: 26px; height: 38px; font-size: 1rem; } .word-slots { gap: 4px; } .container { padding: 10px 12px; } } @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } } </style> </head> <body> <div class="particles" id="particles"></div> <!-- Result modal --> <div class="overlay" id="overlay" role="dialog" aria-modal="true" aria-labelledby="mTitle"> <div class="modal"> <div class="modal-badge" id="mBadge"></div> <h2 id="mTitle"></h2> <div class="reveal-word" id="mWord"></div> <p class="sub" id="mSub"></p> <div class="modal-btns"> <button class="btn btn-accent" id="btnAgain">Play Again</button> </div> </div> </div> <div class="container"> <header> <div class="logo">hang<span>man</span></div> <div class="header-right"> <div class="stats"> <span>W <span class="stat-val" id="sW">0</span></span> <span>L <span class="stat-val" id="sL">0</span></span> <span>Streak <span class="stat-val" id="sS">0</span></span> </div> <button class="btn-icon" id="btnNew" aria-label="New game" title="New game"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/></svg> </button> <div class="theme-toggle" id="themeToggle" role="button" tabindex="0" aria-label="Toggle theme"> <div class="theme-icons"><span>☽</span><span>☼</span></div> </div> </div> </header> <main class="game-area"> <section class="top-row"> <!-- Hangman SVG --> <div class="hangman-panel" id="hPanel"> <svg class="hangman-svg" viewBox="0 0 220 210" xmlns="http://www.w3.org/2000/svg"> <!-- Ground shadow --> <ellipse cx="110" cy="198" rx="50" ry="4" fill="var(--accent)" opacity="0.06"/> <!-- Gallows --> <g class="gallows gallows-main"> <line x1="25" y1="195" x2="95" y2="195"/> <line x1="60" y1="195" x2="60" y2="18"/> <line x1="57" y1="18" x2="140" y2="18"/> <line x1="140" y1="18" x2="140" y2="42"/> </g> <g class="gallows" opacity="0.35"> <line x1="60" y1="48" x2="92" y2="18"/> <line x1="60" y1="72" x2="82" y2="48"/> </g> <!-- Noose --> <path class="gallows gallows-main" d="M140 42 Q140 48 136 50" stroke-width="2.2"/> <!-- Body parts --> <!-- 1 Head --> <circle class="bp" id="b1" cx="136" cy="62" r="12"/> <!-- 2 Body --> <line class="bp" id="b2" x1="136" y1="74" x2="136" y2="125"/> <!-- 3 Left arm --> <line class="bp" id="b3" x1="136" y1="88" x2="112" y2="108"/> <!-- 4 Right arm --> <line class="bp" id="b4" x1="136" y1="88" x2="160" y2="108"/> <!-- 5 Left leg --> <line class="bp" id="b5" x1="136" y1="125" x2="115" y2="160"/> <!-- 6 Right leg --> <line class="bp" id="b6" x1="136" y1="125" x2="157" y2="160"/> <!-- Dead face --> <line class="dead-face" id="d1" x1="130" y1="57" x2="134" y2="61"/> <line class="dead-face" id="d2" x1="134" y1="57" x2="130" y2="61"/> <line class="dead-face" id="d3" x1="138" y1="57" x2="142" y2="61"/> <line class="dead-face" id="d4" x1="142" y1="57" x2="138" y2="61"/> <path class="dead-face" id="d5" d="M130 68 Q136 64 142 68"/> </svg> <div class="wrong-counter"><b id="wCnt">0</b> / 6</div> </div> <!-- Word & hint --> <div class="word-panel"> <div class="category-tag" id="catTag"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg> <span id="catText">Loading</span> </div> <div class="word-slots" id="wordSlots"></div> <p class="hint" id="hintEl"></p> </div> </section> <!-- Keyboard --> <nav class="keyboard" id="kb" aria-label="Letter keyboard"></nav> </main> </div> <script> /* ── Word database ── */ const WORDS = [ { w:"ALGORITHM", c:"Computer Science", h:"A step-by-step procedure for solving a problem" }, { w:"TELESCOPE", c:"Science", h:"An instrument for viewing distant objects in space" }, { w:"SYMPHONY", c:"Music", h:"An elaborate composition for a full orchestra" }, { w:"LABYRINTH", c:"Mythology", h:"An intricate structure of interconnecting passages" }, { w:"CHRYSALIS", c:"Nature", h:"The protective casing of a butterfly pupa" }, { w:"PARADOX", c:"Philosophy", h:"A contradictory statement that may reveal a deeper truth" }, { w:"AVALANCHE", c:"Nature", h:"A mass of snow rapidly sliding down a mountainside" }, { w:"FIBONACCI", c:"Mathematics", h:"A sequence where each number is the sum of the two before it" }, { w:"BLUEPRINT", c:"Engineering", h:"A detailed technical drawing guiding construction" }, { w:"WHIRLPOOL", c:"Nature", h:"A rapidly rotating body of water in a river or sea" }, { w:"QUANTUM", c:"Physics", h:"The minimum discrete amount of a physical property" }, { w:"CATALYST", c:"Chemistry", h:"A substance that speeds up a reaction without being consumed" }, { w:"SILHOUETTE", c:"Art", h:"A dark outline against a lighter background" }, { w:"PANGOLIN", c:"Animals", h:"A scaly mammal that feeds on ants and termites" }, { w:"MNEMONIC", c:"Language", h:"A memory aid like an acronym or rhyme" }, { w:"FJORD", c:"Geography", h:"A long narrow inlet carved by glaciers" }, { w:"OBSIDIAN", c:"Geology", h:"Dark volcanic glass formed from rapidly cooled lava" }, { w:"SAXOPHONE", c:"Music", h:"A brass woodwind instrument iconic in jazz" }, { w:"CLOCKWORK", c:"Engineering", h:"The intricate gear mechanism inside mechanical clocks" }, { w:"PHOSPHORUS", c:"Chemistry", h:"A reactive element that glows faintly in the dark" }, { w:"VORTEX", c:"Physics", h:"A spinning mass of fluid like a whirlpool or tornado" }, { w:"EPIPHANY", c:"Language", h:"A sudden moment of clarity or realization" }, { w:"AURORA", c:"Nature", h:"Colorful lights dancing in polar skies" }, { w:"NEBULA", c:"Astronomy", h:"A vast cloud of gas and dust in outer space" }, { w:"ZEPPELIN", c:"History", h:"A rigid airship named after its German inventor" }, { w:"CIPHER", c:"Cryptography", h:"A method for encoding or decoding secret messages" }, { w:"MONOLITH", c:"Architecture", h:"A large single block of stone or an imposing structure" }, { w:"ECLIPSE", c:"Astronomy", h:"When one celestial body obscures light from another" }, { w:"GLACIER", c:"Geography", h:"A slow-moving river of compacted ice" }, { w:"KALEIDOSCOPE", c:"Optics", h:"A tube of mirrors producing symmetrical color patterns" }, { w:"HEXAGON", c:"Geometry", h:"A six-sided polygon found in honeycombs and basalt" }, { w:"TSUNAMI", c:"Nature", h:"A massive ocean wave triggered by underwater earthquakes" }, { w:"MAGNETIC", c:"Physics", h:"Relating to the attractive force of magnets" }, { w:"PYRAMID", c:"Architecture", h:"Ancient triangular tombs built on the Giza plateau" }, { w:"SAFFRON", c:"Cooking", h:"The world's most expensive spice from crocus flowers" }, { w:"VOLCANO", c:"Geology", h:"A rupture in the crust that erupts lava and ash" }, { w:"ZENITH", c:"Astronomy", h:"The point in the sky directly above an observer" }, { w:"PHANTOM", c:"Literature", h:"A ghostly apparition, or a famous masked musical" }, { w:"ORIGAMI", c:"Art", h:"The Japanese art of folding paper into shapes" }, { w:"QUARTZ", c:"Geology", h:"One of the most abundant minerals in Earth's crust" }, { w:"MERCURY", c:"Astronomy", h:"The smallest and fastest planet orbiting the Sun" }, { w:"SPHINX", c:"Mythology", h:"A creature with a human head and lion body" }, { w:"TYPHOON", c:"Nature", h:"A powerful tropical cyclone in the western Pacific" }, ]; const KB_ROWS = ["QWERTYUIOP","ASDFGHJKL","ZXCVBNM"]; const MAX_WRONG = 6; /* ── State ── */ let word, cat, hint, guessed, wrong, active, wins=0, losses=0, streak=0; /* ── DOM refs ── */ const $ = id => document.getElementById(id); const overlay=$("overlay"), hPanel=$("hPanel"), wordSlots=$("wordSlots"), kb=$("kb"), catText=$("catText"), hintEl=$("hintEl"), wCnt=$("wCnt"), sW=$("sW"), sL=$("sL"), sS=$("sS"), mBadge=$("mBadge"), mTitle=$("mTitle"), mWord=$("mWord"), mSub=$("mSub"); /* ── Particles ── */ (function initParticles(){ const c=$("particles"); for(let i=0;i<18;i++){ const d=document.createElement("div"); d.className="dot"; const s=2+Math.random()*3; d.style.cssText=`left:${Math.random()*100}%;width:${s}px;height:${s}px;animation-duration:${18+Math.random()*28}s;animation-delay:${-Math.random()*30}s;`; c.appendChild(d); } })(); /* ── Build keyboard ── */ function buildKB(){ kb.innerHTML=""; KB_ROWS.forEach(row=>{ const r=document.createElement("div"); r.className="kb-row"; for(const ch of row){ const b=document.createElement("button"); b.className="key"; b.textContent=ch; b.dataset.l=ch; b.setAttribute("aria-label","Guess "+ch); b.addEventListener("click",()=>guess(ch)); r.appendChild(b); } kb.appendChild(r); }); } /* ── Render word ── */ function renderWord(){ wordSlots.innerHTML=""; for(const ch of word){ const s=document.createElement("div"); s.className="slot"; if(guessed.has(ch)){ s.textContent=ch; s.classList.add("revealed"); } wordSlots.appendChild(s); } } /* ── Guess ── */ function guess(ch){ if(!active||guessed.has(ch)) return; guessed.add(ch); const btn=kb.querySelector(`[data-l="${ch}"]`); if(word.includes(ch)){ if(btn) btn.classList.add("used","correct"); renderWord(); /* Check win */ if(word.split("").every(l=>guessed.has(l))){ active=false; wins++; streak++; updateStats(); setTimeout(()=>{ spawnConfetti(); showResult("win"); },500); } } else { if(btn) btn.classList.add("used","wrong"); wrong++; wCnt.textContent=wrong; const part=$("b"+wrong); if(part) part.classList.add("show"); hPanel.classList.add("shake"); setTimeout(()=>hPanel.classList.remove("shake"),450); if(wrong>=MAX_WRONG){ active=false; losses++; streak=0; updateStats(); /* Show dead face */ for(let i=1;i<=5;i++) $("d"+i).classList.add("show"); /* Reveal missing */ setTimeout(()=>{ const slots=wordSlots.querySelectorAll(".slot"); word.split("").forEach((l,i)=>{ if(!guessed.has(l)){ slots[i].textContent=l; slots[i].classList.add("missed"); } }); setTimeout(()=>showResult("lose"),400); },500); } } } /* ── Confetti ── */ function spawnConfetti(){ const colors=["#e8a838","#48c878","#e84848","#38b8e8","#e8d838","#b848e8"]; for(let i=0;i<40;i++){ const p=document.createElement("div"); p.className="confetti-piece"; p.style.left=30+Math.random()*40+"%"; p.style.top="35%"; p.style.background=colors[Math.floor(Math.random()*colors.length)]; p.style.animationDelay=Math.random()*0.3+"s"; p.style.animationDuration=0.8+Math.random()*0.6+"s"; const angle=-60+Math.random()*120; const dist=100+Math.random()*200; const dx=Math.cos(angle*Math.PI/180)*dist; const dy=Math.sin(angle*Math.PI/180)*dist-100; p.style.setProperty("--dx",dx+"px"); p.style.setProperty("--dy",dy+"px"); p.style.animation="none"; document.body.appendChild(p); /* Custom trajectory */ requestAnimationFrame(()=>{ p.style.transition=`all ${0.8+Math.random()*0.6}s cubic-bezier(.25,.46,.45,.94)`; p.style.transform=`translate(${dx}px, ${dy}px) rotate(${Math.random()*720}deg)`; p.style.opacity="0"; }); setTimeout(()=>p.remove(),2000); } } /* ── Show result modal ── */ function showResult(type){ if(type==="win"){ mBadge.className="modal-badge win"; mBadge.innerHTML=`<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="var(--success)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>`; mTitle.textContent="Well Played"; mTitle.style.color="var(--success)"; mWord.textContent=word; mSub.textContent=wrong===0 ? "Flawless victory — not a single wrong guess." : `Solved with ${wrong} wrong guess${wrong>1?"es":""}.`; } else { mBadge.className="modal-badge lose"; mBadge.innerHTML=`<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="var(--danger)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>`; mTitle.textContent="Game Over"; mTitle.style.color="var(--danger)"; mWord.textContent=word; mSub.textContent=`The word was "${word.toLowerCase()}". Better luck next time!`; } overlay.classList.add("open"); } /* ── New game ── */ function newGame(){ const entry=WORDS[Math.floor(Math.random()*WORDS.length)]; word=entry.w; cat=entry.c; hint=entry.h; guessed=new Set(); wrong=0; active=true; catText.textContent=cat; hintEl.textContent=hint; wCnt.textContent="0"; /* Reset SVG parts */ for(let i=1;i<=6;i++) $("b"+i).classList.remove("show"); for(let i=1;i<=5;i++) $("d"+i).classList.remove("show"); renderWord(); buildKB(); overlay.classList.remove("open"); } /* ── Stats ── */ function updateStats(){ sW.textContent=wins; sL.textContent=losses; sS.textContent=streak; } /* ── Theme ── */ function setTheme(t){ document.documentElement.setAttribute("data-theme",t); localStorage.setItem("hm-theme",t); } function toggleTheme(){ const cur=document.documentElement.getAttribute("data-theme"); setTheme(cur==="dark"?"light":"dark"); } /* ── Events ── */ $("themeToggle").addEventListener("click",toggleTheme); $("themeToggle").addEventListener("keydown",e=>{ if(e.key==="Enter"||e.key===" "){ e.preventDefault(); toggleTheme(); } }); $("btnNew").addEventListener("click",newGame); $("btnAgain").addEventListener("click",newGame); overlay.addEventListener("click",e=>{ if(e.target===overlay) newGame(); }); document.addEventListener("keydown",e=>{ if(!active){ if(e.key==="Enter"&&overlay.classList.contains("open")) newGame(); return; } const ch=e.key.toUpperCase(); if(/^[A-Z]$/.test(ch)) guess(ch); }); /* ── Init ── */ const saved=localStorage.getItem("hm-theme"); if(saved) setTheme(saved); newGame(); </script> </body> </html>
Cancel