Reimagining John Whitney

The Idea:

I have enjoyed minimalist animation and fractal art for a long time. For this week’s Computational Media assignment I wanted to try and meet the assignment parameters and implement some form of fractal or simplistic generative art.

I began by trying a couple different fractal patterns that incorporated circles but was not happy with any of the results achieved. After some research I discovered the works of John Whitney Sr. One movie of his, in particular, inspired me to try to work with his style of graphics in P5.js.

Beyond how great the visuals are in this video, it’s even more interesting to learn how the people creating the graphics were able to do so with the technology available at the time.

I began to mess around with parametric equations and researching methods of creating this type of graphic generatively. After some time I found a piece of code by Alexander Miller that helped me to work out some of the problems with my process.

From there I played around, for an ungodly amount of time, with sin and cos functions to get a shape I thought was worth working with. Below are a few clips of the sketch running.

I don’t consider this piece finished but the extra functionality and animation I want to add to it is out of the scope for what this assignment required.

The Code for the project largely involved playing around with sinusoidal functions and trying to figure out ways to make the sketch more interactive. I think that I could have done some things more efficiently but overall I think the project turned out well. You can see the code below.

Link to completed sketch: Here

Code:

/*

ICM Homework 4, 10/01/18

This weeks ICM Homework took inspiration on computer art from 
John Whitney. 

-As the user scrolls their mouse across the 
screen, the number of lines being created from the moving 
objects increases.

-When the user clicks the screen the shapes invert

-Finally, the checkbox at the top left of the screen the shape
changes from a line to a rectangle.

*/


let t = 0;

//object to translate the start point of the lines 
//and set basic functionality

let trans = {
  numLines: 25,
  x: 2,
  y: 2,
};

function setup() {
  createCanvas(600, 600);
  background(0);


  //create a checkbox for changing the shape to rectangles
  rectCheckbox = createCheckbox('rectangles', false);
  rectCheckbox.changed(parabolicEffect);
  rectCheckbox.position(10, 20);


}

function draw() {
  background(0, 0, 0);

  strokeWeight(4);


  //move parabolic shape to center of screen
  translate(width / trans.x, height / trans.y);

  //text for checkbox
  textSize(12);
  fill(255);
  text('Rectangles', -290, -280);

  //call to parabolic effect function
  parabolicEffect();

  // increase the value being pushed into the function  
  t += .3;


}



//parabolic function x
function x(t) {
  if (mouseIsPressed) {
    return -sin(t / 10) * 100 + -sin(t / 10) * 100;
  } else {

    return sin(t / 10) * 100 + sin(t / 10) * 100;
  }
}


//parabolic function y
function y(t) {
  if (mouseIsPressed) {
    for (let i = 0; i < 20; i++) {
      return cos(t / 10) * i;
    }
  } else {
    return -cos(t / 10) * 20;

  }
}

//parabolic function x1
function x1(t) {

  if (mouseIsPressed) {
    return -sin(t / 10) * 100 + -cos(t / 10) * 100;
  } else {
    return sin(t / 10) * 100 + cos(t / 10) * 100;

  }
}

//parabolic function y1
function y1(t) {
  if (mouseIsPressed) {
    return cos(t / 20) * 200 + sin(t / 10) * 100;
  } else {
    return -cos(t / 20) * 200 + -sin(t / 10) * 100;

  }


}
/*
The parabolicEffect function creates the shapes at different 
points mapped to the various parabolic functions.
There is an offset of i or j added to each shape that 
give speed and tracing effects

*/
function parabolicEffect() {


  //map the cursor movement to the number of lines on screen
  let deltaX = map(mouseX, 0, width, 0, trans.numLines);

  //check to see if the rectangle checkbox is true or not
  if (rectCheckbox.checked()) {

    //create the rectangle shape and add in the offset of i 
    for (let i = 0; i < deltaX; i++) {
      noFill();
      stroke(111, 195, 223, 50 + (i * 4));
      rect(x(t + i), y(t + i), x1(t + i), y1(t + i));
      rect(x1(t + i), y(t + i), x(t + i), y1(t + i));

    }
    //create the rectangle shape and add in the offset of j
    for (let j = 5; j < deltaX * 2; j++) {
      stroke(218, 112, 214, 50 + (j * 4));
      rect(x(t - j), y(t - j), x1(t - j), y1(t - j));
      rect(x(t - j), y1(t - j), x1(t - j), y(t - j));

    }
  } else {

    //create the lines and add in the offset of i
    for (let i = 0; i < deltaX; i++) {
      noFill();
      stroke(111, 195, 223, 50 + (i * 4));
      line(x(t + i), y(t + i), x1(t + i), y1(t + i));
      line(x1(t + i), y(t + i), x(t + i), y1(t + i));

    }

    //create the lines and add in the offset of j
    for (let j = 5; j < deltaX * 2; j++) {
      //  fill(218, 112, 214, 50);
      stroke(218, 112, 214, 50 + (j * 4));
      line(x(t - j), y(t - j), x1(t - j), y1(t - j));
      line(x(t - j), y1(t - j), x1(t - j), y(t - j));

    }
  }
}