{"id":"72f0a3c1c8b2d0dcd2d79c89eb76cee58fa13b25e750c45f6e232b88ae1f3883","pubkey":"b22b06b051fd5232966a9344a634d956c3dc33a7f5ecdcad9ed11ddc4120a7f2","created_at":1776546976,"kind":30817,"tags":[["d","default-picture"],["title","Default picture"],["k","0"],["client","nostrhub.io"]],"content":"# NIP default picture\n\n## Avatar Derivation\n\n`draft` `standard` `ui`\n\n## Abstract\n\nThis NIP standardizes a deterministic method for deriving avatar from a user's pubkey.\nThis ensures consistent visual identity across all Nostr clients.\n\n## Motivation\n\nCurrently, Nostr clients generate avatar colors inconsistently. Some use platform-dependent hash\nfunctions, leading to the same pubkey displaying different colors on different clients. Others\nuse varying algorithms or color palettes, fragmenting the user experience.\n\nStandardizing avatar color derivation:\n- Ensures **consistent identity** across clients\n- Provides **predictable, reproducible** colors\n- Allows clients to display avatars before fetching metadata\n\n## Algorithm\n\n### Step 1: Derive an Index\n\nGiven a 64-character lowercase hex pubkey:\n\n1. Extract the **6 characters starting at index 29** (the middle of the pubkey)\n2. Parse this substring as a base-16 (hex) integer\n3. Compute the index as `parsed_value MODULO palette_length`\n\n### Step 2: Select a Color\n\nUse the derived index to select a color from a **standardized palette** of harmonious colors.\n\n### Reference Palette\n\nThe following 20-color palette is designed to provide visually distinct, accessible colors that\nwork well on both light and dark backgrounds. Each color has a predefined text color chosen for\noptimal contrast:\n\n| Index | Hex       | Preview          | Text Color |\n|-------|-----------|------------------|------------|\n| 0     | `#7C3AED` | Purple (Nostr)   | `#FFFFFF`  |\n| 1     | `#6366F1` | Indigo           | `#FFFFFF`  |\n| 2     | `#3B82F6` | Blue             | `#FFFFFF`  |\n| 3     | `#0EA5E9` | Sky              | `#FFFFFF`  |\n| 4     | `#06B6D4` | Cyan             | `rgba(0,0,0,0.87)` |\n| 5     | `#14B8A6` | Teal             | `rgba(0,0,0,0.87)` |\n| 6     | `#10B981` | Emerald          | `rgba(0,0,0,0.87)` |\n| 7     | `#22C55E` | Green            | `rgba(0,0,0,0.87)` |\n| 8     | `#84CC16` | Lime             | `rgba(0,0,0,0.87)` |\n| 9     | `#EAB308` | Yellow           | `rgba(0,0,0,0.87)` |\n| 10    | `#F59E0B` | Amber            | `rgba(0,0,0,0.87)` |\n| 11    | `#F97316` | Orange           | `rgba(0,0,0,0.87)` |\n| 12    | `#EF4444` | Red              | `rgba(0,0,0,0.87)` |\n| 13    | `#EC4899` | Pink             | `rgba(0,0,0,0.87)` |\n| 14    | `#D946EF` | Fuchsia          | `rgba(0,0,0,0.87)` |\n| 15    | `#A855F7` | Violet           | `rgba(0,0,0,0.87)` |\n| 16    | `#8B5CF6` | Light Purple     | `#FFFFFF`  |\n| 17    | `#6366F1` | Periwinkle       | `#FFFFFF`  |\n| 18    | `#06B6D4` | Aqua             | `rgba(0,0,0,0.87)` |\n| 19    | `#14B8A6` | Mint             | `rgba(0,0,0,0.87)` |\n\n> **Note**: These colors are derived from the Tailwind CSS palette. Text colors are chosen to\n> ensure a contrast ratio of at least 4.5:1 (WCAG AA).\n\n## Example\n\nGiven:\n- Pubkey: `a1b2c3d4e5f678901234567890abcde7af92ab0c1d2e3f4a5b6c7d8e9f0a1b2c3d`\n- Palette: 20 colors (as defined above)\n\n1. Extract chars at index 29-34: `7af92a`\n2. Parse as hex: `0x7AF92A` = 8059178\n3. Compute modulo: `8059178 % 20` = 18\n4. Select palette color at index 18: `#06B6D4` (Aqua)\n\n## Implementation Notes\n\n### Initials Display\n\nWhen no profile picture is available, clients should display a **single initial** on the colored\nbackground. The initial should be derived from:\n1. `display_name` field in metadata — the human-readable name the user chose to display\n2. `name` field in metadata — the short identifier\n3. `nip05` field in metadata — the internet identifier (local part, before the `@`. If it starts with `_@` or `@`, use the first letter of the domain instead)\n4. Hex character at index 28 of the pubkey, mapped to a letter (fallback)\n\nFor case (4), the character at index 28 of the pubkey (hex `0-9`, `a-f`, values 0-15) should be\nmapped to a letter `A-P` (0 → `A`, 1 → `B`, ... `a` → `K`, ... `f` → `P`). This ensures\nthe fallback is always a letter and never a digit. Index 28 is chosen because it lies in the\nmiddle of the pubkey, which is not affected by vanity mining.\n\nOnly the **first character** of the selected field should be displayed, **always uppercase** for\nconsistency across clients. This ensures consistent proportions and legibility regardless of\navatar size. The initial should be centered within the avatar circle.\n\n### Text Color\n\nThe text color is **predefined for each palette color** (see table above). No runtime luminance\ncalculation is needed — clients should simply use the text color associated with the selected\npalette index.\n\n### Profile Pictures\n\nWhen a `picture` URL is available in metadata, it should be displayed instead of the\ncolored avatar. The derived color may be used as a placeholder while loading or as a fallback\nif the image fails to load.\n\n## Rationale\n\n### Why the middle characters?\n\nUsing characters from the middle of the pubkey (indices 28-34) ensures fair distribution because:\n\n1. **Vanity mining**: Users commonly mine keys to have specific prefixes (e.g., `000abc...`) or\n   suffixes (e.g., `...000`). If the beginning or end were used, many vanity users would share\n   the same avatar color.\n2. **Nobody mines the middle**: Vanity mining targets the beginning and end of pubkeys because\n   those are what humans see (e.g., in `npub1...`). The middle is untouched in practice.\n\n### Why a fixed palette?\n\nRandom hex-to-RGB conversion can produce:\n- Very dark or very light colors that are hard to read\n- Muddy, unappealing colors\n- Inconsistent visual experience\n\nA curated palette ensures:\n- Colors are always visually distinct and pleasant\n- Consistent contrast for text overlays\n- Alignment with modern UI design standards\n\n### Why 20 colors?\n\n20 provides enough variety to distinguish users while keeping the palette manageable.\nThe modulo operation distributes users evenly across the palette.","sig":"1f326135493a8f30cc941450d6c9a34a95bde2431661b25b7cb98cadf72f8204f633bf62087fe6a773cc3ce47dc5bc4afb58e16e19528c3e995043adbd087472"}