P5.js Hello

What Is This?

This is a post to remind me how to make p5.js posts. It's based on my somewhat idiosyncratic way of working (using Emacs' org-mode for the text-markup and nikola to render it as HTML) and is meant to help me get restarted if I stop using p5.js for a little while and need to remember how to do it. The short version:

The Setup

The next three sections in this post won't normally be visible in other posts, they're specific to my use of nikola and a noweb-like style with org-mode and will be in the source but won't be in the exported HTML.

The Meta-Header

To get p5.js into this post I'm telling nikola to use a template I made in the meta-data block at the beginning of the file for this post.

.. template: p5.tmpl

The p5.tmpl template adds an HTML tag to include the p5 JavaScript code in the HEAD section of the HTML document.

<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.min.js"></script>

The Tangle

Since the intent is to define the JavaScript in the org-mode blocks and then export it I'll typically create a tangle code block to control the export. The org-mode header uses a path relative to the org-mode file that makes up this post. This file is in a sub-folder (posts/) so the path has to go up one directory first then back down into the files/posts/ folder and then into another sub-folder whose name matches the slug for this post (p5js-hello). The folder named after the slug doesn't exist by default and won't be created by Emacs (it will just fail with a message in the Emacs mini-buffer when you export the file) so you need to create it before doing the export.

The tangle is made up of references to blocks that I'll be defining in later sections, referring to them using their name. For example, <<hello-div>> in this tangle will match an org-mode block named hello-div defined in a later section of this post.

#+begin_src js :tangle ../files/posts/p5js-hello/hello.js :exports none
<<hello-div>>

<<hello-class>>

<<hello-sketch>>

<<p5-instance>>
#+end_src

The DIV Shortcode

In order to specify where in this post the p5.js sketch will be rendered I need to create an HTML source tag which points to the JavaScript file I created in the tangle section above (in this case the file is hello.js ). I also want to create a div tag with an ID that I define so that I can tell p5.js to use it as the location for the sketch (in this case the ID will be "hello-08b095a8").

This is the jinja-based shortcode I use to put those two tags into the post.

{{% p5div  source="hello.js" divid="hello-08b095a8" %}}

The hello.js file will sit next to the HTML file for this post once we export it so you only want the file name, not the path to the folder it sits in. I'm mentioning it here because I sometimes get mixed up between the three cases I've run into for files:

  • files that need a path from this post (like the tangle)
  • files that need paths from the top of the repository (usually created using commands run outside of org-mode)
  • files that just need the file-name

When nikola builds the site it will convert that shortcode to a couple of tags that look something like:

<script source="hello.js">

<div class="p5js" id="hello-08b095a8"></div>

In the future I'll probably get rid of or change this shortcode, since the only thing it does that's specific to p5 is set the class attribute, but, for now, this is how it's getting done.

The JavaScript

The remaining sections define the JavaScript that gets exported into the tangle file that I defined in the first section of this post.

The Div ID

Since I need to pass the ID given to the div tag in the previous section to P5 I'll store it in a variable for later.

const HELLO_DIV = "hello-08b095a8";

As noted above, the tangle refers to the JavaScript blocks I'm defining in the rest of the document by name (which I give to them in the block-headers using :noweb-ref). The header where I stick the name doesn't get exported into the HTML document so just for this block I'll show what it looks like with the org-mode header along with the JavaScript that goes into the block.

#+begin_src js :noweb-ref hello-div
const HELLO_DIV = "hello-08b095a8";
#+end_src

Here the :noweb-ref hello-div tells org-mode to stick the JavaScript into the tangle block above where the <<hello-div>> placeholder text is.

The Hello Class

Here's a toy class that keeps the parameters for the circle and which draws the circle when its draw method is called.

class Hello {
  constructor(p5, width, height, diameter, step) {
    this.p5 = p5;
    this.step = step;
    this.radius = 10;
    this.width = width;
    this.height = height;
    this.y = height/2;
    this.diameter = diameter;
    this.x = this.diameter + 1;
  }; //constructor

  draw() {
    this.p5.circle(this.x, this.y, this.diameter);
    if (this.x <= this.diameter || this.x >= this.width - this.diameter) {
      this.step *= -1;
    }; 
    this.x = (this.x + this.step) % this.width;
  }; // draw
}; // Hello

Hello Sketch

Here's the sketch that gets passed to the P5 constructor.

function hello_sketch(p5){
  const WIDTH = 800;
  const HEIGHT = WIDTH/4;
  const BACKGROUND = 255;
  const ALPHA = 50;
  const POINT_COLOR = "RoyalBlue";

  let HELLO;

  p5.setup = function() {
    p5.createCanvas(WIDTH, HEIGHT);
    p5.background(BACKGROUND);
    p5.stroke(POINT_COLOR);
    p5.fill(BACKGROUND);
    HELLO = new Hello(p5, WIDTH, HEIGHT, 50, 5);
  }; // setup

  p5.draw = function() {
    p5.background(BACKGROUND, ALPHA);
    HELLO.draw();
  }; //draw
}; // hello_sketch

P5 Object

Finally, I'll create a p5 object, giving it the sketch and div ID so p5.js will render the code.

new p5(hello_sketch, HELLO_DIV);

If we go back to the top we should see the sketch running (a circle moving back and forth) .

The End

And that's it for the basic post. The parts once again: