Files
miles-web/redesign/redesign expression three.html
T

844 lines
50 KiB
HTML
Raw 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.0">
<title>MILES WOLF ALLEN — SOFT ⇄ LOUD</title>
<meta name="description" content="Redesign expression three — modern simplistic maximalism. The page fluctuates between Swiss-quiet and neon-loud as you scroll.">
<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' fill='%23FF2EA6'/%3E%3Ctext x='50' y='74' font-size='64' font-family='Arial Black' font-weight='900' text-anchor='middle' fill='%23000'%3EM%3C/text%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=Anton&family=Instrument+Serif:ital@0;1&family=Space+Grotesk:wght@400;500;700&family=Space+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css">
<style>
*,*::before,*::after{margin:0;padding:0;box-sizing:border-box}
:root{
--paper:#F4F1EA;
--ink:#131311;
--mut:#7d7a72;
--line:rgba(19,19,17,.16);
--yellow:#F7FF00;
--pink:#FF2EA6;
--cyan:#00F4FF;
--orange:#FF5C00;
--green:#00FF85;
--purple:#8A2BFF;
--grot:'Space Grotesk',sans-serif;
--mono:'Space Mono',monospace;
--disp:'Anton',Impact,sans-serif;
--serif:'Instrument Serif',serif;
--ease:cubic-bezier(.16,1,.3,1);
}
html{scroll-behavior:smooth;overflow-x:hidden;scrollbar-width:thin;scrollbar-color:var(--ink) var(--paper)}
body{
background:var(--paper);color:var(--ink);
font-family:var(--grot);font-size:16px;line-height:1.6;
overflow-x:hidden;-webkit-font-smoothing:antialiased;
transition:background .5s ease,color .5s ease;
}
::selection{background:var(--pink);color:#000}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:none;cursor:pointer}
img,svg{display:block}
.spark{position:fixed;width:6px;height:6px;border-radius:50%;pointer-events:none;z-index:1200;margin:-3px}
.loader{position:fixed;inset:0;z-index:1100;background:var(--paper);color:var(--ink);
display:flex;flex-direction:column;justify-content:space-between;padding:28px 5vw}
.loader-top{display:flex;justify-content:space-between;font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--mut)}
.loader-mid{align-self:center;font-family:var(--disp);font-size:clamp(60px,14vw,180px);line-height:1;text-transform:uppercase;letter-spacing:.01em}
.loader-mid.is-loud{color:transparent;-webkit-text-stroke:2px var(--pink)}
.loader-bot{display:flex;align-items:flex-end;justify-content:space-between;gap:24px}
.loader-count{font-family:var(--mono);font-weight:700;font-size:clamp(28px,5vw,54px);line-height:1}
.loader-count small{font-size:.4em;color:var(--mut);font-weight:400}
.loader-bar{flex:1;height:2px;background:var(--line);position:relative;overflow:hidden;margin-bottom:10px}
.loader-bar i{position:absolute;inset:0;background:var(--pink);transform-origin:left;transform:scaleX(0)}
.nav{position:sticky;top:0;z-index:800;display:flex;align-items:center;justify-content:space-between;gap:18px;
padding:14px 5vw;background:color-mix(in srgb,var(--paper) 88%,transparent);
backdrop-filter:blur(10px);border-bottom:1px solid var(--line)}
.brand{font-family:var(--mono);font-weight:700;font-size:13px;letter-spacing:.06em}
.brand span{color:var(--mut);font-weight:400}
.nav-links{display:flex;gap:26px}
.nav-links a{font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--mut);transition:color .25s}
.nav-links a:hover{color:var(--pink)}
.switch{display:flex;align-items:center;gap:10px;cursor:pointer;user-select:none}
.switch input{position:absolute;opacity:0;pointer-events:none}
.sw-track{width:44px;height:22px;border:1px solid var(--ink);border-radius:99px;position:relative;transition:background .3s,border-color .3s}
.sw-thumb{position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:var(--ink);transition:transform .35s var(--ease),background .3s}
.switch input:checked + .sw-track{background:var(--pink);border-color:var(--pink)}
.switch input:checked + .sw-track .sw-thumb{transform:translateX(22px);background:#000}
.sw-txt{font-family:var(--mono);font-size:10px;letter-spacing:.16em;color:var(--mut);min-width:38px}
.sw-txt.on{color:var(--pink)}
.vu{position:fixed;right:26px;top:50%;transform:translateY(-50%);z-index:700;
display:flex;flex-direction:column;align-items:center;gap:12px;--vu-c:var(--ink)}
.vu-cap{font-family:var(--mono);font-size:9px;letter-spacing:.1em;color:var(--mut)}
.vu-track{width:3px;height:32vh;background:var(--line);position:relative;border-radius:2px}
.vu-fill{position:absolute;bottom:0;left:0;width:100%;height:0;background:var(--vu-c);border-radius:2px;transition:background .4s}
.vu-needle{position:absolute;left:50%;top:0;width:16px;height:2px;background:var(--vu-c);transform:translate(-50%,-50%);transition:background .4s}
.vu-read{writing-mode:vertical-rl;font-family:var(--mono);font-size:9px;letter-spacing:.3em;color:var(--vu-c);transition:color .4s}
section{position:relative}
.q{background:var(--paper);color:var(--ink);padding:clamp(90px,11vw,150px) 5vw;transition:background .5s ease,color .5s ease}
.l{color:#000;padding:clamp(80px,10vw,130px) 5vw;overflow:hidden}
.q-head{display:flex;align-items:baseline;gap:22px;border-top:1px solid var(--line);padding-top:20px;margin-bottom:clamp(44px,6vw,84px)}
.q-no{font-family:var(--mono);font-size:11px;color:var(--mut)}
.q-title{font-family:var(--grot);font-weight:500;font-size:clamp(30px,4.6vw,62px);letter-spacing:-.02em;line-height:1}
.q-tag{margin-left:auto;font-family:var(--mono);font-size:10px;letter-spacing:.18em;color:var(--mut);white-space:nowrap}
.l-head{display:flex;align-items:flex-start;gap:22px;margin-bottom:clamp(40px,5vw,70px);flex-wrap:wrap}
.l-no{font-family:var(--mono);font-size:11px;background:#000;color:#fff;padding:6px 10px;transform:rotate(-2deg)}
.l-title{font-family:var(--disp);font-size:clamp(52px,10vw,140px);line-height:.92;text-transform:uppercase;letter-spacing:.01em}
.l-tag{margin-left:auto;font-family:var(--mono);font-size:10px;letter-spacing:.18em;background:#000;color:#fff;padding:8px 12px;transform:rotate(1.5deg);white-space:nowrap}
.hero{min-height:100svh;display:flex;flex-direction:column;padding-top:clamp(40px,8vh,90px);padding-bottom:0}
.hero-eyebrow{display:flex;justify-content:space-between;gap:16px;font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--mut);
border-bottom:1px solid var(--line);padding-bottom:14px;flex-wrap:wrap}
.hero-name{font-family:var(--disp);text-transform:uppercase;line-height:.86;letter-spacing:.005em;
font-size:clamp(66px,15.5vw,230px);position:relative;z-index:2;margin-block:auto;padding-block:clamp(24px,4vh,48px)}
.hero-name .ln{display:block}
.hero-name .outline{color:transparent;-webkit-text-stroke:2.5px var(--ink);transition:-webkit-text-stroke .5s}
.hero-star{display:inline-block;color:var(--pink);font-size:.42em;vertical-align:.62em;margin-left:.08em;animation:spin 7s linear infinite}
@keyframes spin{to{rotate:360deg}}
.chw{display:inline-block;overflow:hidden;vertical-align:top;padding-bottom:.06em;margin-bottom:-.06em}
.ch{display:inline-block;will-change:transform}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.25}}
.hero-low{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);gap:clamp(28px,4vw,60px);align-items:start;
border-top:1px solid var(--line);padding:26px 0 40px}
.hero-state{font-size:clamp(19px,2.3vw,30px);line-height:1.35;font-weight:500;letter-spacing:-.01em;max-width:24ch}
.hero-state em{font-family:var(--serif);font-style:italic;font-weight:400;font-size:1.12em}
.side-status{display:inline-flex;align-items:center;gap:9px;font-family:var(--mono);font-weight:700;font-size:11px;letter-spacing:.1em;text-transform:uppercase;
border:1px solid var(--ink);border-radius:99px;padding:10px 16px;margin-bottom:14px}
.side-status .dot{width:8px;height:8px;border-radius:50%;background:var(--green);animation:pulse 1.6s ease-in-out infinite}
.side-row{display:flex;justify-content:space-between;gap:14px;font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--mut);padding:11px 0;border-bottom:1px solid var(--line)}
.side-row:last-child{border-bottom:none}
.side-row b{color:var(--ink);font-weight:700}
.band{background:#000;color:var(--yellow);overflow:hidden;transform:rotate(-1.2deg) scale(1.02);border-block:3px solid #000;position:relative;z-index:5}
.marquee{display:flex;width:max-content;animation:mq 26s linear infinite}
.band.rev .marquee{animation-direction:reverse}
.band:hover .marquee{animation-play-state:paused}
.mq-set{display:flex;align-items:center;gap:38px;padding-right:38px;
font-family:var(--disp);text-transform:uppercase;font-size:clamp(26px,4.6vw,58px);line-height:1;padding-block:16px;white-space:nowrap}
.mq-set .ast{color:var(--pink);animation:spin 5s linear infinite}
.mq-set .ghost{color:transparent;-webkit-text-stroke:1.5px var(--yellow)}
@keyframes mq{to{transform:translateX(-50%)}}
.about-grid{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);gap:clamp(40px,6vw,90px)}
.about-state{font-size:clamp(26px,3.6vw,50px);line-height:1.22;font-weight:500;letter-spacing:-.02em;margin-bottom:34px}
.about-state em{font-family:var(--serif);font-style:italic;font-weight:400;color:var(--pink);font-size:1.08em;transition:color .5s}
body.loud-mode .about-state em{color:var(--cyan)}
.about-copy p{max-width:56ch;color:var(--mut);margin-bottom:18px;font-size:15px}
.about-copy p b{color:var(--ink);font-weight:600}
.about-links{display:flex;flex-wrap:wrap;gap:12px;margin-top:30px}
.pill{font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;border:1px solid var(--ink);
padding:11px 18px;border-radius:99px;transition:all .3s var(--ease)}
.pill:hover{background:var(--ink);color:var(--paper);transform:translateY(-2px)}
.facts{border-top:1px solid var(--line)}
.fact{display:grid;grid-template-columns:110px 1fr;gap:16px;padding:16px 0;border-bottom:1px solid var(--line);align-items:baseline}
.fact dt{font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--mut)}
.fact dd{font-size:15px;font-weight:500}
.fact dd .live{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--green);margin-right:8px;animation:pulse 1.6s infinite}
.badge-chip{display:inline-block;font-family:var(--mono);font-size:10px;border:1px solid var(--line);padding:4px 9px;margin:2px 4px 2px 0;border-radius:99px}
.loadout{background:var(--pink)}
.loadout .l-title{text-shadow:5px 5px 0 #000}
.loadout .l-no,.loadout .l-tag{background:#000}
.chip-group{display:flex;align-items:baseline;gap:14px;margin:0 0 16px;font-family:var(--mono);font-size:10px;letter-spacing:.18em;text-transform:uppercase}
.chip-group:first-child{margin-top:0}
.chip-group + .chip-wall{margin-bottom:38px}
.chip-group i{flex:1;height:1px;background:rgba(0,0,0,.35)}
.chip-wall{display:flex;flex-wrap:wrap;gap:14px}
.chip{--r:0deg;font-family:var(--mono);font-weight:700;font-size:clamp(13px,1.5vw,17px);letter-spacing:.04em;text-transform:uppercase;
background:#fff;color:#000;border:2px solid #000;padding:14px 22px;rotate:var(--r);
box-shadow:4px 4px 0 #000;cursor:default;transition:box-shadow .2s,translate .2s;will-change:transform}
.chip:hover{animation:jello 1s;translate:-2px -2px;box-shadow:8px 8px 0 #000}
.chip.locked{background:transparent;color:#fff;border-style:dashed;box-shadow:none}
.chip.locked:hover{animation:rubberBand 1s}
.builds .rows{border-top:1px solid var(--line)}
.row{position:relative;display:grid;grid-template-columns:64px minmax(0,1fr) auto 44px;gap:20px;align-items:center;
padding:26px 10px;border-bottom:1px solid var(--line);overflow:hidden;isolation:isolate}
.row::before{content:'';position:absolute;inset:0;background:var(--ink);transform:scaleY(0);transform-origin:bottom;
transition:transform .45s var(--ease);z-index:-1}
.row::after{content:'';position:absolute;top:0;bottom:0;left:-80%;width:45%;
background:linear-gradient(105deg,transparent,rgba(255,255,255,.28),transparent);transform:skewX(-18deg);transition:left .7s var(--ease)}
.row:hover::before{transform:scaleY(1)}
.row:hover::after{left:130%}
.row-no{font-family:var(--mono);font-size:11px;color:var(--mut);transition:color .3s}
.row-title{display:block;font-weight:700;font-size:clamp(21px,2.8vw,36px);letter-spacing:-.02em;line-height:1.1;transition:transform .45s var(--ease),color .3s}
.row-desc{display:block;color:var(--mut);font-size:13px;margin-top:5px;max-width:52ch;transition:color .3s}
.row-meta{font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--mut);white-space:nowrap;transition:color .3s}
.row-arrow{font-size:20px;justify-self:end;transition:transform .45s var(--ease),color .3s}
.row:hover .row-title{color:var(--paper);transform:translateX(10px)}
.row:hover .row-desc,.row:hover .row-meta,.row:hover .row-no{color:rgba(244,241,234,.65)}
.row:hover .row-arrow{color:var(--yellow);transform:translate(4px,-4px)}
.now{background:var(--yellow);color:#000}
.now .l-no{background:#000;color:var(--yellow)}
.now .l-tag{background:#000;color:var(--yellow)}
.focus-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}
.focus{display:flex;flex-direction:column;gap:14px;border:2px solid #000;padding:26px 24px 30px;
box-shadow:6px 6px 0 #000;transition:transform .35s var(--ease),box-shadow .35s var(--ease)}
.focus:hover{transform:translate(-4px,-4px);box-shadow:12px 12px 0 #000}
.focus-no{font-family:var(--mono);font-size:11px}
.focus-title{font-family:var(--disp);font-size:clamp(26px,2.6vw,40px);line-height:.95;text-transform:uppercase}
.focus-desc{font-size:14px;line-height:1.55;font-weight:500}
.focus-status{align-self:flex-start;font-family:var(--mono);font-size:10px;letter-spacing:.14em;background:#000;color:var(--yellow);padding:6px 10px;transform:rotate(-1.5deg);margin-top:auto}
.now-backburner{margin-top:28px;display:flex;justify-content:space-between;gap:14px;flex-wrap:wrap;border-top:2px solid #000;padding-top:16px;
font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase}
.repeat-rows{border-top:1px solid var(--line)}
.rep{display:grid;grid-template-columns:56px minmax(0,1.1fr) minmax(0,1fr) auto;gap:20px;align-items:baseline;padding:20px 8px;border-bottom:1px solid var(--line);transition:padding-left .35s var(--ease)}
.rep:hover{padding-left:22px}
.rep-no{font-family:var(--mono);font-size:11px;color:var(--mut)}
.rep-main{min-width:0}
.rep-artist{display:block;font-weight:700;font-size:clamp(17px,2vw,24px);letter-spacing:-.01em}
.rep-work{display:block;font-family:var(--serif);font-style:italic;color:var(--mut);font-size:15px;margin-top:2px}
.rep-track{font-family:var(--mono);font-size:11px;color:var(--mut)}
.rep-count{font-family:var(--mono);font-size:11px;letter-spacing:.12em;white-space:nowrap}
.repeat-foot{margin-top:22px;font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--mut)}
.repeat-foot a{border-bottom:1px solid var(--pink);transition:color .25s}
.repeat-foot a:hover{color:var(--pink)}
.score{background:#0c0c0b;color:#fff}
.score .l-no{background:var(--yellow);color:#000}
.score .l-tag{background:var(--yellow);color:#000}
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));border:2px solid #fff}
.stat{padding:clamp(26px,3.4vw,46px) clamp(20px,2.6vw,36px);border-right:2px solid #fff;position:relative;overflow:hidden;isolation:isolate}
.stat:last-child{border-right:none}
.stat::before{content:'';position:absolute;inset:0;background:var(--sc,var(--yellow));transform:translateY(101%);transition:transform .45s var(--ease);z-index:-1}
.stat:hover::before{transform:translateY(0)}
.stat-n{display:block;font-family:var(--disp);font-size:clamp(52px,7.5vw,110px);line-height:.95;color:var(--sc,var(--yellow));transition:color .3s}
.stat:hover .stat-n{color:#000}
.stat-l{display:block;margin-top:12px;font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:rgba(255,255,255,.55);transition:color .3s}
.stat:hover .stat-l{color:#000}
.devlog .entries{border-top:1px solid var(--line)}
.entry{display:grid;grid-template-columns:90px minmax(0,1fr) auto;gap:22px;align-items:baseline;padding:24px 8px;border-bottom:1px solid var(--line);position:relative;transition:padding-left .35s var(--ease)}
.entry:hover{padding-left:26px}
.entry::before{content:'✳';position:absolute;left:2px;color:var(--pink);opacity:0;transition:opacity .3s;font-size:14px}
.entry:hover::before{opacity:1}
.entry-year{font-family:var(--mono);font-size:11px;color:var(--mut)}
.entry-title{font-weight:700;font-size:clamp(18px,2.4vw,30px);letter-spacing:-.015em}
.entry-tags{font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--mut);white-space:nowrap}
.contact{background:var(--cyan)}
.contact .l-title{font-size:clamp(76px,19vw,270px);text-shadow:7px 7px 0 #000}
.contact .sayhi .ch{display:inline-block;animation:floaty 2.6s ease-in-out infinite;animation-delay:calc(var(--i)*.09s)}
@keyframes floaty{0%,100%{transform:translateY(0)}50%{transform:translateY(-.07em)}}
.contact-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:clamp(36px,5vw,80px);align-items:start;margin-top:clamp(36px,5vw,60px)}
.contact-copy p{max-width:44ch;font-weight:500;font-size:clamp(16px,1.8vw,21px);line-height:1.5}
.contact-copy p em{font-family:var(--serif);font-style:italic;font-size:1.1em}
.magnet{display:inline-flex;align-items:center;gap:14px;margin-top:34px;background:#000;color:var(--cyan);
font-family:var(--mono);font-weight:700;font-size:clamp(14px,1.7vw,19px);letter-spacing:.03em;
padding:20px 30px;border:2px solid #000;box-shadow:6px 6px 0 #fff;will-change:transform}
.magnet:hover{box-shadow:10px 10px 0 #fff}
.socials{border-top:2px solid #000}
.soc{display:flex;justify-content:space-between;align-items:center;gap:14px;padding:17px 4px;border-bottom:2px solid #000;
font-family:var(--mono);font-weight:700;font-size:clamp(13px,1.5vw,17px);text-transform:uppercase;letter-spacing:.05em;transition:padding-left .3s var(--ease),background .3s}
.soc:hover{padding-left:18px;background:rgba(0,0,0,.08)}
.soc span:last-child{font-weight:400;font-size:12px}
.foot{display:flex;justify-content:space-between;gap:14px;flex-wrap:wrap;
padding:26px 5vw;border-top:1px solid var(--line);
font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--mut)}
.foot b{color:var(--pink)}
.foot-links a{transition:color .25s}
.foot-links a:hover{color:var(--pink)}
html.js .rv{opacity:0;transform:translateY(28px);transition:opacity .9s var(--ease) var(--d,0s),transform .9s var(--ease) var(--d,0s)}
html.js .rv.is-in{opacity:1;transform:none}
html.js .chip{opacity:0}
html.nf .chip,html.rm .chip{opacity:1}
.bt .bw{display:inline-block;opacity:0;filter:blur(10px);transform:translateY(.35em);
transition:opacity .7s var(--ease) calc(var(--i)*22ms),filter .7s var(--ease) calc(var(--i)*22ms),transform .7s var(--ease) calc(var(--i)*22ms)}
.bt.is-in .bw{opacity:1;filter:blur(0);transform:none}
.shine{background:linear-gradient(110deg,currentColor 42%,var(--pink) 50%,currentColor 58%);background-size:240% 100%;
-webkit-background-clip:text;background-clip:text;color:transparent;animation:shine 3.4s linear infinite}
@keyframes shine{to{background-position:-240% 0}}
html.nf .rv,html.rm .rv{opacity:1;transform:none}
html.nf .bt .bw,html.rm .bt .bw{opacity:1;filter:none;transform:none}
body.loud-mode{--paper:#101010;--ink:#F4F1EA;--mut:#8f8c83;--line:rgba(244,241,234,.17)}
body.loud-mode .q-title,body.loud-mode .about-state{color:var(--paper)}
body.loud-mode .q-title{text-shadow:4px 4px 0 var(--acc,var(--pink))}
body.loud-mode .row::before{background:var(--pink)}
body.loud-mode .row:hover .row-title{color:#000}
body.loud-mode .row:hover .row-desc,body.loud-mode .row:hover .row-meta,body.loud-mode .row:hover .row-no{color:rgba(0,0,0,.65)}
body.loud-mode .pill:hover{background:var(--pink);border-color:var(--pink);color:#000}
body.loud-mode .loader{background:#101010;color:#F4F1EA}
@media(max-width:960px){
.vu{display:none}
.about-grid,.contact-grid,.hero-low{grid-template-columns:1fr}
.focus-grid{grid-template-columns:1fr}
}
@media(max-width:760px){
.nav-links{display:none}
.row{grid-template-columns:40px minmax(0,1fr) 34px}
.row-meta{display:none}
.entry{grid-template-columns:60px minmax(0,1fr)}
.entry-tags{display:none}
.q-tag{display:none}
.rep{grid-template-columns:40px minmax(0,1fr) auto}
.rep-track{display:none}
.stat{border-right:none;border-bottom:2px solid #fff}
.stat:last-child{border-bottom:none}
}
@media(prefers-reduced-motion:reduce){
*,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important}
html{scroll-behavior:auto}
html.js .rv{opacity:1;transform:none}
.bt .bw{opacity:1;filter:none;transform:none}
}
</style>
<noscript><style>
.loader{display:none}
.rv,.chip{opacity:1 !important;transform:none !important}
.bt .bw{opacity:1;filter:none;transform:none}
</style></noscript>
</head>
<body>
<div class="loader" id="loader" aria-hidden="true">
<div class="loader-top"><span>PORTFOLIO — VOL.09</span><span>SOFT ⇄ LOUD</span></div>
<div class="loader-mid" id="loaderWord">SOFT</div>
<div class="loader-bot">
<div class="loader-count"><span id="loaderNum">000</span><small>%</small></div>
<div class="loader-bar"><i id="loaderBar"></i></div>
</div>
</div>
<header class="nav" id="nav">
<a class="brand" href="#top">M—WA <span>©26</span></a>
<nav class="nav-links" aria-label="Sections">
<a href="#about" data-scramble>Identity</a>
<a href="#loadout" data-scramble>Loadout</a>
<a href="#builds" data-scramble>Builds</a>
<a href="#now" data-scramble>Now</a>
<a href="#devlog" data-scramble>Devlog</a>
<a href="#contact" data-scramble>Contact</a>
</nav>
<label class="switch">
<input type="checkbox" id="loudToggle" aria-label="Force loud mode">
<span class="sw-track"><i class="sw-thumb"></i></span>
<span class="sw-txt" id="swTxt">AUTO</span>
</label>
</header>
<aside class="vu" id="vu" aria-hidden="true">
<span class="vu-cap">S</span>
<div class="vu-track"><div class="vu-fill" id="vuFill"></div><div class="vu-needle" id="vuNeedle"></div></div>
<span class="vu-cap">L</span>
<div class="vu-read" id="vuRead">SOFT</div>
</aside>
<main id="top">
<section class="q hero" data-vibe="0.18">
<div class="hero-eyebrow" id="heroEyebrow">
<span>Portfolio — Vol.09</span>
<span class="shine">Modern Simplistic Maximalism</span>
<span>milesallen.site</span>
</div>
<h1 class="hero-name" id="heroName">
<span class="ln" data-split>MILES</span>
<span class="ln outline" data-split>WOLF ALLEN</span>
<span class="hero-star" aria-hidden="true">*</span>
</h1>
<div class="hero-low">
<p class="hero-state" id="heroState">I make games, tools &amp; websites that feel <em>good</em> to use.</p>
<div class="hero-side" id="heroSide">
<span class="side-status"><i class="dot"></i>Usually online</span>
<div class="side-row"><span>Direction</span><b>scroll ↓</b></div>
<div class="side-row"><span>Public repos</span><b>160+</b></div>
<div class="side-row"><span>Loud mode</span><b>press L</b></div>
</div>
</div>
</section>
<div class="band" aria-hidden="true">
<div class="marquee">
<div class="mq-set">
<span>Building emulators</span><span class="ast">*</span>
<span class="ghost">Send help</span><span class="ast">*</span>
<span>160 repos and counting</span><span class="ast">*</span>
<span class="ghost">Still debugging</span><span class="ast">*</span>
<span>Geometry Dash addict</span><span class="ast">*</span>
<span class="ghost">Usually online</span><span class="ast">*</span>
</div>
<div class="mq-set">
<span>Building emulators</span><span class="ast">*</span>
<span class="ghost">Send help</span><span class="ast">*</span>
<span>160 repos and counting</span><span class="ast">*</span>
<span class="ghost">Still debugging</span><span class="ast">*</span>
<span>Geometry Dash addict</span><span class="ast">*</span>
<span class="ghost">Usually online</span><span class="ast">*</span>
</div>
</div>
</div>
<section class="q about" id="about" data-vibe="0.08" style="--acc:var(--pink)">
<header class="q-head rv">
<span class="q-no">01</span>
<h2 class="q-title">Who's Miles</h2>
<span class="q-tag">Identity — Soft</span>
</header>
<div class="about-grid">
<div class="about-copy">
<p class="about-state bt">Software should feel <em>good</em> to use — so I build emulators, games &amp; tools until it does.</p>
<p class="rv">I build things on the internet. Some of them are games, some are tools, and some exist purely because I thought it would be fun. <b>160 repos and 91 stars later</b>, I'm still figuring it out as I go.</p>
<p class="rv" style="--d:.08s">Right now I'm co-founder of <b>Diskette Labs</b>, building <b>Gelectron</b> (a full Electron replacement), and running <b>FEDL</b> — the Geometry Dash demon list. Still in school, somehow.</p>
<div class="about-links rv" style="--d:.14s">
<a class="pill" href="https://milesallen.site/about-me.html">More about me →</a>
<a class="pill" href="https://diskettelabs.com/" target="_blank" rel="noopener">Diskette Labs ↗</a>
</div>
</div>
<dl class="facts rv" style="--d:.1s">
<div class="fact"><dt>Status</dt><dd><span class="live"></span>usually online</dd></div>
<div class="fact"><dt>Crew</dt><dd>Diskette Labs — co-founder</dd></div>
<div class="fact"><dt>Badges</dt><dd><span class="badge-chip">Pull Shark ×2</span><span class="badge-chip">YOLO</span><span class="badge-chip">Quickdraw</span></dd></div>
<div class="fact"><dt>Believes</dt><dd>pancakes &gt; waffles · cereal is soup</dd></div>
<div class="fact"><dt>Stack</dt><dd>JS · TS · Rust · Swift · Python · Blender</dd></div>
</dl>
</div>
</section>
<section class="l loadout" id="loadout" data-vibe="1">
<header class="l-head">
<span class="l-no">02</span>
<h2 class="l-title">My<br>Loadout</h2>
<span class="l-tag">Skills — Loud</span>
</header>
<div class="chip-group">Ready to use<i></i>16</div>
<div class="chip-wall" id="chipWall" data-io>
<span class="chip" data-r="-3">JavaScript</span>
<span class="chip" data-r="2">Backend JS</span>
<span class="chip" data-r="-1">HTML</span>
<span class="chip" data-r="3">CSS</span>
<span class="chip" data-r="-2">Python</span>
<span class="chip" data-r="1">Git</span>
<span class="chip" data-r="-3">Blender</span>
<span class="chip" data-r="2">Unity</span>
<span class="chip" data-r="-1">Unreal</span>
<span class="chip" data-r="3">Cloudflare</span>
<span class="chip" data-r="-2">Linux</span>
<span class="chip" data-r="1">Netlify</span>
<span class="chip" data-r="-3">Bash</span>
<span class="chip" data-r="2">GitHub</span>
<span class="chip" data-r="-1">Electron</span>
<span class="chip" data-r="3">Gelectron</span>
</div>
<div class="chip-group">Currently unlocking<i></i>4</div>
<div class="chip-wall" data-io>
<span class="chip locked" data-r="-2">PHP</span>
<span class="chip locked" data-r="1">.NET</span>
<span class="chip locked" data-r="2">Nix</span>
<span class="chip locked" data-r="-1">Yarn</span>
</div>
</section>
<section class="q builds" id="builds" data-vibe="0.08" style="--acc:var(--cyan)">
<header class="q-head rv">
<span class="q-no">03</span>
<h2 class="q-title">The Builds</h2>
<span class="q-tag">Projects — Soft</span>
</header>
<div class="rows">
<a class="row rv" href="https://milesallen.site/projects/omniemu.html"><span class="row-no">01</span><span class="row-main"><span class="row-title">OmniEmu 2.0</span><span class="row-desc">All your emulators in one place. Install 20+, scan ROMs, launch games.</span></span><span class="row-meta">Active · TS · MIT</span><span class="row-arrow"></span></a>
<a class="row rv" style="--d:.03s" href="https://milesallen.site/projects/gelectron.html"><span class="row-no">02</span><span class="row-main"><span class="row-title">Gelectron</span><span class="row-desc">Drop-in Electron replacement on native web views. No bundled Chromium.</span></span><span class="row-meta">Early · Rust</span><span class="row-arrow"></span></a>
<a class="row rv" style="--d:.06s" href="https://vanilla.milesallen.site/" target="_blank" rel="noopener"><span class="row-no">03</span><span class="row-main"><span class="row-title">Vanilla</span><span class="row-desc">A clean, minimal web experiment. No frameworks, no cruft.</span></span><span class="row-meta">Unreleased · JS</span><span class="row-arrow"></span></a>
<a class="row rv" style="--d:.09s" href="https://me.fedl.site/" target="_blank" rel="noopener"><span class="row-no">04</span><span class="row-main"><span class="row-title">FEDL</span><span class="row-desc">The demon list for Geometry Dash. Ranked levels, verified runs.</span></span><span class="row-meta">Live · 3800+ runs</span><span class="row-arrow"></span></a>
<a class="row rv" style="--d:.12s" href="https://milesallen.site/projects/command-move.html"><span class="row-no">05</span><span class="row-main"><span class="row-title">CommandMove</span><span class="row-desc">True cut-and-paste for Finder. Cmd+X, navigate, Cmd+V.</span></span><span class="row-meta">macOS · Swift</span><span class="row-arrow"></span></a>
<a class="row rv" style="--d:.15s" href="https://milesallen.site/projects/noto.html"><span class="row-no">06</span><span class="row-main"><span class="row-title">Noto</span><span class="row-desc">Note-taking with AI built in. Powered by Cortex, good at organizing chaos.</span></span><span class="row-meta">Active · Flutter</span><span class="row-arrow"></span></a>
<a class="row rv" style="--d:.18s" href="https://milesallen.site/projects/nova.html"><span class="row-no">07</span><span class="row-main"><span class="row-title">Nova AI</span><span class="row-desc">Local AI assistant. Desktop GUI, web interface and CLI. No cloud.</span></span><span class="row-meta">Python · MIT</span><span class="row-arrow"></span></a>
<a class="row rv" style="--d:.21s" href="https://milesallen.site/projects/music-app.html"><span class="row-no">08</span><span class="row-main"><span class="row-title">Music App</span><span class="row-desc">YouTube Music energy without the annoying parts.</span></span><span class="row-meta">JS · Apache-2.0</span><span class="row-arrow"></span></a>
<a class="row rv" style="--d:.24s" href="https://milesallen.site/projects/rhythm-game.html"><span class="row-no">09</span><span class="row-main"><span class="row-title">Rhythm Game</span><span class="row-desc">Hit keys to the beat. Real-time notes. My fingers hurt.</span></span><span class="row-meta">HTML · MPL-2.0</span><span class="row-arrow"></span></a>
<a class="row rv" style="--d:.27s" href="https://milesallen.site/projects/geode-mod.html"><span class="row-no">10</span><span class="row-main"><span class="row-title">FEDL Geode Mod</span><span class="row-desc">The demon list, in-game. Roulette mode, banned mod detection.</span></span><span class="row-meta">WIP · Geode</span><span class="row-arrow"></span></a>
<a class="row rv" style="--d:.30s" href="https://milesallen.site/projects/decompilations.html"><span class="row-no">11</span><span class="row-main"><span class="row-title">Decompilations</span><span class="row-desc">Native PC ports of games that probably shouldn't exist.</span></span><span class="row-meta">HTML · MIT</span><span class="row-arrow"></span></a>
<a class="row rv" style="--d:.33s" href="https://milesallen.site/projects/issue-tracker.html"><span class="row-no">12</span><span class="row-main"><span class="row-title">Issue Tracker</span><span class="row-desc">Built my own because why not. Node.js, no frameworks, raw determination.</span></span><span class="row-meta">Node.js</span><span class="row-arrow"></span></a>
<a class="row rv" style="--d:.36s" href="https://milesallen.site/projects/moon-gaming.html"><span class="row-no">13</span><span class="row-main"><span class="row-title">Moon Gaming</span><span class="row-desc">Browser-game hub built at 2am. A growing library of chaos.</span></span><span class="row-meta">1542 commits</span><span class="row-arrow"></span></a>
</div>
</section>
<section class="l score" id="score" data-vibe="1">
<header class="l-head">
<span class="l-no">04</span>
<h2 class="l-title">Scoreboard</h2>
<span class="l-tag">Numbers — Peak</span>
</header>
<div class="stats">
<div class="stat rv" data-io style="--sc:var(--yellow)"><span class="stat-n" data-count="3800" data-suffix="+">0</span><span class="stat-l">Verified FEDL runs</span></div>
<div class="stat rv" data-io style="--sc:var(--cyan);--d:.06s"><span class="stat-n" data-count="20" data-suffix="+">0</span><span class="stat-l">Emulators in OmniEmu</span></div>
<div class="stat rv" data-io style="--sc:var(--pink);--d:.12s"><span class="stat-n" data-count="1542">0</span><span class="stat-l">Moon Gaming commits</span></div>
<div class="stat rv" data-io style="--sc:var(--green);--d:.18s"><span class="stat-n" data-count="160" data-suffix="+">0</span><span class="stat-l">Public repos</span></div>
<div class="stat rv" data-io style="--sc:var(--orange);--d:.24s"><span class="stat-n" data-count="91">0</span><span class="stat-l">Stars earned</span></div>
</div>
</section>
<section class="q devlog" id="devlog" data-vibe="0.08" style="--acc:var(--purple)">
<header class="q-head rv">
<span class="q-no">05</span>
<h2 class="q-title">Devlog</h2>
<span class="q-tag">Writing — Soft</span>
</header>
<div class="entries">
<a class="entry rv" href="https://milesallen.site/blog/"><span class="entry-year">2026</span><span class="entry-title">Focusing on Diskette Labs</span><span class="entry-tags">Design · Collective</span></a>
<a class="entry rv" style="--d:.05s" href="https://milesallen.site/blog/"><span class="entry-year">2026</span><span class="entry-title">Why I Built Gelectron</span><span class="entry-tags">Rust · Native</span></a>
<a class="entry rv" style="--d:.1s" href="https://milesallen.site/blog/"><span class="entry-year">2026</span><span class="entry-title">Why I Built OmniEmu</span><span class="entry-tags">TypeScript · Electron</span></a>
<a class="entry rv" style="--d:.15s" href="https://milesallen.site/blog/"><span class="entry-year">2025</span><span class="entry-title">CommandMove: Cut &amp; Paste on Mac</span><span class="entry-tags">Swift · macOS</span></a>
<a class="entry rv" style="--d:.2s" href="https://milesallen.site/blog/"><span class="entry-year">2025</span><span class="entry-title">Running the FEDL</span><span class="entry-tags">Node.js · Community</span></a>
<a class="entry rv" style="--d:.25s" href="https://milesallen.site/blog/"><span class="entry-year">2025</span><span class="entry-title">Building Nova AI</span><span class="entry-tags">Python · Local AI</span></a>
</div>
</section>
<section class="l now" id="now" data-vibe="1">
<header class="l-head">
<span class="l-no">06</span>
<h2 class="l-title">The Now</h2>
<span class="l-tag">Focus — Loud</span>
</header>
<div class="focus-grid">
<a class="focus rv" href="https://vanilla.milesallen.site/" target="_blank" rel="noopener">
<span class="focus-no">01</span>
<h3 class="focus-title">Building Vanilla</h3>
<p class="focus-desc">Pure vanilla JS — no frameworks, no libraries, no cruft. Still unreleased but active, polishing daily. The whole point is proving the raw web can feel good.</p>
<span class="focus-status">Active — main project</span>
</a>
<a class="focus rv" style="--d:.08s" href="https://milesallen.site/projects/gelectron.html">
<span class="focus-no">02</span>
<h3 class="focus-title">Building Gelectron</h3>
<p class="focus-desc">Drop-in Electron replacement on native web views — no 150MB binaries, no 300MB of RAM to show a window. Filling out the API layer: BrowserWindow, IPC, Menu, Tray.</p>
<span class="focus-status">Early — side project</span>
</a>
<a class="focus rv" style="--d:.16s" href="https://me.fedl.site/" target="_blank" rel="noopener">
<span class="focus-no">03</span>
<h3 class="focus-title">Running the FEDL</h3>
<p class="focus-desc">The Geometry Dash demon list is still going strong — nearly 4,000 verified runs and 340+ ranked levels. Building better moderation tools and a cleaner submission pipeline.</p>
<span class="focus-status">Ongoing — community</span>
</a>
</div>
<div class="now-backburner">
<span>Back burner: Noto (it'll come around)</span>
<span>This site keeps evolving</span>
<span>Updated Aug 1, 2026</span>
</div>
</section>
<section class="q repeat" id="repeat" data-vibe="0.08" style="--acc:var(--cyan)">
<header class="q-head rv">
<span class="q-no">07</span>
<h2 class="q-title">On Repeat</h2>
<span class="q-tag">Listening — Soft</span>
</header>
<div class="repeat-rows">
<div class="rep rv"><span class="rep-no">01</span><span class="rep-main"><span class="rep-artist">Jamie Paige</span><span class="rep-work">Machine Love</span></span><span class="rep-track">Birdbrain (w/ OK Glass)</span><span class="rep-count">12 tracks</span></div>
<div class="rep rv" style="--d:.05s"><span class="rep-no">02</span><span class="rep-main"><span class="rep-artist">FLAVOR FOLEY</span><span class="rep-work">Spoken For</span></span><span class="rep-track">BUTCHER VANITY</span><span class="rep-count">7 tracks</span></div>
<div class="rep rv" style="--d:.1s"><span class="rep-no">03</span><span class="rep-main"><span class="rep-artist">VocaloKAT</span><span class="rep-work">Singles</span></span><span class="rep-track">Affection Addiction (w/ Aku P)</span><span class="rep-count">4 tracks</span></div>
<div class="rep rv" style="--d:.15s"><span class="rep-no">04</span><span class="rep-main"><span class="rep-artist">EROMA</span><span class="rep-work">Singles</span></span><span class="rep-track">POTETO CHIP</span><span class="rep-count">5 tracks</span></div>
<div class="rep rv" style="--d:.2s"><span class="rep-no">05</span><span class="rep-main"><span class="rep-artist">AnythingBecomeMoe</span><span class="rep-work">Singles</span></span><span class="rep-track">PingPong TIKITAKA</span><span class="rep-count">3 tracks</span></div>
</div>
<p class="repeat-foot rv">Vocaloid on loop, Rage Against the Machine on bad days — <a href="https://milesallen.site/music.html">full listening history →</a></p>
</section>
<section class="l contact" id="contact" data-vibe="1">
<header class="l-head">
<span class="l-no">08</span>
<h2 class="l-title sayhi" id="sayHi">Say Hi</h2>
<span class="l-tag">Contact — Loud</span>
</header>
<div class="contact-grid">
<div class="contact-copy">
<p class="rv">Unless you're a bot — then please go away. Everyone else: I'm open to collaborations, weird ideas, and <em>very</em> specific bug reports.</p>
<a class="magnet" id="mailBtn" href="mailto:[email protected]">[email protected] <span></span></a>
</div>
<div class="socials rv" style="--d:.1s">
<a class="soc" href="https://github.com/mileswolfallen2" target="_blank" rel="noopener"><span data-scramble>GitHub</span><span>mileswolfallen2</span></a>
<a class="soc" href="https://replit.com/@MilesAllen1" target="_blank" rel="noopener"><span data-scramble>Replit</span><span>@MilesAllen1</span></a>
<a class="soc" href="https://codepen.io/mileswolfallen2-the-typescripter" target="_blank" rel="noopener"><span data-scramble>CodePen</span><span>mileswolfallen2</span></a>
<a class="soc" href="https://me.fedl.site" target="_blank" rel="noopener"><span data-scramble>FEDL</span><span>me.fedl.site</span></a>
</div>
</div>
</section>
</main>
<footer class="foot q" data-vibe="0">
<span>© 2026 Miles Wolf Allen</span>
<span class="foot-links"><a href="https://milesallen.site/uses.html">Uses</a> · <a href="https://milesallen.site/colophon.html">Colophon</a> · <a href="https://milesallen.site/quotes.html">Quotes</a> · <a href="https://milesallen.site/music.html">Music</a></span>
<span>Press <b>L</b> to go loud</span>
</footer>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/bundles/anime.umd.min.js"></script>
<script>
(function(){
document.documentElement.classList.add('js');
const $=(s,c)=>(c||document).querySelector(s);
const $$=(s,c)=>Array.from((c||document).querySelectorAll(s));
const RM=matchMedia('(prefers-reduced-motion: reduce)').matches;
if(RM)document.documentElement.classList.add('rm');
const hasAnime=typeof anime!=='undefined';
if(!hasAnime||RM)document.documentElement.classList.add('nf');
function splitChars(el,mask){
const text=el.textContent;
el.setAttribute('aria-label',text.trim());
el.textContent='';
const chars=[];
text.split('').forEach(ch=>{
let c=document.createElement('span');
c.className='ch';
c.textContent=ch===' '?'\u00A0':ch;
c.setAttribute('aria-hidden','true');
if(mask){
const w=document.createElement('span');
w.className='chw';
w.appendChild(c);
el.appendChild(w);
}else{
el.appendChild(c);
}
chars.push(c);
});
return chars;
}
function splitWords(el){
const walk=node=>{
Array.from(node.childNodes).forEach(n=>{
if(n.nodeType===3){
const frag=document.createDocumentFragment();
n.textContent.split(/(\s+)/).forEach(part=>{
if(!part)return;
if(/^\s+$/.test(part)){frag.appendChild(document.createTextNode(' '));return;}
const s=document.createElement('span');
s.className='bw';
s.textContent=part;
frag.appendChild(s);
});
node.replaceChild(frag,n);
}else if(n.nodeType===1){walk(n);}
});
};
walk(el);
$$('.bw',el).forEach((w,i)=>w.style.setProperty('--i',i));
}
let heroChars1=[],heroChars2=[];
if(hasAnime&&!RM){
const lns=$$('#heroName [data-split]');
heroChars1=splitChars(lns[0],true);
heroChars2=splitChars(lns[1],true);
}
$$('.bt').forEach(splitWords);
const sayHi=$('#sayHi');
if(sayHi&&!RM){
const chars=splitChars(sayHi,false);
chars.forEach((c,i)=>c.style.setProperty('--i',i));
}
const loader=$('#loader');
function killLoader(){if(loader)loader.remove();}
function startIntro(){
if(!hasAnime||RM)return;
const {animate,createTimeline,stagger,spring}=anime;
createTimeline({defaults:{ease:'outExpo',duration:900}})
.add('#nav',{y:[-26,0],opacity:[0,1]},0)
.add('#heroEyebrow',{y:[18,0],opacity:[0,1]},60)
.add(heroChars1,{y:['115%','0%'],delay:stagger(36)},120)
.add(heroChars2,{y:['115%','0%'],delay:stagger(36)},300)
.add('.hero-star',{scale:[0,1],rotate:[-180,0],ease:spring({stiffness:180,damping:13})},650)
.add('#heroState',{y:[26,0],opacity:[0,1]},720)
.add('.side-status',{scale:[.8,1],opacity:[0,1],ease:spring({stiffness:200,damping:14})},800)
.add('.side-row',{y:[14,0],opacity:[0,1],delay:stagger(80)},880)
.add('#vu',{opacity:[0,1],x:[24,0]},950);
}
if(!hasAnime||RM){
killLoader();
}else{
const {animate}=anime;
const num=$('#loaderNum'),bar=$('#loaderBar'),word=$('#loaderWord');
const words=['SOFT','LOUD','SOFT','LOUD'];
let wi=0;
const wordTimer=setInterval(()=>{
wi=(wi+1)%words.length;
word.textContent=words[wi];
word.classList.toggle('is-loud',words[wi]==='LOUD');
},300);
const state={v:0};
animate(state,{
v:100,duration:1600,ease:'inOutQuad',
onUpdate:()=>{
num.textContent=String(Math.round(state.v)).padStart(3,'0');
bar.style.transform='scaleX('+(state.v/100)+')';
},
onComplete:()=>{
clearInterval(wordTimer);
animate(loader,{
y:['0%','-102%'],duration:850,ease:'inOutQuint',delay:120,
onComplete:()=>{killLoader();startIntro();}
});
}
});
setTimeout(()=>{if(document.body.contains(loader))killLoader();},4000);
}
const io=new IntersectionObserver(entries=>{
entries.forEach(en=>{
if(!en.isIntersecting)return;
const el=en.target;
el.classList.add('is-in');
const counter=$('[data-count]',el);
if(counter)runCount(counter);
if(el.classList.contains('chip-wall'))burstChips(el);
io.unobserve(el);
});
},{threshold:.18,rootMargin:'0px 0px -6% 0px'});
$$('.rv,.bt,[data-io]').forEach(el=>io.observe(el));
function runCount(el){
const target=parseFloat(el.dataset.count)||0;
const suffix=el.dataset.suffix||'';
if(!hasAnime||RM){el.textContent=target.toLocaleString()+suffix;return;}
const {animate}=anime;
const o={n:0};
animate(o,{
n:target,duration:1700,ease:'outExpo',
onUpdate:()=>{el.textContent=Math.round(o.n).toLocaleString()+suffix;}
});
}
function burstChips(wall){
const chips=$$('.chip',wall);
if(!hasAnime||RM){
chips.forEach(c=>c.style.rotate=c.dataset.r+'deg');
return;
}
const {animate,stagger,spring}=anime;
animate(chips,{
scale:[0,1],y:[44,0],
rotate:(el,i)=>[parseFloat(el.dataset.r)-14,parseFloat(el.dataset.r)],
delay:stagger(34),
ease:spring({stiffness:210,damping:14})
});
animate(chips,{opacity:[0,1],duration:420,delay:stagger(34),ease:'outQuad'});
}
const SCRAMBLE='ABCDEFGHIJKLMNOPQRSTUVWXYZ#*+/<>_';
$$('[data-scramble]').forEach(a=>{
if(RM)return;
const orig=a.textContent;
let raf=null,it=0,total=Math.max(12,orig.length*2);
a.addEventListener('mouseenter',()=>{
if(raf)cancelAnimationFrame(raf);
it=0;
const tick=()=>{
it++;
const reveal=Math.floor((it/total)*orig.length);
a.textContent=orig.split('').map((c,i)=>{
if(c===' ')return ' ';
return i<reveal?c:SCRAMBLE[Math.random()*SCRAMBLE.length|0];
}).join('');
if(it<total){raf=requestAnimationFrame(tick);}
else{a.textContent=orig;raf=null;}
};
tick();
});
});
$$('.magnet').forEach(btn=>{
if(RM||!hasAnime)return;
const {animate,spring}=anime;
let raf=null;
btn.addEventListener('mousemove',e=>{
const r=btn.getBoundingClientRect();
const dx=e.clientX-(r.left+r.width/2);
const dy=e.clientY-(r.top+r.height/2);
if(raf)cancelAnimationFrame(raf);
raf=requestAnimationFrame(()=>{
animate(btn,{x:dx*.3,y:dy*.3,duration:320,ease:'out'});
});
});
btn.addEventListener('mouseleave',()=>{
if(raf)cancelAnimationFrame(raf);
animate(btn,{x:0,y:0,duration:750,ease:spring({stiffness:170,damping:12})});
});
});
if(!RM){
const sparkColors=['var(--pink)','var(--yellow)','var(--cyan)','var(--green)'];
document.addEventListener('pointerdown',e=>{
if(e.button!==0||!hasAnime)return;
const {animate}=anime;
for(let i=0;i<8;i++){
const p=document.createElement('i');
p.className='spark';
p.style.background=sparkColors[i%sparkColors.length];
p.style.left=e.clientX+'px';
p.style.top=e.clientY+'px';
document.body.appendChild(p);
const ang=(i/8)*Math.PI*2;
animate(p,{
x:[0,Math.cos(ang)*52],
y:[0,Math.sin(ang)*52],
opacity:[1,0],scale:[1,.15],
duration:560,ease:'outCubic',
onComplete:()=>p.remove()
});
}
});
}
const body=document.body;
const toggle=$('#loudToggle');
const swTxt=$('#swTxt');
function setLoud(on){
body.classList.toggle('loud-mode',on);
toggle.checked=on;
swTxt.textContent=on?'LOUD':'AUTO';
swTxt.classList.toggle('on',on);
vuTarget=on?1:currentVibe();
}
toggle.addEventListener('change',()=>setLoud(toggle.checked));
addEventListener('keydown',e=>{
if(e.metaKey||e.ctrlKey||e.altKey)return;
const tag=(document.activeElement&&document.activeElement.tagName)||'';
if(/INPUT|TEXTAREA|SELECT/.test(tag))return;
if(e.key.toLowerCase()==='l'){setLoud(!body.classList.contains('loud-mode'));}
});
const vu=$('#vu'),vuFill=$('#vuFill'),vuNeedle=$('#vuNeedle'),vuRead=$('#vuRead');
let vuTarget=0,vuCur=0;
function currentVibe(){
const mid=innerHeight*.5;
let val=null;
$$('[data-vibe]').forEach(s=>{
const r=s.getBoundingClientRect();
if(r.top<=mid&&r.bottom>=mid)val=parseFloat(s.dataset.vibe);
});
return val===null?vuTarget:val;
}
vuTarget=currentVibe();
addEventListener('scroll',()=>{
if(!body.classList.contains('loud-mode'))vuTarget=currentVibe();
},{passive:true});
(function vuLoop(){
vuCur+=(vuTarget-vuCur)*.07;
const pct=(vuCur*100).toFixed(2)+'%';
vuFill.style.height=pct;
vuNeedle.style.top=pct;
vuRead.textContent=vuCur<.33?'SOFT':vuCur<.72?'MID':'LOUD';
const c=vuCur<.33?'var(--ink)':vuCur<.72?'var(--orange)':'var(--pink)';
vu.style.setProperty('--vu-c',c);
requestAnimationFrame(vuLoop);
})();
})();
</script>
</body>
</html>