L-system
Rewrite a start string by repeatedly substituting each symbol per a fixed rule set, then draw the final string with a turtle to grow fractal trees and plants.
Run it
What it looks like when it goes wrong (4)
- The character count runs into six figures and the drawing stops changing in any way you can see — the new branches are shorter than a pixel. The readout is the point: an L-system has no base case. A recursive tree stops because the function says `if (depth === 0) return`; rewriting is unconditional and only ever grows. Nothing in the grammar will ever stop it, so the generation count is a limit the author imposes and has to choose.
- Every branch collapses onto a near-straight line. The structure is all still there — the same characters, the same branch points — and it is invisible, because branching only reads as branching when the daughter directions diverge enough to separate. The grammar has not changed; only the interpretation has.
- Branches swing back over the trunk and the tree folds into itself. Worth seeing straight after the previous one: the same grammar produces a line, a plant, or a tangle depending on one number that the rules say nothing about. The grammar describes topology; the turtle decides geometry.
- Every branch is the same length as its parent, which is the default here and is what the plain grammar actually specifies. It reads as a mesh rather than a plant. Real plant-like results need a shrink factor the L-system itself has no notation for — set it to 60% and the same string becomes a tree. It is a reminder that most published L-system pictures include decisions the grammar does not contain.
Clean-room implementation — written from the described algorithm, not from source. Reuse policy
What it is
An L-system — short for Lindenmayer system — grows a string of symbols by rewriting it against a fixed set of rules, generation after generation, and only then hands the finished string to a turtle to draw. The string never encodes a picture directly; it encodes a sequence of moves, and the picture is whatever trace those moves leave. That’s the trick behind the classic branching fractal trees and plants people reach for this technique to make: the branching comes for free out of the rewriting, not out of anyone computing where a branch will land.
How it works
- Pick an alphabet (the legal symbols) and write an axiom — the starting sentence, built from that alphabet, that counts as generation 0.
- Write production rules: a replacement string for any symbol that should grow. As the source puts it, “the production rules of an L-system describe ways of transforming the sentence.” A symbol with no rule is left as-is.
- To advance one generation, scan the entire current sentence and swap in each symbol’s replacement, reading only the previous generation’s string. Repeat for as many generations as you want: the rules are “applied recursively, starting with the axiom, generating new sentences over and over again.”
- Take the final string and walk it with a turtle (see turtle graphics), one symbol at a time. The minimum vocabulary this needs is a draw action — “draw a line and move forward” — and a state action — “save current state” — the latter being what lets a branch point hold its place so a sibling branch can start from there later.
- Coding Train’s own build order for this (challenge 16, “L-system Fractal Trees”) matches: add rules, write a generate function, write a turtle function, then add an angle variable — the angle being what every turn symbol does to the picture.
Parameters & tuning
Generation count is the growth knob: each generation is built entirely from the last, so the sentence keeps compounding every time you rewrite it. Push it too high and the string — and the time your turtle takes to walk it — balloons long before the tree looks meaningfully different to the eye.
Turn angle is the shape knob. Coding Train treats it as a dedicated variable precisely because it decides whether the result reads as a tight, spindly cluster or a wide, spread canopy — the same role angle plays in any turtle-driven path.
The replacement string per symbol is the strongest knob of all — the difference between a rule that just lengthens the sentence and one that produces side branches. The exact notation (which characters mean “turn,” which mean “branch,” and what the closing half of “save current state” should restore) isn’t specified in what’s evidenced here, so that’s a convention you invent per implementation, not one to copy from a source.
A rule set with no way to stop growing never terminates the way a recursive function’s base case would — an L-system’s only stopping condition is how many generations you chose to run.
Where it’s been used
The Nature of Code’s fractals chapter frames L-systems as the generalization
of its earlier recursive trees: alphabet, axiom, rules, interpreted by a
turtle. Coding Train’s challenge 16 builds the identical pipeline in
p5.js — rules, a generate function, a turtle function, an angle variable —
as part of an algorithmic-botany series. Michael Fogleman’s axi, a
pen-plotter control library, lists Lindenmayer systems among its
drawing-generation features: the same rewrite-then-turtle pipeline, aimed
at a plotter-ready path instead of pixels.
Variants & neighbours
Recursive fractal tree (deterministic)
draws and decides in the same call — no string ever exists — while an
L-system separates generation from drawing into two passes. That’s also why
it generalizes further than a plain branch(): different symbols can
trigger different turtle actions in the same walk, not just “branch left,
branch right.”
Stochastic fractal tree randomizes branch angle at draw time on a fixed recursive structure. Nothing evidenced here shows an L-system with probabilistic rules — the rule set is fixed — so run-to-run variation would have to come from randomizing the turtle-interpretation stage instead, not the rewriting.
Koch snowflake and Cantor set reach comparable self-similar detail with none of this grammar: each recursively divides an existing line into thirds — discarding the middle, or replacing it with an outward bump — directly on whatever segments survived the last pass. No alphabet, no axiom, no rule table; the geometry recurses on itself instead of being written out as a string first.
Recursive function names the general mechanism a plain fractal tree relies on — a function calling itself against a base case. An L-system’s generation step isn’t recursion in that sense: it’s closer to a loop, since every generation is one synchronous rewrite pass over the previous string. The only save/restore in the whole technique happens in the turtle walk at the end.
Go deeper
- The Nature of Code — Fractals — the axiom/rules/turtle framing this page follows.
- Coding Train challenge 16, L-system Fractal Trees — the challenge metadata; same build order, p5.js.
- Michael Fogleman — lists Lindenmayer
systems among
axi’s plotter-drawing features.
Connected to
Further reading: The Coding Train · The Nature of Code
Prerequisite of: turtle graphics
Contrast with: Recursive function
Try it yourself
A deterministic recursive branch() function and an L-system can both end up drawing the exact same forked tree. What's actually different about how each one gets there?
The recursive function decides and draws in the same call: draw a segment, translate, then call itself twice at a shorter length. An L-system separates those two things entirely — it rewrites its axiom string for as many generations as you ask for, with nothing drawn yet, and only afterward walks the finished string with a turtle. The rewriting step never touches a turtle at all; the branching only appears once interpretation starts.