2026-10-21 22:52:18 +03:00
<!doctype html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
< title > hermes.x/messenger — browser messenger (preview)< / title >
< meta name = "description" content = "The web version of Hermes: encrypted DMs over Nostr, addressed by on-chain registered name, running in your browser. Preview of the UI; functional release pending." >
< link rel = "icon" href = "../assets/favicon.svg" type = "image/svg+xml" >
< link rel = "stylesheet" href = "../assets/shared.css" >
< style >
/* ---- status banner ---- */
.status-banner{
background:rgba(255,199,95,.08);
border:1px solid rgba(255,199,95,.26);
border-radius:12px;
padding:14px 18px;
margin:1.5rem auto;
max-width:780px;
font-size:14px;
color:var(--ink);
display:flex;gap:14px;align-items:flex-start;
}
.status-banner .dot{
width:10px;height:10px;border-radius:50%;background:var(--warn);
margin-top:6px;flex-shrink:0;animation:pulse 2s ease-in-out infinite;
}
@keyframes pulse { 50% { opacity:.4 } }
.status-banner b{color:var(--warn)}
/* ---- mockup frame ---- */
.mockup{
background:var(--panel);border:1px solid var(--line2);border-radius:16px;
overflow:hidden;margin:1.5rem auto;max-width:860px;
box-shadow:0 20px 60px rgba(0,0,0,.4);
}
.mockup .window-bar{
display:flex;align-items:center;gap:8px;padding:10px 14px;
background:var(--panel2);border-bottom:1px solid var(--line);
}
.mockup .window-bar .dot{width:11px;height:11px;border-radius:50%;background:#444a56}
.mockup .window-bar .dot:nth-child(1){background:#ff5f57}
.mockup .window-bar .dot:nth-child(2){background:#febc2e}
.mockup .window-bar .dot:nth-child(3){background:#28c840}
.mockup .window-bar .title{color:var(--mut);font-size:12px;margin-left:10px}
.mockup .window-bar .status{margin-left:auto;font-size:11px;color:var(--ok);padding:2px 10px;border-radius:999px;background:rgba(79,209,165,.14)}
.mockup .window-bar .npub{color:var(--mut);font-size:11px;font-family:ui-monospace,monospace;margin-left:12px}
.mockup .npub b{color:var(--sky)}
.mockup .app{display:grid;grid-template-columns:220px 1fr;min-height:420px}
.mockup .side{background:var(--panel2);border-right:1px solid var(--line);display:flex;flex-direction:column}
.mockup .side-head{padding:10px;display:flex;gap:6px;border-bottom:1px solid var(--line)}
.mockup .side-head input{flex:1;background:var(--panel);border:1px solid var(--line);border-radius:6px;padding:6px 10px;color:var(--mut);font-size:12px}
.mockup .side-head button{background:var(--sky);color:#06111a;border:none;border-radius:6px;padding:6px 10px;font-weight:600;cursor:pointer;font-size:13px}
.mockup .contact{display:flex;gap:10px;align-items:center;padding:9px 12px;border-bottom:1px solid rgba(255,255,255,.03);cursor:pointer}
.mockup .contact.active{background:var(--panel3)}
.mockup .contact .avatar{width:28px;height:28px;border-radius:50%;background:linear-gradient(135deg,#2a3a4a,#1a2432);display:flex;align-items:center;justify-content:center;font-size:11px;color:var(--mut);font-weight:600;text-transform:uppercase}
.mockup .contact .meta{flex:1;min-width:0}
.mockup .contact .name{font-size:12.5px;color:var(--ink);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mockup .contact .last{font-size:11px;color:var(--mut);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mockup .contact .badge{background:var(--sky);color:#06111a;font-size:10px;font-weight:700;padding:1px 7px;border-radius:999px}
.mockup .thread{display:flex;flex-direction:column;background:var(--bg)}
.mockup .thread-head{padding:12px 16px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:12px}
.mockup .thread-head .name{font-weight:600;font-size:13px}
.mockup .thread-head .pk{font-family:ui-monospace,monospace;font-size:10.5px;color:var(--mut)}
.mockup .thread-body{flex:1;padding:14px 16px;display:flex;flex-direction:column;gap:6px}
.mockup .bubble{max-width:70%;padding:7px 11px;border-radius:14px;font-size:13px;line-height:1.4}
.mockup .bubble.in{background:#1d2634;align-self:flex-start;border-bottom-left-radius:4px}
.mockup .bubble.out{background:#0d2a3a;align-self:flex-end;border-bottom-right-radius:4px;color:#d9ecfa}
.mockup .bubble .time{display:block;font-size:10px;color:var(--dim);margin-top:3px}
.mockup .compose{display:flex;gap:8px;padding:10px 14px;border-top:1px solid var(--line);background:var(--panel)}
.mockup .compose input{flex:1;background:var(--bg);border:1px solid var(--line);border-radius:8px;padding:9px 11px;color:var(--mut);font-size:13px}
.mockup .compose button{background:var(--sky);color:#06111a;border:none;padding:0 18px;border-radius:8px;font-weight:600;cursor:pointer}
.plan-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px}
@media (max-width:700px){.plan-grid{grid-template-columns:1fr}}
.plan{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:16px}
.plan h3{display:flex;align-items:center;gap:8px}
.plan ul{margin:.5rem 0 0;padding:0 0 0 1.2rem;color:var(--mut);font-size:14px;line-height:1.7}
.mockup-caption{text-align:center;color:var(--dim);font-size:12px;margin-top:-.5rem;margin-bottom:1.5rem}
< / style >
< / head >
< body >
< nav class = "topnav" >
< a class = "brand" href = "../" >
hermes.x: new mark everywhere, drop redundant Overview nav link
The new tight mark (filled Hermes figure, acid blue, 64×64 viewBox)
replaces both mark.svg and favicon.svg so every existing reference —
brand nav, hero, branding grid, OG image, favicon — picks it up with
no attribute changes. The old file sat behind weird width="5" / "3"
height="22" attributes that crushed it into a sliver; squared the
dimensions per slot so the mark actually renders.
Also drop the "Overview" link from each page's top nav — Hermes.X in
the brand slot already goes to the index, so Overview sent you to the
same place with a different word. Three pages touched: index,
branding, messenger.
2026-10-21 23:01:20 +03:00
< img src = "../assets/mark.svg" alt = "Hermes" width = "22" height = "22" style = "display:block" >
2026-10-21 22:52:18 +03:00
< span > Hermes< span class = "x" > .X< / span > < / span >
< / a >
< a href = "./" class = "here" > Messenger< / a >
< a href = "../branding/" > Branding< / a >
< a href = "https://theseus.x/" class = "get" > Get Theseus< / a >
< / nav >
< header class = "hero" >
< div class = "mark" style = "color:var(--sky); line-height:0; display:inline-flex" aria-hidden = "true" >
< img src = "../assets/mark.svg" alt = "Hermes" width = "96" height = "96" style = "display:block" >
< / div >
< h1 > Messenger< / h1 >
< p class = "tag" > Hermes in a browser tab — end-to-end encrypted DMs over Nostr,
addressed by on-chain registered name. The desktop client has
the richest flavour; the web messenger meets you where you are.< / p >
< / header >
< div class = "status-banner" >
< div class = "dot" > < / div >
< div >
< b > Preview.< / b > The desktop messenger inside < a href = "https://theseus.x/" > Theseus< / a >
is live today — threaded chat, persistent history, address book, keyboard
shortcut < code class = "inline" > Ctrl+Shift+E< / code > . The web-only client
(what this page becomes) is in development: BIP-39 → Nostr key derivation,
BCH-name resolution via gateway, NIP-17 wrap/unwrap, WebSocket to relays,
IndexedDB inbox. Everything client-side, nothing uploaded.
< / div >
< / div >
< div class = "mockup" aria-label = "Messenger UI preview" >
< div class = "window-bar" >
< div class = "dot" > < / div > < div class = "dot" > < / div > < div class = "dot" > < / div >
< div class = "title" > Hermes · hermes.x/messenger< / div >
< span class = "npub" > your npub: < b > npub1ab…z89< / b > < / span >
< span class = "status" > 1/1 relay< / span >
< / div >
< div class = "app" >
< aside class = "side" >
< div class = "side-head" > < input value = "Search contacts…" readonly > < button > +< / button > < / div >
< div class = "contact" >
< div class = "avatar" > AL< / div >
< div class = "meta" > < div class = "name" > alice< / div > < div class = "last" > you: see you tomorrow< / div > < / div >
< / div >
< div class = "contact active" >
< div class = "avatar" > BO< / div >
< div class = "meta" > < div class = "name" > bob< / div > < div class = "last" > great, send me the link< / div > < / div >
< div class = "badge" > 2< / div >
< / div >
< div class = "contact" >
< div class = "avatar" > TE< / div >
< div class = "meta" > < div class = "name" > test< / div > < div class = "last" > chipnet is working< / div > < / div >
< / div >
< / aside >
< section class = "thread" >
< div class = "thread-head" >
< div >
< div class = "name" > bob< / div >
< div class = "pk" > 023bf8c1…9ad2< / div >
< / div >
< / div >
< div class = "thread-body" >
< div class = "bubble in" > hey, did you register your name yet?< span class = "time" > 11:38< / span > < / div >
< div class = "bubble out" > just now — bob.x is live< span class = "time" > 11:40< / span > < / div >
< div class = "bubble in" > nice. send me the hermes.x link< span class = "time" > 11:42< / span > < / div >
< div class = "bubble out" > https://hermes.x/messenger< span class = "time" > 11:43< / span > < / div >
< div class = "bubble in" > great, send me the link< span class = "time" > 11:44< / span > < / div >
< / div >
< div class = "compose" >
< input value = "Message…" readonly >
< button > Send< / button >
< / div >
< / section >
< / div >
< / div >
< div class = "mockup-caption" > Non-interactive preview — live build pending (see roadmap below).< / div >
< div class = "wrap narrow" >
< section >
< h2 > Two clients, one identity< / h2 >
< div class = "plan-grid" >
< div class = "plan" >
< h3 > Desktop (Theseus) < span class = "src ok" > live< / span > < / h3 >
< ul >
< li > Full crypto in-process (NIP-17, nip44 v2)< / li >
< li > Persistent inbox + read-state on disk< / li >
< li > Address book (local JSON + vCard import)< / li >
< li > Sidebar panel, Ctrl+Shift+E shortcut< / li >
< li > Vault-bind: no re-typing the mnemonic< / li >
< li > Reverse-resolve pk → on-chain name< / li >
< / ul >
< div class = "cta" style = "justify-content:flex-start;margin-top:1.2rem" >
< a class = "btn primary" href = "https://theseus.x/" > Get Theseus< / a >
< / div >
< / div >
< div class = "plan" >
< h3 > Web (this page) < span class = "src next" > building< / span > < / h3 >
< ul >
< li > Same crypto, same identity (same wallet seed derivation)< / li >
< li > BCH name resolution via public gateway< / li >
< li > WebSocket to Nostr relays from the browser< / li >
< li > IndexedDB inbox — survives tab close, scoped to this origin< / li >
< li > No download, no install, no account< / li >
< li > Mnemonic entry only — never stored in plaintext< / li >
< / ul >
< div class = "cta" style = "justify-content:flex-start;margin-top:1.2rem" >
< a class = "btn ghost" href = "../" > Why Hermes< / a >
< / div >
< / div >
< / div >
< / section >
< section >
< h2 > Why wait for the web client< / h2 >
< p class = "lede" > The web messenger isn't ready yet because of three things we
want to get right before shipping:< / p >
< ol class = "steps" >
< li > < b > Key handling in a tab.< / b >
< span > A wallet mnemonic is the most sensitive bit of data a user has. In
the desktop app it lives in main-process memory; in a tab it has to
survive page reloads without ever landing in plaintext anywhere. We're
wiring a WebCrypto-backed non-extractable key path with the vault PIN
as the gate.< / span > < / li >
< li > < b > Resolver gateway.< / b >
< span > The desktop talks to a chipnet Fulcrum directly. A browser can't
— it needs an HTTPS gateway that answers < code class = "inline" > np< / code >
/ < code class = "inline" > nr< / code > for a name. The gateway is live
(< code class = "inline" > navigate.st/api/dns/alice.x< / code > ) but the
client-side cache + signature-verification path still has an edge case
with lapsed names.< / span > < / li >
< li > < b > Relay persistence.< / b >
< span > Desktop keeps a long-lived WebSocket to each relay. A tab doesn't,
because browsers throttle background sockets. The web client needs
offline queueing and a well-defined "catch-up" fetch on return —
otherwise you re-open the tab and the inbox feels empty.< / span > < / li >
< / ol >
< p > Until the three are solid, < b > install Theseus< / b > for the real thing.
The web client will land here when the above are green.< / p >
< div class = "cta" >
< a class = "btn primary" href = "https://theseus.x/" > Get Theseus< / a >
< a class = "btn ghost" href = "../branding/" > Brand kit< / a >
< / div >
< / section >
< / div >
< footer >
< div > hermes.x — a < a href = "https://silentmode.st/" > Silent Mode< / a > project.< / div >
< div class = "fine" > Preview only. The functional web client is being built.< / div >
< / footer >
< / body >
< / html >