aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-09-10 23:00:21 -0700
committerAdam Soltys <[email protected]>2026-09-10 23:00:21 -0700
commit48e8e588f1a3dee26a2497d1a1757f2f294413a3 (patch)
tree789e7ed5dbe67d2bfae1f45ae4628250639bc772 /src
parent82cd8da7f5ab285b3a91f7284fb8d845400012ca (diff)
downloadcoinosv3-48e8e588f1a3dee26a2497d1a1757f2f294413a3.tar.gz
coinosv3-48e8e588f1a3dee26a2497d1a1757f2f294413a3.zip
A face we've never seen is drawn from the pubkey, not left blank.
The avatar delay left on the messages page wasn't the image at all. A person with no cached profile got an empty circle until a relay answered — and the one that stayed blank longest (npub1k6f89cg, in the live cache) is never cached at all: persistProfile deliberately refuses to write a row with no name and no picture, so every boot re-asked the relays and every boot sat blank for seconds. When it finally arrived it was a punk, which is why it looked like slow art rather than a slow lookup. The punk is derived from the pubkey alone, so it can be drawn in the first frame. It's already the right answer for everyone with no picture, and for a coinos user who kept the default it IS their published picture — same formula, same file. A real photo replaces it when it lands. A name lookup in flight still gets the quiet circle: a picture is expected there, and punk art must not flash in front of it. Also: the punk rewrite now recognises the bare relative path a few older profiles carry, not just the absolute URL. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
Diffstat (limited to 'src')
-rw-r--r--src/features/messages.js24
1 files changed, 18 insertions, 6 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index b23d7ad..59dcb1d 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -337,7 +337,9 @@ export function messagesFeature(ctx) {
// the legacy coinos.io copies 502 for a third of the set — so painting
// those from the local files means no network, no broken faces, and the
// right size for the circle being drawn.
- const PUNK_PIC_RE = /^https?:\/\/(?:[a-z0-9-]+\.)*coinos\.io\/punks\/(\d{1,2})\.webp$/i;
+ // Absolute (what the wizard publishes) or the bare relative path an older
+ // build wrote into a few profiles.
+ const PUNK_PIC_RE = /^(?:https?:\/\/(?:[a-z0-9-]+\.)*coinos\.io\/)?punks\/(\d{1,2})\.webp$/i;
const localPunk = (url, big) => {
const m = PUNK_PIC_RE.exec(url || '');
return m ? (big ? `punks/${m[1]}.webp` : `punks-sm/${m[1]}.webp`) : null;
@@ -1761,12 +1763,22 @@ export function messagesFeature(ctx) {
const avatar = (pk, cls = 'chat-avatar', clickable = true) => {
const p = profileOf(pk);
- // While the profile is in flight, a quiet empty circle — the punk is a
- // statement about having no picture, not a loading state. (`loading` on
- // an entry marks a provisional seed: name known, picture still unknown.)
- const node = p === null || (p && p.loading && !p.picture)
+ // Someone we've never cached used to get an empty circle until a relay
+ // answered — seconds of blankness on every boot, and for anyone whose
+ // kind 0 carries no picture (or none at all, which never gets cached)
+ // that repeated forever. The punk is derived from the pubkey alone, so
+ // it can be drawn in the first frame: it's already the right answer for
+ // everyone without a picture, and for a coinos user who kept the default
+ // it IS their published picture. A real photo replaces it when it lands.
+ //
+ // `loading` is different and still gets the quiet circle: a name lookup
+ // is in flight for that specific person, so a picture is expected and
+ // punk art must not flash in front of it.
+ const node = p && p.loading && !p.picture
? h('div', { class: cls + ' fallback loading' })
- : p.picture
+ : p === null
+ ? fallbackAvatar(h, pk, null, cls)
+ : p.picture
// A background paints synchronously from cache; a fresh <img> decodes
// async, so recreating one per render made avatars visibly flash.
//