Exploring the world of game development can be both exciting and overwhelming. To help you navigate this creative landscape, we've compiled a list of 10 game examples that showcase a variety of genres and styles.
From indie gems to blockbuster hits, these examples highlight the diversity and innovation within the gaming industry. Whether you're a seasoned developer or just starting out, these games offer valuable insights and inspiration.
CODE1
Here's the code:
CODETEXT1
CODE2
Here's the code:
CODETEXT2
CODE3
Here's the code:
CODETEXT3
CODE4
Here's the code:
CODETEXT4
CODE5
Here's the code:
CODETEXT5
Designing your own game has never been easier with Subframe. Its drag-and-drop interface and intuitive, responsive canvas ensure you create pixel-perfect UI every time. Loved by designers and developers alike, Subframe makes the design process seamless and enjoyable.
Start for free and bring your game ideas to life with Subframe today!
CODE6
Here's the code:
CODETEXT6
CODE7
Here's the code:
CODETEXT7
CODE8
Here's the code:
CODETEXT8
CODE9
Here's the code:
CODETEXT9
CODE10
Here's the code:
CODETEXT10
Ready to elevate your UI design game? With Subframe, you can create stunning, pixel-perfect interfaces in minutes. Its drag-and-drop editor ensures efficiency and precision.
Don't wait to bring your ideas to life. Start for free and begin designing immediately!
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Epic Fantasy Adventure</title> <style> @import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@400;600;800&family=Noto+Sans:wght@400;600&display=swap'); :root { --primary-dark: #0c1023; --primary-light: #f8f0e3; --accent-gold: #d4af37; --accent-blue: #3a6ea5; --accent-purple: #6a4c93; --accent-red: #932d2d; --accent-green: #2d934b; --font-fantasy: 'Cinzel', serif; --font-regular: 'Noto Sans', sans-serif; } * { margin: 0; padding: 0; box-sizing: border-box; } body { width: 100%; height: 100vh; background: var(--primary-dark); color: var(--primary-light); font-family: var(--font-regular); overflow: hidden; position: relative; } .container { width: 100%; height: 100%; position: relative; display: flex; flex-direction: column; } .background { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(135deg, rgba(12, 16, 35, 0.9), rgba(12, 16, 35, 0.7)), url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" fill="none" stroke="%23d4af37" stroke-width="0.5" opacity="0.2"/></svg>'); z-index: -1; overflow: hidden; } .background::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: radial-gradient(circle at 50% 50%, rgba(58, 110, 165, 0.2), transparent 70%); animation: pulseLight 12s infinite alternate; } .background::after { content: ''; position: absolute; width: 300px; height: 300px; background: radial-gradient(circle, rgba(212, 175, 55, 0.1) 0%, transparent 70%); top: -150px; right: -150px; border-radius: 50%; filter: blur(30px); animation: moveOrb 24s infinite alternate; } .floating-runes { position: absolute; width: 100%; height: 100%; z-index: -1; } .rune { position: absolute; font-family: var(--font-fantasy); color: var(--accent-gold); opacity: 0; animation: floatRune 12s infinite; font-size: 24px; text-shadow: 0 0 8px var(--accent-gold); } .header { padding: 20px; text-align: center; position: relative; } .title { font-family: var(--font-fantasy); font-size: 42px; font-weight: 800; color: var(--primary-light); letter-spacing: 3px; margin-bottom: 5px; position: relative; text-shadow: 0 0 15px rgba(212, 175, 55, 0.5); } .title::after { content: ''; position: absolute; bottom: -10px; left: 50%; transform: translateX(-50%); width: 180px; height: 2px; background: linear-gradient(90deg, transparent, var(--accent-gold), transparent); } .subtitle { font-family: var(--font-regular); font-size: 16px; font-weight: 400; color: var(--primary-light); opacity: 0.8; margin-top: 15px; } .main-content { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 20px; position: relative; } .hero-selection { display: flex; justify-content: center; flex-wrap: wrap; gap: 20px; margin-bottom: 40px; max-width: 650px; } .hero-card { position: relative; width: 130px; height: 180px; background: rgba(12, 16, 35, 0.7); border: 1px solid rgba(212, 175, 55, 0.3); border-radius: 10px; overflow: hidden; cursor: pointer; transition: all 0.3s ease; } .hero-card::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(135deg, transparent 50%, rgba(var(--accent-color-rgb), 0.1)); z-index: 1; } .hero-card:hover { transform: translateY(-5px); box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3), 0 0 15px rgba(var(--accent-color-rgb), 0.5); } .hero-card.selected { box-shadow: 0 0 20px rgba(var(--accent-color-rgb), 0.7); border-color: rgba(var(--accent-color-rgb), 1); } .hero-bg { position: absolute; top: 0; left: 0; width: 100%; height: 70%; background-size: cover; background-position: center; transition: all 0.5s ease; } .hero-card:hover .hero-bg { transform: scale(1.05); } .hero-info { position: absolute; bottom: 0; left: 0; width: 100%; padding: 10px; background: rgba(12, 16, 35, 0.8); z-index: 2; } .hero-name { font-family: var(--font-fantasy); font-size: 16px; font-weight: 600; color: var(--primary-light); margin-bottom: 4px; } .hero-class { font-size: 12px; color: var(--accent-color); font-weight: 600; } .hero-tooltip { position: absolute; top: 50%; left: 50%; transform: translate(-50%, calc(-100% - 30px)); background: rgba(12, 16, 35, 0.9); border: 1px solid var(--accent-color); padding: 15px; border-radius: 8px; width: 220px; opacity: 0; visibility: hidden; transition: all 0.3s ease; z-index: 10; pointer-events: none; } .hero-tooltip::after { content: ''; position: absolute; bottom: -10px; left: 50%; transform: translateX(-50%); border-left: 10px solid transparent; border-right: 10px solid transparent; border-top: 10px solid var(--accent-color); } .hero-card:hover .hero-tooltip { opacity: 1; visibility: visible; transform: translate(-50%, calc(-100% - 20px)); } .tooltip-title { font-family: var(--font-fantasy); font-size: 16px; margin-bottom: 8px; color: var(--accent-color); } .tooltip-info { font-size: 13px; line-height: 1.3; margin-bottom: 8px; } .tooltip-stat { display: flex; justify-content: space-between; margin-top: 5px; font-size: 12px; } .action-buttons { display: flex; gap: 20px; margin-bottom: 30px; } .action-button { padding: 14px 30px; background: transparent; border: 2px solid var(--accent-gold); border-radius: 30px; color: var(--primary-light); font-family: var(--font-fantasy); font-size: 16px; font-weight: 600; letter-spacing: 1px; cursor: pointer; position: relative; overflow: hidden; transition: all 0.4s ease; } .action-button::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(212, 175, 55, 0.3), transparent); transition: all 0.4s ease; } .action-button:hover { background: rgba(212, 175, 55, 0.1); transform: translateY(-3px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); } .action-button:hover::before { left: 100%; } .action-button.primary { background: rgba(212, 175, 55, 0.2); } .nav-buttons { position: absolute; bottom: 20px; display: flex; gap: 15px; } .nav-button { padding: 8px 20px; background: rgba(12, 16, 35, 0.8); border: 1px solid rgba(212, 175, 55, 0.3); border-radius: 20px; font-size: 14px; color: var(--primary-light); cursor: pointer; transition: all 0.3s ease; display: flex; align-items: center; gap: 5px; } .nav-button:hover { background: rgba(212, 175, 55, 0.1); border-color: var(--accent-gold); } .nav-icon { width: 16px; height: 16px; display: flex; align-items: center; justify-content: center; } .hero-selected-info { text-align: center; margin-bottom: 20px; opacity: 0; transform: translateY(20px); transition: all 0.5s ease; } .hero-selected-info.active { opacity: 1; transform: translateY(0); } .selected-title { font-family: var(--font-fantasy); font-size: 22px; margin-bottom: 5px; color: var(--accent-gold); } .selected-desc { font-size: 14px; max-width: 450px; margin: 0 auto; line-height: 1.5; color: var(--primary-light); opacity: 0.8; } .skill-indicators { display: flex; gap: 8px; margin-top: 10px; justify-content: center; } .skill-dot { width: 8px; height: 8px; border-radius: 50%; background: rgba(212, 175, 55, 0.3); } .skill-dot.active { background: var(--accent-color); box-shadow: 0 0 8px var(--accent-color); } @keyframes pulseLight { 0%, 100% { opacity: 0.5; } 50% { opacity: 0.8; } } @keyframes moveOrb { 0% { top: -150px; right: -150px; } 25% { top: 50%; right: -150px; } 50% { top: 80%; right: 50%; } 75% { top: 30%; right: 80%; } 100% { top: -150px; right: 40%; } } @keyframes floatRune { 0% { transform: translateY(0) rotate(0deg); opacity: 0; } 10% { opacity: 0.4; } 90% { opacity: 0.4; } 100% { transform: translateY(-100px) rotate(20deg); opacity: 0; } } /* Responsive adjustments */ @media (max-width: 700px) { .title { font-size: 36px; } .subtitle { font-size: 14px; } .hero-selection { gap: 15px; } .hero-card { width: 110px; height: 160px; } .action-buttons { flex-direction: column; gap: 10px; } .action-button { padding: 12px 20px; font-size: 14px; } } @media (max-width: 480px) { .hero-selection { gap: 10px; } .hero-card { width: 90px; height: 140px; } .hero-name { font-size: 14px; } .nav-buttons { flex-wrap: wrap; justify-content: center; } } </style> </head> <body> <div class="container"> <div class="background"></div> <div class="floating-runes"></div> <header class="header"> <h1 class="title">Realms of Aetheria</h1> <p class="subtitle">Forge your destiny in a world of magic, prophecy, and ancient powers</p> </header> <main class="main-content"> <div class="hero-selected-info"> <h2 class="selected-title">Choose Your Champion</h2> <p class="selected-desc">Select a hero to embark on your epic journey. Each possesses unique abilities and a personal quest that will shape the fate of Aetheria.</p> </div> <div class="hero-selection"> <!-- Hero Cards Dynamically Generated Here --> </div> <div class="action-buttons"> <button class="action-button primary" id="start-journey">Begin Adventure</button> <button class="action-button" id="read-lore">Explore Lore</button> </div> <div class="nav-buttons"> <div class="nav-button" id="options-btn"> <span class="nav-icon">⚙️</span> Options </div> <div class="nav-button" id="profile-btn"> <span class="nav-icon">👤</span> Profile </div> <div class="nav-button" id="about-btn"> <span class="nav-icon">ℹ️</span> About </div> </div> </main> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Dynamic background elements generateRunes(); // Hero card data const heroes = [ { id: 'mage', name: 'Lyra Flamewhisper', class: 'Archmage', background: 'linear-gradient(to bottom, rgba(106, 76, 147, 0.7), rgba(106, 76, 147, 0.3)), url("data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'100\' height=\'100\' viewBox=\'0 0 100 100\'%3E%3Ccircle cx=\'50\' cy=\'40\' r=\'30\' fill=\'%236a4c93\'/%3E%3C/svg%3E")', accentColor: '106, 76, 147', tooltip: { title: 'Archmage of the Astral College', info: 'Master of elemental magic and prophecy. Lyra seeks to prevent an ancient cataclysm foretold in the stars.', stats: [ { name: 'Intelligence', value: '••••• ' }, { name: 'Strength', value: '••' }, { name: 'Agility', value: '•••' } ] } }, { id: 'warrior', name: 'Thorne Ironfist', class: 'Warlord', background: 'linear-gradient(to bottom, rgba(147, 45, 45, 0.7), rgba(147, 45, 45, 0.3)), url("data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'100\' height=\'100\' viewBox=\'0 0 100 100\'%3E%3Crect x=\'30\' y=\'30\' width=\'40\' height=\'40\' fill=\'%23932d2d\'/%3E%3C/svg%3E")', accentColor: '147, 45, 45', tooltip: { title: 'Commander of the Northern Vanguard', info: 'Battle-hardened leader who rallies armies against the shadows. Seeking vengeance for his fallen kingdom.', stats: [ { name: 'Intelligence', value: '•••' }, { name: 'Strength', value: '•••••' }, { name: 'Agility', value: '••' } ] } }, { id: 'rogue', name: 'Vex Shadowstep', class: 'Nightblade', background: 'linear-gradient(to bottom, rgba(58, 110, 165, 0.7), rgba(58, 110, 165, 0.3)), url("data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'100\' height=\'100\' viewBox=\'0 0 100 100\'%3E%3Cpath d=\'M20,50 L50,20 L80,50 L50,80 Z\' fill=\'%233a6ea5\'/%3E%3C/svg%3E")', accentColor: '58, 110, 165', tooltip: { title: 'Whisper of the Veiled Court', info: 'Master of shadows and secrets. Vex infiltrates the darkest places to uncover artifacts of immense power.', stats: [ { name: 'Intelligence', value: '••••' }, { name: 'Strength', value: '••' }, { name: 'Agility', value: '•••••' } ] } }, { id: 'druid', name: 'Eryn Wildbloom', class: 'Forestkeeper', background: 'linear-gradient(to bottom, rgba(45, 147, 75, 0.7), rgba(45, 147, 75, 0.3)), url("data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'100\' height=\'100\' viewBox=\'0 0 100 100\'%3E%3Cpath d=\'M50,20 L70,50 L50,80 L30,50 Z\' fill=\'%232d934b\'/%3E%3C/svg%3E")', accentColor: '45, 147, 75', tooltip: { title: 'Guardian of the Whispering Groves', info: 'Communion with nature grants Eryn powers to heal and transform. Protector of the ancient forests.', stats: [ { name: 'Intelligence', value: '••••' }, { name: 'Strength', value: '•••' }, { name: 'Agility', value: '•••' } ] } } ]; // Generate hero cards const heroSelection = document.querySelector('.hero-selection'); let selectedHero = null; heroes.forEach(hero => { const heroCard = document.createElement('div'); heroCard.className = 'hero-card'; heroCard.dataset.hero = hero.id; heroCard.style.setProperty('--accent-color', hero.accentColor); heroCard.style.setProperty('--accent-color-rgb', hero.accentColor); heroCard.innerHTML = ` <div class="hero-bg" style="background: ${hero.background}"></div> <div class="hero-info"> <div class="hero-name">${hero.name}</div> <div class="hero-class" style="color: rgb(${hero.accentColor})">${hero.class}</div> </div> <div class="hero-tooltip"> <div class="tooltip-title" style="color: rgb(${hero.accentColor})">${hero.tooltip.title}</div> <div class="tooltip-info">${hero.tooltip.info}</div> ${hero.tooltip.stats.map(stat => ` <div class="tooltip-stat"> <span>${stat.name}</span> <span>${stat.value}</span> </div> `).join('')} </div> `; heroCard.addEventListener('click', () => selectHero(hero.id)); heroSelection.appendChild(heroCard); }); // Show hero selection info const heroSelectedInfo = document.querySelector('.hero-selected-info'); heroSelectedInfo.classList.add('active'); // Hero selection function selectHero(heroId) { const cards = document.querySelectorAll('.hero-card'); cards.forEach(card => { if (card.dataset.hero === heroId) { card.classList.add('selected'); const hero = heroes.find(h => h.id === heroId); const selectedTitle = document.querySelector('.selected-title'); const selectedDesc = document.querySelector('.selected-desc'); selectedTitle.textContent = hero.name; selectedTitle.style.color = `rgb(${hero.accentColor})`; selectedDesc.textContent = hero.tooltip.info; // Add skill indicators const skillIndicators = document.querySelector('.skill-indicators') || document.createElement('div'); skillIndicators.className = 'skill-indicators'; skillIndicators.innerHTML = ''; for (let i = 0; i < 5; i++) { const skillDot = document.createElement('div'); skillDot.className = `skill-dot ${i < hero.tooltip.stats[0].value.length / 2 ? 'active' : ''}`; skillDot.style.setProperty('--accent-color', `rgb(${hero.accentColor})`); skillIndicators.appendChild(skillDot); } if (!document.querySelector('.skill-indicators')) { heroSelectedInfo.appendChild(skillIndicators); } // Update button colors document.querySelector('.action-button.primary').style.borderColor = `rgb(${hero.accentColor})`; document.querySelector('.action-button.primary').style.setProperty('--accent-color', `rgb(${hero.accentColor})`); selectedHero = heroId; } else { card.classList.remove('selected'); } }); } // Generate floating runes function generateRunes() { const runeContainer = document.querySelector('.floating-runes'); const runeSymbols = ['ᚠ', 'ᚢ', 'ᚦ', 'ᚨ', 'ᚱ', 'ᚲ', 'ᚷ', 'ᚹ', 'ᚺ', 'ᚾ', 'ᛁ', 'ᛃ']; for (let i = 0; i < 15; i++) { const rune = document.createElement('div'); rune.className = 'rune'; rune.textContent = runeSymbols[Math.floor(Math.random() * runeSymbols.length)]; const x = Math.random() * 100; const y = Math.random() * 100; const delay = Math.random() * 5; const duration = 8 + Math.random() * 7; rune.style.left = `${x}%`; rune.style.top = `${y}%`; rune.style.animationDuration = `${duration}s`; rune.style.animationDelay = `${delay}s`; runeContainer.appendChild(rune); } } // Button interactions document.getElementById('start-journey').addEventListener('click', function() { if (selectedHero) { this.classList.add('active'); this.innerHTML = 'Journeying...'; setTimeout(() => { this.innerHTML = 'Begin Adventure'; this.classList.remove('active'); // Simulated journey start effect const hero = heroes.find(h => h.id === selectedHero); // Show hero selection effect const message = document.createElement('div'); message.style.position = 'absolute'; message.style.top = '50%'; message.style.left = '50%'; message.style.transform = 'translate(-50%, -50%)'; message.style.background = `rgba(${hero.accentColor}, 0.1)`; message.style.border = `2px solid rgb(${hero.accentColor})`; message.style.borderRadius = '10px'; message.style.padding = '20px 40px'; message.style.fontFamily = 'var(--font-fantasy)'; message.style.fontSize = '22px'; message.style.color = 'var(--primary-light)'; message.style.textAlign = 'center'; message.style.zIndex = '100'; message.style.opacity = '0'; message.style.transition = 'all 0.5s ease'; message.innerHTML = `Your journey begins, ${hero.name}!<br><span style="font-size: 16px; opacity: 0.7">The fate of Aetheria awaits...</span>`; document.body.appendChild(message); setTimeout(() => { message.style.opacity = '1'; }, 100); setTimeout(() => { message.style.opacity = '0'; setTimeout(() => { message.remove(); }, 500); }, 3000); }, 1500); } else { // Show selection required message const heroSelection = document.querySelector('.hero-selection'); heroSelection.style.animation = 'shake 0.5s ease'; setTimeout(() => { heroSelection.style.animation = ''; }, 500); } }); document.getElementById('read-lore').addEventListener('click', function() { // Toggle lore panel effect const lorePanel = document.createElement('div'); lorePanel.style.position = 'absolute'; lorePanel.style.top = '50%'; lorePanel.style.left = '50%'; lorePanel.style.transform = 'translate(-50%, -50%)'; lorePanel.style.width = '400px'; lorePanel.style.maxWidth = '90%'; lorePanel.style.maxHeight = '80%'; lorePanel.style.background = 'rgba(12, 16, 35, 0.95)'; lorePanel.style.border = '1px solid var(--accent-gold)'; lorePanel.style.borderRadius = '10px'; lorePanel.style.padding = '20px'; lorePanel.style.zIndex = '100'; lorePanel.style.overflowY = 'auto'; lorePanel.style.boxShadow = '0 0 30px rgba(0, 0, 0, 0.5)'; lorePanel.style.opacity = '0'; lorePanel.style.transition = 'all 0.3s ease'; lorePanel.innerHTML = ` <h3 style="font-family: var(--font-fantasy); font-size: 24px; color: var(--accent-gold); margin-bottom: 15px;">Chronicles of Aetheria</h3> <p style="margin-bottom: 15px; line-height: 1.6; font-size: 14px;">In the age of wonders, when the stars themselves whispered secrets to those who would listen, the realm of Aetheria was forged from the dreams of ancient deities.</p> <p style="margin-bottom: 15px; line-height: 1.6; font-size: 14px;">The five kingdoms—Luminar, Emberhold, Stormwatch, Verdantia, and Shadowvale—existed in tenuous harmony for a thousand years under the protection of the Crystal Covenant.</p> <p style="margin-bottom: 15px; line-height: 1.6; font-size: 14px;">But darkness stirs again. The Void Emperor has returned from his banishment, his tendrils of corruption spreading across the land. Ancient guardians have fallen silent, and the celestial alignments speak of a coming doom.</p> <p style="margin-bottom: 15px; line-height: 1.6; font-size: 14px;">Only the Chosen Ones—heroes of prophecy marked by the Astral Sigil—can gather the five Elemental Keystones and restore the broken barriers between worlds before the Eternal Night consumes all.</p> <div style="text-align: center; margin-top: 20px;"> <button style="background: transparent; border: 1px solid var(--accent-gold); color: var(--primary-light); padding: 8px 20px; border-radius: 20px; cursor: pointer;" id="close-lore">Close Chronicle</button> </div> `; document.body.appendChild(lorePanel); setTimeout(() => { lorePanel.style.opacity = '1'; }, 100); document.getElementById('close-lore').addEventListener('click', function() { lorePanel.style.opacity = '0'; setTimeout(() => { lorePanel.remove(); }, 300); }); }); // Nav buttons interactions document.querySelectorAll('.nav-button').forEach(button => { button.addEventListener('click', function() { const type = this.id.split('-')[0]; const messages = { options: 'Game settings and preferences', profile: 'Player profile and achievements', about: 'Game information and credits' }; // Create tooltip const tooltip = document.createElement('div'); tooltip.style.position = 'absolute'; tooltip.style.bottom = '70px'; tooltip.style.left = '50%'; tooltip.style.transform = 'translateX(-50%)'; tooltip.style.background = 'rgba(12, 16, 35, 0.9)'; tooltip.style.border = '1px solid var(--accent-gold)'; tooltip.style.borderRadius = '8px'; tooltip.style.padding = '10px 15px'; tooltip.style.fontFamily = 'var(--font-regular)'; tooltip.style.fontSize = '14px'; tooltip.style.color = 'var(--primary-light)'; tooltip.style.whiteSpace = 'nowrap'; tooltip.style.zIndex = '100'; tooltip.style.opacity = '0'; tooltip.style.transition = 'all 0.3s ease'; tooltip.textContent = messages[type]; document.querySelector('.nav-buttons').appendChild(tooltip); setTimeout(() => { tooltip.style.opacity = '1'; }, 50); setTimeout(() => { tooltip.style.opacity = '0'; setTimeout(() => { tooltip.remove(); }, 300); }, 2000); }); }); // Add a shake animation const style = document.createElement('style'); style.textContent = ` @keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 50% { transform: translateX(5px); } 75% { transform: translateX(-5px); } } `; document.head.appendChild(style); // Select the first hero by default setTimeout(() => { selectHero('mage'); }, 1000); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Steampunk Inventory</title> <style> @import url('https://fonts.googleapis.com/css2?family=Pirata+One&family=Special+Elite&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; } :root { --copper-dark: #8B4513; --copper-medium: #B87333; --copper-light: #D2946B; --brass: #D4AF37; --steel: #71797E; --bg-color: #1E1810; --parchment: #F5E8C8; --shadow: rgba(0, 0, 0, 0.8); } body { background-color: var(--bg-color); font-family: 'Special Elite', cursive; width: 100%; height: 100vh; display: flex; justify-content: center; align-items: center; overflow: hidden; color: var(--parchment); } .container { width: 700px; height: 700px; position: relative; } .inventory-frame { width: 100%; height: 100%; background: radial-gradient(ellipse at center, var(--copper-medium) 0%, var(--copper-dark) 90%); border: 20px solid; border-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'%3E%3Cpath fill='none' stroke='%23B87333' stroke-width='8' d='M20,5 L80,5 C85,5 95,10 95,20 L95,80 C95,85 85,95 80,95 L20,95 C10,95 5,85 5,80 L5,20 C5,10 15,5 20,5 Z'/%3E%3Ccircle cx='20' cy='20' r='5' fill='%238B4513'/%3E%3Ccircle cx='80' cy='20' r='5' fill='%238B4513'/%3E%3Ccircle cx='20' cy='80' r='5' fill='%238B4513'/%3E%3Ccircle cx='80' cy='80' r='5' fill='%238B4513'/%3E%3C/svg%3E") 20 stretch; box-shadow: 0 0 30px var(--shadow); position: relative; overflow: hidden; z-index: 1; } .gear { position: absolute; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cpath fill='%23B87333' d='M97.6,55.7l-9.1-2.1c-1-0.2-1.8-1-2.3-1.9c-0.5-0.9-0.5-2,0-2.9l5.5-7.5c1.1-1.5,0.9-3.7-0.4-4.9l-8.7-8.7 c-1.2-1.2-3.4-1.5-4.9-0.4l-7.5,5.5c-0.9,0.5-2,0.5-2.9,0c-0.9-0.5-1.7-1.4-1.9-2.3l-2.1-9.1c-0.4-1.8-2-3.1-3.9-3.1H44.3 c-1.8,0-3.4,1.3-3.9,3.1l-2.1,9.1c-0.2,1-1,1.8-1.9,2.3c-0.9,0.5-2,0.5-2.9,0l-7.5-5.5c-1.5-1.1-3.7-0.9-4.9,0.4l-8.7,8.7 c-1.2,1.2-1.5,3.4-0.4,4.9l5.5,7.5c0.5,0.9,0.5,2,0,2.9c-0.5,0.9-1.4,1.7-2.3,1.9l-9.1,2.1c-1.8,0.4-3.1,2-3.1,3.9v12.3 c0,1.8,1.3,3.4,3.1,3.9l9.1,2.1c1,0.2,1.8,1,2.3,1.9c0.5,0.9,0.5,2,0,2.9l-5.5,7.5c-1.1,1.5-0.9,3.7,0.4,4.9l8.7,8.7 c1.2,1.2,3.4,1.5,4.9,0.4l7.5-5.5c0.9-0.5,2-0.5,2.9,0c0.9,0.5,1.7,1.4,1.9,2.3l2.1,9.1c0.4,1.8,2,3.1,3.9,3.1h12.3 c1.8,0,3.4-1.3,3.9-3.1l2.1-9.1c0.2-1,1-1.8,1.9-2.3c0.9-0.5,2-0.5,2.9,0l7.5,5.5c1.5,1.1,3.7,0.9,4.9-0.4l8.7-8.7 c1.2-1.2,1.5-3.4,0.4-4.9l-5.5-7.5c-0.5-0.9-0.5-2,0-2.9c0.5-0.9,1.4-1.7,2.3-1.9l9.1-2.1c1.8-0.4,3.1-2,3.1-3.9V59.6 C100.7,57.8,99.4,56.2,97.6,55.7z M50.5,78.5c-15.7,0-28.5-12.8-28.5-28.5c0-15.7,12.8-28.5,28.5-28.5S79,34.3,79,50 C79,65.7,66.2,78.5,50.5,78.5z'/%3E%3C/svg%3E"); opacity: 0.2; z-index: -1; } .gear1 { width: 150px; height: 150px; top: -30px; left: -30px; animation: rotate 40s linear infinite; } .gear2 { width: 100px; height: 100px; bottom: 20px; right: 40px; animation: rotate-reverse 30s linear infinite; } .gear3 { width: 70px; height: 70px; top: 50%; right: -20px; animation: rotate 25s linear infinite; } .gear4 { width: 200px; height: 200px; bottom: -60px; left: 20%; opacity: 0.15; animation: rotate-reverse 50s linear infinite; } .inner-container { display: grid; grid-template-rows: auto 1fr; padding: 20px; height: 100%; } .header { display: flex; justify-content: space-between; align-items: center; padding-bottom: 15px; border-bottom: 2px solid var(--copper-light); position: relative; } .header::after { content: ''; position: absolute; bottom: -7px; left: 0; right: 0; height: 2px; background-color: var(--copper-dark); } .title { font-family: 'Pirata One', cursive; font-size: 36px; color: var(--brass); text-shadow: 2px 2px 4px var(--shadow); letter-spacing: 2px; } .stats { display: flex; gap: 15px; } .stat { display: flex; flex-direction: column; align-items: center; } .stat-value { background: var(--copper-dark); color: var(--brass); padding: 5px 10px; border-radius: 5px; border: 1px solid var(--brass); font-size: 14px; position: relative; overflow: hidden; } .stat-value::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 50%; background: linear-gradient(to bottom, rgba(255,255,255,0.2), rgba(255,255,255,0)); } .stat-label { font-size: 12px; margin-top: 5px; } .inventory-grid { display: grid; grid-template-columns: repeat(5, 1fr); grid-auto-rows: 80px; gap: 10px; padding: 20px 0; overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--copper-medium) var(--copper-dark); height: 100%; } .inventory-grid::-webkit-scrollbar { width: 8px; } .inventory-grid::-webkit-scrollbar-track { background: var(--copper-dark); border-radius: 4px; } .inventory-grid::-webkit-scrollbar-thumb { background-color: var(--brass); border-radius: 4px; } .item { background-color: rgba(139, 69, 19, 0.5); border: 2px solid var(--copper-medium); border-radius: 5px; display: flex; flex-direction: column; align-items: center; justify-content: center; cursor: pointer; position: relative; transition: all 0.3s; transform-style: preserve-3d; overflow: hidden; } .item::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 30%; background: linear-gradient(to bottom, rgba(255,255,255,0.1), rgba(255,255,255,0)); z-index: 1; } .item:hover { transform: translateY(-5px); box-shadow: 0 5px 15px rgba(0,0,0,0.3); border-color: var(--brass); } .item.selected { border-color: var(--brass); box-shadow: 0 0 15px var(--brass); animation: pulse 2s infinite; } .item-icon { font-size: 24px; margin-bottom: 5px; } .item-name { font-size: 10px; text-align: center; padding: 0 5px; } .item-quantity { position: absolute; bottom: 2px; right: 2px; background-color: var(--copper-dark); color: var(--brass); font-size: 10px; padding: 1px 4px; border-radius: 10px; border: 1px solid var(--brass); } .tabs { display: flex; margin-top: 20px; border-bottom: 2px solid var(--copper-light); } .tab { padding: 5px 15px; margin-right: 5px; background-color: var(--copper-dark); border: 1px solid var(--copper-medium); border-bottom: none; border-radius: 5px 5px 0 0; cursor: pointer; position: relative; transition: all 0.3s; } .tab:hover { background-color: var(--copper-medium); } .tab.active { background-color: var(--copper-medium); border-color: var(--brass); color: var(--brass); } .tab.active::after { content: ''; position: absolute; bottom: -2px; left: 0; width: 100%; height: 2px; background-color: var(--copper-medium); } .item-detail { position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); width: 90%; background: linear-gradient(to bottom, var(--copper-dark), var(--bg-color)); border: 2px solid var(--copper-medium); border-radius: 5px; padding: 15px; display: none; z-index: 10; box-shadow: 0 0 20px var(--shadow); } .item-detail.active { display: block; animation: slideUp 0.3s forwards; } .detail-header { display: flex; align-items: center; margin-bottom: 10px; border-bottom: 1px solid var(--copper-light); padding-bottom: 10px; } .detail-icon { font-size: 30px; margin-right: 15px; background-color: var(--copper-dark); width: 50px; height: 50px; display: flex; align-items: center; justify-content: center; border-radius: 5px; border: 1px solid var(--brass); } .detail-title { flex-grow: 1; } .detail-name { font-family: 'Pirata One', cursive; font-size: 24px; color: var(--brass); margin: 0; } .detail-type { font-size: 12px; color: var(--copper-light); } .detail-close { background: none; border: none; color: var(--copper-light); font-size: 20px; cursor: pointer; transition: all 0.3s; } .detail-close:hover { color: var(--parchment); transform: scale(1.2); } .detail-body { display: flex; margin-bottom: 15px; } .detail-description { flex-grow: 1; font-size: 14px; line-height: 1.4; } .detail-stats { width: 120px; margin-left: 15px; } .detail-stat { display: flex; justify-content: space-between; margin-bottom: 5px; font-size: 12px; } .detail-stat-value { color: var(--brass); } .detail-actions { display: flex; justify-content: space-between; } .detail-button { background-color: var(--copper-dark); border: 1px solid var(--copper-medium); border-radius: 3px; color: var(--parchment); padding: 5px 15px; cursor: pointer; transition: all 0.3s; font-family: 'Special Elite', cursive; font-size: 14px; display: flex; align-items: center; } .detail-button:hover { background-color: var(--copper-medium); border-color: var(--brass); } .detail-button.primary { background-color: var(--copper-medium); border-color: var(--brass); color: var(--brass); } .detail-button.primary:hover { background-color: var(--brass); color: var(--copper-dark); } /* Custom Steampunk Glow and Button Gear Effects */ .button-gear { display: inline-block; width: 15px; height: 15px; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cpath fill='%23D4AF37' d='M97.6,55.7l-9.1-2.1c-1-0.2-1.8-1-2.3-1.9c-0.5-0.9-0.5-2,0-2.9l5.5-7.5c1.1-1.5,0.9-3.7-0.4-4.9l-8.7-8.7 c-1.2-1.2-3.4-1.5-4.9-0.4l-7.5,5.5c-0.9,0.5-2,0.5-2.9,0c-0.9-0.5-1.7-1.4-1.9-2.3l-2.1-9.1c-0.4-1.8-2-3.1-3.9-3.1H44.3 c-1.8,0-3.4,1.3-3.9,3.1l-2.1,9.1c-0.2,1-1,1.8-1.9,2.3c-0.9,0.5-2,0.5-2.9,0l-7.5-5.5c-1.5-1.1-3.7-0.9-4.9,0.4l-8.7,8.7 c-1.2,1.2-1.5,3.4-0.4,4.9l5.5,7.5c0.5,0.9,0.5,2,0,2.9c-0.5,0.9-1.4,1.7-2.3,1.9l-9.1,2.1c-1.8,0.4-3.1,2-3.1,3.9v12.3 c0,1.8,1.3,3.4,3.1,3.9l9.1,2.1c1,0.2,1.8,1,2.3,1.9c0.5,0.9,0.5,2,0,2.9l-5.5,7.5c-1.1,1.5-0.9,3.7,0.4,4.9l8.7,8.7 c1.2,1.2,3.4,1.5,4.9,0.4l7.5-5.5c0.9-0.5,2-0.5,2.9,0c0.9,0.5,1.7,1.4,1.9,2.3l2.1,9.1c0.4,1.8,2,3.1,3.9,3.1h12.3 c1.8,0,3.4-1.3,3.9-3.1l2.1-9.1c0.2-1,1-1.8,1.9-2.3c0.9-0.5,2-0.5,2.9,0l7.5,5.5c1.5,1.1,3.7,0.9,4.9-0.4l8.7-8.7 c1.2-1.2,1.5-3.4,0.4-4.9l-5.5-7.5c-0.5-0.9-0.5-2,0-2.9c0.5-0.9,1.4-1.7,2.3-1.9l9.1-2.1c1.8-0.4,3.1-2,3.1-3.9V59.6 C100.7,57.8,99.4,56.2,97.6,55.7z'/%3E%3C/svg%3E"); margin-right: 5px; animation: rotate 4s linear infinite; } .detail-button:hover .button-gear { animation: rotate 1s linear infinite; } /* Rivets on corners */ .rivets { position: absolute; width: 12px; height: 12px; background-color: var(--copper-dark); border: 1px solid var(--brass); border-radius: 50%; box-shadow: inset 0 0 3px var(--shadow); } .rivet-1 { top: 10px; left: 10px; } .rivet-2 { top: 10px; right: 10px; } .rivet-3 { bottom: 10px; left: 10px; } .rivet-4 { bottom: 10px; right: 10px; } /* Animations */ @keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } @keyframes rotate-reverse { from { transform: rotate(0deg); } to { transform: rotate(-360deg); } } @keyframes pulse { 0% { box-shadow: 0 0 15px var(--brass); } 50% { box-shadow: 0 0 25px var(--brass), 0 0 30px var(--copper-light); } 100% { box-shadow: 0 0 15px var(--brass); } } @keyframes slideUp { from { transform: translateX(-50%) translateY(50px); opacity: 0; } to { transform: translateX(-50%) translateY(0); opacity: 1; } } /* Custom Gauge for Weight */ .weight-gauge { width: 100%; height: 10px; background-color: var(--copper-dark); border-radius: 5px; overflow: hidden; margin-top: 5px; border: 1px solid var(--copper-medium); position: relative; } .weight-fill { height: 100%; width: 65%; background: linear-gradient(to right, var(--brass), var(--copper-light)); border-radius: 5px; transition: width 0.5s ease; position: relative; } .weight-fill::after { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 50%; background: rgba(255,255,255,0.2); } .weight-text { font-size: 10px; text-align: right; color: var(--parchment); margin-top: 2px; } /* Responsive design */ @media (max-width: 600px) { .inner-container { padding: 10px; } .title { font-size: 28px; } .inventory-grid { grid-template-columns: repeat(4, 1fr); grid-auto-rows: 70px; gap: 8px; } .item-detail { width: 95%; } } @media (max-width: 400px) { .inventory-grid { grid-template-columns: repeat(3, 1fr); } .stats { flex-direction: column; gap: 5px; } .detail-body { flex-direction: column; } .detail-stats { width: 100%; margin-left: 0; margin-top: 10px; } } </style> </head> <body> <div class="container"> <div class="inventory-frame"> <div class="gear gear1"></div> <div class="gear gear2"></div> <div class="gear gear3"></div> <div class="gear gear4"></div> <div class="rivets rivet-1"></div> <div class="rivets rivet-2"></div> <div class="rivets rivet-3"></div> <div class="rivets rivet-4"></div> <div class="inner-container"> <div class="header"> <h1 class="title">Personal Arsenal</h1> <div class="stats"> <div class="stat"> <div class="stat-value">65/100</div> <div class="stat-label">Encumbrance</div> <div class="weight-gauge"> <div class="weight-fill"></div> </div> <div class="weight-text">65 lbs</div> </div> <div class="stat"> <div class="stat-value">1243</div> <div class="stat-label">Aether Coins</div> </div> </div> </div> <div class="tabs"> <div class="tab active">Equipment</div> <div class="tab">Consumables</div> <div class="tab">Components</div> <div class="tab">Archives</div> </div> <div class="inventory-grid"> <div class="item" data-id="1"> <div class="item-icon">🔧</div> <div class="item-name">Aether Wrench</div> <div class="item-quantity">1</div> </div> <div class="item" data-id="2"> <div class="item-icon">🔫</div> <div class="item-name">Tesla Sidearm</div> <div class="item-quantity">1</div> </div> <div class="item" data-id="3"> <div class="item-icon">🧪</div> <div class="item-name">Incendiary Vial</div> <div class="item-quantity">5</div> </div> <div class="item" data-id="4"> <div class="item-icon">🔍</div> <div class="item-name">Analytical Goggles</div> <div class="item-quantity">1</div> </div> <div class="item" data-id="5"> <div class="item-icon">⚙️</div> <div class="item-name">Clockwork Gears</div> <div class="item-quantity">12</div> </div> <div class="item" data-id="6"> <div class="item-icon">📜</div> <div class="item-name">Pneumatic Schematics</div> <div class="item-quantity">3</div> </div> <div class="item" data-id="7"> <div class="item-icon">🧭</div> <div class="item-name">Ethereal Compass</div> <div class="item-quantity">1</div> </div> <div class="item" data-id="8"> <div class="item-icon">🔗</div> <div class="item-name">Pressure Coupling</div> <div class="item-quantity">4</div> </div> <div class="item" data-id="9"> <div class="item-icon">🗡️</div> <div class="item-name">Voltaic Dagger</div> <div class="item-quantity">1</div> </div> <div class="item" data-id="10"> <div class="item-icon">🧰</div> <div class="item-name">Brass Toolkit</div> <div class="item-quantity">1</div> </div> <div class="item" data-id="11"> <div class="item-icon">🦾</div> <div class="item-name">Mechanical Gauntlet</div> <div class="item-quantity">1</div> </div> <div class="item" data-id="12"> <div class="item-icon">💊</div> <div class="item-name">Healing Tincture</div> <div class="item-quantity">7</div> </div> <div class="item" data-id="13"> <div class="item-icon">🔋</div> <div class="item-name">Aether Battery</div> <div class="item-quantity">3</div> </div> <div class="item" data-id="14"> <div class="item-icon">🎭</div> <div class="item-name">Masquerade Mask</div> <div class="item-quantity">1</div> </div> <div class="item" data-id="15"> <div class="item-icon">📯</div> <div class="item-name">Resonance Horn</div> <div class="item-quantity">1</div> </div> </div> <div class="item-detail" id="item-detail"> <div class="detail-header"> <div class="detail-icon">🔫</div> <div class="detail-title"> <h2 class="detail-name">Tesla Sidearm</h2> <div class="detail-type">Weapon • One-handed • Ranged</div> </div> <button class="detail-close">×</button> </div> <div class="detail-body"> <div class="detail-description"> A compact aether-powered pistol that discharges electrical arcs. This prototype was designed by the Ironclad Brigade. The ornate brass casing is engraved with lightning motifs. </div> <div class="detail-stats"> <div class="detail-stat"> <span>Damage:</span> <span class="detail-stat-value">12-18</span> </div> <div class="detail-stat"> <span>Weight:</span> <span class="detail-stat-value">2.4 lbs</span> </div> <div class="detail-stat"> <span>Range:</span> <span class="detail-stat-value">25 m</span> </div> <div class="detail-stat"> <span>Condition:</span> <span class="detail-stat-value">87%</span> </div> </div> </div> <div class="detail-actions"> <button class="detail-button"><span class="button-gear"></span> Disassemble</button> <button class="detail-button"><span class="button-gear"></span> Modify</button> <button class="detail-button primary"><span class="button-gear"></span> Equip</button> </div> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const items = document.querySelectorAll('.item'); const itemDetail = document.getElementById('item-detail'); const closeButton = document.querySelector('.detail-close'); const tabs = document.querySelectorAll('.tab'); // Item selection items.forEach(item => { item.addEventListener('click', function() { // Remove selection from other items items.forEach(i => i.classList.remove('selected')); // Add selection to clicked item this.classList.add('selected'); // Show item details with mechanical animation itemDetail.classList.add('active'); // Update detail content based on selected item updateItemDetail(this.dataset.id); // Add mechanical sound effect playMechanicalSound(); }); }); // Close item detail closeButton.addEventListener('click', function() { itemDetail.classList.remove('active'); items.forEach(i => i.classList.remove('selected')); }); // Tab switching tabs.forEach(tab => { tab.addEventListener('click', function() { tabs.forEach(t => t.classList.remove('active')); this.classList.add('active'); playMechanicalSound(); }); }); // Simulated mechanical sound effect function playMechanicalSound() { try { const context = new (window.AudioContext || window.webkitAudioContext)(); const oscillator = context.createOscillator(); const gainNode = context.createGain(); oscillator.type = 'square'; oscillator.frequency.setValueAtTime(120, context.currentTime); oscillator.frequency.exponentialRampToValueAtTime(40, context.currentTime + 0.2); gainNode.gain.setValueAtTime(0.1, context.currentTime); gainNode.gain.exponentialRampToValueAtTime(0.001, context.currentTime + 0.2); oscillator.connect(gainNode); gainNode.connect(context.destination); oscillator.start(); oscillator.stop(context.currentTime + 0.2); } catch (e) { // Fallback if audio context isn't available console.log("Audio not supported in this context"); } } // Update item detail content function updateItemDetail(itemId) { // This would normally fetch data from a database or state management // For this example, we'll use a simple switch case for item 2 (Tesla Sidearm) // In a real implementation, we'd update all content based on the itemId // Adding a slight mechanical delay effect setTimeout(() => { const detailButtons = document.querySelectorAll('.detail-button'); detailButtons.forEach(button => { button.addEventListener('click', function(e) { e.preventDefault(); playMechanicalSound(); // Add click animation this.style.transform = 'scale(0.95)'; setTimeout(() => { this.style.transform = 'scale(1)'; }, 100); }); }); }, 100); } // Simulated gear movements function animateGears() { const gears = document.querySelectorAll('.gear'); gears.forEach(gear => { const randomDelay = Math.random() * 10; gear.style.animationDelay = `-${randomDelay}s`; }); } // Initialize animations animateGears(); // Add hover sound effect to all interactive elements const interactiveElements = document.querySelectorAll('.item, .tab, .detail-button'); interactiveElements.forEach(el => { el.addEventListener('mouseenter', function() { try { const context = new (window.AudioContext || window.webkitAudioContext)(); const oscillator = context.createOscillator(); const gainNode = context.createGain(); oscillator.type = 'sine'; oscillator.frequency.setValueAtTime(440, context.currentTime); gainNode.gain.setValueAtTime(0.05, context.currentTime); gainNode.gain.exponentialRampToValueAtTime(0.001, context.currentTime + 0.1); oscillator.connect(gainNode); gainNode.connect(context.destination); oscillator.start(); oscillator.stop(context.currentTime + 0.1); } catch (e) { // Fallback if audio context isn't available } }); }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Arial', sans-serif; user-select: none; } body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background: #141E30; background: linear-gradient(to right, #243B55, #141E30); overflow: hidden; } .container { width: 100%; max-width: 700px; height: 700px; display: flex; flex-direction: column; justify-content: center; align-items: center; position: relative; } .puzzle-background { position: absolute; width: 100%; height: 100%; opacity: 0.05; pointer-events: none; z-index: 0; } .puzzle-pattern { width: 100%; height: 100%; background-image: radial-gradient(circle at 25px 25px, rgba(255, 255, 255, 0.2) 2px, transparent 0), radial-gradient(circle at 75px 75px, rgba(255, 255, 255, 0.15) 2px, transparent 0), radial-gradient(circle at 125px 125px, rgba(255, 255, 255, 0.1) 2px, transparent 0); background-size: 150px 150px; animation: patternMove 60s linear infinite; } @keyframes patternMove { 0% { background-position: 0 0; } 100% { background-position: 150px 150px; } } .score-widget { background: rgba(255, 255, 255, 0.1); border-radius: 20px; width: 80%; max-width: 500px; padding: 25px; text-align: center; backdrop-filter: blur(10px); border: 2px solid rgba(255, 255, 255, 0.1); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2); z-index: 2; position: relative; } .widget-title { color: #FFFFFF; margin-bottom: 20px; font-size: 24px; letter-spacing: 2px; text-transform: uppercase; font-weight: 600; text-shadow: 0 0 10px rgba(142, 236, 245, 0.5); } .score-display { display: flex; justify-content: center; margin-bottom: 30px; position: relative; } .score-value { font-size: 72px; font-weight: 700; color: #FFFFFF; text-shadow: 0 0 10px rgba(142, 236, 245, 0.6), 0 0 20px rgba(142, 236, 245, 0.4), 0 0 30px rgba(142, 236, 245, 0.2); position: relative; transition: all 0.3s ease; } .score-change { position: absolute; font-size: 24px; font-weight: bold; opacity: 0; transform: translateY(0); transition: all 0.5s ease; } .score-change.positive { color: #64FFDA; } .score-change.negative { color: #FF5252; } .score-change.show { opacity: 1; transform: translateY(-30px); } .buttons-container { display: flex; justify-content: space-around; margin-bottom: 20px; } .score-btn { background: rgba(255, 255, 255, 0.15); border: none; color: white; padding: 15px 30px; border-radius: 50px; font-size: 16px; cursor: pointer; transition: all 0.3s ease; position: relative; overflow: hidden; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); } .score-btn:before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(120deg, transparent, rgba(255, 255, 255, 0.3), transparent); transform: translateX(-100%); transition: 0.6s; } .score-btn:hover:before { transform: translateX(100%); } .score-btn.increase { background-color: rgba(100, 255, 218, 0.2); } .score-btn.increase:hover { background-color: rgba(100, 255, 218, 0.4); } .score-btn.decrease { background-color: rgba(255, 82, 82, 0.2); } .score-btn.decrease:hover { background-color: rgba(255, 82, 82, 0.4); } .score-btn.reset { background-color: rgba(255, 193, 7, 0.2); margin-top: 15px; } .score-btn.reset:hover { background-color: rgba(255, 193, 7, 0.4); } .level-indicator { margin-top: 30px; color: #FFFFFF; font-size: 18px; } .level-bar { height: 10px; width: 100%; background: rgba(255, 255, 255, 0.1); border-radius: 5px; margin-top: 10px; overflow: hidden; position: relative; } .level-progress { height: 100%; background: linear-gradient(90deg, #64FFDA, #8EECF5); width: 0%; border-radius: 5px; transition: width 0.5s ease; position: relative; } .level-progress:after { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.5) 50%, rgba(255, 255, 255, 0) 100%); animation: shimmer 2s infinite; transform: translateX(-100%); } @keyframes shimmer { 100% { transform: translateX(100%); } } .combo-counter { margin-top: 20px; background: rgba(0, 0, 0, 0.2); border-radius: 10px; padding: 10px 15px; display: inline-flex; align-items: center; transform: scale(0.95); transition: all 0.3s ease; } .combo-counter.active { transform: scale(1); box-shadow: 0 0 15px rgba(142, 236, 245, 0.6); } .combo-title { color: #FFFFFF; font-size: 14px; margin-right: 10px; } .combo-value { color: #64FFDA; font-size: 20px; font-weight: bold; } .combo-multiplier { font-size: 12px; color: #FFC107; margin-left: 5px; } @media (max-width: 500px) { .score-widget { width: 90%; padding: 20px; } .widget-title { font-size: 20px; } .score-value { font-size: 60px; } .buttons-container { flex-direction: column; align-items: center; gap: 15px; } .score-btn { width: 80%; padding: 12px 0; } } .challenge-notification { position: absolute; top: -70px; left: 50%; transform: translateX(-50%); background: rgba(255, 193, 7, 0.2); padding: 10px 20px; border-radius: 10px; color: #FFFFFF; font-size: 14px; transition: top 0.5s ease; z-index: 3; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); border: 1px solid rgba(255, 193, 7, 0.4); } .challenge-notification.show { top: 10px; } .point-values { display: flex; justify-content: space-between; margin-top: 20px; padding: 0 10px; } .point-item { display: flex; flex-direction: column; align-items: center; opacity: 0.7; transition: opacity 0.3s ease; } .point-item:hover { opacity: 1; } .point-icon { width: 40px; height: 40px; border-radius: 10px; display: flex; justify-content: center; align-items: center; margin-bottom: 5px; font-weight: bold; color: #FFF; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16); } .point-icon.easy { background: linear-gradient(135deg, #64FFDA, #48D1CC); } .point-icon.medium { background: linear-gradient(135deg, #FFC107, #FF9800); } .point-icon.hard { background: linear-gradient(135deg, #FF5252, #F44336); } .point-label { font-size: 12px; color: #FFF; opacity: 0.8; } </style> </head> <body> <div class="container"> <div class="puzzle-background"> <div class="puzzle-pattern"></div> </div> <div class="score-widget"> <div class="challenge-notification">Challenge unlocked: Color Cascade!</div> <h1 class="widget-title">Puzzle Master</h1> <div class="score-display"> <div class="score-value" id="score">0</div> <div class="score-change" id="score-change">+0</div> </div> <div class="buttons-container"> <button class="score-btn increase" data-value="10">Easy (+10)</button> <button class="score-btn increase" data-value="25">Medium (+25)</button> <button class="score-btn increase" data-value="50">Hard (+50)</button> </div> <button class="score-btn decrease" data-value="-5">Hint (-5)</button> <button class="score-btn reset">Reset Score</button> <div class="combo-counter" id="combo-counter"> <span class="combo-title">COMBO</span> <span class="combo-value" id="combo-value">0</span> <span class="combo-multiplier" id="combo-multiplier">x1</span> </div> <div class="level-indicator"> <span>LEVEL </span> <span id="level">1</span> </div> <div class="level-bar"> <div class="level-progress" id="level-progress"></div> </div> <div class="point-values"> <div class="point-item"> <div class="point-icon easy">+10</div> <div class="point-label">Easy</div> </div> <div class="point-item"> <div class="point-icon medium">+25</div> <div class="point-label">Medium</div> </div> <div class="point-item"> <div class="point-icon hard">+50</div> <div class="point-label">Hard</div> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Elements const scoreElement = document.getElementById('score'); const scoreChangeElement = document.getElementById('score-change'); const levelElement = document.getElementById('level'); const levelProgressElement = document.getElementById('level-progress'); const comboCounter = document.getElementById('combo-counter'); const comboValue = document.getElementById('combo-value'); const comboMultiplier = document.getElementById('combo-multiplier'); const challengeNotification = document.querySelector('.challenge-notification'); // Variables let currentScore = 0; let currentLevel = 1; let pointsToNextLevel = 100; let combo = 0; let lastActionTime = 0; const comboTimeout = 5000; // 5 seconds let comboTimeoutId; // Initialize updateScoreDisplay(); updateLevelDisplay(); // Score Buttons document.querySelectorAll('.score-btn').forEach(btn => { btn.addEventListener('click', function() { // Reset button if (this.classList.contains('reset')) { resetScore(); return; } // Get value const value = parseInt(this.dataset.value); // Calculate final value with combo let finalValue = value; if (value > 0 && combo > 0) { const multiplier = 1 + (combo * 0.1); // 10% per combo finalValue = Math.round(value * multiplier); } // Update combo if (value > 0) { updateCombo(true); } else { resetCombo(); } // Update score updateScore(finalValue); // Add button press effects addButtonEffect(this); }); }); // Functions function updateScore(value) { currentScore += value; if (currentScore < 0) currentScore = 0; // Show score change animation scoreChangeElement.textContent = value > 0 ? `+${value}` : value; scoreChangeElement.className = 'score-change'; scoreChangeElement.classList.add(value >= 0 ? 'positive' : 'negative'); scoreChangeElement.classList.add('show'); setTimeout(() => { scoreChangeElement.classList.remove('show'); }, 1000); // Update score with animation animateScoreChange(currentScore); // Check level up checkLevelProgress(); // Check for challenges checkChallenges(); } function updateScoreDisplay() { scoreElement.textContent = currentScore; } function animateScoreChange(newScore) { const duration = 1000; const startTime = performance.now(); const startScore = parseInt(scoreElement.textContent); function updateAnimation(currentTime) { const elapsedTime = currentTime - startTime; if (elapsedTime < duration) { const progress = elapsedTime / duration; const currentValue = Math.floor(startScore + progress * (newScore - startScore)); scoreElement.textContent = currentValue; requestAnimationFrame(updateAnimation); } else { scoreElement.textContent = newScore; } } requestAnimationFrame(updateAnimation); } function resetScore() { currentScore = 0; currentLevel = 1; pointsToNextLevel = 100; resetCombo(); updateScoreDisplay(); updateLevelDisplay(); // Add reset animation scoreElement.style.transform = 'scale(0.5)'; scoreElement.style.opacity = '0.5'; setTimeout(() => { scoreElement.style.transform = 'scale(1)'; scoreElement.style.opacity = '1'; }, 300); } function updateLevelDisplay() { levelElement.textContent = currentLevel; const progress = (currentScore % pointsToNextLevel) / pointsToNextLevel * 100; levelProgressElement.style.width = `${progress}%`; } function checkLevelProgress() { if (currentScore >= currentLevel * pointsToNextLevel) { currentLevel++; // Show level up animation levelElement.style.transform = 'scale(1.5)'; levelElement.style.color = '#FFC107'; setTimeout(() => { levelElement.style.transform = 'scale(1)'; levelElement.style.color = '#FFFFFF'; }, 500); } updateLevelDisplay(); } function updateCombo(increment) { clearTimeout(comboTimeoutId); if (increment) { const now = Date.now(); if (now - lastActionTime < comboTimeout) { combo++; } else { combo = 1; } lastActionTime = now; // Activate combo visual comboCounter.classList.add('active'); // Set combo timeout comboTimeoutId = setTimeout(() => { resetCombo(); }, comboTimeout); } // Update display comboValue.textContent = combo; comboMultiplier.textContent = `x${(1 + (combo * 0.1)).toFixed(1)}`; } function resetCombo() { combo = 0; comboCounter.classList.remove('active'); comboValue.textContent = combo; comboMultiplier.textContent = 'x1'; clearTimeout(comboTimeoutId); } function addButtonEffect(button) { button.style.transform = 'scale(0.95)'; setTimeout(() => { button.style.transform = 'scale(1)'; }, 150); } function checkChallenges() { // Show challenge at a certain score if (currentScore >= 100 && !challengeNotification.classList.contains('show')) { challengeNotification.classList.add('show'); setTimeout(() => { challengeNotification.classList.remove('show'); }, 3000); } } }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>FPS Chat Overlay</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', sans-serif; } body { width: 100%; height: 100%; overflow: hidden; display: flex; justify-content: center; align-items: center; background-image: url('data:image/jpeg;base64,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AAAAAAAAAAAAAAAAAK4bY5xJ93HXUzZ6+KQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTNk66c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnTFnS7c7PTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNnSZs6WbnpkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnO0s6Xbnp0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJekli766YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGLOqWXrtgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmzpZr03IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOZ0lnS9O2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Strategy Game Analytics Dashboard</title> <style> :root { --primary: #3a86ff; --secondary: #8338ec; --accent: #ff006e; --success: #06d6a0; --warning: #ffbe0b; --danger: #ef476f; --dark: #1a1a2e; --light: #f8f9fa; --medium: #73737d; --card-bg: rgba(255, 255, 255, 0.05); --card-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); --card-border: 1px solid rgba(255, 255, 255, 0.08); --tooltip-bg: rgba(26, 26, 46, 0.95); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; } body { background: linear-gradient(135deg, var(--dark), #121224); color: var(--light); overflow-x: hidden; min-height: 700px; max-width: 700px; margin: 0 auto; position: relative; } .dashboard { display: grid; grid-template-columns: repeat(12, 1fr); grid-template-rows: auto; gap: 16px; padding: 20px; max-width: 100%; height: 700px; overflow-y: auto; position: relative; } .dashboard::-webkit-scrollbar { width: 6px; } .dashboard::-webkit-scrollbar-track { background: rgba(255, 255, 255, 0.05); border-radius: 10px; } .dashboard::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.2); border-radius: 10px; } .header { grid-column: span 12; display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; position: sticky; top: 0; z-index: 100; backdrop-filter: blur(10px); background: rgba(26, 26, 46, 0.7); padding: 12px; border-radius: 12px; } .header h1 { font-size: 1.5rem; font-weight: 700; background: linear-gradient(90deg, var(--primary), var(--secondary)); -webkit-background-clip: text; background-clip: text; color: transparent; } .filters { display: flex; gap: 12px; } .filter-dropdown { position: relative; } .filter-button { background: var(--card-bg); border: var(--card-border); border-radius: 8px; color: var(--light); padding: 8px 12px; font-size: 0.85rem; cursor: pointer; display: flex; align-items: center; gap: 6px; transition: all 0.3s ease; } .filter-button:hover { background: rgba(255, 255, 255, 0.1); } .filter-button i { font-size: 0.7rem; } .filter-dropdown-content { display: none; position: absolute; background: var(--tooltip-bg); backdrop-filter: blur(10px); min-width: 160px; border-radius: 8px; box-shadow: var(--card-shadow); z-index: 10; top: 40px; right: 0; border: var(--card-border); padding: 8px 0; } .filter-dropdown-content a { color: var(--light); padding: 8px 16px; text-decoration: none; display: block; font-size: 0.85rem; transition: all 0.2s ease; } .filter-dropdown-content a:hover { background: rgba(255, 255, 255, 0.1); } .filter-dropdown:hover .filter-dropdown-content { display: block; animation: fadeIn 0.3s ease; } .card { background: var(--card-bg); border-radius: 12px; box-shadow: var(--card-shadow); transition: all 0.3s ease; border: var(--card-border); overflow: hidden; display: flex; flex-direction: column; transform-style: preserve-3d; transform: perspective(800px) rotateX(8deg) rotateY(0deg); position: relative; } .card:hover { box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3); transform: perspective(800px) rotateX(10deg) rotateY(5deg) translateY(-5px); border: 1px solid rgba(255, 255, 255, 0.15); } .card::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(45deg, transparent 48%, rgba(255, 255, 255, 0.03) 50%, transparent 52%); z-index: 1; pointer-events: none; } .card-header { padding: 16px; border-bottom: 1px solid rgba(255, 255, 255, 0.05); display: flex; justify-content: space-between; align-items: center; } .card-title { font-size: 1rem; font-weight: 600; color: var(--light); display: flex; align-items: center; gap: 8px; } .card-icon { display: flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 8px; background: rgba(255, 255, 255, 0.1); } .card-options { color: var(--medium); font-size: 1.2rem; cursor: pointer; transition: color 0.2s ease; } .card-options:hover { color: var(--light); } .card-body { padding: 16px; flex-grow: 1; display: flex; flex-direction: column; justify-content: space-between; } .card-metric { font-size: 2rem; font-weight: 700; color: var(--light); margin-bottom: 8px; } .card-trend { display: flex; align-items: center; gap: 6px; font-size: 0.875rem; } .trend-up { color: var(--success); } .trend-down { color: var(--danger); } .card-description { color: var(--medium); font-size: 0.875rem; line-height: 1.5; margin-top: 12px; } .chart-container { width: 100%; height: 180px; margin-top: 16px; } .metrics-card { grid-column: span 4; } @media (max-width: 600px) { .metrics-card { grid-column: span 12; } } .chart-card { grid-column: span 6; } @media (max-width: 600px) { .chart-card { grid-column: span 12; } } .tactics-card { grid-column: span 12; } .tactics-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-top: 16px; } @media (max-width: 600px) { .tactics-grid { grid-template-columns: 1fr; } } .tactic-item { background: rgba(255, 255, 255, 0.05); border-radius: 8px; padding: 12px; display: flex; flex-direction: column; gap: 8px; transition: all 0.2s ease; position: relative; overflow: hidden; cursor: pointer; } .tactic-item:hover { background: rgba(255, 255, 255, 0.1); transform: translateY(-2px); } .tactic-item::before { content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; } .tactic-item.balanced::before { background: var(--primary); } .tactic-item.aggressive::before { background: var(--danger); } .tactic-item.defensive::before { background: var(--success); } .tactic-name { font-weight: 600; font-size: 0.9rem; } .tactic-stats { display: flex; gap: 12px; font-size: 0.8rem; color: var(--medium); } .tactic-stat { display: flex; align-items: center; gap: 4px; } .leaderboard-card { grid-column: span 6; } @media (max-width: 600px) { .leaderboard-card { grid-column: span 12; } } .leaderboard-list { margin-top: 16px; } .leaderboard-item { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid rgba(255, 255, 255, 0.05); } .leaderboard-rank { width: 24px; height: 24px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 0.8rem; background: rgba(255, 255, 255, 0.1); } .rank-1 { background: linear-gradient(135deg, #FFD700, #FFA500); color: #000; } .rank-2 { background: linear-gradient(135deg, #C0C0C0, #A9A9A9); color: #000; } .rank-3 { background: linear-gradient(135deg, #CD7F32, #8B4513); color: #fff; } .leaderboard-avatar { width: 32px; height: 32px; border-radius: 8px; background: var(--secondary); display: flex; align-items: center; justify-content: center; font-weight: 600; color: white; } .leaderboard-info { flex-grow: 1; } .leaderboard-name { font-weight: 600; font-size: 0.9rem; } .leaderboard-faction { font-size: 0.75rem; color: var(--medium); } .leaderboard-score { font-weight: 600; color: var(--light); } .resource-card { grid-column: span 3; } @media (max-width: 600px) { .resource-card { grid-column: span 6; } } .resource-icon { font-size: 1.4rem; margin-right: 8px; } .maps-card { grid-column: span 12; margin-top: 20px; } .maps-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-top: 16px; } @media (max-width: 600px) { .maps-grid { grid-template-columns: repeat(2, 1fr); } } .map-item { aspect-ratio: 16/9; border-radius: 8px; overflow: hidden; position: relative; cursor: pointer; transition: all 0.3s ease; } .map-item:hover { transform: scale(1.03); box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3); } .map-image { width: 100%; height: 100%; object-fit: cover; filter: brightness(0.7); transition: all 0.3s ease; } .map-item:hover .map-image { filter: brightness(0.9); } .map-info { position: absolute; bottom: 0; left: 0; width: 100%; padding: 12px; background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent); } .map-name { font-weight: 600; font-size: 0.9rem; } .map-stats { display: flex; gap: 12px; font-size: 0.75rem; color: rgba(255, 255, 255, 0.7); margin-top: 4px; } .tooltip { position: absolute; background: var(--tooltip-bg); color: var(--light); padding: 12px 16px; border-radius: 8px; font-size: 0.85rem; box-shadow: var(--card-shadow); border: var(--card-border); z-index: 100; max-width: 250px; pointer-events: none; opacity: 0; transition: opacity 0.2s ease; backdrop-filter: blur(10px); } .tooltip h4 { margin-bottom: 6px; font-size: 0.95rem; } .tooltip p { color: var(--medium); font-size: 0.8rem; line-height: 1.4; } .tooltip-stat { display: flex; justify-content: space-between; margin-top: 8px; font-size: 0.8rem; } .tooltip-stat-label { color: var(--medium); } .tooltip-stat-value { font-weight: 500; } @keyframes fadeIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(58, 134, 255, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(58, 134, 255, 0); } 100% { box-shadow: 0 0 0 0 rgba(58, 134, 255, 0); } } .pulse { animation: pulse 2s infinite; } .loading-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: var(--dark); display: flex; justify-content: center; align-items: center; z-index: 1000; transition: opacity 0.5s ease, visibility 0.5s ease; } .loading-spinner { width: 50px; height: 50px; border: 3px solid rgba(255, 255, 255, 0.1); border-radius: 50%; border-top-color: var(--primary); animation: spin 1s ease-in-out infinite; } @keyframes spin { to { transform: rotate(360deg); } } .hidden { opacity: 0; visibility: hidden; } .notification { position: fixed; bottom: 20px; right: 20px; background: var(--primary); color: white; padding: 12px 16px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); display: flex; align-items: center; gap: 12px; z-index: 1000; transform: translateX(120%); transition: transform 0.3s ease; } .notification.show { transform: translateX(0); } .notification-icon { font-size: 1.2rem; } .notification-content { flex-grow: 1; } .notification-title { font-weight: 600; font-size: 0.9rem; margin-bottom: 4px; } .notification-message { font-size: 0.8rem; opacity: 0.9; } .notification-close { color: rgba(255, 255, 255, 0.8); cursor: pointer; transition: color 0.2s ease; } .notification-close:hover { color: white; } .toggle-button { background: var(--card-bg); border: var(--card-border); border-radius: 20px; color: var(--light); display: flex; position: relative; overflow: hidden; font-size: 0.75rem; width: 100%; margin-top: 16px; } .toggle-option { flex: 1; text-align: center; padding: 8px 0; cursor: pointer; position: relative; z-index: 2; transition: color 0.3s ease; } .toggle-option.active { color: #000; } .toggle-slider { position: absolute; height: 100%; background: var(--primary); transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); border-radius: 20px; z-index: 1; width: 33.33%; } /* Custom scrollbar for webkit browsers */ ::-webkit-scrollbar { width: 10px; } ::-webkit-scrollbar-track { background: rgba(255, 255, 255, 0.05); } ::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.1); border-radius: 5px; } ::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.2); } </style> </head> <body> <div class="loading-overlay"> <div class="loading-spinner"></div> </div> <div class="dashboard"> <div class="header"> <h1>STRATFORGE ANALYTICS</h1> <div class="filters"> <div class="filter-dropdown"> <button class="filter-button">Timeline <i>▼</i></button> <div class="filter-dropdown-content"> <a href="#" data-filter="day">Last 24 Hours</a> <a href="#" data-filter="week">Last 7 Days</a> <a href="#" data-filter="month">Last 30 Days</a> <a href="#" data-filter="season">Current Season</a> </div> </div> <div class="filter-dropdown"> <button class="filter-button">Game Mode <i>▼</i></button> <div class="filter-dropdown-content"> <a href="#" data-mode="all">All Modes</a> <a href="#" data-mode="ranked">Ranked</a> <a href="#" data-mode="casual">Casual</a> <a href="#" data-mode="tournament">Tournament</a> </div> </div> </div> </div> <div class="card metrics-card"> <div class="card-header"> <div class="card-title"> <div class="card-icon">⚔️</div> Battles Fought </div> <div class="card-options">⋮</div> </div> <div class="card-body"> <div> <div class="card-metric">247</div> <div class="card-trend trend-up"> <span>↑ 12.3%</span> vs. last week </div> </div> <div class="chart-container battles-chart"></div> </div> </div> <div class="card metrics-card"> <div class="card-header"> <div class="card-title"> <div class="card-icon">🏆</div> Win Rate </div> <div class="card-options">⋮</div> </div> <div class="card-body"> <div> <div class="card-metric">62.8%</div> <div class="card-trend trend-up"> <span>↑ 2.7%</span> vs. last week </div> </div> <div class="chart-container winrate-chart"></div> </div> </div> <div class="card metrics-card"> <div class="card-header"> <div class="card-title"> <div class="card-icon">⭐</div> Ranking Points </div> <div class="card-options">⋮</div> </div> <div class="card-body"> <div> <div class="card-metric">1,842</div> <div class="card-trend trend-up"> <span>↑ 87</span> since last week </div> </div> <div class="chart-container ranking-chart"></div> </div> </div> <div class="card chart-card"> <div class="card-header"> <div class="card-title"> <div class="card-icon">📊</div> Performance Trends </div> <div class="card-options">⋮</div> </div> <div class="card-body"> <div class="toggle-button"> <div class="toggle-slider"></div> <div class="toggle-option active" data-index="0">Win Rate</div> <div class="toggle-option" data-index="1">Resources</div> <div class="toggle-option" data-index="2">Units</div> </div> <div class="chart-container performance-chart"></div> </div> </div> <div class="card chart-card"> <div class="card-header"> <div class="card-title"> <div class="card-icon">⚡</div> Match Duration Analysis </div> <div class="card-options">⋮</div> </div> <div class="card-body"> <div class="chart-container duration-chart"></div> <div class="card-description"> Your optimal match duration is 15-20 minutes, where your win rate peaks at 78%. </div> </div> </div> <div class="card tactics-card"> <div class="card-header"> <div class="card-title"> <div class="card-icon">🎯</div> Tactical Analysis </div> <div class="card-options">⋮</div> </div> <div class="card-body"> <div class="card-description"> Comparing your most effective tactical approaches based on win rate and resource efficiency. </div> <div class="tactics-grid"> <div class="tactic-item balanced" data-tactic="balanced"> <div class="tactic-name">Balanced Control</div> <div class="tactic-stats"> <div class="tactic-stat"> <span>Win:</span> 67% </div> <div class="tactic-stat"> <span>Games:</span> 89 </div> </div> </div> <div class="tactic-item aggressive" data-tactic="aggressive"> <div class="tactic-name">Aggressive Expansion</div> <div class="tactic-stats"> <div class="tactic-stat"> <span>Win:</span> 72% </div> <div class="tactic-stat"> <span>Games:</span> 54 </div> </div> </div> <div class="tactic-item defensive" data-tactic="defensive"> <div class="tactic-name">Defensive Stronghold</div> <div class="tactic-stats"> <div class="tactic-stat"> <span>Win:</span> 58% </div> <div class="tactic-stat"> <span>Games:</span> 62 </div> </div> </div> </div> </div> </div> <div class="card resource-card"> <div class="card-header"> <div class="card-title"> <div class="card-icon">💎</div> Crystal </div> <div class="card-options">⋮</div> </div> <div class="card-body"> <div> <div class="card-metric">153</div> <div class="card-trend trend-up"> <span>↑ 8.2%</span> efficiency </div> </div> </div> </div> <div class="card resource-card"> <div class="card-header"> <div class="card-title"> <div class="card-icon">⚙️</div> Metal </div> <div class="card-options">⋮</div> </div> <div class="card-body"> <div> <div class="card-metric">247</div> <div class="card-trend trend-down"> <span>↓ 3.1%</span> efficiency </div> </div> </div> </div> <div class="card resource-card"> <div class="card-header"> <div class="card-title"> <div class="card-icon">🔋</div> Energy </div> <div class="card-options">⋮</div> </div> <div class="card-body"> <div> <div class="card-metric">412</div> <div class="card-trend trend-up"> <span>↑ 15.3%</span> efficiency </div> </div> </div> </div> <div class="card resource-card"> <div class="card-header"> <div class="card-title"> <div class="card-icon">🌾</div> Supply </div> <div class="card-options">⋮</div> </div> <div class="card-body"> <div> <div class="card-metric">92/100</div> <div class="card-trend"> <span>92%</span> utilization </div> </div> </div> </div> <div class="card leaderboard-card"> <div class="card-header"> <div class="card-title"> <div class="card-icon">🥇</div> Faction Leaderboard </div> <div class="card-options">⋮</div> </div> <div class="card-body"> <div class="leaderboard-list"> <div class="leaderboard-item"> <div class="leaderboard-rank rank-1">1</div> <div class="leaderboard-avatar" style="background-color: #3a86ff;">RP</div> <div class="leaderboard-info"> <div class="leaderboard-name">RiftPhoenix</div> <div class="leaderboard-faction">Nova Imperium</div> </div> <div class="leaderboard-score">2,145</div> </div> <div class="leaderboard-item"> <div class="leaderboard-rank rank-2">2</div> <div class="leaderboard-avatar" style="background-color: #8338ec;">TD</div> <div class="leaderboard-info"> <div class="leaderboard-name">TacticalDrift</div> <div class="leaderboard-faction">Terra Coalition</div> </div> <div class="leaderboard-score">2,067</div> </div> <div class="leaderboard-item"> <div class="leaderboard-rank rank-3">3</div> <div class="leaderboard-avatar" style="background-color: #ff006e;">SQ</div> <div class="leaderboard-info"> <div class="leaderboard-name">StratQuasar</div> <div class="leaderboard-faction">Zephyr Alliance</div> </div> <div class="leaderboard-score">1,978</div> </div> <div class="leaderboard-item"> <div class="leaderboard-rank">4</div> <div class="leaderboard-avatar" style="background-color: #06d6a0;">VX</div> <div class="leaderboard-info"> <div class="leaderboard-name">VortexMaster</div> <div class="leaderboard-faction">Nova Imperium</div> </div> <div class="leaderboard-score">1,903</div> </div> <div class="leaderboard-item"> <div class="leaderboard-rank pulse">5</div> <div class="leaderboard-avatar" style="background-color: #ef476f;">YU</div> <div class="leaderboard-info"> <div class="leaderboard-name">YOU</div> <div class="leaderboard-faction">Terra Coalition</div> </div> <div class="leaderboard-score">1,842</div> </div> </div> </div> </div> <div class="card maps-card"> <div class="card-header"> <div class="card-title"> <div class="card-icon">🗺️</div> Map Performance </div> <div class="card-options">⋮</div> </div> <div class="card-body"> <div class="maps-grid"> <div class="map-item" data-map="nebula"> <img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='120' viewBox='0 0 200 120'%3E%3Crect width='200' height='120' fill='%23172A45'/%3E%3Ccircle cx='60' cy='40' r='20' fill='%233A86FF' opacity='0.7'/%3E%3Ccircle cx='140' cy='80' r='25' fill='%238338EC' opacity='0.6'/%3E%3Ccircle cx='100' cy='60' r='15' fill='%23FF006E' opacity='0.5'/%3E%3Cpath d='M0,120 L200,0' stroke='%23FFFFFF' stroke-width='0.5' opacity='0.2'/%3E%3Cpath d='M0,0 L200,120' stroke='%23FFFFFF' stroke-width='0.5' opacity='0.2'/%3E%3C/svg%3E" class="map-image" alt="Nebula Outpost Map"> <div class="map-info"> <div class="map-name">Nebula Outpost</div> <div class="map-stats"> <div class="map-stat">Win: 78%</div> <div class="map-stat">Played: 32</div> </div> </div> </div> <div class="map-item" data-map="desert"> <img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='120' viewBox='0 0 200 120'%3E%3Crect width='200' height='120' fill='%23D4A76A'/%3E%3Cellipse cx='50' cy='30' rx='30' ry='10' fill='%23C69C6D' opacity='0.7'/%3E%3Cellipse cx='150' cy='70' rx='40' ry='15' fill='%23C69C6D' opacity='0.8'/%3E%3Cellipse cx='100' cy='100' rx='50' ry='10' fill='%23C69C6D' opacity='0.6'/%3E%3Cpath d='M20,20 Q100,60 180,20' stroke='%238B5A2B' stroke-width='2' fill='none' opacity='0.3'/%3E%3Cpath d='M20,100 Q100,60 180,100' stroke='%238B5A2B' stroke-width='2' fill='none' opacity='0.3'/%3E%3C/svg%3E" class="map-image" alt="Desert Dunes Map"> <div class="map-info"> <div class="map-name">Desert Dunes</div> <div class="map-stats"> <div class="map-stat">Win: 52%</div> <div class="map-stat">Played: 45</div> </div> </div> </div> <div class="map-item" data-map="frost"> <img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='120' viewBox='0 0 200 120'%3E%3Crect width='200' height='120' fill='%2381A4CD'/%3E%3Cpolygon points='0,120 200,120 200,80 0,80' fill='%23FFFFFF' opacity='0.8'/%3E%3Ccircle cx='50' cy='40' r='15' fill='%23FFFFFF' opacity='0.6'/%3E%3Ccircle cx='150' cy='30' r='20' fill='%23FFFFFF' opacity='0.5'/%3E%3Ccircle cx='100' cy='50' r='10' fill='%23FFFFFF' opacity='0.7'/%3E%3Cpath d='M0,60 L200,60' stroke='%23FFFFFF' stroke-width='2' opacity='0.4'/%3E%3C/svg%3E" class="map-image" alt="Frost Valley Map"> <div class="map-info"> <div class="map-name">Frost Valley</div> <div class="map-stats"> <div class="map-stat">Win: 71%</div> <div class="map-stat">Played: 28</div>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Quest Tracker Panel</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, serif; } body { display: flex; justify-content: center; align-items: center; height: 700px; width: 700px; background-color: #2c1e0f; overflow: hidden; } #quest-tracker { width: 90%; height: 90%; background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400"><filter id="paper" x="0" y="0" width="100%" height="100%"><feTurbulence type="fractalNoise" baseFrequency="0.04" numOctaves="5" result="noise" /><feDiffuseLighting in="noise" lighting-color="rgb(239,224,182)" surfaceScale="2"><feDistantLight azimuth="45" elevation="60" /></feDiffuseLighting></filter><rect width="400" height="400" filter="url(%23paper)" opacity="1"/></svg>'); border-radius: 10px; box-shadow: 0 0 20px rgba(0, 0, 0, 0.5), inset 0 0 40px rgba(139, 69, 19, 0.3); position: relative; overflow: hidden; padding: 30px; display: flex; flex-direction: column; transition: all 0.5s ease; border: 8px solid #5c3c17; border-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><filter id="wood" x="0" y="0" width="100%" height="100%"><feTurbulence type="fractalNoise" baseFrequency="0.07" numOctaves="3" result="noise" /><feColorMatrix type="matrix" values="1 0 0 0 0, 0 1 0 0 0, 0 0 1 0 0, 0 0 0 1 0" in="noise" result="coloredNoise" /><feComponentTransfer><feFuncR type="table" tableValues="0.4 0.6" /><feFuncG type="table" tableValues="0.2 0.4" /><feFuncB type="table" tableValues="0.1 0.2" /></feComponentTransfer></filter><rect width="100" height="100" filter="url(%23wood)" /></svg>') 20 stretch; } .compass { position: absolute; top: 15px; right: 15px; width: 60px; height: 60px; background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle cx="50" cy="50" r="45" fill="none" stroke="%235c3c17" stroke-width="2"/><circle cx="50" cy="50" r="5" fill="%235c3c17"/><path d="M50 10 L45 45 L50 50 L55 45 Z" fill="%23a52a2a"/><path d="M50 90 L55 55 L50 50 L45 55 Z" fill="%235c3c17"/><path d="M10 50 L45 55 L50 50 L45 45 Z" fill="%235c3c17"/><path d="M90 50 L55 45 L50 50 L55 55 Z" fill="%235c3c17"/><text x="50" y="20" font-size="8" text-anchor="middle" fill="%235c3c17">N</text><text x="50" y="85" font-size="8" text-anchor="middle" fill="%235c3c17">S</text><text x="15" y="52" font-size="8" text-anchor="middle" fill="%235c3c17">W</text><text x="85" y="52" font-size="8" text-anchor="middle" fill="%235c3c17">E</text></svg>'); animation: pulse 5s infinite; z-index: 10; } @keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } } h1 { text-align: center; margin-bottom: 15px; font-family: 'Blackletter', 'Palatino Linotype', serif; color: #3b2506; font-size: 2.2rem; letter-spacing: 1px; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2); position: relative; padding-bottom: 10px; } h1::after { content: ""; position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); width: 70%; height: 3px; background: linear-gradient(90deg, transparent, #5c3c17 20%, #5c3c17 80%, transparent); } .ink-spot { position: absolute; background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><path d="M25,5 C15,5 5,25 15,35 C25,45 35,35 35,25 C35,15 35,5 25,5 Z" fill="%231a0f00" opacity="0.15"/></svg>'); width: 50px; height: 50px; z-index: 1; } .quest-list { flex: 1; overflow-y: auto; margin-top: 10px; margin-bottom: 10px; scrollbar-width: thin; scrollbar-color: #5c3c17 rgba(239,224,182,0.5); padding-right: 10px; position: relative; } .quest-list::-webkit-scrollbar { width: 8px; } .quest-list::-webkit-scrollbar-track { background: rgba(239,224,182,0.5); border-radius: 10px; } .quest-list::-webkit-scrollbar-thumb { background-color: #5c3c17; border-radius: 10px; } .quest-item { background-color: rgba(255, 255, 255, 0.3); margin-bottom: 15px; border-radius: 5px; position: relative; overflow: hidden; transition: all 0.3s ease; border: 1px solid rgba(92, 60, 23, 0.3); box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1); transform-origin: center; } .quest-item:hover { transform: scale(1.02); box-shadow: 3px 3px 7px rgba(0, 0, 0, 0.2); } .quest-header { padding: 12px 15px; cursor: pointer; display: flex; justify-content: space-between; align-items: center; background-color: rgba(92, 60, 23, 0.1); border-bottom: 1px dashed rgba(92, 60, 23, 0.3); position: relative; } .quest-title { font-weight: bold; font-size: 1.1rem; color: #3b2506; display: flex; align-items: center; } .quest-type { font-size: 0.75rem; padding: 2px 8px; border-radius: 10px; margin-right: 10px; text-transform: uppercase; font-weight: bold; letter-spacing: 0.5px; } .main-quest { background-color: #a52a2a; color: #fff; } .side-quest { background-color: #3b5998; color: #fff; } .guild-quest { background-color: #daa520; color: #3b2506; } .exploration { background-color: #228b22; color: #fff; } .quest-status { font-size: 0.8rem; color: #5c3c17; display: flex; align-items: center; } .quest-content { max-height: 0; overflow: hidden; transition: max-height 0.5s ease; background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" opacity="0.05"><path d="M0,20 Q40,5 80,20 T160,20 T240,20 T320,20 T400,20 T480,20 T560,20 T640,20 V200 H0 Z" fill="%23000"/></svg>'); background-size: 100px; } .quest-content.active { max-height: 300px; border-top: 1px dashed rgba(92, 60, 23, 0.3); } .quest-details { padding: 15px; color: #3b2506; font-size: 0.9rem; line-height: 1.5; position: relative; } .quest-location { margin-top: 10px; font-style: italic; display: flex; align-items: center; font-size: 0.85rem; } .location-icon { margin-right: 8px; width: 16px; height: 16px; background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z" fill="%233b2506"/></svg>'); background-repeat: no-repeat; background-size: contain; } .quest-rewards { margin-top: 10px; display: flex; align-items: center; font-size: 0.85rem; } .reward-icon { margin-right: 8px; width: 16px; height: 16px; background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm.31-8.86c-1.77-.45-2.34-.94-2.34-1.67 0-.84.79-1.43 2.1-1.43 1.38 0 1.9.66 1.94 1.64h1.71c-.05-1.34-.87-2.57-2.49-2.97V5H10.9v1.69c-1.51.32-2.72 1.3-2.72 2.81 0 1.79 1.49 2.69 3.66 3.21 1.95.46 2.34 1.15 2.34 1.87 0 .53-.39 1.39-2.1 1.39-1.6 0-2.23-.72-2.32-1.64H8.04c.1 1.7 1.36 2.66 2.86 2.97V19h2.34v-1.67c1.52-.29 2.72-1.16 2.73-2.77-.01-2.2-1.9-2.96-3.66-3.42z" fill="%23daa520"/></svg>'); background-repeat: no-repeat; background-size: contain; } .objectives { margin-top: 15px; list-style-type: none; } .objective-item { padding: 5px 0; display: flex; align-items: center; position: relative; } .objective-checkbox { margin-right: 10px; width: 16px; height: 16px; border: 1px solid #5c3c17; border-radius: 3px; position: relative; cursor: pointer; background-color: rgba(255, 255, 255, 0.5); flex-shrink: 0; } .objective-checkbox.checked::after { content: "✓"; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #3b2506; font-size: 12px; } .objective-text { transition: all 0.3s ease; } .objective-item.completed .objective-text { text-decoration: line-through; opacity: 0.7; } .tab-switcher { display: flex; justify-content: center; margin-bottom: 15px; position: relative; } .tab-option { padding: 8px 15px; cursor: pointer; background-color: rgba(255, 255, 255, 0.3); border: 1px solid rgba(92, 60, 23, 0.3); transition: all 0.3s ease; position: relative; z-index: 1; color: #3b2506; } .tab-option:first-child { border-top-left-radius: 10px; border-bottom-left-radius: 10px; } .tab-option:last-child { border-top-right-radius: 10px; border-bottom-right-radius: 10px; } .tab-option.active { background-color: rgba(92, 60, 23, 0.2); font-weight: bold; } .tab-option:hover:not(.active) { background-color: rgba(92, 60, 23, 0.1); } .tab-content { display: none; } .tab-content.active { display: block; animation: fadeIn 0.5s ease; } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .quest-map { position: relative; width: 100%; height: 200px; margin: 15px 0; background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" viewBox="0 0 800 600"><filter id="paper-texture" x="0%" y="0%" width="100%" height="100%"><feTurbulence type="fractalNoise" baseFrequency="0.04" numOctaves="5" result="noise" /><feDiffuseLighting in="noise" lighting-color="rgb(239,224,182)" surfaceScale="2"><feDistantLight azimuth="45" elevation="60" /></feDiffuseLighting></filter><rect width="800" height="600" filter="url(%23paper-texture)" opacity="0.8" /><path d="M100,100 C150,50 200,150 250,100 S350,50 400,100 S450,200 500,150 S550,50 600,100 S650,200 700,150" stroke="%235c3c17" stroke-width="3" fill="none" stroke-dasharray="10 5" /><circle cx="150" cy="120" r="20" fill="%23a52a2a" opacity="0.5" /><circle cx="320" cy="180" r="15" fill="%23228b22" opacity="0.5" /><circle cx="450" cy="90" r="25" fill="%233b5998" opacity="0.5" /><circle cx="580" cy="160" r="18" fill="%23daa520" opacity="0.5" /><path d="M50,250 C100,200 150,300 200,250 S300,200 350,250 S400,350 450,300 S500,200 550,250 S600,350 650,300 S700,200 750,250" stroke="%235c3c17" stroke-width="2" fill="none" /><path d="M200,400 C250,350 300,450 350,400 S450,350 500,400 S550,500 600,450 S650,350 700,400" stroke="%235c3c17" stroke-width="2" fill="none" /><path d="M100,500 Q150,450 200,500 T300,500 T400,500 T500,500" stroke="%235c3c17" stroke-width="3" fill="none" /><text x="150" y="100" font-family="serif" font-size="12" fill="%233b2506">Elwynn Forest</text><text x="380" y="180" font-family="serif" font-size="12" fill="%233b2506">Duskwood</text><text x="550" y="250" font-family="serif" font-size="12" fill="%233b2506">Stranglethorn Vale</text><text x="250" y="380" font-family="serif" font-size="12" fill="%233b2506">Burning Steppes</text><text x="450" y="450" font-family="serif" font-size="12" fill="%233b2506">Redridge Mountains</text></svg>'); background-size: cover; border-radius: 5px; border: 1px solid rgba(92, 60, 23, 0.5); box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); } .progress-container { margin-top: 10px; margin-bottom: 20px; } .progress-label { display: flex; justify-content: space-between; margin-bottom: 5px; color: #3b2506; font-size: 0.85rem; } .progress-bar { width: 100%; height: 10px; background-color: rgba(255, 255, 255, 0.5); border-radius: 10px; overflow: hidden; position: relative; box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.1); } .progress-fill { height: 100%; background-color: #a52a2a; width: 0; border-radius: 10px; transition: width 1s ease; background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent); background-size: 20px 20px; animation: progress-animation 1s linear infinite; } @keyframes progress-animation { 0% { background-position: 0 0; } 100% { background-position: 20px 0; } } .helper-icons { display: flex; justify-content: space-around; margin-top: 15px; } .helper-icon { display: flex; flex-direction: column; align-items: center; cursor: pointer; transition: all 0.3s ease; } .helper-icon:hover { transform: scale(1.1); } .helper-icon span { font-size: 0.7rem; margin-top: 5px; color: #3b2506; } .icon-img { width: 35px; height: 35px; border-radius: 50%; background-color: rgba(255, 255, 255, 0.6); display: flex; justify-content: center; align-items: center; border: 1px solid rgba(92, 60, 23, 0.3); box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); } .filter-dropdown { position: absolute; top: 10px; right: 10px; z-index: 5; } .filter-button { padding: 5px 10px; background-color: rgba(255, 255, 255, 0.6); border: 1px solid rgba(92, 60, 23, 0.3); border-radius: 5px; cursor: pointer; display: flex; align-items: center; font-size: 0.8rem; color: #3b2506; transition: all 0.3s ease; } .filter-button:hover { background-color: rgba(92, 60, 23, 0.1); } .filter-icon { margin-right: 5px; width: 12px; height: 12px; background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" fill="%233b2506"/></svg>'); background-repeat: no-repeat; background-size: contain; } .filter-options { position: absolute; top: 100%; right: 0; background-color: rgba(255, 255, 255, 0.9); border: 1px solid rgba(92, 60, 23, 0.3); border-radius: 5px; padding: 10px; min-width: 150px; display: none; box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); } .filter-options.active { display: block; animation: fadeIn 0.3s ease; } .filter-option { margin-bottom: 5px; display: flex; align-items: center; } .filter-option input { margin-right: 5px; } .filter-option label { font-size: 0.8rem; color: #3b2506; cursor: pointer; } .expander-icon { width: 18px; height: 18px; position: relative; transition: transform 0.3s ease; } .expander-icon::before, .expander-icon::after { content: ""; position: absolute; background-color: #3b2506; transition: all 0.3s ease; } .expander-icon::before { width: 100%; height: 2px; top: 50%; left: 0; transform: translateY(-50%); } .expander-icon::after { width: 2px; height: 100%; left: 50%; top: 0; transform: translateX(-50%); } .quest-header.active .expander-icon::after { transform: translateX(-50%) rotate(90deg); opacity: 0; } .quest-item .marker { position: absolute; top: 10px; right: 10px; width: 12px; height: 12px; border-radius: 50%; } .quest-item .marker.new { background-color: #e74c3c; animation: pulse 1s infinite; } .quest-item .marker.updated { background-color: #3498db; animation: pulse 1s infinite; } @keyframes quill-write { 0% { opacity: 0; transform: translate(-20px, -20px); } 100% { opacity: 1; transform: translate(0, 0); } } .quill-cursor { position: absolute; width: 30px; height: 30px; background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path d="M20,80 L30,30 L35,25 C40,20 50,20 55,25 L60,30 L70,80 Z" fill="none" stroke="%233b2506" stroke-width="2"/><path d="M30,30 L70,80" stroke="%233b2506" stroke-width="1"/><path d="M30,75 L25,85 L35,80 Z" fill="%233b2506"/></svg>'); background-repeat: no-repeat; background-size: contain; pointer-events: none; z-index: 1000; opacity: 0; } .ink-drop { position: absolute; width: 20px; height: 20px; background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path d="M50,20 C30,20 20,60 30,80 C40,100 60,100 70,80 C80,60 70,20 50,20 Z" fill="%231a0f00" opacity="0.15"/></svg>'); background-repeat: no-repeat; background-size: contain; pointer-events: none; z-index: 5; opacity: 0; transform: scale(0); } @keyframes dropInk { 0% { transform: scale(0); opacity: 0; } 50% { transform: scale(1.2); opacity: 0.8; } 100% { transform: scale(1); opacity: 0.2; } } .quest-rewards-items { display: flex; justify-content: flex-start; margin-top: 10px; flex-wrap: wrap; gap: 10px; } .reward-item { width: 40px; height: 40px; background-color: rgba(255, 255, 255, 0.3); border: 1px solid rgba(92, 60, 23, 0.5); border-radius: 5px; display: flex; justify-content: center; align-items: center; position: relative; cursor: pointer; transition: all 0.3s ease; } .reward-item:hover { transform: scale(1.1); box-shadow: 0 0 10px rgba(218, 165, 32, 0.5); } .reward-tooltip { position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); background-color: rgba(58, 38, 14, 0.9); color: #fff; padding: 5px 8px; border-radius: 5px; font-size: 0.7rem; white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity 0.3s ease; z-index: 100; } .reward-item:hover .reward-tooltip { opacity: 1; } @media (max-width: 700px) { #quest-tracker { width: 95%; padding: 20px; } h1 { font-size: 1.8rem; } .compass { width: 50px; height: 50px; top: 10px; right: 10px; } .quest-header { padding: 10px; } .quest-title { font-size: 0.95rem; } .quest-type { font-size: 0.7rem; padding: 2px 6px; margin-right: 8px; } .quest-details { padding: 10px; font-size: 0.85rem; } .tab-option { padding: 6px 10px; font-size: 0.9rem; } .helper-icon span { font-size: 0.65rem; } .icon-img { width: 30px; height: 30px; } .quest-map { height: 180px; } } </style> </head> <body> <div id="quest-tracker"> <div class="compass"></div> <h1>Adventures of Eldoria</h1> <div class="progress-container"> <div class="progress-label"> <span>Journey Progress</span> <span id="progress-percentage">0%</span> </div> <div class="progress-bar"> <div class="progress-fill" id="progress-fill"></div> </div> </div> <div class="tab-switcher"> <div class="tab-option active" data-tab="active-quests">Active Quests</div> <div class="tab-option" data-tab="completed-quests">Completed</div> <div class="tab-option" data-tab="quest-map">Map</div> </div> <div class="tab-content active" id="active-quests"> <div class="filter-dropdown"> <div class="filter-button"> <div class="filter-icon"></div> <span>Filter</span> </div> <div class="filter-options"> <div class="filter-option"> <input type="checkbox" id="filter-main" checked> <label for="filter-main">Main Quests</label> </div> <div class="filter-option"> <input type="checkbox" id="filter-side" checked> <label for="filter-side">Side Quests</label> </div> <div class="filter-option"> <input type="checkbox" id="filter-guild" checked> <label for="filter-guild">Guild Quests</label> </div> <div class="filter-option"> <input type="checkbox" id="filter-exploration" checked> <label for="filter-exploration">Exploration</label> </div> </div> </div> <div class="quest-list"> <div class="quest-item" data-type="main-quest"> <div class="quest-header"> <div class="quest-title"> <div class="quest-type main-quest">Main</div> <span>The Crown of Eldoria</span> </div> <div class="expander-icon"></div> </div> <div class="quest-content"> <div class="quest-details"> <p>Recover the lost Crown of Eldoria from the depths of the Ancient Catacombs to restore power to the rightful heir of the kingdom.</p> <div class="quest-location"> <div class="location-icon"></div> <span>Ancient Catacombs, Duskwood Depths</span> </div> <div class="quest-rewards"> <div class="reward-icon"></div> <span>2500 gold, Royal Seal of Eldoria</span> </div> <ul class="objectives"> <li class="objective-item"> <div class="objective-checkbox"></div> <span class="objective-text">Speak with the Court Historian in Gildhaven</span> </li> <li class="objective-item"> <div class="objective-checkbox"></div> <span class="objective-text">Find the entrance to the Ancient Catacombs</span> </li> <li class="objective-item"> <div class="objective-checkbox"></div> <span class="objective-text">Defeat the Catacomb Guardian</span> </li> <li class="objective-item"> <div class="objective-checkbox"></div> <span class="objective-text">Retrieve the Crown of Eldoria</span> </li> <li class="objective-item"> <div class="objective-checkbox"></div> <span class="objective-text">Return to the Royal Palace</span> </li> </ul> </div> </div> </div> <div class="quest-item" data-type="side-quest"> <div class="quest-header"> <div class="quest-title"> <div class="quest-type side-quest">Side</div> <span>Mysterious Brew</span> </div> <div class="expander-icon"></div> </div> <div class="quest-content"> <div class="quest-details"> <p>The local alchemist needs rare ingredients for a mysterious brew that could cure the plague affecting Shadowbrook village.</p> <div class="quest-location"> <div class="location-icon"></div> <span>Misty Woods, Elwynn Forest</span> </div> <div class="quest-rewards"> <div class="reward-icon"></div> <span>800 gold, Recipe: Elixir of Clarity</span> </div> <ul class="objectives"> <li class="objective-item completed"> <div class="objective-checkbox checked"></div> <span class="objective-text">Collect 5 Luminous Mushrooms</span> </li> <li class="objective-item"> <div class="objective-checkbox"></div> <span class="objective-text">Find the rare Moonblossom flower</span> </li> <li class="objective-item"> <div class="objective-checkbox"></div> <span class="objective-text">Gather water from the Whispering Spring</span> </li> <li class="objective-item"> <div class="objective-checkbox"></div> <span class="objective-text">Return to Alchemist Thorne</span> </li> </ul> <div class="quest-rewards-items"> <div class="reward-item"> <img src="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 50 50'><path
<html> <head> <title>NightStalker FPS Pause Menu</title> <style> @import url('https://fonts.googleapis.com/css2?family=Audiowide&family=Rajdhani:wght@500;700&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Rajdhani', sans-serif; user-select: none; } :root { --neon-blue: #00f3ff; --neon-pink: #ff00e5; --neon-purple: #9d00ff; --background: #0f0f15; --menu-bg: rgba(25, 25, 35, 0.85); --text-primary: #ffffff; --text-secondary: #a0a0a0; } body { width: 100%; height: 100vh; background: var(--background); color: var(--text-primary); display: flex; justify-content: center; align-items: center; overflow: hidden; background-image: radial-gradient(circle at 20% 35%, rgba(29, 78, 216, 0.15) 0%, transparent 50%), radial-gradient(circle at 80% 65%, rgba(217, 70, 239, 0.15) 0%, transparent 50%); } .container { position: relative; width: 700px; height: 700px; display: flex; justify-content: center; align-items: center; overflow: hidden; } .game-background { position: absolute; width: 100%; height: 100%; background-image: url('https://images.unsplash.com/photo-1550745165-9bc0b252726f?ixlib=rb-4.0.3&auto=format&fit=crop&w=1050&q=80'); background-size: cover; background-position: center; filter: brightness(0.4) contrast(1.2) saturate(1.2); z-index: -1; } .pause-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(15, 15, 23, 0.7); backdrop-filter: blur(5px); z-index: 0; } .pause-menu { position: relative; width: 85%; max-width: 500px; background: var(--menu-bg); border-radius: 10px; box-shadow: 0 0 30px rgba(0, 0, 0, 0.5), 0 0 15px var(--neon-blue), inset 0 0 10px rgba(0, 0, 0, 0.8); padding: 2rem; z-index: 1; overflow: hidden; display: flex; flex-direction: column; gap: 1.5rem; } .menu-grid { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-image: linear-gradient(to right, rgba(255, 255, 255, 0.03) 1px, transparent 1px), linear-gradient(to bottom, rgba(255, 255, 255, 0.03) 1px, transparent 1px); background-size: 20px 20px; z-index: -1; } .menu-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; padding-bottom: 1rem; border-bottom: 1px solid rgba(255, 255, 255, 0.1); } .game-title { font-family: 'Audiowide', cursive; font-size: 2.2rem; color: var(--text-primary); text-shadow: 0 0 10px var(--neon-blue), 0 0 20px rgba(0, 243, 255, 0.5); letter-spacing: 2px; } .mission-info { text-align: right; font-size: 0.9rem; } .mission-label { color: var(--text-secondary); font-size: 0.8rem; letter-spacing: 1px; } .mission-name { color: var(--neon-blue); font-weight: 700; font-size: 1rem; } .player-stats { background: rgba(0, 0, 0, 0.3); border-radius: 8px; padding: 1rem; display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-bottom: 1rem; border: 1px solid rgba(255, 255, 255, 0.05); } .stat-item { display: flex; flex-direction: column; align-items: center; } .stat-value { font-size: 1.8rem; font-weight: 700; color: var(--neon-pink); text-shadow: 0 0 10px rgba(255, 0, 229, 0.5); } .stat-label { color: var(--text-secondary); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 1px; } .menu-options { display: flex; flex-direction: column; gap: 0.7rem; } .menu-button { position: relative; background: rgba(0, 0, 0, 0.3); color: var(--text-primary); border: none; padding: 0.9rem 1.2rem; font-size: 1.1rem; font-weight: 700; text-transform: uppercase; letter-spacing: 1px; cursor: pointer; transition: all 0.3s ease; border-radius: 5px; overflow: hidden; display: flex; justify-content: space-between; align-items: center; text-align: left; } .menu-button::before { content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; background: var(--neon-blue); transform: scaleY(0); transform-origin: bottom; transition: transform 0.3s ease; } .menu-button:hover::before, .menu-button:focus::before { transform: scaleY(1); } .menu-button:hover, .menu-button:focus { background: rgba(0, 243, 255, 0.1); outline: none; } .menu-button:active { transform: scale(0.98); } .menu-button.resume { background: linear-gradient(90deg, rgba(0, 243, 255, 0.2), transparent); } .menu-button.resume:hover { background: linear-gradient(90deg, rgba(0, 243, 255, 0.3), transparent); } .menu-button.quit { background: linear-gradient(90deg, rgba(255, 0, 0, 0.2), transparent); } .menu-button.quit:hover { background: linear-gradient(90deg, rgba(255, 0, 0, 0.3), transparent); } .button-icon { width: 24px; height: 24px; display: flex; justify-content: center; align-items: center; } .shortcut { font-size: 0.7rem; background: rgba(255, 255, 255, 0.1); padding: 0.2rem 0.5rem; border-radius: 3px; color: var(--text-secondary); } .menu-footer { margin-top: 1rem; display: flex; justify-content: center; gap: 0.5rem; color: var(--text-secondary); font-size: 0.8rem; } .server-status { display: flex; align-items: center; gap: 0.5rem; } .status-dot { width: 8px; height: 8px; background: var(--neon-pink); border-radius: 50%; box-shadow: 0 0 5px var(--neon-pink); animation: pulse 2s infinite; } .ping-value { color: var(--neon-blue); font-weight: 700; } .notification { position: absolute; top: 10px; right: 10px; background: rgba(0, 0, 0, 0.7); border-left: 3px solid var(--neon-purple); padding: 0.5rem 1rem; border-radius: 3px; font-size: 0.8rem; display: flex; align-items: center; gap: 0.5rem; transform: translateX(120%); transition: transform 0.3s ease; } .notification.show { transform: translateX(0); } .notification-icon { color: var(--neon-purple); } @keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.5; } 100% { opacity: 1; } } @keyframes scanline { 0% { transform: translateY(-100%); } 100% { transform: translateY(100%); } } .scanline { position: absolute; top: 0; left: 0; width: 100%; height: 2px; background: linear-gradient(to right, transparent, var(--neon-blue), transparent); opacity: 0.3; z-index: 2; animation: scanline 3s linear infinite; } /* Responsive adjustments */ @media (max-width: 500px) { .pause-menu { width: 95%; padding: 1.5rem; } .game-title { font-size: 1.8rem; } .stat-value { font-size: 1.5rem; } .menu-button { padding: 0.7rem 1rem; font-size: 1rem; } .player-stats { padding: 0.8rem; gap: 0.5rem; } } </style> </head> <body> <div class="container"> <div class="game-background"></div> <div class="pause-overlay"></div> <div class="scanline"></div> <div class="pause-menu"> <div class="menu-grid"></div> <div class="menu-header"> <div class="game-title">NIGHTSTALKER</div> <div class="mission-info"> <div class="mission-label">CURRENT MISSION</div> <div class="mission-name">NEURAL INFILTRATION</div> </div> </div> <div class="player-stats"> <div class="stat-item"> <div class="stat-value">24</div> <div class="stat-label">Eliminations</div> </div> <div class="stat-item"> <div class="stat-value">18</div> <div class="stat-label">Match Score</div> </div> <div class="stat-item"> <div class="stat-value">3.2</div> <div class="stat-label">K/D Ratio</div> </div> </div> <div class="menu-options"> <button class="menu-button resume" id="resumeBtn"> <span>Resume Game</span> <span class="shortcut">ESC</span> </button> <button class="menu-button" id="loadoutBtn"> <span>Customize Loadout</span> <span class="button-icon"> <svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" /> </svg> </span> </button> <button class="menu-button" id="settingsBtn"> <span>Game Settings</span> <span class="button-icon"> <svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /> </svg> </span> </button> <button class="menu-button" id="squadBtn"> <span>Squad Management</span> <span class="button-icon"> <svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" /> </svg> </span> </button> <button class="menu-button quit" id="quitBtn"> <span>Quit Match</span> <span class="button-icon"> <svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" /> </svg> </span> </button> </div> <div class="menu-footer"> <div class="server-status"> <div class="status-dot"></div> <span>SERVER: EU-WEST</span> </div> <span>|</span> <div class="ping">PING: <span class="ping-value">32ms</span></div> </div> </div> <div class="notification" id="notification"> <span class="notification-icon"> <svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /> </svg> </span> <span id="notificationText">Action completed successfully!</span> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const buttons = document.querySelectorAll('.menu-button'); const notification = document.getElementById('notification'); const notificationText = document.getElementById('notificationText'); // Random ping value fluctuation const pingValue = document.querySelector('.ping-value'); setInterval(() => { const basePing = 32; const randomVariation = Math.floor(Math.random() * 8) - 3; pingValue.textContent = `${basePing + randomVariation}ms`; }, 2000); // Add hover audio feedback effect buttons.forEach(button => { button.addEventListener('mouseenter', () => { playSound('hover'); }); button.addEventListener('click', (e) => { e.preventDefault(); playSound('click'); // Show appropriate notification based on button clicked let message = ''; if (button.id === 'resumeBtn') { message = 'Returning to combat...'; } else if (button.id === 'loadoutBtn') { message = 'Loadout customization accessed'; } else if (button.id === 'settingsBtn') { message = 'Settings panel opened'; } else if (button.id === 'squadBtn') { message = 'Squad management accessed'; } else if (button.id === 'quitBtn') { message = 'Warning: Quitting match will count as a loss'; } showNotification(message); // Add button press animation button.classList.add('clicked'); setTimeout(() => { button.classList.remove('clicked'); }, 200); }); }); // ESC key to resume document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { playSound('click'); showNotification('Returning to combat...'); } }); function showNotification(text) { notificationText.textContent = text; notification.classList.add('show'); setTimeout(() => { notification.classList.remove('show'); }, 3000); } function playSound(type) { // In a real implementation, this would play actual sounds // For this demo, we're just simulating the sound effect console.log(`Playing ${type} sound`); } // Add dynamic scanline effect const scanlines = document.querySelectorAll('.scanline'); scanlines.forEach(scanline => { setInterval(() => { scanline.style.top = '0'; scanline.style.opacity = '0.3'; // Reset the animation scanline.style.animation = 'none'; setTimeout(() => { scanline.style.animation = 'scanline 3s linear infinite'; }, 10); }, 3000); }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>E-Sports Leaderboard</title> <style> @import url('https://fonts.googleapis.com/css2?family=Rajdhani:wght@400;500;600;700&family=Orbitron:wght@400;500;600;700;800&display=swap'); :root { --primary-gradient: linear-gradient(135deg, #00c6ff, #0072ff); --secondary-gradient: linear-gradient(135deg, #fc466b, #3f5efb); --highlight-gradient: linear-gradient(135deg, #ffdb4d, #ff9d00); --bg-dark: #0d1117; --bg-card: #161b22; --text-primary: #f0f6fc; --text-secondary: #8b949e; --accent-pulse: #ff4d4d; --accent-highlight: #2eff9e; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Rajdhani', sans-serif; } body { background-color: var(--bg-dark); color: var(--text-primary); display: flex; justify-content: center; align-items: center; min-height: 100vh; overflow-x: hidden; } .leaderboard-container { width: 100%; max-width: 680px; height: 680px; padding: 20px; border-radius: 12px; background-color: var(--bg-card); position: relative; overflow: hidden; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); } .leaderboard-container::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 5px; background: var(--primary-gradient); animation: gradientShift 10s infinite alternate; } @keyframes gradientShift { 0% { background: var(--primary-gradient); } 50% { background: var(--secondary-gradient); } 100% { background: var(--highlight-gradient); } } .header { position: relative; padding: 20px 0; text-align: center; margin-bottom: 25px; z-index: 1; } .title { font-family: 'Orbitron', sans-serif; font-size: 2.2rem; font-weight: 700; letter-spacing: 1px; margin-bottom: 10px; text-transform: uppercase; background: linear-gradient(135deg, #00c6ff, #0072ff); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; filter: drop-shadow(0 2px 4px rgba(0, 198, 255, 0.3)); animation: titlePulse 3s infinite alternate; } @keyframes titlePulse { 0% { filter: drop-shadow(0 2px 4px rgba(0, 198, 255, 0.3)); } 100% { filter: drop-shadow(0 2px 10px rgba(0, 198, 255, 0.6)); } } .subtitle { font-size: 1.1rem; color: var(--text-secondary); margin-bottom: 15px; font-weight: 500; } .tournament-info { display: flex; justify-content: space-between; align-items: center; padding: 8px 15px; background: rgba(255, 255, 255, 0.05); border-radius: 6px; margin-bottom: 10px; } .tournament-name { display: flex; align-items: center; font-family: 'Orbitron', sans-serif; font-weight: 600; } .tournament-name i { margin-right: 8px; color: var(--accent-highlight); } .prize-pool { background: var(--highlight-gradient); padding: 5px 12px; border-radius: 20px; font-weight: 600; color: #000; font-size: 0.9rem; } .leaderboard-tabs { display: flex; justify-content: space-between; margin-bottom: 15px; } .tab { flex: 1; padding: 10px; text-align: center; background: rgba(255, 255, 255, 0.05); cursor: pointer; transition: all 0.3s ease; font-weight: 600; border-bottom: 2px solid transparent; } .tab:first-child { border-top-left-radius: 6px; border-bottom-left-radius: 6px; } .tab:last-child { border-top-right-radius: 6px; border-bottom-right-radius: 6px; } .tab.active { background: rgba(255, 255, 255, 0.1); border-bottom: 2px solid var(--accent-highlight); } .tab:hover:not(.active) { background: rgba(255, 255, 255, 0.08); } .leaderboard-list { height: 400px; overflow-y: auto; padding-right: 5px; } .leaderboard-list::-webkit-scrollbar { width: 6px; } .leaderboard-list::-webkit-scrollbar-track { background: rgba(255, 255, 255, 0.05); border-radius: 10px; } .leaderboard-list::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.2); border-radius: 10px; } .leaderboard-list::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.3); } .player-card { display: flex; align-items: center; padding: 12px 15px; margin-bottom: 10px; background: rgba(255, 255, 255, 0.03); border-radius: 8px; transition: all 0.3s ease; position: relative; overflow: hidden; } .player-card::before { content: ''; position: absolute; top: 0; left: 0; height: 100%; width: 3px; background: var(--primary-gradient); opacity: 0.7; } .player-card:hover { transform: translateY(-3px); box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); background: rgba(255, 255, 255, 0.06); } .rank { width: 40px; height: 40px; display: flex; justify-content: center; align-items: center; font-family: 'Orbitron', sans-serif; font-weight: 700; font-size: 1.2rem; border-radius: 50%; margin-right: 15px; background: rgba(255, 255, 255, 0.05); position: relative; } .rank-1, .rank-2, .rank-3 { color: #000; } .rank-1 { background: linear-gradient(135deg, #FFD700, #FFA500); } .rank-2 { background: linear-gradient(135deg, #C0C0C0, #A9A9A9); } .rank-3 { background: linear-gradient(135deg, #CD7F32, #8B4513); } .player-avatar { width: 45px; height: 45px; border-radius: 50%; margin-right: 15px; object-fit: cover; border: 2px solid transparent; background: var(--primary-gradient); padding: 2px; } .top-player .player-avatar { background: var(--highlight-gradient); } .player-info { flex: 1; } .player-name { font-weight: 600; font-size: 1.1rem; margin-bottom: 3px; display: flex; align-items: center; } .team { font-size: 0.85rem; color: var(--text-secondary); display: flex; align-items: center; } .team i { margin-right: 5px; font-size: 0.8rem; } .player-stats { display: flex; justify-content: space-between; align-items: center; width: 180px; } .stat { text-align: center; } .stat-value { font-weight: 600; font-size: 1.1rem; font-family: 'Orbitron', sans-serif; } .stat-label { font-size: 0.7rem; color: var(--text-secondary); text-transform: uppercase; } .change-indicator { display: flex; align-items: center; margin-left: 15px; font-weight: 600; font-size: 0.9rem; } .change-up { color: var(--accent-highlight); } .change-down { color: var(--accent-pulse); } .change-none { color: var(--text-secondary); } .top-player { background: rgba(255, 255, 255, 0.07); border: 1px solid rgba(46, 255, 158, 0.2); } .top-player::before { background: var(--highlight-gradient); } .rising-player { position: relative; } .rising-player::after { content: '🔥 RISING STAR'; position: absolute; top: 10px; right: 10px; font-size: 0.7rem; background: rgba(255, 77, 77, 0.2); color: var(--accent-pulse); padding: 3px 6px; border-radius: 4px; font-weight: 600; } .player-card.animating { animation: rankChange 1s ease; } @keyframes rankChange { 0% { transform: translateX(-10px); opacity: 0.5; } 50% { transform: translateX(10px); } 100% { transform: translateX(0); opacity: 1; } } .pro-badge { background: var(--secondary-gradient); color: white; font-size: 0.7rem; padding: 2px 6px; border-radius: 4px; margin-left: 8px; font-weight: 600; } .update-info { text-align: center; margin-top: 15px; font-size: 0.8rem; color: var(--text-secondary); } .spotlight { position: absolute; width: 150px; height: 150px; background: radial-gradient(circle, rgba(46, 255, 158, 0.15) 0%, rgba(46, 255, 158, 0) 70%); border-radius: 50%; pointer-events: none; z-index: 0; opacity: 0; transition: opacity 0.3s ease; } .player-card:hover .spotlight { opacity: 1; } @media (max-width: 600px) { .title { font-size: 1.8rem; } .player-stats { width: 120px; } .stat-value { font-size: 0.9rem; } .player-avatar { width: 35px; height: 35px; } .rank { width: 30px; height: 30px; font-size: 1rem; } .pro-badge { display: none; } .rising-player::after { display: none; } } /* Game-specific styling for selected tab */ .valorant-theme .player-card::before { background: linear-gradient(135deg, #ff4655, #962e38); } .league-theme .player-card::before { background: linear-gradient(135deg, #0bc4e2, #0a617d); } .fortnite-theme .player-card::before { background: linear-gradient(135deg, #9d4dbb, #41328a); } </style> </head> <body> <div class="leaderboard-container"> <div class="header"> <h1 class="title">Pro Circuit Leaderboard</h1> <p class="subtitle">Track the top players in competitive esports</p> <div class="tournament-info"> <div class="tournament-name"> <i class="fas fa-trophy"></i> World Championship Series - Season XII </div> <div class="prize-pool">$2.5M Prize Pool</div> </div> </div> <div class="leaderboard-tabs"> <div class="tab active" data-game="valorant">VALORANT</div> <div class="tab" data-game="league">LEAGUE OF LEGENDS</div> <div class="tab" data-game="fortnite">FORTNITE</div> </div> <div class="leaderboard-list valorant-theme"> <!-- Players will be added dynamically via JS --> </div> <p class="update-info">Rankings updated: <span id="last-updated">2 hours ago</span> • Live updates every 60 minutes</p> </div> <script src="https://kit.fontawesome.com/3b45a31e01.js" crossorigin="anonymous"></script> <script> document.addEventListener('DOMContentLoaded', function() { // Player data for different games const gameData = { valorant: [ { id: 1, rank: 1, name: "TenZ", team: "Sentinels", avatar: "https://i.imgur.com/gJVxgG7.jpg", kd: 1.85, winRate: 68, tournWins: 7, change: "up", isPro: true, isRising: false }, { id: 2, rank: 2, name: "Shroud", team: "T1", avatar: "https://i.imgur.com/5VoQorE.jpg", kd: 1.77, winRate: 65, tournWins: 5, change: "up", isPro: true, isRising: false }, { id: 3, rank: 3, name: "ScreaM", team: "Team Liquid", avatar: "https://i.imgur.com/jNssMRR.jpg", kd: 1.72, winRate: 62, tournWins: 4, change: "down", isPro: true, isRising: false }, { id: 4, rank: 4, name: "s1mple", team: "Natus Vincere", avatar: "https://i.imgur.com/qWuKirG.jpg", kd: 1.69, winRate: 58, tournWins: 3, change: "none", isPro: true, isRising: false }, { id: 5, rank: 5, name: "Aceu", team: "NRG", avatar: "https://i.imgur.com/Ei1VxWH.jpg", kd: 1.65, winRate: 56, tournWins: 3, change: "up", isPro: true, isRising: false }, { id: 6, rank: 6, name: "Hiko", team: "100 Thieves", avatar: "https://i.imgur.com/XmvZY3q.jpg", kd: 1.61, winRate: 54, tournWins: 2, change: "down", isPro: true, isRising: false }, { id: 7, rank: 7, name: "Asuna", team: "100 Thieves", avatar: "https://i.imgur.com/EIPbfOm.jpg", kd: 1.58, winRate: 52, tournWins: 2, change: "up", isPro: true, isRising: false }, { id: 8, rank: 8, name: "Sinatraa", team: "Sentinels", avatar: "https://i.imgur.com/f8Ugd7M.jpg", kd: 1.56, winRate: 51, tournWins: 2, change: "down", isPro: true, isRising: false }, { id: 9, rank: 9, name: "Ninja", team: "Cloud9", avatar: "https://i.imgur.com/LUdaGZY.jpg", kd: 1.52, winRate: 49, tournWins: 1, change: "up", isPro: true, isRising: false }, { id: 10, rank: 10, name: "Subroza", team: "TSM", avatar: "https://i.imgur.com/4QYq1JB.jpg", kd: 1.49, winRate: 47, tournWins: 1, change: "none", isPro: true, isRising: true } ], league: [ { id: 1, rank: 1, name: "Faker", team: "T1", avatar: "https://i.imgur.com/qFSS1JG.jpg", kd: 4.2, winRate: 73, tournWins: 12, change: "none", isPro: true, isRising: false }, { id: 2, rank: 2, name: "Uzi", team: "RNG", avatar: "https://i.imgur.com/85MgQxk.jpg", kd: 3.9, winRate: 68, tournWins: 8, change: "up", isPro: true, isRising: false }, { id: 3, rank: 3, name: "Caps", team: "G2 Esports", avatar: "https://i.imgur.com/MFjYkDu.jpg", kd: 3.7, winRate: 65, tournWins: 7, change: "down", isPro: true, isRising: false }, { id: 4, rank: 4, name: "Bjergsen", team: "TSM", avatar: "https://i.imgur.com/Xp0uRL2.jpg", kd: 3.5, winRate: 62, tournWins: 6, change: "up", isPro: true, isRising: false }, { id: 5, rank: 5, name: "Jankos", team: "G2 Esports", avatar: "https://i.imgur.com/9r9ywGK.jpg", kd: 3.3, winRate: 60, tournWins: 5, change: "none", isPro: true, isRising: false }, { id: 6, rank: 6, name: "Perkz", team: "Cloud9", avatar: "https://i.imgur.com/4kNgCyL.jpg", kd: 3.1, winRate: 58, tournWins: 5, change: "up", isPro: true, isRising: false }, { id: 7, rank: 7, name: "Rekkles", team: "Fnatic", avatar: "https://i.imgur.com/TkBNDqI.jpg", kd: 3.0, winRate: 55, tournWins: 4, change: "down", isPro: true, isRising: false }, { id: 8, rank: 8, name: "Doinb", team: "FPX", avatar: "https://i.imgur.com/c6oKPft.jpg", kd: 2.9, winRate: 54, tournWins: 4, change: "up", isPro: true, isRising: true }, { id: 9, rank: 9, name: "TheShy", team: "IG", avatar: "https://i.imgur.com/A86KTqv.jpg", kd: 2.8, winRate: 52, tournWins: 3, change: "down", isPro: true, isRising: false }, { id: 10, rank: 10, name: "Doublelift", team: "Team Liquid", avatar: "https://i.imgur.com/NHZDZF5.jpg", kd: 2.7, winRate: 50, tournWins: 3, change: "none", isPro: true, isRising: false } ], fortnite: [ { id: 1, rank: 1, name: "Bugha", team: "Sentinels", avatar: "https://i.imgur.com/yST8RKK.jpg", kd: 6.2, winRate: 24, tournWins: 9, change: "up", isPro: true, isRising: false }, { id: 2, rank: 2, name: "Mongraal", team: "FaZe Clan", avatar: "https://i.imgur.com/Vx0Htx3.jpg", kd: 5.9, winRate: 22, tournWins: 7, change: "down", isPro: true, isRising: false }, { id: 3, rank: 3, name: "Benjyfishy", team: "NRG", avatar: "https://i.imgur.com/2BCBKy3.jpg", kd: 5.7, winRate: 21, tournWins: 6, change: "up", isPro: true, isRising: false }, { id: 4, rank: 4, name: "Tfue", team: "Unaffiliated", avatar: "https://i.imgur.com/1QkFmQb.jpg", kd: 5.5, winRate: 20, tournWins: 5, change: "down", isPro: true, isRising: false }, { id: 5, rank: 5, name: "MrSavage", team: "100 Thieves", avatar: "https://i.imgur.com/CrxC0kQ.jpg", kd: 5.3, winRate: 19, tournWins: 5, change: "up", isPro: true, isRising: false }, { id: 6, rank: 6, name: "Clix", team: "NRG", avatar: "https://i.imgur.com/Yc8lzNZ.jpg", kd: 5.1, winRate: 18, tournWins: 4, change: "up", isPro: true, isRising: true }, { id: 7, rank: 7, name: "Zayt", team: "NRG", avatar: "https://i.imgur.com/eFuKdPn.jpg", kd: 5.0, winRate: 17, tournWins: 4, change: "down", isPro: true, isRising: false }, { id: 8, rank: 8, name: "Arkhram", team: "100 Thieves", avatar: "https://i.imgur.com/dF2jJRd.jpg", kd: 4.8, winRate: 16, tournWins: 3, change: "up", isPro: true, isRising: false }, { id: 9, rank: 9, name: "Mitr0", team: "Team Liquid", avatar: "https://i.imgur.com/3qQEFTP.jpg", kd: 4.7, winRate: 15, tournWins: 3, change: "down", isPro: true, isRising: false }, { id: 10, rank: 10, name: "Th0masHD", team: "Guild Esports", avatar: "https://i.imgur.com/B2V7pBZ.jpg", kd: 4.5, winRate: 14, tournWins: 2, change: "up", isPro: true, isRising: true } ] }; // Current selected game let currentGame = 'valorant'; // Function to render the leaderboard function renderLeaderboard(game) { const leaderboardList = document.querySelector('.leaderboard-list'); leaderboardList.innerHTML = ''; // Update theme class leaderboardList.className = 'leaderboard-list'; leaderboardList.classList.add(`${game}-theme`); gameData[game].forEach(player => { const card = document.createElement('div'); card.className = `player-card ${player.rank <= 3 ? 'top-player' : ''} ${player.isRising ? 'rising-player' : ''}`; card.setAttribute('data-id', player.id); const rankClass = player.rank <= 3 ? `rank-${player.rank}` : ''; let changeIcon = ''; let changeClass = ''; if (player.change === 'up') { changeIcon = '<i class="fas fa-arrow-up"></i>'; changeClass = 'change-up'; } else if (player.change === 'down') { changeIcon = '<i class="fas fa-arrow-down"></i>'; changeClass = 'change-down'; } else { changeIcon = '<i class="fas fa-minus"></i>'; changeClass = 'change-none'; } card.innerHTML = ` <div class="spotlight"></div> <div class="rank ${rankClass}">${player.rank}</div> <img src="${player.avatar}" alt="${player.name}" class="player-avatar"> <div class="player-info"> <div class="player-name">${player.name} ${player.isPro ? '<span class="pro-badge">PRO</span>' : ''}</div> <div class="team"><i class="fas fa-users"></i> ${player.team}</div> </div> <div class="player-stats"> <div class="stat"> <div class="stat-value">${player.kd}</div> <div class="stat-label">K/D</div> </div> <div class="stat"> <div class="stat-value">${player.winRate}%</div> <div class="stat-label">WIN</div> </div> <div class="stat"> <div class="stat-value">${player.tournWins}</div> <div class="stat-label">TOURNS</div> </div> </div> <div class="change-indicator ${changeClass}"> ${changeIcon} </div> `; leaderboardList.appendChild(card); }); // Add spotlight effect for each player card document.querySelectorAll('.player-card').forEach(card => { const spotlight = card.querySelector('.spotlight'); card.addEventListener('mousemove', (e) => { const rect = card.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; spotlight.style.left = `${x - 75}px`; spotlight.style.top = `${y - 75}px`; }); }); } // Initial render renderLeaderboard(currentGame); // Tab switching document.querySelectorAll('.tab').forEach(tab => { tab.addEventListener('click', () => { document.querySelector('.tab.active').classList.remove('active'); tab.classList.add('active'); currentGame = tab.getAttribute('data-game'); renderLeaderboard(currentGame); }); }); // Periodic ranking animation (simulated live updates) function simulateRankChanges() { // Get two random players const players = [...gameData[currentGame]]; const player1Index = Math.floor(Math.random() * players.length); let player2Index; do { player2Index = Math.floor(Math.random() * players.length); } while (player2Index === player1Index); const player1 = players[player1Index]; const player2 = players[player2Index]; // Only swap if they're adjacent in ranking and not in top 3 if (Math.abs(player1.rank - player2.rank) === 1 && player1.rank > 3 && player2.rank > 3) { // Swap ranks const tempRank = player1.rank; player1.rank = player2.rank; player2.rank = tempRank; // Update change indicators if (player1.rank < player2.rank) { player1.change = 'up'; player2.change = 'down'; } else { player1.change = 'down'; player2.change = 'up'; } // Sort the array by rank gameData[currentGame].sort((a, b) => a.rank - b.rank); // Re-render leaderboard with animation renderLeaderboard(currentGame); // Add animation class to the affected players document.querySelectorAll(`.player-card[data-id="${player1.id}"], .player-card[data-id="${player2.id}"]`).forEach(card => { card.classList.add('animating'); setTimeout(() => { card.classList.remove('animating'); }, 1000); }); // Update last updated time document.getElementById('last-updated').textContent = 'just now'; } } // Simulate rank changes every 10-20 seconds setInterval(() => { if (Math.random() > 0.5) { // 50% chance to trigger simulateRankChanges(); } }, Math.floor(Math.random() * 10000) + 10000); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>RPG Skill Tree Interface</title> <style> :root { --primary-color: #2c3e50; --secondary-color: #3498db; --accent-color: #e74c3c; --available-color: #2ecc71; --locked-color: #7f8c8d; --tree-background: radial-gradient(circle, rgba(15, 32, 39, 0.95) 0%, rgba(32, 58, 67, 0.95) 50%, rgba(44, 83, 100, 0.95) 100%); --skill-shadow: 0 0 15px rgba(52, 152, 219, 0.5); --skill-glow: 0 0 25px rgba(46, 204, 113, 0.7); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: var(--primary-color); display: flex; justify-content: center; align-items: center; height: 100vh; color: white; overflow: hidden; } .container { width: 700px; height: 700px; position: relative; background: var(--tree-background); border-radius: 50%; box-shadow: 0 0 50px rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; overflow: hidden; } .center-circle { width: 100px; height: 100px; background: linear-gradient(135deg, #e67e22, #d35400); border-radius: 50%; display: flex; justify-content: center; align-items: center; box-shadow: 0 0 30px rgba(230, 126, 34, 0.6); z-index: 10; position: relative; cursor: pointer; transition: all 0.3s ease; } .center-circle:hover { transform: scale(1.1); } .center-circle img { width: 60px; height: 60px; object-fit: contain; filter: drop-shadow(0 0 5px rgba(255, 255, 255, 0.7)); } .skill-tree { position: absolute; width: 100%; height: 100%; top: 0; left: 0; } .skill-node { position: absolute; width: 70px; height: 70px; border-radius: 50%; background: rgba(30, 45, 60, 0.8); border: 3px solid var(--locked-color); display: flex; justify-content: center; align-items: center; cursor: pointer; transition: all 0.3s ease; box-shadow: var(--skill-shadow); transform: scale(0); opacity: 0; z-index: 5; } .skill-node.expanding { animation: nodeExpand 0.7s cubic-bezier(0.17, 0.89, 0.32, 1.49) forwards; } .skill-node.available { border-color: var(--available-color); animation: pulse 2s infinite; box-shadow: var(--skill-glow); } .skill-node.unlocked { border-color: var(--secondary-color); background: rgba(52, 152, 219, 0.3); } .skill-node.selected { border-color: var(--accent-color); background: rgba(231, 76, 60, 0.3); transform: scale(1.15); } .skill-node:hover:not(.locked) { transform: scale(1.2); box-shadow: 0 0 20px rgba(52, 152, 219, 0.8); } .skill-node.locked { cursor: not-allowed; } .skill-node img { width: 35px; height: 35px; filter: grayscale(100%) brightness(70%); transition: all 0.3s ease; } .skill-node.available img, .skill-node.unlocked img { filter: grayscale(0%) brightness(100%); } .connector { position: absolute; background-color: var(--locked-color); height: 4px; transform-origin: 0 0; opacity: 0; z-index: 2; } .connector.available { background-color: var(--available-color); box-shadow: 0 0 10px rgba(46, 204, 113, 0.5); } .connector.unlocked { background-color: var(--secondary-color); box-shadow: 0 0 10px rgba(52, 152, 219, 0.8); } .skill-tooltip { position: absolute; background: rgba(15, 32, 39, 0.95); border: 2px solid var(--secondary-color); border-radius: 10px; padding: 15px; width: 280px; pointer-events: none; opacity: 0; transform: translateY(10px); transition: all 0.3s ease; z-index: 20; box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); } .skill-tooltip h3 { font-size: 1.2rem; margin-bottom: 5px; color: var(--secondary-color); } .skill-tooltip p { font-size: 0.9rem; margin-bottom: 10px; line-height: 1.4; } .skill-tooltip .skill-level { display: flex; align-items: center; gap: 5px; margin-top: 10px; } .skill-tooltip .skill-level-dots { display: flex; gap: 3px; } .skill-tooltip .dot { width: 12px; height: 12px; border-radius: 50%; background-color: var(--locked-color); } .skill-tooltip .dot.active { background-color: var(--available-color); } .skill-point-info { position: absolute; top: 20px; right: 20px; background: rgba(15, 32, 39, 0.8); border: 2px solid var(--secondary-color); border-radius: 10px; padding: 10px 15px; z-index: 20; display: flex; align-items: center; gap: 10px; } .skill-point-info img { width: 24px; height: 24px; } .skill-point-info span { font-size: 1.2rem; font-weight: bold; } .class-info { position: absolute; top: 20px; left: 20px; background: rgba(15, 32, 39, 0.8); border: 2px solid var(--secondary-color); border-radius: 10px; padding: 10px 15px; z-index: 20; } .class-info h2 { margin: 0; font-size: 1.2rem; color: var(--secondary-color); } .class-info p { margin: 5px 0 0; font-size: 0.9rem; } .particle { position: absolute; width: 5px; height: 5px; background: var(--secondary-color); border-radius: 50%; pointer-events: none; opacity: 0; z-index: 1; } .reset-button { position: absolute; bottom: 20px; right: 20px; background: rgba(231, 76, 60, 0.2); border: 2px solid var(--accent-color); color: white; border-radius: 10px; padding: 10px 15px; cursor: pointer; transition: all 0.3s ease; z-index: 20; } .reset-button:hover { background: rgba(231, 76, 60, 0.4); transform: scale(1.05); } @keyframes nodeExpand { 0% { transform: scale(0); opacity: 0; } 60% { transform: scale(1.2); } 100% { transform: scale(1); opacity: 1; } } @keyframes connectorGrow { 0% { opacity: 0; transform: scaleX(0); } 100% { opacity: 1; transform: scaleX(1); } } @keyframes pulse { 0% { box-shadow: 0 0 10px rgba(46, 204, 113, 0.7); } 50% { box-shadow: 0 0 25px rgba(46, 204, 113, 0.9); } 100% { box-shadow: 0 0 10px rgba(46, 204, 113, 0.7); } } @keyframes particleMove { 0% { transform: translate(0, 0); opacity: 1; } 100% { transform: translate(var(--tx), var(--ty)); opacity: 0; } } .mobile-warning { display: none; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.8); color: white; flex-direction: column; justify-content: center; align-items: center; text-align: center; padding: 20px; z-index: 100; } .mobile-warning h2 { margin-bottom: 20px; color: var(--accent-color); } @media (max-width: 700px) { .container { transform: scale(0.8); } } @media (max-width: 500px) { .mobile-warning { display: flex; } } </style> </head> <body> <div class="container"> <div class="class-info"> <h2>Battle Mage</h2> <p>Lvl 24 Arcane Specialist</p> </div> <div class="skill-point-info"> <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjM2RjODVjIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBvbHlnb24gcG9pbnRzPSIxMiAyIDIgNyAxMiAxMiAyMiA3IDEyIDIiLz48cG9seWxpbmUgcG9pbnRzPSIyIDEyIDEyIDE3IDIyIDEyIi8+PHBvbHlsaW5lIHBvaW50cz0iMiAxNyAxMiAyMiAyMiAxNyIvPjwvc3ZnPg==" alt="Skill Point Icon"> <span>Points: <span id="skill-points">5</span></span> </div> <div class="center-circle" id="center-circle"> <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0xOCA4aDEuNSBhMi41IDIuNSAwIDAgMSAwIDUgaC0uNSIvPjxwYXRoIGQ9Ik0yIDE0aDE2di0ybC0yLTJoLTYgbC0yLTJINzYiLz48cGF0aCBkPSJNNCAyMC43OEE0IDQgMCAwIDAgOC44NCAxOEgxOGE0IDQgMCAwIDAgMi01LjQ1TDE3IDZIMXYxMmEzIDMgMCAwIDAgMyAyLjc4WiIvPjwvc3ZnPg==" alt="Magic Staff"> </div> <div class="skill-tree" id="skill-tree"></div> <div class="skill-tooltip" id="skill-tooltip"> <h3>Skill Name</h3> <p>Skill description goes here</p> <div class="skill-level"> <span>Level:</span> <div class="skill-level-dots" id="skill-level-dots"> <div class="dot active"></div> <div class="dot"></div> <div class="dot"></div> </div> </div> </div> <button class="reset-button" id="reset-button">Reset Skills</button> <div class="mobile-warning"> <h2>Best Viewed on Desktop</h2> <p>This RPG skill tree interface is designed for a desktop experience. For optimal interaction, please view on a larger screen.</p> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const container = document.querySelector('.container'); const skillTree = document.getElementById('skill-tree'); const tooltip = document.getElementById('skill-tooltip'); const centerCircle = document.getElementById('center-circle'); const skillPointsDisplay = document.getElementById('skill-points'); const resetButton = document.getElementById('reset-button'); let skillPoints = 5; let isTreeExpanded = false; let activeTooltipNode = null; // Skill data structure const skills = [ { id: 'fireball', name: 'Arcane Blast', description: 'Launches a powerful ball of arcane energy that explodes on impact, dealing area damage to enemies.', maxLevel: 3, currentLevel: 0, isUnlocked: false, isAvailable: true, position: { angle: 0, distance: 200 }, dependencies: [], iconPath: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZTc0YzNjIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PGNpcmNsZSBjeD0iMTIiIGN5PSIxMiIgcj0iMTAiLz48cGF0aCBkPSJNMTYgOGwtNCA0bTAgMGwtNCA0bTQtNC00LTRtNCA0IDQgNCIvPjwvc3ZnPg==" }, { id: 'frostbolt', name: 'Frost Nova', description: 'Summons a wave of frost that slows enemies caught in its radius and reduces their attack speed.', maxLevel: 3, currentLevel: 0, isUnlocked: false, isAvailable: false, position: { angle: 60, distance: 200 }, dependencies: ['fireball'], iconPath: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjM2RjOGZmIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBhdGggZD0iTTMgMTJoMThtLTktOUwxMiAxMmwtOS05em05IDE4TDEyIDEybDkgOXptOC05TDEyIDEybDgtOHpNMyAxMi4ybDkgOHoiLz48L3N2Zz4=" }, { id: 'lightning', name: 'Chain Lightning', description: 'Unleashes a bolt of lightning that arcs between multiple enemies, with each jump dealing additional damage.', maxLevel: 3, currentLevel: 0, isUnlocked: false, isAvailable: false, position: { angle: 300, distance: 200 }, dependencies: ['fireball'], iconPath: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZjFjNDA0IiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBhdGggZD0iTTEzIDEwVjNoLTFsMi0yLTEwIDZoNGwtNiAxMiAxMC02aC00bDcgLTgiLz48L3N2Zz4=" }, { id: 'barrier', name: 'Arcane Barrier', description: 'Creates a magical shield that absorbs damage and increases resistance to magical attacks.', maxLevel: 3, currentLevel: 0, isUnlocked: false, isAvailable: false, position: { angle: 180, distance: 200 }, dependencies: ['fireball'], iconPath: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjOWI0ZGNhIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBhdGggZD0iTTEyIDIycy04LTQtOC0xMFY1bDgtM2w4IDN2N2MwIDYtOCAxMC04IDEweiIvPjwvc3ZnPg==" }, { id: 'meteor', name: 'Meteor Shower', description: 'Calls down a barrage of meteors from the sky, creating multiple impact zones that deal massive damage.', maxLevel: 3, currentLevel: 0, isUnlocked: false, isAvailable: false, position: { angle: 30, distance: 300 }, dependencies: ['frostbolt'], iconPath: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZWQ0YzY3IiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBhdGggZD0iTTggM3YzbS04IDhsMTggME00IDE5bDQgNG02LTF2Mi0yem0yLTdsMy0zeiIvPjxwYXRoIGQ9Ik0xNSA1bDEgMS00IDQgNCA0IDEgMSIvPjwvc3ZnPg==" }, { id: 'icewall', name: 'Ice Wall', description: 'Conjures a wall of solid ice that blocks enemy movement and projectiles while dealing cold damage over time.', maxLevel: 3, currentLevel: 0, isUnlocked: false, isAvailable: false, position: { angle: 90, distance: 300 }, dependencies: ['frostbolt'], iconPath: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjM2RjOGZmIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBhdGggZD0iTTQgMjBoMTZNNCAxNGgyTTEwIDE0aDlNNCAxNGgxNk00IDhoMnYxMk0xMCA4aDJ2MTJNMTggOGgydnEyTTE4IDhoLTJ2MTIiLz48L3N2Zz4=" }, { id: 'thunderstorm', name: 'Thunderstorm', description: 'Summons a persistent storm cloud that strikes random enemies with lightning bolts for the duration.', maxLevel: 3, currentLevel: 0, isUnlocked: false, isAvailable: false, position: { angle: 270, distance: 300 }, dependencies: ['lightning'], iconPath: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZjFjNDA0IiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBhdGggZD0iTTMgNmg1bDcgMTFoNk04IDZsMTEgMTFNMyAxN2gzbDMtNSIvPjxwYXRoIGQ9Ik0xNSA3aDRhMiAyIDAgMCAxIDAgNA0gNCAwIDAgMCA0IDRoM2EzIDMgMCAwIDAgMC02aC01bDItMyIvPjwvc3ZnPg==" }, { id: 'teleport', name: 'Blink', description: 'Instantly teleports to a targeted location, granting a brief moment of invulnerability after arrival.', maxLevel: 3, currentLevel: 0, isUnlocked: false, isAvailable: false, position: { angle: 330, distance: 300 }, dependencies: ['lightning'], iconPath: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMzQ5OGRiIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBhdGggZD0iTTUgOWgtNHYxMmg0di0xMnoiLz48cGF0aCBkPSJNMTYgNWgtNHYxNmg0di0xNnoiLz48cGF0aCBkPSJNMTIgNWg4di03IiAvPjxwYXRoIGQ9Ik0yMyA1LTEwIDEzIiAvPjwvc3ZnPg==" }, { id: 'magicarmor', name: 'Arcane Armor', description: 'Enhances armor with magical energy, reflecting a portion of received damage back to attackers.', maxLevel: 3, currentLevel: 0, isUnlocked: false, isAvailable: false, position: { angle: 150, distance: 300 }, dependencies: ['barrier'], iconPath: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjOWI0ZGNhIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBhdGggZD0iTTIxIDEwYTMuMDcgMy4wNyAwIDAgMC0yLTIuOCAyMi41NSAyMi41NSAwIDAgMC0xNC0xLjggMS43NiAxLjc2IDAgMCAwLTEuMiAxLjgtMzUuMjQgMzUuMjQgMCAwIDAgMS45IDE1LjQgMS42IDEuNiAwIDAgMCAxLjMuOGg0YTEuNTggMS41OCAwIDAgMCAxLjUtLjlMMTQgMThoM2ExLjgxIDEuODEgMCAwIDAgMS43LTEuMy4zNy4zNyAwIDAgMSAuMy0uM1pNNyA2aDEwIi8+PHBhdGggZD0iTTEyIDE4djQiLz48L3N2Zz4=" }, { id: 'manashield', name: 'Mana Shield', description: 'Converts incoming damage to mana consumption instead, protecting health at the cost of magical energy.', maxLevel: 3, currentLevel: 0, isUnlocked: false, isAvailable: false, position: { angle: 210, distance: 300 }, dependencies: ['barrier'], iconPath: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjOTc0Y2YyIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PGNpcmNsZSBjeD0iMTIiIGN5PSIxMiIgcj0iMTAiLz48cGF0aCBkPSJNMTIgNnYxMk02IDE4bDEyLTEyIi8+PC9zdmc+" } ]; function polarToCartesian(angle, distance) { const radians = (angle - 90) * Math.PI / 180; const x = distance * Math.cos(radians); const y = distance * Math.sin(radians); return { x, y }; } function createSkillNode(skill) { const { x, y } = polarToCartesian(skill.position.angle, skill.position.distance); const node = document.createElement('div'); node.classList.add('skill-node'); node.classList.add('locked'); node.dataset.skillId = skill.id; if (skill.isAvailable) { node.classList.remove('locked'); node.classList.add('available'); } if (skill.isUnlocked) { node.classList.remove('locked'); node.classList.remove('available'); node.classList.add('unlocked'); } node.style.left = `calc(50% + ${x}px - 35px)`; node.style.top = `calc(50% + ${y}px - 35px)`; const icon = document.createElement('img'); icon.src = skill.iconPath; icon.alt = skill.name; node.appendChild(icon); skillTree.appendChild(node); // Add event listeners node.addEventListener('click', function(e) { if (node.classList.contains('locked')) return; if (node.classList.contains('available') && skillPoints > 0) { upgradeSkill(skill.id); } else if (node.classList.contains('unlocked')) { // Toggle selection if (node.classList.contains('selected')) { node.classList.remove('selected'); } else { // Remove selected class from all nodes document.querySelectorAll('.skill-node').forEach(n => { n.classList.remove('selected'); }); node.classList.add('selected'); } } }); node.addEventListener('mouseenter', function(e) { showTooltip(skill, e); activeTooltipNode = node; }); node.addEventListener('mouseleave', function() { hideTooltip(); activeTooltipNode = null; }); return node; } function createConnector(parentId, childId) { const parent = skills.find(s => s.id === parentId); const child = skills.find(s => s.id === childId); if (!parent || !child) return; const startCoords = polarToCartesian(parent.position.angle, parent.position.distance); const endCoords = polarToCartesian(child.position.angle, child.position.distance); const connector = document.createElement('div'); connector.classList.add('connector'); connector.dataset.from = parentId; connector.dataset.to = childId; // Calculate the angle and length of the connector const dx = endCoords.x - startCoords.x; const dy = endCoords.y - startCoords.y; const length = Math.sqrt(dx * dx + dy * dy); const angle = Math.atan2(dy, dx) * 180 / Math.PI; // Position and size the connector connector.style.width = `${length}px`; connector.style.transform = `translateX(${startCoords.x + 350}px) translateY(${startCoords.y + 350}px) rotate(${angle}deg)`; // Apply the appropriate class based on the parent skill's status if (parent.isUnlocked) { connector.classList.add('unlocked'); } else if (parent.isAvailable && child.isAvailable) { connector.classList.add('available'); } skillTree.appendChild(connector); // Animate the connector after it's added setTimeout(() => { connector.style.opacity = '1'; connector.style.animation = 'connectorGrow 0.8s ease-out forwards'; }, 300); return connector; } function showTooltip(skill, event) { // Update tooltip content const tooltipTitle = tooltip.querySelector('h3'); const tooltipDesc = tooltip.querySelector('p'); const levelDotsContainer = document.getElementById('skill-level-dots'); tooltipTitle.textContent = skill.name; tooltipDesc.textContent = skill.description; // Clear previous level dots levelDotsContainer.innerHTML = ''; // Create level dots for (let i = 0; i < skill.maxLevel; i++) { const dot = document.createElement('div'); dot.classList.add('dot'); if (i < skill.currentLevel) { dot.classList.add('active'); } levelDotsContainer.appendChild(dot); } // Position the tooltip near the skill node without going off-screen const containerRect = container.getBoundingClientRect(); const nodeRect = event.currentTarget.getBoundingClientRect(); // Calculate position relative to the container const nodeXRelative = nodeRect.left - containerRect.left; const nodeYRelative = nodeRect.top - containerRect.top; let tooltipX = nodeXRelative + nodeRect.width + 10; let tooltipY = nodeYRelative; // Check if the tooltip would go off the right edge if (tooltipX + 280 > containerRect.width) { tooltipX = nodeXRelative - 280
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Eldritch Wilds Explorer</title> <style> :root { --primary-color: #2c3e50; --secondary-color: #3498db; --accent-color: #e74c3c; --light-color: #ecf0f1; --dark-color: #1a252f; --forest-color: #27ae60; --desert-color: #f39c12; --mountain-color: #7f8c8d; --water-color: #3498db; --ruins-color: #95a5a6; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: var(--dark-color); color: var(--light-color); display: flex; flex-direction: column; height: 700px; width: 700px; overflow: hidden; position: relative; } .map-container { flex: 1; position: relative; overflow: hidden; background-color: var(--primary-color); border-radius: 8px; box-shadow: 0 10px 20px rgba(0, 0, 0, 0.4); } .map { position: absolute; transform-origin: 0 0; cursor: grab; transition: box-shadow 0.3s ease; background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxkZWZzPjxwYXR0ZXJuIGlkPSJwYXR0ZXJuIiB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHBhdHRlcm5Vbml0cz0idXNlclNwYWNlT25Vc2UiIHBhdHRlcm5UcmFuc2Zvcm09InJvdGF0ZSgzMCkiPjxyZWN0IHdpZHRoPSIyMCIgaGVpZ2h0PSI0MCIgZmlsbD0iIzIxMzE0MSIgZmlsbC1vcGFjaXR5PSIwLjQiPjwvcmVjdD48L3BhdHRlcm4+PC9kZWZzPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiMyYzNlNTAiPjwvcmVjdD48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI3BhdHRlcm4pIj48L3JlY3Q+PC9zdmc+'); background-size: cover; } .map-layer { position: absolute; top: 0; left: 0; right: 0; bottom: 0; pointer-events: none; } .map.active { cursor: grabbing; } .location-marker { position: absolute; width: 20px; height: 20px; border-radius: 50%; background-color: var(--accent-color); transform: translate(-50%, -50%); cursor: pointer; pointer-events: auto; box-shadow: 0 0 0 rgba(231, 76, 60, 0.4); animation: pulse 2s infinite; transition: all 0.3s ease; z-index: 10; } .location-marker::after { content: ''; position: absolute; width: 100%; height: 100%; border-radius: 50%; background-color: var(--accent-color); opacity: 0.6; transform: scale(1); animation: markerPulse 2s infinite; } .location-marker:hover { transform: translate(-50%, -50%) scale(1.2); z-index: 100; animation: none; } @keyframes markerPulse { 0% { transform: scale(1); opacity: 0.6; } 70% { transform: scale(2); opacity: 0; } 100% { transform: scale(1); opacity: 0; } } .tooltip { position: absolute; background-color: rgba(44, 62, 80, 0.9); color: var(--light-color); padding: 12px; border-radius: 6px; font-size: 14px; max-width: 200px; transform: translateY(-100%); margin-top: -15px; opacity: 0; visibility: hidden; transition: all 0.3s ease; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); pointer-events: none; z-index: 20; border: 1px solid rgba(255, 255, 255, 0.1); } .tooltip::after { content: ''; position: absolute; bottom: -10px; left: 50%; transform: translateX(-50%); border-width: 10px 10px 0; border-style: solid; border-color: rgba(44, 62, 80, 0.9) transparent transparent; } .tooltip h3 { margin-bottom: 5px; font-size: 16px; color: var(--secondary-color); border-bottom: 1px solid rgba(255, 255, 255, 0.2); padding-bottom: 5px; } .tooltip p { margin-bottom: 8px; line-height: 1.4; } .location-marker:hover .tooltip { opacity: 1; visibility: visible; transform: translateY(-110%); } .biome-forest { background-color: var(--forest-color); } .biome-desert { background-color: var(--desert-color); } .biome-mountain { background-color: var(--mountain-color); } .biome-water { background-color: var(--water-color); } .biome-ruins { background-color: var(--ruins-color); } .location-icon { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: white; font-size: 10px; } .controls { position: absolute; bottom: 20px; right: 20px; z-index: 100; display: flex; flex-direction: column; gap: 10px; } .control-button { width: 40px; height: 40px; border-radius: 50%; background-color: rgba(44, 62, 80, 0.8); color: var(--light-color); border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; font-size: 18px; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); transition: all 0.2s ease; } .control-button:hover { background-color: var(--secondary-color); transform: translateY(-2px); } .layers-panel { position: absolute; top: 20px; left: 20px; background-color: rgba(44, 62, 80, 0.8); border-radius: 8px; padding: 15px; z-index: 100; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); } .layer-control { display: flex; align-items: center; margin-bottom: 10px; gap: 8px; } .layer-control:last-child { margin-bottom: 0; } .layer-checkbox { appearance: none; width: 18px; height: 18px; border: 2px solid var(--light-color); border-radius: 4px; cursor: pointer; position: relative; } .layer-checkbox:checked { background-color: var(--secondary-color); border-color: var(--secondary-color); } .layer-checkbox:checked::after { content: "✓"; position: absolute; color: white; font-size: 14px; top: -2px; left: 3px; } .layer-label { font-size: 14px; cursor: pointer; } .layer-color { width: 12px; height: 12px; border-radius: 50%; margin-right: 5px; display: inline-block; } .terrain-forest { background-color: var(--forest-color); } .terrain-mountain { background-color: var(--mountain-color); } .terrain-desert { background-color: var(--desert-color); } .terrain-water { background-color: var(--water-color); } .terrain-ruins { background-color: var(--ruins-color); } .scale-indicator { position: absolute; bottom: 20px; left: 20px; background-color: rgba(44, 62, 80, 0.8); padding: 5px 10px; border-radius: 4px; font-size: 12px; z-index: 100; } .compass { position: absolute; top: 20px; right: 20px; width: 60px; height: 60px; border-radius: 50%; background-color: rgba(44, 62, 80, 0.8); display: flex; align-items: center; justify-content: center; z-index: 100; box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3); } .compass-pointer { position: absolute; width: 4px; height: 30px; background: linear-gradient(to bottom, var(--accent-color) 50%, white 50%); transform-origin: center bottom; } .compass-marker { position: absolute; font-size: 10px; color: var(--light-color); font-weight: bold; } .compass-marker.north { top: 5px; } .compass-marker.east { right: 5px; } .compass-marker.south { bottom: 5px; } .compass-marker.west { left: 5px; } .header { background-color: var(--primary-color); padding: 15px 20px; display: flex; justify-content: space-between; align-items: center; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); z-index: 10; border-bottom: 1px solid rgba(255, 255, 255, 0.1); } .title { font-size: 1.4rem; font-weight: bold; color: var(--light-color); position: relative; } .title::after { content: ""; position: absolute; bottom: -5px; left: 0; height: 2px; width: 60px; background-color: var(--accent-color); } .search-container { position: relative; } .search-input { background-color: rgba(255, 255, 255, 0.1); border: none; padding: 8px 12px 8px 32px; border-radius: 4px; color: var(--light-color); font-size: 0.9rem; width: 180px; transition: all 0.3s ease; } .search-input::placeholder { color: rgba(236, 240, 241, 0.6); } .search-input:focus { outline: none; background-color: rgba(255, 255, 255, 0.2); width: 220px; } .search-icon { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: var(--light-color); opacity: 0.7; } .loader { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: var(--primary-color); display: flex; justify-content: center; align-items: center; z-index: 1000; opacity: 1; transition: opacity 0.5s ease; } .loader.hidden { opacity: 0; pointer-events: none; } .spinner { width: 60px; height: 60px; border-radius: 50%; border: 4px solid rgba(236, 240, 241, 0.1); border-top: 4px solid var(--accent-color); animation: spin 1.5s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .terrain { position: absolute; border-radius: 40%; filter: blur(20px); opacity: 0.4; mix-blend-mode: soft-light; pointer-events: none; } .location-label { position: absolute; font-size: 12px; font-weight: bold; color: var(--light-color); text-shadow: 0 1px 3px rgba(0,0,0,0.7); transform: translate(-50%, 12px); pointer-events: none; opacity: 0; transition: opacity 0.3s ease; text-align: center; width: 100px; } .location-marker:hover + .location-label { opacity: 1; } .notification { position: absolute; top: 80px; left: 50%; transform: translateX(-50%); background-color: rgba(46, 204, 113, 0.9); color: white; padding: 10px 20px; border-radius: 4px; box-shadow: 0 3px 10px rgba(0,0,0,0.2); z-index: 1000; opacity: 0; transition: opacity 0.3s ease, transform 0.3s ease; pointer-events: none; } .notification.active { opacity: 1; transform: translateX(-50%) translateY(0); } .coords-display { position: absolute; bottom: 60px; left: 20px; background-color: rgba(44, 62, 80, 0.8); padding: 8px 12px; border-radius: 4px; font-size: 12px; color: var(--light-color); z-index: 100; } .hidden { display: none; } @keyframes float { 0% { transform: translateY(0px); } 50% { transform: translateY(-5px); } 100% { transform: translateY(0px); } } .floating { animation: float 3s ease-in-out infinite; } </style> </head> <body> <div class="header"> <h1 class="title">Eldritch Wilds</h1> <div class="search-container"> <span class="search-icon">🔍</span> <input type="text" class="search-input" placeholder="Search locations..."> </div> </div> <div class="map-container"> <div class="map" id="map"> <!-- Terrain layers will be added dynamically --> <div class="map-layer" id="terrain-layer"></div> <div class="map-layer" id="markers-layer"></div> </div> <div class="layers-panel"> <div class="layer-control"> <input type="checkbox" class="layer-checkbox" id="forest-layer" checked> <span class="layer-color terrain-forest"></span> <label class="layer-label" for="forest-layer">Enchanted Forests</label> </div> <div class="layer-control"> <input type="checkbox" class="layer-checkbox" id="mountain-layer" checked> <span class="layer-color terrain-mountain"></span> <label class="layer-label" for="mountain-layer">Mystic Peaks</label> </div> <div class="layer-control"> <input type="checkbox" class="layer-checkbox" id="desert-layer" checked> <span class="layer-color terrain-desert"></span> <label class="layer-label" for="desert-layer">Whispering Sands</label> </div> <div class="layer-control"> <input type="checkbox" class="layer-checkbox" id="water-layer" checked> <span class="layer-color terrain-water"></span> <label class="layer-label" for="water-layer">Abyssal Waters</label> </div> <div class="layer-control"> <input type="checkbox" class="layer-checkbox" id="ruins-layer" checked> <span class="layer-color terrain-ruins"></span> <label class="layer-label" for="ruins-layer">Ancient Ruins</label> </div> </div> <div class="controls"> <button class="control-button" id="zoom-in">+</button> <button class="control-button" id="zoom-out">−</button> <button class="control-button" id="reset-view">⟲</button> </div> <div class="scale-indicator">Scale: 1.0x</div> <div class="compass"> <div class="compass-pointer"></div> <div class="compass-marker north">N</div> <div class="compass-marker east">E</div> <div class="compass-marker south">S</div> <div class="compass-marker west">W</div> </div> <div class="coords-display">X: 0, Y: 0</div> </div> <div class="notification" id="notification">Discovery saved to journal!</div> <div class="loader" id="loader"> <div class="spinner"></div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Map configuration const mapWidth = 2000; const mapHeight = 2000; const minScale = 0.5; const maxScale = 3; // DOM elements const mapContainer = document.querySelector('.map-container'); const map = document.getElementById('map'); const terrainLayer = document.getElementById('terrain-layer'); const markersLayer = document.getElementById('markers-layer'); const zoomInBtn = document.getElementById('zoom-in'); const zoomOutBtn = document.getElementById('zoom-out'); const resetViewBtn = document.getElementById('reset-view'); const scaleIndicator = document.querySelector('.scale-indicator'); const coordsDisplay = document.querySelector('.coords-display'); const notification = document.getElementById('notification'); const loader = document.getElementById('loader'); const searchInput = document.querySelector('.search-input'); // Map state let currentScale = 1; let isDragging = false; let startX, startY, translateX = 0, translateY = 0; // Update map size map.style.width = `${mapWidth}px`; map.style.height = `${mapHeight}px`; // Set initial position to center centerMap(); // Loader setTimeout(() => { loader.classList.add('hidden'); }, 1500); // Terrain data const terrains = [ { type: 'forest', color: 'var(--forest-color)', positions: [ { x: 300, y: 400, width: 500, height: 400 }, { x: 1200, y: 600, width: 400, height: 350 }, { x: 800, y: 1400, width: 550, height: 300 } ]}, { type: 'mountain', color: 'var(--mountain-color)', positions: [ { x: 600, y: 200, width: 350, height: 300 }, { x: 1500, y: 800, width: 400, height: 500 }, { x: 400, y: 1200, width: 300, height: 450 } ]}, { type: 'desert', color: 'var(--desert-color)', positions: [ { x: 1000, y: 300, width: 400, height: 300 }, { x: 1700, y: 1600, width: 250, height: 320 }, { x: 300, y: 800, width: 350, height: 280 } ]}, { type: 'water', color: 'var(--water-color)', positions: [ { x: 1100, y: 1100, width: 500, height: 450 }, { x: 200, y: 1600, width: 350, height: 300 }, { x: 1700, y: 300, width: 280, height: 280 } ]}, { type: 'ruins', color: 'var(--ruins-color)', positions: [ { x: 900, y: 800, width: 120, height: 120 }, { x: 1400, y: 1400, width: 100, height: 100 }, { x: 500, y: 600, width: 90, height: 90 }, { x: 1600, y: 500, width: 80, height: 80 }, { x: 300, y: 1400, width: 110, height: 110 } ]} ]; // Location data const locations = [ { name: "Whispering Grove", x: 450, y: 520, type: "forest", description: "Ancient trees whose leaves shimmer with arcane energy. Adventurers report hearing whispered secrets from another realm." }, { name: "Dragontooth Spire", x: 680, y: 280, type: "mountain", description: "A jagged peak where dragon scales can be found embedded in the rock. The air crackles with remnant draconic magic." }, { name: "Timeless Oasis", x: 1100, y: 380, type: "desert", description: "Water that flows backward in time. Drinking it grants visions of possible futures, but aging accelerates for days afterward." }, { name: "Kraken's Deep", x: 1300, y: 1200, type: "water", description: "Bottomless waters home to an ancient entity. Ships report being lifted and examined before being gently replaced." }, { name: "Observatory of Eons", x: 950, y: 850, type: "ruins", description: "Star-mapping chamber built by a forgotten civilization. The constellations depicted no longer exist in our sky." }, { name: "Emberheart Forest", x: 1280, y: 700, type: "forest", description: "Trees with luminescent crimson cores. The forest floor is warm year-round, and rare fire-resistant herbs grow abundantly." }, { name: "Mirror Peak", x: 1580, y: 900, type: "mountain", description: "A mountain face of naturally reflective stone. It's said your reflection shows your true self, not your physical appearance." }, { name: "Shifting Dunes", x: 350, y: 880, type: "desert", description: "Sand that rearranges into different landscapes each dawn. Nomads navigate by reading patterns in the granules." }, { name: "Siren's Bay", x: 250, y: 1650, type: "water", description: "Waters that amplify and transform sound. Fishers create special harmonies to attract rare species from the depths." }, { name: "Clockwork Citadel", x: 1450, y: 1420, type: "ruins", description: "Mechanisms still turning after millennia. The central chamber realigns with celestial bodies during equinoxes." } ]; // Layer visibility const layerVisibility = { forest: true, mountain: true, desert: true, water: true, ruins: true }; // Generate terrain function generateTerrain() { terrains.forEach(terrain => { terrain.positions.forEach(pos => { const terrainEl = document.createElement('div'); terrainEl.className = `terrain terrain-${terrain.type}`; terrainEl.dataset.type = terrain.type; terrainEl.style.left = `${pos.x}px`; terrainEl.style.top = `${pos.y}px`; terrainEl.style.width = `${pos.width}px`; terrainEl.style.height = `${pos.height}px`; terrainEl.style.backgroundColor = terrain.color; terrainLayer.appendChild(terrainEl); }); }); } // Generate location markers function generateMarkers() { locations.forEach(location => { const markerEl = document.createElement('div'); markerEl.className = `location-marker biome-${location.type}`; markerEl.style.left = `${location.x}px`; markerEl.style.top = `${location.y}px`; markerEl.innerHTML = ` <div class="tooltip"> <h3>${location.name}</h3> <p>${location.description}</p> </div> `; const labelEl = document.createElement('div'); labelEl.className = 'location-label'; labelEl.textContent = location.name; labelEl.style.left = `${location.x}px`; labelEl.style.top = `${location.y}px`; markerEl.addEventListener('click', function() { showNotification(`Location explored: ${location.name}`); }); markersLayer.appendChild(markerEl); markersLayer.appendChild(labelEl); }); } // Map interaction - drag functionality map.addEventListener('mousedown', startDrag); map.addEventListener('touchstart', startDrag); document.addEventListener('mousemove', drag); document.addEventListener('touchmove', drag); document.addEventListener('mouseup', endDrag); document.addEventListener('touchend', endDrag); function startDrag(e) { e.preventDefault(); isDragging = true; map.classList.add('active'); if (e.type === 'mousedown') { startX = e.clientX; startY = e.clientY; } else { startX = e.touches[0].clientX; startY = e.touches[0].clientY; } } function drag(e) { if (!isDragging) return; e.preventDefault(); let clientX, clientY; if (e.type === 'mousemove') { clientX = e.clientX; clientY = e.clientY; } else { clientX = e.touches[0].clientX; clientY = e.touches[0].clientY; } const dx = clientX - startX; const dy = clientY - startY; translateX += dx; translateY += dy; startX = clientX; startY = clientY; updateMapTransform(); updateCoordinates(); } function endDrag() { isDragging = false; map.classList.remove('active'); } // Map zoom functionality zoomInBtn.addEventListener('click', () => zoom(0.2)); zoomOutBtn.addEventListener('click', () => zoom(-0.2)); resetViewBtn.addEventListener('click', resetView); // Add pinch-to-zoom functionality let initialDistance = 0; map.addEventListener('touchstart', handleTouchStart, { passive: false }); map.addEventListener('touchmove', handleTouchMove, { passive: false }); function handleTouchStart(e) { if (e.touches.length === 2) { initialDistance = getTouchDistance(e); } } function handleTouchMove(e) { if (e.touches.length === 2) { e.preventDefault(); const currentDistance = getTouchDistance(e); const distanceChange = currentDistance - initialDistance; if (Math.abs(distanceChange) > 10) { const zoomChange = distanceChange > 0 ? 0.05 : -0.05; zoom(zoomChange); initialDistance = currentDistance; } } } function getTouchDistance(e) { const dx = e.touches[0].clientX - e.touches[1].clientX; const dy = e.touches[0].clientY - e.touches[1].clientY; return Math.sqrt(dx * dx + dy * dy); } // Zoom on mousewheel mapContainer.addEventListener('wheel', function(e) { e.preventDefault(); const zoomChange = e.deltaY > 0 ? -0.1 : 0.1; zoom(zoomChange); }); function zoom(scaleChange) { const newScale = currentScale + scaleChange; if (newScale >= minScale && newScale <= maxScale) { currentScale = newScale; updateMapTransform(); scaleIndicator.textContent = `Scale: ${currentScale.toFixed(1)}x`; } } function updateMapTransform() { map.style.transform = `translate(${translateX}px, ${translateY}px) scale(${currentScale})`; } function centerMap() { const containerWidth = mapContainer.clientWidth; const containerHeight = mapContainer.clientHeight; translateX = (containerWidth - mapWidth) / 2; translateY = (containerHeight - mapHeight) / 2; updateMapTransform(); updateCoordinates(); } function resetView() { currentScale = 1; centerMap(); scaleIndicator.textContent = `Scale: ${currentScale.toFixed(1)}x`; } function updateCoordinates() { // Calculate center of the viewport in map coordinates const containerWidth = mapContainer.clientWidth; const containerHeight = mapContainer.clientHeight; const centerX = Math.round((mapWidth / 2) - (translateX / currentScale) - (containerWidth / 2 / currentScale)); const centerY = Math.round((mapHeight / 2) - (translateY / currentScale) - (containerHeight / 2 / currentScale)); coordsDisplay.textContent = `X: ${centerX}, Y: ${centerY}`; } // Layer visibility controls document.querySelectorAll('.layer-checkbox').forEach(checkbox => { checkbox.addEventListener('change', function() { const layerType = this.id.split('-')[0]; layerVisibility[layerType] = this.checked; updateLayerVisibility(); }); }); function updateLayerVisibility() { // Update terrain visibility document.querySelectorAll('.terrain').forEach(terrain => { const type = terrain.dataset.type; terrain.style.display = layerVisibility[type] ? 'block' : 'none'; }); // Update marker visibility document.querySelectorAll('.location-marker').forEach(marker => { const type = Array.from(marker.classList) .find(cls => cls.startsWith('biome-')) ?.replace('biome-', ''); if (type && !layerVisibility[type]) { marker.style.display = 'none'; marker.nextElementSibling.style.display = 'none'; } else { marker.style.display = 'block'; marker.nextElementSibling.style.display = 'block'; } }); } // Search functionality searchInput.addEventListener('input', function() { const searchTerm = this.value.toLowerCase(); if (searchTerm.length < 2) { // Reset highlights and return if search term is too short document.querySelectorAll('.location-marker').forEach(marker => { marker.style.transform = 'translate(-50%, -50%)'; marker.style.boxShadow = 'none'; marker.classList.remove('floating'); }); return; } let foundMatch = false; locations.forEach((location, index) => { const marker = document.querySelectorAll('.location-marker')[index]; const label = document.querySelectorAll('.location-label')[index]; if (location.name.toLowerCase().includes(searchTerm) || location.description.toLowerCase().includes(searchTerm)) { // Highlight matching location marker.style.transform = 'translate(-50%, -50%) scale(1.3)'; marker.style.boxShadow = '0 0 15px rgba(255, 255, 255, 0.7)'; marker.classList.add('floating'); label.style.opacity = '1'; if (!foundMatch) { // Center on first match translateX = (mapContainer.clientWidth / 2) - (location.x * currentScale); translateY = (mapContainer.clientHeight / 2) - (location.y * currentScale); updateMapTransform(); updateCoordinates(); foundMatch = true; } } else { // Reset non-matching locations marker.style.transform = 'translate(-50%, -50%)'; marker.style.boxShadow = 'none'; marker.classList.remove('floating'); label.style.opacity = '0'; } }); }); // Notification system function showNotification(message) { notification.textContent = message; notification.classList.add('active'); setTimeout(() => { notification.classList.remove('active'); }, 3000); } // Initialize the map generateTerrain(); generateMarkers(); updateLayerVisibility(); updateCoordinates(); }); </script> </body> </html>