Processing.js vs P5.js – What’s The Difference?
A couple of days ago, P5.js was released into the wild. It’s a JavaScript library for visual programming that follows the Processing doctrine.
As per this post:
Processing is an environment/programming language that is meant to make visual, interactive applications extremely easy to write. It can be used for everything from teaching children how to code to visualizing scientific data.
It’s the language that’s partially behind wizardry like this:
and this:
and, of course, everything you can find here.
But, if we had processing.js before, what’s P5.js?
What is P5.js?
P5.js is a JavaScript library aiming
to make coding accessible for artists, designers, educators, and beginners, and reinterprets this for today’s web
So, it sounds like Processing itself. But what is it really?
Ease up, confused reader, we’ll get to it! First, watch their amazingly enthusiastic introduction here, then come back.
Did it click? Get it now? No? Ok. Let’s break it down.
Differences between Processing.js and P5.js
TL;DR: P5 is a direct JS port of the Processing language. Processing.js is a converter which interprets pure Processing code into JS on the fly. The latter requires you to learn Processing, but not JS, and vice versa.
Live compilation vs Language Translation: Processing.js is a library which takes raw Processing code (which is similar to Java, with types and all) and converts it to JavaScript on the fly. The examples you see running in your browser on the Processing.js website are, in fact, pure Processing code translated live into JS. This conversion is, for example, similar to what you get when you use Dart2js to run Dart code in browsers without a built-in Dart VM. On the other hand, P5 is a full conversion of Processing into JS code – all the functions will eventually be translated, and you’ll be writing in JavaScript.
In Processing.js, you need to define a canvas area with a data source which leads to a PDE file (a file with Processing source code). There are alternative approaches, too, but in a nutshell, that’s it. In P5, you write JS code directly, and it gets executed like any other JS file you include on your website.
Extending: Another difference is that P5 can be extended with addon libraries. For example, the p5.dom.js library addition adds the option of creating and manipulating HTML elements with P5, adding sliders, buttons, form elements and much more to your sketches – much like the demonstrators did in the Hello video we linked to in the previous section.
Note that of the two, only P5 is officially supported by the Processing Foundation and there’s even a transition manual for Processing users here.
Demos
Let’s see a demo comparison to get the full gist of it. I’ve made a Github repository containing the same demo written with each approach.
git clone https://github.com/Swader/processing
In the processing
folder, you have two subfolders: processing
and p5
. Each will contain demo1
and demo2
subdirectories, which contain an index.html
file. This is what you can run in your browser and test. The first sample is from the P5 website – a continually drawn ellipse which turns black when the mouse is clicked.
Note that Processing.js loads the pde
file with an Ajax request (via XHR), so you will get a cross-origin error if you try to open it in your browser by just running index.html
. To get it to run properly, you should probably set up a virtual server through which to access the samples. That’s best done with an instance of Homestead Improved in a Vagrant box – you’ll be up and running in five minutes flat.
P5.js
In this case, we need the sketch.js
file which contains our sketch code, and the index.html
file in which it runs. The sketch.js
code is as follows:
function setup() {
createCanvas(640, 480);
}
function draw() {
if (mouseIsPressed) {
fill(0);
} else {
fill(255);
}
ellipse(mouseX, mouseY, 80, 80);
}
The index.html
file contains only this:
<head>
<script language="javascript" src="../p5.js"></script>
<!-- uncomment lines below to include extra p5 libraries -->
<!--<script language="javascript" src="../addons/p5.dom.js"></script>-->
<!--<script language="javascript" src="../addons/p5.sound.js"></script>-->
<script language="javascript" src="sketch.js"></script>
</head>
<body>
</body>
Processing.js
For this example, we need a pde
file with Processing code. In our case, that’s sketch.pde
with the following P5-translated code:
void setup() {
size(640, 480);
}
void draw() {
if (mousePressed) {
fill(0);
} else {
fill(255);
}
ellipse(mouseX, mouseY, 80, 80);
}
Then, we have our index.html
file:
<head>
<script language="javascript" src="../processing.min.js"></script>
</head>
<body>
<canvas data-processing-sources="sketch.pde"></canvas>
</body>
Analysis
At first glance, there is no discernible difference. Both samples run at approximately the same speed, perform well, and have similar syntax. However, if you’re using Google Chrome, and go to chrome://flags
, then activate the frame rate counter (see the image below), you’ll notice that drawing in the Processing.js canvas maintains a steady frame rate of around 58 to 60, while P5 goes as low as 50 when drawing, and back up to 60 when idle. Another interesting fact is that Processing uses hardware acceleration all the time, even when your cursor is outside the canvas area. P5, on the other hand, pauses the rendering if no changes to the canvas are pending (your cursor is outside the drawing area), hence lightening the load while not drawing.
Demos 2
Let’s do another demo now – a simple particle effect. This particle emitter will spawn gravitationally sensitive particles in random directions, and we’ll take another look at the frame rate. The example we’ll be using (and translating to P5) is this.
Processing.js
The code for sketch.pde
is the one from the example linked above:
ParticleSystem ps;
void setup() {
size(640,360);
ps = new ParticleSystem(new PVector(width/2,50));
}
void draw() {
background(0);
ps.addParticle();
ps.run();
}
// A simple Particle class
class Particle {
PVector location;
PVector velocity;
PVector acceleration;
float lifespan;
Particle(PVector l) {
acceleration = new PVector(0,0.05);
velocity = new PVector(random(-1,1),random(-2,0));
location = l.get();
lifespan = 255.0;
}
void run() {
update();
display();
}
// Method to update location
void update() {
velocity.add(acceleration);
location.add(velocity);
lifespan -= 1.0;
}
// Method to display
void display() {
stroke(255,lifespan);
fill(255,lifespan);
ellipse(location.x,location.y,8,8);
}
// Is the particle still useful?
boolean isDead() {
if (lifespan < 0.0) {
return true;
} else {
return false;
}
}
}
// A class to describe a group of Particles
// An ArrayList is used to manage the list of Particles
class ParticleSystem {
ArrayList<Particle> particles;
PVector origin;
ParticleSystem(PVector location) {
origin = location.get();
particles = new ArrayList<Particle>();
}
void addParticle() {
particles.add(new Particle(origin));
}
void run() {
for (int i = particles.size()-1; i >= 0; i--) {
Particle p = particles.get(i);
p.run();
if (p.isDead()) {
particles.remove(i);
}
}
}
}
P5
The code for P5 when translated from the above is as follows:
var ps;
function setup() {
createCanvas(640, 360);
ps = new ParticleSystem(new p5.Vector(width/2, 50));
}
function draw() {
background(0);
ps.addParticle();
ps.run();
}
function Particle(lvector) {
this.location = lvector.get();
this.acceleration = new p5.Vector(0,0.05);
var random1 = Math.random() * ((Math.random() > 0.5) ? -1 : 1);
var random2 = Math.random() - ((Math.random() > 0.5) ? 1 : 2);
this.velocity = new p5.Vector(random1, random2);
this.lifespan = 255.0;
}
Particle.prototype.run = function() {
this.update();
this.display();
}
Particle.prototype.update = function() {
this.velocity.add(this.acceleration);
this.location.add(this.velocity);
this.lifespan -= 1.0;
}
Particle.prototype.display = function() {
stroke(255, this.lifespan);
fill(255, this.lifespan);
ellipse(this.location.x, this.location.y, 8, 8);
}
Particle.prototype.isDead = function() {
return (this.lifespan < 0);
}
function ParticleSystem(location) {
this.origin = location.get();
this.particles = [];
}
ParticleSystem.prototype.addParticle = function() {
this.particles.push(new Particle(this.origin));
}
ParticleSystem.prototype.run = function() {
var p;
for (var i = this.particles.length - 1; i >= 0; i--) {
p = this.particles[i];
p.run();
if (p.isDead()) {
this.particles.splice(i, 1);
}
}
}
Analysis
Once again, we see a slightly better frame rate with Processing.js. P5 maintains it at around 56, while Processing.js looks to be standing ground at 58 or so. In both cases, Processing.js has proven victorious, performance-wise.
Conclusion
P5js is a young and ambitious project that aims to bring visual programming to the masses in a manner more approachable than Processing was until now. While it is currently being forced to be dumbed down somewhat feature-wise, the team is hard at work porting the rest of the Processing language to this JS counterpart.
The advantages of using P5 over Processing.js are:
- Writing JS code you’re probably already familiar with
- Officially supported by the Processing Foundation
- HTML DOM manipulation with the DOM library addon – adding common HTML elements to your P5 sketches and more
- Lighter on the resources when not drawing
The advantage of using Processing.js:
- You learn Processing and can use it in environments where it’s faster and more portable to non-web environments
- Seems to have a steadier frame rate and performs better in both demos we tried
We’ll be keeping an eye on this library and playing around with it regularly. Will you? Let us know if you whip up some interesting examples, we’d love to write about them!