Files
miles-web/remake/index.html
T
2026-08-28 17:04:27 -05:00

766 lines
46 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 &amp; 3D Artist</title>
<meta name="description" content="Portfolio of Miles Wolf Allen — developer, 3D artist, and builder of emulators, games, and tools.">
<meta name="keywords" content="Miles Wolf Allen, developer, portfolio, emulator, Geometry Dash, FEDL, OmniEmu, Swift, TypeScript">
<meta name="author" content="Miles Wolf Allen">
<link rel="canonical" href="https://milesallen.site/remake/index.html">
<meta property="og:title" content="MILES WOLF ALLEN — Developer & 3D Artist">
<meta property="og:description" content="Portfolio of Miles Wolf Allen — developer, 3D artist, and builder of emulators, games, and tools.">
<meta property="og:type" content="website">
<meta name="theme-color" content="#f5b700">
<link rel="icon" type="image/png" href="../favicon.png">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Josefin+Sans:wght@300;400&family=Spectral:ital,wght@0,400;0,600;1,400&family=Anton&display=swap" rel="stylesheet">
<link rel="stylesheet" href="broadside.css">
<style>
/* ============================================================
CINEMATIC INTRO — Iad-lab inspired. A colossal MILES wordmark
splits apart from a full-bleed crop, crashes back together,
flashes cobalt, then blows past the camera to reveal the site.
============================================================ */
.intro{
position:fixed;inset:0;z-index:1000;overflow:hidden;
background:#000;
}
/* flying word stage — sits above the black intro, animates independently */
.intro-stage{
position:fixed;inset:0;z-index:1002;overflow:hidden;pointer-events:none;
display:grid;place-items:center;
}
/* dark loader phase */
.intro-tag{
position:absolute;bottom:34px;left:50%;transform:translateX(-50%);
font-family:var(--sentient);font-size:12px;letter-spacing:.28em;
text-transform:uppercase;color:#888;white-space:nowrap;
}
.intro-tag b{color:var(--yellow);font-weight:700;}
.intro-bar{
position:absolute;bottom:22px;left:50%;transform:translateX(-50%);
width:min(320px,70vw);height:2px;background:#222;
}
.intro-bar .fill{height:100%;width:0;background:var(--orange);}
/* the slider wordmark (flies in, then lands on the hero) */
.intro-word{
position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
font-family:var(--morganite);font-weight:400;text-transform:uppercase;
font-size:clamp(90px,22vw,340px);line-height:.72;letter-spacing:.02em;
white-space:nowrap;opacity:0;
background:linear-gradient(90deg,var(--orange),var(--yellow));
-webkit-background-clip:text;background-clip:text;color:transparent;
will-change:transform;
}
/* main page (revealed after intro) */
.site{opacity:0;}
/* ================= NAV ================= */
.nav{
position:sticky;top:0;z-index:50;background:var(--yellow);color:var(--black);
display:flex;align-items:center;justify-content:space-between;gap:16px;
padding:14px 5vw;border-bottom:3px solid var(--black);flex-wrap:wrap;
}
.nav-brand{font-family:var(--morganite);font-weight:400;font-size:34px;line-height:1;letter-spacing:.02em;display:flex;align-items:center;gap:10px;}
.nav-brand .swatch{width:18px;height:18px;border-radius:50%;background:var(--cobalt);display:inline-block;}
.nav-links{display:flex;gap:8px;flex-wrap:wrap;align-items:center;}
.nav-links a{font-family:var(--sentient);font-size:13px;letter-spacing:-.01em;padding:7px 16px;border-radius:999px;border:2px solid var(--black);transition:background .2s,color .2s;}
.nav-links a:hover{background:var(--black);color:var(--yellow);}
.nav-links a.cta{background:var(--cobalt);border-color:var(--cobalt);color:var(--white);}
.nav-links a.cta:hover{background:var(--black);border-color:var(--black);color:var(--yellow);}
@media(max-width:640px){.nav-links{width:100%;order:3;}}
/* ================= HERO ================= */
.hero{position:relative;overflow:hidden;padding:70px 5vw 90px;}
.hero .sticker{right:6vw;top:30px;}
.hero-title{font-family:var(--morganite);font-weight:400;font-size:clamp(96px,22vw,229px);line-height:.7;letter-spacing:.01em;text-transform:uppercase;margin-top:24px;}
.hero-title .kick{display:block;font-family:var(--thunder);font-weight:300;font-size:clamp(28px,4.5vw,46px);line-height:1;letter-spacing:.02em;margin-bottom:20px;text-transform:none;}
.hero-title .loud{display:block;}
.hero-sub{margin-top:70px;max-width:480px;font-size:16px;line-height:1.44;letter-spacing:-.015em;}
.hero-sub em{font-weight:600;}
.hero-status{display:inline-flex;align-items:center;gap:10px;margin-top:24px;font-family:var(--fine);font-size:12px;text-transform:uppercase;letter-spacing:.1em;border:1px solid var(--black);border-radius:999px;padding:6px 16px;}
.hero-status i{width:9px;height:9px;border-radius:50%;background:var(--cobalt);display:inline-block;animation:pulse 1.6s ease-in-out infinite;}
@keyframes pulse{0%,100%{opacity:1;}50%{opacity:.25;}}
.hero-actions{display:flex;gap:14px;flex-wrap:wrap;margin-top:34px;}
.hook{text-align:center;padding:9vw 6vw;position:relative;}
.hook-text{font-family:var(--thunder);font-weight:300;font-size:clamp(30px,5vw,56px);line-height:1.1;max-width:1100px;margin:0 auto;}
.hook-text em{font-family:var(--fine);font-weight:400;}
/* ================= MARQUEE ================= */
.marquee{overflow:hidden;white-space:nowrap;border-top:3px solid var(--black);border-bottom:3px solid var(--black);padding:16px 0;}
.marquee .track{display:inline-flex;animation:scrollLeft 22s linear infinite;}
.marquee span{font-family:var(--morganite);font-weight:400;font-size:32px;letter-spacing:.02em;margin:0 30px;text-transform:uppercase;flex-shrink:0;}
@keyframes scrollLeft{0%{transform:translateX(0);}100%{transform:translateX(-50%);}}
/* ================= STATS ================= */
.stats{display:grid;grid-template-columns:repeat(4,1fr);}
.stat{border-right:1px solid rgba(255,255,255,.55);border-bottom:1px solid rgba(255,255,255,.55);padding:60px 5vw;text-align:center;}
.stat:last-child{border-right:none;}
.stat-num{font-family:var(--morganite);font-weight:400;font-size:clamp(64px,10vw,110px);line-height:.7;color:var(--white);}
.stat-label{font-family:var(--fine);font-size:11px;text-transform:uppercase;letter-spacing:.12em;color:var(--white);margin-top:16px;}
@media(max-width:760px){.stats{grid-template-columns:1fr 1fr;}.stat:nth-child(2){border-right:none;}.stat:nth-child(1),.stat:nth-child(2){border-bottom:1px solid rgba(255,255,255,.55);}}
/* ================= SECTIONS ================= */
.section{position:relative;padding:110px 5vw 120px;}
.sec-label{font-family:var(--fine);font-size:12px;text-transform:uppercase;letter-spacing:.16em;border:1px solid currentColor;border-radius:999px;display:inline-block;padding:5px 16px;margin-bottom:40px;}
.sec-title{font-family:var(--morganite);font-weight:400;font-size:clamp(100px,18vw,229px);line-height:.66;letter-spacing:.01em;text-transform:uppercase;max-width:92vw;margin-bottom:48px;}
.sec-sub{font-size:12px;font-family:var(--fine);text-transform:uppercase;letter-spacing:.14em;max-width:520px;line-height:1.6;margin-bottom:70px;}
.or-white{color:var(--white);}
.sec-label.flat{border-color:var(--white);}
/* ================= ABOUT ================= */
.about-grid{display:grid;grid-template-columns:auto 1fr;gap:80px;align-items:start;}
.avatar-frame{border:3px solid var(--black);outline:3px solid var(--white);transform:rotate(-3deg);width:240px;background:var(--white);box-shadow:6px 6px 0 var(--black);}
.avatar-frame img{width:240px;filter:contrast(1.1);display:block;}
.avatar-name{font-family:var(--morganite);font-weight:400;font-size:30px;text-transform:uppercase;margin-top:16px;}
.avatar-tag{font-family:var(--fine);font-size:12px;text-transform:uppercase;letter-spacing:.1em;color:rgba(0,0,0,.55);margin-top:2px;}
.about-body{border:3px solid var(--black);background:var(--white);padding:34px;box-shadow:6px 6px 0 var(--black);}
.about-body p{font-size:16px;line-height:1.55;letter-spacing:-.015em;max-width:560px;margin-bottom:18px;color:rgba(0,0,0,.9);}
.badge-row{display:flex;gap:10px;flex-wrap:wrap;margin-top:26px;}
.badge{padding:5px 18px;border-radius:999px;border:2px solid var(--black);font-family:var(--fine);font-size:13px;letter-spacing:-.01em;background:var(--cobalt);color:var(--white);transform:rotate(-2deg);}
.badge:nth-child(2){background:var(--orange);color:var(--white);transform:rotate(1deg);}
.badge:nth-child(3){background:var(--white);color:var(--black);transform:rotate(-1deg);}
.about-cta{display:flex;gap:12px;flex-wrap:wrap;margin-top:30px;align-items:center;}
.hair-rule{height:2px;background:var(--black);margin:60px 0 40px;width:100%;}
.page-links{display:flex;gap:24px;flex-wrap:wrap;}
.page-links a{font-family:var(--fine);font-size:13px;text-transform:uppercase;letter-spacing:.06em;border-bottom:1px solid var(--black);}
.page-links a:hover{color:var(--cobalt);border-color:var(--cobalt);}
@media(max-width:820px){.about-grid{grid-template-columns:1fr;gap:40px;}.avatar-frame,.avatar-frame img{width:200px;}}
/* ================= SKILLS ================= */
.skill-group-label{font-family:var(--fine);font-size:12px;text-transform:uppercase;letter-spacing:.16em;margin-bottom:24px;color:var(--white);}
.skill-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));margin-bottom:60px;}
.skill{border:2px solid var(--white);border-right:none;border-bottom:none;padding:26px 14px;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;min-height:130px;}
.skill:nth-child(4n){border-right:2px solid var(--white);}
.skill .si{width:30px;height:30px;filter:invert(1);}
.skill span{font-family:var(--fine);font-size:13px;text-transform:uppercase;letter-spacing:.05em;}
.skill.alt1{background:var(--black);color:var(--yellow);}
.skill.alt2{background:var(--yellow);color:var(--black);}
.skill.alt3{background:var(--white);color:var(--black);}
.skill.alt1 .si,.skill.alt2 .si{filter:none;}
.skill.alt2 .si{filter:none;}
.skill.alt3 .si{filter:invert(0);}
.skill.learn{border-style:dashed;opacity:.75;}
/* ================= PROJECTS ================= */
.project-grid{display:grid;grid-template-columns:1fr 1fr;gap:30px;}
.proj-card{border:3px solid var(--black);background:var(--white);display:block;padding:34px;transform:rotate(-1deg);transition:transform .25s,background .25s,color .25s;box-shadow:6px 6px 0 var(--black);}
.proj-card:nth-child(odd){transform:rotate(1deg);}
.proj-card:hover{transform:rotate(-1deg) scale(1.01);}
.proj-top{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-bottom:18px;flex-wrap:wrap;}
.proj-tag{font-family:var(--fine);font-size:11px;text-transform:uppercase;letter-spacing:.1em;background:var(--yellow);color:var(--black);border-radius:999px;padding:4px 14px;border:2px solid var(--black);}
.proj-tag.on-orange{background:var(--orange);color:var(--white);}
.proj-meta{font-family:var(--fine);font-size:11px;text-transform:uppercase;letter-spacing:.04em;color:rgba(0,0,0,.72);}
.proj-title{font-family:var(--morganite);font-weight:400;font-size:clamp(36px,4vw,56px);line-height:.8;text-transform:uppercase;margin-bottom:16px;}
.proj-desc{font-size:15px;line-height:1.5;letter-spacing:-.01em;max-width:44ch;color:rgba(0,0,0,.88);}
@media(max-width:800px){.project-grid{grid-template-columns:1fr;}}
/* ================= HIGHLIGHTS ================= */
.hl-block{margin-bottom:80px;}
.hl-block h3{font-family:var(--morganite);font-weight:400;font-size:clamp(40px,6vw,64px);text-transform:uppercase;margin-bottom:28px;color:var(--yellow);}
.hl-row{display:grid;grid-template-columns:repeat(4,1fr);border-top:2px solid var(--yellow);}
.hl-cell{border-right:2px solid var(--yellow);border-bottom:2px solid var(--yellow);padding:40px 30px;}
.hl-cell:last-child{border-right:none;}
.hl-num{font-family:var(--morganite);font-weight:400;font-size:clamp(52px,7vw,84px);line-height:.7;color:var(--white);}
.hl-label{font-family:var(--fine);font-size:11px;text-transform:uppercase;letter-spacing:.12em;color:var(--white);margin-top:16px;}
@media(max-width:760px){.hl-row{grid-template-columns:1fr 1fr;}.hl-cell:nth-child(2){border-right:none;}}
/* ================= GITHUB ================= */
.gh-stats{display:flex;gap:16px;flex-wrap:wrap;align-items:flex-start;}
.gh-stats img{border:3px solid var(--black);background:var(--white);height:165px;width:auto;box-shadow:5px 5px 0 var(--black);}
/* ================= BLOG ================= */
.blog-grid{display:grid;grid-template-columns:1fr 1fr;gap:30px;}
.blog-card{border:3px solid var(--white);display:block;padding:30px;transform:rotate(-1deg);transition:transform .25s,border-color .25s;box-shadow:6px 6px 0 var(--black);}
.blog-card:nth-child(even){transform:rotate(1deg);}
.blog-card:hover{transform:rotate(0);border-color:var(--yellow);}
.blog-date{font-family:var(--fine);font-size:12px;text-transform:uppercase;letter-spacing:.12em;color:var(--yellow);margin-bottom:16px;}
.blog-title{font-family:var(--morganite);font-weight:400;font-size:clamp(30px,3vw,40px);text-transform:uppercase;line-height:.85;margin-bottom:14px;}
.blog-excerpt{font-size:15px;line-height:1.5;letter-spacing:-.01em;color:rgba(255,255,255,.92);margin-bottom:18px;max-width:46ch;}
.blog-tags{display:flex;gap:8px;flex-wrap:wrap;margin-top:14px;}
.blog-tag{font-family:var(--fine);font-size:11px;text-transform:uppercase;letter-spacing:.06em;border:1px solid var(--yellow);color:var(--yellow);border-radius:999px;padding:4px 14px;}
@media(max-width:760px){.blog-grid{grid-template-columns:1fr;}}
/* ================= CONTACT ================= */
.contact-card{border:3px solid var(--black);background:var(--white);padding:44px;transform:rotate(-1deg);max-width:640px;position:relative;box-shadow:6px 6px 0 var(--black);}
.contact-card .sticker{right:-30px;top:-40px;background:var(--yellow);color:var(--cobalt);transform:rotate(10deg);}
.contact-list{display:flex;flex-direction:column;}
.contact-row{display:flex;justify-content:space-between;align-items:center;gap:20px;padding:20px 6px;border-bottom:2px solid var(--black);font-size:16px;transition:padding-left .2s,color .2s;flex-wrap:wrap;}
.contact-row:last-child{border-bottom:none;}
.contact-row span.k{font-family:var(--fine);font-size:11px;text-transform:uppercase;letter-spacing:.14em;opacity:.75;}
.contact-row:hover{padding-left:18px;color:var(--cobalt);}
/* ================= FOOTER ================= */
.site-foot{background:var(--black);color:var(--white);padding:70px 5vw 80px;text-align:center;}
.site-foot .foot-brand{font-family:var(--morganite);font-weight:400;font-size:clamp(48px,10vw,110px);line-height:.7;color:var(--yellow);text-transform:uppercase;margin-bottom:30px;}
.site-foot .foot-links{display:flex;gap:18px;flex-wrap:wrap;justify-content:center;margin-bottom:30px;}
.site-foot .foot-links a{font-family:var(--fine);font-size:12px;text-transform:uppercase;letter-spacing:.1em;border-radius:999px;border:1px solid var(--white);padding:7px 18px;transition:background .2s,color .2s;}
.site-foot .foot-links a:hover{background:var(--yellow);color:var(--black);border-color:var(--yellow);}
.site-foot .foot-note{color:rgba(255,255,255,.55);font-size:13px;line-height:1.7;}
.site-foot .foot-note a{color:var(--yellow);border-bottom:1px solid var(--yellow);}
/* ============================================================
FUN — index hover pops + ambient life
============================================================ */
/* nav links: bounce to say hi */
.nav-brand .swatch{transition:transform .3s;}
.nav-brand:hover .swatch{transform:scale(1.4) rotate(180deg);}
.nav-links a{transition:transform .16s cubic-bezier(.34,1.56,.64,1),background .2s,color .2s;}
.nav-links a:hover{transform:translateY(-3px);}
.nav-links a.cta:hover{transform:translateY(-3px) scale(1.05);}
/* hero: wordmark gently breathes, kick wiggles */
.hero{overflow:hidden;}
.hero-title .loud{transition:transform .4s cubic-bezier(.34,1.56,.64,1);}
.hero-title:hover .loud{transform:translateX(8px) rotate(-1deg);}
.hero-title .kick{display:inline-block;transition:transform .2s;}
.hero-title:hover .kick{animation:jiggle .6s ease-in-out;}
/* hook: happy sway */
.hook-text{transition:transform .3s;}
.hook-text:hover{transform:scale(1.02) rotate(-.5deg);}
/* section titles: loud on hover */
.sec-title{transition:transform .3s cubic-bezier(.34,1.56,.64,1),letter-spacing .3s;}
.sec-title:hover{letter-spacing:.02em;}
.section:hover .sec-title{transform:translateX(6px);}
.sec-label{transition:transform .2s cubic-bezier(.34,1.56,.64,1),background .2s,color .2s;}
.sec-label:hover{transform:rotate(-4deg) scale(1.05);background:var(--cobalt);color:var(--white);}
.sec-label.flat:hover{background:var(--orange);color:var(--white);}
/* stats: number pops + label slides on hover */
.stat{transition:background .25s;}
.stat:hover{background:rgba(255,255,255,.1);}
.stat-num{transition:transform .25s cubic-bezier(.34,1.56,.64,1);display:inline-block;}
.stat:hover .stat-num{transform:scale(1.15) rotate(-3deg);}
.stat-label{transition:letter-spacing .25s,background .2s;}
.stat:hover .stat-label{letter-spacing:.22em;background:var(--yellow);color:var(--black);padding:2px 8px;border-radius:999px;}
/* skill cells: wobbly wave on hover */
.skill{transition:transform .2s cubic-bezier(.34,1.56,.64,1),background .2s,color .2s,opacity .2s;will-change:transform;}
.skill:hover{transform:translateY(-6px) rotate(-2deg) scale(1.05);z-index:2;}
.skill.learn:hover{transform:translateY(-6px) rotate(2deg) scale(1.05);opacity:1;}
.skill-group-label{transition:letter-spacing .3s;}
.skill-group-label::after{content:'→';display:inline-block;margin-left:8px;opacity:0;transform:translateX(-6px);transition:opacity .2s,transform .2s;}
.skill-group-label:hover{letter-spacing:.22em;}
/* project cards: lift, straighten, stamp arrow */
.proj-card{transition:transform .25s cubic-bezier(.34,1.56,.64,1),background .25s,color .25s,box-shadow .25s;}
.proj-card:hover{transform:rotate(0) scale(1.03) translateY(-6px);background:var(--cobalt);color:var(--white);box-shadow:8px 8px 0 var(--black);}
.proj-card:hover .proj-desc,.proj-card:hover .proj-meta{color:rgba(255,255,255,.92);}
.proj-title{transition:letter-spacing .25s,transform .25s;}
.proj-card:hover .proj-title{letter-spacing:.02em;}
.proj-tag{transition:transform .2s,background .2s,color .2s;}
.proj-card:hover .proj-tag{transform:rotate(-6deg) scale(1.1);}
.proj-card:hover .proj-tag.on-orange{background:var(--orange);}
/* blog cards: rise + straighten */
.blog-card{transition:transform .25s cubic-bezier(.34,1.56,.64,1),border-color .25s,background .25s,box-shadow .25s;box-shadow:6px 6px 0 var(--black);}
.blog-card:hover{transform:rotate(0) scale(1.03) translateY(-6px);background:var(--black);border-color:var(--yellow);}
.blog-tag{transition:background .2s,color .2s,transform .15s;}
.blog-card:hover .blog-tag{background:var(--yellow);color:var(--black);transform:rotate(-5deg);}
.blog-title{transition:letter-spacing .25s;}
.blog-card:hover .blog-title{letter-spacing:.02em;}
/* contact rows already slide; polish */
.contact-row .val{transition:transform .2s;}
.contact-row:hover .val{transform:translateX(6px);}
/* badges: dotted wiggle on hover */
.badge{transition:transform .2s cubic-bezier(.34,1.56,.64,1),background .2s,color .2s;}
.badge:hover{transform:rotate(-4deg) scale(1.12)!important;}
/* avatar: straightens to say hi */
.avatar-frame{transition:transform .3s cubic-bezier(.34,1.56,.64,1);}
.avatar-frame:hover{transform:rotate(0) scale(1.02);}
/* back-to-top / footer brand */
.site-foot .foot-brand{transition:letter-spacing .3s;}
.site-foot .foot-brand:hover{letter-spacing:.05em;color:var(--white);}
/* marquee spans: brighten on hover */
.marquee span{transition:opacity .2s;}
.marquee:hover span{opacity:1;}
</style>
</head>
<body>
<!-- ============ CINEMATIC INTRO ============ -->
<div class="intro" id="intro" aria-hidden="true">
<div class="intro-tag" id="introTag">SICK AGENCY · <b>MILES WOLF ALLEN</b></div>
<div class="intro-bar" id="introBar"><div class="fill" id="introFill"></div></div>
</div>
<div class="intro-stage" id="introStage" aria-hidden="true">
<div class="intro-word" id="introWord">MILES</div>
</div>
<!-- ============ SITE ============ -->
<div class="site" id="site">
<nav class="nav">
<a class="nav-brand" href="#top"><span class="swatch"></span>MILES</a>
<div class="nav-links">
<a href="#about">About</a>
<a href="#skills">Skills</a>
<a href="#projects">Projects</a>
<a href="#blog">Devlog</a>
<a class="cta" href="#contact">Say hi</a>
</div>
</nav>
<main id="top">
<!-- ============ HERO — YELLOW ============ -->
<section class="band yellow hero">
<span class="sticker" style="background:var(--cobalt);color:var(--white);"><b>USUALLY</b>ONLINE <small>@mileswolfallen2</small></span>
<div class="hero-title">
<span class="kick">Hi, I'm —</span>
<span class="loud">MILES<br>WOLF<br>ALLEN</span>
</div>
<p class="hero-sub">I make games, tools, and websites. I'm still in school and building a full Electron replacement — <em>send help</em>. I also work at Diskette Labs.</p>
<div class="hero-status"><i></i> usually online</div>
<div class="hero-actions">
<a class="btn primary" href="https://github.com/mileswolfallen2" target="_blank">GitHub</a>
<a class="btn" href="https://replit.com/@MilesAllen1" target="_blank">Replit</a>
<a class="btn" href="https://codepen.io/mileswolfallen2-the-typescripter" target="_blank">CodePen</a>
<a class="btn" href="https://diskettelabs.com/" target="_blank">Diskette Labs</a>
</div>
</section>
<!-- ============ HOOK — ORANGE ============ -->
<section class="band orange hook">
<p class="hook-text">I believe pancakes are better than waffles, cereal is soup, and software should <em>feel good to use.</em></p>
</section>
<!-- ============ MARQUEE — YELLOW ============ -->
<div class="band yellow marquee">
<div class="track">
<span>* building emulators *</span><span>* send help *</span><span>* 160 repos and counting *</span><span>* still debugging *</span><span>* geometry dash addict *</span><span>* usually online *</span><span>* ↑ ↑ ↓ ↓ ← → ← → B A *</span>
<span>* building emulators *</span><span>* send help *</span><span>* 160 repos and counting *</span><span>* still debugging *</span><span>* geometry dash addict *</span><span>* usually online *</span><span>* ↑ ↑ ↓ ↓ ← → ← → B A *</span>
</div>
</div>
<!-- ============ STATS — ORANGE ============ -->
<section class="band orange stats">
<div class="stat"><div class="stat-num">160</div><div class="stat-label">Repos online</div></div>
<div class="stat"><div class="stat-num">91</div><div class="stat-label">Stars earned</div></div>
<div class="stat"><div class="stat-num">13</div><div class="stat-label">Watching me</div></div>
<div class="stat"><div class="stat-num">37</div><div class="stat-label">I watch</div></div>
</section>
<!-- ============ ABOUT — YELLOW ============ -->
<section class="band yellow section" id="about">
<span class="sec-label">Level 01 // Identity</span>
<h2 class="sec-title">Who's Miles?</h2>
<p class="sec-sub">the human behind the commits</p>
<div class="about-grid">
<div class="avatar-block" style="text-align:center;">
<div class="avatar-frame"><img src="https://avatars.githubusercontent.com/u/115095719?v=4" alt="Miles Wolf Allen" loading="lazy" width="240" height="240"></div>
<div class="avatar-name">Miles Wolf Allen</div>
<div class="avatar-tag">@mileswolfallen2</div>
</div>
<div class="about-body">
<p>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. 160 repos, 91 stars, and a growing list of things I'm figuring out as I go.</p>
<div class="badge-row">
<span class="badge">Pull Shark x2</span>
<span class="badge">YOLO</span>
<span class="badge">Quickdraw</span>
</div>
<div class="about-cta">
<a class="btn primary" href="https://diskettelabs.com/" target="_blank">Member of Diskette Labs</a>
<a class="btn" href="../about-me.html">More About Me</a>
</div>
<div class="hair-rule"></div>
<div class="page-links">
<a href="../uses.html">Uses</a>
<a href="../now.html">Now</a>
<a href="../colophon.html">Colophon</a>
<a href="../experiments.html" style="color:var(--cobalt);border-color:var(--cobalt);">Internet History</a>
</div>
</div>
</div>
</section>
<!-- ============ SKILLS — COBALT ============ -->
<section class="band cobalt section" id="skills">
<span class="sec-label flat">Level 02 // Loadout</span>
<h2 class="sec-title or-white">My Loadout</h2>
<p class="sec-sub or-white">what I actually know how to use</p>
<div class="skill-group-label">Ready to use</div>
<div class="skill-grid">
<div class="skill"><span>JavaScript</span></div>
<div class="skill alt1"><span>Node.js</span></div>
<div class="skill alt2"><span>HTML5</span></div>
<div class="skill alt3"><span>CSS3</span></div>
<div class="skill"><span>Python</span></div>
<div class="skill alt1"><span>Git</span></div>
<div class="skill alt2"><span>Blender</span></div>
<div class="skill alt3"><span>Unity</span></div>
<div class="skill"><span>Unreal</span></div>
<div class="skill alt1"><span>Cloudflare</span></div>
<div class="skill alt2"><span>Linux</span></div>
<div class="skill alt3"><span>Netlify</span></div>
<div class="skill"><span>Bash</span></div>
<div class="skill alt1"><span>GitHub</span></div>
<div class="skill alt2"><span>Electron</span></div>
<div class="skill alt3"><span>Gelectron</span></div>
</div>
<div class="skill-group-label">Currently unlocking</div>
<div class="skill-grid">
<div class="skill learn"><span>PHP</span></div>
<div class="skill learn alt1"><span>.NET</span></div>
<div class="skill learn alt2"><span>Nix</span></div>
<div class="skill learn alt3"><span>Yarn</span></div>
</div>
</section>
<!-- ============ PROJECTS — YELLOW ============ -->
<section class="band yellow section" id="projects">
<span class="sec-label">Level 03 // Builds</span>
<h2 class="sec-title">The Projects</h2>
<p class="sec-sub">stuff I've made (and some I forked)</p>
<div class="project-grid">
<a class="proj-card" href="../projects/omniemu.html">
<div class="proj-top"><span class="proj-tag">Active</span><span class="proj-meta">TypeScript / v0.3.2</span></div>
<div class="proj-title">OmniEmu 2.0</div>
<div class="proj-desc">All your emulators in one place. Install 20+ emulators, scan your ROMs, and launch games without opening 15 different apps.</div>
</a>
<a class="proj-card" href="../projects/gelectron.html">
<div class="proj-top"><span class="proj-tag">Early</span><span class="proj-meta">Rust + Node.js</span></div>
<div class="proj-title">Gelectron</div>
<div class="proj-desc">Drop-in replacement for Electron using native web views (WKWebView / WebView2 / WebKitGTK) instead of bundling Chromium.</div>
</a>
<a class="proj-card" href="https://vanilla.milesallen.site/" target="_blank">
<div class="proj-top"><span class="proj-tag">Unreleased</span><span class="proj-meta">Vanilla JS</span></div>
<div class="proj-title">Vanilla</div>
<div class="proj-desc">A clean, minimal web experiment. Pure vanilla JS, no frameworks, no cruft.</div>
</a>
<a class="proj-card" href="../projects/fedl.html">
<div class="proj-top"><span class="proj-tag on-orange">Live</span><span class="proj-meta">2196 commits</span></div>
<div class="proj-title">FEDL</div>
<div class="proj-desc">The demon list for Geometry Dash. Ranked levels, run submissions, and a community of people way better at the game than me.</div>
</a>
<a class="proj-card" href="../projects/command-move.html">
<div class="proj-top"><span class="proj-tag">Swift</span><span class="proj-meta">macOS / MIT</span></div>
<div class="proj-title">CommandMove</div>
<div class="proj-desc">True cut-and-paste for Finder on macOS. Select files, Cmd+X, navigate, Cmd+V. What Apple forgot to build.</div>
</a>
<a class="proj-card" href="../projects/noto.html">
<div class="proj-top"><span class="proj-tag">Active</span><span class="proj-meta">Flutter / AI</span></div>
<div class="proj-title">Noto</div>
<div class="proj-desc">Note-taking app with AI built in. Built with Flutter, powered by Cortex AI, and actually good at organizing my chaos.</div>
</a>
<a class="proj-card" href="../projects/nova.html">
<div class="proj-top"><span class="proj-tag">Python</span><span class="proj-meta">Desktop / Web / CLI</span></div>
<div class="proj-title">Nova AI</div>
<div class="proj-desc">AI assistant that runs on your machine. Desktop GUI, web interface, and CLI. No cloud, no subscriptions, just vibes.</div>
</a>
<a class="proj-card" href="../projects/music-app.html">
<div class="proj-top"><span class="proj-tag">JS</span><span class="proj-meta">Apache-2.0</span></div>
<div class="proj-title">Music App</div>
<div class="proj-desc">Music player that doesn't interrupt you with ads. Inspired by YouTube Music but without the annoying parts.</div>
</a>
<a class="proj-card" href="../projects/rhythm-game.html">
<div class="proj-top"><span class="proj-tag">HTML</span><span class="proj-meta">MPL-2.0</span></div>
<div class="proj-title">Rhythm Game</div>
<div class="proj-desc">Hit keys to the beat. Song selection, real-time notes, and keyboard controls. My fingers hurt.</div>
</a>
<a class="proj-card" href="../projects/geode-mod.html">
<div class="proj-top"><span class="proj-tag">WIP</span><span class="proj-meta">MIT</span></div>
<div class="proj-title">FEDL Geode Mod</div>
<div class="proj-desc">Geometry Dash mod that shows the demon list in-game. Roulette mode, banned mod detection, and more.</div>
</a>
<a class="proj-card" href="../projects/decompilations.html">
<div class="proj-top"><span class="proj-tag">HTML</span><span class="proj-meta">MIT</span></div>
<div class="proj-title">Decompilations</div>
<div class="proj-desc">Native PC ports and decompilations of games. Progress tracking for projects that probably shouldn't exist.</div>
</a>
<a class="proj-card" href="../projects/issue-tracker.html">
<div class="proj-top"><span class="proj-tag">HTML</span><span class="proj-meta">Node.js</span></div>
<div class="proj-title">Issue Tracker</div>
<div class="proj-desc">Built my own issue tracker because why not. Node.js backend, no frameworks, just raw determination.</div>
</a>
<a class="proj-card" href="../projects/moon-gaming.html">
<div class="proj-top"><span class="proj-tag">HTML</span><span class="proj-meta">1,542 commits</span></div>
<div class="proj-title">Moon Gaming</div>
<div class="proj-desc">Game hub with 1,500+ commits. Browse, play, and explore a growing library of browser games I made at 2am.</div>
</a>
</div>
</section>
<!-- ============ HIGHLIGHTS — COBALT ============ -->
<section class="band cobalt section" id="highlights">
<span class="sec-label flat">Level 04 // Scoreboard</span>
<h2 class="sec-title or-white">Scoreboard</h2>
<p class="sec-sub or-white">what my projects have achieved</p>
<div class="hl-block">
<h3>FEDL</h3>
<div class="hl-row">
<div class="hl-cell"><div class="hl-num">3,839</div><div class="hl-label">Verified runs</div></div>
<div class="hl-cell"><div class="hl-num">341</div><div class="hl-label">Ranked levels</div></div>
<div class="hl-cell"><div class="hl-num">250+</div><div class="hl-label">Active players</div></div>
<div class="hl-cell"><div class="hl-num">3,800+</div><div class="hl-label">YouTube videos</div></div>
</div>
</div>
<div class="hl-block">
<h3>OmniEmu 2.0</h3>
<div class="hl-row">
<div class="hl-cell"><div class="hl-num">20+</div><div class="hl-label">Emulators</div></div>
<div class="hl-cell"><div class="hl-num">3</div><div class="hl-label">Platforms</div></div>
<div class="hl-cell"><div class="hl-num" style="font-size:clamp(34px,5vw,58px);">v0.3.2</div><div class="hl-label">Latest</div></div>
<div class="hl-cell"><div class="hl-num" style="font-size:clamp(34px,5vw,58px);">TS</div><div class="hl-label">Built with</div></div>
</div>
</div>
<div class="hl-block">
<h3>Other projects</h3>
<div class="hl-row">
<div class="hl-cell"><div class="hl-num">3</div><div class="hl-label">Nova interfaces</div></div>
<div class="hl-cell"><div class="hl-num">5</div><div class="hl-label">Noto AI features</div></div>
<div class="hl-cell"><div class="hl-num">1,542</div><div class="hl-label">Moon Gaming commits</div></div>
<div class="hl-cell"><div class="hl-num" style="font-size:clamp(34px,5vw,58px);">MIT</div><div class="hl-label">Licensed</div></div>
</div>
</div>
</section>
<!-- ============ GITHUB STATS — YELLOW ============ -->
<section class="band yellow section" id="stats">
<span class="sec-label">Level 05 // GitHub</span>
<h2 class="sec-title">Stats</h2>
<p class="sec-sub">the raw numbers, straight from the API</p>
<div class="gh-stats">
<img src="https://github-readme-stats.josselinonduty.fr/api?username=mileswolfallen2&show_icons=true&theme=noctis_minimus" alt="GitHub stats" loading="lazy">
<img src="https://github-readme-stats.josselinonduty.fr/api/top-langs/?username=mileswolfallen2&layout=compact&theme=noctis_minimus" alt="GitHub languages" loading="lazy">
<img src="https://streak-stats.demolab.com/?user=mileswolfallen2&theme=noctis_minimus" alt="GitHub streak" loading="lazy">
</div>
</section>
<!-- ============ BLOG — COBALT ============ -->
<section class="band cobalt section" id="blog">
<span class="sec-label flat">Level 06 // Devlog</span>
<h2 class="sec-title or-white">Devlog</h2>
<p class="sec-sub or-white">things I've learned, broken, and fixed</p>
<div class="blog-grid">
<a class="blog-card" href="diskette-devlog.html">
<div class="blog-date">2026</div>
<div class="blog-title">Focusing on Diskette Labs</div>
<div class="blog-excerpt">I'm co-founder of Diskette Labs, a product design collective started by Owen. It's where my focus is now — but I'm still open to collaborations.</div>
<div class="blog-tags"><span class="blog-tag">Design</span><span class="blog-tag">Collective</span></div>
</a>
<a class="blog-card" href="gelectron-devlog.html">
<div class="blog-date">2026</div>
<div class="blog-title">Why I Built Gelectron</div>
<div class="blog-excerpt">Electron bundles Chromium with every app. 150-300MB per app, hundreds of MBs of RAM. Native web views fix that.</div>
<div class="blog-tags"><span class="blog-tag">Rust</span><span class="blog-tag">Native</span></div>
</a>
<a class="blog-card" href="omniemu-devlog.html">
<div class="blog-date">2026</div>
<div class="blog-title">Why I Built OmniEmu</div>
<div class="blog-excerpt">I got tired of opening 15 different emulator apps. So I built one that manages them all. Here's how it started.</div>
<div class="blog-tags"><span class="blog-tag">TypeScript</span><span class="blog-tag">Electron</span></div>
</a>
<a class="blog-card" href="command-move-devlog.html">
<div class="blog-date">2026</div>
<div class="blog-title">CommandMove: Cut &amp; Paste on Mac</div>
<div class="blog-excerpt">macOS doesn't have Cmd+X for files. I fixed that. Global event taps, AppleScript, and a lot of Accessibility permissions.</div>
<div class="blog-tags"><span class="blog-tag">Swift</span><span class="blog-tag">macOS</span></div>
</a>
<a class="blog-card" href="fedl-devlog.html">
<div class="blog-date">2025</div>
<div class="blog-title">Running the FEDL</div>
<div class="blog-excerpt">What it takes to maintain a Geometry Dash demon list. 3,800+ verified runs, ranked levels, and a community that never sleeps.</div>
<div class="blog-tags"><span class="blog-tag">Node.js</span><span class="blog-tag">Community</span></div>
</a>
<a class="blog-card" href="nova-devlog.html">
<div class="blog-date">2025</div>
<div class="blog-title">Building Nova AI</div>
<div class="blog-excerpt">Local AI that doesn't phone home. Desktop GUI, web interface, CLI — no subscriptions, no cloud, no nonsense.</div>
<div class="blog-tags"><span class="blog-tag">Python</span><span class="blog-tag">AI</span></div>
</a>
</div>
</section>
<!-- ============ CONTACT — ORANGE ============ -->
<section class="band orange section" id="contact">
<span class="sec-label flat">Level 07 // Reach out</span>
<h2 class="sec-title or-white">Get In Touch</h2>
<p class="sec-sub or-white">unless you're a bot, then please go away</p>
<div class="contact-card">
<span class="sticker" style="background:var(--yellow);color:var(--cobalt);"><b>TEXT<br>US</b><small>or email</small></span>
<div class="contact-list">
<a class="contact-row" href="mailto:[email protected]"><span class="k">email</span><span>[email protected]</span></a>
<a class="contact-row" href="https://github.com/mileswolfallen2" target="_blank"><span class="k">github</span><span>mileswolfallen2</span></a>
<a class="contact-row" href="https://replit.com/@MilesAllen1" target="_blank"><span class="k">replit</span><span>@MilesAllen1</span></a>
<a class="contact-row" href="https://codepen.io/mileswolfallen2-the-typescripter" target="_blank"><span class="k">codepen</span><span>mileswolfallen2</span></a>
<a class="contact-row" href="https://me.fedl.site" target="_blank"><span class="k">website</span><span>me.fedl.site</span></a>
</div>
</div>
</section>
<!-- ============ FOOTER — BLACK ============ -->
<footer class="site-foot">
<div class="foot-brand">MILES</div>
<div class="foot-links">
<a href="../uses.html">Uses</a>
<a href="../now.html">Now</a>
<a href="../colophon.html">Colophon</a>
<a href="../experiments.html">Internet History</a>
<a href="https://server.fedl.site/git/miles" target="_blank" rel="noopener">Backup</a>
<a href="../redesign/hub.html">View Redesigns</a>
</div>
<p class="foot-note">Built by Miles · 2026 · Powered by too much coffee and the Konami code<br>Remake in the SICK AGENCY broadside style, with a loud MILES slash intro.</p>
</footer>
</main>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
<script>
(function(){
// Skip intro for reduced-motion / small screens to keep it snappy
var REDUCED = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var SMALL = window.innerWidth < 560;
var intro = document.getElementById('intro');
var stage = document.getElementById('introStage');
var introWord = document.getElementById('introWord');
var tag = document.getElementById('introTag');
var fill = document.getElementById('introFill');
var site = document.getElementById('site');
var heroLoud = document.querySelector('.hero-title .loud');
if (REDUCED || SMALL || !window.gsap) { finish(); return; }
var pct = 0;
var started = false;
var progressTimer = setInterval(function(){
pct += Math.random() * 24;
if (pct >= 100) { pct = 100; clearInterval(progressTimer); }
if (fill) fill.style.width = pct + '%';
}, 200);
function finish(){
if (intro && intro.parentNode) intro.remove();
if (stage && stage.parentNode) stage.remove();
site.style.opacity = '1';
document.body.style.overflow = '';
}
// Hide everything (except hero, which reveals during the merge), readied
// behind the black intro so there's no flash.
function preparePage(){
gsap.set(site, { opacity: 1 });
gsap.set('.site .band:not(.hero), .site nav, .site footer',
{ opacity: 0, y: 60, scaleY: 0.92, transformOrigin: '50% 100%' });
gsap.set('.proj-card,.skill,.stat,.hl-cell,.blog-card,.sec-label,.sec-title,.sec-sub,.badge,.avatar-frame,.sticker,.contact-row,.gh-stats img',
{ opacity: 0, scale: 0.7, rotation: 4 });
gsap.set('.hero .kick', { opacity: 0, x: -28 });
gsap.set('.hero-sub, .hero-status, .hero-actions', { opacity: 0, y: 18 });
gsap.set('.hero .loud', { opacity: 0, scale: 1.15, rotationX: 10, transformOrigin: '0% 50%' });
gsap.set('.hero .sticker', { opacity: 0, scale: 0.5, rotation: -30 });
}
// MILES flies to its spot on the page hero while the hero title pops in.
function revealHero(){
gsap.to('.hero .kick', { opacity: 1, x: 0, duration: 0.5, ease: 'power3.out', onComplete: function(){ gsap.set('.hero .kick', { clearProps: 'transform' }); } });
gsap.to('.hero-sub, .hero-status, .hero-actions', { opacity: 1, y: 0, duration: 0.5, ease: 'power3.out', stagger: 0.08, onComplete: function(){ gsap.set('.hero-sub, .hero-status, .hero-actions', { clearProps: 'transform' }); } });
if (heroLoud) {
var wRect = introWord.getBoundingClientRect();
var hRect = heroLoud.getBoundingClientRect();
var scale = hRect.height / wRect.height;
gsap.to('.hero .loud', { opacity: 1, scale: 1, rotationX: 0, duration: 0.7, ease: 'back.out(1.4)', onComplete: function(){ gsap.set('.hero .loud', { clearProps: 'transform' }); } });
gsap.to(introWord, {
x: (hRect.left + hRect.width/2) - (wRect.left + wRect.width/2),
y: (hRect.top + hRect.height/2) - (wRect.top + wRect.height/2),
scale: scale, opacity: 0, duration: 0.75, ease: 'power3.inOut'
});
}
}
// Reveal a section and its cards with a playful staggered pop.
function revealBlock(el){
gsap.to(el, { opacity: 1, y: 0, scaleY: 1, duration: 0.8, ease: 'back.out(1.4)', transformOrigin: '50% 100%',
onComplete: function(){ gsap.set(el, { clearProps: 'transform' }); }
});
var things = el.querySelectorAll('.proj-card,.skill,.stat,.hl-cell,.blog-card,.sec-label,.sec-title,.sec-sub,.badge,.avatar-frame,.sticker,.contact-row,.gh-stats img');
if (things.length) {
gsap.to(things, { opacity: 1, scale: 1, rotation: 0, duration: 0.7, ease: 'elastic.out(1.1, 0.5)', stagger: 0.06, delay: 0.1,
onComplete: function(){ gsap.set(things, { clearProps: 'transform' }); }
});
}
}
// Pop sections in as they scroll into view.
function setupScrollReveal(){
var BLOCKS = '.site .band:not(.hero), .site footer';
if (typeof IntersectionObserver === 'undefined') {
gsap.to(BLOCKS, { opacity: 1, y: 0, scaleY: 1 });
gsap.to('.proj-card,.skill,.stat,.hl-cell,.blog-card,.sec-label,.sec-title,.sec-sub,.badge,.avatar-frame,.sticker,.contact-row,.gh-stats img', { opacity: 1, scale: 1, rotation: 0 });
return;
}
var io = new IntersectionObserver(function(entries){
entries.forEach(function(entry){
if (!entry.isIntersecting) return;
var el = entry.target;
io.unobserve(el);
revealBlock(el);
});
}, { rootMargin: '0px 0px -12% 0px', threshold: 0.05 });
document.querySelectorAll(BLOCKS).forEach(function(el){ io.observe(el); });
}
function startSequence() {
if (started) return;
started = true;
document.body.style.overflow = 'hidden';
preparePage();
var tl = gsap.timeline({ onComplete: finish });
// ---- 1) black hold, tag + bar breathe in ----
tl.set(intro, { backgroundColor: '#000' })
.fromTo(tag, { opacity: 0, y: 10 }, { opacity: 1, y: 0, duration: 0.45, ease: 'power2.out' }, 0.1)
.fromTo(fill, { width: '0%' }, { width: '100%', duration: 1.3, ease: 'power2.inOut' }, 0.1);
// ---- 2) MILES SLIDES IN from the left, big and springy ----
tl.fromTo(introWord,
{ x: '-120vw', scale: 3.2, opacity: 0, skewX: -14 },
{ x: 0, scale: 1, opacity: 1, skewX: 0, duration: 1.15, ease: 'back.out(1.3)' }, 0.5);
// hold the beat, then
tl.to(tag, { opacity: 0, duration: 0.25 }, 2.0)
.to(fill, { width: '100%', duration: 0.2 }, 2.0)
// ---- 3) MILES flies to its spot in the hero ----
.add(function(){
revealHero();
gsap.fromTo('.nav', { opacity: 0, y: -40 }, { opacity: 1, y: 0, duration: 0.6, ease: 'back.out(1.4)', onComplete: function(){ gsap.set('.nav', { clearProps: 'transform' }); } });
gsap.fromTo('.hero .sticker', { opacity: 0, scale: 0.5, rotation: -30 }, { opacity: 1, scale: 1, rotation: 0, duration: 0.7, ease: 'back.out(1.6)', onComplete: function(){ gsap.set('.hero .sticker', { clearProps: 'transform' }); } });
}, 2.25)
// ---- 4) open the curtain ----
.to(intro, { opacity: 0, duration: 0.4, ease: 'power2.inOut' }, 2.5)
.to(stage, { opacity: 0, duration: 0.25 }, 2.4)
.add(setupScrollReveal, 2.6);
document.body.style.overflow = '';
}
window.addEventListener('load', function(){ setTimeout(startSequence, 400); });
setTimeout(startSequence, 3000);
})();
</script>
</body>
</html>