summaryrefslogtreecommitdiffstats
path: root/src/recipient-search.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-09-10 22:51:56 -0700
committerAdam Soltys <[email protected]>2026-09-10 22:51:56 -0700
commit82cd8da7f5ab285b3a91f7284fb8d845400012ca (patch)
treeebf9d6d638ba110ff1e17624148ef7d9ac7412b5 /src/recipient-search.js
parentac675185e362930f2086e01ab578fdd3423e4c79 (diff)
downloadcoinosv3-82cd8da7f5ab285b3a91f7284fb8d845400012ca.tar.gz
coinosv3-82cd8da7f5ab285b3a91f7284fb8d845400012ca.zip
Ship the punks at the size we actually draw them.
The art is 240x240 (20KB each, 1.5MB for the set) because that's what a punk published as someone's nostr picture should be — but the circles the app draws are 18 to 64px, so a new wallet with nothing cached was fetching eight times the pixels it could show, one request per face. punks-sm carries a 128px copy of each: 4KB instead of 20KB, indistinguishable at 64px. Small circles and the wizard's picker tiles load those; only the 64px profile avatar and the value the wizard publishes stay full-size. The bigger win is that a punk picture is our own art wherever it turns up. Everyone who keeps the default publishes v3.coinos.io/punks/N.webp as their nostr picture, so those faces now paint straight off disk at the size being drawn — no request, no thumbnail to make, and no broken circle when the legacy coinos.io copies 502 (which they do for a third of the set). Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
Diffstat (limited to 'src/recipient-search.js')
-rw-r--r--src/recipient-search.js17
1 files changed, 14 insertions, 3 deletions
diff --git a/src/recipient-search.js b/src/recipient-search.js
index a5c5f46..be3c70e 100644
--- a/src/recipient-search.js
+++ b/src/recipient-search.js
@@ -15,12 +15,23 @@ import { queryOn, parseNostrPubkey, npubOf, PROFILE_RELAYS } from './nostr.js';
// if the image can't load (offline).
// Self-hosted (dist/punks) — coinos.io's own copies 502 for a third of the
// set. Same deterministic formula the coinos app uses.
-export const punkUrl = (pk) =>
- `punks/${Math.floor((parseInt(pk.slice(-2), 16) / 256) * 64) + 1}.webp`;
+const punkN = (pk) => Math.floor((parseInt(pk.slice(-2), 16) / 256) * 64) + 1;
+export const punkUrl = (pk) => `punks/${punkN(pk)}.webp`;
+// The art is 240px, which is what a punk published as someone's nostr
+// picture should be — and eight times what a 30px circle needs. We ship a
+// 128px copy of each (a fifth of the bytes, 20KB → 4KB) and paint the circles
+// from that, so a brand-new wallet with nothing cached fills its faces in
+// straight away. Only the 64px profile avatar takes the full-size one.
+export const punkSmallUrl = (pk) => `punks-sm/${punkN(pk)}.webp`;
+export const punkSmallN = (n) => `punks-sm/${n}.webp`;
export const fallbackAvatar = (h, pk, name, cls) =>
h('div', { class: cls + ' fallback' },
- h('img', { class: 'punk', src: punkUrl(pk), alt: '', onError: (e) => { e.target.style.display = 'none'; } }),
+ h('img', {
+ class: 'punk', alt: '',
+ src: cls.includes('profile-avatar') ? punkUrl(pk) : punkSmallUrl(pk),
+ onError: (e) => { e.target.style.display = 'none'; },
+ }),
(name || npubOf(pk) || '??').slice(0, 2));
const REGISTRAR = 'https://names.coinos.io';