Skip to content

Instantly share code, notes, and snippets.

@tfc
Created April 14, 2026 07:43
Show Gist options
  • Select an option

  • Save tfc/2d30b290506f61277d1d9a3137bb69d6 to your computer and use it in GitHub Desktop.

Select an option

Save tfc/2d30b290506f61277d1d9a3137bb69d6 to your computer and use it in GitHub Desktop.
Mandelbrot fractal in nix
let
pkgs = import <nixpkgs> {};
inherit (pkgs) lib;
# minimal complex number library
complex = {
zero = { r = 0.0; i = 0.0; };
fromXY = r: i: { inherit r i; };
multiply = a: b: {
r = a.r * b.r - a.i * b.i;
i = a.r * b.i + a.i * b.r;
};
add = a: b: {
r = a.r + b.r;
i = a.i + b.i;
};
abs2 = { r, i }: r * r + i * i;
};
toS = builtins.toString;
# from floating point to integer, we're dropping after the decimal point
toI = fl: lib.strings.toInt (builtins.head (builtins.split "\\." (builtins.toString fl)));
# typical mandelbrot fractal iteration function
iterate = cfg@{ threshold, limit }: point: n: current:
let
next = complex.add (complex.multiply current current) point;
in
if n >= threshold || complex.abs2 next > limit * limit
then n
else iterate cfg point (n + 1) next;
# the bounds within the complex coordinate plane that we want to paint
bounds = {
x0 = -3;
y0 = -1;
x1 = 1;
y1 = 1;
};
step = 0.05;
ranges = {
x = lib.lists.range (toI (bounds.x0 / step)) (toI (bounds.x1 / step));
y = lib.lists.range (toI (bounds.y0 / step)) (toI (bounds.y1 / step));
};
map2d = f: map (y: map (x: f (step * x) (step * y)) ranges.x) ranges.y;
cfg = { threshold = 5000; limit = 1000; };
result =
let
f = x: y:
let
c = complex.fromXY x y;
in
iterate cfg c 0 complex.zero;
in
map2d f;
renderField = renderItem: field:
let
renderedField = map (map renderItem) field;
in
builtins.throw ("\n" + lib.strings.concatLines (map lib.concatStrings renderedField));
# cheap ASCII rasterization
renderMandelbrotScore = n:
let x = cfg.threshold / n; in
if 1000 < x then "."
else if 500 < x then ","
else if 200 < x then ":"
else if 100 < x then ";"
else if 50 < x then "!"
else if 20 < x then "/"
else if 10 < x then "%"
else if 5 < x then "?"
else "#";
in
renderField renderMandelbrotScore result
# for debugging the values when rasterization looks off
#renderField toS result
error:
… while calling the 'throw' builtin
at /Users/tfc/mb/default.nix:64:5:
63| in
64| builtins.throw ("\n" + lib.strings.concatLines (map lib.concatStrings renderedField));
| ^
65|
error:
...............................,,,,,,,,,,,,,,,,,,,,,,,,,::::#,,,,,,,,,,,,,,......
.............................,,,,,,,,,,,,,,,,,,,,,,,,,,,::;:,,,,,,,,,,,,,,,,.....
............................,,,,,,,,,,,,,,,,,,,,,,,,,,,::;;::,,,,,,,,,,,,,,,.....
...........................,,,,,,,,,,,,,,,,,,,,,,,,,,,:;:;#::,,,,,,,,,,,,,,,,....
.........................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::####::,,,,,,,,,,,,,,,,...
........................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::####;:,,,,,,,,,,,,,,,,...
.......................,,,,,,,,,,,,,,,,,,,,,,,,,::::::::####::::,,,:,,,,,,,,,,,..
......................,,,,,,,,,,,,,,,,,,,,,,,,,,:!::!://!!!/;;:;::::,,,,,,,,,,,..
.....................,,,,,,,,,,,,,,,,,,,,,,,,,,::;#:;##########::::::,,,,,,,,,,..
....................,,,,,,,,,,,,,,,,,,,,,,,,,,,::%##############?##;:,,,,,,,,,,,.
....................,,,,,,,,,,,,,,,,,,,,,,,,,,:::!#################:,,,,,,,,,,,,.
...................,,,,,,,,,,,,,,,,,,,,,,,,,,::/;#################;::,,,,,,,,,,,.
..................,,,,,,,,,,,,,,,,,:,,,,,,,,::::###################:::,,,,,,,,,,.
.................,,,,,,,,,,,,,,,,,::::::::::::/#####################?:,,,,,,,,,,,
.................,,,,,,,,,,,,,,,,,,:::::;:::::;#####################::,,,,,,,,,,,
................,,,,,,,,,,,,,,,,,,:::#;%#/;:::######################::,,,,,,,,,,,
................,,,,,,,,,,,,,,,,,,:::#######::######################;:,,,,,,,,,,,
................,,,,,,,,,,,,,,,,::::#########:######################;,,,,,,,,,,,,
................,,,,,,,,,,,,,,,:::::#########;######################:,,,,,,,,,,,,
...............,,,,,,,,,,:,,:::::/#;#########!#####################:,,,,,,,,,,,,,
...............,,,,,##############################################::,,,,,,,,,,,,,
...............,,,,,,,,,,:,,:::::/#;#########!#####################:,,,,,,,,,,,,,
................,,,,,,,,,,,,,,,:::::#########;######################:,,,,,,,,,,,,
................,,,,,,,,,,,,,,,,::::#########:######################;,,,,,,,,,,,,
................,,,,,,,,,,,,,,,,,,:::#######::######################;:,,,,,,,,,,,
................,,,,,,,,,,,,,,,,,,:::#;%#/;:::######################::,,,,,,,,,,,
.................,,,,,,,,,,,,,,,,,,:::::;:::::;#####################::,,,,,,,,,,,
.................,,,,,,,,,,,,,,,,,::::::::::::/#####################?:,,,,,,,,,,,
..................,,,,,,,,,,,,,,,,,:,,,,,,,,::::###################:::,,,,,,,,,,.
...................,,,,,,,,,,,,,,,,,,,,,,,,,,::/;#################;::,,,,,,,,,,,.
....................,,,,,,,,,,,,,,,,,,,,,,,,,,:::!#################:,,,,,,,,,,,,.
....................,,,,,,,,,,,,,,,,,,,,,,,,,,,::%##############?##;:,,,,,,,,,,,.
.....................,,,,,,,,,,,,,,,,,,,,,,,,,,::;#:;##########::::::,,,,,,,,,,..
......................,,,,,,,,,,,,,,,,,,,,,,,,,,:!::!://!!!/;;:;::::,,,,,,,,,,,..
.......................,,,,,,,,,,,,,,,,,,,,,,,,,::::::::####::::,,,:,,,,,,,,,,,..
........................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::####;:,,,,,,,,,,,,,,,,...
.........................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::####::,,,,,,,,,,,,,,,,...
...........................,,,,,,,,,,,,,,,,,,,,,,,,,,,:;:;#::,,,,,,,,,,,,,,,,....
............................,,,,,,,,,,,,,,,,,,,,,,,,,,,::;;::,,,,,,,,,,,,,,,.....
.............................,,,,,,,,,,,,,,,,,,,,,,,,,,,::;:,,,,,,,,,,,,,,,,.....
...............................,,,,,,,,,,,,,,,,,,,,,,,,,::::#,,,,,,,,,,,,,,......
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment