A WebGL toy for exploring the modular multiplication pattern f(X, Y) = (X·Y + step) mod n.
It visualizes the pattern from a 2015 Math Stack Exchange question — the modular multiplication table rendered as colors per pixel. The visible bands trace the hyperbolae X·Y = k·n for integer k; step shifts the color cycle to animate them. The same hyperbolic structure shows up at every value of n — bigger n just means a bigger tile with more bands resolved inside it.
Open index.html in a browser, or serve the directory:
python3 -m http.server
No build step, no dependencies.
| Drag | Pan |
| Wheel | Zoom around the cursor |
| Double-click | 2× zoom at click point |
| Shift + double-click | ½× zoom at click point |
n input |
Set modulus directly |
| Space | Pause / resume animation |
| R | Reset view |
| D | Toggle debug overlay (red tile boundary + cursor crosshair + cursor readout) |
| Palette dropdown | Greyscale, binary, triangle, sine, RGB bands, rainbow |
| Speed slider | Animation speed (log scale, default 1×) |
The pattern is periodic with period n in both X and Y, so changing n renders a different-sized tile of the same modular-multiplication structure. The canvas may show multiple tiles side-by-side when n is smaller than the window.
"Zoom by α around cursor (cx, cy)" means: the tile grows from n × n pixels to (α·n) × (α·n) pixels, and the cursor stays at the same proportional spot inside whichever tile it's in. Concretely:
n ← α · n
tx ← cx · (α − 1) + α · tx
ty ← cy · (α − 1) + α · ty
The pattern formula in the shader is f(X, Y) = ((X + tx)(Y + ty) + step) mod n at canvas pixel (X, Y).
Press D to toggle the debug overlay, which draws a red square around one tile (the one whose intrinsic origin sits at canvas pixel (-tx, -ty)) and shows the cursor's tile-relative position in the readout. Across any zoom or pan, the tile-relative position should stay constant — that's the invariant that defines "zoom around the cursor" here.
index.html— page layout, controls, styles.index.js— shader, state, input handling, render loop.CLAUDE.md— implementation notes for Claude Code / contributors.