📄 src/web3/utils/hash.ts
D-OPEN SOVEREIGN
Documentation & Insights
Returns 4 coordinates inside a container.
- Deterministic for a given username
- Adds padding to avoid edges
- Optionally applies a jitter ring to spread points nicer1// Deterministic coordinates for 4 nodes based on a username
2export type Point = { x: number; y: number };
3
4function fnv1a32(input: string): number {
5 // FNV-1a 32-bit
6 let hash = 0x811c9dc5 >>> 0;
7 for (let i = 0; i < input.length; i++) {
8 hash ^= input.charCodeAt(i);
9 // multiply by FNV prime 16777619
10 hash = Math.imul(hash, 0x01000193) >>> 0;
11 }
12 return hash >>> 0;
13}
14
15function xorshift32(seed: number): () => number {
16 // returns a function producing uint32 values
17 let x = (seed || 0x9e3779b9) >>> 0;
18 return () => {
19 x ^= x << 13;
20 x >>>= 0;
21 x ^= x >>> 17;
22 x >>>= 0;
23 x ^= x << 5;
24 x >>>= 0;
25 return x >>> 0;
26 };
27}
28
29/**
30 * Returns 4 coordinates inside a container.
31 * - Deterministic for a given username
32 * - Adds padding to avoid edges
33 * - Optionally applies a jitter ring to spread points nicer
34 */
35export function hashUsernameToCoords(username: string, width: number, height: number, padding = 16): Point[] {
36 const base = fnv1a32(username);
37 const next = xorshift32(base);
38
39 const innerW = Math.max(0, width - padding * 2);
40 const innerH = Math.max(0, height - padding * 2);
41
42 const points: Point[] = [];
43 for (let i = 0; i < 4; i++) {
44 // produce two uint32, turn them into floats in [0,1)
45 const rx = next() / 0x1_0000_0000;
46 const ry = next() / 0x1_0000_0000;
47
48 // basic mapped coordinates
49 let x = padding + rx * innerW;
50 let y = padding + ry * innerH;
51
52 // small deterministic jitter to reduce overlaps (optional)
53 const angle = (next() % 360) * (Math.PI / 180);
54 const radius = 0.035 * Math.min(innerW, innerH); // ~3.5% of min dimension
55 x = Math.min(width - padding, Math.max(padding, x + Math.cos(angle) * radius));
56 y = Math.min(height - padding, Math.max(padding, y + Math.sin(angle) * radius));
57
58 points.push({ x, y });
59 }
60 return points;
61}
62