(() => { const USR = 'mileswolfallen2'; const ASCII = ` ██╗ ██╗██████╗ ██████╗ ███████╗██╗ ██████╗ ██╗ ██╗ ██║ ██║██╔══██╗██╔═══██╗██╔════╝██║ ██╔═══██╗██║ ██║ ██║ ██║██████╔╝██║ ██║███████╗██║ ██║ ██║██║ █╗ ██║ ██║ ██║██╔══██╗██║ ██║╚════██║██║ ██║ ██║██║███╗██║ ╚██████╔╝██║ ██║╚██████╔╝███████║███████╗╚██████╔╝╚███╔███╔╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚══════╝ ╚═════╝ ╚══╝╚══╝`.trim(); const bootLines = [ 'BIOS v4.0 — Miles Systems Inc.', 'Copyright (c) 2026 Miles Allen', '', 'Memory Test: 640K OK', 'Detecting hardware...', ' CPU: Developer Core™ @ 3.5GHz', ' GPU: Pixel Renderer v2.0', ' RAM: 640K Conventional + 384K Extended', ' HDD: 42 Repos Detected', '', 'Loading MILES.EXE...', ' [████████████████████████] 100%', '', 'Connecting to GitHub API...', ' Status: CONNECTED', '', 'Connecting to FEDL Server...', ' Status: ONLINE', '', 'Initializing Portfolio v4.0...', ' Rendering interface... DONE', '', 'System Ready. Type HELP for commands.', '> Starting MILES.EXE...' ]; const bootScreen = document.getElementById('boot-screen'); const bootText = document.getElementById('boot-text'); const site = document.getElementById('site'); let bootIndex = 0; function typeBoot() { if (bootIndex >= bootLines.length) { setTimeout(() => { bootScreen.classList.add('done'); site.classList.remove('hidden'); initSite(); }, 300); return; } bootText.textContent += (bootIndex === 0 ? '' : '\n') + bootLines[bootIndex]; bootIndex++; const delay = bootLines[bootIndex - 1] === '' ? 200 : bootLines[bootIndex - 1].startsWith(' [') ? 20 : 60; setTimeout(typeBoot, delay); } setTimeout(typeBoot, 400); // ═══════════ SITE INIT ═══════════ function initSite() { renderAsciiArt(); renderSkills(); renderTools(); loadGitHub(); loadFEDL(); startClock(); initNav(); initScrollSpy(); initFilters(); } // ═══════════ ASCII ART ═══════════ function renderAsciiArt() { const el = document.getElementById('ascii-art'); if (!el) return; el.textContent = ASCII; } // ═══════════ CLOCK ═══════════ function startClock() { const el = document.getElementById('menu-clock'); function tick() { const now = new Date(); el.textContent = now.toLocaleTimeString('en-US', { hour12: false }); } tick(); setInterval(tick, 1000); } // ═══════════ NAVIGATION ═══════════ function initNav() { document.querySelectorAll('.nav-link').forEach(link => { link.addEventListener('click', e => { e.preventDefault(); const target = link.getAttribute('href').slice(1); document.getElementById(target)?.scrollIntoView({ behavior: 'smooth' }); }); }); } // ═══════════ SCROLL SPY ═══════════ let spyTicking = false; function initScrollSpy() { const sections = document.querySelectorAll('.section'); const links = document.querySelectorAll('.nav-link'); function update() { const scrollY = window.scrollY + 120; let current = 'home'; sections.forEach(sec => { if (sec.offsetTop <= scrollY) current = sec.id; }); links.forEach(l => { const isActive = l.dataset.section === current; l.classList.toggle('active', isActive); }); sections.forEach(sec => { sec.classList.toggle('active-section', sec.id === current); }); spyTicking = false; } window.addEventListener('scroll', () => { if (!spyTicking) { spyTicking = true; requestAnimationFrame(update); } }); setTimeout(update, 100); } // ═══════════ GITHUB API ═══════════ async function loadGitHub() { try { const userRes = await fetch(`https://api.github.com/users/${USR}`); if (!userRes.ok) throw new Error(userRes.status); const user = await userRes.json(); animateNum('stat-repos', user.public_repos || 0, 147); animateNum('stat-followers', user.followers || 0, 12); animateNum('stat-gists', user.public_gists || 0, 1); document.getElementById('stat-joined').textContent = new Date(user.created_at).getFullYear().toString(); animateBar('bar-joined', 80); const reposRes = await fetch(`https://api.github.com/users/${USR}/repos?per_page=100&sort=updated`); if (!reposRes.ok) throw new Error(reposRes.status); const repos = await reposRes.json(); let totalStars = 0, totalForks = 0; repos.forEach(r => { totalStars += r.stargazers_count || 0; totalForks += r.forks_count || 0; }); animateNum('stat-stars', totalStars, 50); animateNum('stat-forks', totalForks, 30); animateBar('bar-repos', Math.min(100, (user.public_repos / 150) * 100)); animateBar('bar-stars', Math.min(100, totalStars * 10)); animateBar('bar-forks', Math.min(100, totalForks * 10)); animateBar('bar-followers', Math.min(100, (user.followers / 20) * 100)); animateBar('bar-gists', Math.min(100, user.public_gists * 20)); try { const eventsRes = await fetch(`https://api.github.com/users/${USR}/events/public?per_page=15`); if (eventsRes.ok) { const events = await eventsRes.json(); renderActivity(events.slice(0, 10)); } } catch (e) { /* skip */ } renderProjects(repos); document.getElementById('sb-status').textContent = 'GitHub API: Connected (' + repos.length + ' repos)'; } catch (err) { document.getElementById('sb-status').textContent = 'GitHub API: Error — retrying...'; document.getElementById('activity-log').innerHTML = `
> API error: ${err.message}
`; setTimeout(loadGitHub, 30000); } } // ═══════════ FEDL API ═══════════ const FEDL_BASE = 'https://server.fedl.site/fedl'; async function loadFEDL() { try { const [listRes, runsRes, ghRes] = await Promise.allSettled([ fetch(`${FEDL_BASE}/api/list`), fetch(`${FEDL_BASE}/api/runs`), fetch(`https://api.github.com/repos/${USR}/fedl`) ]); if (listRes.status === 'fulfilled' && listRes.value.ok) { const listData = await listRes.value.json(); const levels = listData.items || []; animateNum('fedl-levels', levels.length, 30); const firstLevel = levels[0]; if (firstLevel) { document.getElementById('fedl-top1').textContent = (firstLevel.title || firstLevel.name || '').slice(0, 14) || '#1'; } } if (runsRes.status === 'fulfilled' && runsRes.value.ok) { const runsData = await runsRes.value.json(); const runs = runsData.items || []; const verified = runs.filter(r => r.status === 'approved'); animateNum('fedl-runs', verified.length, 25); const playerCounts = {}; verified.forEach(r => { const name = r.playerName || r.player || 'Unknown'; playerCounts[name] = (playerCounts[name] || 0) + 1; }); const topPlayer = Object.entries(playerCounts).sort((a, b) => b[1] - a[1])[0]; if (topPlayer) { document.getElementById('fedl-topplayer').textContent = topPlayer[0].slice(0, 14); } animateNum('fedl-players', Object.keys(playerCounts).length, 20); const sorted = [...verified].sort((a, b) => new Date(b.reviewedAt || b.submittedAt || 0) - new Date(a.reviewedAt || a.submittedAt || 0) ); if (sorted[0]) { const date = sorted[0].reviewedAt || sorted[0].submittedAt; document.getElementById('fedl-updated').textContent = date ? getTimeAgo(date) : 'recently'; } } if (ghRes.status === 'fulfilled' && ghRes.value.ok) { const gh = await ghRes.value.json(); animateNum('fedl-stars', gh.stargazers_count || 0, 30); document.getElementById('fedl-lang').textContent = gh.language || 'HTML'; if (!document.getElementById('fedl-updated').textContent || document.getElementById('fedl-updated').textContent === '—') { document.getElementById('fedl-updated').textContent = getTimeAgo(gh.pushed_at); } } } catch (err) { console.error('FEDL load error:', err); } } // ═══════════ RENDER ═══════════ function renderActivity(events) { const log = document.getElementById('activity-log'); log.innerHTML = events.map(e => { let dot = 'other', msg = e.type; if (e.type === 'PushEvent') { dot = 'push'; msg = `Push ${e.payload.commits?.length || 0} commit(s)`; } else if (e.type === 'CreateEvent') { dot = 'create'; msg = `Create ${e.payload.ref_type}`; } else if (e.type === 'DeleteEvent') { msg = `Delete ${e.payload.ref_type}`; } else if (e.type === 'IssuesEvent') { msg = `${e.payload.action} issue`; } else if (e.type === 'WatchEvent') { msg = 'Star'; } else if (e.type === 'ForkEvent') { msg = 'Fork'; } else if (e.type === 'PullRequestEvent') { msg = `${e.payload.action} PR`; } return `
${(e.repo?.name || '').replace(USR + '/', '')} ${msg} ${getTimeAgo(e.created_at)}
`; }).join(''); } const SITE_URLS = { 'fedl': 'https://fedl.site', 'miles-web': 'https://me.fedl.site', 'OmniEmu2.0': 'https://github.com/mileswolfallen2/OmniEmu2.0', 'moon-gaming': 'https://moon-gaming.vercel.app', 'linuxWeb': 'https://linuxweb.vercel.app', 'FNFHTML5': 'https://fnfhtml5.pages.dev', 'fun-miles-lancher': 'https://github.com/mileswolfallen2/fun-miles-lancher', 'goplayer': 'https://github.com/mileswolfallen2/goplayer' }; const PINNED = ['OmniEmu2.0', 'fedl', 'moon-gaming', 'miles-web']; const ICONS = { 'OmniEmu2.0': '🎮', 'fedl': '🎯', 'moon-gaming': '🌙', 'miles-web': '🌐', 'linuxWeb': '🐧', 'FNFHTML5': '🎵', 'fun-miles-lancher': '🚀', 'the-start-of-the-thing': '⭐', 'for-a-frend': '🤝', 'v86-wasmless': '💻', 'goplayer': '🎶', 'open-fl-test': '🧪', 'A1R': '✈️' }; function renderProjects(repos) { const list = document.getElementById('projects-list'); const sorted = repos.sort((a, b) => { const ai = PINNED.indexOf(a.name), bi = PINNED.indexOf(b.name); if (ai !== -1 && bi !== -1) return ai - bi; if (ai !== -1) return -1; if (bi !== -1) return 1; return (b.stargazers_count || 0) - (a.stargazers_count || 0); }).slice(0, 20); list.innerHTML = sorted.map(r => { const icon = ICONS[r.name] || '📁'; const desc = r.description || 'No description.'; const isFork = r.fork; const url = SITE_URLS[r.name] || r.homepage || `https://github.com/${USR}/${r.name}`; return ` ${icon}
${r.name}
${desc}
${r.language ? `${r.language}` : ''} ${r.stargazers_count > 0 ? `★ ${r.stargazers_count}` : ''} ${isFork ? `FORK` : ''}
OPEN →
`; }).join(''); } // ═══════════ FILTERS ═══════════ function initFilters() { document.querySelectorAll('.pf-btn').forEach(btn => { btn.addEventListener('click', () => { document.querySelectorAll('.pf-btn').forEach(b => b.classList.remove('active')); btn.classList.add('active'); const filter = btn.dataset.filter; document.querySelectorAll('.project-row').forEach(row => { if (filter === 'all') { row.style.display = ''; return; } row.style.display = row.dataset.type === filter ? '' : 'none'; }); }); }); } // ═══════════ SKILLS ═══════════ function renderSkills() { const skills = [ { name: 'Python', pct: 80, color: 'green' }, { name: 'JavaScript', pct: 75, color: 'amber' }, { name: 'C++', pct: 55, color: 'cyan' }, { name: 'HTML/CSS', pct: 85, color: 'green' }, { name: 'React', pct: 60, color: 'purple' }, { name: 'Node.js', pct: 65, color: 'green' }, { name: 'Git', pct: 80, color: 'cyan' }, { name: 'Linux', pct: 75, color: 'amber' } ]; document.getElementById('skills-list').innerHTML = skills.map(s => `
${s.name}
${s.pct}%
` ).join(''); setTimeout(() => { document.querySelectorAll('.skill-fill').forEach(f => { f.style.width = f.dataset.pct + '%'; }); }, 300); } function renderTools() { const tools = ['VS Code', 'Git', 'GitHub', 'Replit', 'Node.js', 'Electron', 'Linux', 'Firefox DevTools', 'Figma', 'Docker', 'SQLite', 'Geode']; document.getElementById('tools-grid').innerHTML = tools.map(t => `${t}` ).join(''); } // ═══════════ UTILITIES ═══════════ function animateNum(id, target, speed) { const el = document.getElementById(id); if (!el) return; let current = 0; const steps = speed || 30; const step = Math.max(1, Math.floor(target / steps)); const interval = setInterval(() => { current += step; if (current >= target) { current = target; clearInterval(interval); } el.textContent = current.toLocaleString(); }, 30); } function animateBar(id, pct) { const el = document.getElementById(id); if (!el) return; setTimeout(() => { el.style.width = pct + '%'; }, 200); } function getTimeAgo(dateStr) { const now = new Date(); const then = new Date(dateStr); const mins = Math.floor((now - then) / 60000); if (mins < 1) return 'just now'; if (mins < 60) return `${mins}m ago`; const hrs = Math.floor(mins / 60); if (hrs < 24) return `${hrs}h ago`; const days = Math.floor(hrs / 24); if (days < 30) return `${days}d ago`; const months = Math.floor(days / 30); if (months < 12) return `${months}mo ago`; return `${Math.floor(months / 12)}y ago`; } setInterval(() => { loadGitHub(); loadFEDL(); }, 300000); })();