# Defining setup() and draw() at runtime

**URL:** https://discourse.processing.org/t/defining-setup-and-draw-at-runtime/31728
**Category:** Coding Questions
**Created:** [August 14, 2021, 8:56pm UTC](https://discourse.processing.org/t/defining-setup-and-draw-at-runtime/31728 "2021-08-14T20:56:08Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![javagar](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/javagar/32/11434_2.png) [@javagar](https://discourse.processing.org/u/javagar)
#### Post date: [August 14, 2021, 8:56pm UTC](https://discourse.processing.org/t/defining-setup-and-draw-at-runtime/31728/1 "2021-08-14T20:56:08Z")

</div>

The following probably ought not be done, as it seems, at best, poor programming style. Perhaps, even worse, it could break in the future. However, as of this time, it does work without any obvious problem, so here goes, followed after the second example by a question …

The following randomly chooses between two different `setup()` functions at runtime, each designating a different canvas size, among other details:

```auto
function preload() {
  
  / ****randomly choose a setup function**** /
  
  switch (random([0, 1])) {
    case 0:
      setup = function () {
        createCanvas(377, 233);
        background(255, 64, 128);
        fill(255, 128);
        stroke(0);
        noLoop();
      };
      break;
    default:
      setup = function () {
        createCanvas(233, 144);
        background(255, 128, 64);
        fill(0, 128);
        stroke(255);
        noLoop();
      };
      break;
  }
}

function draw() {
  rect(5 * width / 16, height / 5, width / 2, height / 3);
  triangle(
    width / 2,
    height / 4,
    width / 4,
    (height * 3) / 4,
    (width * 3) / 4,
    (height * 3) / 4
  );
}

```

We have been warned about [Things That May Break Your 2.x Sketches](https://github.com/processing/processing/wiki/Changes-in-3.0#things-that-may-break-your-2x-sketches). Specifically, it was stated:

> **Do not use variables in `size()`** - This time we really mean it. …

Technically, the above example does not use variables in `size()`, but it does defer defining the dimensions of the canvas.

This second example randomly chooses between three different `draw()` functions at runtime:

```auto
function setup() {
  createCanvas(377, 233);
  noLoop();
  rectMode(CENTER);
  background(255, 255, 127);
  fill(255, 255, 255, 127);
  
  / ****randomly choose a draw function**** /
  
  switch (random([0, 1, 2])) {
    case 0:
      draw = function () {
        let nudge = width / 12;
        rect(width / 2 + nudge, height / 2, width / 2, height / 2);
        rect(width / 3 + nudge, height / 3, width / 2, height / 3);
      };
      break;
    case 1:
      draw = function () {
        let nudge = width / 12;
        ellipse(width / 2 + nudge, 3 * height / 5, width / 2, height / 2);
        rect(width / 3 + nudge, height / 3, width / 2, height / 3);
      };
      break;
    default:
      draw = function () {
        let nudge = width / 12;
        triangle(
          width / 2 + nudge,
          height / 4,
          width / 4 + nudge,
          (height * 3) / 4,
          (width * 3) / 4 + nudge,
          (height * 3) / 4
        );
        rect(width / 3 + nudge, height / 3, width / 2, height / 3);
      };
  }
}

```

Regarding both of these examples, there are obviously other means of accomplishing the same effects. But, here’s the question … Are there any circumstances at all under which it would be beneficial to choose between alternative definitions of `setup()` or `draw()` at runtime?

---

<div class="post-metadata">

### Author: ![KumuPaul](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kumupaul/32/13072_2.png) [@KumuPaul](https://discourse.processing.org/u/KumuPaul)
#### Post date: [August 15, 2021, 3:26am UTC](https://discourse.processing.org/t/defining-setup-and-draw-at-runtime/31728/2 "2021-08-15T03:26:31Z")

</div>

The caution about `size()` is specific to **processing**. It is not relevant for **p5.js**.

---

<div class="post-metadata">

### Author: ![KumuPaul](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kumupaul/32/13072_2.png) [@KumuPaul](https://discourse.processing.org/u/KumuPaul)
#### Post date: [August 15, 2021, 3:45am UTC](https://discourse.processing.org/t/defining-setup-and-draw-at-runtime/31728/3 "2021-08-15T03:45:00Z")

</div>

Declaring global `draw` and `setup` functions inside of the `preload()` function is not going to work because p5.js never calls `preload()` unless it finds a global `setup()`. However, you could declare your draw function within setup:

```auto
function setup() {
	createCanvas(windowWidth, windowHeight);
	angleMode(DEGREES);
	background(100);
	window.draw = random([draw1, draw2, draw3]);
}

function draw1() {
	circle(mouseX, mouseY, 20);
}

function draw2() {
	square(mouseX, mouseY, 20);
}

function draw3() {
	triangle(
		mouseX + cos(30) * 20,
		mouseY + sin(30) * 20,
		mouseX + cos(150) * 20,
		mouseY + sin(150) * 20,
		mouseX + cos(270) * 20,
		mouseY + sin(270) * 20
	);
}

```

You could even change the draw function while the sketch is running:

```auto
function setup() {
	createCanvas(windowWidth, windowHeight);
	angleMode(DEGREES);
	background(100);
	window.draw = random([draw1, draw2, draw3]);
	setInterval(
		() => {
			window.draw = random([draw1, draw2, draw3].filter(d => d !== window.draw));
		},
		2000
	);
	rectMode(CENTER);
}

function draw1() {
	fill('red');
	circle(mouseX, mouseY, 20);
}

function draw2() {
	fill('green');
	square(mouseX, mouseY, 20);
}

function draw3() {
	fill('blue');
	triangle(
		mouseX + cos(30) * 10,
		mouseY + sin(30) * 10,
		mouseX + cos(150) * 10,
		mouseY + sin(150) * 10,
		mouseX + cos(270) * 10,
		mouseY + sin(270) * 10
	);
}

```

If you want to declare everything (`preload`/`setup`/`draw`) at runtime, then I would suggest you use instance mode:

```auto
function mySketch(p) {
	p.setup = function setup() {
		p.createCanvas(p.windowWidth, p.windowHeight);
		p.background(100);
	}

	p.draw = function draw() {
		p.ellipse(p.mouseX, p.mouseY, 20, 20);
	}
}

function startSketch() {
	console.log('starting');
	window.sketchInstance = new p5(mySketch);
}

```

One reason you might do this would be if you wanted to create your sketch when the user clicks a button on your webpage (perhaps you want to have multiple sketches that the user can toggle between.

In general I think that any user who has gotten past the basics of JavaScript should be using instance mode because it is much more reflective of best practices in JavaScript.

* * *

As far as I can tell, there is no way to get p5.js to properly load if you only declare a global `setup()` function at runtime (i.e. in response to some user action or on a timer).

---

<div class="post-metadata">

### Author: ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)
#### Post date: [August 15, 2021, 3:57am UTC](https://discourse.processing.org/t/defining-setup-and-draw-at-runtime/31728/4 "2021-08-15T03:57:56Z")

</div>

> [@KumuPaul](#):
>
> , there is no way to get p5.js to properly load if you only declare a global `setup()` function at runtime

I use these 3 lines below to force p5.js to instantiate on global mode:

```auto
window.mocha = 'Hack to block p5.js auto global instantiation.';
new p5; // Prematurely instantiates p5.js so its props are available now.
window._setupDone = undefined; // Blocks duplicate instantiation warn.

```

An online example sketch using the trick above:

> **[Sierpinski Pentagon \[p5.js\] - GoToLoop - OpenProcessing](https://openprocessing.org/sketch/955445)**

---

<div class="post-metadata">

### Author: ![KumuPaul](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kumupaul/32/13072_2.png) [@KumuPaul](https://discourse.processing.org/u/KumuPaul)
#### Post date: [August 15, 2021, 4:08am UTC](https://discourse.processing.org/t/defining-setup-and-draw-at-runtime/31728/5 "2021-08-15T04:08:12Z")

</div>

Nice. That is quite the hack 😂. All that so you can use `cos()` at the top level?

---

<div class="post-metadata">

### Author: ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)
#### Post date: [August 15, 2021, 4:11am UTC](https://discourse.processing.org/t/defining-setup-and-draw-at-runtime/31728/6 "2021-08-15T04:11:16Z")

</div>

Yea! I totally coulda just used Math.**cos()** instead. 🙄  
But I’ve just wanted an opportunity to test the p5js premature instantiation. 😜

P.S.: Also needed to access constant DEG\_TO\_RAD. 😹

---

<div class="post-metadata">

### Author: ![javagar](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/javagar/32/11434_2.png) [@javagar](https://discourse.processing.org/u/javagar)
#### Post date: [August 15, 2021, 7:19am UTC](https://discourse.processing.org/t/defining-setup-and-draw-at-runtime/31728/7 "2021-08-15T07:19:22Z")

</div>

> [@KumuPaul](#):
>
> I would suggest you use instance mode …

Thanks - good advice. This creates a new `draw()` function whenever the mouse is released:

```auto
// create anonymous p5 instance
new p5(function(p) {
  p.setup = function() {
    p.createCanvas(p.windowWidth, p.windowHeight);
    p.background(255);
    p.noStroke();
    
    // create initial draw function
    p.draw = function() {
      p.textAlign(p.CENTER, p.CENTER);
      p.textSize(p.min(p.windowWidth, p.windowHeight) / 12);
      p.text("Click mouse\nto begin\na new drawing", p.width / 2, p.height / 2);
    };
  };

  p.mouseReleased = function() {
    p.background(127);
    
    // mouse release creates a new draw function
    p.draw = function() {
      let x = p.mouseX;
      let y = p.mouseY;
      p.fill(((x + y) % 32) * 8);
      p.ellipse(x, y, 8, 8);
    };
  };
  
});

```

---

<div class="post-metadata">

### Author: ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)
#### Post date: [August 27, 2021, 11:02pm UTC](https://discourse.processing.org/t/defining-setup-and-draw-at-runtime/31728/8 "2021-08-27T23:02:32Z")

</div>

> [@javagar](#):
>
> Are there any circumstances at all under which it would be beneficial to choose between alternative definitions of `setup()` or `draw()` at runtime?

A classic case where I see people trying to do things like this is sketch galleries / sketch portfolio loaders. There are many sketches – from a single person, or from students in a class, etc. – and the question is how to combine the existing draw function into either a slideshow or a pick-a-random-sketch frame populator.

The key element here is that the sketches to be combined / randomized already exist with separate draw functions – so the question of combining their contents is often “how little refactoring can I get away with and still make this work?”

---

<div class="post-metadata">

### Author: ![javagar](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/javagar/32/11434_2.png) [@javagar](https://discourse.processing.org/u/javagar)
#### Post date: [August 27, 2021, 11:26pm UTC](https://discourse.processing.org/t/defining-setup-and-draw-at-runtime/31728/9 "2021-08-27T23:26:17Z")

</div>

> [@jeremydouglass](#):
>
> … can I get away with …

Therein lies much of the fun of trying. 😀
