pubkey.ts raw

   1  /**
   2   * UI utilities for pubkey visualization.
   3   *
   4   * For pubkey validation, formatting, and conversion, use the domain Pubkey class:
   5   *   import { Pubkey } from '@/domain'
   6   *   - Pubkey.isValidHex(hex)
   7   *   - Pubkey.tryFromString(input)?.hex
   8   *   - Pubkey.tryFromString(input)?.npub
   9   *   - Pubkey.tryFromString(input)?.formatNpub(length)
  10   */
  11  
  12  import { LRUCache } from 'lru-cache'
  13  
  14  const pubkeyImageCache = new LRUCache<string, string>({ max: 1000 })
  15  
  16  /**
  17   * Generate a unique SVG image based on a pubkey.
  18   * Uses the pubkey bytes to deterministically create a colorful gradient pattern.
  19   */
  20  export function generateImageByPubkey(pubkey: string): string {
  21    if (pubkeyImageCache.has(pubkey)) {
  22      return pubkeyImageCache.get(pubkey)!
  23    }
  24  
  25    const paddedPubkey = pubkey.padEnd(2, '0')
  26  
  27    // Split into 3 parts for colors and the rest for control points
  28    const colors: string[] = []
  29    const controlPoints: string[] = []
  30    for (let i = 0; i < 11; i++) {
  31      const part = paddedPubkey.slice(i * 6, (i + 1) * 6)
  32      if (i < 3) {
  33        colors.push(`#${part}`)
  34      } else {
  35        controlPoints.push(part)
  36      }
  37    }
  38  
  39    // Generate SVG with multiple radial gradients
  40    const gradients = controlPoints
  41      .map((point, index) => {
  42        const cx = parseInt(point.slice(0, 2), 16) % 100
  43        const cy = parseInt(point.slice(2, 4), 16) % 100
  44        const r = (parseInt(point.slice(4, 6), 16) % 35) + 30
  45        const c = colors[index % (colors.length - 1)]
  46  
  47        return `
  48          <radialGradient id="grad${index}-${pubkey}" cx="${cx}%" cy="${cy}%" r="${r}%">
  49            <stop offset="0%" style="stop-color:${c};stop-opacity:1" />
  50            <stop offset="100%" style="stop-color:${c};stop-opacity:0" />
  51          </radialGradient>
  52          <rect width="100%" height="100%" fill="url(#grad${index}-${pubkey})" />
  53        `
  54      })
  55      .join('')
  56  
  57    const image = `
  58      <svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
  59        <rect width="100%" height="100%" fill="${colors[2]}" fill-opacity="0.3" />
  60        ${gradients}
  61      </svg>
  62    `
  63    const imageData = `data:image/svg+xml;base64,${btoa(image)}`
  64  
  65    pubkeyImageCache.set(pubkey, imageData)
  66  
  67    return imageData
  68  }
  69