// ========== Theme Management ========== class ThemeManager { constructor() { this.theme = localStorage.getItem('theme') || 'light'; this.init(); } init() { this.applyTheme(); this.bindEvents(); } applyTheme() { document.documentElement.setAttribute('data-theme', this.theme); // Update meta theme color const metaThemeColor = document.querySelector('meta[name="theme-color"]'); if (metaThemeColor) { const themeColor = this.theme === 'dark' ? '#134e4a' : '#f0fdfa'; metaThemeColor.setAttribute('content', themeColor); } } toggleTheme() { this.theme = this.theme === 'light' ? 'dark' : 'light'; localStorage.setItem('theme', this.theme); this.applyTheme(); // Dispatch custom event for components window.dispatchEvent(new CustomEvent('theme-changed', { detail: { theme: this.theme } })); } bindEvents() { // Listen for theme toggle events from components window.addEventListener('theme-toggle', () => this.toggleTheme()); } } // Initialize theme manager const themeManager = new ThemeManager(); // ========== Typewriter Effect ========== class Typewriter { constructor(element, texts, speed = 100) { this.element = element; this.texts = texts; this.speed = speed; this.textIndex = 0; this.charIndex = 0; this.isDeleting = false; this.init(); } init() { this.type(); } type() { const currentText = this.texts[this.textIndex]; if (this.isDeleting) { this.element.textContent = currentText.substring(0, this.charIndex - 1); this.charIndex--; } else { this.element.textContent = currentText.substring(0, this.charIndex + 1); this.charIndex++; } let typeSpeed = this.speed; if (this.isDeleting) typeSpeed /= 2; if (!this.isDeleting && this.charIndex === currentText.length) { typeSpeed = 2000; // Pause at end this.isDeleting = true; } else if (this.isDeleting && this.charIndex === 0) { this.isDeleting = false; this.textIndex = (this.textIndex + 1) % this.texts.length; typeSpeed = 500; // Pause before next text } setTimeout(() => this.type(), typeSpeed); } } // Initialize typewriter on load document.addEventListener('DOMContentLoaded', () => { const typewriterElement = document.getElementById('typewriter'); if (typewriterElement) { new Typewriter(typewriterElement, [ 'Which model truly dominates?', 'Speed vs Reasoning?', 'Production vs Research?', 'Let\\'s find out...' ]); } }); // ========== Smooth Scroll ========== class SmoothScroll { constructor() { this.init(); } init() { document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', (e) => { e.preventDefault(); const target = document.querySelector(anchor.getAttribute('href')); if (target) { target.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); }); } } // Initialize smooth scroll document.addEventListener('DOMContentLoaded', () => new SmoothScroll()); // ========== Intersection Observer Animations ========== class ScrollAnimations { constructor() { this.observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }; this.init(); } init() { const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('animate-in'); // Trigger counter animation if (entry.target.classList.contains('stat-card')) { this.animateCounters(entry.target); } // Trigger chart animation if (entry.target.classList.contains('benchmark-card')) { this.animateCharts(entry.target); } } }); }, this.observerOptions); // Observe elements document.querySelectorAll('.model-card, .benchmark-card, .stat-card').forEach(el => { observer.observe(el); }); } animateCounters(container) { const counter = container.querySelector('[data-count]'); if (!counter || counter.classList.contains('counted')) return; counter.classList.add('counted'); const target = parseInt(counter.dataset.count); const duration = 2000; const start = performance.now(); const updateCounter = (timestamp) => { const elapsed = timestamp - start; const progress = Math.min(elapsed / duration, 1); const current = Math.floor(progress * target); counter.textContent = current; if (progress < 1) { requestAnimationFrame(updateCounter); } else { counter.textContent = target + (target === 99.2 ? '%' : target === 8 ? '+' : target === 32 ? 'k' : target === 175 ? 'B' : ''); } }; requestAnimationFrame(updateCounter); } animateCharts(container) { const bars = container.querySelectorAll('.chart-bar'); bars.forEach((bar, index) => { const percentage = bar.dataset.percentage; const fill = bar.querySelector('.bar-fill'); setTimeout(() => { fill.style.setProperty('--bar-width', `${percentage}%`); fill.style.maxWidth = `${percentage}%`; }, index * 200); }); } } // Initialize scroll animations document.addEventListener('DOMContentLoaded', () => new ScrollAnimations()); // ========== Particles Animation ========== class ParticleSystem { constructor(containerId, particleCount = 50) { this.container = document.getElementById(containerId); this.particleCount = particleCount; if (this.container) { this.init(); } } init() { for (let i = 0; i < this.particleCount; i++) { const particle = document.createElement('div'); particle.className = 'particle'; particle.style.left = Math.random() * 100 + '%'; particle.style.animationDelay = Math.random() * 15 + 's'; particle.style.animationDuration = (15 + Math.random() * 10) + 's'; // Random colors from theme const colors = ['#14b8a6', '#a855f7', '#f59e0b']; particle.style.background = colors[Math.floor(Math.random() * colors.length)]; this.container.appendChild(particle); } } } // Initialize particles on load document.addEventListener('DOMContentLoaded', () => { new ParticleSystem('particles-js', 30); }); // ========== FAQ Accordion ========== class FAQAccordion { constructor() { this.init(); } init() { document.querySelectorAll('.faq-question').forEach(question => { question.addEventListener('click', () => { const answer = question.nextElementSibling; const icon = question.querySelector('i'); // Close all other FAQs document.querySelectorAll('.faq-question').forEach(q => { if (q !== question) { q.classList.remove('active'); q.nextElementSibling.classList.remove('open'); q.querySelector('i').style.transform = 'rotate(0deg)'; } }); // Toggle current FAQ question.classList.toggle('active'); answer.classList.toggle('open'); if (question.classList.contains('active')) { icon.style.transform = 'rotate(180deg)'; } else { icon.style.transform = 'rotate(0deg)'; } }); }); } } // Initialize FAQ document.addEventListener('DOMContentLoaded', () => new FAQAccordion()); // ========== Navbar Scroll Effect ========== class NavbarScroll { constructor() { this.lastScroll = 0; this.navbar = document.querySelector('kimi-navbar'); this.init(); } init() { window.addEventListener('scroll', () => { const currentScroll = window.pageYOffset; if (currentScroll > 100) { this.navbar?.setAttribute('scrolled', 'true'); } else { this.navbar?.setAttribute('scrolled', 'false'); } this.lastScroll = currentScroll; }); } } // Initialize navbar scroll document.addEventListener('DOMContentLoaded', () => new NavbarScroll()); // ========== Mobile Menu Toggle ========== class MobileMenu { constructor() { this.isOpen = false; this.init(); } init() { const toggleButton = document.querySelector('[data-mobile-toggle]'); const menu = document.querySelector('[data-mobile-menu]'); if (!toggleButton || !menu) return; toggleButton.addEventListener('click', () => { this.isOpen = !this.isOpen; menu.classList.toggle('hidden'); menu.classList.toggle('flex'); // Animate hamburger icon const icon = toggleButton.querySelector('i'); if (this.isOpen) { icon.setAttribute('data-feather', 'x'); } else { icon.setAttribute('data-feather', 'menu'); } feather.replace(); }); } } // Initialize mobile menu document.addEventListener('DOMContentLoaded', () => new MobileMenu());