Skip to content

Instantly share code, notes, and snippets.

@bmorphism
Created January 8, 2026 15:06
Show Gist options
  • Select an option

  • Save bmorphism/b2e9017e88f77949bf1025b48177b79e to your computer and use it in GitHub Desktop.

Select an option

Save bmorphism/b2e9017e88f77949bf1025b48177b79e to your computer and use it in GitHub Desktop.
Gay-TOFU: Error-correcting codec demo
<!DOCTYPE html>
<html>
<head>
<title>Hamming Swarm Error-Correcting Codec</title>
<style>
body {
margin: 0;
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a2e 100%);
color: #e0e0e0;
font-family: 'SF Mono', 'Consolas', monospace;
padding: 20px;
}
.container { max-width: 1200px; margin: 0 auto; }
h1 {
color: #6CEC13;
text-align: center;
font-size: 2em;
margin-bottom: 10px;
}
.subtitle {
text-align: center;
color: #888;
margin-bottom: 30px;
font-size: 0.9em;
}
.panel {
background: rgba(0,0,0,0.6);
border: 1px solid #333;
border-radius: 8px;
padding: 20px;
margin: 20px 0;
}
.row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin: 20px 0;
}
textarea {
width: 100%;
min-height: 100px;
background: #1a1a1a;
color: #e0e0e0;
border: 1px solid #444;
border-radius: 4px;
padding: 10px;
font-family: 'SF Mono', monospace;
font-size: 14px;
resize: vertical;
}
button {
background: linear-gradient(135deg, #851BE4 0%, #37C0C8 100%);
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
font-weight: bold;
margin: 5px;
transition: transform 0.1s;
}
button:hover { transform: scale(1.05); }
button:active { transform: scale(0.95); }
.btn-danger {
background: linear-gradient(135deg, #ff4444 0%, #cc0000 100%);
}
.color-strip {
display: flex;
flex-wrap: wrap;
gap: 2px;
margin: 10px 0;
}
.color-cell {
width: 30px;
height: 30px;
border: 1px solid #333;
border-radius: 3px;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 12px;
cursor: pointer;
transition: transform 0.1s;
}
.color-cell:hover {
transform: scale(1.2);
z-index: 10;
border: 2px solid #6CEC13;
}
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin: 15px 0;
}
.stat-box {
background: rgba(255,255,255,0.05);
padding: 15px;
border-radius: 6px;
border: 1px solid #333;
}
.stat-label {
color: #888;
font-size: 11px;
text-transform: uppercase;
letter-spacing: 1px;
}
.stat-value {
font-size: 24px;
font-weight: bold;
color: #6CEC13;
margin-top: 5px;
}
.error-viz {
background: #1a1a1a;
padding: 15px;
border-radius: 6px;
margin: 10px 0;
font-family: monospace;
font-size: 13px;
}
.error { color: #ff4444; font-weight: bold; }
.corrected { color: #6CEC13; font-weight: bold; }
.unchanged { color: #888; }
label {
display: block;
color: #6CEC13;
margin: 10px 0 5px 0;
font-weight: bold;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 1px;
}
.slider-container {
margin: 15px 0;
}
input[type="range"] {
width: 100%;
height: 6px;
background: #333;
outline: none;
border-radius: 3px;
}
input[type="range"]::-webkit-slider-thumb {
appearance: none;
width: 18px;
height: 18px;
background: #6CEC13;
cursor: pointer;
border-radius: 50%;
}
.binary-display {
font-family: 'Courier New', monospace;
background: #0a0a0a;
padding: 10px;
border-radius: 4px;
font-size: 12px;
margin: 10px 0;
overflow-x: auto;
}
.bit {
display: inline-block;
margin: 0 2px;
padding: 2px 4px;
background: #1a1a1a;
border-radius: 2px;
}
.bit-flipped {
background: #ff4444;
color: white;
}
</style>
</head>
<body>
<div class="container">
<h1>🌈 Hamming Swarm Error-Correcting Codec</h1>
<div class="subtitle">
Bijective color encoding with automatic error detection and correction via Hamming distance
</div>
<!-- Encode Panel -->
<div class="panel">
<h2 style="color: #851BE4;">📤 Encode Message</h2>
<label>Plain Text Message</label>
<textarea id="plain-text" placeholder="Enter your message here... (A-Z only, spaces ignored)">HELLO WORLD</textarea>
<div class="slider-container">
<label>Encoding Seed: <span id="encode-seed-value">42</span></label>
<input type="range" id="encode-seed" min="1" max="999999" value="42" oninput="updateSeed('encode')">
</div>
<button onclick="encodeMessage()">🔒 Encode with Gay-TOFU Colors</button>
<div id="encoded-output"></div>
</div>
<!-- Corruption Panel -->
<div class="panel">
<h2 style="color: #37C0C8;">💥 Simulate Transmission Errors</h2>
<div class="slider-container">
<label>Error Rate: <span id="error-rate-value">10%</span></label>
<input type="range" id="error-rate" min="0" max="50" value="10" oninput="updateErrorRate()">
</div>
<button onclick="corruptMessage()">⚡ Introduce Random Bit Flips</button>
<button onclick="resetCorruption()" class="btn-danger">🔄 Reset Corruption</button>
<div id="corruption-viz"></div>
</div>
<!-- Decode Panel -->
<div class="panel">
<h2 style="color: #6CEC13;">📥 Decode & Error Correction</h2>
<button onclick="decodeMessage()">🔓 Decode with Error Correction</button>
<div id="decoded-output"></div>
</div>
<!-- Statistics -->
<div class="panel">
<h2 style="color: #6CEC13;">📊 Statistics</h2>
<div class="stats">
<div class="stat-box">
<div class="stat-label">Original Length</div>
<div class="stat-value" id="stat-orig-len">0</div>
</div>
<div class="stat-box">
<div class="stat-label">Bits Flipped</div>
<div class="stat-value" id="stat-flips">0</div>
</div>
<div class="stat-box">
<div class="stat-label">Errors Corrected</div>
<div class="stat-value" id="stat-corrected">0</div>
</div>
<div class="stat-box">
<div class="stat-label">Correction Rate</div>
<div class="stat-value" id="stat-rate">0%</div>
</div>
<div class="stat-box">
<div class="stat-label">GF(3) Trit Sum</div>
<div class="stat-value" id="stat-trit">0</div>
</div>
<div class="stat-box">
<div class="stat-label">Hamming Distance</div>
<div class="stat-value" id="stat-hamming">0</div>
</div>
</div>
</div>
</div>
<script>
// ═══════════════════════════════════════════════════════════════════════════════
// Gay-TOFU Color System
// ═══════════════════════════════════════════════════════════════════════════════
const PHI2 = 1.3247179572447460; // Plastic constant
function hslToRgb(h, s, l) {
const c = (1 - Math.abs(2 * l - 1)) * s;
const hp = h / 60;
const x = c * (1 - Math.abs((hp % 2) - 1));
let r1 = 0, g1 = 0, b1 = 0;
if (hp >= 0 && hp < 1) [r1, g1, b1] = [c, x, 0];
else if (hp >= 1 && hp < 2) [r1, g1, b1] = [x, c, 0];
else if (hp >= 2 && hp < 3) [r1, g1, b1] = [0, c, x];
else if (hp >= 3 && hp < 4) [r1, g1, b1] = [0, x, c];
else if (hp >= 4 && hp < 5) [r1, g1, b1] = [x, 0, c];
else if (hp >= 5 && hp < 6) [r1, g1, b1] = [c, 0, x];
const m = l - c / 2;
return [r1 + m, g1 + m, b1 + m];
}
function plasticColor(n, seed) {
const seedNorm = (seed % 1000000) / 1000000;
const h = (((seedNorm + n / PHI2) % 1.0) * 360);
const s = (((seedNorm + n / (PHI2 * PHI2)) % 1.0) * 0.5) + 0.5;
return hslToRgb(h, s, 0.55);
}
function rgbToHex(r, g, b) {
const toHex = x => Math.round(x * 255).toString(16).padStart(2, '0');
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}
function tritFromHue(hue) {
const sector = Math.floor(hue / 120) % 3;
return sector === 0 ? 1 : sector === 1 ? 0 : -1;
}
// ═══════════════════════════════════════════════════════════════════════════════
// Alphabet & Binary Encoding
// ═══════════════════════════════════════════════════════════════════════════════
const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ🌈'.split('');
function letterToIndex(letter) {
return ALPHABET.indexOf(letter.toUpperCase());
}
function indexToLetter(index) {
return ALPHABET[index];
}
function letterToBinary(letter) {
const index = letterToIndex(letter);
return index === -1 ? null : index.toString(2).padStart(5, '0');
}
function binaryToLetter(binary) {
const index = parseInt(binary, 2);
return index < ALPHABET.length ? ALPHABET[index] : null;
}
function hammingDistance(bin1, bin2) {
let distance = 0;
for (let i = 0; i < 5; i++) {
if (bin1[i] !== bin2[i]) distance++;
}
return distance;
}
// ═══════════════════════════════════════════════════════════════════════════════
// Encoding State
// ═══════════════════════════════════════════════════════════════════════════════
let encodedData = [];
let corruptedData = [];
let currentSeed = 42;
// ═══════════════════════════════════════════════════════════════════════════════
// UI Updates
// ═══════════════════════════════════════════════════════════════════════════════
function updateSeed(type) {
const value = document.getElementById(`${type}-seed`).value;
document.getElementById(`${type}-seed-value`).textContent = value;
currentSeed = parseInt(value);
}
function updateErrorRate() {
const value = document.getElementById('error-rate').value;
document.getElementById('error-rate-value').textContent = `${value}%`;
}
// ═══════════════════════════════════════════════════════════════════════════════
// Encoding
// ═══════════════════════════════════════════════════════════════════════════════
function encodeMessage() {
const text = document.getElementById('plain-text').value
.toUpperCase()
.replace(/[^A-Z]/g, '');
if (text.length === 0) {
alert('Please enter a message with A-Z letters');
return;
}
encodedData = [];
let tritSum = 0;
const letters = text.split('');
let html = '<label>Encoded Color Sequence</label>';
html += '<div class="color-strip">';
letters.forEach((letter, i) => {
const index = letterToIndex(letter);
const [r, g, b] = plasticColor(index + 1, currentSeed);
const color = rgbToHex(r, g, b);
const binary = letterToBinary(letter);
const h = (((currentSeed % 1000000) / 1000000 + (index + 1) / PHI2) % 1.0) * 360;
const trit = tritFromHue(h);
tritSum += trit;
encodedData.push({
letter,
index,
binary,
color,
trit
});
html += `<div class="color-cell" style="background: ${color}; color: ${getContrastColor(color)}"
title="${letter} = ${binary} (trit=${trit})">${letter}</div>`;
});
html += '</div>';
html += `<div class="binary-display">`;
encodedData.forEach(d => {
html += `<span class="bit">${d.binary}</span> `;
});
html += `</div>`;
document.getElementById('encoded-output').innerHTML = html;
// Update stats
document.getElementById('stat-orig-len').textContent = letters.length;
document.getElementById('stat-trit').textContent = `${tritSum} (mod 3 = ${((tritSum % 3) + 3) % 3})`;
// Reset corruption
corruptedData = [];
document.getElementById('corruption-viz').innerHTML = '';
document.getElementById('decoded-output').innerHTML = '';
}
function getContrastColor(hexColor) {
const r = parseInt(hexColor.slice(1, 3), 16);
const g = parseInt(hexColor.slice(3, 5), 16);
const b = parseInt(hexColor.slice(5, 7), 16);
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
return luminance > 0.5 ? '#000' : '#fff';
}
// ═══════════════════════════════════════════════════════════════════════════════
// Corruption
// ═══════════════════════════════════════════════════════════════════════════════
function corruptMessage() {
if (encodedData.length === 0) {
alert('Please encode a message first');
return;
}
const errorRate = parseInt(document.getElementById('error-rate').value) / 100;
corruptedData = JSON.parse(JSON.stringify(encodedData));
let totalFlips = 0;
corruptedData.forEach(item => {
const binaryArray = item.binary.split('');
item.flips = [];
for (let i = 0; i < 5; i++) {
if (Math.random() < errorRate) {
binaryArray[i] = binaryArray[i] === '0' ? '1' : '0';
item.flips.push(i);
totalFlips++;
}
}
item.corruptedBinary = binaryArray.join('');
item.corruptedLetter = binaryToLetter(item.corruptedBinary);
});
// Visualize corruption
let html = '<label>Corrupted Sequence (red = bit flips)</label>';
html += '<div class="error-viz">';
corruptedData.forEach((item, idx) => {
const orig = encodedData[idx].binary.split('');
const corr = item.corruptedBinary.split('');
html += `<div style="margin: 5px 0;">`;
html += `<b>${item.letter}</b> → <b class="${item.flips.length > 0 ? 'error' : 'unchanged'}">${item.corruptedLetter}</b>: `;
for (let i = 0; i < 5; i++) {
const className = orig[i] !== corr[i] ? 'bit-flipped' : '';
html += `<span class="bit ${className}">${corr[i]}</span>`;
}
if (item.flips.length > 0) {
html += ` <span class="error">(${item.flips.length} flips, d=${hammingDistance(item.binary, item.corruptedBinary)})</span>`;
}
html += `</div>`;
});
html += '</div>';
document.getElementById('corruption-viz').innerHTML = html;
document.getElementById('stat-flips').textContent = totalFlips;
}
function resetCorruption() {
corruptedData = [];
document.getElementById('corruption-viz').innerHTML = '';
document.getElementById('decoded-output').innerHTML = '';
document.getElementById('stat-flips').textContent = '0';
document.getElementById('stat-corrected').textContent = '0';
document.getElementById('stat-rate').textContent = '0%';
document.getElementById('stat-hamming').textContent = '0';
}
// ═══════════════════════════════════════════════════════════════════════════════
// Decoding with Error Correction
// ═══════════════════════════════════════════════════════════════════════════════
function decodeMessage() {
const dataToUse = corruptedData.length > 0 ? corruptedData : encodedData;
if (dataToUse.length === 0) {
alert('Please encode a message first');
return;
}
let correctedCount = 0;
let totalHamming = 0;
const results = [];
dataToUse.forEach((item, idx) => {
const binaryToCorrect = item.corruptedBinary || item.binary;
// Minimum distance decoding
let minDistance = Infinity;
let bestMatch = null;
ALPHABET.forEach(letter => {
const validBinary = letterToBinary(letter);
const dist = hammingDistance(binaryToCorrect, validBinary);
if (dist < minDistance) {
minDistance = dist;
bestMatch = letter;
}
});
const wasCorrupted = item.flips && item.flips.length > 0;
const wasCorrected = wasCorrupted && bestMatch === encodedData[idx].letter;
if (wasCorrected) correctedCount++;
if (wasCorrupted) totalHamming += minDistance;
results.push({
original: encodedData[idx].letter,
received: item.corruptedLetter || item.letter,
corrected: bestMatch,
wasCorrupted,
wasCorrected,
distance: minDistance
});
});
// Visualize decoding
let html = '<label>Decoded Message with Error Correction</label>';
html += '<div class="error-viz">';
results.forEach(r => {
html += `<div style="margin: 5px 0;">`;
if (r.wasCorrupted) {
html += `<b class="unchanged">${r.original}</b> → `;
html += `<b class="error">${r.received}</b> → `;
html += `<b class="${r.wasCorrected ? 'corrected' : 'error'}">${r.corrected}</b> `;
html += r.wasCorrected ?
`<span class="corrected">✓ CORRECTED (d=${r.distance})</span>` :
`<span class="error">✗ FAILED (d=${r.distance})</span>`;
} else {
html += `<b class="unchanged">${r.original}</b> → <b class="corrected">${r.corrected}</b> `;
html += `<span class="unchanged">✓ No errors</span>`;
}
html += `</div>`;
});
html += '</div>';
html += `<label>Final Decoded Text</label>`;
html += `<textarea readonly style="font-size: 18px; text-align: center; font-weight: bold;">${results.map(r => r.corrected).join('')}</textarea>`;
document.getElementById('decoded-output').innerHTML = html;
// Update stats
const corruptedCount = results.filter(r => r.wasCorrupted).length;
const correctionRate = corruptedCount > 0 ?
Math.round((correctedCount / corruptedCount) * 100) : 100;
document.getElementById('stat-corrected').textContent = `${correctedCount}/${corruptedCount}`;
document.getElementById('stat-rate').textContent = `${correctionRate}%`;
document.getElementById('stat-hamming').textContent =
corruptedCount > 0 ? (totalHamming / corruptedCount).toFixed(2) : '0';
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment