Lively-Place / script.js
R-Kentaren's picture
Upload 3 files
327b6f3 verified
Raw History Blame Contribute Delete
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;');