Processing (p5js)

Processing is a programming system for learning how to code within the context of the visual arts. It is well-suited to rapid prototyping of interactive graphics and idiosyncratic user interfaces. The language was originally implemented using Java, but has now been adapted to JavaScript in the p5js system. Programs in this system are called ‘sketches’ and run within a normal web browser. Code may be edited locally or using an online editor. As a result, sketches are easy to host online.

Pausch Bridge p5js Example

The following p5js sketch was developed by Nick Diamant as a prototype for an online Pausch Bridge animation loop editor. Special thanks to Nick for contributing this code.

The sketch shown below can be tested live in your browser by following this link.

../_images/Pausch01-screenshot.png

Screenshot of a custom ‘piano-roll’ loop editor for Pausch Bridge animation written in JavaScript using p5js. Dragging the mouse through the main canvas area draws colorful linework. This graphic content is interpreted as an animation which plays row by row from top to bottom. The left playbar shows a moving dot indicating the current playback position. At the top is the output preview with a row of rectangles representing the 57 lighting element groups of the bridge. Pressing any key will offer to save the image to a local PNG file which can be subsequently processed into video for the bridge.

Downloads

The sketch and the p5js runtime can be downloaded as the zip package Pausch01.zip.

Please note that not all browsers will load the index.html file from a local drive due to security protections. (On my computer, FireFox works, Safari mostly works, but Chrome does not.) If you have trouble running it, please consult the Get Started page; you could either upload the sketch.js file into the online editor or set up a local server.

Pausch01/sketch.js code

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
// Loop editor for the Pausch Bridge lighting system written using p5js
// (https://p5js.org/).  This implements a 'piano roll' drawing canvas in which
// each row can be sequenced out to the 57 lighting groups of the bridge.  The
// preview playback continuously loops through the image as it is drawn.
// 
// Original version by Nick Diamant <ndiamant@andrew.cmu.edu>,
// downloaded from https://editor.p5js.org/dinkolas/sketches/Ai9tqWsYU

// Changes:

// 2021-03-26:  garthz@cmu.edu
//		added comments to the code
//		added the keyPressed implementation to save the image

// -------------------------------------------------------------------------------------
let N = 300;  // Number of video frames in the loop.
let w = 57;   // Width of the preview display, e.g. number of lighting groups on bridge.
let row = 0;  // Playhead index, current frame of loop.
let h = 0;    // Current hue index for drawing brush.

function setup() {
    createCanvas(windowWidth, windowHeight);
    frameRate(30);
    background(0);
}

function windowResized() {
    resizeCanvas(windowWidth, windowHeight);
    background(0);
}

function keyPressed() {
    // fetch the 'piano roll' portion of the canvas
    pixels = get(width * 0.1, height * 0.2, width * 0.8, height * 0.7)
    pixels.save('Pausch01', 'png');
}

function draw() {

    // Draw a new line segment whenever the mouse button is pressed.  The color
    // continuously cycles through hues.  Four overlapping segments are drawn with
    // varying width to create a soft edge effect.
    if (mouseIsPressed) {
	h = (h + 1) % 100;
	colorMode(HSB, 100);
	blendMode(LIGHTEST);
	for (let i = 0; i < 4; i++) {
	    strokeWeight(map(i, 0, 3, 40, 5));
	    stroke(h, 100, map(i, 0, 3, 10, 100));
	    line(mouseX, mouseY, pmouseX, pmouseY);
	}
    }

    // Clear the margins to black all around to leave space for the playbar and preview pane.
    blendMode(BLEND);
    noStroke();
    fill(0);
    rect(0, 0, width, height * 0.2);
    rect(0, 0, width * 0.1, height);
    rect(width * 0.9, 0, width * 0.1, height);
    rect(0, height * 0.9, width, height * 0.1);

    // Draw the playhead dot moving vertically in the playbar.   
    let rowYCoord = map(row, 0, N - 1, height * 0.2, height * 0.9);
    colorMode(RGB, 100);
    noStroke();
    fill(100);
    ellipse(width * 0.05, rowYCoord, 10, 10);

    // Read back the canvas image pixels and extract the currently playing row into an array.
    let colors = [];
    loadPixels();
    let d = pixelDensity();
    let y = floor(rowYCoord);
    for (let i = 0; i < w; i++) {
	let x = floor(map(i, 0, w - 1, width * 0.1, width * 0.9));
	//4 * ((y * d + j) * width * d + (x * d + i));

	let p = 4 * ((y * d) * width * d + (x * d));
	let r = pixels[p];
	let g = pixels[p + 1];
	let b = pixels[p + 2];
	colors.push({
	    r: r,
	    g: g,
	    b: b
	});
    }

    // Redraw the preview pane at the top with rectangles representing the
    // bridge lighting colors using the color data extracted from the currently playing row.
    for (let i = 0; i < w; i++) {
	let x = map(i, 0, w - 1, width * 0.1, width * 0.9);
	let c = colors[i];
	noStroke();
	fill(c.r, c.g, c.b);
	rect(x, height * 0.05, width * 0.8 / w, height * 0.1);
    }

    // Advance the playhead.
    row = (row + 1) % N;
}