diff options
| author | Tyler Hoang <tyler@tylerhoang.xyz> | 2026-05-28 11:57:31 -0700 |
|---|---|---|
| committer | Tyler Hoang <tyler@tylerhoang.xyz> | 2026-05-28 11:57:31 -0700 |
| commit | 2ed8368a7972eda05fa1d9abb73194cfb31a1baa (patch) | |
| tree | 77164283f38117add07b48cf247dede8aef6cbee | |
| parent | e95e7082cd84dab268533908ca681b152ead9b29 (diff) | |
aero: quiet-web nostalgia pass (sticky note, webring, neighbors, uptime)
Implements the Frutiger Aero "Quiet Web" design handoff, merged into the
existing site without touching content:
- aero.css: append AERO — DEEPER POLISH (glass sheen, icon halo, horizon
ripple, plus aero+chrome styles for all new widgets)
- index.html: Neighbors icon + #w-neighbors window, #webring pill, #sticky
note, #uptime ribbon, Caveat font, sticky-drag + webring JS
- enter.html: welcome droplets, indie-pledge strip, footer webring, Caveat
font (gate sheen + logo halo via CSS)
aero.js left unchanged (current version newer than handoff's).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| -rw-r--r-- | aero.css | 604 | ||||
| -rwxr-xr-x | enter.html | 28 | ||||
| -rwxr-xr-x | index.html | 97 |
3 files changed, 727 insertions, 2 deletions
@@ -1230,3 +1230,607 @@ body[data-theme="chrome"] .art-foot .more { color: oklch(82% 0.14 290) !importan body[data-theme="chrome"] .browser-status { background: linear-gradient(180deg, oklch(85% 0.01 240) 0%, oklch(65% 0.02 245) 50%, oklch(78% 0.01 240) 100%) !important; border-top: 1px solid oklch(28% 0.03 250) !important; color: oklch(15% 0.02 250) !important; font-family: "Michroma", sans-serif !important; font-size: 9px !important; letter-spacing: 1.2px; text-transform: uppercase; box-shadow: inset 0 1px 0 oklch(99% 0 0 / 0.5); } body[data-theme="chrome"] .browser-status .progress { background: oklch(15% 0.04 265) !important; border: 1px solid oklch(28% 0.04 265) !important; box-shadow: inset 0 1px 2px oklch(2% 0.02 270 / 0.7); } body[data-theme="chrome"] .browser-status .progress-bar { background: linear-gradient(180deg, oklch(85% 0.18 200) 0%, oklch(70% 0.18 290) 50%, oklch(80% 0.18 320) 100%) !important; box-shadow: inset 0 1px 0 oklch(99% 0.05 200 / 0.5), 0 0 6px oklch(70% 0.18 290 / 0.8); } + +/* ================================================================ + AERO — DEEPER POLISH (Frutiger / web-2.0 indie nostalgia) + Glossy holographic shimmer on glass, water ripple at the + horizon, breathing icon halos, plus widgets that capture the + pre-corporate-internet feel: a sticky note, a webring strip, + and a "Neighbors" buddy list. + ================================================================ */ + +/* Slow holographic sweep across every glass panel (aero only) */ +/* (.win is already position: absolute — don't re-set position here or + it'll override the inline drag positioning logic.) */ +body[data-theme="aero"] .glass::after { + content: ""; + position: absolute; inset: 0; + background: linear-gradient(115deg, + transparent 30%, + oklch(99% 0.04 200 / 0.20) 47%, + oklch(96% 0.10 145 / 0.10) 50%, + oklch(99% 0.04 200 / 0.20) 53%, + transparent 70%); + background-size: 250% 100%; + animation: aeroSheen 11s ease-in-out infinite; + pointer-events: none; + mix-blend-mode: screen; + border-radius: inherit; + /* clip the gradient to the rounded panel without breaking + resize handles which sit outside the panel bounds */ + overflow: hidden; +} +@keyframes aeroSheen { + 0%, 100% { background-position: 200% 0%; } + 50% { background-position: -40% 0%; } +} + +/* don't apply sheen to inner glass children like the browser window's + inner page (they're already inside .glass) */ +body[data-theme="aero"] .glass .glass::after { display: none; } + +/* Icon halo — gentle breathing glow + brighter specular */ +body[data-theme="aero"] .icon .glyph { + box-shadow: + inset 0 1px 0 rgba(255,255,255,0.95), + inset 0 -3px 6px rgba(40,80,140,0.4), + 0 4px 14px rgba(40,80,140,0.38), + 0 0 0 1px rgba(255,255,255,0.25); + transition: transform 220ms ease, box-shadow 220ms ease, filter 220ms ease; +} +body[data-theme="aero"] .icon:hover .glyph { + transform: translateY(-3px) scale(1.05); + filter: saturate(1.15) brightness(1.05); + box-shadow: + inset 0 1px 0 rgba(255,255,255,1), + inset 0 -3px 6px rgba(40,80,140,0.45), + 0 8px 22px rgba(40,80,140,0.45), + 0 0 22px oklch(85% 0.14 200 / 0.5); +} +body[data-theme="aero"] .icon .glyph::before { + background: linear-gradient(to bottom, + rgba(255,255,255,0.95) 0%, + rgba(255,255,255,0.35) 60%, + transparent 100%); +} + +/* Horizon water-ripple at the bottom of the desktop — reflection vibe */ +body[data-theme="aero"] .desk::before { + content: ""; + position: absolute; left: 0; right: 0; bottom: 0; height: 38%; + background: + radial-gradient(120% 60% at 50% 110%, oklch(86% 0.08 165 / 0.45) 0%, transparent 70%), + repeating-linear-gradient(0deg, + oklch(99% 0.02 200 / 0.06) 0px, oklch(99% 0.02 200 / 0.06) 1px, + transparent 1px, transparent 5px); + pointer-events: none; + z-index: 0; + mask-image: linear-gradient(180deg, transparent 0%, black 60%, black 100%); + -webkit-mask-image: linear-gradient(180deg, transparent 0%, black 60%, black 100%); +} +body[data-theme="aero"] .desk::after { + content: ""; + position: absolute; left: 0; right: 0; bottom: -5%; height: 22%; + background: + radial-gradient(80% 100% at 25% 100%, oklch(94% 0.08 145 / 0.35) 0%, transparent 60%), + radial-gradient(80% 100% at 75% 100%, oklch(90% 0.10 200 / 0.35) 0%, transparent 60%); + filter: blur(8px); + pointer-events: none; + z-index: 0; + animation: aeroHorizon 16s ease-in-out infinite alternate; +} +@keyframes aeroHorizon { + 0% { transform: translateX(-2%); } + 100% { transform: translateX(2%); } +} + +/* Aqua buttons — add tasty iridescent rim in aero */ +body[data-theme="aero"] .aqua::after { + content: ""; + position: absolute; inset: -1px; + border-radius: inherit; + padding: 1px; + background: linear-gradient(135deg, + oklch(98% 0.04 200 / 0.4), + oklch(96% 0.10 145 / 0.3) 50%, + oklch(98% 0.04 200 / 0.4)); + -webkit-mask: + linear-gradient(#000 0 0) content-box, + linear-gradient(#000 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; + pointer-events: none; +} + +/* ============= STICKY NOTE (pinned to desktop) ============= */ +.sticky-note { + position: absolute; + width: 200px; + padding: 18px 16px 22px; + background: linear-gradient(180deg, oklch(96% 0.07 95) 0%, oklch(92% 0.11 92) 100%); + border: 1px solid oklch(85% 0.10 92); + box-shadow: + inset 0 1px 0 oklch(99% 0.04 95), + 0 1px 0 oklch(80% 0.08 90), + 0 18px 30px -10px rgba(80,60,20,0.35), + 0 4px 8px rgba(80,60,20,0.15); + font-family: "Caveat", "Comic Sans MS", "Marker Felt", cursive; + font-size: 17px; + line-height: 1.35; + color: oklch(35% 0.08 60); + transform: rotate(-3.2deg); + z-index: 8; + cursor: grab; + user-select: none; +} +.sticky-note::before { + /* tape strip across the top */ + content: ""; + position: absolute; + left: 50%; top: -10px; transform: translateX(-50%) rotate(-2deg); + width: 70px; height: 18px; + background: linear-gradient(180deg, + oklch(96% 0.02 200 / 0.55) 0%, + oklch(92% 0.04 200 / 0.5) 100%); + border: 1px solid oklch(85% 0.05 200 / 0.5); + border-top-color: oklch(99% 0.02 200 / 0.7); + box-shadow: 0 2px 4px rgba(40,80,140,0.15); +} +.sticky-note::after { + /* faint torn edge at the bottom */ + content: ""; + position: absolute; + left: 4px; right: 4px; bottom: 0; height: 4px; + background: linear-gradient(180deg, transparent, oklch(80% 0.10 90 / 0.4)); + border-radius: 0 0 2px 2px; +} +.sticky-note .sn-head { + font-family: "Plus Jakarta Sans", sans-serif; + font-weight: 800; + font-size: 9px; + letter-spacing: 1.6px; + text-transform: uppercase; + color: oklch(50% 0.12 60); + border-bottom: 1px dashed oklch(70% 0.10 70); + padding-bottom: 4px; + margin-bottom: 6px; + text-align: center; +} +.sticky-note .sn-sig { + display: block; + margin-top: 8px; + font-size: 14px; + color: oklch(45% 0.12 50); + opacity: 0.85; + text-align: right; +} +.sticky-note .sn-underline { + text-decoration: underline; + text-decoration-color: oklch(55% 0.16 30); + text-decoration-thickness: 1.5px; +} +/* chrome theme — sticky note becomes silver foil */ +body[data-theme="chrome"] .sticky-note { + background: linear-gradient(180deg, + oklch(90% 0.01 240) 0%, + oklch(78% 0.01 240) 50%, + oklch(88% 0.01 240) 100%); + border: 1px solid oklch(35% 0.03 250); + color: oklch(15% 0.02 250); + font-family: "IBM Plex Mono", monospace; + font-size: 11px; + letter-spacing: 0.3px; + box-shadow: + inset 0 1px 0 oklch(99% 0 0), + inset 0 -1px 0 oklch(45% 0.02 250), + 0 18px 30px -10px oklch(5% 0.03 270 / 0.6); +} +body[data-theme="chrome"] .sticky-note::before { + background: linear-gradient(180deg, + oklch(80% 0.06 290 / 0.7), + oklch(60% 0.10 290 / 0.6)); + border-color: oklch(35% 0.10 290 / 0.7); +} +body[data-theme="chrome"] .sticky-note .sn-head { + font-family: "Michroma", sans-serif; + color: oklch(75% 0.14 290); + border-bottom-color: oklch(45% 0.06 270); +} +body[data-theme="chrome"] .sticky-note .sn-sig { + font-family: "IBM Plex Mono", monospace; + color: oklch(70% 0.10 290); +} + +/* ============= WEBRING STRIP ============= */ +.webring { + position: absolute; + left: 50%; transform: translateX(-50%); + top: 16px; + z-index: 150; + display: flex; align-items: center; gap: 0; + padding: 4px 6px; + border-radius: 999px; + background: linear-gradient(to bottom, rgba(255,255,255,0.65), rgba(210,232,250,0.45)); + backdrop-filter: blur(16px) saturate(170%); + -webkit-backdrop-filter: blur(16px) saturate(170%); + border: 1px solid rgba(255,255,255,0.85); + box-shadow: + inset 0 1px 0 rgba(255,255,255,0.95), + inset 0 -1px 0 rgba(120,160,200,0.25), + 0 8px 24px rgba(40,80,140,0.28); + font-family: "Plus Jakarta Sans", "Segoe UI", sans-serif; + font-size: 11px; + font-weight: 700; + color: oklch(28% 0.06 240); + user-select: none; +} +.webring .wr-label { + padding: 0 12px 0 14px; + font-size: 10px; + letter-spacing: 2px; + text-transform: uppercase; + color: oklch(38% 0.13 220); + border-right: 1px solid rgba(120,160,200,0.35); + white-space: nowrap; +} +.webring .wr-label .wr-flower { font-size: 12px; margin-right: 4px; } +.webring .wr-btn { + display: inline-flex; align-items: center; gap: 5px; + padding: 6px 12px; border-radius: 999px; + border: 0; background: transparent; + font: inherit; color: inherit; + cursor: pointer; + text-decoration: none; + letter-spacing: 0.3px; + white-space: nowrap; +} +.webring .wr-btn:hover { + background: rgba(255,255,255,0.55); + color: oklch(40% 0.16 230); +} +.webring .wr-btn.middle { + font-family: "IBM Plex Mono", monospace; + font-weight: 500; + font-size: 10px; + opacity: 0.75; + padding: 6px 8px; + cursor: default; +} +.webring .wr-btn.middle:hover { background: transparent; color: inherit; } + +body[data-theme="chrome"] .webring { + background: linear-gradient(180deg, + oklch(90% 0.01 240), + oklch(62% 0.02 250), + oklch(80% 0.01 240)); + border: 1px solid oklch(35% 0.03 250); + backdrop-filter: none; + -webkit-backdrop-filter: none; + color: oklch(15% 0.02 250); + box-shadow: + inset 0 1px 0 oklch(99% 0 0), + inset 0 -1px 0 oklch(40% 0.02 250), + 0 8px 24px oklch(5% 0.03 270); +} +body[data-theme="chrome"] .webring .wr-label { + font-family: "Michroma", sans-serif; + color: oklch(35% 0.18 290); + border-right-color: oklch(35% 0.03 250); + letter-spacing: 2.5px; +} +body[data-theme="chrome"] .webring .wr-btn { + font-family: "Michroma", sans-serif; + font-size: 9px; + letter-spacing: 1.5px; + text-transform: uppercase; +} +body[data-theme="chrome"] .webring .wr-btn:hover { + background: oklch(45% 0.10 290 / 0.5); + color: oklch(96% 0.04 290); +} + +/* ============= NEIGHBORS / BUDDY LIST ============= */ +.bud-list { display: flex; flex-direction: column; gap: 0; } +.bud-row { + display: grid; + grid-template-columns: 12px 1fr auto; + align-items: center; + gap: 10px; + padding: 8px 4px; + border-bottom: 1px dotted oklch(72% 0.05 220); + font-size: 12px; + cursor: pointer; + border-radius: 4px; + transition: background 120ms; +} +.bud-row:last-child { border-bottom: 0; } +.bud-row:hover { + background: rgba(255,255,255,0.55); + padding-left: 8px; +} +.bud-led { + width: 8px; height: 8px; border-radius: 50%; + box-shadow: inset 0 1px 0 rgba(255,255,255,0.7); +} +.bud-led.on { + background: radial-gradient(circle at 30% 30%, oklch(96% 0.18 145), oklch(60% 0.18 150)); + box-shadow: inset 0 1px 0 rgba(255,255,255,0.7), 0 0 6px oklch(72% 0.18 145 / 0.7); +} +.bud-led.idle { + background: radial-gradient(circle at 30% 30%, oklch(95% 0.16 85), oklch(70% 0.18 75)); + box-shadow: inset 0 1px 0 rgba(255,255,255,0.7), 0 0 6px oklch(75% 0.18 80 / 0.5); +} +.bud-led.off { + background: radial-gradient(circle at 30% 30%, oklch(78% 0.02 230), oklch(55% 0.03 235)); + box-shadow: inset 0 1px 0 rgba(255,255,255,0.5); +} +.bud-name { + font-weight: 700; + color: oklch(25% 0.06 230); + letter-spacing: -0.1px; +} +.bud-host { + font-family: "IBM Plex Mono", monospace; + font-size: 10px; + opacity: 0.6; + font-weight: 500; +} +.bud-mood { + font-size: 11px; + font-style: italic; + color: oklch(45% 0.10 235); + text-align: right; + max-width: 130px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.bud-foot { + margin-top: 10px; + padding-top: 8px; + border-top: 1px dotted oklch(72% 0.05 220); + display: flex; + justify-content: space-between; + align-items: center; + font-size: 10px; + font-family: "IBM Plex Mono", monospace; + opacity: 0.7; + color: oklch(35% 0.06 230); +} +.bud-foot a { + color: oklch(45% 0.14 230); + text-decoration: none; + border-bottom: 1px dotted oklch(55% 0.14 230); +} + +body[data-theme="chrome"] .bud-row { border-bottom-color: oklch(50% 0.03 250 / 0.4); } +body[data-theme="chrome"] .bud-name { color: oklch(12% 0.02 250); font-family: "Audiowide", "Space Grotesk", sans-serif; font-weight: 400; } +body[data-theme="chrome"] .bud-host { color: oklch(60% 0.10 280); } +body[data-theme="chrome"] .bud-mood { color: oklch(70% 0.10 290); } +body[data-theme="chrome"] .bud-foot { border-top-color: oklch(50% 0.03 250 / 0.4); color: oklch(60% 0.08 280); } +body[data-theme="chrome"] .bud-row:hover { background: oklch(35% 0.05 270 / 0.4); } + +/* ============= "LAST UPDATED" + UPTIME RIBBON ============= */ +.uptime-ribbon { + position: absolute; + left: 20px; + bottom: 88px; + z-index: 7; + display: flex; align-items: center; gap: 8px; + padding: 6px 14px 6px 10px; + border-radius: 999px; + background: linear-gradient(to bottom, rgba(255,255,255,0.65), rgba(210,235,250,0.45)); + backdrop-filter: blur(12px) saturate(160%); + -webkit-backdrop-filter: blur(12px) saturate(160%); + border: 1px solid rgba(255,255,255,0.85); + box-shadow: + inset 0 1px 0 rgba(255,255,255,0.95), + 0 6px 16px rgba(40,80,140,0.25); + font-family: "IBM Plex Mono", monospace; + font-size: 10px; + letter-spacing: 0.4px; + color: oklch(32% 0.06 235); + user-select: none; + white-space: nowrap; +} +.uptime-ribbon .ur-led { + width: 7px; height: 7px; border-radius: 50%; + background: radial-gradient(circle at 30% 30%, oklch(96% 0.18 145), oklch(60% 0.18 150)); + box-shadow: inset 0 1px 0 rgba(255,255,255,0.7), 0 0 6px oklch(72% 0.18 145 / 0.7); + animation: led-pulse 2.4s ease-in-out infinite; +} +.uptime-ribbon .ur-sep { opacity: 0.4; } + +body[data-theme="chrome"] .uptime-ribbon { + background: linear-gradient(180deg, + oklch(88% 0.01 240), + oklch(62% 0.02 250), + oklch(80% 0.01 240)); + border: 1px solid oklch(35% 0.03 250); + backdrop-filter: none; + -webkit-backdrop-filter: none; + color: oklch(15% 0.02 250); + box-shadow: + inset 0 1px 0 oklch(99% 0 0), + 0 6px 16px oklch(5% 0.03 270); +} + +/* ============= WELCOME — WEBRING + INDIE STRIP ============= */ +.welcome-webring { + position: fixed; + left: 50%; transform: translateX(-50%); + bottom: 64px; + z-index: 4; + display: flex; align-items: center; gap: 0; + padding: 5px 6px; + border-radius: 999px; + background: linear-gradient(to bottom, rgba(255,255,255,0.65), rgba(210,232,250,0.45)); + backdrop-filter: blur(16px) saturate(170%); + -webkit-backdrop-filter: blur(16px) saturate(170%); + border: 1px solid rgba(255,255,255,0.85); + box-shadow: + inset 0 1px 0 rgba(255,255,255,0.95), + 0 8px 24px rgba(40,80,140,0.28); + font-family: "Plus Jakarta Sans", sans-serif; + font-weight: 700; + font-size: 11px; + color: oklch(28% 0.06 240); +} +.welcome-webring .wr-label { + padding: 0 12px; + font-size: 9px; + letter-spacing: 2px; + text-transform: uppercase; + color: oklch(38% 0.13 220); + white-space: nowrap; +} +.welcome-webring a { + display: inline-flex; align-items: center; gap: 4px; + padding: 6px 11px; + border-radius: 999px; + text-decoration: none; + color: inherit; + letter-spacing: 0.3px; + white-space: nowrap; +} +.welcome-webring a:hover { + background: rgba(255,255,255,0.55); + color: oklch(40% 0.16 230); +} +.welcome-webring .wr-sep { width: 1px; height: 16px; background: rgba(120,160,200,0.3); } + +/* Water droplet decorations on welcome */ +.welcome-drops { + position: fixed; inset: 0; pointer-events: none; z-index: 0; +} +.welcome-drops .drop { + position: absolute; + border-radius: 50% 50% 48% 52% / 60% 60% 40% 40%; + background: radial-gradient(circle at 35% 28%, + rgba(255,255,255,0.92) 0%, + rgba(220,245,255,0.45) 18%, + rgba(180,225,250,0.18) 55%, + rgba(140,200,240,0.1) 100%); + border: 1px solid rgba(255,255,255,0.55); + box-shadow: + inset -4px -6px 12px rgba(80,140,200,0.2), + inset 3px 4px 8px rgba(255,255,255,0.5), + 0 4px 14px rgba(120,180,240,0.18); +} +.welcome-drops .drop::after { + content: ""; + position: absolute; + left: 22%; top: 18%; + width: 22%; height: 16%; + background: rgba(255,255,255,0.85); + border-radius: 50%; + filter: blur(0.4px); +} + +/* "Made with love" indie strip — at the top of welcome */ +.indie-strip { + position: fixed; top: 22px; left: 26px; + z-index: 4; + display: flex; gap: 8px; flex-direction: column; + font-family: "IBM Plex Mono", monospace; + font-size: 10px; + letter-spacing: 0.4px; + color: oklch(28% 0.06 235); + text-shadow: 0 1px 0 rgba(255,255,255,0.6); +} +.indie-strip .is-line { + display: inline-flex; align-items: center; gap: 6px; + padding: 4px 10px; + border-radius: 999px; + background: rgba(255,255,255,0.5); + border: 1px solid rgba(255,255,255,0.8); + box-shadow: inset 0 1px 0 rgba(255,255,255,0.95); + width: fit-content; + backdrop-filter: blur(10px); + white-space: nowrap; +} +.indie-strip .is-dot { + width: 6px; height: 6px; border-radius: 50%; + background: radial-gradient(circle at 30% 30%, oklch(96% 0.18 145), oklch(60% 0.18 150)); + box-shadow: 0 0 4px oklch(70% 0.18 145 / 0.8); +} + +body[data-theme="chrome"] .indie-strip { color: oklch(85% 0.02 245); text-shadow: 0 1px 2px oklch(5% 0.03 270); } +body[data-theme="chrome"] .indie-strip .is-line { + background: oklch(15% 0.04 270 / 0.6); + border: 1px solid oklch(50% 0.10 290 / 0.4); + backdrop-filter: blur(10px); +} +body[data-theme="chrome"] .welcome-webring { + background: linear-gradient(180deg, + oklch(90% 0.01 240), + oklch(62% 0.02 250), + oklch(80% 0.01 240)); + border: 1px solid oklch(35% 0.03 250); + backdrop-filter: none; + -webkit-backdrop-filter: none; + color: oklch(15% 0.02 250); + font-family: "Michroma", sans-serif; + font-size: 9px; + letter-spacing: 1.5px; + text-transform: uppercase; +} +body[data-theme="chrome"] .welcome-webring .wr-label { + color: oklch(35% 0.18 290); + letter-spacing: 2.5px; +} +body[data-theme="chrome"] .welcome-webring a:hover { + background: oklch(45% 0.10 290 / 0.5); + color: oklch(96% 0.04 290); +} +body[data-theme="chrome"] .welcome-drops .drop { + background: radial-gradient(circle at 35% 28%, + rgba(220,200,255,0.7) 0%, + rgba(160,140,220,0.25) 30%, + rgba(80,60,140,0.12) 80%); + border: 1px solid rgba(200,180,255,0.4); + box-shadow: + inset -4px -6px 12px rgba(40,20,100,0.4), + inset 3px 4px 8px rgba(220,200,255,0.4), + 0 4px 14px oklch(40% 0.16 290 / 0.3); +} + +/* Caveat for handwritten sticky */ +/* (Imported in HTML head — kept here so the file documents the dep) */ + +/* Welcome gate — aero holographic sheen */ +body[data-theme="aero"] .gate { + overflow: hidden; +} +body[data-theme="aero"] .gate::after { + content: ""; + position: absolute; inset: 0; + background: linear-gradient(115deg, + transparent 28%, + oklch(99% 0.04 200 / 0.22) 45%, + oklch(96% 0.12 145 / 0.12) 50%, + oklch(99% 0.04 200 / 0.22) 55%, + transparent 72%); + background-size: 260% 100%; + animation: aeroSheen 9s ease-in-out infinite; + pointer-events: none; + mix-blend-mode: screen; + border-radius: inherit; +} + +/* Welcome mark — gentle floating ring of light (aero) */ +body[data-theme="aero"] .mark::after { + content: ""; + position: absolute; inset: -6px; + border-radius: 50%; + background: conic-gradient(from 0deg, + oklch(96% 0.10 145 / 0.0), + oklch(96% 0.14 145 / 0.55), + oklch(96% 0.10 200 / 0.55), + oklch(96% 0.12 145 / 0.0)); + mask: radial-gradient(circle, transparent 56%, black 58%, black 64%, transparent 66%); + -webkit-mask: radial-gradient(circle, transparent 56%, black 58%, black 64%, transparent 66%); + animation: spin 18s linear infinite; + pointer-events: none; + opacity: 0.8; +} @@ -5,7 +5,7 @@ <title>welcome — tyler.xyz</title> <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> -<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Audiowide&family=Michroma&family=Plus+Jakarta+Sans:wght@200;300;400;500;600;700;800&family=Space+Grotesk:wght@400;500;700&family=IBM+Plex+Mono:wght@400;500&display=swap" /> +<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Audiowide&family=Caveat:wght@400;500;600;700&family=Michroma&family=Plus+Jakarta+Sans:wght@200;300;400;500;600;700;800&family=Space+Grotesk:wght@400;500;700&family=IBM+Plex+Mono:wght@400;500&display=swap" /> <link rel="stylesheet" href="aero.css" /> <style> body { @@ -164,6 +164,22 @@ <script>(function(){var t=localStorage.getItem('tyler.theme')||'aero';document.body.setAttribute('data-theme',t);})();</script> <div id="bub-stage" style="position:fixed;inset:0;pointer-events:none;z-index:0"></div> + <!-- Floating water droplets in the corners (aero polish) --> + <div class="welcome-drops" aria-hidden="true"> + <div class="drop" style="left: 6%; top: 10%; width: 84px; height: 76px;"></div> + <div class="drop" style="left: 14%; bottom: 18%; width: 42px; height: 38px;"></div> + <div class="drop" style="right: 8%; top: 22%; width: 56px; height: 50px;"></div> + <div class="drop" style="right: 18%; top: 8%; width: 28px; height: 26px;"></div> + <div class="drop" style="right: 12%; bottom: 28%; width: 96px; height: 86px;"></div> + <div class="drop" style="left: 28%; bottom: 8%; width: 36px; height: 32px;"></div> + </div> + + <!-- Indie-web pledge strip (top-left) --> + <div class="indie-strip"> + <div class="is-line"><span class="is-dot"></span>no ads · no trackers</div> + <div class="is-line" style="opacity: 0.85;">hand-coded · hosted at home · since 2019</div> + </div> + <div class="stage"> <div class="gate"> <div class="mark">❀</div> @@ -180,6 +196,16 @@ <div class="footer-note">tyler hoang © 2026 · hosted on vultr · <a class="aero-link" style="color:inherit;" href="mailto:tyler@tylerhoang.xyz">tyler@tylerhoang.xyz</a></div> + <!-- Webring footer (very 2003) --> + <div class="welcome-webring"> + <span class="wr-label"><span style="font-size:12px;">❀</span> quiet web ring</span> + <a href="#" title="previous site">« prev</a> + <span class="wr-sep"></span> + <a href="#" title="random site">random</a> + <span class="wr-sep"></span> + <a href="#" title="next site">next »</a> + </div> + <div class="badges"> <div class="badge">best viewed on a real computer</div> <div class="badge green">javascript on</div> @@ -5,7 +5,7 @@ <title>tyler.xyz · Aqua Desktop</title> <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> -<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Audiowide&family=Michroma&family=Plus+Jakarta+Sans:wght@200;300;400;500;600;700;800&family=Space+Grotesk:wght@400;500;700&family=IBM+Plex+Mono:wght@400;500&display=swap" /> +<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Audiowide&family=Caveat:wght@400;500;600;700&family=Michroma&family=Plus+Jakarta+Sans:wght@200;300;400;500;600;700;800&family=Space+Grotesk:wght@400;500;700&family=IBM+Plex+Mono:wght@400;500&display=swap" /> <link rel="stylesheet" href="aero.css" /> <style> /* ============= LOCKED PALETTE ============= */ @@ -296,6 +296,7 @@ <div class="icon" data-open="podcast"><div class="glyph" style="background: var(--icon-silver)">🎙</div><div class="label">REEL MOUTH</div></div> <div class="icon" data-open="films"><div class="glyph" style="background: var(--icon-pink)">🎞</div><div class="label">Films</div></div> <div class="icon" data-open="browser"><div class="glyph" style="background: var(--icon-blue)">🌐</div><div class="label">Internet</div></div> + <div class="icon" data-open="neighbors"><div class="glyph" style="background: var(--icon-green)">🏡</div><div class="label">Neighbors</div></div> <div class="icon" data-open="guestbook"><div class="glyph" style="background: var(--icon-blue)">✉</div><div class="label">Contact</div></div> </div> @@ -524,6 +525,59 @@ </div> </div> + <!-- NEIGHBORS / BUDDY LIST --> + <div class="win glass" id="w-neighbors" style="left: 880px; top: 220px; width: 340px; display: none;"> + <div class="titlebar" style="background: var(--title-bar);"><div class="dots"><div class="dot r no-drag" onclick="this.closest('.win').style.display='none'"></div><div class="dot y"></div><div class="dot g"></div></div>Neighbors — the indie web</div> + <div class="body"> + <div style="font-size: 11px; opacity: 0.7; margin-bottom: 10px; text-transform: uppercase; letter-spacing: 1.5px;">friends & favorite homepages · 6 of 19</div> + <div class="bud-list"> + <div class="bud-row"><div class="bud-led on"></div><div><div class="bud-name">trinh's garden 🌿</div><div class="bud-host">trinh.computer</div></div><div class="bud-mood">repotting a monstera</div></div> + <div class="bud-row"><div class="bud-led on"></div><div><div class="bud-name">jay's mixtapes</div><div class="bud-host">jaylim.fm</div></div><div class="bud-mood">new bossa nova set</div></div> + <div class="bud-row"><div class="bud-led idle"></div><div><div class="bud-name">ari's lab notebook</div><div class="bud-host">arielab.dev</div></div><div class="bud-mood">soldering @ 3am again</div></div> + <div class="bud-row"><div class="bud-led on"></div><div><div class="bud-name">linh writes things</div><div class="bud-host">linhwrites.net</div></div><div class="bud-mood">draft #4 of the essay</div></div> + <div class="bud-row"><div class="bud-led idle"></div><div><div class="bud-name">marco's hifi corner</div><div class="bud-host">marco.audio</div></div><div class="bud-mood">tube amp restoration</div></div> + <div class="bud-row"><div class="bud-led off"></div><div><div class="bud-name">small green pixels</div><div class="bud-host">smallgreenpix.org</div></div><div class="bud-mood">— offline · away —</div></div> + </div> + <div class="bud-foot"> + <span>last sync · 2 min ago</span> + <a href="#">see all 19 →</a> + </div> + <p style="margin: 12px 0 0; font-size: 11px; line-height: 1.55; opacity: 0.7; font-family: 'Plus Jakarta Sans', sans-serif;"> + all hand-curated. no algorithms, no follow-back debt. if you keep a homepage and want to be neighbors, <a class="aero-link" href="mailto:tyler@tylerhoang.xyz">drop a line</a>. + </p> + </div> + </div> + + <!-- WEBRING (top-center floating) --> + <div class="webring no-drag" id="webring"> + <div class="wr-label"><span class="wr-flower">❀</span>quiet web ring</div> + <a class="wr-btn" href="#" id="wr-prev" title="previous site in the ring">« prev</a> + <span class="wr-btn middle" id="wr-count">site 42 / 184</span> + <a class="wr-btn" href="#" id="wr-rand" title="random site">random</a> + <a class="wr-btn" href="#" id="wr-next" title="next site in the ring">next »</a> + </div> + + <!-- STICKY NOTE pinned to desktop --> + <div class="sticky-note" id="sticky" style="right: 32px; top: 96px;"> + <div class="sn-head">remember</div> + water the basil · ☕<br/> + call mom on sunday<br/> + finish thesis ch. <span class="sn-underline">3</span> by friday<br/> + <span style="opacity:0.7">— and stop checking</span><br/> + <span style="opacity:0.7">the news so much</span> + <span class="sn-sig">— t.</span> + </div> + + <!-- UPTIME RIBBON (bottom-right above taskbar) --> + <div class="uptime-ribbon" id="uptime"> + <div class="ur-led"></div> + <span>online & quiet</span> + <span class="ur-sep">·</span> + <span>uptime 412d</span> + <span class="ur-sep">·</span> + <span>♥ from long beach, ca</span> + </div> + <!-- TASKBAR --> <div class="taskbar"> <div class="start"><span style="font-size:16px;">❀</span> tyler</div> @@ -556,6 +610,47 @@ Aero.makeResizable(w, { minW: 300, minH: 220 }); }); + // Sticky note — draggable, lightly random tilt so each load feels handmade + const sticky = document.getElementById('sticky'); + if (sticky) { + const rot = (-4 + Math.random() * 3).toFixed(2); + sticky.style.transform = `rotate(${rot}deg)`; + Aero.makeDraggable(sticky, sticky); + } + + // Webring — silly old-internet behaviour + const wrPrev = document.getElementById('wr-prev'); + const wrNext = document.getElementById('wr-next'); + const wrRand = document.getElementById('wr-rand'); + const wrCount = document.getElementById('wr-count'); + const ringSites = [ + 'mireia.computer', 'jaylim.fm', 'trinh.computer', 'arielab.dev', + 'linhwrites.net', 'marco.audio', 'smallgreenpix.org', 'amalia.zone', + 'thursday.cafe', 'soft.garden', 'foglamp.club', 'kanji.coffee' + ]; + let ringIdx = 42; + function ringHop(dir) { + ringIdx = Math.max(1, Math.min(184, ringIdx + dir)); + wrCount.textContent = `site ${ringIdx} / 184`; + const site = ringSites[Math.floor(Math.random() * ringSites.length)]; + wrCount.title = `would surf to ${site}`; + wrCount.animate( + [{ opacity: 0.3 }, { opacity: 0.75 }], + { duration: 280, easing: 'ease-out' } + ); + } + if (wrPrev) wrPrev.addEventListener('click', e => { e.preventDefault(); ringHop(-1); }); + if (wrNext) wrNext.addEventListener('click', e => { e.preventDefault(); ringHop(1); }); + if (wrRand) wrRand.addEventListener('click', e => { + e.preventDefault(); + ringIdx = 1 + Math.floor(Math.random() * 184); + wrCount.textContent = `site ${ringIdx} / 184`; + wrCount.animate( + [{ transform: 'scale(0.9)', opacity: 0.3 }, { transform: 'scale(1)', opacity: 0.75 }], + { duration: 320, easing: 'ease-out' } + ); + }); + document.querySelectorAll('.icon').forEach(ic => { ic.addEventListener('dblclick', () => { const key = ic.dataset.open; |
