From 9d44e0cb44522b9963716f335aab04527fcc8cf3 Mon Sep 17 00:00:00 2001 From: you Date: Thu, 19 Mar 2026 08:44:45 +0000 Subject: [PATCH] Add 1-byte hash usage matrix (16x16 heatmap) Rows = high nibble, columns = low nibble. Color intensity shows packet count (log scale). Hover for exact count. Placed above collision risk table in Repeater Hashes tab. --- public/analytics.js | 59 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/public/analytics.js b/public/analytics.js index 15b3d5ae..0f55c697 100644 --- a/public/analytics.js +++ b/public/analytics.js @@ -706,11 +706,18 @@ +
+

1-Byte Hash Usage Matrix

+

Each cell shows how many packets used that 1-byte hop prefix (row=high nibble, col=low nibble). Darker = more traffic.

+
+
+

1-Byte Collision Risk

Loading…
`; + renderHashMatrix(data.topHops); renderCollisions(data.topHops); } @@ -738,6 +745,58 @@ return svg; } + function renderHashMatrix(topHops) { + const el = document.getElementById('hashMatrix'); + const oneByteHops = topHops.filter(h => h.size === 1); + if (!oneByteHops.length) { el.innerHTML = '
No 1-byte hops
'; return; } + + // Build 16x16 grid: row = high nibble, col = low nibble + const grid = Array.from({ length: 16 }, () => Array(16).fill(0)); + let maxCount = 0; + for (const hop of oneByteHops) { + const byte = parseInt(hop.hex, 16); + if (isNaN(byte)) continue; + const hi = (byte >> 4) & 0xF; + const lo = byte & 0xF; + grid[hi][lo] = hop.count; + if (hop.count > maxCount) maxCount = hop.count; + } + + const nibbles = '0123456789ABCDEF'.split(''); + const cellSize = 36; + const headerSize = 24; + + let html = `
`; + // Header row + html += ``; + for (const n of nibbles) { + html += ``; + } + html += ''; + + for (let hi = 0; hi < 16; hi++) { + html += ``; + for (let lo = 0; lo < 16; lo++) { + const count = grid[hi][lo]; + const hex = nibbles[hi] + nibbles[lo]; + let bg = 'transparent'; + let color = 'var(--text-muted)'; + if (count > 0) { + const intensity = Math.log(count + 1) / Math.log(maxCount + 1); + const r = Math.round(34 + intensity * (239 - 34)); + const g = Math.round(197 - intensity * (197 - 68)); + const b = Math.round(94 - intensity * (94 - 68)); + bg = `rgb(${r},${g},${b})`; + color = intensity > 0.5 ? '#fff' : 'var(--text)'; + } + html += ``; + } + html += ''; + } + html += '
${n}
${nibbles[hi]}${count || ''}
'; + el.innerHTML = html; + } + async function renderCollisions(topHops) { const el = document.getElementById('collisionList'); const oneByteHops = topHops.filter(h => h.size === 1);