/* =================================================== JAESWIFT.XYZ — Main JavaScript Animations, particles, typing, scroll effects =================================================== */ (function () { 'use strict'; // ─── CONFIG ─── const CONFIG = { typingStrings: [ 'Developer // Tinkerer // Builder', 'Self-hosted everything.', 'Linux enthusiast since day one.', 'Building the future, one commit at a time.', 'root@jaeswift:~# echo "Hello, World"', 'Cybersecurity & Infrastructure.', 'AI Agent Operator.', ], typingSpeed: 60, typingDeleteSpeed: 30, typingPause: 2500, particleCount: 80, particleMaxSpeed: 0.3, particleConnectionDist: 120, startTime: Date.now(), }; // ─── UTILITIES ─── const $ = (sel, ctx = document) => ctx.querySelector(sel); const $$ = (sel, ctx = document) => [...ctx.querySelectorAll(sel)]; // ─── NAVBAR ─── function initNavbar() { const navbar = $('#navbar'); const toggle = $('#navToggle'); const menu = $('#navMenu'); const navItems = $$('.nav-item'); // Scroll effect let lastScroll = 0; window.addEventListener('scroll', () => { const scrollY = window.scrollY; navbar.classList.toggle('scrolled', scrollY > 50); lastScroll = scrollY; }, { passive: true }); // Mobile toggle toggle.addEventListener('click', () => { menu.classList.toggle('active'); toggle.classList.toggle('active'); }); // Mobile dropdown toggle if (window.innerWidth <= 768) { navItems.forEach(item => { const link = item.querySelector('.nav-link'); link.addEventListener('click', (e) => { if (item.querySelector('.dropdown')) { e.preventDefault(); item.classList.toggle('active'); } }); }); } // Active link on scroll const sections = $$('section[id]'); window.addEventListener('scroll', () => { const scrollPos = window.scrollY + 100; sections.forEach(section => { const top = section.offsetTop; const height = section.offsetHeight; const id = section.getAttribute('id'); if (scrollPos >= top && scrollPos < top + height) { $$('.nav-link').forEach(l => l.classList.remove('active')); const activeLink = $(`.nav-link[href="#${id}"]`); if (activeLink) activeLink.classList.add('active'); } }); }, { passive: true }); // Smooth scroll for nav links $$('.nav-link, .dropdown a[href^="#"]').forEach(link => { link.addEventListener('click', (e) => { const href = link.getAttribute('href'); if (href && href.startsWith('#')) { e.preventDefault(); const target = $(href); if (target) { target.scrollIntoView({ behavior: 'smooth', block: 'start' }); menu.classList.remove('active'); toggle.classList.remove('active'); } } }); }); } // ─── LIVE CLOCK ─── function initClock() { const navTime = $('#navTime'); if (!navTime) return; function update() { const now = new Date(); const h = String(now.getHours()).padStart(2, '0'); const m = String(now.getMinutes()).padStart(2, '0'); const s = String(now.getSeconds()).padStart(2, '0'); navTime.textContent = `${h}:${m}:${s}`; } update(); setInterval(update, 1000); } // ─── UPTIME COUNTER ─── function initUptime() { const uptimeEl = $('#uptime'); if (!uptimeEl) return; function update() { const elapsed = Date.now() - CONFIG.startTime; const totalSec = Math.floor(elapsed / 1000); const days = Math.floor(totalSec / 86400); const hours = Math.floor((totalSec % 86400) / 3600); const mins = Math.floor((totalSec % 3600) / 60); uptimeEl.textContent = `${days}d ${String(hours).padStart(2, '0')}h ${String(mins).padStart(2, '0')}m`; } update(); setInterval(update, 60000); } // ─── TYPING EFFECT ─── function initTyping() { const el = $('#typingText'); if (!el) return; let stringIndex = 0; let charIndex = 0; let isDeleting = false; function type() { const current = CONFIG.typingStrings[stringIndex]; if (isDeleting) { el.textContent = current.substring(0, charIndex - 1); charIndex--; } else { el.textContent = current.substring(0, charIndex + 1); charIndex++; } let delay = isDeleting ? CONFIG.typingDeleteSpeed : CONFIG.typingSpeed; if (!isDeleting && charIndex === current.length) { delay = CONFIG.typingPause; isDeleting = true; } else if (isDeleting && charIndex === 0) { isDeleting = false; stringIndex = (stringIndex + 1) % CONFIG.typingStrings.length; delay = 400; } setTimeout(type, delay); } setTimeout(type, 1200); } // ─── SCROLL REVEAL ─── function initScrollReveal() { const elements = $$('[data-animate]'); if (!elements.length) return; const observer = new IntersectionObserver((entries) => { entries.forEach((entry, index) => { if (entry.isIntersecting) { setTimeout(() => { entry.target.classList.add('visible'); }, index * 100); observer.unobserve(entry.target); } }); }, { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }); elements.forEach(el => observer.observe(el)); } // ─── SKILL BARS ANIMATION ─── function initSkillBars() { const bars = $$('.bar-fill'); if (!bars.length) return; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const bar = entry.target; const width = bar.getAttribute('data-width'); bar.style.setProperty('--target-width', width + '%'); bar.classList.add('animated'); observer.unobserve(bar); } }); }, { threshold: 0.5 }); bars.forEach(bar => observer.observe(bar)); } // ─── PARTICLE SYSTEM ─── function initParticles() { const canvas = $('#particles'); if (!canvas) return; const ctx = canvas.getContext('2d'); let particles = []; let animationId; let mouseX = -1000; let mouseY = -1000; function resize() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } function createParticle() { return { x: Math.random() * canvas.width, y: Math.random() * canvas.height, vx: (Math.random() - 0.5) * CONFIG.particleMaxSpeed, vy: (Math.random() - 0.5) * CONFIG.particleMaxSpeed, size: Math.random() * 1.5 + 0.5, opacity: Math.random() * 0.5 + 0.1, }; } function initParticleArray() { particles = []; for (let i = 0; i < CONFIG.particleCount; i++) { particles.push(createParticle()); } } function drawParticle(p) { ctx.beginPath(); ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2); ctx.fillStyle = `rgba(0, 255, 200, ${p.opacity})`; ctx.fill(); } function drawConnections() { for (let i = 0; i < particles.length; i++) { for (let j = i + 1; j < particles.length; j++) { const dx = particles[i].x - particles[j].x; const dy = particles[i].y - particles[j].y; const dist = Math.sqrt(dx * dx + dy * dy); if (dist < CONFIG.particleConnectionDist) { const opacity = (1 - dist / CONFIG.particleConnectionDist) * 0.15; ctx.beginPath(); ctx.moveTo(particles[i].x, particles[i].y); ctx.lineTo(particles[j].x, particles[j].y); ctx.strokeStyle = `rgba(0, 255, 200, ${opacity})`; ctx.lineWidth = 0.5; ctx.stroke(); } } } // Mouse connections particles.forEach(p => { const dx = p.x - mouseX; const dy = p.y - mouseY; const dist = Math.sqrt(dx * dx + dy * dy); if (dist < 200) { const opacity = (1 - dist / 200) * 0.3; ctx.beginPath(); ctx.moveTo(p.x, p.y); ctx.lineTo(mouseX, mouseY); ctx.strokeStyle = `rgba(0, 255, 200, ${opacity})`; ctx.lineWidth = 0.8; ctx.stroke(); } }); } function update() { particles.forEach(p => { p.x += p.vx; p.y += p.vy; // Wrap around if (p.x < 0) p.x = canvas.width; if (p.x > canvas.width) p.x = 0; if (p.y < 0) p.y = canvas.height; if (p.y > canvas.height) p.y = 0; // Mouse repulsion const dx = p.x - mouseX; const dy = p.y - mouseY; const dist = Math.sqrt(dx * dx + dy * dy); if (dist < 100) { const force = (100 - dist) / 100 * 0.02; p.vx += (dx / dist) * force; p.vy += (dy / dist) * force; } // Speed limit const speed = Math.sqrt(p.vx * p.vx + p.vy * p.vy); if (speed > CONFIG.particleMaxSpeed * 2) { p.vx *= 0.98; p.vy *= 0.98; } }); } function animate() { ctx.clearRect(0, 0, canvas.width, canvas.height); update(); drawConnections(); particles.forEach(drawParticle); animationId = requestAnimationFrame(animate); } // Event listeners window.addEventListener('resize', () => { resize(); initParticleArray(); }); window.addEventListener('mousemove', (e) => { mouseX = e.clientX; mouseY = e.clientY; }, { passive: true }); window.addEventListener('mouseleave', () => { mouseX = -1000; mouseY = -1000; }); // Visibility API - pause when tab hidden document.addEventListener('visibilitychange', () => { if (document.hidden) { cancelAnimationFrame(animationId); } else { animate(); } }); resize(); initParticleArray(); animate(); } // ─── GLITCH EFFECT (random intensification) ─── function initGlitchEffect() { const glitch = $('.glitch'); if (!glitch) return; setInterval(() => { glitch.classList.add('glitch-active'); setTimeout(() => glitch.classList.remove('glitch-active'), 200); }, 5000 + Math.random() * 5000); } // ─── TERMINAL ANIMATION ─── function initTerminal() { const terminal = $('#terminal'); if (!terminal) return; const commands = [ { prompt: 'uptime', output: ' up 47 days, 3:22, 1 user, load: 0.12' }, { prompt: 'df -h / | tail -1', output: '/dev/sda1 50G 12G 36G 25% /' }, { prompt: 'curl -s ifconfig.me', output: '███.███.███.███' }, { prompt: 'docker ps --format "table {{.Names}}"', output: 'gitea\nnginx-proxy\nagent-zero\nmonitoring' }, { prompt: 'echo $SHELL', output: '/bin/zsh' }, { prompt: 'neofetch --off | head -3', output: 'OS: Debian GNU/Linux 12\nKernel: 6.1.0-18-amd64\nUptime: 47 days, 3 hours' }, ]; let cmdIndex = 0; function addTermLine(content, isOutput = false) { const line = document.createElement('div'); line.className = 'term-line' + (isOutput ? ' term-output' : ''); if (isOutput) { line.textContent = content; } else { line.innerHTML = `jae@swift:~$ ${content}`; } // Insert before the last line (cursor line) const cursorLine = terminal.lastElementChild; terminal.insertBefore(line, cursorLine); } function typeCommand() { if (cmdIndex >= commands.length) cmdIndex = 0; const cmd = commands[cmdIndex]; let charIdx = 0; // Remove old cursor line, add new command line being typed const cursorLine = terminal.lastElementChild; const typingLine = document.createElement('div'); typingLine.className = 'term-line'; typingLine.innerHTML = `jae@swift:~$ `; terminal.insertBefore(typingLine, cursorLine); cursorLine.remove(); const cmdSpan = typingLine.querySelector('.term-cmd'); function typeChar() { if (charIdx < cmd.prompt.length) { cmdSpan.textContent += cmd.prompt[charIdx]; charIdx++; setTimeout(typeChar, 50 + Math.random() * 80); } else { // Remove cursor from typing line const cursor = typingLine.querySelector('.term-cursor'); if (cursor) cursor.remove(); // Show output setTimeout(() => { const outputLines = cmd.output.split('\n'); outputLines.forEach(line => { const outputEl = document.createElement('div'); outputEl.className = 'term-line term-output'; outputEl.textContent = line; terminal.appendChild(outputEl); }); // Add new cursor line const newCursor = document.createElement('div'); newCursor.className = 'term-line'; newCursor.innerHTML = `jae@swift:~$ `; terminal.appendChild(newCursor); // Scroll terminal terminal.scrollTop = terminal.scrollHeight; // Keep only last ~15 lines while (terminal.children.length > 15) { terminal.removeChild(terminal.firstChild); } cmdIndex++; }, 300); } } typeChar(); } // Run terminal animation every 6-10 seconds setInterval(typeCommand, 8000 + Math.random() * 4000); } // ─── CONTACT FORM ─── function initContactForm() { const form = $('#contactForm'); if (!form) return; form.addEventListener('submit', (e) => { e.preventDefault(); const btn = form.querySelector('.form-submit'); const originalText = btn.querySelector('.submit-text').textContent; btn.querySelector('.submit-text').textContent = 'TRANSMITTING...'; btn.disabled = true; btn.style.borderColor = 'var(--warning)'; btn.style.color = 'var(--warning)'; setTimeout(() => { btn.querySelector('.submit-text').textContent = '✓ TRANSMITTED'; btn.style.borderColor = 'var(--accent)'; btn.style.color = 'var(--accent)'; setTimeout(() => { btn.querySelector('.submit-text').textContent = originalText; btn.disabled = false; btn.style.borderColor = ''; btn.style.color = ''; form.reset(); }, 2000); }, 1500); }); } // ─── FOOTER SIGNAL ANIMATION ─── function initFooterSignal() { const signal = $('#footerSignal'); if (!signal) return; const blocks = ['░', '█']; function update() { const strength = 6 + Math.floor(Math.random() * 4); // 6-9 out of 10 let bar = ''; for (let i = 0; i < 10; i++) { bar += i < strength ? blocks[1] : blocks[0]; } signal.textContent = `SIGNAL: ${bar} ${strength * 10}%`; } setInterval(update, 3000); } // ─── RANDOM HUD DATA FLICKERS ─── function initHUDFlickers() { const statValues = $$('.stat-value:not(.stat-online)'); setInterval(() => { statValues.forEach(el => { if (Math.random() > 0.7) { el.style.opacity = '0.3'; setTimeout(() => { el.style.opacity = '1'; }, 100 + Math.random() * 200); } }); }, 2000); } // ─── PANEL HOVER GLOW TRAIL ─── function initPanelGlow() { $$('.panel, .blog-card, .dev-card, .link-card').forEach(card => { card.addEventListener('mousemove', (e) => { const rect = card.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; card.style.setProperty('--mouse-x', `${x}px`); card.style.setProperty('--mouse-y', `${y}px`); card.style.background = `radial-gradient(circle 200px at ${x}px ${y}px, rgba(0, 255, 200, 0.04), var(--bg-panel))`; }); card.addEventListener('mouseleave', () => { card.style.background = ''; }); }); } // ─── INIT ─── // ─── NETWORK GRAPH ─── function initNetworkGraph() { const canvas = document.getElementById('networkGraph'); if (!canvas) return; const ctx = canvas.getContext('2d'); function resize() { const rect = canvas.parentElement.getBoundingClientRect(); canvas.width = rect.width; canvas.height = 100; } resize(); window.addEventListener('resize', resize); const dlData = []; const ulData = []; const maxPoints = 80; // Seed initial data for (let i = 0; i < maxPoints; i++) { dlData.push(30 + Math.random() * 40); ulData.push(20 + Math.random() * 30); } function drawLine(data, color, alpha) { const w = canvas.width; const h = canvas.height; const step = w / (maxPoints - 1); ctx.beginPath(); ctx.strokeStyle = color; ctx.lineWidth = 1.5; ctx.globalAlpha = alpha; for (let i = 0; i < data.length; i++) { const x = i * step; const y = h - (data[i] / 100) * h; if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y); } ctx.stroke(); // Fill under the line ctx.lineTo(canvas.width, canvas.height); ctx.lineTo(0, canvas.height); ctx.closePath(); ctx.fillStyle = color; ctx.globalAlpha = alpha * 0.08; ctx.fill(); ctx.globalAlpha = 1; } function drawGrid() { const w = canvas.width; const h = canvas.height; ctx.strokeStyle = 'rgba(0,255,200,0.06)'; ctx.lineWidth = 0.5; // Horizontal for (let y = 0; y < h; y += 20) { ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(w, y); ctx.stroke(); } // Vertical for (let x = 0; x < w; x += 30) { ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, h); ctx.stroke(); } } function updateStats() { const dl = dlData[dlData.length - 1]; const ul = ulData[ulData.length - 1]; const dlEl = document.getElementById('dlSpeed'); const ulEl = document.getElementById('ulSpeed'); const pkEl = document.getElementById('packetCount'); if (dlEl) dlEl.textContent = (dl * 0.032).toFixed(1) + ' Gbps'; if (ulEl) ulEl.textContent = (ul * 0.028).toFixed(1) + ' Gbps'; if (pkEl) pkEl.textContent = Math.floor(dl * 180).toLocaleString() + ' pkt/s'; } function animate() { ctx.clearRect(0, 0, canvas.width, canvas.height); drawGrid(); // Push new data const lastDl = dlData[dlData.length - 1]; const lastUl = ulData[ulData.length - 1]; dlData.push(Math.max(10, Math.min(95, lastDl + (Math.random() - 0.48) * 12))); ulData.push(Math.max(5, Math.min(85, lastUl + (Math.random() - 0.48) * 10))); if (dlData.length > maxPoints) dlData.shift(); if (ulData.length > maxPoints) ulData.shift(); drawLine(dlData, '#00ffc8', 0.9); drawLine(ulData, '#00a8ff', 0.6); updateStats(); requestAnimationFrame(animate); } animate(); } // ─── METRIC BARS (fluctuating) ─── function initMetricBars() { const metrics = [ { bar: 'cpuBar', val: 'cpuVal', base: 23, range: 18 }, { bar: 'memBar', val: 'memVal', base: 67, range: 8 }, { bar: 'diskBar', val: 'diskVal', base: 45, range: 25 }, { bar: 'bwBar', val: 'bwVal', base: 78, range: 15 }, ]; function updateMetrics() { metrics.forEach(m => { const barEl = document.getElementById(m.bar); const valEl = document.getElementById(m.val); if (!barEl || !valEl) return; const val = Math.max(5, Math.min(98, m.base + (Math.random() - 0.5) * m.range)); barEl.style.width = val + '%'; valEl.textContent = Math.round(val) + '%'; // Colour shift for high values if (val > 85) { barEl.style.background = 'linear-gradient(90deg, #ff4757, rgba(255,71,87,0.4))'; barEl.style.boxShadow = '0 0 8px rgba(255,71,87,0.4)'; valEl.style.color = '#ff4757'; } else if (val > 70) { barEl.style.background = 'linear-gradient(90deg, #ffa502, rgba(255,165,2,0.4))'; barEl.style.boxShadow = '0 0 8px rgba(255,165,2,0.3)'; valEl.style.color = '#ffa502'; } else { barEl.style.background = ''; barEl.style.boxShadow = ''; valEl.style.color = ''; } }); } updateMetrics(); setInterval(updateMetrics, 2000 + Math.random() * 1000); } // ─── SCAN BAR ─── function initScanBar() { const fill = document.getElementById('scanFill'); const pct = document.getElementById('scanPct'); if (!fill || !pct) return; let progress = 0; function tick() { progress += 0.5 + Math.random() * 1.5; if (progress >= 100) { progress = 0; fill.style.transition = 'none'; fill.style.width = '0%'; pct.textContent = '0%'; setTimeout(() => { fill.style.transition = 'width 0.3s linear'; requestAnimationFrame(tick); }, 800); return; } fill.style.width = progress + '%'; pct.textContent = Math.round(progress) + '%'; setTimeout(tick, 80 + Math.random() * 120); } fill.style.transition = 'width 0.3s linear'; tick(); } // ─── POWER FLICKER ─── function initPowerFlicker() { const el = document.getElementById('powerPct'); if (!el) return; setInterval(() => { const vals = [97, 98, 99, 98, 100, 98, 97, 99]; const v = vals[Math.floor(Math.random() * vals.length)]; el.innerHTML = v + '%'; }, 4000); } // ─── SERVER HEALTH ─── function initServerHealth() { const el = document.getElementById('serverHealth'); if (!el) return; setInterval(() => { const v = 95 + Math.floor(Math.random() * 5); el.textContent = v + '%'; }, 5000); } // ─── API CONFIG ─── const API_BASE = window.location.hostname === 'localhost' ? 'http://localhost:5000' : '/api'; // ─── BLOG FEED (dynamic from API) ─── function initBlogFeed() { const grid = document.getElementById('blogGrid'); if (!grid) return; fetch(API_BASE + '/posts') .then(r => r.json()) .then(posts => { posts.sort((a, b) => new Date(b.date) - new Date(a.date)); const latest = posts.slice(0, 3); if (latest.length === 0) { grid.innerHTML = '
NO TRANSMISSIONS FOUND
'; return; } grid.innerHTML = latest.map((post, i) => `
${post.date.replace(/-/g, '.')} ${(post.tags && post.tags[0]) ? post.tags[0].toUpperCase() : 'POST'}

${post.title}

${post.excerpt || (post.content || '').substring(0, 120) + '...'}

`).join(''); // Animate cards in requestAnimationFrame(() => { grid.querySelectorAll('.blog-card').forEach(card => { card.style.opacity = '1'; card.style.transform = 'translateY(0)'; }); }); }) .catch(() => { grid.innerHTML = '
SIGNAL LOST — RETRY LATER
'; }); } // ─── LIVE SERVER STATS (from API) ─── function initLiveStats() { function fetchStats() { fetch(API_BASE + '/stats') .then(r => r.json()) .then(d => { // Update metric bars with real data const metrics = [ { bar: 'cpuBar', val: 'cpuVal', value: d.cpu_percent }, { bar: 'memBar', val: 'memVal', value: d.memory_percent }, { bar: 'diskBar', val: 'diskVal', value: d.disk_percent }, ]; metrics.forEach(m => { const barEl = document.getElementById(m.bar); const valEl = document.getElementById(m.val); if (!barEl || !valEl) return; barEl.style.width = m.value + '%'; valEl.textContent = Math.round(m.value) + '%'; if (m.value > 85) { barEl.style.background = 'linear-gradient(90deg, #ff4757, rgba(255,71,87,0.4))'; barEl.style.boxShadow = '0 0 8px rgba(255,71,87,0.4)'; valEl.style.color = '#ff4757'; } else if (m.value > 70) { barEl.style.background = 'linear-gradient(90deg, #ffa502, rgba(255,165,2,0.4))'; barEl.style.boxShadow = '0 0 8px rgba(255,165,2,0.3)'; valEl.style.color = '#ffa502'; } else { barEl.style.background = ''; barEl.style.boxShadow = ''; valEl.style.color = ''; } }); // Update uptime from real data const uptimeEl = document.getElementById('uptime'); if (uptimeEl && d.uptime_seconds) { const totalSec = Math.floor(d.uptime_seconds); const days = Math.floor(totalSec / 86400); const hours = Math.floor((totalSec % 86400) / 3600); const mins = Math.floor((totalSec % 3600) / 60); uptimeEl.textContent = days + 'd ' + String(hours).padStart(2, '0') + 'h ' + String(mins).padStart(2, '0') + 'm'; } // Update server health const healthEl = document.getElementById('serverHealth'); if (healthEl) { const health = Math.round(100 - (d.cpu_percent * 0.3 + d.memory_percent * 0.3 + d.disk_percent * 0.4) / 3); healthEl.textContent = Math.min(99, Math.max(80, health)) + '%'; } // Container counts const containerEl = document.getElementById('containerUp'); const containerTotalEl = document.querySelector('.container-total'); if (containerEl) containerEl.textContent = d.container_running; if (containerTotalEl) containerTotalEl.textContent = d.container_total; }) .catch(() => {}); } fetchStats(); setInterval(fetchStats, 10000); // refresh every 10s } // ─── LIVE WEATHER ─── function initLiveWeather() { const tempEl = document.getElementById('weatherTemp'); const condEl = document.getElementById('weatherCond'); if (!tempEl && !condEl) return; fetch(API_BASE + '/weather') .then(r => r.json()) .then(d => { if (tempEl) tempEl.textContent = d.temp_c + '°C'; if (condEl) condEl.textContent = d.condition; const feelsEl = document.getElementById('weatherFeels'); if (feelsEl) feelsEl.textContent = 'FEELS ' + d.feels_like + '°C'; const windEl = document.getElementById('weatherWind'); if (windEl) windEl.textContent = d.wind_kph + ' KPH ' + d.wind_dir; const humEl = document.getElementById('weatherHumidity'); if (humEl) humEl.textContent = d.humidity + '% RH'; }) .catch(() => {}); } // ─── NOW PLAYING ─── function initNowPlaying() { const trackEl = document.getElementById('npTrack'); const artistEl = document.getElementById('npArtist'); if (!trackEl && !artistEl) return; function fetchTrack() { fetch(API_BASE + '/nowplaying') .then(r => r.json()) .then(d => { if (trackEl) trackEl.textContent = d.track; if (artistEl) artistEl.textContent = d.artist; const albumEl = document.getElementById('npAlbum'); if (albumEl) albumEl.textContent = d.album; }) .catch(() => {}); } fetchTrack(); setInterval(fetchTrack, 30000); } document.addEventListener('DOMContentLoaded', () => { initNavbar(); initClock(); initUptime(); initTyping(); initScrollReveal(); initSkillBars(); initParticles(); initGlitchEffect(); initTerminal(); initContactForm(); initFooterSignal(); initHUDFlickers(); initPanelGlow(); initNetworkGraph(); initMetricBars(); initScanBar(); initPowerFlicker(); initServerHealth(); // Live API integrations initBlogFeed(); initLiveStats(); initLiveWeather(); initNowPlaying(); // Page load animation document.body.style.opacity = '0'; document.body.style.transition = 'opacity 0.8s ease'; requestAnimationFrame(() => { document.body.style.opacity = '1'; }); console.log('%c[JAESWIFT] %cSystems Online', 'color: #00ffc8; font-weight: bold; font-size: 14px;', 'color: #c8d6e5; font-size: 12px;'); }); })();