If we plot the escape times for points in this complex plane series, we end up in a world of burning ships.
The largest ship is located on the real axis at -1.75.
If we consider an escape radius of 2, the world also has a radius of 2, since any points starting outside of the world diverge right away.
The ships are located near the real axis (y = 0) among negative real numbers.
Zooming in closer to the ships in the bottom left
The ship near -1.6 between the largest ship and the dark expanse.
Small ships near the edge of darkness
Zoomed in to the small ship near -1.57
Small ship and disorder near the expanse, with curving spires.
Left of the largest ship are some very small ships. The light ends at (-2, 0)
Zoomed in to a small ship near -1.94
The equation using complex numbers is this:
It's similar to the Mandelbrot equation:
Except instead of squaring each number, we add the absolute values of the real and imaginary components together during each iteration and square the sum instead.
z is a complex number composed of real and imaginary numbers:
Fractal images are generated by changing the value of c:
If we convert to using x and y, the burning ship fractal equation reduces to::
A common way of exploring fractals is by putting different starting (x0, y0) numbers into the equation and making note of whether the series:
Escape time: given a starting point (x0, y0), we can give each point a color by calculating the number of iterations it takes for the series to diverge, and the distance from zero when escaping.
const ESCAPE_THRESHOLD = 4;
const MAX_ITERATIONS = 255;
function iterateUntilEscape(x0, y0) {
let x = 0, y = 0;
let numIterations = 0;
while ((x*x + y*y < ESCAPE_THRESHOLD) &&
(numIterations < MAX_ITERATIONS)) {
const x_next = x*x - y*y + x0;
const y_next = 2*Math.abs(x*y) + y0;
x = x_next;
y = y_next;
numIterations++;
}
return [numIterations, x*x + y*y];
}
We'll set the RGBA colors of every pixel in the image based on the number of iterations. Here's an example of a fiery yellow/red color palette by scaling just the green and alpha values of each pixel.
function getColor(numIterations) {
return [
255, // red
numIterations * 7, // green
0, // blue
numIterations * 15 // alpha
];
}
Here's a general function for drawing fractals onto canvas elements. Changing the iterateUntilEscape function will change the drawn fractal.
function drawFractal(canvasEl, xRange, yRange, getColor) {
const canvasWidth = canvasEl.width;
const canvasHeight = canvasEl.height;
const context = canvasEl.getContext('2d');
const canvasImageData =
context.createImageData(canvasWidth, canvasHeight);
const image = canvasImageData.data;
for (let i = 0; i < canvasHeight; i++) {
for (let j = 0; j < canvasWidth; j++) {
const x0 = xRange[0] +
j*(xRange[1] - xRange[0]) / canvasWidth;
const y0 = yRange[0] +
i*(yRange[1] - yRange[0]) / canvasHeight;
const [numIterations, escapeDistance] =
iterateUntilEscape(x0, y0);
const pixelIndex = 4*i*canvasWidth + 4*j;
if (numIterations !== MAX_ITERATIONS) {
const mu = getMu(numIterations, escapeDistance);
const pixels = getColor({ numIterations, mu });
for (let p = 0; p < 4; p++) {
image[pixelIndex + p] = pixels[p];
}
}
}
}
context.putImageData(canvasImageData, 0, 0);
}
Here's the largest ship colored based on number of iterations alone.
By considering escape distances on a logarithmic scale, we can use this extra information to smooth the color transitions.
const ESCAPE_RADIUS = 2;
function getMu(numIterations, escapeDistance) {
return numIterations + 1 -
Math.log(escapeDistance) / Math.log(ESCAPE_RADIUS);
}
function getColor(mu) {
return [ 255, mu * 7, 0, mu * 15 ];
}
Here's the same image as above colored with renormalized iteration counts.
Nebulabrots are a way of rendering fractals where pixels are colored based on how frequently they're visited while calculating the iterations until escape across the viewport.
Zoomed-in to various parts of the fractal world.
The mast of the largest ship
Distant view when approaching the expanse along the real axis near x = -1.5
The left edge of the world near x = -2.0
All fractals on the page are interactive and rendered when they're in view.
Fractal image controls
TODO
Source code