Skip to main content
BVDART Logo

Building an Interactive Fractal Explorer

⚙ Tutorial• 2 min read
fractalwebglperformancelab
Technical deep-dive into implementing a performant Mandelbrot/Julia set explorer with WebGL and progressive rendering.

Three Challenges

The Lab generates Mandelbrot and Julia images with adjustable parameters and viewports. Interactive fractal explorers raise three useful engineering questions: performance, numerical precision, and progressive detail. The techniques below describe ways to address them; the current Lab uses CPU raster generation.

Which points escape?

Each pixel asks: does this c escape?Re: -2.200 → 1.000 · Im: 1.200 → -1.200
Follow the selected orbitz₀ = 0
zₙ₊₁ = zₙ² + c
Complex orbit from zero with escape circle|z| = 2ReIm|z| = 0.338

Escapes at step 33

Crossing the radius-2 circle proves escape. A finite run that stays inside does not prove membership.

Try this Set c = 0: every iterate stays at zero. Try c = −1 for a two-point cycle, then c = 0.5 for an escaping orbit.

Magnify the boundary around the zoom focus: every displayed pixel is recomputed in the smaller complex-plane region. Use any control to take over.

Select a point in the Mandelbrot field and follow the repeated calculation that decides its color.

Try it yourself
  1. Move c with the plane or the Re(c) and Im(c) controls.
  2. Scrub Orbit step n; compare c = 0, c = −1 and c = 0.5 with Im(c) = 0.

Watch: Each image pixel chooses c while z starts at zero. The orbit panel shows repeated squaring and addition; crossing radius 2 establishes escape. A finite unescaped sample remains inconclusive.

Full guide Open in the Lab

GPU-Accelerated Rendering

An escape-time iteration can run in a WebGL fragment shader. Each pixel computes its own iteration count independently, making the Mandelbrot set well suited to parallel GPU execution. Actual rendering time depends on the device, image dimensions, iteration limit and chosen region.

mandelbrot.frag
// Fragment shader (GLSL) — core iteration
vec2 z = vec2(0.0);
for (int i = 0; i < MAX_ITER; i++) {
  if (dot(z, z) > 4.0) { iter = i; break; }
  z = vec2(
    z.x*z.x - z.y*z.y + c.x,
    2.0*z.x*z.y + c.y
  );
}
glsl

Deep Zoom Precision

Precision becomes an issue at deep zoom levels when adjacent pixel coordinates become too close for the chosen numeric representation. Perturbation methods address this by computing a high-precision reference orbit on the CPU and expressing nearby pixels as small differences from that reference. This is an advanced rendering technique, not a feature of the current Lab generator.

Progressive Rendering

Progressive rendering can start with a coarse grid and refine it in later passes. This gives a viewer an early approximation while expensive detail is still being computed. Color mappings can then translate iteration values into a palette. These are design options for a fractal explorer; the current Lab renders its raster result as a completed image.

One constant, a different set

Each pixel starts a different orbitThe same c is used everywhere
One constant for the whole image
The selected starting point
First 16 steps of the selected Julia orbit|z| = 2ReIm|z| = 0.221
z₀ = 0.250 + (0.150)i
c = -0.800 + (0.156)i
zₙ₊₁ = zₙ² + c

This starting point escapes after 72 steps.

Moving the crosshair tests one starting point. Moving c changes the recurrence at every pixel. Dark areas are unescaped samples in this finite test.

Try this Choose c = 0. The filled Julia set is the unit disk: starting magnitudes below 1 shrink, and those above 1 grow. Move the crosshair to compare both.

Move c continuously from its current value through connected and disconnected Julia structures, then return. Use any control to take over.

Vary the constant c, then inspect an orbit in its Julia set. Here the starting point varies while c stays fixed.

Try it yourself
  1. Choose c in the small parameter plane or use its real and imaginary controls.
  2. Set c = 0 and move the crosshair inside and outside the unit disk.

Watch: The main image varies z₀ while every pixel uses the same c. Changing c reshapes the whole field; moving the main crosshair only selects an orbit to inspect.

Full guide Open in the Lab

Related Concepts

Related Artworks

Explore Related Sections

More about the work: