Task 5 of 5

Julia Sets: Turn the Dial

Here's the payoff. Take the exact loop you've built and flip the roles: in a Julia set, z starts at the pixel and c is one fixed complex number shared by every thread. Each choice of c is a different fractal — c = 0 gives a plain disk, −0.7269 + 0.1889i a galaxy of spirals — and the Mandelbrot set turns out to be the map of which c values give connected Julias.

Because c arrives as kernel arguments, changing it costs one function call — no recompiling. That's what makes those mesmerizing morphing-Julia animations: nudge c, redraw, repeat.

same loop, roles swapped — mandelbrot varies c, julia varies z₀
Goal: a graphical Julia kernel over the fixed view −1.6…1.6: seed z from the pixel, add the arguments cRe, cIm each step, and keep task 4's smooth shading (interior black).

Requirements

Hint 1 — what actually changes

Two lines. Mandelbrot: z starts at 0 and c is the pixel. Julia: z starts at the pixel and c is the argument pair. The loop body, the guard, the shading — all identical.

Hint 2 — the exact edits

Seed with

let zr = this.constants.xMin + x * this.constants.step;

(and likewise zi from y), then inside the loop use … + cRe and … + cIm instead of px / py.

Same idea elsewhere

A per-launch value broadcast to every thread is what other APIs call a uniform: a WGSL uniform buffer, a Metal constant buffer, a plain CUDA kernel parameter. Animating one uniform per frame — exactly your c — is how every shader-toy Julia morph is driven.

All tasks in Escape-Time Fractals

  1. Map Pixels to the Complex Plane
  2. The Escape-Time Loop
  3. Paint by Iteration Count
  4. Smooth Out the Bands
  5. Julia Sets: Turn the Dial

This page is an interactive exercise — the editor, the GPU runner and your saved progress need JavaScript. The text above is the full brief.