chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
// 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)}`;
}