// 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) => ``; return col < 2 ? [rect(col), rect(4 - col)] : [rect(col)]; }) .join(''); const svg = `` + `` + `${rects}`; return `data:image/svg+xml,${encodeURIComponent(svg)}`; }