Exploring Recursive Art: Fractals with Context Free
Generating Intricate Imagery with Simple Rules and Shapes
With AI-generated art stealing the spotlight, it’s easy to overlook the charm of simpler, rule-based generative art. This article introduces Context Free Art , a tool that enables you to create intricate, beautiful designs using basic rules and recursion.
Context Free Art is perfect for generating fractals, trees, and other patterns with minimal coding.
Generative art piece created by the author with Context Free.
🔍 Let’s explore how simple algorithms can lead to complex structures. If this sounds interesting, download the software to follow along :)
Intro
Context Free (and the command-line tool cfdg) is a digital art program that takes a description of an image and generates it as a bitmap, vector image, or even a movie.
The magic of Context Free lies in its recursive nature: shapes can contain other shapes, which can, in turn, contain even more shapes. This recursive layering allows complex and intricate designs to emerge from simple instructions. As we dive deeper, you’ll see how this process enables the creation of detailed and dynamic generative art.
Source Giphy
Let’s start out by creating a simple program.
Getting started
Writing a simple program in Context Free involves a few key components:
- Shapes: the fundamental graphical elements in your image e.g squares, circles, and triangles.
- Rules: how shapes are drawn and transformed. Rules can specify size, position, rotation, and other properties.
- Startshape: This is the starting point of your drawing. It tells Context Free which shape to begin with.
As this is a visual software. Let’s see how these elements work together by looking at some code examples.
Example 1: A Simple Rectangle
To draw a single square, we can type and press Render on the top bar of the program.
startshape RECTANGLE
shape RECTANGLE
rule {
SQUARE []
}
Here we can see all three elements we introduced above. They result in a square.
A rectangle appears
In simple terms, in this code:
startshape RECTANGLE
tells Context Free that the initial shape to draw is calledRECTANGLE
. This is the starting point of the design.- Then we define the
RECTANGLE
shape. Within this shape, we specify how it will be drawn by including rules. - In this case we only have a single rule with a primitive
SQUARE[]
. Which instructs Context Free to draw a square.
Other common primitive shapes you could try are: CIRCLE[]
and TRIANGLE[]
. They work in the same way.
Example 2: Adding rule options
The empty brackets [] in SQUARE[]means that there are no transformations (like scaling, rotating, or moving). To alter this, you can change the rule properties:
s: Size
x: X-coordinate
y: Y-coordinate and
r: Rotation
As seen below:
startshape EXAMPLE
shape EXAMPLE
rule {
SQUARE [s 1 x 0 y 0] // Center square
SQUARE [s 1.5 x 3 y 3 r 45] // Smaller, rotated, blue square
}
In this example, our startshape EXAMPLE
consists of two squares.
- The first one
SQUARE[s 1 x 0 y 0]
is located at the center and has a size of . - The second one
SQUARE [ s 1.5 x 3 y 3 r 45 ]
is 1.5 times bigger, rotated 45 degrees and placed at the coordinates (3,3).
So far so good.
Example 3: A Rectangle That Gets Smaller
Next, let’s introduce recursion by calling a shape within itself to create more interesting patterns.
We’ll make a rectangle that gradually shrinks as it moves upward. To do this, we’ll call the shape RECTANGLE
inside itself and adjust both its vertical position (y) and size.
startshape RECTANGLE
shape RECTANGLE
rule {
SQUARE []
RECTANGLE [y 0.95 s 0.97]
}
In this example, the RECTANGLE
shape draws a square and then recursively calls itself with a slight upward shift (y 0.95) and a smaller scale (s 0.97). This recursion creates a series of squares that progressively shrink and climb upwards, forming a stacked, diminishing square pattern.
🚀 Note: In Context Free Art, positive values for y move shapes upward, while negative values move them downward. Here, y 0.95 moves each square up by 0.95 units, causing it to stack above the previous shape.
One rule - Rectangle gets progressively smaller as the y coordinate increases
The recursion ends when the generated shape reaches a minimum size, at which point the program stops further recursion and yields the final result.
This self-limiting recursion is what gives Context Free Art its magical ability to create intricate, organic patterns from simple instructions.
Source: Giphy
Example 4: A Splitting Rectangle
Now, let’s make the rectangle “branch out” as it gets smaller, creating a pattern with splits.
startshape RECTANGLE
shape RECTANGLE
rule {
SQUARE []
RECTANGLE [y 0.95 s 0.97]
}
rule 0.03 {
RECTANGLE [r 45 s 0.5]
RECTANGLE [r -45 s 0.5]
}
Branching - adding a second rule
In this example we have two rules:
-
The first rule draws a square and then calls RECTANGLE recursively, moving it slightly up (y 0.95) and making it a bit smaller (s 0.97).
-
The second rule, specified with a 3% probability (rule 0.03), occasionally causes the rectangle to “split” into two smaller rectangles.
- One rectangle rotates 45 degrees to the right (r 45) and scales down to half its size (s 0.5).
- The other rectangle rotates 45 degrees to the left (r -45) and also scales down to half its size.
In other words: on each iteration 97% of the time the rectangle is made smaller and is merely shifted upwards, as defined by our first rule. But a 3% of the time, two new rotatedRECTANGLE shapes are made. This introduces branching!
Example 5: Creating Generative Trees 🌱
Now that we have a basic understanding of shapes, rules, and recursion, we are ready for a more complete example with more shapes, each with a different set of rules.
startshape SPIKE
// CF::Symmetry = CF::Dihedral, 2
shape SPIKE
rule {
SQUARE []
SPIKE [y 0.95 s 0.97]
}
rule 0.03 {
CIRCLE []
SPIKE [r 90 f 2]
SPIKE [r -90]
}
rule 0.03 {
tree[]
}
shape tree
rule 20 {
SQUARE[]
tree [s .99 y .995 r 2]
}
rule 1 {
SQUARE[]
tree [r 10 s .8 y .995 b .07 z - .07]
tree [r 10 s .8 y .995 f 90 b .01 z -.01]
}
rule 1 {
SQUARE[]
tree [s .99 y .995 f 90]
tree [r 10 s .5 y .995 b .07 z -.07]
tree [r 10 s .5 y .995 f 90 b .01 z -.01]
}
rule 10 {
SQUARE[]
tree [s .99 y .995 r 2 f 90]
}
The result is a symmetrical, tree-like structure with spikes and branches, achieved through recursive scaling, positioning, and low-probability branching rules.
The added recursions inside the shape SPIKE enhance the complexity of the paths generated
- Starting Shape: SPIKE is the main shape, which recursively draws a SQUARE that scales down (s 0.97) and moves up (y 0.95) with each iteration, forming a stacked effect.
- Variation Rules: Occasionally, a CIRCLE shape and side branches are added by rotating SPIKE 90° and -90° to create lateral spikes. Another rule introduces the tree shape, adding variety to the main structure.
- Shape tree: The tree shape adds branching with multiple rules.
Example 6: Introducing Symmetry 🪞
One simple way to make complex patterns even more visually appealing is by introducing symmetry.
If you uncomment this line in the code above:
startshape SPIKE
CF::Symmetry = CF::Dihedral, 2
(...)
And run the code again. We add dihedral symmetry along the center, mirroring the design and creating a balanced, organic look.
Dihedral symmetry mirrors the design along a central axis, creating balanced and intricate patterns. In this case CF::Symmetry = CF::Dihedral, 2
This symmetry function is powerful for generating intricate, natural-looking patterns. You can further experiment by increasing the symmetry value to 3, 4, or higher, which creates unique and interesting structures with each increment.
CF::Symmetry = CF::Dihedral, 5
The best part? Each time you run the code, it generates a different version of the design, so you’ll end up with a new variation each time — keeping the imagery fresh and surprising!
Thanks for reading, and happy experimenting!
We’ve covered a lot, from creating simple shapes and recursive patterns to adding symmetry for intricate, eye-catching designs. Context Free is a fantastic playground for anyone curious about generative art.
🎨 It’s simple to pick up, and the results are endlessly surprising. There’s something magical about watching a few lines of code come alive with every render, creating new, one-of-a-kind designs every time.
Still, we have barely scratched the surface, if you would like to learn more have look at the wiki!