Fractals in Scaly

−0.5 + 0i, 3 wide Drag to move, scroll or pinch to zoom, double-click to zoom in. Reset the view

Run the same program

Loading…

Runs of this picture

WhereThe loopSpeedupPicture
None yet.

What runs here

One Scaly program, compiled to WebAssembly, draws sixteen fractals — eleven in the plane, five in space; the list above the picture chooses one, its arrows go from one to the next. Its work is a single for over the points of the picture. Nothing in it says “in parallel” or “on the graphics card”: the rounds of the loop do not depend on each other, so the runtime may hand them to other cores; and its body is arithmetic on 32-bit numbers, so the compiler also writes it as a kernel the card can run. What changes between the buttons is only what the host gives the program — one core, all of them, the card — and the picture comes out the same. relaxed before the loop allows the card's floating point, which rounds a little more loosely: on the card some points come out a shade different — a few in a hundred in the Mandelbrot set, more where a fractal is wilder, as the Burning Ship and Lyapunov’s —, and one on the very edge of a set may fall to the other side. The table says how many.

While it runs, the page reads the picture straight out of the program's memory, where its threads and the card put the points, and paints what is there: one core goes row by row, all of them fill their parts of the picture at once, and the card is done before the eye can follow. Each point is the average of several places in it — nine unless you choose otherwise —, which smooths the edges and multiplies the work: enough to see the difference, not only to read it.

“Let Scaly decide” gives the program both: the runtime measures the first rounds on the processor, remembers how long each run on the cores took, and sends the loop to the card where that pays — a small picture with few iterations may stay on the cores. The times are those of the loop alone, measured by the program. The card needs its kernel compiled once — a browser translates it into the card's own language, and Safari takes far longer for that than for a run —, so the page does that in the background as soon as a program is loaded; where you are quicker, the table says how much of a time it was. The first run on the cores includes starting their threads; a run on the cores whose picture you move or zoom away is broken off.

The colours flow instead of standing in bands: for each place the program measures not only how many turns it took to run away — or, for Newton’s fractal, the Nova and the Magnet, to come to rest — but how far its last turn went beyond the bound, with a logarithm it writes itself in the four operations: a kernel on the card has no other. The palettes are the program’s own too, five colours each, blended point by point.

The five in space are drawn as a camera sees them: from the eye a ray goes through each point of the picture, in steps, each as long as the fractal’s distance estimate says is free around it, until it meets the surface. There the program works out the light — the surface’s slope from six more estimates, a soft shadow towards the sun, how deep in a fold the place lies —, with a square root that, like the logarithm, it writes itself. Drag to turn the camera round the fractal, zoom to come nearer: past the surface the camera stays and its lens grows longer, up to a thousand times. While you move, the page draws small pictures one after the other, and the full one as soon as you let go.

The program — the original

Change it and build it: the Scaly compiler, built for WebAssembly, compiles your version here in the page — for threads and for the card, as the original was. The first build loads the compiler (about 8 MB); after that a build takes a fraction of a second. The buttons above then run your version. It gets the same arguments — width, height, iterations, the centre and width of the picture in billionths, and the samples per side of a point and which fractal (0 to 15, in the order of the arrows; for one in space the centre and the width are the camera’s: its turn and its lift in radians, and how far it is) — and shows the picture it writes to a file whose name ends in .<width>x<height>.rgba; where it prints picture at and the address of the picture in its memory before its loop, the page watches it grow. What else it prints appears under the buttons.