# Painting with functions

Table of Contents

Functions are everywhere in programming. If you’re confused by the concept, it makes sense to take some time to understand them now, and save yourself from a lot of pain.

In its simplest form, a function is a reusable sequence of instructions. A label for lines of code.

InstructionsLink to heading

An instruction is the programmer telling the computer to do something.

If you tell your dog to sit, or bark, or shake, that’s an instruction.

We’ll start with a computer that already knows how to draw simple shapes:

// This grey text is a "comment".
// It's just for you to read, it has
//  no effect on the program.

// This is an instruction! Draw a:
rectangle(100, 200, 150, 250, 'red');
//          x,   y,   w,   h, color

// It says: draw a rectangle:
//  100 pixels from the left (x)
//  200 pixels from the top (y)
//  150 pixels width (w)
//  250 pixels height (h)
//  in red (color)

By the end of the article, you’ll be able to make relatively complex paintings using these simple shapes, by combining them using functions.

Let’s get to know what instructions we can work with.

ShapesLink to heading

// rectangle(x, y, width, height, color)
rectangle(100, 100, 400, 100, 'red');

// circle(x, y, radius, color)
circle(200, 300, 50, 'blue');
// x and y specify the center.

// triangle(x, y, w, h, color)
triangle(400, 400, 200, 150, 'green');
// x and y specify center of base.
// w is width of base.

We can draw rectangles, circles, and triangles. What we put in the parentheses is information about where to draw them, and what color.

In the editor above, change the numbers until you understand what they do. Don’t continue until you can make the circle fit inside the rectangle!

ComposingLink to heading

What can we do with this? A whole lot!

Let’s combine 2 instructions, and draw a tree:

// a trunk
rectangle(280, 300, 40, 100, 'chocolate');

// the leaves
triangle(300, 300, 200, 200, 'green');

// optional:
// - Edit this to make your own tree!
// - E.g. can you add christmas ornaments?

Looks lonely! Let’s make it a little smaller, and add a few more trees:

// left tree
rectangle(290 - 150, 300, 20, 50, 'chocolate');
triangle(300 - 150, 300, 100, 100, 'green');

// center tree
rectangle(290, 300, 20, 50, 'chocolate');
triangle(300, 300, 100, 100, 'green');

// right tree
rectangle(290 + 150, 300, 20, 50, 'chocolate');
triangle(300 + 150, 300, 100, 100, 'green');

See how, to move an exact copy 150 pixels to the right, we just add 150 to the x coordinates (how far to the right it is). We subtract to go left.

Apart from that x-shifting, the rest of the code is the same for all the trees.

Writing the same code with some small variations gets tedious over time: say I wanted 10 trees, that’s a lot to write or copy paste!

GeneralizingLink to heading

That’s where functions come in: they get rid of this repetitiveness.

Let’s start with that center tree:

// left tree
rectangle(290 - 150, 300, 20, 50, 'chocolate');
triangle(300 - 150, 300, 100, 100, 'green');

// center tree. Now a function!
tree();

// right tree
rectangle(290 + 150, 300, 20, 50, 'chocolate');
triangle(300 + 150, 300, 100, 100, 'green');

function tree() {
  rectangle(290, 300, 20, 50, 'chocolate');
  triangle(300, 300, 100, 100, 'green');
}

We turned the center tree into function tree() { ... }, and executed the lines inside it with tree().

We have defined the tree function as drawing a rectangle and a triangle, in a tree layout, just like we did before.

You can see the result is indistinguishable! It’s exactly the same picture.

Let’s try to replace our other trees, to avoid the repetitiveness:

// left tree (expected)
tree(); // goes in the center instead!

// center tree
tree();

// right tree (expected)
tree(); // goes in the center instead!

function tree() {
  rectangle(290, 300, 20, 50, 'chocolate');
  triangle(300, 300, 100, 100, 'green');
}

That’s a problem: the program drew 3 trees, but they’re all on top of each other.

The rectangles and triangles for each tree are drawn at exactly the same positions, there’s nothing to tell each tree that it should be to the left or to the right (-150 and +150).

The function we created is not very useful if it always draws the tree in the same place. Let’s fix that.

tree(-150); // left tree
tree(0); // center tree
tree(+150); // right tree

function tree(offset) {
  // centered on 300 + offset
  rectangle(290 + offset, 300, 20, 50, 'chocolate');
  triangle(300 + offset, 300, 100, 100, 'green');
}

When we define a function, we can declare parameters (sometimes called arguments) to specify variations: changes in the code that will be run.

To know what value to use as the offset, we look at how the function is used, e.g. tree(150) means that:

  • the offset will be 150, so
  • 290 + offset will be 290 + 150 = 440

And 440 pixels from the left edge is where the rectangle for the trunk of the right tree starts.

The tree function now knows where to put its rectangle and triangle, based on the offset parameter.

SimplifyingLink to heading

It’s more intuitive to say “put a tree at x=450” than “put a tree 150 pixels after 300 pixels”.

We can make both our function and our usage simpler, by allowing tree(x) to put the tree directly at x rather than 300 + x:

tree(100);
tree(300);
tree(500);

function tree(x) {
  // centered on x
  rectangle(x - 10, 300, 20, 50, 'chocolate');
  triangle(x, 300, 100, 100, 'green');
}

Now tree(100) creates a tree whose center is 100 pixels from the left.

And we can do the same for y:

tree(100, 350);
tree(300, 350);
tree(500, 350);

// now we can fit more!
tree(200, 300);
tree(400, 300);

function tree(x, y) {
  // centered on x, rooted at y.
  rectangle(x - 10, y - 50, 20, 50, 'chocolate');
  triangle(x, y - 50, 100, 100, 'green');
}

You can now use tree as an instruction!.

Functions are themselves instructions, and can be used in other functions.

For example, we can make a forest function that uses our new tree function, several times.

forest(350)

function forest(y) {
  tree(100, y);
  tree(300, y);
  tree(500, y);

  tree(200, y - 50);
  tree(400, y - 50);
}
function tree(x, y) {
  rectangle(x - 10, y - 50, 20, 50, 'chocolate');
  triangle(x, y - 50, 100, 100, 'green');
}

This produces exactly the same result as our previous example.

But it’s now in a function, which means we can have more fun with less effort!

forest(350)
// more forests!
forest(525)
forest(175)

function forest(y) {
  tree(100, y);
  tree(300, y);
  tree(500, y);

  tree(200, y - 50);
  tree(400, y - 50);
}
function tree(x, y) {
  rectangle(x - 10, y - 50, 20, 50, 'chocolate');
  triangle(x, y - 50, 100, 100, 'green');
}

Imagine how many lines of code that would be if we didn’t use functions!

It’s 15 rectangles and 15 triangles, all with different positions. It would be a mess:

rectangle(90, 300, 20, 50, 'chocolate');
triangle(100, 300, 100, 100, 'green');
rectangle(290, 300, 20, 50, 'chocolate');
triangle(300, 300, 100, 100, 'green');
rectangle(490, 300, 20, 50, 'chocolate');
triangle(500, 300, 100, 100, 'green');
rectangle(190, 250, 20, 50, 'chocolate');
triangle(200, 250, 100, 100, 'green');
rectangle(390, 250, 20, 50, 'chocolate');
triangle(400, 250, 100, 100, 'green');
rectangle(90, 475, 20, 50, 'chocolate');
triangle(100, 475, 100, 100, 'green');
rectangle(290, 475, 20, 50, 'chocolate');
triangle(300, 475, 100, 100, 'green');
rectangle(490, 475, 20, 50, 'chocolate');
triangle(500, 475, 100, 100, 'green');
rectangle(190, 425, 20, 50, 'chocolate');
triangle(200, 425, 100, 100, 'green');
rectangle(390, 425, 20, 50, 'chocolate');
triangle(400, 425, 100, 100, 'green');
rectangle(90, 125, 20, 50, 'chocolate');
triangle(100, 125, 100, 100, 'green');
rectangle(290, 125, 20, 50, 'chocolate');
triangle(300, 125, 100, 100, 'green');
rectangle(490, 125, 20, 50, 'chocolate');
triangle(500, 125, 100, 100, 'green');
rectangle(190, 75, 20, 50, 'chocolate');
triangle(200, 75, 100, 100, 'green');
rectangle(390, 75, 20, 50, 'chocolate');
triangle(400, 75, 100, 100, 'green');

Not only would it be harder to tell what’s going on just by reading the code (are those trees, or pistacho chocolate bars?), but it would also be more time consuming to make changes.

Imagine we wanted to change the color of our tree trunk to brown: we’d have to change 15 lines, instead of just 1 in the tree function!

Hopefully you now understand why functions are in your best interest, even if it seems like an extra step.

LibraryLink to heading

To achieve something complex, you want to have a few good functions available.

Sometimes you might find that someone else already wrote some functions for you to use. In programming, we call this a library: a reusable source of knowledge we can leverage.

So let’s build a library for your drawing needs!

We already have functions for trees and forests, let’s add more.

BackdropLink to heading

Every painting needs a backdrop.

This doesn’t need to be a function, as we only need one backdrop, but “drawing the backdrop” is a reasonable instruction to make our life easier, later.

backdrop();

function backdrop() {
  // sky
  rectangle(0, 0, 600, 500, 'aqua');
}

We drew the sky.

A rectangle that fills the screen: starts at the top left corner (0, 0), and is the same size as the canvas (600 wide, and 500 pixels high).

Or is it an ocean, or a lake? Adding a sun would help clarify that.

backdrop();

function backdrop() {
  // sky
  rectangle(0, 0, 600, 500, 'aqua');

  // sun
  circle(500, 100, 30, 'yellow');
}

Note that the sun circle can go on top of the sky rectangle.

Instructions happen in a sequence, order matters: if you first draw a blue rectangle, and then a yellow circle on top, you can see the yellow circle.

If you do it the other way around, the rectangle covers the circle and you don’t see it. You can try it, by putting the rectangle after the circle in the editor above.

Now we just need some surface to put trees on:

backdrop();

function backdrop() {
  // sky
  rectangle(0, 0, 600, 500, 'aqua');

  // sun
  circle(500, 100, 30, 'yellow');

  // ground/grass
  rectangle(0, 250, 600, 250, 'olivedrab');
}

We have a backdrop! Let’s see how we would use it.

Adding the trees is as easy as calling (executing) our tree function:

backdrop();
tree(100, 380);
tree(200, 350);
tree(250, 465);

function backdrop() {
  // sky
  rectangle(0, 0, 600, 500, 'aqua');

  // sun
  circle(500, 100, 30, 'yellow');

  // ground/grass
  rectangle(0, 250, 600, 250, 'olivedrab');
}

function tree(x, y) {
  rectangle(x - 10, y - 50, 20, 50, 'chocolate');
  triangle(x, y - 50, 100, 100, 'green');
}

Let’s remove the trees for now, and work on another function in our library.

CloudLink to heading

Clouds look nice in paintings! Especially when they’re all puffy.

A simple way to approximate a puffy shape, is with a few circles:

backdrop();
cloud(150, 150);

function cloud(x, y) {
  // big center puff
  circle(x, y, 20, 'white');

  // small left puff
  circle(x - 20, y + 10, 10, 'white');

  // medium right puff
  circle(x + 20, y + 5, 15, 'white');
}


function backdrop() {
  // sky
  rectangle(0, 0, 600, 500, 'aqua');

  // sun
  circle(500, 100, 30, 'yellow');

  // ground/grass
  rectangle(0, 250, 600, 250, 'olivedrab');
}

That looks nice! A cloud centered on x=150, and y=150

Once we have the function for it, we can add as many clouds as we like, with little effort:

backdrop();
cloud(100, 50);
cloud(150, 100);
cloud(250, 50);

function cloud(x, y) {
  // big center puff
  circle(x, y, 20, 'white');

  // small left puff
  circle(x - 20, y + 10, 10, 'white');

  // medium right puff
  circle(x + 20, y + 5, 15, 'white');
}


function backdrop() {
  // sky
  rectangle(0, 0, 600, 500, 'aqua');

  // sun
  circle(500, 100, 30, 'yellow');

  // ground/grass
  rectangle(0, 250, 600, 250, 'olivedrab');
}

MountainLink to heading

The most visually pleasing paintings, in my opinion, are landscapes with mountains.

So here’s a simplified mountain: two overlapping triangles.

Let’s make a function with it:

backdrop();
mountain(200, 250);

function mountain(x, y) {
  // base
  triangle(x, y, 120, 100, 'saddlebrown');

  // snow cap
  triangle(x, y - 50, 60, 50, 'white');
}


function backdrop() {
  // sky
  rectangle(0, 0, 600, 500, 'aqua');

  // sun
  circle(500, 100, 30, 'yellow');

  // ground/grass
  rectangle(0, 250, 600, 250, 'olivedrab');
}

Once again, now that we have the function for one mountain, we can add multiple mountains!

backdrop();
mountain(200, 250);
mountain(50, 250);
mountain(100, 250);


function mountain(x, y) {
  // base
  triangle(x, y, 120, 100, 'saddlebrown');

  // snow cap
  triangle(x, y - 50, 60, 50, 'white');
}
function backdrop() {
  // sky
  rectangle(0, 0, 600, 500, 'aqua');

  // sun
  circle(500, 100, 30, 'yellow');

  // ground/grass
  rectangle(0, 250, 600, 250, 'olivedrab');
}

This doesn’t look great because the mountains are all the same size, but that’s a problem for a future article.

If you’d like some practice, see what you can do about it!

hint: add a h parameter to mountain

HouseLink to heading

We have methods to draw the sky, a sun, grass, trees, and mountains.

A house would fit well!

This will be our most complex drawing element yet. Let’s construct it step by step:

backdrop();
house(300, 300);

function house(x, y) {
  // walls
  rectangle(x - 50, y - 75, 100, 75, 'lightgrey');

  // roof
  triangle(x, y - 75, 120, 40, 'brown');
}


function backdrop() {
  // sky
  rectangle(0, 0, 600, 500, 'aqua');

  // sun
  circle(500, 100, 30, 'yellow');

  // ground/grass
  rectangle(0, 250, 600, 250, 'olivedrab');
}

That’s a very basic house, let’s add a door and a doorknob:

backdrop();
house(300, 300);

function house(x, y) {
  // walls
  rectangle(x - 50, y - 75, 100, 75, 'lightgrey');

  // roof
  triangle(x, y - 75, 120, 40, 'brown');

  door(x - 15, y);
}
function door(x, y) {
  // door
  rectangle(x - 12.5, y - 40, 25, 40, 'peru');

  // doorknob
  circle(x - 6, y - 20, 3, 'saddlebrown');
}


function backdrop() {
  // sky
  rectangle(0, 0, 600, 500, 'aqua');

  // sun
  circle(500, 100, 30, 'yellow');

  // ground/grass
  rectangle(0, 250, 600, 250, 'olivedrab');
}

Once you have one house, you can have as many houses as you can fit, with little extra effort!

backdrop();
house(300, 300);
house(150, 400);
house(450, 350);

function house(x, y) {
  // walls
  rectangle(x - 50, y - 75, 100, 75, 'lightgrey');

  // roof
  triangle(x, y - 75, 120, 40, 'brown');

  door(x - 15, y);
}
function door(x, y) {
  // door
  rectangle(x - 12.5, y - 40, 25, 40, 'peru');

  // doorknob
  circle(x - 6, y - 20, 3, 'saddlebrown');
}

function backdrop() {
  // sky
  rectangle(0, 0, 600, 500, 'aqua');

  // sun
  circle(500, 100, 30, 'yellow');

  // ground/grass
  rectangle(0, 250, 600, 250, 'olivedrab');
}

All togetherLink to heading

We’ve built a library of shapes to use in a painting, now it’s just a matter of drawing the painting we want!

Let’s start by drawing one of each shape, so we know what we’re working with:

// Our top-level instructions.
// These alone give a good idea about
//  what the program is doing

backdrop();

cloud(100, 100);
mountain(200, 250);

tree(150, 450);
house(450, 350);

// Our function definitions.
// These are "details" on how to implement
//  the top-level instructions

function backdrop() {
  // sky
  rectangle(0, 0, 600, 500, 'aqua');

  // sun
  circle(500, 100, 30, 'yellow');

  // ground/grass
  rectangle(0, 250, 600, 250, 'olivedrab');
}
function cloud(x, y) {
  // big center puff
  circle(x, y, 20, 'white');

  // small left puff
  circle(x - 20, y + 10, 10, 'white');

  // medium right puff
  circle(x + 20, y + 5, 15, 'white');
}
function mountain(x, y) {
  // base
  triangle(x, y, 120, 100, 'saddlebrown');

  // snow cap
  triangle(x, y - 50, 60, 50, 'white');
}
function tree(x, y) {
  rectangle(x - 10, y - 50, 20, 50, 'chocolate');
  triangle(x, y - 50, 100, 100, 'green');
}
function house(x, y) {
  // walls
  rectangle(x - 50, y - 75, 100, 75, 'lightgrey');

  // roof
  triangle(x, y - 75, 120, 40, 'brown');

  door(x - 15, y);
}
function door(x, y) {
  // door
  rectangle(x - 12.5, y - 40, 25, 40, 'peru');

  // doorknob
  circle(x - 6, y - 20, 3, 'saddlebrown');
}

Now we can re-use them and lay them out as needed.

backdrop();

cloud(100, 50);
cloud(150, 100);
cloud(250, 50);

mountain(200, 250);
mountain(50, 250);
mountain(100, 250);

tree(70, 380);
tree(210, 360);
tree(130, 420)
tree(250, 465);

house(450, 350);


function backdrop() {
  // sky
  rectangle(0, 0, 600, 500, 'aqua');

  // sun
  circle(500, 100, 30, 'yellow');

  // ground/grass
  rectangle(0, 250, 600, 250, 'olivedrab');
}
function cloud(x, y) {
  // big center puff
  circle(x, y, 20, 'white');

  // small left puff
  circle(x - 20, y + 10, 10, 'white');

  // medium right puff
  circle(x + 20, y + 5, 15, 'white');
}
function mountain(x, y) {
  // base
  triangle(x, y, 120, 100, 'saddlebrown');

  // snow cap
  triangle(x, y - 50, 60, 50, 'white');
}
function tree(x, y) {
  rectangle(x - 10, y - 50, 20, 50, 'chocolate');
  triangle(x, y - 50, 100, 100, 'green');
}
function house(x, y) {
  // walls
  rectangle(x - 50, y - 75, 100, 75, 'lightgrey');

  // roof
  triangle(x, y - 75, 120, 40, 'brown');

  door(x - 15, y);
}
function door(x, y) {
  // door
  rectangle(x - 12.5, y - 40, 25, 40, 'peru');

  // doorknob
  circle(x - 6, y - 20, 3, 'saddlebrown');
}

It’s not going to win any art competitions, but that’s not the point!

We made a small project with some complexity, out of simple building blocks, thanks to functions.

ConclusionLink to heading

Functions are sequences of instructions, that we can label and reuse.

They are smaller programs (e.g. drawing only a house) inside our bigger program (e.g. drawing the whole painting), that help us keep our code easier to write, understand, and modify.

What we’ve been working with isn’t a “dumbed down” version of functions. This is what it looks like in “real” code too!

Our instructions have exclusively been about drawing rectangles, circles, triangles, and other groups of them, e.g. door(x, y), but our program is by all means a real program, these are real instructions that come from a library of basic shapes.

What next?Link to heading

You have now understood the concept of functions, which is the important part.

If this was new to you, I recommend you take some time to internalize the concept. Use the editor below and make your own unique painting!

// Make your own painting!

// rectangle(x, y, width, height, color);
// triangle(x, y, width, height, color);
// circle(x, y, radius, color);
// function newInstructionName(x, y) { ... }

// WARNING:
//  Your code will be lost if you refresh or close
//  this page.
//
// To save your code and the drawing
// - click on "Open Sandbox" in the bottom right
// - copy the URL
// - store it somewhere, or share it with the
//   community in the comments at the bottom
//
// Feel free to delete these grey lines

I’m working on new articles so you can learn about loops with the same setup, hold tight!

In the meantime, you can have a look at these (more advanced) resources:

My avatar

You did it! You finished the article!

Interested in learning more?
Read my other posts, or book a 1:1 session


More Posts

Comments