GitHub
teilweisepackages/lsystem/src

L-System

@ralphschuler/lsystem

Erzeugt komplexe Strukturen durch wiederholtes paralleles Ersetzen von Symbolen nach gewichteten Regeln.

grammarproceduralstochastic

01 · Problem

Wofür braucht man das?

Pflanzen, Fraktale und prozedurale Formen lassen sich kompakt als Axiom plus lokale Umschreibregeln beschreiben.

02 · Denkmodell

Das mentale Modell

Jede Generation liest ausschließlich die vorherige Symbolfolge und baut eine neue. Stochastische Regeln wählen pro Symbol eine Transformation aus einer validierten Gewichtsverteilung.

Im Repository

LSystem filtert Regeln pro Zeichen und wählt mit Math.random. Arrays von Transform-Symbolen werden per String-Coercion mit Kommas angehängt; Gewichte und exponentielles Wachstum sind unbegrenzt.

03 · Kontrollfluss

Was passiert in welcher Reihenfolge?

  1. Regeln einmal nach Ursprungssymbol gruppieren und Gewichte validieren.
  2. Für jede Iteration eine frische Ausgabefolge erzeugen.
  3. Für jedes Symbol eine Regel über injizierten Zufall wählen oder es unverändert übernehmen.
  4. Transformationssymbole einzeln anhängen und vor einem Größenlimit stoppen.

04 · Bauteile

Die entscheidenden Verträge

LSystem(axiom, rules) Speichert Startfolge und stochastische Umschreibregeln.
generate(iterations) Wendet Regeln generationenweise auf jedes Symbol an.
Rule / SymbolType Beschreibt Ursprung, Transformation und Wahrscheinlichkeit.

05 · Build it yourself

Selbst implementieren

Nutze Symbolarrays statt impliziter String-Coercion und injiziere Zufall für reproduzierbare Generationen.

  1. Indiziere Regeln pro Symbol und normalisiere positive Gewichte.
  2. Erzeuge jede Generation aus einem unveränderten Snapshot der vorherigen.
  3. Begrenze Iterationen und maximale Symbolzahl vor unkontrolliertem Wachstum.
minimal.ts · unabhängig vom Package
type Rule<S> = { weight: number; replacement: readonly S[] };

function expand<S>(
  input: readonly S[],
  rules: ReadonlyMap<S, readonly Rule<S>[]>,
  random: () => number,
) {
  const output: S[] = [];
  for (const symbol of input) {
    const rule = chooseWeighted(rules.get(symbol) ?? [], random());
    output.push(...(rule?.replacement ?? [symbol]));
  }
  return output;
}

06 · Verifizieren

Was du testen solltest

  • Deterministischer RNG erzeugt erwartete Generationen und Randgewichte.
  • Symbole ohne Regel bleiben erhalten; mehrere Ersatzsymbole enthalten keine Kommas.
  • Ungültige Gewichte und Überschreiten des Größenlimits führen zu klaren Fehlern.

07 · Grenzen

Kompromisse und Stolperfallen

  • Materialisierte Folgen können exponentiell wachsen; Streaming erschwert spätere Generationen.
  • Stochastische Ergebnisse sind ohne Seed nicht reproduzierbar.
Wichtig

Die Transformationsfolge ist eine Sequenz, kein String-Zufallsprodukt. Datenrepräsentation und spätere Turtle-Interpretation sollten getrennt bleiben.

08 · Weiterdenken

Quellcode und Nachbarn

Originalcode auf GitHub ansehen