CodingTrain / CodingTrain/node-p5-test

Using p5.js in Node runtime

Open
#1 3 comments 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
7
Forks
1
PR merge metrics
No merged PRs in 30d

Description

## TL;DR: scroll down to the bottom for the templates
---

After studying the source code of [`p5.js`](https://github.com/processing/p5.js), this is what I have gathered so far:

> [These](https://gist.github.com/ccf46106d311bb7dd93fea40c634eece) variables are available in browser `window` and unavailable in node

## p5 Instance Mode

For making p5 work in instance mode I created this template:

```js
// Adapted from:
// ! Heart Curve
// ! Daniel Shiffman
// https://thecodingtrain.com/CodingChallenges/134-heart-curve.html
// https://youtu.be/oUBAi9xQ2X4
// https://editor.p5js.org/codingtrain/sketches/egvieHyt0

const w = 400,
h = 400;
setupWindow(w, h);

const p5 = require("p5");

new p5((p) => {
const heart = [];
let a = 0;
p.setup = () => {
p.createCanvas(w, h);
while (true) {
const r = p.height / 40;
const x = r * 16 * p.pow(p.sin(a), 3);
const y = -r * (13 * p.cos(a) - 5 * p.cos(2 * a) - 2 * p.cos(3 * a) - p.cos(4 * a));
heart.push(p.createVector(x, y));
// So that it stops
if (a > p.TWO_PI) {
break;
}

a += 0.1;
}
p.background(0);
p.translate(p.width / 2, p.height / 2);

p.stroke(255);
p.strokeWeight(2);
p.fill(150, 0, 100);
p.beginShape();
for (let v of heart) {
p.vertex(v.x, v.y);
}
p.endShape();
saveAsPNG(p, "filename");
};
});

async function saveAsPNG(p5Inst, filename = "sketch", exit = true) {
// --- save as png function code ---
}

function setupWindow(w = 100, h = 100) {
// --- setup window function code ---
}
```
**In this way, p5.js can be used in Instance Mode to work with `node-canvas`**

Click here to see the codes for saveAsPNG and setupWindow:

**`saveAsPNG` - Saves the canvas Image to filname using fs**
```js
async function saveAsPNG(p5Inst, filename = "sketch", exit = true) {
const fs = require("fs");
const buffer = p5Inst._renderer.drawingContext.canvas.toBuffer()
await fs.promises.writeFile(filename + ".png", buffer)
if (exit) process.exit(0)
}
```
**`setupWindow` - Add necessary variables to `global` for p5 to run**
```js
function setupWindow(w = 100, h = 100) {
// Import required stuff
const { createCanvas } = require("canvas");
const { JSDOM } = require("jsdom");
const { performance } = require("perf_hooks");

// All the global properties will be available to p5
global.window = global;

// Use JSDOM to simulate DOM methods
const dom = new JSDOM();
global.document = dom.window.document;

const nodeCanvas = createCanvas(w, h);

// p5 will use the methods on nodeCanvas context (overriding JSDOM's getContext function)
dom.window.HTMLCanvasElement.prototype.getContext = (type) => {
return nodeCanvas.getContext(type);
};

// p5 uses window.performance
global.performance = performance;

// window.screen is used to determine displayWidth and displayHeight
// in this case it will be undefined
global.screen = {};

// p5 uses events "load" and "error"
// Using JSDOM equivalent
global.addEventListener = dom.window.addEventListener.bind(dom.window);
global.removeEventListener = dom.window.removeEventListener.bind(dom.window);

// Navigator.userAgent is used by p5 to polyfill methods in older browsers (safari)
global.navigator = { userAgent: "node" };

// when we declare a function in node, it doesn't pollute global scope
// So implicitly write code so that p5 can access these functions on global/window.
// UNCOMMENT NEXT TWO LINES WHEN USING GLOBAL MODE
// global.setup = setup
// global.draw = draw

}

```

## Going further - Global Mode!

This is the template for using p5.js in node with Global Mode:

```js
// Adapted from:
// ! Heart Curve
// ! Daniel Shiffman
// https://thecodingtrain.com/CodingChallenges/134-heart-curve.html
// https://youtu.be/oUBAi9xQ2X4
// https://editor.p5js.org/codingtrain/sketches/egvieHyt0

// width and height to be passed both in createCanvas and in setupWindow
setupWindow(400, 400);
// Note that in global mode even though we don't use the p5 variable, it still needs to be imported.
const p5 = require("p5");

const heart = [];
let a = 0;

function setup() {
createCanvas(400, 400);
}

function draw() {
while (true) {
const r = height / 40;
const x = r * 16 * pow(sin(a), 3);
const y = -r * (13 * cos(a) - 5 * cos(2 * a) - 2 * cos(3 * a) - cos(4 * a));
heart.push(createVector(x, y));
// So that it stops
if (a > TWO_PI) {
break;
}

a += 0.1;
}
background(0);
translate(width / 2, height / 2);

stroke(255);
strokeWeight(2);
fill(150, 0, 100);
beginShape();
for (let v of heart) {
vertex(v.x, v.y);
}
endShape();
// in global mode, p5 is attatched to the window (global in node)
// the third arg stands for whether to exit the process
// in this case, if false is passed, then this sketch will run forever, until manually cancelled (because this is the draw loop)
saveAsPNG(global, "globalimg", true);
}
```

In this case as well, the functions `saveAsPNG` and `setupWindow` should be appended at the end of the file, with the last two lines of `setupWindow` uncommented.

This is the output of the global mode code
![globalimg](https://user-images.githubusercontent.com/59444569/107874719-72f09b00-6ee1-11eb-90d4-f887a10eac06.png)

## Use these Templates!
To Use these templates, first install these node-modules
`npm i p5 canvas jsdom`
* [Template for using `node-canvas` with `p5.js` in global mode](https://gist.github.com/c59e02991929db850373b3c7d1a858ef)
* [Template for using `node-canvas` with `p5.js` in instance mode](https://gist.github.com/3e898a0acf73f6b58a563981732b4fdc)

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.