Skip to content

Instantly share code, notes, and snippets.

@AlpinDale
Created August 13, 2025 07:31
Show Gist options
  • Select an option

  • Save AlpinDale/f21dbac4606cff9f23756a5addfe39a5 to your computer and use it in GitHub Desktop.

Select an option

Save AlpinDale/f21dbac4606cff9f23756a5addfe39a5 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>MNIST</title>
<style>
:root { --bg:#0f1116; --fg:#e6e6e6; --muted:#a3a3a3; --panel:#1b1f2a; --border:#333; }
html, body { height: 100%; }
body { margin: 0; font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial; background: var(--bg); color: var(--fg); }
.container { max-width: 1100px; margin: 0 auto; padding: 16px; }
h1 { font-size: 22px; margin: 8px 0 16px; }
.wrap { display: grid; grid-template-columns: 360px 1fr; gap: 24px; align-items: start; }
.card { background: var(--bg); border: 1px solid var(--border); border-radius: 12px; padding: 16px; }
.row { display: flex; gap: 12px; align-items: center; margin: 8px 0; flex-wrap: wrap; }
#canvas { background: #000; border-radius: 8px; box-shadow: inset 0 0 0 1px var(--border); touch-action: none; }
button { padding: 8px 12px; border-radius: 8px; border: 1px solid var(--border); background: var(--panel); color: var(--fg); cursor: pointer; }
button:active { transform: translateY(1px); }
input[type=range] { width: 160px; }
.bar { height: 14px; background: linear-gradient(90deg, #6ee7b7, #3b82f6); border-radius: 7px; }
.bar-wrap { background: var(--panel); border-radius: 7px; height: 14px; width: 100%; }
.prob-row { display: grid; grid-template-columns: 20px 1fr 44px; gap: 8px; align-items: center; margin: 6px 0; }
.muted { color: var(--muted); font-size: 12px; }
.pred { font-size: 42px; font-weight: 700; }
@media (max-width: 900px){ .wrap { grid-template-columns: 1fr; } }
</style>
<script>
const ortScript = document.createElement('script');
ortScript.src = 'https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.min.js';
document.head.appendChild(ortScript);
</script>
</head>
<body>
<div class="container">
<h1>MNIST</h1>
<div class="wrap">
<div class="card">
<canvas id="canvas" width="320" height="320"></canvas>
<div class="row">
<button id="clearBtn">🔄 Clear</button>
<button id="predictBtn">🔮 Predict</button>
</div>
<div class="row">
<label>Brush</label>
<input id="brush" type="range" min="5" max="40" value="22" />
<label><input id="auto" type="checkbox" checked /> Auto predict</label>
</div>
<div class="muted">Tip: Draw a large white digit on the black canvas.</div>
</div>
<div class="card">
<h3 style="margin-top:0">Prediction</h3>
<div id="pred" class="pred">–</div>
<div id="probs" style="margin-top: 12px"></div>
<h3>Processed 28×28</h3>
<canvas id="preview" width="160" height="160" style="background:#000;border-radius:8px;box-shadow:inset 0 0 0 1px var(--border)"></canvas>
</div>
</div>
</div>
<script>
const modelBase64 = `CAMSBENOVEsaBTIuNS4xIgdhaS5jbnRrKAE6ss4BCmIKDFBhcmFtZXRlcjE5MwobUGFyYW1ldGVyMTkzX3Jlc2hhcGUxX3NoYXBlEhVQYXJhbWV0ZXIxOTNfcmVzaGFwZTEaEVRpbWVzMjEyX3Jlc2hhcGUxIgdSZXNoYXBlMgA6AAqrAQoGSW5wdXQzCgpQYXJhbWV0ZXI1EhZDb252b2x1dGlvbjI4X091dHB1dF8wGg1Db252b2x1dGlvbjI4IgRDb252KhUKDGtlcm5lbF9zaGFwZUAFQAWgAQcqEAoHc3RyaWRlc0ABQAGgAQcqGQoIYXV0b19wYWQiClNBTUVfVVBQRVKgAQMqDAoFZ3JvdXAYAaABAioSCglkaWxhdGlvbnNAAUABoAEHMgA6AApGChZDb252b2x1dGlvbjI4X091dHB1dF8wCgpQYXJhbWV0ZXI2Eg9QbHVzMzBfT3V0cHV0XzAaBlBsdXMzMCIDQWRkMgA6AAo0Cg9QbHVzMzBfT3V0cHV0XzASD1JlTFUzMl9PdXRwdXRfMBoGUmVMVTMyIgRSZWx1MgA6AAqQAQoPUmVMVTMyX091dHB1dF8wEhJQb29saW5nNjZfT3V0cHV0XzAaCVBvb2xpbmc2NiIHTWF4UG9vbCoVCgxrZXJuZWxfc2hhcGVAAkACoAEHKhAKB3N0cmlkZXNAAkACoAEHKhEKBHBhZHNAAEAAQABAAKABByoVCghhdXRvX3BhZCIGTk9UU0VUoAEDMgA6AAq6AQoSUG9vbGluZzY2X091dHB1dF8wCgtQYXJhbWV0ZXI4NxIXQ29udm9sdXRpb24xMTBfT3V0cHV0XzAaDkNvbnZvbHV0aW9uMTEwIgRDb252KhUKDGtlcm5lbF9zaGFwZUAFQAWgAQcqEAoHc3RyaWRlc0ABQAGgAQcqGQoIYXV0b19wYWQiClNBTUVfVVBQRVKgAQMqDAoFZ3JvdXAYAaABAioSCglkaWxhdGlvbnNAAUABoAEHMgA6AApKChdDb252b2x1dGlvbjExMF9PdXRwdXRfMAoLUGFyYW1ldGVyODgSEFBsdXMxMTJfT3V0cHV0XzAaB1BsdXMxMTIiA0FkZDIAOgAKNwoQUGx1czExMl9PdXRwdXRfMBIQUmVMVTExNF9PdXRwdXRfMBoHUmVMVTExNCIEUmVsdTIAOgAK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`;
let session = null;
async function loadModel() {
await new Promise((resolve) => {
if (window.ort) return resolve();
ortScript.addEventListener('load', resolve, { once: true });
});
const binary = atob(modelBase64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
session = await ort.InferenceSession.create(bytes.buffer, { executionProviders: ['wasm'] });
}
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const preview = document.getElementById('preview');
const pctx = preview.getContext('2d');
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.height);
let drawing = false;
let brush = 22;
const white = '#fff';
function startDraw(x, y) { drawing = true; ctx.beginPath(); ctx.moveTo(x, y); }
function drawTo(x, y) { if (!drawing) return; ctx.lineTo(x, y); ctx.strokeStyle = white; ctx.lineWidth = brush; ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.stroke(); }
function endDraw() { drawing = false; ctx.closePath(); if (document.getElementById('auto').checked) predict(); }
function getXY(evt) {
const rect = canvas.getBoundingClientRect();
const clientX = evt.touches ? evt.touches[0].clientX : evt.clientX;
const clientY = evt.touches ? evt.touches[0].clientY : evt.clientY;
return [clientX - rect.left, clientY - rect.top];
}
canvas.addEventListener('mousedown', e => startDraw(...getXY(e)));
canvas.addEventListener('mousemove', e => drawTo(...getXY(e)));
window.addEventListener('mouseup', endDraw);
canvas.addEventListener('touchstart', e => { e.preventDefault(); startDraw(...getXY(e)); });
canvas.addEventListener('touchmove', e => { e.preventDefault(); drawTo(...getXY(e)); });
canvas.addEventListener('touchend', e => { e.preventDefault(); endDraw(); });
document.getElementById('brush').addEventListener('input', (e) => brush = parseInt(e.target.value, 10));
document.getElementById('clearBtn').addEventListener('click', () => {
ctx.fillStyle = '#000'; ctx.fillRect(0, 0, canvas.width, canvas.height);
pctx.fillStyle = '#000'; pctx.fillRect(0, 0, preview.width, preview.height);
document.getElementById('pred').textContent = '–';
document.getElementById('probs').innerHTML = '';
});
document.getElementById('predictBtn').addEventListener('click', () => predict());
function toGrayscale(data) {
const gray = new Float32Array(data.length / 4);
for (let i = 0, j = 0; i < data.length; i += 4, j++) {
const r = data[i], g = data[i+1], b = data[i+2];
gray[j] = (0.299*r + 0.587*g + 0.114*b);
}
return gray;
}
function findBBox(gray, w, h, thr=10) {
let xMin=w, yMin=h, xMax=-1, yMax=-1; let any=false;
for (let y=0; y<h; y++) {
for (let x=0; x<w; x++) {
const v = gray[y*w + x];
if (v > thr) { any = true; if (x < xMin) xMin = x; if (x > xMax) xMax = x; if (y < yMin) yMin = y; if (y > yMax) yMax = y; }
}
}
if (!any) return null;
return [xMin, yMin, xMax+1, yMax+1];
}
function preprocess() {
const w = canvas.width, h = canvas.height;
const img = ctx.getImageData(0, 0, w, h);
const gray = toGrayscale(img.data);
const bbox = findBBox(gray, w, h, 10);
if (!bbox) return new Float32Array(28*28);
const [x0, y0, x1, y1] = bbox;
const cw = x1 - x0, ch = y1 - y0;
const tmp = document.createElement('canvas');
tmp.width = cw; tmp.height = ch; const tctx = tmp.getContext('2d');
tctx.putImageData(ctx.getImageData(x0, y0, cw, ch), 0, 0);
const scale = 20 / Math.max(cw, ch);
const nw = Math.max(1, Math.round(cw * scale));
const nh = Math.max(1, Math.round(ch * scale));
const scaled = document.createElement('canvas');
scaled.width = nw; scaled.height = nh; const sctx = scaled.getContext('2d');
sctx.imageSmoothingEnabled = true;
sctx.drawImage(tmp, 0, 0, nw, nh);
const out = document.createElement('canvas');
out.width = 28; out.height = 28; const octx = out.getContext('2d');
octx.fillStyle = '#000'; octx.fillRect(0, 0, 28, 28);
const left = Math.floor((28 - nw) / 2); const top = Math.floor((28 - nh) / 2);
octx.drawImage(scaled, left, top);
pctx.imageSmoothingEnabled = false;
pctx.drawImage(out, 0, 0, 160, 160);
const oimg = octx.getImageData(0, 0, 28, 28);
const og = toGrayscale(oimg.data);
const arr = new Float32Array(28*28);
for (let i=0; i<og.length; i++) arr[i] = og[i] / 255.0;
return arr;
}
async function predict() {
if (!session) await loadModel();
const vec = preprocess();
if (!vec) return;
const input = new ort.Tensor('float32', vec, [1, 1, 28, 28]);
const feeds = {}; feeds[session.inputNames[0]] = input;
const outputMap = await session.run(feeds);
const outName = session.outputNames[0];
const logits = outputMap[outName].data;
let max = -1e9; for (let v of logits) if (v>max) max=v;
const exps = logits.map(v => Math.exp(v - max));
const sum = exps.reduce((a,b)=>a+b,0);
const probs = exps.map(v => v/sum);
const pred = probs.indexOf(Math.max(...probs));
document.getElementById('pred').textContent = String(pred);
const probsEl = document.getElementById('probs');
probsEl.innerHTML = '';
for (let d=0; d<10; d++) {
const row = document.createElement('div'); row.className = 'prob-row';
const label = document.createElement('div'); label.textContent = String(d);
const barWrap = document.createElement('div'); barWrap.className = 'bar-wrap';
const bar = document.createElement('div'); bar.className = 'bar'; bar.style.width = (probs[d]*100).toFixed(1) + '%';
const val = document.createElement('div'); val.textContent = (probs[d]*100).toFixed(1) + '%'; val.style.textAlign = 'right';
barWrap.appendChild(bar); row.appendChild(label); row.appendChild(barWrap); row.appendChild(val);
probsEl.appendChild(row);
}
}
loadModel();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment