EnglishGitHub
teilweisepackages/lsystem/src

L-System

@ralphschuler/lsystem

Schreibt Symbolfolgen mit normalisierten Gewichten und austauschbarer Zufallsquelle um.

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

Schreibt Symbolfolgen mit normalisierten Gewichten und austauschbarer Zufallsquelle um. Ausgabe kann exponentiell wachsen. Rendering und anwendungsspezifische Ausgabelimits sind von der Grammatik getrennt.

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 / generateSchreibt ein Axiom mit validierten gewichteten Regeln um.
Rule / SymbolTypeBeschreibt Symbole, Ersetzungen und relative Gewichte.

05 · Selbst bauen

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.
Konzeptskizze · kann ausgelassene Helfer verwenden
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 solltest du testen?

  • 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.

Selbst ausprobieren

Formuliere die erste Prüfaussage als fehlschlagenden Test, implementiere die kleinste Korrektur und ergänze einen Grenzfall.

Deterministischer RNG erzeugt erwartete Generationen und Randgewichte.

Ansatz vergleichen

Dein Test sollte beim gezielten Verletzen der Invariante fehlschlagen und nach der Korrektur wieder bestehen. Halte den Aufbau deterministisch und prüfe ein beobachtbares Ergebnis.

07 · Grenzen

Kompromisse und Stolperfallen

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

Ausgabe kann exponentiell wachsen. Rendering und anwendungsspezifische Ausgabelimits sind von der Grammatik getrennt.

08 · Weiterdenken

Quellcode und verwandte Ideen

yarn tsx packages/lsystem/examples/basic.ts