Files
miles-web/index.html
T
2026-07-25 17:00:36 -05:00

1267 lines
51 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Miles Wolf Allen | Developer & 3D Artist</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700;800;900&family=Fraunces:opsz,[email protected],300;9..144,400;9..144,500;9..144,600;9..144,700;9..144,800;9..144,900&display=swap" rel="stylesheet">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
:root {
--bg: #05050a;
--surface: rgba(15, 15, 25, 0.7);
--surface-solid: #0f0f19;
--border: rgba(255, 255, 255, 0.06);
--border-bright: rgba(255, 255, 255, 0.12);
--text: #f0f0f5;
--text-dim: #6b6b80;
--accent: #0ea5e9;
--accent-2: #34d399;
--accent-3: #f97316;
--green: #34d399;
--orange: #f97316;
--glow: rgba(14, 165, 233, 0.4);
--glow-2: rgba(52, 211, 153, 0.3);
}
body {
font-family: 'Montserrat', -apple-system, BlinkMacSystemFont, sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.6;
overflow-x: hidden;
-webkit-font-smoothing: antialiased;
}
h1, h2, h3, .hero h1, .section-header h2 {
font-family: 'Fraunces', serif;
}
/* ANIMATED MESH BACKGROUND */
.mesh-bg {
position: fixed;
inset: 0;
z-index: 0;
overflow: hidden;
}
.mesh-bg::before {
content: '';
position: absolute;
width: 150%;
height: 150%;
top: -25%;
left: -25%;
background:
radial-gradient(ellipse 600px 600px at 20% 20%, rgba(14, 165, 233, 0.12) 0%, transparent 70%),
radial-gradient(ellipse 500px 500px at 80% 30%, rgba(0, 212, 255, 0.08) 0%, transparent 70%),
radial-gradient(ellipse 400px 400px at 50% 80%, rgba(255, 92, 170, 0.06) 0%, transparent 70%);
animation: meshMove 20s ease-in-out infinite alternate;
}
@keyframes meshMove {
0% { transform: translate(0, 0) scale(1); }
33% { transform: translate(30px, -20px) scale(1.02); }
66% { transform: translate(-20px, 30px) scale(0.98); }
100% { transform: translate(10px, -10px) scale(1.01); }
}
.grid-overlay {
position: fixed;
inset: 0;
background-image:
linear-gradient(rgba(255, 255, 255, 0.015) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.015) 1px, transparent 1px);
background-size: 80px 80px;
mask-image: radial-gradient(ellipse at center, black 30%, transparent 70%);
-webkit-mask-image: radial-gradient(ellipse at center, black 30%, transparent 70%);
pointer-events: none;
z-index: 1;
}
.noise {
position: fixed;
inset: 0;
opacity: 0.03;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
pointer-events: none;
z-index: 1;
}
.container {
max-width: 1100px;
margin: 0 auto;
padding: 0 28px;
position: relative;
z-index: 2;
}
/* NAV */
nav {
padding: 28px 0;
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
z-index: 10;
}
.nav-logo {
font-weight: 900;
font-size: 1.2rem;
color: var(--text);
text-decoration: none;
letter-spacing: -0.03em;
display: flex;
align-items: center;
gap: 8px;
}
.nav-logo .dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: var(--accent);
box-shadow: 0 0 12px var(--glow);
animation: dotPulse 3s ease-in-out infinite;
}
@keyframes dotPulse {
0%, 100% { box-shadow: 0 0 12px var(--glow); }
50% { box-shadow: 0 0 24px var(--glow), 0 0 48px rgba(14, 165, 233, 0.2); }
}
.nav-links { display: flex; gap: 8px; align-items: center; }
.nav-links a {
color: var(--text-dim);
text-decoration: none;
font-size: 0.85rem;
font-weight: 500;
padding: 8px 14px;
border-radius: 8px;
transition: all 0.25s;
}
.nav-links a:hover {
color: var(--text);
background: rgba(255, 255, 255, 0.05);
}
.nav-links .theme-btn {
width: 36px;
height: 36px;
border-radius: 10px;
border: 1px solid var(--border);
background: var(--surface);
backdrop-filter: blur(12px);
color: var(--text-dim);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.25s;
margin-left: 8px;
}
.nav-links .theme-btn:hover {
border-color: var(--accent);
color: var(--text);
box-shadow: 0 0 16px rgba(14, 165, 233, 0.15);
}
.theme-btn svg { width: 16px; height: 16px; }
/* HERO */
.hero {
padding: 100px 0 80px;
text-align: center;
}
.hero-chip {
display: inline-flex;
align-items: center;
gap: 8px;
background: var(--surface);
backdrop-filter: blur(16px);
border: 1px solid var(--border);
padding: 8px 18px;
border-radius: 999px;
font-size: 0.8rem;
font-weight: 500;
color: var(--text-dim);
margin-bottom: 36px;
}
.hero-chip .live-dot {
width: 7px;
height: 7px;
border-radius: 50%;
background: var(--green);
box-shadow: 0 0 8px rgba(0, 255, 136, 0.5);
animation: livePulse 2s ease-in-out infinite;
}
@keyframes livePulse {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.5; transform: scale(0.8); }
}
.hero h1 {
font-size: clamp(3rem, 8vw, 5.5rem);
font-weight: 900;
letter-spacing: -0.05em;
line-height: 1.05;
margin-bottom: 24px;
}
.hero h1 .line { display: block; }
.hero h1 .grad {
background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 50%, var(--accent-3) 100%);
background-size: 200% 200%;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
animation: gradShift 6s ease-in-out infinite;
}
@keyframes gradShift {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
.hero-sub {
font-size: 1.15rem;
color: var(--text-dim);
max-width: 520px;
margin: 0 auto 40px;
line-height: 1.7;
}
.hero-actions {
display: flex;
gap: 12px;
justify-content: center;
flex-wrap: wrap;
}
.btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 14px 28px;
border-radius: 12px;
font-size: 0.9rem;
font-weight: 700;
text-decoration: none;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
cursor: pointer;
border: none;
font-family: inherit;
}
.btn-glow {
background: var(--accent);
color: #fff;
box-shadow: 0 0 20px rgba(14, 165, 233, 0.3), 0 4px 16px rgba(0, 0, 0, 0.3);
}
.btn-glow:hover {
transform: translateY(-2px);
box-shadow: 0 0 40px rgba(14, 165, 233, 0.5), 0 8px 32px rgba(0, 0, 0, 0.4);
}
.btn-glass {
background: var(--surface);
backdrop-filter: blur(12px);
color: var(--text);
border: 1px solid var(--border);
}
.btn-glass:hover {
border-color: var(--border-bright);
background: rgba(255, 255, 255, 0.08);
transform: translateY(-2px);
}
.btn svg { width: 16px; height: 16px; }
/* STATS BAR */
.stats-bar {
display: flex;
justify-content: center;
gap: 48px;
padding: 32px 0;
margin-bottom: 20px;
}
.stat-item { text-align: center; }
.stat-num {
font-size: 2.2rem;
font-weight: 900;
letter-spacing: -0.03em;
background: linear-gradient(135deg, var(--text), var(--accent));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.stat-label {
font-size: 0.75rem;
font-weight: 600;
color: var(--text-dim);
text-transform: uppercase;
letter-spacing: 0.1em;
}
/* SECTIONS */
.section {
padding: 64px 0;
position: relative;
}
.section-divider {
width: 60px;
height: 3px;
background: linear-gradient(90deg, var(--accent), var(--accent-2));
border-radius: 3px;
margin-bottom: 16px;
}
.section-header {
margin-bottom: 40px;
}
.section-header h2 {
font-size: 2.2rem;
font-weight: 900;
letter-spacing: -0.04em;
margin-bottom: 8px;
}
.section-header p {
color: var(--text-dim);
font-size: 1rem;
}
/* PROFILE CARD */
.profile-card {
background: var(--surface);
backdrop-filter: blur(20px);
border: 1px solid var(--border);
border-radius: 20px;
padding: 36px;
display: flex;
gap: 32px;
align-items: center;
position: relative;
overflow: hidden;
margin-bottom: 20px;
}
.profile-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(90deg, transparent, var(--accent), var(--accent-2), transparent);
opacity: 0.5;
}
.profile-avatar {
width: 100px;
height: 100px;
border-radius: 50%;
border: 3px solid var(--accent);
box-shadow: 0 0 30px rgba(14, 165, 233, 0.2);
flex-shrink: 0;
transition: transform 0.3s, box-shadow 0.3s;
}
.profile-avatar:hover {
transform: scale(1.05);
box-shadow: 0 0 50px rgba(14, 165, 233, 0.35);
}
.profile-info h2 {
font-size: 1.6rem;
font-weight: 800;
letter-spacing: -0.02em;
}
.profile-info .handle {
color: var(--accent);
font-size: 0.9rem;
font-weight: 600;
margin-bottom: 8px;
}
.profile-info .bio {
color: var(--text-dim);
font-size: 0.9rem;
margin-bottom: 12px;
}
.profile-stats {
display: flex;
gap: 20px;
}
.profile-stats .ps {
font-size: 0.85rem;
color: var(--text-dim);
}
.profile-stats .ps b {
color: var(--text);
font-weight: 700;
}
/* ACHIEVEMENTS */
.achievements {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.achievement {
background: var(--surface);
backdrop-filter: blur(12px);
border: 1px solid var(--border);
border-radius: 12px;
padding: 12px 18px;
display: flex;
align-items: center;
gap: 8px;
font-size: 0.82rem;
font-weight: 600;
transition: all 0.25s;
}
.achievement:hover {
border-color: var(--accent);
transform: translateY(-2px);
box-shadow: 0 4px 20px rgba(14, 165, 233, 0.1);
}
.achievement svg { width: 18px; height: 18px; color: var(--accent); }
/* SKILLS */
.skills-label {
font-size: 0.7rem;
font-weight: 700;
color: var(--text-dim);
text-transform: uppercase;
letter-spacing: 0.1em;
margin-bottom: 14px;
}
.skills-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
gap: 10px;
margin-bottom: 32px;
}
.skill {
background: var(--surface);
backdrop-filter: blur(12px);
border: 1px solid var(--border);
border-radius: 12px;
padding: 14px;
text-align: center;
font-size: 0.8rem;
font-weight: 600;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
cursor: default;
}
.skill:hover {
border-color: var(--accent);
background: rgba(14, 165, 233, 0.08);
transform: translateY(-3px);
box-shadow: 0 8px 30px rgba(14, 165, 233, 0.12);
}
.skill svg { width: 22px; height: 22px; color: var(--accent); }
/* PROJECTS */
.projects-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 16px;
}
.project-card {
background: var(--surface);
backdrop-filter: blur(16px);
border: 1px solid var(--border);
border-radius: 16px;
padding: 28px;
text-decoration: none;
color: var(--text);
transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
flex-direction: column;
position: relative;
overflow: hidden;
}
.project-card::after {
content: '';
position: absolute;
inset: 0;
border-radius: 16px;
padding: 1px;
background: linear-gradient(135deg, var(--accent), var(--accent-2), var(--accent-3));
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
opacity: 0;
transition: opacity 0.35s;
pointer-events: none;
}
.project-card:hover::after { opacity: 1; }
.project-card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3), 0 0 30px rgba(14, 165, 233, 0.08);
}
.project-card .pc-top {
display: flex;
justify-content: space-between;
align-items: start;
margin-bottom: 14px;
}
.project-card .pc-icon {
width: 40px;
height: 40px;
border-radius: 10px;
background: rgba(14, 165, 233, 0.1);
border: 1px solid rgba(14, 165, 233, 0.2);
display: flex;
align-items: center;
justify-content: center;
}
.project-card .pc-icon svg { width: 20px; height: 20px; color: var(--accent); }
.project-card .pc-tag {
font-size: 0.65rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.06em;
padding: 4px 10px;
border-radius: 6px;
border: 1px solid;
}
.pc-tag.active { color: var(--green); border-color: rgba(0, 255, 136, 0.3); background: rgba(0, 255, 136, 0.05); }
.pc-tag.community { color: var(--accent-2); border-color: rgba(0, 212, 255, 0.3); background: rgba(0, 212, 255, 0.05); }
.pc-tag.wip { color: #f59e0b; border-color: rgba(245, 158, 11, 0.3); background: rgba(245, 158, 11, 0.05); }
.pc-tag.lang { color: var(--text-dim); border-color: var(--border); background: transparent; }
.project-card h3 {
font-size: 1.15rem;
font-weight: 800;
letter-spacing: -0.02em;
margin-bottom: 8px;
}
.project-card p {
font-size: 0.85rem;
color: var(--text-dim);
line-height: 1.5;
flex: 1;
}
.project-card .pc-meta {
display: flex;
gap: 16px;
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid var(--border);
font-size: 0.75rem;
color: var(--text-dim);
font-weight: 500;
}
.project-card .pc-meta span {
display: flex;
align-items: center;
gap: 4px;
}
/* HIGHLIGHTS */
.hl-group { margin-bottom: 28px; }
.hl-group:last-child { margin-bottom: 0; }
.hl-group-label {
display: flex;
align-items: center;
gap: 8px;
font-family: 'Fraunces', serif;
font-size: 1.1rem;
font-weight: 700;
color: var(--text);
margin-bottom: 12px;
letter-spacing: -0.02em;
}
.hl-group-dot {
width: 8px; height: 8px;
border-radius: 50%;
display: inline-block;
}
.hl-group-dot.blue { background: var(--accent); box-shadow: 0 0 8px rgba(14,165,233,0.5); }
.hl-group-dot.green { background: var(--green); box-shadow: 0 0 8px rgba(52,211,153,0.5); }
.hl-group-dot.orange { background: var(--orange); box-shadow: 0 0 8px rgba(249,115,22,0.5); }
.hl-divider {
height: 1px;
background: linear-gradient(90deg, transparent, var(--border), transparent);
margin: 8px 0 24px;
}
.hl-hero {
background: var(--surface);
backdrop-filter: blur(16px);
border: 1px solid var(--border);
border-radius: 16px;
overflow: hidden;
margin-bottom: 20px;
position: relative;
transition: border-color 0.3s, box-shadow 0.3s;
}
.hl-hero::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0;
height: 3px;
background: linear-gradient(90deg, var(--accent), var(--accent-2));
opacity: 0;
transition: opacity 0.3s;
}
.hl-hero:hover::before { opacity: 1; }
.hl-hero:hover {
border-color: rgba(14, 165, 233, 0.3);
box-shadow: 0 0 40px rgba(14, 165, 233, 0.1);
}
.hl-hero-header {
padding: 24px 28px 0;
display: flex;
align-items: center;
gap: 10px;
}
.hl-hero-dot {
width: 10px; height: 10px;
border-radius: 50%;
display: inline-block;
flex-shrink: 0;
}
.hl-hero-dot.blue { background: var(--accent); box-shadow: 0 0 10px rgba(14,165,233,0.6); }
.hl-hero-dot.green { background: var(--green); box-shadow: 0 0 10px rgba(52,211,153,0.6); }
.hl-hero-name {
font-family: 'Fraunces', serif;
font-size: 1.8rem;
font-weight: 900;
letter-spacing: -0.04em;
color: var(--text);
line-height: 1;
}
.hl-hero-stats {
display: grid;
grid-template-columns: repeat(4, 1fr);
padding: 20px 0 0;
}
.hl-hero-stat {
text-align: center;
padding: 16px 12px 20px;
border-right: 1px solid var(--border);
transition: background 0.3s;
}
.hl-hero-stat:last-child { border-right: none; }
.hl-hero-stat:hover { background: rgba(255,255,255,0.02); }
.hl-hero-stat .hl-number {
font-family: 'Fraunces', serif;
font-size: 2rem;
font-weight: 900;
letter-spacing: -0.04em;
line-height: 1;
margin-bottom: 6px;
}
.hl-hero-stat .hl-label {
font-size: 0.72rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--text-dim);
}
@media (max-width: 768px) {
.hl-hero-stats { grid-template-columns: repeat(2, 1fr); }
.hl-hero-stat:nth-child(2) { border-right: none; }
.hl-hero-stat:nth-child(1),
.hl-hero-stat:nth-child(2) { border-bottom: 1px solid var(--border); }
.hl-hero-name { font-size: 1.4rem; }
}
.highlights-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 14px;
}
.highlight-card {
background: var(--surface);
backdrop-filter: blur(16px);
border: 1px solid var(--border);
border-radius: 14px;
padding: 22px 20px;
position: relative;
overflow: hidden;
transition: border-color 0.3s, box-shadow 0.3s, transform 0.2s;
}
.highlight-card::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0;
height: 3px;
background: linear-gradient(90deg, var(--accent), var(--accent-2));
opacity: 0;
transition: opacity 0.3s;
}
.highlight-card:hover::before { opacity: 1; }
.highlight-card:hover {
border-color: rgba(14, 165, 233, 0.3);
box-shadow: 0 0 30px rgba(14, 165, 233, 0.12);
transform: translateY(-2px);
}
.hl-icon {
width: 36px; height: 36px;
display: flex; align-items: center; justify-content: center;
border-radius: 10px;
margin-bottom: 14px;
}
.hl-icon svg { width: 20px; height: 20px; }
.hl-icon.blue { background: rgba(14,165,233,0.12); color: var(--accent); }
.hl-icon.green { background: rgba(52,211,153,0.12); color: var(--green); }
.hl-icon.orange { background: rgba(249,115,22,0.12); color: var(--orange); }
.hl-number {
font-family: 'Fraunces', serif;
font-size: 2rem;
font-weight: 900;
letter-spacing: -0.04em;
line-height: 1;
margin-bottom: 4px;
}
.hl-number.blue { color: var(--accent); }
.hl-number.green { color: var(--green); }
.hl-number.orange { color: var(--orange); }
.hl-label {
font-size: 0.78rem;
color: var(--text-dim);
font-weight: 500;
line-height: 1.3;
}
/* CONTACT */
.contact-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 12px;
}
.contact-card {
background: var(--surface);
backdrop-filter: blur(12px);
border: 1px solid var(--border);
border-radius: 14px;
padding: 20px 22px;
text-decoration: none;
color: var(--text);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
align-items: center;
gap: 14px;
}
.contact-card:hover {
border-color: var(--accent);
transform: translateY(-3px);
box-shadow: 0 8px 30px rgba(14, 165, 233, 0.1);
}
.contact-card .cc-icon {
width: 40px;
height: 40px;
border-radius: 10px;
background: rgba(14, 165, 233, 0.1);
border: 1px solid rgba(14, 165, 233, 0.15);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.contact-card .cc-icon svg { width: 18px; height: 18px; color: var(--accent); }
.contact-card .cc-label {
font-size: 0.68rem;
color: var(--text-dim);
text-transform: uppercase;
letter-spacing: 0.08em;
font-weight: 600;
}
.contact-card .cc-value {
font-size: 0.9rem;
font-weight: 600;
}
/* FOOTER */
footer {
text-align: center;
padding: 60px 0 40px;
color: var(--text-dim);
font-size: 0.8rem;
border-top: 1px solid var(--border);
margin-top: 20px;
}
footer a { color: var(--accent); text-decoration: none; }
/* REVEAL ANIMATION */
.reveal {
opacity: 0;
transform: translateY(30px);
transition: opacity 0.7s cubic-bezier(0.4, 0, 0.2, 1), transform 0.7s cubic-bezier(0.4, 0, 0.2, 1);
}
.reveal.visible {
opacity: 1;
transform: translateY(0);
}
/* LITE THEME */
[data-theme="lite"] {
--bg: #f8f6f3;
--surface: rgba(255, 255, 255, 0.8);
--surface-solid: #fff;
--border: rgba(0, 0, 0, 0.08);
--border-bright: rgba(0, 0, 0, 0.15);
--text: #111;
--text-dim: #777;
--accent: #0ea5e9;
--accent-2: #34d399;
--accent-3: #f97316;
--green: #34d399;
--orange: #f97316;
--glow: rgba(14, 165, 233, 0.25);
--glow-2: rgba(52, 211, 153, 0.2);
}
[data-theme="lite"] .mesh-bg::before {
background:
radial-gradient(ellipse 600px 600px at 20% 20%, rgba(14, 165, 233, 0.06) 0%, transparent 70%),
radial-gradient(ellipse 500px 500px at 80% 30%, rgba(0, 180, 216, 0.04) 0%, transparent 70%),
radial-gradient(ellipse 400px 400px at 50% 80%, rgba(224, 64, 128, 0.03) 0%, transparent 70%);
}
[data-theme="lite"] .grid-overlay {
background-image:
linear-gradient(rgba(0, 0, 0, 0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 0, 0, 0.03) 1px, transparent 1px);
}
[data-theme="lite"] .noise { opacity: 0.015; }
@media (max-width: 768px) {
.hero h1 { font-size: 2.5rem; }
.profile-card { flex-direction: column; text-align: center; padding: 28px; }
.profile-stats { justify-content: center; }
.hero-actions { justify-content: center; }
.stats-bar { gap: 24px; }
.stat-num { font-size: 1.6rem; }
.projects-grid { grid-template-columns: 1fr; }
.highlights-grid { grid-template-columns: repeat(2, 1fr); }
.nav-links a:not(.theme-btn) { display: none; }
}
</style>
</head>
<body>
<div class="mesh-bg"></div>
<div class="grid-overlay"></div>
<div class="noise"></div>
<div class="container">
<nav>
<a href="#" class="nav-logo">
<span class="dot"></span>
milesallen.site
</a>
<div class="nav-links">
<a href="#about">About</a>
<a href="#skills">Skills</a>
<a href="#projects">Projects</a>
<a href="#contact">Contact</a>
<button id="theme-toggle" class="theme-btn" aria-label="Toggle theme">
<svg class="sun-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
<svg class="moon-icon" style="display:none" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg>
</button>
</div>
</nav>
<section class="hero">
<div class="hero-chip">
<span class="live-dot"></span>
usually online
</div>
<h1>
<span class="line">Hi, I'm</span>
<span class="line grad">Miles Wolf Allen</span>
</h1>
<p class="hero-sub">I make games, tools, and websites. Right now I'm deep into backend JavaScript and building emulators that run in your browser. Send help.</p>
<div class="hero-actions">
<a href="https://github.com/mileswolfallen2" class="btn btn-glow" target="_blank">
<svg viewBox="0 0 16 16" fill="currentColor"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>
GitHub
</a>
<a href="https://replit.com/@MilesAllen1" class="btn btn-glass" target="_blank">Replit</a>
<a href="https://codepen.io/mileswolfallen2-the-typescripter" class="btn btn-glass" target="_blank">CodePen</a>
</div>
</section>
<div class="stats-bar reveal">
<div class="stat-item">
<div class="stat-num" id="s-repos">--</div>
<div class="stat-label">repos online</div>
</div>
<div class="stat-item">
<div class="stat-num" id="s-stars">--</div>
<div class="stat-label">stars earned</div>
</div>
<div class="stat-item">
<div class="stat-num" id="s-followers">--</div>
<div class="stat-label">people watching</div>
</div>
<div class="stat-item">
<div class="stat-num" id="s-following">--</div>
<div class="stat-label">people I watch</div>
</div>
</div>
<section id="about" class="section reveal">
<div class="section-divider"></div>
<div class="profile-card">
<img src="https://avatars.githubusercontent.com/u/115095719?v=4" alt="Miles" class="profile-avatar">
<div class="profile-info">
<h2>Miles Wolf Allen</h2>
<div class="handle">@mileswolfallen2</div>
<div class="bio">I build things on the internet. Some of them are games, some are tools, and some are just because I thought it would be fun.</div>
<div class="profile-stats">
<div class="ps"><b id="p-repos">142</b> repos</div>
<div class="ps"><b id="p-stars">91</b> stars</div>
<div class="ps"><b id="p-followers">12</b> followers</div>
</div>
</div>
</div>
<div class="achievements">
<div class="achievement">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 11-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
Pull Shark x2
</div>
<div class="achievement">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>
YOLO
</div>
<div class="achievement">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
Quickdraw
</div>
</div>
</section>
<section id="skills" class="section reveal">
<div class="section-divider"></div>
<div class="section-header">
<h2>Skills & Tech</h2>
<p>what I actually know how to use</p>
</div>
<div class="skills-label">can build stuff with</div>
<div class="skills-grid">
<div class="skill"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>JavaScript</div>
<div class="skill"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M13 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V9z"/><polyline points="13 2 13 9 20 9"/></svg>HTML</div>
<div class="skill"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2.69l5.66 5.66a8 8 0 11-11.31 0z"/></svg>CSS</div>
<div class="skill"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 013 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>Python</div>
<div class="skill"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="4"/><path d="M16 8v5a3 3 0 006 0v-1a10 10 0 10-3.92 7.94"/></svg>Git</div>
<div class="skill"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 003 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0021 16z"/></svg>Blender</div>
<div class="skill"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>Unity</div>
<div class="skill"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="12 2 2 7 12 12 22 7 12 2"/><polyline points="2 17 12 22 22 17"/><polyline points="2 12 12 17 22 12"/></svg>Unreal</div>
<div class="skill"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 10h-1.26A8 8 0 109 20h9a5 5 0 000-10z"/></svg>Cloudflare</div>
<div class="skill"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>Linux</div>
<div class="skill"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>Netlify</div>
<div class="skill"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg>Bash</div>
<div class="skill"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 00-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0020 4.77 5.07 5.07 0 0019.91 1S18.73.65 16 2.48a13.38 13.38 0 00-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 005 4.77a5.44 5.44 0 00-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 009 18.13V22"/></svg>GitHub</div>
</div>
<div class="skills-label">figuring out right now</div>
<div class="skills-grid">
<div class="skill"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 3h6a4 4 0 014 4v14a3 3 0 00-3-3H2z"/><path d="M22 3h-6a4 4 0 00-4 4v14a3 3 0 013-3h7z"/></svg>PHP</div>
<div class="skill"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 10h-1.26A8 8 0 109 20h9a5 5 0 000-10z"/></svg>.NET</div>
<div class="skill"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z"/></svg>Nix</div>
<div class="skill"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></svg>Yarn</div>
<div class="skill"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 3h6a4 4 0 014 4v14a3 3 0 00-3-3H2z"/><path d="M22 3h-6a4 4 0 00-4 4v14a3 3 0 013-3h7z"/></svg>Backend JS</div>
</div>
</section>
<section id="projects" class="section reveal">
<div class="section-divider"></div>
<div class="section-header">
<h2>Projects</h2>
<p>stuff I've made (and some I forked)</p>
</div>
<div class="projects-grid">
<a href="projects/omniemu.html" class="project-card">
<div class="pc-top">
<div class="pc-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="6" width="20" height="12" rx="2"/><circle cx="8" cy="12" r="2"/><circle cx="16" cy="12" r="2"/></svg></div>
<span class="pc-tag active">Active</span>
</div>
<h3>OmniEmu 2.0</h3>
<p>All your emulators in one place. Install 20+ emulators, scan your ROMs, and launch games without opening 15 different apps.</p>
<div class="pc-meta"><span>&#9733; 1</span><span>MIT</span><span>v0.3.2</span></div>
</a>
<a href="projects/fedl.html" class="project-card">
<div class="pc-top">
<div class="pc-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg></div>
<span class="pc-tag community">Community</span>
</div>
<h3>FEDL</h3>
<p>The demon list for Geometry Dash. Ranked levels, run submissions, and a community of people way better at the game than me.</p>
<div class="pc-meta"><span>&#9733; 2</span><span>196 commits</span><span>Live</span></div>
</a>
<a href="projects/noto.html" class="project-card">
<div class="pc-top">
<div class="pc-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg></div>
<span class="pc-tag active">Active</span>
</div>
<h3>Noto</h3>
<p>Note-taking app with AI built in. Built with Flutter, powered by Cortex AI, and actually good at organizing my chaos.</p>
<div class="pc-meta"><span>&#9733; 1</span><span>MIT</span></div>
</a>
<a href="projects/nova.html" class="project-card">
<div class="pc-top">
<div class="pc-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z"/></svg></div>
<span class="pc-tag lang">Python</span>
</div>
<h3>Nova AI</h3>
<p>AI assistant that runs on your machine. Desktop GUI, web interface, and CLI. No cloud, no subscriptions, just vibes.</p>
<div class="pc-meta"><span>&#9733; 1</span><span>MIT</span></div>
</a>
<a href="projects/music-app.html" class="project-card">
<div class="pc-top">
<div class="pc-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18V5l12-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/></svg></div>
<span class="pc-tag lang">JavaScript</span>
</div>
<h3>Music App</h3>
<p>Music player that doesn't interrupt you with ads. Inspired by YouTube Music but without the annoying parts.</p>
<div class="pc-meta"><span>&#9733; 1</span><span>Apache-2.0</span></div>
</a>
<a href="projects/rhythm-game.html" class="project-card">
<div class="pc-top">
<div class="pc-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polygon points="10 8 16 12 10 16 10 8"/></svg></div>
<span class="pc-tag lang">HTML</span>
</div>
<h3>Rhythm Game</h3>
<p>Hit keys to the beat. Song selection, real-time notes, and keyboard controls. My fingers hurt.</p>
<div class="pc-meta"><span>&#9733; 1</span><span>MPL-2.0</span></div>
</a>
<a href="projects/geode-mod.html" class="project-card">
<div class="pc-top">
<div class="pc-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14.7 6.3a1 1 0 000 1.4l1.6 1.6a1 1 0 001.4 0l3.77-3.77a6 6 0 01-7.94 7.94l-6.91 6.91a2.12 2.12 0 01-3-3l6.91-6.91a6 6 0 017.94-7.94l-3.76 3.76z"/></svg></div>
<span class="pc-tag wip">WIP</span>
</div>
<h3>FEDL Geode Mod</h3>
<p>Geometry Dash mod that shows the demon list in-game. Roulette mode, banned mod detection, and more.</p>
<div class="pc-meta"><span>MIT</span></div>
</a>
<a href="projects/decompilations.html" class="project-card">
<div class="pc-top">
<div class="pc-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 3h6a4 4 0 014 4v14a3 3 0 00-3-3H2z"/><path d="M22 3h-6a4 4 0 00-4 4v14a3 3 0 013-3h7z"/></svg></div>
<span class="pc-tag lang">HTML</span>
</div>
<h3>Decompilations</h3>
<p>Native PC ports and decompilations of games. Progress tracking for projects that probably shouldn't exist.</p>
<div class="pc-meta"><span>MIT</span></div>
</a>
<a href="projects/issue-tracker.html" class="project-card">
<div class="pc-top">
<div class="pc-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2"/><rect x="9" y="3" width="6" height="4" rx="1"/><path d="M9 14l2 2 4-4"/></svg></div>
<span class="pc-tag lang">HTML</span>
</div>
<h3>Issue Tracker</h3>
<p>Built my own issue tracker because why not. Node.js backend, no frameworks, just raw determination.</p>
<div class="pc-meta"><span>MIT</span></div>
</a>
<a href="projects/moon-gaming.html" class="project-card">
<div class="pc-top">
<div class="pc-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="6" width="20" height="12" rx="2"/><line x1="6" y1="12" x2="10" y2="12"/><circle cx="17" cy="11" r="1"/><circle cx="15" cy="13" r="1"/></svg></div>
<span class="pc-tag lang">HTML</span>
</div>
<h3>Moon Gaming</h3>
<p>Game hub with 1,500+ commits. Browse, play, and explore a growing library of browser games I made at 2am.</p>
<div class="pc-meta"><span>&#9733; 1,542</span><span>MIT</span></div>
</a>
</div>
</section>
<section id="highlights" class="section reveal">
<div class="section-divider"></div>
<div class="section-header">
<h2>Project Highlights</h2>
<p>What my projects have achieved</p>
</div>
<div class="hl-hero">
<div class="hl-hero-header">
<span class="hl-hero-dot blue"></span>
<span class="hl-hero-name">FEDL</span>
</div>
<div class="hl-hero-stats">
<div class="hl-hero-stat">
<div class="hl-number blue" id="hl-fedl-runs">--</div>
<div class="hl-label">Verified Runs</div>
</div>
<div class="hl-hero-stat">
<div class="hl-number green" id="hl-fedl-levels">--</div>
<div class="hl-label">Ranked Levels</div>
</div>
<div class="hl-hero-stat">
<div class="hl-number orange" id="hl-fedl-players">--</div>
<div class="hl-label">Ranked Players</div>
</div>
<div class="hl-hero-stat">
<div class="hl-number blue" id="hl-fedl-videos">--</div>
<div class="hl-label">YouTube Videos</div>
</div>
</div>
</div>
<div class="hl-hero">
<div class="hl-hero-header">
<span class="hl-hero-dot green"></span>
<span class="hl-hero-name">OmniEmu 2.0</span>
</div>
<div class="hl-hero-stats">
<div class="hl-hero-stat">
<div class="hl-number blue">20+</div>
<div class="hl-label">Emulators Supported</div>
</div>
<div class="hl-hero-stat">
<div class="hl-number green">3</div>
<div class="hl-label">Platforms (Win/Mac/Linux)</div>
</div>
<div class="hl-hero-stat">
<div class="hl-number orange">0.3.2</div>
<div class="hl-label">Latest Release</div>
</div>
<div class="hl-hero-stat">
<div class="hl-number blue">TS</div>
<div class="hl-label">Built with TypeScript</div>
</div>
</div>
</div>
<div class="hl-divider"></div>
<div class="hl-group">
<div class="hl-group-label"><span class="hl-group-dot" style="background:var(--text-dim)"></span>Other Projects</div>
<div class="highlights-grid">
<div class="highlight-card">
<div class="hl-icon blue"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M12 1v6M12 17v6M4.22 4.22l4.24 4.24M15.54 15.54l4.24 4.24M1 12h6M17 12h6M4.22 19.78l4.24-4.24M15.54 8.46l4.24-4.24"/></svg></div>
<div class="hl-number blue">3</div>
<div class="hl-label">Nova Interfaces</div>
</div>
<div class="highlight-card">
<div class="hl-icon green"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg></div>
<div class="hl-number green">5</div>
<div class="hl-label">Noto AI Features</div>
</div>
<div class="highlight-card">
<div class="hl-icon orange"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="6" width="20" height="12" rx="2"/><line x1="6" y1="12" x2="10" y2="12"/><circle cx="17" cy="11" r="1"/><circle cx="15" cy="13" r="1"/></svg></div>
<div class="hl-number orange">1.5k+</div>
<div class="hl-label">Moon Gaming Commits</div>
</div>
<div class="highlight-card">
<div class="hl-icon blue"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18V5l12-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/></svg></div>
<div class="hl-number blue">Ad-free</div>
<div class="hl-label">Music App Playback</div>
</div>
<div class="highlight-card">
<div class="hl-icon green"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg></div>
<div class="hl-number green">MIT</div>
<div class="hl-label">Licensed Across Projects</div>
</div>
</div>
</div>
</section>
<section id="contact" class="section reveal">
<div class="section-divider"></div>
<div class="section-header">
<h2>Get In Touch</h2>
<p>unless you're a bot, then please go away</p>
</div>
<div class="contact-grid">
<a href="mailto:[email protected]" class="contact-card">
<div class="cc-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg></div>
<div><div class="cc-label">Email</div><div class="cc-value">[email protected]</div></div>
</a>
<a href="https://github.com/mileswolfallen2" class="contact-card" target="_blank">
<div class="cc-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 00-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0020 4.77 5.07 5.07 0 0019.91 1S18.73.65 16 2.48a13.38 13.38 0 00-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 005 4.77a5.44 5.44 0 00-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 009 18.13V22"/></svg></div>
<div><div class="cc-label">GitHub</div><div class="cc-value">mileswolfallen2</div></div>
</a>
<a href="https://replit.com/@MilesAllen1" class="contact-card" target="_blank">
<div class="cc-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="12 2 22 8.5 22 15.5 12 22 2 15.5 2 8.5 12 2"/><line x1="12" y1="22" x2="12" y2="15.5"/></svg></div>
<div><div class="cc-label">Replit</div><div class="cc-value">@MilesAllen1</div></div>
</a>
<a href="https://codepen.io/mileswolfallen2-the-typescripter" class="contact-card" target="_blank">
<div class="cc-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="12 2 22 8.5 22 15.5 12 22 2 15.5 2 8.5 12 2"/><line x1="12" y1="22" x2="12" y2="8.5"/><polyline points="22 8.5 12 2 2 8.5"/></svg></div>
<div><div class="cc-label">CodePen</div><div class="cc-value">mileswolfallen2</div></div>
</a>
<a href="https://me.fedl.site" class="contact-card" target="_blank">
<div class="cc-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z"/></svg></div>
<div><div class="cc-label">Website</div><div class="cc-value">me.fedl.site</div></div>
</a>
</div>
</section>
<footer>
Built by Miles &middot; 2026 &middot; Powered by <a href="https://docs.github.com/en/rest" target="_blank">GitHub API</a> and too much coffee
</footer>
</div>
<script>
// Theme toggle
const toggle = document.getElementById('theme-toggle');
const html = document.documentElement;
const saved = localStorage.getItem('theme');
if (saved) html.setAttribute('data-theme', saved);
toggle.addEventListener('click', () => {
const next = html.getAttribute('data-theme') === 'lite' ? '' : 'lite';
if (next) { html.setAttribute('data-theme', next); localStorage.setItem('theme', next); }
else { html.removeAttribute('data-theme'); localStorage.removeItem('theme'); }
document.querySelector('.sun-icon').style.display = next === 'lite' ? 'none' : 'block';
document.querySelector('.moon-icon').style.display = next === 'lite' ? 'block' : 'none';
});
// Scroll reveal
const observer = new IntersectionObserver((entries) => {
entries.forEach(e => { if (e.isIntersecting) e.target.classList.add('visible'); });
}, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' });
document.querySelectorAll('.reveal').forEach(el => observer.observe(el));
// GitHub API stats
fetch('https://api.github.com/users/mileswolfallen2')
.then(r => r.json())
.then(u => {
document.getElementById('s-repos').textContent = u.public_repos || '147';
document.getElementById('s-stars').textContent = '--';
document.getElementById('s-followers').textContent = u.followers || '13';
document.getElementById('s-following').textContent = u.following || '37';
document.getElementById('p-repos').textContent = u.public_repos || '147';
document.getElementById('p-followers').textContent = u.followers || '13';
})
.catch(() => {
document.getElementById('s-repos').textContent = '147';
document.getElementById('s-stars').textContent = '--';
document.getElementById('s-followers').textContent = '13';
document.getElementById('s-following').textContent = '37';
document.getElementById('p-repos').textContent = '147';
document.getElementById('p-followers').textContent = '13';
});
fetch('https://api.github.com/users/mileswolfallen2/repos?per_page=100')
.then(r => r.json())
.then(repos => {
const total = repos.reduce((a, r) => a + r.stargazers_count, 0);
document.getElementById('s-stars').textContent = total;
document.getElementById('p-stars').textContent = total;
})
.catch(() => {});
// FEDL live stats
Promise.all([
fetch('https://server.fedl.site/fedl/api/runs').then(r => r.json()),
fetch('https://server.fedl.site/fedl/api/list').then(r => r.json())
])
.then(([runs, listData]) => {
const approved = runs.filter(r => r.status === 'approved');
document.getElementById('hl-fedl-runs').textContent = approved.length.toLocaleString();
const levels = Array.isArray(listData) ? listData : (listData.items || []);
document.getElementById('hl-fedl-levels').textContent = levels.length;
const players = new Set(approved.map(r => r.accountUsername || r.playerName)).size;
document.getElementById('hl-fedl-players').textContent = players.toLocaleString();
const videos = new Set(approved.map(r => r.videoUrl).filter(Boolean)).size;
document.getElementById('hl-fedl-videos').textContent = videos.toLocaleString();
})
.catch(() => {
document.getElementById('hl-fedl-runs').textContent = '3,839';
document.getElementById('hl-fedl-levels').textContent = '341';
document.getElementById('hl-fedl-players').textContent = '250+';
document.getElementById('hl-fedl-videos').textContent = '3,800+';
});
</script>
</body>
</html>