Spaces:
Running
Running
Download script.js from LivelyPlace/Lively-Place: direct link, hf CLI and curl.
- Browser
- Download file 15 kB
-
https://huggingface.co/spaces/LivelyPlace/Lively-Place/resolve/main/script.js
- Command line
-
hf download hf://spaces/LivelyPlace/Lively-Place/script.js
-
curl -L -o script.js https://huggingface.co/spaces/LivelyPlace/Lively-Place/resolve/main/script.js
15 kB
| /* ============================================ | |
| 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 = ` | |
| <span class="msg-name ${randomColor}">${escapeHtml(message.name)}</span> | |
| <span class="msg-time">${message.time}</span> | |
| <p class="msg-text">${escapeHtml(message.text)}</p> | |
| `; | |
| 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;'); | |