/* ============================================ KBdmly Community - 2007 Retro Web JavaScript Interactive Features & Animations ============================================ */ // ============================================ // HIT COUNTER - Classic 2007 Feature! // ============================================ function initCounter() { const counterEl = document.getElementById('counter'); if (!counterEl) return; // Get or initialize counter let count = localStorage.getItem('siteVisitorCount'); if (!count) { // First visit ever - set a base number to look popular count = Math.floor(Math.random() * 5000) + 10000; // Start between 10,000-15,000 localStorage.setItem('siteVisitorCount', count); } else { count = parseInt(count) + 1; localStorage.setItem('siteVisitorCount', count); } // Animate counter counting up animateCounter(counterEl, 0, count, 2000); } function animateCounter(element, start, end, duration) { const startTime = performance.now(); function update(currentTime) { const elapsed = currentTime - startTime; const progress = Math.min(elapsed / duration, 1); // Easing function for smooth animation const easeOut = 1 - Math.pow(1 - progress, 3); const current = Math.floor(start + (end - start) * easeOut); element.textContent = current.toString().padStart(6, '0'); if (progress < 1) { requestAnimationFrame(update); } } requestAnimationFrame(update); } // ============================================ // SPARKLE CURSOR TRAIL // ============================================ function initSparkles() { const sparklesContainer = document.getElementById('sparkles'); if (!sparklesContainer) return; const sparkleEmojis = ['✨', '⭐', '💫', '🌟', '✦', '★', '☆']; document.addEventListener('mousemove', (e) => { // Only create sparkle occasionally for performance if (Math.random() > 0.85) { createSparkle(e.clientX, e.clientY, sparklesContainer, sparkleEmojis); } }); } function createSparkle(x, y, container, emojis) { const sparkle = document.createElement('span'); sparkle.className = 'sparkle'; sparkle.textContent = emojis[Math.floor(Math.random() * emojis.length)]; sparkle.style.left = x + 'px'; sparkle.style.top = y + 'px'; container.appendChild(sparkle); // Remove after animation setTimeout(() => { sparkle.remove(); }, 1000); } // ============================================ // SHOUTBOX / GUESTBOOK FUNCTIONALITY // ============================================ function initShoutbox() { const form = document.getElementById('shoutForm'); const messagesContainer = document.getElementById('messagesContainer'); if (!form || !messagesContainer) return; // Load saved messages loadMessages(messagesContainer); form.addEventListener('submit', (e) => { e.preventDefault(); const nameInput = document.getElementById('msgName'); const textInput = document.getElementById('msgText'); const name = nameInput.value.trim(); const text = textInput.value.trim(); if (!name || !text) return; // Create new message const message = { name: name, text: text, time: new Date().toLocaleTimeString('id-ID', { hour: '2-digit', minute: '2-digit' }), timestamp: Date.now() }; // Save to localStorage saveMessage(message); // Add to DOM addMessageToDOM(message, messagesContainer); // Clear form textInput.value = ''; // Scroll to bottom messagesContainer.scrollTop = messagesContainer.scrollHeight; // Show success effect showPostSuccess(form); }); } function saveMessage(message) { let messages = JSON.parse(localStorage.getItem('shoutboxMessages') || '[]'); messages.push(message); // Keep only last 50 messages if (messages.length > 50) { messages = messages.slice(-50); } localStorage.setItem('shoutboxMessages', JSON.stringify(messages)); } function loadMessages(container) { const messages = JSON.parse(localStorage.getItem('shoutboxMessages') || '[]'); // Sort by timestamp messages.sort((a, b) => a.timestamp - b.timestamp); messages.forEach(msg => addMessageToDOM(msg, container)); } function addMessageToDOM(message, container) { const messageDiv = document.createElement('div'); messageDiv.className = 'message'; // Random color class for variety const colors = ['member-name', 'new-member-name']; const randomColor = colors[Math.floor(Math.random() * colors.length)]; messageDiv.innerHTML = ` ${escapeHtml(message.name)} ${message.time}

${escapeHtml(message.text)}

`; container.appendChild(messageDiv); } function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } function showPostSuccess(form) { const btn = form.querySelector('.submit-btn'); const originalText = btn.innerHTML; btn.innerHTML = '✅ Posted!'; btn.style.background = 'linear-gradient(180deg, #00cc00 0%, #009900 100%)'; setTimeout(() => { btn.innerHTML = originalText; btn.style.background = ''; }, 1500); } // ============================================ // BACK TO TOP BUTTON // ============================================ function initBackToTop() { const btn = document.getElementById('backToTop'); if (!btn) return; window.addEventListener('scroll', () => { if (window.scrollY > 300) { btn.classList.add('visible'); } else { btn.classList.remove('visible'); } }); btn.addEventListener('click', () => { window.scrollTo({ top: 0, behavior: 'smooth' }); }); } // ============================================ // SMOOTH SCROLL FOR NAV LINKS // ============================================ function initSmoothScroll() { document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function(e) { e.preventDefault(); const targetId = this.getAttribute('href'); const targetElement = document.querySelector(targetId); if (targetElement) { targetElement.scrollIntoView({ behavior: 'smooth', block: 'start' }); // Update active nav state document.querySelectorAll('.nav-btn').forEach(btn => btn.classList.remove('active')); this.classList.add('active'); } }); }); } // ============================================ // MEMBER COUNT ANIMATION // ============================================ function initMemberCountAnimation() { const memberCountEl = document.getElementById('memberCount'); if (!memberCountEl) return; const targetCount = 256 + Math.floor(Math.random() * 50); // Base + random // Animate on scroll into view const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { animateNumber(memberCountEl, 0, targetCount, 1500); observer.unobserve(entry.target); } }); }, { threshold: 0.5 }); observer.observe(memberCountEl); } function animateNumber(element, start, end, duration) { const startTime = performance.now(); function update(currentTime) { const elapsed = currentTime - startTime; const progress = Math.min(elapsed / duration, 1); const easeOut = 1 - Math.pow(1 - progress, 3); const current = Math.floor(start + (end - start) * easeOut); element.textContent = current; if (progress < 1) { requestAnimationFrame(update); } } requestAnimationFrame(update); } // ============================================ // RANDOM MEMBER STATUS CHANGES // ============================================ function initMemberStatusSimulation() { const statuses = document.querySelectorAll('.member-status'); setInterval(() => { statuses.forEach(status => { if (Math.random() > 0.7) { // 30% chance to change const options = ['online', 'away', 'offline']; const weights = [0.5, 0.3, 0.2]; // More likely online let random = Math.random(); let newIndex = 0; for (let i = 0; i < weights.length; i++) { random -= weights[i]; if (random <= 0) { newIndex = i; break; } } status.className = 'member-status ' + options[newIndex]; status.textContent = options[newIndex] === 'online' ? '● Online' : options[newIndex] === 'away' ? '● Away' : '● Offline'; } }); }, 5000); // Check every 5 seconds } // ============================================ // EASTER EGG - KONAMI CODE // ============================================ function initEasterEgg() { const konamiCode = ['ArrowUp', 'ArrowUp', 'ArrowDown', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowLeft', 'ArrowRight', 'b', 'a']; let konamiIndex = 0; document.addEventListener('keydown', (e) => { if (e.key === konamiCode[konamiIndex]) { konamiIndex++; if (konamiIndex === konamiCode.length) { activateEasterEgg(); konamiIndex = 0; } } else { konamiIndex = 0; } }); } function activateEasterEgg() { // Rainbow mode! document.body.style.animation = 'rainbow-bg 2s linear infinite'; // Add rainbow keyframes dynamically const style = document.createElement('style'); style.textContent = ` @keyframes rainbow-bg { 0% { filter: hue-rotate(0deg); } 100% { filter: hue-rotate(360deg); } } `; document.head.appendChild(style); // Show alert in retro style setTimeout(() => { alert('🎉 SECRET UNLOCKED! 🎉\n\nYou found the Konami Code!\nYou are a TRUE 2007 web veteran!\n\n★☆★ CONGRATULATIONS! ★☆★'); }, 100); // Remove after 10 seconds setTimeout(() => { document.body.style.animation = ''; }, 10000); } // ============================================ // TYPING EFFECT FOR TAGLINE (Optional) // ============================================ function initTypingEffect() { const tagline = document.querySelector('.tagline'); if (!tagline) return; const originalText = tagline.textContent; tagline.textContent = ''; let charIndex = 0; // Start typing after a short delay setTimeout(() => { typeCharacter(); }, 1000); function typeCharacter() { if (charIndex < originalText.length) { tagline.textContent += originalText.charAt(charIndex); charIndex++; setTimeout(typeCharacter, 80); } } } // ============================================ // PARALLAX EFFECT ON HEADER // ============================================ function initParallax() { const header = document.querySelector('.logo-section'); if (!header) return; window.addEventListener('scroll', () => { const scrolled = window.scrollY; if (scrolled < 400) { header.style.backgroundPositionY = scrolled * 0.5 + 'px'; } }); } // ============================================ // INITIALIZE EVERYTHING ON DOM LOAD // ============================================ document.addEventListener('DOMContentLoaded', () => { console.log('%c✦ KBdmly Community Website ✦', 'color: #00ffff; font-size: 20px; font-weight: bold; text-shadow: 0 0 10px #00ffff;'); console.log('%cWelcome, fellow time traveler from 2007! 🚀', 'color: #ff00ff; font-size: 14px;'); console.log('%cTry the Konami Code for a surprise! ⬆️⬆️⬇️⬇️⬅️➡️⬅️➡️BA', 'color: #ffcc00; font-size: 12px;'); // Initialize all features initCounter(); initSparkles(); initShoutbox(); initBackToTop(); initSmoothScroll(); initMemberCountAnimation(); initMemberStatusSimulation(); initEasterEgg(); initTypingEffect(); initParallax(); // Add loaded class for entrance animations document.body.classList.add('loaded'); }); // ============================================ // ADDITIONAL VISUAL EFFECTS // ============================================ // Randomly twinkle stars in title function initStarTwinkle() { const stars = document.querySelectorAll('.star'); setInterval(() => { stars.forEach(star => { if (Math.random() > 0.7) { star.style.transform = `scale(${1 + Math.random() * 0.5})`; star.style.color = ['#ffcc00', '#ff6600', '#ff00ff', '#00ffff'][Math.floor(Math.random() * 4)]; setTimeout(() => { star.style.transform = ''; star.style.color = '#ffcc00'; }, 300); } }); }, 800); } // Initialize star twinkle after load setTimeout(initStarTwinkle, 2000); // Hover sound effect simulation (visual feedback) document.querySelectorAll('.nav-btn, .glossy-button, .big-join-btn').forEach(btn => { btn.addEventListener('mouseenter', () => { btn.style.transition = 'all 0.1s'; }); }); // Console welcome message with ASCII art console.log(` %c╔══════════════════════════════════════╗ ║ ║ ║ ✦ KBdmly Community ✦ ║ ║ ║ ║ ~* Est. 2024 *~ ║ ║ ║ ║ Welcome to our retro website! ║ ║ ║ ╚══════════════════════════════════════╝ `, 'color: #00ff00; background: #001100; padding: 10px; font-family: monospace;');