L-Systems and the Grammar of Plants

After reading this you can read an L-system grammar, expand it by hand for a few iterations, translate the resulting string into a drawing, and predict how many segments the plant will have before you ever press grow.

What an L-system is

An L-system is a rewriting rule for strings, invented by the biologist Aristid Lindenmayer in 1968. You start with a short string called the axiom. You have a set of production rules that say how to replace each symbol. Then you rewrite the whole string at once, replacing every symbol by its rule simultaneously, and you repeat.

The parallel rewriting is the biological idea. In an ordinary grammar you expand one symbol at a time. In an L-system every cell divides in the same tick, so every symbol is replaced together. That single change is what makes L-systems model growing tissue instead of parsing sentences.

Here is the smallest interesting example. Take the axiom A with two rules: A becomes AB, and B becomes A. Rewrite four times and you get A, then AB, then ABA, then ABAAB, then ABAABABA. The string lengths are 1, 2, 3, 5, 8: the Fibonacci sequence. Lindenmayer used exactly this to model the branching of the alga Anabaena.

From string to picture with turtle graphics

A string of letters is not yet a plant. The bridge is turtle graphics. Imagine a turtle that holds a pen and reads the string one symbol at a time. Each symbol is a command.

F
Move forward one step and draw a line segment.
+
Turn left by the branch angle.
-
Turn right by the branch angle.
[
Push the current position and heading onto a stack. This starts a branch.
]
Pop the stack, returning the turtle to the last saved point. This ends a branch and resumes the trunk.
X
A control symbol that draws nothing. It only carries the grammar forward so branches keep appearing.

The push and pop pair is what gives L-system plants their tree shape. When the turtle reads [, it remembers where it stood. It wanders off drawing a twig. When it reads the matching ], it teleports back and keeps going along the main limb. Nesting brackets nest branches, and that is the whole trick behind a fern frond that splits, splits again, and returns to the stem.

When to use it, and when not to

Reach for an L-system when the structure you want is branching and self-similar: ferns, trees, seaweed, blood vessels, river networks, snowflakes. The grammar is tiny, the output is huge, and you control the look with a few parameters.

Do not reach for it when growth depends on the environment in a real way. A plain L-system does not know about light, gravity, collisions between branches, or nutrients. It rewrites symbols in a vacuum. If you want branches that avoid each other or grow toward a resource, you need a space-filling model instead. For that, see the Mycelium Growth tool, which grows networks by reaching into open space rather than by rewriting a string.

An L-system encodes the plan of a plant, not its physics. Two runs of the same deterministic grammar are identical down to the last segment. Real ferns never are. The stochastic grammars and the angle jitter in this tool exist precisely to add the variation that biology supplies for free.

Counting segments before you draw

Because every symbol expands at once, the string grows roughly geometrically. If each symbol is replaced on average by g symbols per iteration, the length after n iterations is about:

L_n \approx L_0 \cdot g^{\,n}

Here L_0 is the length of the axiom, g is the growth factor of the dominant rule, and n is the iteration count. The number of drawn segments is the count of F symbols in the final string, which scales the same way.

The exact growth factor comes from the rule. For the Fibonacci grammar above, the length ratio settles toward the golden ratio \varphi \approx 1.618, so g = 1.618. For a rule like F becomes FF+F-F, the symbol F is replaced by four F symbols, so the F count multiplies by 4 each round. Ten iterations of that would give 4^{10} \approx 10^6 segments, which is why iteration counts stay small.

A worked fern using the demo grammar

Barnsley-style fern by hand

Load the tool with its defaults and the grammar is the classic fern:

  • Axiom: X
  • Rule 1: X becomes F+[[X]-X]-F[-FX]+X
  • Rule 2: F becomes FF
  • Branch angle: 25 degrees
  1. Start with the axiom: X. It has zero F symbols, so nothing is drawn yet.
  2. Iteration 1. Replace X using rule 1. There is no F to expand yet. Result: F+[[X]-X]-F[-FX]+X. Count the F symbols: there are 3. Count the X symbols: there are 4.
  3. Iteration 2. Every F becomes FF and every X becomes the rule 1 string. The 3 old F symbols each double to 2, giving 6, plus each of the 4 X expansions contributes 3 fresh F, adding 12. Total F: 6 + 12 = 18.
  4. Track the X count too. Each of the 4 old X becomes a string with 4 X, so X goes from 4 to 16.

The pattern is now clear. Let f_n and x_n be the counts of F and X after iteration n. The recurrences are:

f_n = 2 f_{n-1} + 3 x_{n-1}, \qquad x_n = 4 x_{n-1}

Starting from f_0 = 0 and x_0 = 1, the segment count (the F total) climbs fast.

Symbol counts for the default fern grammar by iteration
Iteration nX countF count (segments)Ratio to previous F
143-
216186.000
364844.667
42563604.286
5102414884.133
6409660484.065

The ratio settles toward 4, the dominant growth factor, because the X term drives the F term and X multiplies by exactly 4 each step. At iteration 6 you already draw 6048 segments from a two-line grammar. The tool's status line reports this segment count so you can check it against the table.

The F count for the default fern. Each bar is roughly four times the one before, so the axis climbs from single digits to thousands in six steps.

How the angle and jitter change the shape

The branch angle is the single most visible parameter. It is the turn applied by every + and -. Small angles near 15 degrees give tall narrow plants. Angles near 25 degrees give the open fern. Angles above 45 degrees fold the plant into a dense bush. The grammar is unchanged; only the interpretation of the turn symbols changes.

With the default fern grammar drawn to iteration 4, setting the branch angle to 15 degrees produces a narrow upright plant, 25 degrees produces the familiar open fern, and 60 degrees folds it into a tight fan. The segment count stays fixed at 360 across all angles because the grammar does not change.

The angle jitter adds a seeded random offset to each turn, drawn uniformly from minus the jitter to plus the jitter. With jitter at 0 degrees the plant is perfectly self-similar: every sub-branch is a scaled copy of the whole. Set jitter to 5 degrees and each branch bends a little differently, so the fern stops looking machine-made. This is the stochastic extension catalogued in Prusinkiewicz and Lindenmayer's The Algorithmic Beauty of Plants.

Common mistakes

Unbalanced brackets break the drawing. Every [ must have a matching ]. If a rule pushes without popping, the turtle never returns to the trunk and the plant drifts off screen. Count your brackets in each production before you run it.

The second common mistake is pushing the iteration count too high. Because segments grow by a factor near 4 per step here, iteration 9 would ask for roughly 380000 segments and iteration 11 for over 6 million. The browser will slow to a crawl. Stay at iteration 4 to 6 for the fern, and lower for grammars with larger growth factors.

A subtler error is confusing the control symbol X with a drawing symbol. X draws nothing. It exists only to carry the recursion. If you delete X from the axiom the plant stops growing new branches, because there is nothing left for rule 1 to expand.

Related tools

L-systems are one member of a family of models where simple local rules produce complex global structure. If that idea interests you, several other tools on this site show it from different angles. The Boids Flocking Simulator gets flocking from three local steering rules. The Ant Colony Pheromone Trails tool builds foraging routes from evaporating chemical trails. The Lenia Continuous Life tool grows moving lifeforms in a continuous cellular automaton. For the role of chance in biology, the Genetic Drift Simulator shows how randomness alone fixes or loses genes, and the Evolving Creatures tool watches selection reshape a population over generations.

Frequently asked questions

Why do L-systems rewrite every symbol at once?

Because they model organisms whose cells divide in parallel. Lindenmayer built them to describe the growth of the alga Anabaena, where all cells in a filament divide together. Rewriting one symbol at a time, as ordinary grammars do, would model a machine reading a tape, not tissue growing.

How many iterations should I use?

For the default fern, 4 to 6 is the sweet spot. Iteration 4 draws 360 segments and looks like a fern. Iteration 6 draws 6048 and fills in the fine fronds. Beyond that the segment count roughly quadruples each step, so 8 or more will bog down the browser without adding visible detail.

What is the difference between a deterministic and a stochastic L-system?

A deterministic grammar has exactly one rule per symbol, so every run gives the same plant. A stochastic grammar offers several rules for a symbol and picks one at random each time, so runs differ. The stochastic tree option here does this, and the angle jitter adds a second, milder source of randomness on top.

Can an L-system make a fern that reacts to sunlight?

Not a plain one. The grammar rewrites symbols with no knowledge of the outside world, so light, gravity and collisions have no effect. Environmentally sensitive L-systems exist in the research literature, but they add machinery well beyond the string rewriting shown here.

Why does the plant look green at the tips and brown at the base?

That colouring is a rendering choice, not part of the grammar. The tool tracks how deep each segment sits in the bracket nesting: shallow segments near the axiom are drawn thick and brown like bark, deep segments near the end of a branch are drawn thin and green like new growth, with leaves dotted at the branch ends.