Let’s draw some squares!
Last week I introduced Clojure as a possible replacement for Javascript for my generative art pursuits. Clojure has the Quil library that provides many of the same capabilities that p5.js provides to Javascript. Let’s look at a simple example. This Javascript/p5.js program generates an image like the one at the top of this post.
function setup() {
createCanvas(800, 800);
background(240);
stroke(0);
let size = 500;
let offset = 50;
let centerX = width/2;
let centerY = height/2;
let topLeftX = centerX - size/2;
let topLeftY = centerY - size/2;
fill(200, 150, 250, 150);
rect(topLeftX, topLeftY, size, size);
rect(topLeftX-offset, topLeftY-offset, size, size);
rect(topLeftX+offset, topLeftY+offset, size, size);
}
The program is fairly simple: create the canvas, fill in the background with grey, set the stroke (line) color to black, set the fill color, and draw three rectangles slightly offset from each other. If you’ve been following along with my previous posts, this looks pretty basic. The only remotely tricky thing going on here is that the fill()
function has a fourth parameter. The first three set the red, green and blue components of the fill color, while the fourth sets the transparency. This is what allows us to see the through the squares, and is what causes the gradations of color where the squares overlap.
Now here is a Clojure program doing exactly the same thing.
(ns my_clj.square
(:require [quil.core :as q]))
(defn setup []
(q/background 240)
(q/stroke 0)
(let [size 500
offset 50
center-x (/ (q/width) 2)
center-y (/ (q/height) 2)
top-left-x (- center-x (/ size 2))
top-left-y (- center-y (/ size 2))]
(q/fill 200 150 250 150)
(q/rect top-left-x top-left-y size size)
(q/rect (- top-left-x offset) (- top-left-y offset) size size)
(q/rect (+ top-left-x offset) (+ top-left-y offset) size size)))
(defn -main [& args]
(q/defsketch squares
:title "Squares"
:setup setup
:size [800 800]))
Well that looks very different! But, the differences are mostly the differences between Javascript and Clojure, not in the commands doing the drawing. If you look closely, you’ll see a one-to-one correspondence between the drawing commands between the two programs in almost every case. “Almost”, because there is no equivalent to the createCanvas()
function in Clojure; instead, the canvas size is set is the -main
function at the bottom of the program. Other than that, the drawing commands are the same: they have the same names (other than having “q/” prepended to then, which I’ll get to in a second), and they take the same parameters. How you define those parameters looks different, but if you understand what’s going on in the first program, you can follow along what’s going in the second. Because p5.js and Quil are both based on
Processing
, they are very similar in how they are used.
So, why do all the drawing commands have “q/” in from of their names? Look up at the top of the program at the first two lines. This sets the namespace (ns
) to “my_clj.square”, and then imports the “quil.core” library into that namespace. The “:as q” part lets us refer to to “quil.core” as “q”. Without that, we’d have to write functiions like quil.core/fill
. There is also a way to import the “quil.core” in such a way that the Quil functions become part of the namespace, and you don’t even have to add “q/”. That saves a little typing at the expense of possible conflicts (what if I have two libraries to import, and both have a function named fill
? What if I want to write a function named fill
as part of my program?) Actually, Javascript with p5.js has a similar feature: using p5.js the way I have always shown in these posts imports the function names directly into the namespace, but there is also a process called
instantiation
which provides a way to separate those functions out. You would want to do this, for example, if you wanted to set up a web page with more than one p5.js sketch running on it.
Another thing worth noting is that the Clojure program above is not very useful by itself. It exists as part of a system of files making up the program.
[my-clj] $ tree
.
├── LICENSE
├── README.md
├── project.clj
└── src
└── my_clj
└── square.clj
2 directories, 4 files
Of course this is a very simple program, so there is not all that much going on there. The project.clj
is important, as it describes the program so the compiler knows what to do with it. The src
directory holds the files for the program itself, and directory structure under src
defines the namespaces used in the program. Our program uses the namespace “my_clj.square”, so it can be found in the file src/my_clj/square.clj
. This program structure can all be set up manually, of course, but there is a utility program called
Leiningen
which will do it for you. The Javascript version didn’t stand on its own either – since it ran in a web browser, it required at least an HTML file to start it up. When I talk about programs, I’ll generally be ignoring the support files, but they will always be required.
Go ahead and make any changes you want to the Clojure program to see what you can get it to do, if you are so inclined! There are many Quil functions to try out. Have fun!