Procedures are powerful creative tools. Defining procedures for creating form allows artists to focus on creative intent, reduce tedium, build higher scales of complexity, and explore otherwise impossible ideas.
p5.js
Simply put, a procedure is a set of instructions, and computational form is any image, sound, or other form generated by following a procedure. Working with procedures places the emphasis on defining processes rather than results, enabling new aesthetics and applications.
Artists ranging from Sol Lewitt to Yoko Ono have explored the conceptual and aesthetic implications of generative art. The increasing prevalence of digital fabrication and short-run manufacturing has driven interest in parametric design. Procedurally generated content is widely used in the video game industry to create worlds far too complex to craft by hand. The world wide web is a digital-native platform where procedures are commonly used to generate up-to-date, personalized content.
Consider the advantages and disadvantages of using procedures to generate form.
Doing simple, repetitious work by hand is tedious and very prone to simple errors. Following defined procedures makes errors less likely and well-defined procedures can often be automated completely by computers.
The process of defining a computer program to create form is often initially slower than creating the form directly by hand. But once the program is completed it can be very fast to try many variations.
Practical concerns often limit how much detail can be included in manually created form. Working with procedures allows extremely—even infinitely—detailed compositions to be created.
Creating form through procedures shifts the artist’s perspective and can lead to novel, creative approaches to problems.
Because procedures can be executed quickly and tirelessly by computers, it is possible to create systems that produce unique variations for every viewer.
Draw a Sierpinski triangle with pencil and paper.
The Sierpinski Triangle is a fractal. It is infinitely detailed and self-similar. There are many, many ways to generate a Sierpinski triangle. The amazing Sierpinski triangle page to end most Sierpinski triangle pages details dozens of them. Here is yet another.
Please take out a sheet of paper and a pen and follow these instructions:
Yes, these instructions will go on forever. Stop after a few minutes.
Computational Form doesn’t necessarily require computers or computer programming. Artists have been experimenting with generative concepts since before computers even existed and artists still write instructions and then carry them out themselves manually. But computers are an exceptionally powerful tool for exploring procedural generation and computational form. They are fast, accurate, predictable, and reliable and they don’t complain about tedious tasks.
This site explores a variety of computer languages and tools that can be used to create form computationally. Many of the examples—including those in this chapter—are written using p5.js. For a quick introduction to p5.js, see the Hello, p5! chapter and the p5.js website.
Here is a simple example of a p5.js program that draws a house.
This is a fairly simple program. It is mostly a series of fill
, rect
, and triangle
commands to specify colors and draw shapes. This program demonstrates the indirect nature of drawing with code. If we wanted the grass to be a darker green, we wouldn’t change it directly. Instead, we would alter the program and then completely redraw the image using the new instructions.
At first, this indirect way of working can feel cumbersome. It would be easier to create and alter this drawing in a program like Adobe Illustrator. But even a slightly more sophisticated program begins to show the power afforded by working with procedures.
This example is only a little more complex but instead of drawing one specific house, can generate many, many variations. The procedure used here introduces a few new concepts like making decisions based on random numbers and mixing colors, but the flow of the program is still straight down from top to bottom.
As procedures begin to include looping
and conditional branching
they become much more powerful and even a short program can produce complex, detailed form. The following program draws a Sierpinski triangle using a completely different procedure from the one above.
When beginner and intermediate programmers run into trouble building more complex projects, they often hear this (bad) advice: Break your complex program into smaller parts, and solve those parts.
I’ve given this advice myself, but now I try not to. Very often this advice just isn’t helpful, especially for beginners. This advice falls short because it describes how the final program should be structured (results) rather than the how-to approach to developing it (process). In practice, programming almost always involves prototyping, backtracking, and refactoring. It is hard to understand a complex problem and it is hard to break complex problems down into parts. How big should the parts be? How do you build an individual part without the other parts it depends on? Once you have a few working parts, how do you put them together? With experience, these questions get easier to answer, but advanced programmers still frequently encounter problems they can’t initially understand well enough to break down. When this happens to you, you still have an option for getting started: Make a simpler program.
Imagine you want to make a game like pong, but you don’t know how. You could begin by trying to break it down into sub-tasks—keyboard-controlled paddles, an animated ball, a scoreboard—but it is very hard to plan all those pieces all at once. At the planning stage you will have a rough idea of how each piece should work, but you won’t know the details until you start building each piece. Without understanding the details, the pieces you make probably won’t fit together. You might end up with a lot of code that doesn’t work and that you don’t understand. It is much better to have a little bit of code that does work and that you do understand.
Instead, you could start with a very simple program: just draw a little square—the ball—on the screen. Build and run this program to make sure it works. Then start adding on. Make the ball move to the right. Don’t worry about the paddles or the score yet: focus on the ball. Make the square bounce when it hits the side. Then make it move diagonally. Make the ball bounce off all the sides. You might make dozens of incremental working programs as you get the basic ball working. As you do, take the time to review the code and make sure you understand how everything works.
Remember: it is much, much better to have a little bit of code you understand than a lot of code you don’t understand.
Working this way will let you discover the details of how your ball—an important piece of your program—works. These details will help you discover how that piece will connect with the others. As you start to build other elements—like the paddles or scoreboard—you might find out that you need to go back and change how the ball works. Expect to run into some dead ends, and expect the need to backtrack. Sure, this might have been avoided if you had made a complete, correct plan in the beginning, but in the beginning, you didn’t know enough to make a complete, correct plan.
The reason this strategy works is simple: instead of trying to do something you can’t, you try to do something you can.
A complex system that works is invariably found to have evolved from a simple system that worked. The inverse proposition also appears to be true: A complex system designed from scratch never works and cannot be made to work. You have to start over, beginning with a working simple system.
Gall’s Law
When designing a procedural generation system there are several properties to consider. The designer must balance these concerns and design a system that fits the goals of the project. As an example, consider execution speed. A newly-written procedure may run slowly, perhaps taking minutes or hours to generate an image. Usually, with effort, the procedure can be rewritten to run much more quickly, perhaps in just a few milliseconds. It probably wouldn’t be worth the effort to speed up the procedure if it is part of a tool that will only be used a few times, but the optimized procedure could be used in completely different ways.
The following properties are borrowed from the first chapter of Procedural Content Generation in Games, a great textbook on procedural generation that is available free online and in print.
Game Maker’s Toolkit is a Youtube channel that features high-quality video essays on game design. His video on the level generation in Spelunky is great.
The author of Spelunky, Derek Yu, wrote a fantastic book on making the game, along with a deeper dive into how the levels are procedurally generated. His blog post on finishing games is also great.
If you want to play Spelunky—which I highly recommend—the original version (not the HD Remake) is free.
Procedural Content Generation in Games Online Book A free online textbook that focuses on gaming applications.