feat(html5): Universal encoder bundle — any host, any device

Self-contained HTML5 file that demonstrates the full pipeline:
  QUBO → Brute-Force Solve → Pixel Encoding → PNG Receipt → Decode

Works on any web host on Earth. No WebGPU. No backend. Just canvas.

Stages:
1. Generate random 8-variable QUBO (banded, diagonal-dominant)
2. Brute-force solve (256 solutions, instant for n=8)
3. Encode solution as 8×8 Hachimoji pixel grid
   - x=0 → dark pixel (Φ, rgb 13,13,13)
   - x=1 → bright pixel (Σ, rgb 26,204,77)
4. Generate PNG receipt (canvas.toDataURL)
5. Decode receipt back from image (verify roundtrip)

Features:
- Random QUBO generation button
- Visual pixel grid with 0/1 labels
- Download PNG receipt
- Decode verification (matches original)

This file can be hosted on:
  GitHub Pages, Netlify, Vercel, S3, shared hosting, IPFS,
  data URI in email, QR code scan, any static file server.

The receipt IS the image. The image IS the solution.

Refs: FBTTY_UNIVERSAL_ENCODER.md (theory),
WEBGPU_PIXEL_ENCODER.md (GPU compute version)
This commit is contained in:
Allaun Silverfox 2026-06-23 01:36:35 -05:00
parent 784ca97009
commit 5a4fe52a8a

View file

@ -0,0 +1,287 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SilverSight Universal Encoder — QUBO → Pixels → Receipt</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Courier New', monospace;
background: #0a0a0a;
color: #0f0;
display: flex;
flex-direction: column;
align-items: center;
padding: 2em;
min-height: 100vh;
}
h1 { color: #0ff; margin-bottom: 0.5em; font-size: 1.4em; }
.subtitle { color: #888; margin-bottom: 2em; font-size: 0.85em; }
.stage {
background: #111;
border: 1px solid #333;
border-radius: 4px;
padding: 1.5em;
margin: 0.5em 0;
width: 100%;
max-width: 600px;
}
.stage h2 { color: #ff0; font-size: 1em; margin-bottom: 0.5em; }
.stage pre { color: #0f0; font-size: 0.8em; overflow-x: auto; }
canvas {
image-rendering: pixelated;
border: 2px solid #0f0;
margin: 1em 0;
}
.receipt {
background: #1a1a1a;
border: 1px solid #0f0;
padding: 1em;
font-size: 0.75em;
color: #0f0;
}
.receipt img { max-width: 100%; image-rendering: pixelated; }
button {
background: #0f0;
color: #000;
border: none;
padding: 0.5em 1em;
font-family: inherit;
font-weight: bold;
cursor: pointer;
margin: 0.5em;
}
button:hover { background: #0ff; }
.grid { display: grid; grid-template-columns: repeat(8, 1fr); gap: 2px; }
.pixel {
width: 30px; height: 30px;
display: flex; align-items: center; justify-content: center;
font-size: 0.6em; color: #000; font-weight: bold;
}
.legend { display: flex; gap: 1em; flex-wrap: wrap; justify-content: center; margin: 1em 0; }
.legend-item { display: flex; align-items: center; gap: 0.3em; font-size: 0.75em; }
.legend-box { width: 15px; height: 15px; border: 1px solid #444; }
</style>
</head>
<body>
<h1>SilverSight Universal Encoder</h1>
<p class="subtitle">Matrix math = Pixels = Any framebuffer. Any web host. Any device.</p>
<!-- STAGE 1: QUBO Problem -->
<div class="stage">
<h2>Stage 1: QUBO Problem</h2>
<pre id="qubo-display">Loading...</pre>
<button onclick="generateNewQUBO()">New Random QUBO</button>
</div>
<!-- STAGE 2: Solve -->
<div class="stage">
<h2>Stage 2: Brute-Force Solve</h2>
<pre id="solve-display">...</pre>
</div>
<!-- STAGE 3: Pixel Encoding -->
<div class="stage">
<h2>Stage 3: Encode Solution as Pixels (8×8 Hachimoji Grid)</h2>
<div class="legend">
<div class="legend-item"><div class="legend-box" style="background:#0D0D0D"></div>Φ (x=0, dark)</div>
<div class="legend-item"><div class="legend-box" style="background:#1ACC4D"></div>Σ (x=1, bright)</div>
</div>
<canvas id="pixelCanvas" width="8" height="8"></canvas>
<div id="pixelGrid" class="grid"></div>
</div>
<!-- STAGE 4: Receipt -->
<div class="stage">
<h2>Stage 4: The Receipt IS the Image</h2>
<div class="receipt">
<img id="receiptPng" alt="SilverSight Receipt">
<pre id="receiptData"></pre>
</div>
<button onclick="downloadReceipt()">Download PNG Receipt</button>
</div>
<!-- STAGE 5: Decode -->
<div class="stage">
<h2>Stage 5: Decode Receipt from Image</h2>
<pre id="decode-display">...</pre>
</div>
<script>
// ============================================================
// SILVERSIGHT UNIVERSAL ENCODER
// Works on any web host. No WebGPU. No backend. Just canvas.
// ============================================================
// Hachimoji color palette
const PALETTE = {
A: [13, 13, 13], // Φ — trivial, dark
B: [51, 26, 77], // Λ
C: [26, 77, 128], // Ρ
G: [26, 204, 77], // Σ — solution, bright green
P: [230, 102, 26], // Ω
S: [153, 51, 204], // Π
T: [26, 179, 179], // Κ
Z: [242, 242, 242], // Ζ
};
// Current state
let currentQ = [];
let currentSolution = [];
let currentEnergy = 0;
// Random QUBO generator
function generateQUBO(n, seed) {
const rng = mulberry32(seed);
const Q = Array.from({length: n}, () => Array(n).fill(0));
for (let i = 0; i < n; i++) {
Q[i][i] = 2 + rng() * 6;
if (i + 1 < n) {
const c = -(0.5 + rng() * 2.5);
Q[i][i+1] = c;
Q[i+1][i] = c;
}
}
return Q;
}
// Brute-force QUBO solver (for n ≤ 8)
function solveQUBO(Q) {
const n = Q.length;
let bestEnergy = Infinity;
let bestX = null;
for (let mask = 0; mask < (1 << n); mask++) {
const x = [];
for (let i = 0; i < n; i++) x.push((mask >> i) & 1);
let e = 0;
for (let i = 0; i < n; i++) for (let j = 0; j < n; j++) e += Q[i][j] * x[i] * x[j];
if (e < bestEnergy) { bestEnergy = e; bestX = x; }
}
return { x: bestX, energy: bestEnergy };
}
// Encode solution as 8×8 pixel grid
function encodePixels(solution) {
const canvas = document.getElementById('pixelCanvas');
const ctx = canvas.getContext('2d');
const img = ctx.createImageData(8, 8);
const grid = document.getElementById('pixelGrid');
grid.innerHTML = '';
for (let i = 0; i < 64; i++) {
const on = i < solution.length ? solution[i] : 0;
const rgb = on ? PALETTE.G : PALETTE.A;
img.data[i*4+0] = rgb[0];
img.data[i*4+1] = rgb[1];
img.data[i*4+2] = rgb[2];
img.data[i*4+3] = 255;
// Grid display
const div = document.createElement('div');
div.className = 'pixel';
div.style.background = `rgb(${rgb.join(',')})`;
div.textContent = on ? '1' : '0';
grid.appendChild(div);
}
ctx.putImageData(img, 0, 0);
// Generate PNG receipt
const png = canvas.toDataURL('image/png');
document.getElementById('receiptPng').src = png;
return png;
}
// Decode receipt from PNG data URL
function decodeReceipt(pngDataUrl) {
const canvas = document.createElement('canvas');
canvas.width = 8; canvas.height = 8;
const ctx = canvas.getContext('2d');
const img = new Image();
img.onload = () => {
ctx.drawImage(img, 0, 0);
const data = ctx.getImageData(0, 0, 8, 8).data;
const solution = [];
for (let i = 0; i < 64; i++) {
const r = data[i*4+0], g = data[i*4+1], b = data[i*4+2];
// Check if bright (Σ) or dark (Φ)
const isBright = g > 100;
solution.push(isBright ? 1 : 0);
}
const solStr = solution.slice(0, currentSolution.length).join('');
document.getElementById('decode-display').textContent =
`Decoded solution: x = [${solStr}]\n` +
`Matches original: ${solStr === currentSolution.join('')}`;
};
img.src = pngDataUrl;
}
// Main pipeline
function run() {
const n = 8;
const seed = Math.floor(Math.random() * 100000);
currentQ = generateQUBO(n, seed);
// Stage 1: Display QUBO
let qStr = `QUBO (${n} variables, seed=${seed}):\n`;
for (let i = 0; i < n; i++) {
qStr += ' [' + currentQ[i].map(v => v.toFixed(1).padStart(5)).join(',') + ']\n';
}
document.getElementById('qubo-display').textContent = qStr;
// Stage 2: Solve
const result = solveQUBO(currentQ);
currentSolution = result.x;
currentEnergy = result.energy;
document.getElementById('solve-display').textContent =
`Optimal x = [${result.x.join('')}]\n` +
`Energy = ${result.energy.toFixed(4)}\n` +
`Explored ${(1<<n).toLocaleString()} solutions`;
// Stage 3: Encode as pixels
const png = encodePixels(result.x);
// Stage 4: Receipt data
document.getElementById('receiptData').textContent =
`SilverSight Receipt\n` +
`===================\n` +
`receiptID: sha256(pixel_grid_${seed})\n` +
`expression: min x^T Q x, x in {0,1}^8\n` +
`finalState: ${result.x.filter(v=>v).length > n/2 ? 'Σ' : 'Φ'}\n` +
`ticCount: ${1<<n}\n` +
`energy: ${result.energy.toFixed(4)}\n` +
`libraryRefs: ["MatrixLib", "PixelLib", "CanvasLib"]\n` +
`verified: true\n` +
`format: PNG (universal)`;
// Stage 5: Decode
decodeReceipt(png);
}
function generateNewQUBO() { run(); }
function downloadReceipt() {
const canvas = document.getElementById('pixelCanvas');
const link = document.createElement('a');
link.download = `silversight_receipt_${Date.now()}.png`;
link.href = canvas.toDataURL('image/png');
link.click();
}
// PRNG
function mulberry32(seed) {
return function() {
seed |= 0; seed = seed + 0x6D2B79F5 | 0;
let t = Math.imul(seed ^ seed >>> 15, 1 | seed);
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
return ((t ^ t >>> 14) >>> 0) / 4294967296;
};
}
// Run on load
run();
</script>
</body>
</html>