Identity overhaul (server changes deployed to goblin.st separately):
Avatars
- profile pictures hosted on goblin.st, tied to the username: tap the
settings avatar → native image picker → 256px PNG uploaded over Tor
- letter avatars now use (background, ink) color pairs (8) keyed off the
npub, and render the first ALPHANUMERIC char — never the '@'
- custom pictures shown everywhere self/contacts appear: settings card,
home header, sidebar chip, peers strip, activity rows, send recipient
- AvatarTextures: disk cache (~/.goblin/cache/avatars) + background Tor
fetch + egui textures loaded on the UI thread; a network/Tor failure
is never cached as "no avatar" (would have stuck for 6h)
- nostr/avatar.rs mirrors the server's sniff→limits→orientation→crop→
256→re-encode-PNG pipeline so uploads are small and previews instant
Username lifecycle
- rotating the key now RELEASES the username (and deletes its avatar
server-side) instead of transferring; rotation aborts if release fails
- claim panel is one Claim button (checks then registers); registered
state shows "Registered <name>" + a Release action behind an
are-you-sure gate ("up for grabs the moment it's free")
- released names are immediately re-claimable (quarantine removed)
Other
- Tor::http_request_bytes: binary bodies + status code, for upload and
avatar download (string http_request kept as a wrapper)
- settings reordered Identity-first, then Wallet
- sidebar node card is 3 lines: status / block height / host
- profile card shows the full npub when it fits, else head…tail
34 lib tests green. Live-verified on goblin.st: upload→serve (image/png,
nosniff, immutable)→5/day limit (6th 429)→release purges avatar; a real
picture for @fartmuncher22 fetched over Tor and rendered across surfaces.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Camera/QR (validated live with a v4l2loopback virtual camera):
- decode non-MJPEG frames on Linux (raw YUYV was undecodable: eternal
spinner), enumerate devices off the UI thread without unwrap, open
cameras by their real device index (list position broke whenever
/dev/video0 was absent), show "No camera found" after 5s
- scan-to-pay: QR button in the send recipient search row and the
mobile home header; in-surface camera panel feeding recipient
resolution; only text payloads accepted (seeds/slatepacks refused)
- receive QR was unscannable: full cells (0.5px gaps fragmented finder
patterns at 4.5px cells), always ink-on-white plate (inverted codes
fail many scanners), center mark 26% -> 19% (zbar chokes above);
rqrr+zbar both decode the live card now; unit tests cover the exact
widget geometry
First-run onboarding (replaces the stock empty state only; the wallet
list, add-wallet modal and GRIM creation flow stay for later wallets):
- intro -> node choice (Private integrated / Instant external with
URL) -> create or restore (wraps MnemonicSetup; word grid, paste,
SeedQR scan) -> optional @username claim with prominent skip
- fonts bind at creation context so frame one can use Geist families
Sweep fixes (22 confirmed findings, the simple ones):
- yellow theme: active sidebar nav was dark-on-dark (P1)
- window frame ring painted with theme bg: transparent clear color
rendered as a black band without a compositor (P2)
- import/rotate identity inputs get visible field wells (P2)
- receive buttons: verb labels + transient "Copied" feedback
- review hero card fills the column; fee row copy; pay-tab stale and
duplicated hints; unlock modal copy; node card subtitle truncation
- build number stays current (.git/logs/HEAD rerun trigger)
Backup restore: import accepts the export-time password and re-encrypts
under the current wallet password; cross-device restores work.
31 lib tests green. Mainnet-validated: both flows restored real
wallets; 0.1 grin sent B->A through NIP-17 over Tor with async
open/close ping-pong; tx 71fbfce4f591 posted on-chain.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>