Spiral Waves
Four Archimedean arms turning in place, so the bands between them seem to stream inward.
About this piece
Four thin spiral arms leave the middle of the frame, two in cobalt and two in coral, and the whole set turns slowly in place. Nothing else is drawn. Each arm is one stroked line of 90 straight segments, and every frame is wiped and redrawn from a formula, so there is no trail, no fading and no accumulated history: what you see at any instant is the complete picture.
The curve is the Archimedean spiral, the one Archimedes studied in his treatise On Spirals in the 3rd century BC. A point moves out along a line at a steady speed while the line itself turns at a steady speed, so the distance from the centre grows in exact proportion to the angle turned. In polar coordinates that is
r = b (θ − φ)
where θ is the direction you are looking in, r is how far out the arm is in that direction, φ is the direction the arm leaves the centre in, and b sets how loosely it winds. Its defining property is that a ray from the centre crosses successive turns of one arm at a constant spacing, 2πb. That is why it is also called the arithmetic spiral: the crossings go up like 1, 2, 3, 4, not like 1, 2, 4, 8.
This plate’s numbers
Every arm sweeps 3.4π radians, which is 1.7 turns, and ends at 0.44 of the frame’s short edge, so the outer tips never touch the border. Putting those two together gives b = 0.44 × short edge ÷ (3.4π), about 4.1% of the short edge per radian. One arm alone would leave a gap of 2πb, about 26% of the short edge, between its own turns.
The four arms are a quarter-turn apart (their φ values differ by π/2), so they split that gap into four equal parts. Along any ray from the centre, neighbouring arms are always bπ/2 = 0.44 ÷ 6.8 of the short edge apart, which is about 6.5%. On a stage 500 pixels tall that is 32 pixels of bare paper between every pair of strokes. The spacing is the same at every radius and at every moment, so the arms never cross or touch: an Archimedean spiral and a rotated copy of itself are nested curves, not intersecting ones. The even, untouched bands between the strokes are the whole design.
Why the bands seem to stream inward
The figure only ever rotates. Each arm’s starting direction is φ = 0.4t + a quarter-turn per arm, and t only grows. On a canvas the y axis points down, so a growing angle turns clockwise on screen, and the arms themselves wind clockwise as they go outward. Yet what the eye reports is not turning but flow: the bands seem to stream inward, sinking into the centre while new ones appear at the rim.
The formula says why, in one line. Turn the spiral by an extra angle α and every arm becomes r = b(θ − φ − α) = b(θ − φ) − bα. In every direction, every arm is now exactly bα closer to the centre than before. For an Archimedean spiral, rotating it and sliding every arm radially are the same picture, and your visual system, which has no way to tell them apart along most of the length, takes the simpler-looking reading of steady radial motion. It is the same trick as a barber’s pole, where a helix turning about its axis is seen as stripes climbing it.
The speed follows from the code. The phase grows by 0.4 radians per unit of animation time, so the arms move inward at 0.4b, about 1.6% of the short edge, per unit. One arm-spacing (bπ/2) therefore passes any point every π ÷ 0.8 ≈ 3.93 time units. The animation adds 0.03 time units per frame it draws, which makes that 131 frames: about 2.2 seconds at 60 frames a second. Because the four arms are identical in shape, the figure looks the same again every 2.2 seconds; because they alternate in colour, the cobalt and coral bands trade places each time, and the coloured pattern repeats every 4.4 seconds. A full revolution takes about 8.7 seconds.
Archimedean, not logarithmic
The spiral usually cited for nautilus shells and the arms of spiral galaxies is a different curve, the logarithmic spiral. On that one the distances between successive turnings grow in a geometric progression, so every turn is the same shape as the last, only bigger; on the Archimedean spiral those distances are constant. Even there the match is loose: the nautilus is described as only approximately logarithmic, and real galaxy arms change their pitch angle with distance from the centre, which a true logarithmic spiral does not. This plate draws neither of those things. Its arms are evenly spaced, like the groove on a record or a rolled-up carpet seen end on, and that even spacing is exactly what makes the streaming illusion work — a rotating logarithmic spiral would seem to zoom rather than flow.
Honest limits
The speed is counted in frames, not seconds. The clock advances a fixed 0.03 every time the browser paints, so the 2.2-second figure holds only on a 60 Hz screen. On a 120 Hz display the bands stream twice as fast, one spacing every 1.1 seconds; on a busy laptop that drops frames they slow down. The gallery thumbnail runs on the same frame clock.
The illusion is only true in the middle of the arms. The formula above treats the spiral as endless, but each arm here starts at the centre and stops at 0.44 of the short edge. Those two ends visibly rotate rather than stream: the four arm tips sweep round the rim clockwise, and at the centre, where all four arms begin at the same point, their innermost hooks spin like the blades of a pinwheel. Watch either end and the flow turns back into spin.
Despite the name, nothing here is a wave in the physical sense. No two arms add, cancel or interfere; the “waves” are the bare bands between strokes, moving because the strokes do. And under prefers-reduced-motion the plate draws a single still frame and never animates, so the streaming is not shown at all.
Draw your own
The bands are not drawn at all. What you see as a wave is the bare ground left between four strokes, and the whole trick is in how those strokes are offset. The general Archimedean spiral is r = a + bθ: a point starts at distance a from the centre and moves outward at a steady speed while its direction turns at a steady rate, and b is simply the outward speed divided by the turning speed. One arm’s successive turns are always 2πb apart. This plate draws four copies of one arm, each rotated a quarter-turn (φ = 0, π/2, π, 3π/2) from the last. Rotating an arm by φ is the same as setting a = −bφ, so the four arms are really one spiral with four different starting distances, each bπ/2 further in than the last — and that is why the gaps between them come out as four identical, evenly spaced bands that never narrow, widen or cross.
The snippet below is that idea in 25 lines of HTML and plain JavaScript, with no library. With b = 20 px per radian, one arm’s own turns sit 2π × 20 ≈ 126 px apart, the four arms split that into bands 20π/2 ≈ 31.4 px apart, and a 3 px stroke leaves about 28 px of bare ground in each band. Each arm sweeps 3.4π radians (1.7 turns) and ends 20 × 3.4π ≈ 214 px from the centre, inside a 480 px canvas. It paints with the same cobalt, coral and ground this page’s animation reads from the site palette, light or dark to match your device. Save it as an .html file and open it.
<canvas id="spiral" width="480" height="480"></canvas>
<script>
const dark = matchMedia('(prefers-color-scheme: dark)').matches; // follow the OS theme
const [bg, cobalt, coral] = dark ? ['#0B0D12', '120,158,255', '255,120,84']
: ['#E7E2D5', '52,88,214', '190,68,28'];
document.body.style.background = bg;
const ctx = document.getElementById('spiral').getContext('2d');
const b = 20; // px per radian: one arm's own turns sit 2*PI*b = 126 px apart
const arms = 4, maxTheta = 3.4 * Math.PI; let t = 0; // 1.7 turns per arm
const still = matchMedia('(prefers-reduced-motion: reduce)').matches;
function frame() {
ctx.clearRect(0, 0, 480, 480); ctx.lineWidth = 3;
for (let s = 0; s < arms; s++) {
const phi = t + s * 2 * Math.PI / arms; // arms a quarter-turn apart
ctx.strokeStyle = 'rgba(' + (s % 2 ? coral : cobalt) + ',0.8)';
ctx.beginPath();
for (let th = 0; th <= maxTheta; th += 0.05) // r = b * theta
ctx.lineTo(240 + b * th * Math.cos(th + phi), 240 + b * th * Math.sin(th + phi));
ctx.stroke();
}
t += 0.012; // turning by 0.012 rad = sliding every arm b * 0.012 px inward
if (!still) requestAnimationFrame(frame);
}
frame();
</script>
The motion is the same 0.012 radians per frame the plate turns by. Because rotating by φ only changes a, each frame slides every arm 20 × 0.012 = 0.24 px inward, so one band passes any point every 31.4 ÷ 0.24 ≈ 131 frames, about 2.2 seconds at 60 frames a second. Under prefers-reduced-motion it draws one still frame and stops.
Where to take it: set arms to 2 and the bands double to about 63 px; set it to 8 and they shrink to about 16 px, with only 13 px of ground left between strokes. Halve b to 10 and everything tightens by half, including the outer reach (about 107 px). Write the radius as 40 + b * th instead of b * th and you have given the spiral an a of 40 px: a bare 40 px hole opens in the middle, like the label on a record. Change th + phi to phi − th in both places and the arms wind the other way, so the same clockwise turn now makes the bands stream outward instead of in. What the snippet does not do: its speed is counted in frames, so it runs twice as fast on a 120 Hz screen; it reads your light or dark setting once, when the page loads; and it draws at 480 CSS pixels without scaling for high-density screens, so the lines are slightly soft on a phone or a Retina display.
Curious how the loop and canvas fit together? Read how it works →
More from the gallery
- Plate 05 Particle Burst A continuous bloom of particles from the core.
- Plate 06 Geometric Flow Hexagons orbiting in harmonic rotation.
- Plate 07 Color Symphony Layered sine waves scrolling in phase.
- Plate 08 Fractal Dreams A branching L-system swaying toward infinite depth.
- Plate 09 Truchet Tiles Quarter-arc tiles re-rolling into one continuous meander.
- Plate 10 Lissajous Ribbon A Lissajous curve traced as a tapering ribbon, phase adrift.