Eigenvalues of random matrices repel like charges, live, every frame.
A Gaussian matrix drifts by an Ornstein-Uhlenbeck process and all of its eigenvalues are recomputed every frame, with Householder tridiagonalization and implicit QL for the symmetric and complex Hermitian ensembles and Hessenberg reduction with Francis double-shift QR for the non-symmetric one. Born from the zero matrix, the Hermitian spectrum bursts open and settles into Wigner's semicircle as Dyson Brownian motion, its world lines repelling and never crossing, while the unfolded spacings converge on the Wigner surmise instead of the Poisson curve that uncorrelated levels follow. The real Ginibre ensemble lifts off the real line into Girko's circular law disk (an ellipse in the elliptic ensemble), keeping an excess of exactly real eigenvalues. A rank-one spike pulls a lone outlier out of the bulk once it passes the BBP threshold, at theta + 1/theta.
Try it. Press 1 to 4 for GOE, GUE, Poisson and Ginibre. Drag up or down to add a spike and pull an outlier eigenvalue out of the semicircle, or drag outside the disk to pull out a conjugate pair. Left and right arrows change the matrix size, up and down change tau in the elliptic ensemble, and Space restarts from the zero matrix.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build a live visualization of random matrix eigenvalues with JavaScript and the HTML canvas element. Put everything in a single index.html file with no libraries or build step, so I can open it directly in a browser.
Start simple:
- Make a canvas that fills the window, stays sharp on high-DPI screens (scale by devicePixelRatio), and resizes with the window. Paint it near black.
- Keep an N x N matrix G (N = 48) of Gaussian entries with variance 1/N, starting at zero. Every frame nudge it with an Ornstein-Uhlenbeck step: G = a G + sqrt(1 - a^2) * noise / sqrt(N), with a = exp(-h / 2) and a small h.
- Form the symmetric matrix H = (G + G^T) / sqrt(2) and compute all its eigenvalues yourself: the Jacobi rotation method is the easiest to write and fast enough at this size.
- Draw the spectrum over time: each frame, scroll the picture one pixel left and draw a short segment from each sorted eigenvalue's previous height to its new one at the right edge. Color each line by its index.
Once that works, make it beautiful:
- Next to the lines, keep a running histogram of eigenvalues and overlay Wigner's semicircle sqrt(4 - x^2) / (2 pi).
- Unfold the gaps with the semicircle's cumulative distribution so their mean is 1, histogram the gaps from the middle of the spectrum, and compare with the Wigner surmise (pi/2) s exp(-pi s^2 / 4) and with exp(-s).
- Add a key that replaces H with a diagonal matrix of independent values so the lines cross freely and the gaps follow exp(-s).
Explain the key ideas in short code comments. When you're done, tell me how to open it and suggest three directions I could take it next, such as a complex Hermitian version with s^2 level repulsion, non-symmetric matrices whose eigenvalues fill a disk, or a rank-one spike that pulls an outlier out of the bulk.