~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
50 lines · 1.6 KB Raw History
// A stand-in avatar for an identity with no profile picture.
//
// The pattern is drawn from the DID, so the same identity shows the same
// picture on every page and every visit, with nothing stored anywhere.

/**
 * 32-bit FNV-1a.
 * @param {string} text
 */
function hash(text) {
  let h = 0x811c9dc5;
  for (const ch of text) {
    h ^= /** @type {number} */ (ch.codePointAt(0));
    h = Math.imul(h, 0x01000193) >>> 0;
  }
  return h >>> 0;
}

/**
 * A 5 by 5 pattern mirrored around its middle column, in a hue the key
 * picks, as an SVG data URI.
 * @param {string} [key] - a DID, or any stable name for the identity
 * @returns {string}
 */
export function identicon(key) {
  const seed = hash(String(key || '?'));
  const hue = seed % 360;
  const cells = [];
  // The low 15 bits paint the left three columns; the mirror fills the rest.
  for (let col = 0; col < 3; col += 1) {
    for (let row = 0; row < 5; row += 1) {
      if ((seed >> (col * 5 + row)) & 1) cells.push([col, row]);
    }
  }
  if (cells.length === 0) cells.push([2, 2]);

  const fill = `hsl(${hue} 50% 45%)`;
  const rects = cells
    .flatMap(([col, row]) => {
      const rect = (/** @type {number} */ x) =>
        `<rect x="${x}" y="${row}" width="1" height="1"/>`;
      return col < 2 ? [rect(col), rect(4 - col)] : [rect(col)];
    })
    .join('');
  const svg =
    `<svg xmlns="http://www.w3.org/2000/svg" viewBox="-1 -1 7 7">` +
    `<rect x="-1" y="-1" width="7" height="7" fill="hsl(${hue} 45% 92%)"/>` +
    `<g fill="${fill}">${rects}</g></svg>`;
  return `data:image/svg+xml,${encodeURIComponent(svg)}`;
}