Ulam Spiral
Write 1 in the middle of a grid, then keep counting in a square spiral outward: 2 to its right, 3 above that, 4 and 5 to the left, and so on. Now light only the primes. They should look scattered, and mostly they do, but they also line up in diagonal streaks. This plate counts the spiral live, starting with cells big enough to read and zooming out until the whole stage is one field of primes. The coral diagonal is 4n² + 12n + 7, which is never a multiple of 2, 3 or 5.
About this piece
The count starts at 1 in the centre and spirals outward. While the cells are big you can read every number: primes are filled squares with the number cut out of them, other numbers are written in faint ink, and a thin line follows the order of the count. The cells shrink as the spiral grows, from at most 44 to 3 pixels, and the numbers and the path drop out when they no longer fit. The ring being counted right now lights its primes in the text ink, so you can see the front move; behind it they settle into cobalt, slightly deeper towards the rim. The count takes 16 seconds, the finished spiral is held for 5, and then it starts again.
How far it counts depends on the stage: as many square rings as fit at 3 pixels a cell. In a 1280×720 window that is 92 rings, a 185×185 square, so the count stops at 185² = 34,225, of which 3,656 (10.7%) are prime. The line along the bottom keeps that tally live. The line at the top names the coral diagonal, lists its latest values as the count reaches them and says how many of them are prime. With reduced motion switched on you get one still frame: the finished spiral.
How the spiral is numbered
Start at 1 and walk: right 1, up 1, left 2, down 2, right 3, up 3, and so on, writing the next number in every cell you step on. Each pair of legs is one longer than the last, so ring k (the square of side 2k + 1 around the centre) is finished at the number (2k + 1)². That is why the odd squares 9, 25, 49, 81, … sit in a line running from 1 to the bottom-right corner, and the even squares 4, 16, 36, 64, … in a line running up and to the left.
A second pattern falls out of the walk. Every step moves one cell, and changes both the count and x + y by one, so the odd numbers sit on one colour of a checkerboard and the even numbers on the other. Every prime but 2 is odd, so every prime but 2 sits on the odd colour. Along a diagonal, x + y changes by 0 or 2 per step, so each diagonal is either all odd or all even. Half of all diagonals can never hold a prime except 2, which is the first reason the picture looks streaky.
Why the diagonals appear
Walk out along any diagonal and every step crosses into the next ring, which is 8 cells longer than the one before. So the gaps between neighbours on a diagonal grow by 8 each step, and the numbers on it are given by a quadratic 4n² + bn + c. Some of those quadratics can never be divisible by small primes, while others are divisible by 3 or 5 on a fixed share of their values. A number that cannot be a multiple of 3 or 5 is much more likely to be prime than an ordinary odd number of the same size, so those diagonals come out bright.
Worked example, the coral diagonal. 4n² + 12n + 7 gives 7, 23, 47, 79, 119, 167, 223, …, on the cells running from 7 (just below and left of 1) to the bottom-right. It is odd for every n. Divided by 3 it always leaves the same remainder as n² + 1, which is 1 or 2, never 0. Divided by 5 it leaves only 2, 3 or 4. So 2, 3 and 5 never divide it. 7 does: 119 = 7 × 17 is the first composite on it, the ringed square on screen. For n = 0 to 99 (values up to 40,399) it is prime 42 times. Among all odd numbers from 7 to 40,399, about 21% are prime, so the coral diagonal is lit about twice as often.
The four rays that leave 1 itself show the contrast. Counted over n = 0 to 99, the same span as above:
| Ray from 1 | Quadratic | Starts | Primes in 100 | Never a multiple of (2, 3, 5, 7) |
|---|---|---|---|---|
| down-right | 4n²+4n+1 | 1, 9, 25, 49 | 0 | 2 |
| down-left | 4n²+2n+1 | 1, 7, 21, 43 | 25 | 2, 5 |
| up-right | 4n²−2n+1 | 1, 3, 13, 31 | 32 | 2, 5 |
| up-left | 4n²+1 | 1, 5, 17, 37 | 33 | 2, 3, 7 |
| coral, from 7 | 4n²+12n+7 | 7, 23, 47, 79 | 42 | 2, 3, 5 |
The down-right ray is the odd squares, (2n + 1)², so it has no primes at all and shows as a dark line. Each n = 0 row also counts 1, which is not prime. Most of the lines you see in the picture are short runs of this kind of bias rather than single perfect diagonals.
Where it comes from, and what is not known
Stanisław Ulam drew the spiral in 1963, doodling on a grid during a dull talk, and Martin Gardner made it famous in his Mathematical Games column in Scientific American in March 1964. Long before that, Euler had noticed that n² + n + 41 is prime for every n from 0 to 39. If you start the spiral at 41 instead of 1, those 40 primes fall on one diagonal.
What the picture suggests is still an open problem. Nobody has proved that any quadratic such as n² + 1 takes infinitely many prime values (that is Bunyakovsky’s conjecture, open since 1857). Hardy and Littlewood’s Conjecture F, from 1923, predicts how dense the primes on each such quadratic should be, and the counts match it well, but it is a conjecture, not a theorem. The spiral shows the bias; it does not explain it.
How it is computed
The plate walks the spiral leg by leg (it never uses a formula for a cell’s position) and tests every number up to the last by trial division by 2, 3 and then 6k ± 1. Both are done once per stage size, so a frame only redraws: how far the count has got is a pure function of the plate’s age, and the frame rate never changes what is shown. The math lives in one block of code, used by the gallery tile, the embed and a node module that the test suite loads. The suite walks the spiral to 10,000 and checks every cell against the closed-form position formula written separately in the test. It checks the prime test against a sieve of Eratosthenes for every number up to 1,000,000, and checks that every value of 4n² + 12n + 7 on screen lies on the line x + y = −2. It also checks the table above against the code. A planted run that marks the composite 119 as prime turns the suite red.
A 30-line version
The snippet below draws the finished spiral in the site’s palette, 3 pixels a number, with the coral diagonal, in 27 lines of HTML and plain JavaScript with no library. It is an Ulam spiral generator in its simplest form: walk, test, fill. It draws once and does not animate, so it needs no reduced-motion handling. The test suite runs it against a stub canvas and checks that it lights exactly the plate’s primes, in the plate’s cells. It leaves out the count, the zoom, the numbers, sharp drawing on high-density screens (it draws in CSS pixels) and the reaction to theme changes. Its plain trial division is fine up to a few hundred thousand numbers; past that, use a sieve.
Things worth changing: C = 1 shows the classic one-pixel look with far more rings. Starting the count at 41 instead of 1 (write n + 40 into isPrime) puts Euler’s 40 primes on one diagonal.
<canvas id="ulam" style="position:fixed; inset:0"></canvas>
<script>
const dark = matchMedia('(prefers-color-scheme: dark)').matches;
const [ground, ink, accent] = dark ? ['#0B0D12', '#96B4FF', '#FF7854']
: ['#E7E2D5', '#2848CD', '#BE441C']; // the site's palette
const cv = document.getElementById('ulam'), ctx = cv.getContext('2d');
const W = cv.width = innerWidth, H = cv.height = innerHeight;
const C = 3; // pixels per number
const K = Math.floor((Math.min(W, H) / C - 1) / 2); // rings that fit on screen
const N = (2 * K + 1) ** 2; // so the count stops at an odd square
function isPrime(n) { for (let d = 2; d * d <= n; d++) if (n % d === 0) return false; return n > 1; }
const diag = new Set(); // 4n² + 12n + 7: 7, 23, 47, 79, ...
for (let n = 0; 4 * n * n + 12 * n + 7 <= N; n++) diag.add(4 * n * n + 12 * n + 7);
ctx.fillStyle = ground; ctx.fillRect(0, 0, W, H);
let x = 0, y = 0, dx = 1, dy = 0, leg = 1, steps = 0, turns = 0;
for (let n = 1; n <= N; n++) {
if (isPrime(n)) {
ctx.fillStyle = diag.has(n) ? accent : ink;
ctx.fillRect(W / 2 + x * C - C / 2, H / 2 - y * C - C / 2, C, C); // y grows upward
}
x += dx; y += dy;
if (++steps === leg) { // end of a leg: turn left
steps = 0; [dx, dy] = [-dy, dx];
if (++turns % 2 === 0) leg++; // legs run 1, 1, 2, 2, 3, 3, ...
}
}
</script>
The plates it sits nearest
- Quantum Fibonacci also places numbered points one after another on a spiral, there at the golden angle, and patterns appear that nobody put in by hand.
- Hilbert Weave is another way to walk every cell of a square grid in one unbroken path.
- Sierpinski Chaos Game is another plate where a simple rule repeated thousands of times shows structure only once enough marks are down.
Honest limits
The streaks are a bias, not a law. No diagonal is all prime. Even the coral one is composite more often than not: 58 of its first 100 values are not prime.
The picture depends on where you start. Start at 41 or at 17 and different diagonals light up. The spiral layout makes quadratics visible as lines; it does not make the primes special.
The cells are 3 pixels at the end. That keeps the diagonals visible on a phone, but it means a 390×844 phone, full screen, counts to 13,689 rather than the hundreds of thousands a 1-pixel print would show. A 4K wallpaper counts further, up to 260 rings (521² = 271,441).
Curious how the loop and canvas fit together? Read how it works →
More from the gallery
- Plate 44 Pendulum Wave Fifteen pendulums tuned to 51 to 65 swings a minute drift into snakes, split into two rows at 30 s and line up again at 60 s.
- Plate 01 Quantum Fibonacci Golden-angle phyllotaxis blooming from the seed outward.
- Plate 02 Bitcoin Matrix A quiet rain of ₿ and hex sliding down the glass.
- Plate 03 Cosmic Circles Soft orbs drifting through slow orbital rounds.
- Plate 04 Spiral Waves Archimedean arms turning, so the bands seem to stream inward.
- Plate 05 Particle Burst A continuous bloom of particles from the core.