Fractal Explorer: Deep Zoom in the Browser

A single-page WebGPU app for exploring escape-time fractals as an instrument rather than a renderer: pan, zoom, switch formulas, and remix colors while the image stays live, all the way down to zooms of 1e100. That is far past where ordinary floating point stops working, and getting there is most of what this post is about. It's live in your browser at fractals.charliedeck.com.

Escape-Time Fractals in Five Minutes
Almost everything in the app is a variation on one loop. Take a complex number , start at , and repeat:
For some values of the sequence stays small forever, orbiting in a bounded tangle. For others it shoots off to infinity. The Mandelbrot set is simply the set of where the orbit never escapes: the black interior in every rendering. The famous filigree is the boundary between the two fates.
The picture comes from asking how fast each point escapes. There's a classical shortcut: once , the orbit can never return, since from there and the growth compounds. So the renderer iterates each pixel's until either crosses that escape radius or an iteration budget runs out, and colors the pixel by the count. Bands of equal escape time form the glowing contour lines around the set; points that never escape stay black.
Two refinements matter for image quality. Smooth coloring removes the hard bands: instead of the integer count, use the fractional overshoot, meaning how far past the radius the final landed (), so color varies continuously. And orbit traps color by the closest approach an orbit makes to some shape (a point, a line), which is where the app's more painterly palettes come from.
One more relationship: fix and vary the starting instead, and you get that parameter's Julia set. Every point of the Mandelbrot set indexes a different Julia set. The Mandelbrot is an atlas, and the app lets you open any page of it.
A Field Guide to the Fourteen Formulas
Every formula in the app is the same idea, iterate and watch for escape, with a different step function. In rough order of how gently they treat newcomers:
- Mandelbrot: , plus higher powers (the "multibrots," whose bulb counts grow with ).
- Julia: the same iteration with frozen and the pixel supplying . Connected lace or scattered dust, depending on whether sits inside or outside the Mandelbrot set.
- Burning Ship: fold the plane first, . The absolute values break symmetry and produce the famous smoldering armada along the negative real axis.
- Tricorn: conjugate before squaring, . Three-fold symmetric, with "tricorn" points where the Mandelbrot has cusps.
- Celtic: take , then fold only its real part: . Knotwork-like webbing instead of bulbs.
- Phoenix: the step remembers the previous iterate, . That one term of memory grows feathered, bird-like Julia sets.
- Nova: a relaxed Newton's method for with a constant added, . Instead of escaping, orbits converge to roots; the fractal is the basin boundary.
- Magnet I: , from the renormalization of an Ising magnet. Physics gave this one both its name and its convergence-to-1 escape condition.
- Spider: where itself drifts each step (). The moving parameter smears the set into webs and spinnerets.
- Lambda: , the logistic map's complex parameter plane. Population dynamics as filigree.
- Mandelbox 2D: no polynomial at all. Fold space at the box walls, invert through a sphere, scale, add . An IFS-flavored escape fractal full of right angles.
- Barnsley I: a conditional step, depending on the sign of . The branch produces crystalline, fern-adjacent structure.
- Glynn: a Julia iteration at a fractional power near . The broken symmetry grows organic root-and-branch forms.
- Tetration: , power towers. Orbits can converge, cycle, or blow up, and the map between those behaviors is startlingly intricate.
The control panel only shows the parameters the active formula actually uses, and each formula ships with presets so you land somewhere interesting instead of a black void.
Why You Can't Just Zoom: The Precision Wall
Deep zoom has a wall in it, and the wall isn't iteration count.
At a zoom factor of , the on-screen viewport spans about complex-plane units, so on a 1,000-pixel canvas neighboring pixels are roughly apart. Floating point, meanwhile, can only distinguish numbers that differ relatively by about the machine epsilon: for the 32-bit floats GPUs run fastest (and WebGPU shaders only speak f32), for JavaScript's 64-bit doubles.
Set those equal and you get the walls: f32 dies at zooms around 1e4–1e5, f64 around 1e13. Past the wall, adjacent pixels round to the same representable number. The renderer is asked to iterate the identical value a thousand times per row, and the image dissolves into rectangular mush. No amount of iteration budget fixes it; the input coordinates themselves have collapsed.
You could iterate every pixel in software arbitrary-precision arithmetic, and at 1e100 you'd wait minutes per frame. The problem, then: get arbitrary-precision correctness at f32 speed.
Perturbation: One Exact Orbit, a Million Cheap Corrections
The trick, worked out in K. I. Martin's SuperFractalThing and refined for years on the deep-zoom forums, is that nearby orbits stay nearby. You only need one orbit computed exactly.
The CPU computes a single reference orbit at the zoom center using arbitrary-precision arithmetic (a custom binary float in precision.ts, its precision scaled to the zoom at roughly one bit per doubling, plus guard bits). Every pixel then tracks only its delta from that reference. Substituting into gives the delta's own recurrence:
No full-precision coordinates appear anywhere in that formula. The reference values arrive as ordinary floats, and is tiny but only needs relative accuracy, which is the one thing floating point is genuinely good at. So the GPU iterates millions of deltas in fast f32 while the CPU's one slow exact orbit anchors them all. At extreme depths the deltas themselves would underflow f32, so the shader tracks their binary exponents explicitly and normalizes its internal scale. A delta can sit at of a pixel one moment and grow to escape magnitude the next without losing its footing.
Two failure modes remain:
- Glitches. When a pixel's orbit swings close to zero while the reference doesn't (or vice versa), the delta stops being small relative to the reference and the linearization starts producing garbage, classically visible as smooth blobs where filigree should be. The fix is rebasing: the moment rivals , re-anchor the pixel's state against the start of the reference orbit and keep iterating. For the whole polynomial family (Mandelbrot at any power, Julia, Burning Ship, Tricorn, Celtic, Phoenix) the app's rebasing recurrences are exact at any depth, even when the reference orbit itself escapes. The rational and transcendental formulas (Nova, Magnet, Lambda, Barnsley, Glynn, Tetration) get exact scaled recurrences too. Spider is the lone holdout, since its per-pixel drifting has no shared reference to rebase against.
- Stale references. The reference orbit depends only on the center point and formula, not the zoom level, so it's reused across zooms and recomputed only when you pan outside its validity radius, change formula, or zoom past the precision it was built with. Watching the status bar, you can see how rarely that actually happens.
Making 1e100 Feel Like Dragging a Map
Correct-at-depth is worth little if every frame takes a second, so the renderer treats frame time as a budget. While you interact, it measures GPU cost per pixel and renders whole frames at whatever resolution fits: full frame rate at any depth, just softer. When you stop, it refines to full resolution in tiles radiating out from your zoom anchor, a budgeted batch per frame. Antialiasing runs last, as a second tiled sweep of four subpixel samples, so enabling it never adds latency; edges simply smooth themselves after the sharp image is already up. Iteration limits tune themselves to depth (about 2,500 at 1e40, 5,600 at 1e94), with the Iterations slider left as a base quality dial.
And because the full view state (exact high-precision center, scale, formula, palette) serializes into the URL hash after each interaction, any place you find is a bookmark. A 1e100 minibrot that took twenty minutes of wandering is one ctrl-C away from being shared.
fractals.charliedeck.com: wheel to zoom, drag to pan, and try switching formulas mid-zoom.