CodingTrain / CodingTrain/node-p5-test
Using p5.js in Node runtime
- 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

## 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.