MNIST digit recognizer

I wrote this network by hand: forward propagation, backpropagation, cross-entropy loss, and mini-batch gradient descent, all as raw matrix math — no autograd, no ML framework. It trains to about 98% accuracy on MNIST, and the exact same Rust code that trains it also runs inference here, compiled to WebAssembly so it executes locally in this browser tab. Draw a digit below.

Draw a digit

Model input

What the network receives after being rescaled and shifted to a center of mass at (14,14) — the same preprocessing MNIST itself was built with.

Prediction

draw something

Confidence over time

Start drawing to see probabilities update.

How it works

The network is small: 784 pixel inputs, one 128-unit hidden layer with ReLU, a 10-unit softmax output. I built it three times — first in Python/NumPy to get the calculus right, then from scratch in Rust using nothing but ndarray for matrix operations (forward pass, backprop, mini-batch SGD), and finally compiled that same Rust code to WebAssembly via wasm-bindgen. The trained weights are embedded directly in the .wasm binary, so what's predicting your digit right now is the literal Rust forward pass — no server, no Python, no framework — running client-side.