fractals_3d_webgl · MandelboxFoldScale
Mandelbox fold-scale 2D projection
A 2D orthographic projection of Tom Lowe's Mandelbox (2010) escape-time field. For each starting c = (x, y, z) the iteration applies (1) a box-fold (per-component mirror across the cube [-1, 1]^3), (2) a sphere-fold (r < 0.5 -> *4, 0.5 <= r < 1 -> /r^2), (3) a uniform scale, and (4) a translation by c. The 'scale' parameter (Lowe's famous scale-2, scale-3, scale -1.5 knobs) controls whether the resulting set is solid, hollow, or contains nested sub-fractals. The full 3D field is sampled on a (dim, dim) grid with a 2-sample Z slab, projected from a slow camera orbit. Orbit-trap minimum |z| drives a warm-to-cool ramp; escape iteration count supplies a bright rim.
Original: https://en.wikipedia.org/wiki/Mandelbox
▶ Try the live demo (JS port) ▶ Run reference.py via Pyodide 10 formulas have instant JS ports. The Pyodide path runs the actual Python in your browser — first load is ~6 MB, then instant.
Math essence
For each c, iterate z := boxFold(z); if |z|<0.5 then z := 4z else if |z|<1 then z := z/|z|^2; then z := scale*z + c. Escape when |z| > 2.5. boxFold mirrors each component z_i -> 2*clamp(z_i, -1, 1) - z_i, producing a [0, 1] -> [-1, 0] reflection. The (u, v) grid is rotated by pitch/yaw and averaged over 2 z-planes, then coloured by minimum |z| along the orbit and by the iteration count of escape.
Parameters
| Name | Type | Default | Range | Description |
|---|---|---|---|---|
dim | int | 256 | 128–512 | Square canvas side length in pixels. |
scale | float | -1.5 | -3–3 | Mandelbox scale factor; -1.5 is the iconic 'negative-1.5' Mandelbox. |
fold | float | 1 | 0.5–2 | Box-fold half-extent (1.0 = the canonical cube). |
max_iter | int | 12 | 4–32 | Escape-time iteration cap. |
camera_pitch | float | 0.45 | -1.2–1.2 | Camera pitch (radians), animated by step(). |
camera_yaw | float | 0.35 | -1.2–1.2 | Camera yaw (radians), animated by step(). |
orbit_speed | float | 0.12 | 0–0.4 | Per-step camera phase increment. |
warm | tuple | 255,180,90 | — | Warm end of the orbit-trap ramp. |
cool | tuple | 90,160,255 | — | Cool end of the orbit-trap ramp. |
void_color | tuple | 10,12,22 | — | Background colour (escaped points). |
rim_color | tuple | 255,245,220 | — | Highlight rim colour (boundary iter). |
seed | int | 7 | 0–999 | RNG seed. |
Reference
First 60 lines of reference.py. Full source:
library_external/fractals_3d_webgl/MandelboxFoldScale/reference.py
from __future__ import annotations
from typing import ClassVar
import numpy as np
def _mandelbox_iterate(
cx: np.ndarray, cy: np.ndarray, cz: np.ndarray, max_iter: int, escape: float,
scale: float, fold: float
) -> tuple[np.ndarray, np.ndarray]:
"""Tom Lowe's Mandelbox iteration (2010).
For each starting point c = (cx, cy, cz), iterate
z := boxFold(z)
if |z| < 0.5: z := z * 4
elif |z| < 1: z := z / |z|^2
z := scale * z + c
Escape when |z| > escape.
The boxFold is the per-component fold used in IQ/MIQEL's reference
implementations: z_i := clamp(z_i, -1, 1) * 2 - z_i, which mirrors
the cube [-1, 1]^3 onto itself. We track the minimum |z| (orbit
trap) along each trajectory, the same quantity that gives the
dramatic colour bands in scale-2 and scale-3 Mandelbox renders.
"""
x = cx.copy()
y = cy.copy()
z = cz.copy()
iters = np.zeros(cx.shape, dtype=np.int32)
orbit_min = np.full(cx.shape, np.inf, dtype=np.float32)
escape2 = escape * escape
for _ in range(max_iter):
r2 = x * x + y * y + z * z
mask = r2 < escape2
if not np.any(mask):
break
iters[mask] += 1
r_m = np.sqrt(r2[mask])
orbit_min[mask] = np.minimum(orbit_min[mask], r_m.astype(np.float32))
# Box-fold: mirror each component across the [-1, 1] range
xs = np.clip(x[mask], -fold, fold)
ys = np.clip(y[mask], -fold, fold)
zs = np.clip(z[mask], -fold, fold)
xs = xs * 2.0 - x[mask]
ys = ys * 2.0 - y[mask]
zs = zs * 2.0 - z[mask]
# Sphere-fold
r2_s = xs * xs + ys * ys + zs * zs
r_s = np.sqrt(r2_s)
small = r_s < 0.5
med = (r_s >= 0.5) & (r_s < 1.0)
if np.any(small):
xs[small] *= 4.0
ys[small] *= 4.0
zs[small] *= 4.0
if np.any(med):
r2_m = r2_s[med] Try running it locally
The reference implementation is self-contained Python with numpy. Install the package and run:
python library_external/fractals_3d_webgl/MandelboxFoldScale/reference.py Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.
More from fractals_3d_webgl
3D Menger sponge level-3 wireframe
fractals_3d_webgl · MengerSponge3DLevel3
A level-3 3D Menger sponge explicitly generated as 20^3 = 8000 kept sub-cubes and rasterised as a 12-edge wireframe projection.
Mandelbulb power-8 2D projection
fractals_3d_webgl · Mandelbulb2DProjection
A 2D orthographic projection of the iconic power-8 Mandelbulb escape-time field.
Poincare-disk hyperbolic tiling (Escher / Coxeter)
fractals_3d_webgl · HyperbolicTilingPoincare3D
A 3D hyperboloid-lifted rendering of the (p, q) hyperbolic tessellation in the Poincare disk model.
Sierpinski tetrahedron (tetrix) 3D chaos game
fractals_3d_webgl · SierpinskiTetrahedron3D
A 3D chaos-game rendering of the Sierpinski tetrahedron (tetrix): a regular tetrahedron recursively replaced by four half-size copies at its corners (Hausdorff dimension log(4)/log(2) = 2).