013 - Fraktale & L-Systems
Fraktale sind selbstähnliche Strukturen – Muster, die sich auf jeder Vergrößerungsstufe wiederholen. Sie sind ein Kernthema generativer Kunst, weil sie aus einfachen Regeln komplexe, organisch wirkende Formen erzeugen.
Warum Fraktale?
Die Natur ist voller Fraktale: Bäume, Farne, Küstenlinien, Blutgefäße, Schneeflocken. Wenn du "natürlich" aussehende generative Kunst machen willst, kommst du an Fraktalen nicht vorbei.
Das Faszinierende: Wenige Zeilen Code erzeugen unendliche Komplexität. Ein L-System mit 3 Regeln kann einen realistischen Baum zeichnen. Die Mandelbrot-Menge entsteht aus z = z² + c.
Drei Ansätze
| Ansatz | Prinzip | Beispiele |
|---|---|---|
| L-Systems | Grammatik-basierte Ersetzungsregeln | Bäume, Pflanzen, Koch-Kurve |
| Escape-Time | Iterative Berechnung pro Pixel | Mandelbrot, Julia |
| IFS | Zufällige Auswahl aus Transformationen | Barnsley Fern, Sierpiński |
L-Systems (Lindenmayer-Systeme)
Das Konzept
Ein L-System ist eine Grammatik:
- Axiom: Startstring (z.B.
"F") - Regeln: Ersetzungen pro Iteration (z.B.
F → F+F--F+F) - Interpretation: Turtle Graphics führt den String aus
Beispiel Koch-Kurve:
Axiom: F
Regel: F → F+F--F+F
Nach 1: F+F--F+F
Nach 2: F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+FDie Turtle interpretiert:
F= vorwärts zeichnen+= rechts drehen (60°)-= links drehen (60°)
TurtleAgent
import { TurtleAgent } from '@carstennichte/cc-toolbox';
// Manuell konfigurieren
const turtle = new TurtleAgent({
axiom: 'F',
rules: [{ symbol: 'F', replacement: 'F+F--F+F' }],
iterations: 4,
angleIncrement: 60,
stepSize: 4,
startPosition: new Vector(100, 400),
startAngle: 0
});
// L-System ausführen
const paths = turtle.runLSystem();
// Zeichnen
for (const path of paths) {
ctx.drawPath(path.getPoints());
}Fertige Presets
// Koch-Kurve
const koch = TurtleAgent.koch(iterations, stepSize);
// Sierpiński-Dreieck
const sierpinski = TurtleAgent.sierpinski(iterations, stepSize);
// Drachenkurve
const dragon = TurtleAgent.dragonCurve(iterations, stepSize);
// Fraktaler Baum
const tree = TurtleAgent.tree(iterations, stepSize);
// Hilbert-Kurve (Space-Filling)
const hilbert = TurtleAgent.hilbert(iterations, stepSize);
// Gosper-Kurve (Flowsnake)
const gosper = TurtleAgent.gosper(iterations, stepSize);
// Lévy C-Kurve
const levy = TurtleAgent.levyCurve(iterations, stepSize);
// Penrose Tiling (P3)
const penrose = TurtleAgent.penrose(iterations, stepSize);Turtle-Befehle
| Befehl | Symbol | Beschreibung |
|---|---|---|
forward(n) |
F, G |
n Schritte vorwärts, zeichnen |
backward(n) |
– | n Schritte rückwärts |
right(°) |
+ |
Rechts drehen |
left(°) |
- |
Links drehen |
push() |
[ |
State auf Stack |
pop() |
] |
State vom Stack |
penUp() |
– | Stift heben |
penDownCmd() |
– | Stift senken |
Stochastische L-Systems
Für organischere Ergebnisse – Regeln mit Wahrscheinlichkeit:
const stochasticTree = new TurtleAgent({
axiom: 'X',
rules: [
{ symbol: 'X', replacement: 'F[+X][-X]FX', probability: 0.5 },
{ symbol: 'X', replacement: 'F[+X]FX', probability: 0.3 },
{ symbol: 'X', replacement: 'F[-X]FX', probability: 0.2 },
{ symbol: 'F', replacement: 'FF' }
],
iterations: 5,
angleIncrement: 25,
seed: 12345 // Reproduzierbar
});Escape-Time Fraktale
Das Konzept
Für jeden Pixel:
- Starte mit komplexer Zahl
c(aus Pixel-Position) - Iteriere
z = z² + c - Zähle Iterationen bis
|z| > 2(Escape) - Farbe basiert auf Iterations-Anzahl
FractalRenderer
import { FractalRenderer } from '@carstennichte/cc-toolbox';
const fractal = new FractalRenderer({
type: 'mandelbrot', // oder 'julia'
width: 800,
height: 600,
centerX: -0.5,
centerY: 0,
zoom: 1,
maxIterations: 100,
colorScheme: 'rainbow' // oder 'grayscale', 'fire', custom
});
// Render to ImageData
const imageData = fractal.render();
ctx.putImageData(imageData, 0, 0);
// Zoom
fractal.zoomTo(x, y, factor);Julia-Sets
const julia = new FractalRenderer({
type: 'julia',
juliaC: { real: -0.7, imag: 0.27015 }, // Der "Seed"
// ... rest
});
// Animierte Julia-Sets: variiere juliaC über Zeit
julia.setJuliaC(Math.sin(time) * 0.5, Math.cos(time) * 0.5);Bekannte Julia-Parameter
| Name | Real | Imag | Beschreibung |
|---|---|---|---|
| Dendrite | 0 | 1 | Baumartig |
| Siegel Disk | -0.391 | -0.587 | Spiralen |
| Rabbit | -0.123 | 0.745 | "Douady Rabbit" |
| San Marco | -0.75 | 0 | Basilika-Form |
| Dragons | -0.8 | 0.156 | Drachenartig |
IFS (Iterated Function Systems)
Das Konzept
Ein IFS ist eine Menge von affinen Transformationen. In jedem Schritt:
- Wähle zufällig eine Transformation (gewichtet)
- Wende sie auf den aktuellen Punkt an
- Zeichne den Punkt
- Wiederhole millionenfach
Warum funktioniert das? Der "Chaos Game" Algorithmus konvergiert zum Attraktor des IFS – dem Fraktal.
IFSRenderer
import { IFSRenderer } from '@carstennichte/cc-toolbox';
const fern = IFSRenderer.barnsleyFern({
iterations: 100000,
pointSize: 1,
color: '#2d5a27'
});
// Render
fern.render(ctx);Fertige IFS-Presets
// Barnsley Farn
const fern = IFSRenderer.barnsleyFern();
// Sierpiński-Dreieck
const sierpinski = IFSRenderer.sierpinskiTriangle();
// Sierpiński-Teppich
const carpet = IFSRenderer.sierpinskiCarpet();
// Ahornblatt
const maple = IFSRenderer.mapleLeaf();
// Kristall
const crystal = IFSRenderer.crystal();Custom IFS
const custom = new IFSRenderer({
transforms: [
{
// Transformation 1: Skalierung + Rotation + Translation
a: 0.5, b: 0, c: 0, d: 0.5, // 2x2 Matrix
e: 0, f: 0, // Translation
probability: 0.33
},
{
a: 0.5, b: 0, c: 0, d: 0.5,
e: 0.5, f: 0,
probability: 0.33
},
{
a: 0.5, b: 0, c: 0, d: 0.5,
e: 0.25, f: 0.5,
probability: 0.34
}
],
iterations: 50000
});IFS-Transformation erklärt
Jede Transformation ist: [x', y'] = [a b; c d] * [x, y] + [e, f]
| Parameter | Bedeutung |
|---|---|
a, d |
Skalierung (diagonal) |
b, c |
Scherung/Rotation (off-diagonal) |
e, f |
Translation |
probability |
Auswahlwahrscheinlichkeit |
Integration mit anderen Systemen
Mit Animation
// Animierte L-System Iteration
const animation = new Animation({
from: 1,
to: 6,
easing: Easing.stepped(6)
});
function draw(props) {
const iterations = Math.floor(animation.getValue(clock.progress));
const paths = TurtleAgent.tree(iterations, 5).runLSystem();
// ...
}Mit ColorSet
// Farbpalette für Escape-Time
fractal.setColorFunction((iterations, maxIter) => {
const t = iterations / maxIter;
return colorSet.getColorAt(t);
});SVG Export (Plotter!)
// L-Systems sind perfekt für Plotter
const paths = TurtleAgent.hilbert(6, 2).runLSystem();
svgExporter.beginFrame();
for (const path of paths) {
svgExporter.drawPath(path.getPoints());
}
svgExporter.save('hilbert.svg');Performance-Tipps
| Fraktal-Typ | Tipp |
|---|---|
| L-System | Iterations begrenzen (>6 wird sehr groß) |
| Mandelbrot | WebGL für Echtzeit, Canvas für Export |
| IFS | Web Worker für >100k Iterationen |
Referenz
TurtleAgent
| Methode | Beschreibung |
|---|---|
forward(n) |
n Schritte vorwärts |
backward(n) |
n Schritte rückwärts |
left(°) / right(°) |
Drehen |
push() / pop() |
State Stack |
runLSystem(iter?) |
L-System ausführen |
getPaths() |
Alle Pfade als VectorPath[] |
reset() |
Zurücksetzen |
FractalRenderer
| Methode | Beschreibung |
|---|---|
render() |
Gibt ImageData zurück |
zoomTo(x, y, factor) |
Zoom auf Punkt |
pan(dx, dy) |
Verschieben |
setJuliaC(r, i) |
Julia-Parameter setzen |
setColorScheme(name) |
Farbschema wechseln |
IFSRenderer
| Methode | Beschreibung |
|---|---|
render(ctx) |
Auf Canvas zeichnen |
getPoints() |
Alle berechneten Punkte |
addTransform(t) |
Transformation hinzufügen |
setIterations(n) |
Iterationsanzahl |