Section 12 of 14

Deep zoom rendering

Every picture in this project's main galleries is computed in double-precision floating point, the 64-bit number format a processor does arithmetic in natively. This is fast and efficient, but it breaks down when you zoom deeply enough into the Mandelbrot set. Past a certain point, neighboring samples round to the same number and whole groups of pixels compute the same orbit. The result is blocky discretization artifacts that have nothing to do with the fractal, and they get worse the deeper you go.

The frame computed in double precision: horizontal bars and flat blocks of color where neighboring pixels round to the same coordinate, with the shapes of the true picture only roughly visible through them.

Double precision

The same frame computed by perturbation: fine spirals and filigree in navy, blue, and white, sharp down to the pixel.

Perturbation

The same deep frame computed in double precision (left), where the picture breaks into flat blocks because neighboring pixels round to the same coordinate, and computed by perturbation (right).

It's possible, but expensive, to switch to higher-precision arithmetic: 128-bit floats, or arbitrary-precision libraries such as rug in Rust or mpmath in Python. Fortunately, the deep-zoom community has developed clever mathematics that looks much deeper into the Mandelbrot set far more efficiently. I go over it briefly at the end of this page. Deeper frames also need a slower, more deliberate way of browsing, which the Deep tab of the fractal explorer provides.

Here is a video of a deep descent, down to a frame about 3.5 × 10−15 wide. It was made with builder/zoom.py, which computes a high-precision field once at each halving of the width and colors it separately.

Video pendingA deep zoom into the Mandelbrot set, from the whole set down to a frame about 3.5 × 10⁻¹⁵ wide.

Midway

Midway

Final frame

Final frame

A zoom from the whole Mandelbrot set into the seahorse valley. It then descends into a minibrot and repeats the same sequence inside the minibrot's own seahorse valley.

Deep frames have wildly varying escape times, and getting a rendering that conveys their full range of detail often takes more exploration and parameter tweaking. The percentile stretch from rendering fundamentals spreads the palette linearly between each frame's own 0.5th and 99.5th percentiles. At extreme depths escape counts run into the tens of thousands, and the stretch leaves most of the picture inside a few percent of the palette. For deep frames an absolute scale generally works best: the smooth count passes through a logarithm or a power curve, and the palette then repeats at a fixed period. The figure below shows the video's final frame under several such colorings.

The video's final frame on the leveled scale: the spiral in dark red and orange over broad fields that run from deep blue to pale yellow.

Leveled

The same frame at a longer period: fewer, wider bands, so the spiral reads as orange and yellow arms over blue.

Higher period

The same frame and pass in a palette of blues: the spiral in pale lavender and white over deep blue.

Palette switch

The same frame in a palette of greens: the spiral in pale green and white over dark green, flecked with fine points of light.

Another palette

The video's final frame under four more colorings of the same field.

What depth adds to a picture

With some deliberate choices guiding the descent, deeper parts of the Mandelbrot set and related fractals produce much richer detail and patterns in regions that look plain and smooth at shallower depths. In the shallow parts of the Mandelbrot set, the smooth rendering approach often leaves large areas with only a smooth gradient. For most of the gallery I used alternative rendering modes (especially tia and stripe) to add detail to these regions, but it's also possible to find extremely deep areas of these fractals that contain beautiful fractal richness where the shallower levels would be smooth. The figure below compares a shallow frame with a deep frame inside it.

A frame at the same center 10⁻¹² wide: two spirals joined in an S by chains of cream and orange filigree over broad smooth fields of dark red and black, the center on a small four-armed knot where the chains meet.

Shallowwidth 10⁻¹²

The deep frame at the center of the shallow one: rings of small curled spirals around a dark eye, in rust, cream, and black, with a field of finer filigree at lower left.

Deepwidth 2.3 × 10⁻¹⁷

A shallow frame (left) and a deep frame inside it (right): a region that is smooth at the shallow depth fills with detail further down.

Minibrot descents

Small copies of the set, minibrots, lie all along the boundary: every filament passes infinitely many of them, at every depth, smaller and more numerous the further down you go. From outside, a copy looks like a small black body with the familiar bulbs and hairs. If you zoom into the copy's neighborhood, you see more than that. The copy's own seahorse valleys and spirals are laid over the structure you were already in, so a region that looked smooth from further out fills with filigree. Close to a copy, that filigree often arranges into what look like whole Julia sets, the embedded Julia sets that deep-zoom artists steer toward. The figure below follows one descent of this kind, six steps down a chain of components nested one inside the next. Each step frames the next component in the chain, and the last frame is about a billionth of the complex plane wide.

The whole Mandelbrot set, black on banded color.

Whole setwidth 3

The seahorse valley between the main cardioid and the large disk, centered on a copy too small to see.

Seahorse valleywidth 0.05

A small copy of period 27, a black speck ringed with filigree.

Period 27width 1.9 × 10⁻⁵

The copy's own large disk, of period 54, with the filigree around it.

Period 54width 2 × 10⁻⁶

The edge of the period-54 disk, lined with its tiny satellite bulbs, the one of period 972 at the center, under a band of filigree.

Period 972width 5 × 10⁻⁸

The last frame, about a billionth wide: a tiny copy among dense spirals in purple and blue.

Last stepwidth 1.3 × 10⁻⁹

Six steps down one descent, each frame centered on the next component in a chain nested one inside the next. Filigree from each copy appears in regions that were smooth one step earlier.

Descents like the one in the video can be composed by hand or automated. The neighborhood of a minibrot is a small, turned copy of the whole set, so every place in the set has a twin inside every minibrot, smaller and slightly distorted. That means any frame can be carried into any minibrot: find the minibrot, then find the frame's twin inside it. Simply scaling and turning the frame by the minibrot's size and angle misses the twin badly at any real depth, often by thousands of frame widths, so I solve for the twin directly instead. The Dive block at the top of the fractal explorer's Deep tab does all of this in one press. You choose where to search for minibrots (the current view, a view you paste in, or a random wallpaper) and what to do with the ones it finds: land on one, stop at its symmetry point, carry a second view inside it, or collect the largest of them. Pressing it again from where it lands keeps descending, and since the periods multiply at every step, the nesting can keep going until the iteration cap runs out. Keep diving repeats the dive with fresh random draws until you stop it, and every result collects in a Dive results list that you can browse and save from.

The Dive block on the explorer's dark panel: “Search for minibrots near” a small picture of the Mandelbrot set marked random, with Random lit under Here and Paste; “then dive into” in a dropdown; a second picture of the set marked random, with Random lit under None, Here, and Paste; a Go button; and under them two boxes, New coloring on arrival and Keep diving, both ticked.
The Dive block in the Deep tab.

Nesting one minibrot inside another lets you choose what kind of detail you get. Take two frames, A and B, each centered on a minibrot. Framing A inside A's copy, B inside A's, A inside B's, or B inside B's gives four different pictures from the same two places.

Spiral arms of filigree in blue, orange, and pale green winding round a center whose copy is too small to see.

Aperiod 28, width 4.2 × 10⁻⁶

A small black copy of the set at the center of a cross of filigree, between broad smooth fields of blue.

Bperiod 18, width 1.4 × 10⁻⁴

A's spirals again, inside A's own copy and turned by 134 degrees, their smooth fields now grained with finer filigree.

A then Aperiod 784, width 1.4 × 10⁻¹³, turned 134°

B's cross and its copy again, inside A's copy and turned by 134 degrees, the blue fields grained with finer filigree.

A then Bperiod 504, width 4.7 × 10⁻¹², turned 134°

A's spirals again, inside B's copy and turned by 52 degrees, with finer filigree grained through the smooth fields.

B then Aperiod 504, width 2.5 × 10⁻¹¹, turned 52°

B's cross and copy again, inside B's own copy and turned by 52 degrees, its fields grained with finer filigree.

B then Bperiod 324, width 8.4 × 10⁻¹⁰, turned 52°

Two frames, A and B (top), and the four ways to nest one inside the other (bottom).

How a deep frame is computed

The Deep tab in the fractal explorer computes one orbit at high precision, the reference orbit, for the center of the frame, using fixed-point arithmetic with as many bits as the frame's width requires. Every pixel then iterates only its small offset from that orbit. Write a pixel's orbit as zn = Zn + δn, where Zn is the reference orbit, and let Δc be how far the pixel's c is from the center's c. For z ↦ z2 + c the offset then obeys

and the higher degrees follow from the binomial expansion in the same way. The offsets are tiny, but a double keeps its relative precision at any magnitude, so δ fits comfortably in an ordinary double even where the coordinates themselves do not. This is perturbation, and it is how every modern deep-zoom renderer works.

The reference orbit is only a good anchor while a pixel's orbit stays near it. When the full value Zn + δn passes closer to zero than δn itself, the offset has become the larger quantity and precision starts to drain away. To fix this I use rebasing, which comes from Zhuoran on fractalforums.org. At that step the pixel takes its whole current value as a new offset and restarts from the beginning of the same reference orbit. With rebasing, one reference orbit serves the entire frame. The fractal explorer draws the multibrot families up to degree six, on both the parameter and dynamical planes, using the smooth rendering mode. Its iteration cap follows the same depth rule as the rest of the engine, up to a ceiling of a million, or two million when you set the count yourself, and a probe raises it when too many samples reach it. In practice it works down to widths of about 10−30 close to a minibrot, where the ceiling on iterations runs out. Renderers that also extend the exponent range of their offsets go hundreds of decades deeper.

Rendering speed

The fractal explorer renders deep frames on the CPU, in WebAssembly, across the browser's worker threads. On one six-core desktop, the video's final frame takes about 15 seconds at 1280 by 720 with one sample per pixel, averaging about fifteen thousand iterations a sample. On the same machine, Fraktaler 3, a mature open-source deep-zoom renderer, takes about 50 seconds on the CPU with its acceleration on and about 100 without it. Compared like for like (CPU, doubles, plain perturbation), the fractal explorer does about seven times as many iterations per second. I think the reason is specialization rather than a better algorithm: Fraktaler 3 interprets general formulas and tracks derivatives at every step, while my kernel runs one fixed update. The two agree on more than 99.7% of pixels.

GPUs are clearly faster at this kind of independent per-pixel work. On the same machine Fraktaler 3's GPU path draws the frame in under 3 seconds, in single precision. Consumer GPUs are slow at doubles, and in double precision the same GPU roughly ties the fractal explorer's CPU kernel, which is why the fast GPU renderers work in single precision with extended-exponent tricks. I kept rendering on the CPU for portability, and only used the GPU to evaluate the neural networks.

Deep-zoom renderers usually add bilinear approximation, which skips many iterations at once by applying a precomputed linear map. I built it into the fractal explorer and then took it back out, because on the frames worth looking at it wasn't much faster, and it changed the picture. On frames with visible structure it ranged from about 20% slower than plain perturbation to about 2.6 times faster. At every tolerance tried it also moved escape counts, and on some frames it moved the boundary of the interior, so the pictures stopped matching what the engine draws. It paid off handsomely only on frames that were almost entirely interior. Fraktaler 3 shows the same pattern on the video's final frame: its approximation buys a factor of about 1.3 to 2 and moves a fifth of the pixels by more than one iteration.

The multibrots

The deep rendering techniques on this page work on the multibrots and their Julia sets too, though each iteration costs more as the degree rises. Their deep areas are full of rich detail, and learning to navigate them well is a key part of making fractal artwork.

A tiny copy of the Mandelbrot set at the center of a pinwheel of spiral arms in magenta, violet, and pale blue.

Mandelbrot setwidth 2.4 × 10⁻¹⁵

The Julia set for that point, zoomed in close to it: a four-armed pinwheel of spirals in violet and magenta around a small black island.

Julia setwidth 10⁻¹³

A small black copy of the degree-3 multibrot in a ring of gold filigree, with branching arms on amber.

Degree 3width 2.4 × 10⁻¹⁵

The degree-3 Julia set for that point, zoomed in close to it: two large spirals of gold filigree on amber and brown.

Degree 3 Julia setwidth 4.6 × 10⁻¹⁴

A small black copy of the degree-4 multibrot at the center of spiral arms of filigree in green and white.

Degree 4width 3.8 × 10⁻¹⁴

The degree-4 Julia set for that point, zoomed in close to it: pinwheels of green and white filigree around a tiny black island.

Degree 4 Julia setwidth 1.3 × 10⁻¹²

A small black copy of the degree-5 multibrot in a pentagonal frame of filigree, with spirals around it in blue and white.

Degree 5width 5.7 × 10⁻¹⁸

The degree-5 Julia set for that point: rings of pale blue filigree around dark blue pools, with spirals at the sides.

Degree 5 Julia setwidth 7.3 × 10⁻³

Spiraling arms of red and white filigree dotted with tiny black copies, around a pale center.

Degree 6width 3.6 × 10⁻¹⁴

The degree-6 Julia set for that point, at the same center and width: a six-armed star of red and white filigree.

Degree 6 Julia setwidth 3.6 × 10⁻¹⁴

Deep locations on the Mandelbrot set and the degree-3 to degree-6 multibrots (top to bottom). Each row shows a location on the parameter plane (left) and a view of the Julia set for that location's c (right). The neighborhoods look alike, much as they do at the Misiurewicz points, but these are not Misiurewicz points, and the two sides do not match exactly.

Random dives

I designed the walks, their parameters, and the judges entirely for the double-precision range, where rendering is fast enough to search at scale. But understanding the shallow regions well turns out to also be valuable for generating deep fractal artwork because it helps you descend into the beautiful parts of each multibrot. A random dive starts from one of those places and carries it down a chain of minibrots, so running dives continuously is a straightforward way to approximate the whole process at depth. The results are impressive even with no filtering beyond dropping blank frames, and no judge looking at the deep frames. The figure below shows some I picked by eye; the Deep tab's Random dives list holds a thousand more, unpicked, alongside a hand-picked gallery.

A small black copy of the set in a ring of filigree, among spiral arms in orange, cream, and deep purple.

Mandelbrot setwidth 6.7 × 10⁻⁸

Chains of small spirals in pink and white filigree over rose and dark blue.

Mandelbrot setwidth 1.4 × 10⁻¹⁰

A small black copy of the set in a cross of gold and copper filigree, with spirals at its tips, on deep blue.

Mandelbrot setwidth 8.4 × 10⁻¹⁴

A small black copy of the set ringed by petals of white and gray, inside a frame of copper spirals on dark blue.

Degree 4width 5.3 × 10⁻¹⁷

A wide spiral of teal and gold filigree, its arms made of rows of smaller spirals.

Mandelbrot setwidth 2.4 × 10⁻¹¹

A small black copy of the set among swirls of pale blue and white filigree on dark blue.

Degree 4width 5.7 × 10⁻¹⁵

A winding chain of spirals in pink and pale blue across a near-black ground.

Degree 3width 4.8 × 10⁻¹⁵

One broad spiral of pale green filigree over mottled green.

Mandelbrot setwidth 1.5 × 10⁻¹¹

A small black copy of the set at the center of four-fold spiral arms in red, white, and periwinkle.

Mandelbrot setwidth 5 × 10⁻¹³

Clusters of bright green bulbs and small spirals across dark green.

Degree 3width 5.8 × 10⁻¹³

A tiny copy of the set at the center of a star of cream and orange filigree, with spirals at the corners.

Mandelbrot setwidth 3.3 × 10⁻¹⁵

The edge of a dark blue region lined with seahorse spirals, fading to pale violet on the right.

Degree 4width 1.6 × 10⁻¹³

Chains of pale blue seahorse spirals winding around dark navy pools on white.

Mandelbrot setwidth 4 × 10⁻¹³

A lattice of tiny spirals in pink, blue, and plum, circling one center at the upper left.

Mandelbrot setwidth 1.6 × 10⁻¹²

A small black copy of the set among spirals of mauve filigree on pale pink.

Degree 4width 1.7 × 10⁻¹³

Deep frames from random dives, picked by eye.

Every figure on this page links to its frame in the explorer, the deep ones in the Deep tab, and the tab's links carry the frame and its coloring.