aldus.nexus

Fractal explorer

Deep-zoom the Mandelbrot set with its matching Julia set beside it, and share exactly where you are.

The numbers

escape times in this view
reference orbit |Zₙ|
render time by depththis visit

How it works

Every pixel asks one question: if you start at zero and keep squaring and adding c, do you fly off to infinity? Each step below shows the maths with live numbers for the point under your pointer. The How it works guide has the short version.

1One rule, iterated

Pick a complex number c = x + iy, one for each pixel. Start at z₀ = 0 and apply z → z² + c again and again. Squaring a complex number squares its size and doubles its angle, so the point spins and stretches. For some c the orbit stays near the origin forever: those c are the Mandelbrot set, drawn dark. For the rest it eventually runs away, and the colour says how quickly.

Move the pointer over the set (or tap) and watch the first steps of that point's orbit, drawn on the picture too. Inside the big cardioid it settles on one value; in the round bulb to its left it flips between two. Both edges are simple curves: the cardioid is c = eit/2 − e2it/4 and the bulb a circle of radius ¼ round −1, and you can draw the cardioid or the bulb in maths art.

The same feedback loop that makes this coastline also makes the weather unpredictable in chaos lab, and turns typed equations into pictures in maths art.

zn+1 = zn² + c, z0 = 0(x + iy)² = x² − y² + 2xy·ic = …


          

2The escape radius

Once |z| is bigger than 2 (and bigger than |c|), the next square outruns anything c can add, so the orbit is gone for good. That makes the test finite: iterate until |z| passes the radius, or give up after a maximum number of steps and call the point inside. Deeper views need more steps, so the limit grows with the zoom.

The page actually waits until |z| passes 256, not 2: a few extra steps cost little and make the smooth colours in step 3 exact.

|z| > 2 ⇒ |z² + c| ≥ |z|² − |c| > |z|so once outside the radius, it never comes backthis point: …

Nmax ≈ 250 + 150 d + 2 d², d = log₁₀ zoomthe automatic iteration limit, times the iterations settingnow: d = …, Nmax = …

3Smooth colouring

Counting whole steps gives flat bands of colour. Far outside the radius |z| roughly squares each step, so log log |z| grows by log 2 every step; subtracting it from the count gives a fraction that slides smoothly between whole steps. The palette is a looping neon gradient indexed by ln(ν + 1), stretched over the range of escape times in the current view (measured after the first coarse pass), so the whole set and a view ten thousand steps deep both run from dark to bright.

ν = n + 1 − log₂ ( ln |zn| )n: the step where |z| passed 256…

f = (ln(ν + 1) − L) / (H − L)L, H: the 1st and 99.5th percentiles in this view…

colour = palette[ (1023 b f + t) mod 1024 ]b: the bands slider, t: the cycle offsetb = …, index …

4Julia sets

Use the same rule but swap the roles: keep c fixed and start z₀ at each pixel. Every c has its own Julia set, and the Mandelbrot set is the map of them all: if c is inside, the orbit of 0 stays bounded and the Julia set is one connected piece; outside, it shatters into dust (a Cantor set). Near the boundary the Julia set looks just like the Mandelbrot set around c.

A map whose every point is a whole picture turns up again in reaction-diffusion nebulas, where each tile of the parameter map is a dish grown with its own feed and kill rates, and the patterns crowd along a sharp edge in the same way.

zn+1 = zn² + c, z0 = pixelc fixed: the point under the pointer, or the view centrec = …

c ∈ M ⇔ Julia set connectedFatou and Julia, around 1918…

5Deep zoom: perturbation

A double has 53 bits, about 16 digits. Past a zoom of about 10¹³ neighbouring pixels have the same double coordinates and the picture melts into blocks. The fix is perturbation theory: compute one reference orbit Z at the view centre with as many bits as needed, using BigInt fixed point, then iterate only each pixel's tiny difference δ from it, in ordinary doubles.

Expanding (Z + δ)² + C + δc and subtracting Z² + C leaves an update for δ alone. When the pixel's orbit passes closer to 0 than its own δ, the page rebases it onto the start of the reference (δ ← Z + δ, m ← 0), which stops the glitches a single reference would otherwise cause. Doubles reach 10⁻³⁰⁸, so δ is safe far beyond the page's limit of 10¹⁵⁰. The same trick of exact big integers for huge ranges powers binary search's zoom from the cosmos to one particle.

δn+1 = 2 Zn δn + δn² + δcz = Z + δ, c = C + δcmode: …

bits ≈ log₂(1 / pixel) + 40precision of the reference centre…

|Zm + δ| < |δ| ⇒ δ ← Zm + δ, m ← 0rebasing (Zhuoran, 2021)rebases this view: …


          

6Tiles, workers and passes

The view is cut into 64-pixel tiles, handed to Web Workers so the page never freezes. Each tile is drawn in passes: every 8th pixel as a block, then every 4th, 2nd and finally every pixel, each pass computing only the pixels the last one skipped. Tiles nearest the centre go first, and anything still queued is dropped as soon as you move.

pixels = W·H, work ≈ Σ iterationsa pass computes only the new samples…

rate = iterations / secondall workers together…

7Shareable coordinates

The address holds the exact centre as decimals (as many digits as the zoom needs), the zoom as a power of ten, the palette and the iteration setting. Opening a link checks every value strictly: digits only, bounded lengths and ranges, and anything else falls back to the whole set. The planet forge shares its worlds the same way, with a seed.

?re=…&im=…&z=log₁₀ zoomdigits ≈ log₁₀(1 / pixel) + 3…