Files

130 lines
30 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Miles City // A Personal Portfolio</title>
<meta name="description" content="Explore Miles City — a map of tools, games, communities, and ideas by Miles Wolf Allen.">
<meta name="theme-color" content="#101a1f">
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' rx='18' fill='%23d9f99d'/%3E%3Cpath d='M23 73V27h13l14 19 14-19h13v46H64V51L50 68 36 51v22z' fill='%23101a1f'/%3E%3C/svg%3E">
<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=DM+Mono:wght@400;500&family=Manrope:wght@400;500;600;700;800&family=Space+Grotesk:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
:root {
--night:#101a1f; --night-2:#17242a; --paper:#edf0e6; --muted:#879791; --line:rgba(237,240,230,.15);
--lime:#d9f99d; --orange:#ff8365; --cyan:#88d8d2; --violet:#b6a5ff; --mono:'DM Mono',monospace; --display:'Space Grotesk',sans-serif; --body:Manrope,sans-serif; --ease:cubic-bezier(.2,.8,.2,1);
}
* { box-sizing:border-box; }
html { scroll-behavior:smooth; background:var(--night); }
body { margin:0; color:var(--paper); background:var(--night); font-family:var(--body); overflow-x:hidden; }
body.panel-open { overflow:hidden; }
::selection { color:var(--night); background:var(--lime); }
a { color:inherit; text-decoration:none; }
button { color:inherit; font:inherit; cursor:pointer; }
.sr-only { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0; }
.grain { position:fixed; inset:0; z-index:30; pointer-events:none; opacity:.045; background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 160 160' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); mix-blend-mode:screen; }
.stars { position:fixed; inset:0; z-index:-3; opacity:.75; background-image:radial-gradient(circle,rgba(237,240,230,.7) 0 1px,transparent 1.5px),radial-gradient(circle,rgba(136,216,210,.45) 0 1px,transparent 1.5px); background-size:91px 91px,147px 147px; background-position:17px 21px,55px 4px; }
.glow { position:fixed; z-index:-2; left:var(--mx,50%); top:var(--my,40%); width:600px; height:600px; pointer-events:none; transform:translate(-50%,-50%); background:radial-gradient(circle,rgba(136,216,210,.1),transparent 67%); }
.progress { position:fixed; z-index:50; left:0; top:0; width:0; height:3px; background:var(--lime); box-shadow:0 0 14px var(--lime); }
.topbar { position:fixed; z-index:20; top:0; left:0; right:0; height:76px; display:flex; align-items:center; justify-content:space-between; gap:20px; padding:0 5vw; border-bottom:1px solid transparent; transition:background .3s,border-color .3s; }
.topbar.scrolled { background:rgba(16,26,31,.8); border-color:var(--line); backdrop-filter:blur(17px); }
.brand { display:flex; align-items:center; gap:11px; font:500 11px var(--mono); letter-spacing:.1em; text-transform:uppercase; }
.brand i { width:12px; height:12px; display:block; border:2px solid var(--lime); border-radius:50% 50% 50% 0; transform:rotate(-45deg); box-shadow:0 0 14px rgba(217,249,157,.5); }
.topnav { display:flex; gap:30px; color:var(--muted); font:400 10px var(--mono); letter-spacing:.08em; text-transform:uppercase; }
.topnav a { position:relative; padding:8px 0; }
.topnav a::after { content:''; position:absolute; left:0; right:100%; bottom:1px; height:1px; background:var(--lime); transition:right .3s var(--ease); }
.topnav a:hover,.topnav a:focus-visible { color:var(--paper); } .topnav a:hover::after,.topnav a:focus-visible::after { right:0; }
.city-status { color:var(--lime); font:400 10px var(--mono); text-transform:uppercase; } .city-status::before { content:'●'; margin-right:7px; animation:blink 1.7s steps(1) infinite; } @keyframes blink { 50% { opacity:.3; } }
@media(max-width:680px) { .topbar { height:64px; } .topnav { display:none; } .city-status { font-size:9px; } }
.hero { position:relative; min-height:100svh; padding:135px 5vw 75px; overflow:hidden; }
.hero-copy { position:relative; z-index:4; width:min(450px,90vw); }
.eyebrow { display:flex; align-items:center; gap:12px; color:var(--lime); font:400 10px var(--mono); letter-spacing:.14em; text-transform:uppercase; }
.eyebrow::before { content:''; width:29px; height:1px; background:var(--lime); }
h1 { margin:22px 0 24px; font:700 clamp(4.5rem,11.5vw,11rem)/.78 var(--display); letter-spacing:-.12em; }
h1 span { display:block; } h1 .outline { color:transparent; -webkit-text-stroke:1px var(--paper); } h1 .lime { color:var(--lime); } h1 em { color:var(--orange); font:600 .76em/.8 Georgia,serif; letter-spacing:-.04em; }
.hero-copy p { max-width:400px; color:var(--muted); font-size:14px; line-height:1.8; }
.hero-copy p strong { color:var(--paper); font-weight:600; }
.hero-actions { display:flex; flex-wrap:wrap; align-items:center; gap:18px; margin-top:30px; }
.primary { display:inline-flex; align-items:center; gap:12px; padding:13px 16px; color:var(--night); background:var(--lime); box-shadow:5px 5px 0 var(--orange); font:500 10px var(--mono); text-transform:uppercase; transition:transform .2s var(--ease),box-shadow .2s var(--ease); }
.primary:hover { transform:translate(-3px,-3px); box-shadow:8px 8px 0 var(--orange); }
.primary::after { content:'↘'; font-size:15px; }
.quiet-link { display:inline-flex; align-items:center; gap:9px; color:var(--paper); font:400 10px var(--mono); text-transform:uppercase; }
.quiet-link::before { content:''; width:24px; height:1px; background:var(--paper); transition:width .25s var(--ease); } .quiet-link:hover { color:var(--lime); } .quiet-link:hover::before { width:42px; background:var(--lime); }
.map-wrap { position:absolute; z-index:1; right:-4vw; top:11vh; width:min(78vw,1050px); height:min(82vh,760px); min-height:510px; perspective:1100px; }
.map-stage { position:absolute; inset:0; transform:rotateX(48deg) rotateZ(-9deg) rotateY(-4deg); transform-style:preserve-3d; transition:transform .8s var(--ease); }
.map-surface { position:absolute; inset:4%; overflow:hidden; border:1px solid rgba(217,249,157,.35); background:linear-gradient(135deg,rgba(25,43,45,.97),rgba(14,25,30,.98)); box-shadow:28px 30px 0 rgba(0,0,0,.22),0 0 80px rgba(136,216,210,.08); transform-style:preserve-3d; }
.map-surface::before { content:''; position:absolute; inset:0; opacity:.17; background-image:linear-gradient(rgba(136,216,210,.2) 1px,transparent 1px),linear-gradient(90deg,rgba(136,216,210,.2) 1px,transparent 1px); background-size:42px 42px; }
.map-surface::after { content:'MILES CITY / EST. 2008'; position:absolute; right:25px; top:20px; color:rgba(237,240,230,.36); font:400 9px var(--mono); letter-spacing:.12em; }
.city-map { position:absolute; inset:4%; width:92%; height:92%; overflow:visible; }
.map-label { position:absolute; z-index:2; color:rgba(237,240,230,.33); font:400 9px var(--mono); letter-spacing:.14em; text-transform:uppercase; pointer-events:none; }
.label-north { left:13%; top:10%; } .label-west { left:9%; bottom:20%; } .label-east { right:9%; top:39%; } .label-south { left:44%; bottom:10%; }
.map-legend { position:absolute; z-index:3; left:24px; bottom:21px; display:flex; gap:16px; color:rgba(237,240,230,.52); font:400 8px var(--mono); text-transform:uppercase; } .map-legend span::before { content:''; display:inline-block; width:7px; height:7px; margin-right:6px; border:1px solid currentColor; border-radius:50%; } .map-legend span:first-child::before { background:var(--lime); border-color:var(--lime); } .map-legend span:last-child::before { background:var(--orange); border-color:var(--orange); }
.road { fill:none; stroke:#66817d; stroke-linecap:round; stroke-linejoin:round; } .road.major { stroke:#90aca3; stroke-width:13; opacity:.27; } .road.minor { stroke:#52706d; stroke-width:5; opacity:.45; } .road.center { stroke:var(--lime); stroke-width:1; stroke-dasharray:9 14; opacity:.6; } .water { fill:#12313b; stroke:#4b7777; stroke-width:1; opacity:.78; } .park { fill:#1f423b; stroke:#6a9b75; stroke-width:1; opacity:.8; } .district { fill:#1a2d31; stroke:rgba(217,249,157,.28); stroke-width:1; } .block { fill:#263d3d; opacity:.72; }
.pin { position:absolute; z-index:5; display:flex; align-items:center; gap:8px; min-width:125px; padding:8px 10px; border:1px solid rgba(237,240,230,.3); color:var(--paper); background:rgba(16,26,31,.83); text-align:left; transform:translate(-50%,-50%); backdrop-filter:blur(8px); transition:transform .3s var(--ease),background .25s,border-color .25s,box-shadow .25s; }
.pin:hover,.pin:focus-visible,.pin.active { z-index:8; border-color:var(--lime); background:var(--lime); color:var(--night); outline:none; box-shadow:7px 7px 0 rgba(0,0,0,.25); transform:translate(-50%,-50%) translateY(-7px); }
.pin::before { content:''; flex:0 0 9px; width:9px; height:9px; border-radius:50% 50% 50% 0; background:var(--orange); transform:rotate(-45deg); } .pin.active::before,.pin:hover::before,.pin:focus-visible::before { background:var(--night); }
.pin .pin-name { display:block; font:500 10px var(--mono); text-transform:uppercase; letter-spacing:.05em; } .pin .pin-kind { display:block; margin-top:3px; color:var(--muted); font:400 8px var(--mono); text-transform:uppercase; } .pin:hover .pin-kind,.pin:focus-visible .pin-kind,.pin.active .pin-kind { color:rgba(16,26,31,.68); }
.pin-arcade { left:38%; top:30%; } .pin-foundry { left:69%; top:28%; } .pin-stadium { left:72%; top:66%; } .pin-library { left:35%; top:70%; } .pin-home { left:51%; top:49%; } .pin-contact { left:20%; top:56%; }
.route { position:absolute; z-index:1; width:1px; height:60px; background:linear-gradient(var(--lime),transparent); transform-origin:top; opacity:.6; }
.route-a { left:38%; top:34%; transform:rotate(27deg); } .route-b { left:67%; top:32%; transform:rotate(-30deg); } .route-c { left:70%; top:62%; transform:rotate(18deg); } .route-d { left:39%; top:66%; transform:rotate(-18deg); }
.map-pulse { position:absolute; z-index:4; width:20px; height:20px; border:1px solid var(--lime); border-radius:50%; transform:translate(-50%,-50%); animation:ping 2.4s ease-out infinite; pointer-events:none; } .pulse-home { left:51%; top:49%; } @keyframes ping { 0% { opacity:.8; transform:translate(-50%,-50%) scale(.55); } 100% { opacity:0; transform:translate(-50%,-50%) scale(2.7); } }
@media(max-width:900px) { .map-wrap { right:-13vw; top:27vh; width:105vw; height:58vh; min-height:430px; opacity:.9; } .map-stage { transform:rotateX(48deg) rotateZ(-7deg) rotateY(0); } .hero-copy { position:relative; z-index:6; } .pin { min-width:105px; } .pin .pin-kind { display:none; } }
@media(max-width:580px) { .hero { min-height:920px; padding:110px 5vw 70px; } .map-wrap { top:34vh; right:-27vw; width:135vw; height:520px; min-height:0; } .map-surface { inset:5%; } .pin { min-width:0; padding:7px; } .pin .pin-name { font-size:8px; } .pin::before { width:7px; height:7px; flex-basis:7px; } .pin-home,.pin-contact { display:none; } .map-legend { display:none; } }
.panel-scrim { position:fixed; z-index:39; inset:0; background:rgba(3,7,9,.55); opacity:0; visibility:hidden; transition:opacity .35s,visibility .35s; }
.panel-scrim.open { opacity:1; visibility:visible; }
.city-panel { position:fixed; z-index:40; top:50%; right:4vw; width:min(430px,calc(100vw - 40px)); padding:29px; border:1px solid var(--lime); background:rgba(18,29,32,.96); box-shadow:18px 18px 0 rgba(0,0,0,.3); transform:translate(45px,-50%); opacity:0; visibility:hidden; transition:opacity .4s ease,transform .55s var(--ease),visibility .4s; backdrop-filter:blur(15px); }
.city-panel.open { transform:translate(0,-50%); opacity:1; visibility:visible; }
.panel-close { position:absolute; right:14px; top:14px; width:27px; height:27px; display:grid; place-items:center; border:1px solid var(--line); color:var(--muted); background:transparent; font-size:17px; line-height:1; } .panel-close:hover { color:var(--night); background:var(--lime); border-color:var(--lime); }
.panel-kicker { color:var(--orange); font:400 9px var(--mono); text-transform:uppercase; letter-spacing:.13em; } .city-panel h2 { max-width:340px; margin:17px 0 13px; font:600 clamp(2.4rem,5vw,4rem)/.84 var(--display); letter-spacing:-.1em; } .city-panel p { margin:0; color:var(--muted); font-size:13px; line-height:1.8; } .panel-rule { height:1px; margin:24px 0 15px; background:var(--line); } .panel-meta { display:flex; justify-content:space-between; gap:15px; color:var(--muted); font:400 9px var(--mono); text-transform:uppercase; } .panel-meta b { color:var(--lime); font-weight:400; } .panel-link { display:inline-flex; gap:10px; align-items:center; margin-top:25px; color:var(--lime); font:500 10px var(--mono); text-transform:uppercase; } .panel-link::after { content:'↗'; font-size:16px; } .panel-link:hover { color:var(--orange); }
@media(max-width:580px) { .city-panel { top:auto; right:15px; bottom:15px; left:15px; width:auto; padding:24px; transform:translateY(30px); } .city-panel.open { transform:translateY(0); } .city-panel h2 { font-size:2.7rem; } }
.directory { position:relative; z-index:4; padding:145px 0 105px; background:var(--night); border-top:1px solid var(--line); }
.directory-inner { width:min(1150px,90vw); margin:auto; }
.section-head { display:flex; align-items:end; justify-content:space-between; gap:30px; margin-bottom:48px; } .section-label { color:var(--lime); font:400 10px var(--mono); letter-spacing:.14em; text-transform:uppercase; } h2.section-title { margin:10px 0 0; font:600 clamp(3rem,7vw,6.5rem)/.8 var(--display); letter-spacing:-.11em; } h2.section-title em { color:var(--orange); font:600 .82em Georgia,serif; letter-spacing:-.04em; } .section-head p { max-width:290px; margin:0 0 4px; color:var(--muted); font:400 11px/1.75 var(--mono); }
.directory-list { display:grid; border-top:1px solid var(--line); } .directory-item { display:grid; grid-template-columns:57px minmax(160px,.8fr) minmax(260px,1.3fr) auto auto; gap:20px; align-items:center; padding:23px 0; border-bottom:1px solid var(--line); transition:padding .25s var(--ease),background .25s; } .directory-item:hover { padding-left:13px; background:linear-gradient(90deg,rgba(217,249,157,.08),transparent 70%); } .directory-no { color:var(--orange); font:400 10px var(--mono); } .directory-item h3 { margin:0; font:600 18px var(--display); letter-spacing:-.05em; } .directory-item p { margin:0; color:var(--muted); font:400 11px/1.65 var(--mono); } .directory-type { color:var(--lime); font:400 9px var(--mono); text-transform:uppercase; } .directory-arrow { color:var(--lime); font-size:18px; }
.city-bands { display:grid; grid-template-columns:1fr 1fr; gap:2px; margin-top:120px; background:var(--line); } .city-band { min-height:260px; padding:28px; background:var(--night-2); } .city-band h3 { margin:10px 0 13px; font:600 clamp(2rem,4vw,3.4rem)/.85 var(--display); letter-spacing:-.09em; } .city-band h3 em { color:var(--lime); font:600 .88em Georgia,serif; } .city-band p { max-width:410px; color:var(--muted); font-size:13px; line-height:1.8; } .city-band a { display:inline-block; margin-top:14px; color:var(--lime); font:400 10px var(--mono); text-transform:uppercase; } .city-band a:hover { color:var(--orange); }
.footer-links { display:flex; justify-content:space-between; flex-wrap:wrap; gap:20px; margin-top:80px; padding-top:24px; border-top:1px solid var(--line); color:var(--muted); font:400 10px var(--mono); text-transform:uppercase; } .footer-links a { color:var(--lime); } .footer-links a:hover { color:var(--orange); }
@media(max-width:760px) { .directory { padding-top:100px; } .section-head { display:block; } .section-head p { margin-top:20px; } .directory-item { grid-template-columns:35px 1fr auto; gap:10px; } .directory-item p { grid-column:2 / -1; grid-row:2; } .directory-type { grid-column:2; grid-row:3; } .city-bands { grid-template-columns:1fr; margin-top:90px; } }
.reveal { opacity:0; transform:translateY(26px); transition:opacity .75s var(--ease),transform .75s var(--ease); } .reveal.visible { opacity:1; transform:none; }
@media(prefers-reduced-motion:reduce) { *,*::before,*::after { animation-duration:.001ms!important; animation-iteration-count:1!important; transition-duration:.001ms!important; scroll-behavior:auto!important; } .reveal { opacity:1; transform:none; } .map-stage { transform:rotateX(48deg) rotateZ(-9deg) rotateY(-4deg)!important; } }
</style>
</head>
<body>
<div class="stars" aria-hidden="true"></div><div class="glow" aria-hidden="true"></div><div class="grain" aria-hidden="true"></div><div class="progress" id="progress"></div>
<nav class="topbar" id="topbar"><a class="brand" href="#top"><i></i><span>Miles City / city guide</span></a><div class="topnav"><a href="#city-map">Map</a><a href="#directory">Directory</a><a href="#about">About</a><a href="#contact">Contact</a></div><span class="city-status">city is open</span></nav>
<main id="top">
<section class="hero" id="city-map"><div class="hero-copy"><div class="eyebrow">welcome to miles city</div><h1><span class="outline">MILES</span><span>WOLF <em>ALLEN</em><span class="lime">.</span></span></h1><p>A map of the things I build: <strong>tools, games, communities, and experiments</strong> connected by one slightly overactive curiosity.</p><div class="hero-actions"><a class="primary" href="#map-surface">explore the city</a><a class="quiet-link" href="#directory">skip to the directory</a></div></div><div class="map-wrap" id="mapWrap"><div class="map-stage" id="mapStage"><div class="map-surface" id="map-surface"><svg class="city-map" viewBox="0 0 1000 650" role="img" aria-label="Stylized map of Miles City showing roads, parks, water, and districts"><path class="water" d="M760 0h240v650H850c35-54 42-108 13-158-25-44-28-83-8-126 22-49 3-94-35-124-40-32-63-78-60-130z"></path><path class="park" d="M78 404c45-31 101-31 135 4 29 31 23 87-8 112-45 36-114 30-148-12-24-29-17-79 21-104z"></path><path class="park" d="M426 49c62-24 127-4 143 42 13 39-28 78-81 79-62 0-111-47-95-86 6-15 16-27 33-35z"></path><path class="district" d="M146 74h242l31 145-89 96-169-28-52-117z"></path><path class="district" d="M438 177l143-31 142 83-22 155-142 20-124-91z"></path><path class="district" d="M130 323l173-25 119 95-30 154-178 34-127-94z"></path><path class="district" d="M431 404l128-31 132 21 70 130-161 77-166-74z"></path><path class="road major" d="M-30 288C174 268 311 281 466 338S747 448 1028 370"></path><path class="road major" d="M352-25c35 150 47 257 34 357s-31 190-4 347"></path><path class="road minor" d="M76 122c165 94 308 105 461 84s259-13 410 94"></path><path class="road minor" d="M27 490c154-95 283-108 409-63s278 98 537 21"></path><path class="road minor" d="M192 20c43 124 57 245 39 369s-3 190 55 277"></path><path class="road minor" d="M602 16c-43 113-59 233-33 343s72 180 151 291"></path><path class="road center" d="M-30 288C174 268 311 281 466 338S747 448 1028 370"></path><path class="road center" d="M352-25c35 150 47 257 34 357s-31 190-4 347"></path><g class="blocks"><rect class="block" x="176" y="122" width="54" height="35" rx="3"></rect><rect class="block" x="246" y="102" width="72" height="42" rx="3"></rect><rect class="block" x="174" y="188" width="95" height="31" rx="3"></rect><rect class="block" x="481" y="222" width="54" height="45" rx="3"></rect><rect class="block" x="558" y="202" width="75" height="35" rx="3"></rect><rect class="block" x="467" y="291" width="82" height="34" rx="3"></rect><rect class="block" x="590" y="284" width="59" height="53" rx="3"></rect><rect class="block" x="191" y="363" width="70" height="42" rx="3"></rect><rect class="block" x="282" y="346" width="77" height="31" rx="3"></rect><rect class="block" x="151" y="435" width="96" height="39" rx="3"></rect><rect class="block" x="268" y="439" width="63" height="55" rx="3"></rect><rect class="block" x="466" y="438" width="71" height="35" rx="3"></rect><rect class="block" x="552" y="423" width="72" height="47" rx="3"></rect></g></svg><span class="map-label label-north">north loop / ideas</span><span class="map-label label-west">west commons</span><span class="map-label label-east">east river / systems</span><span class="map-label label-south">southside / play</span><span class="route route-a"></span><span class="route route-b"></span><span class="route route-c"></span><span class="route route-d"></span><span class="map-pulse pulse-home"></span><button class="pin pin-arcade" type="button" data-location="arcade"><span><b class="pin-name">Arcade</b><small class="pin-kind">OmniEmu / tools</small></span></button><button class="pin pin-foundry" type="button" data-location="foundry"><span><b class="pin-name">Foundry</b><small class="pin-kind">Gelectron / systems</small></span></button><button class="pin pin-stadium" type="button" data-location="stadium"><span><b class="pin-name">Stadium</b><small class="pin-kind">FEDL / community</small></span></button><button class="pin pin-library" type="button" data-location="library"><span><b class="pin-name">Library</b><small class="pin-kind">Noto / notes</small></span></button><button class="pin pin-home" type="button" data-location="home"><span><b class="pin-name">Home Base</b><small class="pin-kind">About Miles</small></span></button><button class="pin pin-contact" type="button" data-location="contact"><span><b class="pin-name">Post Office</b><small class="pin-kind">Say hello</small></span></button><div class="map-legend"><span>district</span><span>open channel</span></div></div></div>
</section>
<section class="directory" id="directory"><div class="directory-inner"><div class="section-head reveal"><div><div class="section-label">the city guide / 01</div><h2 class="section-title">A readable<br><em>directory.</em></h2></div><p>Prefer the direct route? Heres every district with the useful details up front.</p></div><div class="directory-list"><a class="directory-item reveal" href="https://milesallen.site/projects/omniemu.html"><span class="directory-no">01</span><h3>OmniEmu 2.0</h3><p>All your emulators in one place — scan ROMs, install what you need, and launch without opening fifteen different apps.</p><span class="directory-type">arcade / active ↗</span><span class="directory-arrow"></span></a><a class="directory-item reveal" href="https://milesallen.site/projects/gelectron.html"><span class="directory-no">02</span><h3>Gelectron</h3><p>A drop-in Electron replacement using native web views instead of bundling an entire copy of Chromium with every app.</p><span class="directory-type">foundry / in progress ↗</span><span class="directory-arrow"></span></a><a class="directory-item reveal" href="https://milesallen.site/projects/fedl.html"><span class="directory-no">03</span><h3>FEDL</h3><p>The Geometry Dash demon list: ranked levels, run submissions, and a community that keeps raising the ceiling.</p><span class="directory-type">stadium / live ↗</span><span class="directory-arrow"></span></a><a class="directory-item reveal" href="https://milesallen.site/projects/noto.html"><span class="directory-no">04</span><h3>Noto</h3><p>Note-taking with AI built in — a calmer way to turn a pile of fragments into something you can find later.</p><span class="directory-type">library / active ↗</span><span class="directory-arrow"></span></a><a class="directory-item reveal" href="https://milesallen.site/projects/moon-gaming.html"><span class="directory-no">05</span><h3>Moon Gaming</h3><p>A browser game hub with a suspicious number of commits and a library that keeps getting bigger at 2am.</p><span class="directory-type">arcade annex / growing ↗</span><span class="directory-arrow"></span></a></div><div class="city-bands"><article class="city-band reveal" id="about"><div class="section-label">home base / 02</div><h3>The person<br>behind the <em>map.</em></h3><p>Im Miles — a developer and 3D artist, co-founder of Diskette Labs, and a student who spends a lot of time turning “that should be easier” into a repository.</p><a href="../about-me.html">read more about me ↗</a></article><article class="city-band reveal" id="contact"><div class="section-label">post office / 03</div><h3>Send a<br><em>message.</em></h3><p>Have a question, a strange idea, or a link to something youre making? The city is open to visitors.</p><a href="mailto:[email protected]">open a channel ↗</a></article></div><div class="footer-links"><span>© 2026 Miles Wolf Allen / Miles City</span><a href="https://github.com/mileswolfallen2" target="_blank" rel="noopener">github ↗</a><a href="https://diskettelabs.com/" target="_blank" rel="noopener">diskette labs ↗</a><a href="#top">return to city hall ↑</a></div></div></section>
</main>
<div class="panel-scrim" id="panelScrim"></div><aside class="city-panel" id="cityPanel" role="dialog" aria-modal="true" aria-labelledby="panelTitle"><button class="panel-close" id="panelClose" type="button" aria-label="Close location details">×</button><div class="panel-kicker" id="panelKicker">district / arcade</div><h2 id="panelTitle">OmniEmu 2.0</h2><p id="panelDescription">All your emulators in one place. Scan ROMs, install what you need, and launch without opening fifteen different apps.</p><div class="panel-rule"></div><div class="panel-meta"><span id="panelStack">typescript / desktop</span><b id="panelStatus">active</b></div><a class="panel-link" id="panelLink" href="https://milesallen.site/projects/omniemu.html" target="_blank" rel="noopener">visit the project</a></aside>
<script>
(() => {
const locations = {
arcade:{ kicker:'district / arcade',title:'OmniEmu 2.0',description:'All your emulators in one place. Scan ROMs, install what you need, and launch without opening fifteen different apps.',stack:'typescript / desktop',status:'active',link:'https://milesallen.site/projects/omniemu.html' },
foundry:{ kicker:'district / industrial systems',title:'Gelectron',description:'A drop-in Electron replacement using native web views instead of bundling an entire copy of Chromium with every app.',stack:'rust / node / native',status:'in progress',link:'https://milesallen.site/projects/gelectron.html' },
stadium:{ kicker:'district / community stadium',title:'FEDL',description:'The Geometry Dash demon list: ranked levels, run submissions, and a community that keeps raising the ceiling.',stack:'node / community',status:'live',link:'https://milesallen.site/projects/fedl.html' },
library:{ kicker:'district / library of thoughts',title:'Noto',description:'Note-taking with AI built in — a calmer way to turn a pile of fragments into something you can find later.',stack:'flutter / ai',status:'active',link:'https://milesallen.site/projects/noto.html' },
home:{ kicker:'neighborhood / home base',title:'Miles Wolf Allen',description:'Developer, 3D artist, co-founder of Diskette Labs, and a person who keeps turning “that should be easier” into a repository.',stack:'curiosity / perpetual beginner',status:'online',link:'../about-me.html' },
contact:{ kicker:'neighborhood / post office',title:'Come say hello.',description:'Have a question, a strange idea, or a link to something youre making? The city is open to visitors.',stack:'email / github / diskette labs',status:'accepting mail',link:'mailto:[email protected]' }
};
const body=document.body, panel=document.getElementById('cityPanel'), scrim=document.getElementById('panelScrim');
const openLocation = key => { const item=locations[key]; document.querySelectorAll('.pin').forEach(pin=>pin.classList.toggle('active',pin.dataset.location===key)); document.getElementById('panelKicker').textContent=item.kicker; document.getElementById('panelTitle').textContent=item.title; document.getElementById('panelDescription').textContent=item.description; document.getElementById('panelStack').textContent=item.stack; document.getElementById('panelStatus').textContent=item.status; document.getElementById('panelLink').href=item.link; panel.classList.add('open'); scrim.classList.add('open'); body.classList.add('panel-open'); document.getElementById('panelClose').focus(); };
const closeLocation = () => { panel.classList.remove('open'); scrim.classList.remove('open'); body.classList.remove('panel-open'); document.querySelectorAll('.pin').forEach(pin=>pin.classList.remove('active')); };
document.querySelectorAll('.pin').forEach(pin=>pin.addEventListener('click',()=>openLocation(pin.dataset.location))); document.getElementById('panelClose').addEventListener('click',closeLocation); scrim.addEventListener('click',closeLocation); addEventListener('keydown',event=>{ if(event.key==='Escape') closeLocation(); });
const topbar=document.getElementById('topbar'), progress=document.getElementById('progress'); const updateScroll=()=>{ topbar.classList.toggle('scrolled',scrollY>20); const max=document.documentElement.scrollHeight-innerHeight; progress.style.width=`${max?scrollY/max*100:0}%`; }; addEventListener('scroll',updateScroll,{passive:true}); updateScroll();
const glow=document.querySelector('.glow'); addEventListener('pointermove',event=>{ document.documentElement.style.setProperty('--mx',`${event.clientX}px`); document.documentElement.style.setProperty('--my',`${event.clientY}px`); if(glow) { glow.style.left=`${event.clientX}px`; glow.style.top=`${event.clientY}px`; } },{passive:true});
const mapStage=document.getElementById('mapStage'); addEventListener('pointermove',event=>{ if(matchMedia('(pointer:coarse)').matches) return; const x=event.clientX/innerWidth-.5; const y=event.clientY/innerHeight-.5; mapStage.style.transform=`rotateX(${48-y*3}deg) rotateZ(${-9+x*2}deg) rotateY(${-4+x*3}deg)`; },{passive:true});
const reveal=new IntersectionObserver(entries=>entries.forEach(entry=>{ if(entry.isIntersecting){ entry.target.classList.add('visible'); reveal.unobserve(entry.target); } }),{threshold:.12}); document.querySelectorAll('.reveal').forEach((item,index)=>{ item.style.transitionDelay=`${Math.min(index%4,3)*70}ms`; reveal.observe(item); });
})();
</script>
</body>
</html>