/** * CHAMPIONS OF LUNERARIA - Studio Grade Interactions * Cursor Ambient Tracking, Battle Flow Stage Machine, Champion Roster System, * 3D Card Gyroscope/Tilt, and Accessible Lightbox Modal. */ document.addEventListener('DOMContentLoaded', () => { initCursorTracker(); initHeaderScroll(); initAudioSynthesizer(); initHeroParticles(); initBattleFlowSteps(); initChampionRoster(); initArmyFilters(); init3DCardTilts(); initCinemaTheater(); initStudioLightbox(); initPlatformMatrix(); initScrollTop(); initScrollAnimations(); }); /* -------------------------------------------------------------------------- 1. Global Cursor Ambient Glow Tracker -------------------------------------------------------------------------- */ function initCursorTracker() { window.addEventListener('mousemove', (e) => { document.documentElement.style.setProperty('--mouse-x', `${e.clientX}px`); document.documentElement.style.setProperty('--mouse-y', `${e.clientY}px`); }, { passive: true }); } /* -------------------------------------------------------------------------- 2. Sticky Header Glass & Scroll State -------------------------------------------------------------------------- */ function initHeaderScroll() { const header = document.querySelector('.site-header'); if (!header) return; window.addEventListener('scroll', () => { header.classList.toggle('scrolled', window.scrollY > 40); }, { passive: true }); } /* -------------------------------------------------------------------------- 3. Ambient Web Audio Synthesizer Trigger -------------------------------------------------------------------------- */ function initAudioSynthesizer() { const btn = document.getElementById('btnAudioSynth'); if (!btn || !window.luneAudio) return; btn.addEventListener('click', () => { const isPlaying = window.luneAudio.toggle(); btn.classList.toggle('is-playing', isPlaying); btn.setAttribute('aria-pressed', isPlaying ? 'true' : 'false'); const label = btn.querySelector('.audio-label'); if (label) { label.textContent = isPlaying ? 'Atmosphäre: An' : 'Atmosphäre: Aus'; } }); } /* -------------------------------------------------------------------------- 4. Hero Floating Ambient Sparks Canvas -------------------------------------------------------------------------- */ function initHeroParticles() { const canvas = document.getElementById('heroParticleCanvas'); if (!canvas) return; const ctx = canvas.getContext('2d'); let width, height; let particles = []; function resize() { width = canvas.width = canvas.offsetWidth; height = canvas.height = canvas.offsetHeight; } window.addEventListener('resize', resize, { passive: true }); resize(); class Spark { constructor() { this.reset(); } reset() { this.x = Math.random() * width; this.y = height + Math.random() * 20; this.size = Math.random() * 2.2 + 0.6; this.speedY = Math.random() * 0.6 + 0.25; this.speedX = (Math.random() - 0.5) * 0.35; this.alpha = Math.random() * 0.5 + 0.15; this.color = Math.random() > 0.45 ? '56, 232, 216' : '245, 158, 11'; } update() { this.y -= this.speedY; this.x += this.speedX; if (this.y < -10) this.reset(); } draw() { ctx.beginPath(); ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); ctx.fillStyle = `rgba(${this.color}, ${this.alpha})`; ctx.fill(); } } const count = Math.min(width < 768 ? 24 : 48, 55); for (let i = 0; i < count; i++) { const p = new Spark(); p.y = Math.random() * height; particles.push(p); } function frame() { ctx.clearRect(0, 0, width, height); particles.forEach(p => { p.update(); p.draw(); }); requestAnimationFrame(frame); } if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) { frame(); } } /* -------------------------------------------------------------------------- 5. Interactive Battle Flow (Rundenzyklus Timeline) -------------------------------------------------------------------------- */ const FLOW_DATA = { 1: { title: 'Phase 1: Die Geheime Aufstellung', desc: 'Wähle Truppen im HUD, investiere in Einkommen und positioniere deine Einheiten auf den Aufmarschfeldern deiner Lane. Bis zum Signal der Schlacht bleibt deine Aufstellung für die Feinde unsichtbar.', img: 'assets/img/planung-hud.jpg' }, 2: { title: 'Phase 2: Der Simultane Aufmarsch', desc: 'Das Signal ertönt. Beide Heere setzen sich simultan in Bewegung. Formationen formieren sich automatisch auf Basis von Bewegungsgeschwindigkeit, Reichweite und Formationslinien.', img: 'assets/img/aufmarsch.jpg' }, 3: { title: 'Phase 3: Der Deterministische Clash (20 Hz)', desc: 'Schwerter, Pfeile und Magmasäulen kollidieren. Der autoritative Regelkern berechnet jede Interaktion auf der Millisekunde genau. Rüstungsklassen (Leicht, Schwer, Äther) entscheiden über Durchschlagskraft.', img: 'assets/img/held-kampf.jpg' }, 4: { title: 'Phase 4: Die Bossgrotte „Mondschlund“', desc: 'Wähle den riskanten Vorstoß: Sende Truppen zur Grotte, bezwinge die Schlundkrone und entsende den Superboss (6.800 HP) auf eine gegnerische Lane zur massiven Belagerung.', img: 'assets/img/boss-lane.jpg' }, 5: { title: 'Phase 5: Der Fall des Mondherz-Ancients', desc: 'Türme stürzen in Trümmer. Erst wenn die Grenzwachten und Bastionen gefallen sind, öffnet sich der Zugang zum gegnerischen Kristallkern. Sein Einsturz krönt das Siegerteam.', img: 'assets/img/ancient-fall.jpg' } }; function initBattleFlowSteps() { const buttons = document.querySelectorAll('.flow-step-btn'); const titleEl = document.getElementById('flowStageTitle'); const descEl = document.getElementById('flowStageDesc'); const imgEl = document.getElementById('flowStageImg'); buttons.forEach(btn => { btn.addEventListener('click', () => { buttons.forEach(b => b.classList.remove('is-active')); btn.classList.add('is-active'); const step = btn.dataset.step; const data = FLOW_DATA[step]; if (!data) return; if (titleEl) titleEl.textContent = data.title; if (descEl) descEl.textContent = data.desc; if (imgEl) { imgEl.style.opacity = '0.3'; setTimeout(() => { imgEl.src = data.img; imgEl.style.opacity = '1'; }, 150); } }); }); } /* -------------------------------------------------------------------------- 6. Champion Roster Showcase (Riot / Dota Style) -------------------------------------------------------------------------- */ const CHAMPION_PROFILES = { sylvara: { badge: 'Elfen · Assassine / Flankenspringerin', name: 'Sylvara, die Mondklinge', quote: '„Zwei Klingen, ein Sprung – und die hintere Reihe verstummt vor dem ersten Zauber.“', image: 'assets/img/held-kampf.jpg', abilities: [ { key: 'Passiv', name: 'Schattensprung', desc: 'Springt beim ersten Angriff der Runde direkt in die gegnerische Backline auf verwundbare Fernkämpfer.' }, { key: 'Skill 1', name: 'Mondsichel-Wurf', desc: 'Schleudert rotierende Mondklingen durch Gegnerketten, die auf dem Rückweg magischen Schnittschaden verursachen.' }, { key: 'Ultimate', name: 'Mondsicheltanz', desc: 'Wirbelt mit blendendem Mondlicht durch bis zu 5 Ziele. Löst bedingungsgesteuert aus, sobald ein Fernkämpfer isoliert ist.' } ] }, brunhild: { badge: 'Menschen · Frontkämpferin / Sprungangriff', name: 'Brunhild, die Walküre', quote: '„Mein Speer verfehlt nie sein Zeichen. Der Himmel stürzt über den Feinden ein.“', image: 'assets/img/fig-funkenlanze.jpg', abilities: [ { key: 'Passiv', name: 'Duellstolz', desc: 'Erhöht ihren ausgeteilten Schaden gegen feindliche Helden und Bosse um 35 %.' }, { key: 'Skill 1', name: 'Speer der Vergeltung', desc: 'Markiert das Ziel mit einer Leuchtgaleere und senkt gegnerische Rüstung um 40 %.' }, { key: 'Ultimate', name: 'Walkürensturz', desc: 'Katapultiert sich in die Lüfte und schlägt mit Flächenbeben und 2-Sekunden-Betäubung auf das markierte Ziel ein.' } ] }, funkenlanze: { badge: 'Glutpakt · Elite-Heldin / Hitzestrahl', name: 'Funkenlanze von der Sonnenesse', quote: '„Glühende Schlacke schmiedet das Heer – kein Turm widersteht unserer Hitze.“', image: 'assets/img/aufmarsch.jpg', abilities: [ { key: 'Passiv', name: 'Hitzeschild', desc: 'Absorbiert Puls- und Ätherschaden und lädt bei Treffern ihre Lanze mit glühendem Magma auf.' }, { key: 'Skill 1', name: 'Lanzenstoß', desc: 'Durchdringt schwere Panzerung mit linearem Hitzestrahl über 12 Meter Kampfreichweite.' }, { key: 'Ultimate', name: 'Eruptionszündung', desc: 'Verwandelt die Lanze in eine lodernde Magmasäule, die Belagerungsschaden an Gebäuden verdoppelt.' } ] } }; function initChampionRoster() { const tabs = document.querySelectorAll('.roster-tab-btn'); const badgeEl = document.getElementById('rosterBadge'); const nameEl = document.getElementById('rosterName'); const quoteEl = document.getElementById('rosterQuote'); const imgEl = document.getElementById('rosterImg'); const stackEl = document.getElementById('rosterAbilityStack'); tabs.forEach(tab => { tab.addEventListener('click', () => { tabs.forEach(t => t.classList.remove('is-active')); tab.classList.add('is-active'); const heroKey = tab.dataset.champion; const data = CHAMPION_PROFILES[heroKey]; if (!data) return; if (badgeEl) badgeEl.textContent = data.badge; if (nameEl) nameEl.textContent = data.name; if (quoteEl) quoteEl.textContent = data.quote; if (imgEl) imgEl.src = data.image; if (stackEl) { stackEl.innerHTML = data.abilities.map(ab => `