Animated marching squares on a sinusoidal scalar field. Tap to cycle palettes; toggle between contour lines and filled regions.
Four corners, each above or below a threshold. Two states per corner, four corners per cell, sixteen possible configurations. The entire marching squares algorithm fits in a lookup table small enough to scribble on a napkin. You examine a 2×2 cell of scalar values, compare each corner against an isovalue, pack the results into a four-bit index, and the table tells you which edges to connect. The line segments, stitched across thousands of cells, trace smooth contour lines through a noisy field.
William Lorensen and Harvey Cline published the three-dimensional cousin, marching cubes, at SIGGRAPH 1987 as a way to extract polygon meshes from CT and MRI scans. Their paper has collected over fifteen thousand citations. The 2D version predates the name, quietly at work in cartographic software that drew elevation contours and weather isobars. Topographic maps from the US Geological Survey had been solving the same geometric problem by hand since the nineteenth century: where does the 500-meter line cross between a point measured at 480 and one at 530? Somewhere in between, proportionally. The computer just does the interpolation faster.
The implementation here skips Perlin noise and builds its scalar field from a sum of sine and cosine waves, four terms with different frequencies and phase offsets drifting over time. The field function returns a value roughly between −1 and 1 for every grid intersection:
function field(nx, ny, t) {
const x = nx * Math.PI * 2;
const y = ny * Math.PI * 2;
return (
Math.sin(x * 2.1 + t * 0.9) * Math.cos(y * 1.7 + t * 0.6)
+ Math.sin(x * 0.9 - y * 1.4 + t * 0.4) * 0.7
+ Math.cos(x * 3.3 + y * 2.6 - t * 0.7) * 0.35
+ Math.sin(x * 1.2 + y * 3.1 + t * 0.3) * 0.25
) / 2.3;
}
Six threshold levels slice through that field, each producing its own contour. The edge-point interpolation does the real work of turning blocky grid cells into curves that look organic. Given two corner values straddling a threshold, the function finds the exact fractional position where the isovalue crosses the cell edge: t = (thresh − v0) / (v1 − v0). Linear interpolation, nothing fancier, yet the visual result reads as fluid and continuous because the underlying field is smooth.
Two of the sixteen cases deserve special attention: cases 5 and 10, the saddle points, where diagonally opposite corners sit above the threshold while the other two sit below. The lookup table resolves each saddle by picking one of two possible pairings, which means the algorithm can occasionally produce contours that cross where they shouldn't. Disambiguating saddles requires sampling the cell center or checking the average value, a fix that most production implementations add and most creative-coding demos skip. The version here skips it too. At 120 by 90 cells refreshing sixty times a second, nobody notices the occasional topological misdemeanor.