breep-Body

 

For this piece the motion definitely came first. I most experimented with ways of conveying the body through lines while getting to know Mocap in Processing, the video underneath is one of the more refined outcomes of my experimentation. With my series of experimentations in place, I thought through each and wanted to build a form of narrative in which this digital body wills itself into existence from an initial form as a plane. From this I came to the final piece, which moves toward the viewer just as the walking motion does, urging itself onwards into existence as the viewer scrolls through.

I am mildly pleased with the outcome, but not happy. I feel that greater blending between the states with more steps would make this a more cohesive transition.

 

 

 
// Based off of Template provided on 60212 Fall 2018 Website
 
 
// Renders a BVH file with Processing v3.4
// Note: mouseX controls the camera.
// Based off of com.rhizomatiks.bvh
// Golan Levin, September 2018
 
 
 
PBvh myBrekelBvh;
PBvh secondBrekelBvh; 
PBvh thirdBrekelBvh;
PBvh fourthBrekelBvh; 
PBvh fifthBrekelBvh; 
boolean bDrawMeat = true; 
boolean bDrawLineConnectingHands = false; 
boolean bDrawCircleAtOrigin = false; 
boolean bDrawLineToBoneInScreenspace = false; 
float boneScreenX; 
float boneScreenY; 
int xCamera = 500; 
int yCamera = 500; 
int zCamera = 500; 
int distance = 3200; 
int distanceFinal = 4000; 
int distanceWalkout = 4400; 
 
//------------------------------------------------
void setup() {
  size( 1280, 720, P3D );
  // Load a BVH file recorded with a Kinect v2, made in Brekel Pro Body v2.
  myBrekelBvh = new PBvh( loadStrings("walk_bold.bvh" ) );
 
  secondBrekelBvh = new PBvh( loadStrings("walk-cycle.bvh") ); 
 
}
 
 
//------------------------------------------------
void draw() {
  lights() ;
  background(0, 0, 0);
 
  pushMatrix(); 
  setMyCamera();        // Position the camera. See code below.
  //drawMyGround();       // Draw the ground. See code below.
  updateAndDrawBody();  // Update and render the BVH file. See code below.
  popMatrix(); 
 
  drawHelpInfo();
  drawLineToHead();
 
 
}
 
void keyPressed() {
  switch (key) {
  case 'M': 
  case 'm': 
    bDrawMeat = !bDrawMeat; 
    break;
  case 'L':
  case 'l': 
    bDrawLineConnectingHands = !bDrawLineConnectingHands;
    break;
  case 'O': 
  case 'o': 
    bDrawCircleAtOrigin = !bDrawCircleAtOrigin; 
    break;
  case 'H': 
  case 'h':
    bDrawLineToBoneInScreenspace = !bDrawLineToBoneInScreenspace; 
    break;
 
  case 'w': 
    yCamera += 50; 
    break; 
  case 's':
    yCamera -= 50; 
    break; 
  case 'd':
    xCamera += 50; 
    break; 
  case 'a':
    xCamera -= 50; 
    break; 
 
  case 'f':
    zCamera += 50; 
    break; 
  case 'g':
    zCamera -= 50; 
    break; 
 
  }
}
 
 
//------------------------------------------------
void updateAndDrawBody() {
 
  pushMatrix(); 
  translate(width/2, height/2, 0); // position the body in space
  scale(-1, -1, 1); // correct for the coordinate system orientation
  myBrekelBvh.update(millis()); // update the BVH playback
 
  pushMatrix();
  stroke(255, 0, 0); 
  //myBrekelBvh.draw();        // one way to draw the BVH file (see PBvh.pde)
  popMatrix(); 
 
 
  if (bDrawMeat) {
    myBrekelBvh.drawBones(); // a different way to draw the BVH file
  }
 
  if (bDrawLineConnectingHands) {
    drawLineConnectingHands();
  }
 
  if (bDrawCircleAtOrigin) {
    drawCircleAtOrigin();
  }
 
  if (bDrawLineToBoneInScreenspace) {
    myBrekelBvh.calculateScreenspaceLocationOfBone("Head");
  }
 
  popMatrix();
 
 
  pushMatrix(); 
  translate(width/2, height/2, 0); // position the body in space
  scale(-1, -1, 1); // correct for the coordinate system orientation
  myBrekelBvh.update(millis()); // update the BVH playback
 
  pushMatrix();
  stroke(255, 0, 0); 
  //myBrekelBvh.draw();        // one way to draw the BVH file (see PBvh.pde)
  popMatrix(); 
 
 
  if (bDrawMeat) {
    secondBrekelBvh.drawBones(); // a different way to draw the BVH file
  }
 
  if (bDrawLineConnectingHands) {
    drawLineConnectingHands();
  }
 
  if (bDrawCircleAtOrigin) {
    drawCircleAtOrigin();
  }
 
  if (bDrawLineToBoneInScreenspace) {
    secondBrekelBvh.calculateScreenspaceLocationOfBone("Head");
  }
 
  popMatrix();
 
}
 
//------------------------------------------------
 
void drawHelpInfo() {
  fill(255); 
  float ty = 20; 
  float dy = 15; 
  //text("BVH Loader for Processing 3.4", 20, ty+=dy);
  //text("Displays files recorded with Kinect v2 + Brekel Pro Body 2", 20, ty+=dy);
 
  //text("", 20, ty+=dy);
  //text("Press 'M' to toggle meat", 20, ty+=dy);
  //text("Press 'L' to draw line connecting hands", 20, ty+=dy);
  //text("Press 'O' to draw circle at Origin", 20, ty+=dy);
  //text("Press 'H' to draw line from mouse to Head", 20, ty+=dy);
}
 
 
//------------------------------------------------
 
void drawLineToHead() {
  if (bDrawLineToBoneInScreenspace) {
    stroke(0, 255, 255); 
    strokeWeight(3); 
    line (mouseX, mouseY, boneScreenX, boneScreenY);
  }
}
 
 
//------------------------------------------------
 
void drawCircleAtOrigin() {
  fill(255); 
  stroke(255, 0, 0); 
  strokeWeight(4); 
  ellipse(0, 0, 20, 20);
}
 
 
//------------------------------------------------
void drawLineConnectingHands() {
  // This example code shows how to reach into the skeleton 
  // in order to get specific joint locations (in 3D)
 
  PVector[] boneLocationsFirst = new PVector[19]; 
  PVector[] boneLocationsSecond = new PVector[19]; 
 
  for (int i = 0; i < 19; i ++){
    int currentIndex = i; 
    BvhBone currentBoneFirst = myBrekelBvh.parser.getBones().get(currentIndex); 
    PVector currentBonePosFirst = currentBoneFirst.absPos;
 
    BvhBone currentBoneSecond = secondBrekelBvh.parser.getBones().get(currentIndex); 
    PVector currentBonePosSecond = currentBoneSecond.absPos;
 
    boneLocationsFirst[i] = currentBonePosFirst;
    boneLocationsSecond[i] = currentBonePosSecond; 
  }
 
 
  for (int j = 0; j < 19; j ++){
      for (int z = 0; z < 19; z ++){ 
      PVector currentPosFirst = boneLocationsFirst[j]; 
      PVector secondPosFirst = boneLocationsFirst[z]; 
 
      PVector currentPosSecond = boneLocationsSecond[j];
      PVector secondPosSecond = boneLocationsSecond[z]; 
 
      stroke(255, 255, 255); 
      strokeWeight(1); 
 
      // Body Lines 
 
      pushMatrix(); 
 
      if (j == 1) {
        for (int a = 1; a < 4; a ++){
        line( 7 * boneLocationsFirst[a].x, 7 * boneLocationsFirst[a].y, boneLocationsFirst[a].z + distance, 
             7 * boneLocationsFirst[a+1].x, 7 *boneLocationsFirst[a+1].y, boneLocationsFirst[a+1].z + distance);
        }
      } 
 
      if (j == 5) { 
        line( 7 * boneLocationsFirst[3].x, 7 * boneLocationsFirst[3].y, boneLocationsFirst[3].z + distance, 
             7 * boneLocationsFirst[5].x, 7 * boneLocationsFirst[5].y, boneLocationsFirst[5].z + distance);
 
        for (int b = 5; b < 8; b ++){
        line( 7 * boneLocationsFirst[b].x, 7 * boneLocationsFirst[b].y, boneLocationsFirst[b].z + distance, 
             7 * boneLocationsFirst[b+1].x, 7 * boneLocationsFirst[b+1].y, boneLocationsFirst[b+1].z + distance);
        }
      }
 
      if (j == 9) { 
        line( 7 * boneLocationsFirst[3].x, 7 * boneLocationsFirst[3].y, boneLocationsFirst[3].z + distance, 
             7 * boneLocationsFirst[9].x, 7 *boneLocationsFirst[9].y, boneLocationsFirst[9].z + distance);
 
        for (int c = 9; c < 12; c ++){
        line( 7 * boneLocationsFirst[c].x, 7 * boneLocationsFirst[c].y, boneLocationsFirst[c].z + distance, 
             7 * boneLocationsFirst[c+1].x, 7 *boneLocationsFirst[c+1].y, boneLocationsFirst[c+1].z + distance);
        }
      }
 
      if (j == 13) { 
        line( 7 * boneLocationsFirst[1].x, 7 * boneLocationsFirst[1].y, boneLocationsFirst[1].z + distance, 
             7 * boneLocationsFirst[13].x, 7 *boneLocationsFirst[13].y, boneLocationsFirst[13].z + distance);
 
        for (int d = 13; d < 15; d ++){
        line( 7 * boneLocationsFirst[d].x, 7 * boneLocationsFirst[d].y, boneLocationsFirst[d].z + distance, 
             7 * boneLocationsFirst[d+1].x, 7 *boneLocationsFirst[d+1].y, boneLocationsFirst[d+1].z + distance);
        }
      }
 
      if (j == 16) { 
        line( 7 * boneLocationsFirst[1].x, 7 * boneLocationsFirst[1].y, boneLocationsFirst[1].z + distance, 
             7 * boneLocationsFirst[16].x, 7 *boneLocationsFirst[16].y, boneLocationsFirst[16].z + distance);
 
        for (int e = 16; e < 18; e ++){
        line( 7 * boneLocationsFirst[e].x, 7 * boneLocationsFirst[e].y, boneLocationsFirst[e].z + distance, 
             7 * boneLocationsFirst[e+1].x, 7 *boneLocationsFirst[e+1].y, boneLocationsFirst[e+1].z + distance);
        }
      }
 
      /* translate(0, 0, distance); 
      ellipse(7 * boneLocationsFirst[4].x, 7 * boneLocationsFirst[4].y + 30, 20, 20); */ 
 
      popMatrix(); 
 
      ////----------------------
 
      pushMatrix(); 
 
      if (j == 1) {
        for (int a = 1; a < 4; a ++){
        line( 8 * boneLocationsFirst[a].x, 8 * boneLocationsFirst[a].y, boneLocationsFirst[a].z + distanceFinal, 
             8 * boneLocationsFirst[a+1].x, 8 *boneLocationsFirst[a+1].y, boneLocationsFirst[a+1].z + distanceFinal);
        }
      } 
 
      if (j == 5) { 
        line( 8 * boneLocationsFirst[3].x, 8 * boneLocationsFirst[3].y, boneLocationsFirst[3].z + distanceFinal, 
             8 * boneLocationsFirst[5].x, 8 * boneLocationsFirst[5].y, boneLocationsFirst[5].z + distanceFinal);
 
        for (int b = 5; b < 8; b ++){
        line( 8 * boneLocationsFirst[b].x, 8 * boneLocationsFirst[b].y, boneLocationsFirst[b].z + distanceFinal, 
             8 * boneLocationsFirst[b+1].x, 8 * boneLocationsFirst[b+1].y, boneLocationsFirst[b+1].z + distanceFinal);
        }
      }
 
      if (j == 9) { 
        line( 8 * boneLocationsFirst[3].x, 8 * boneLocationsFirst[3].y, boneLocationsFirst[3].z + distanceFinal, 
             8 * boneLocationsFirst[9].x, 8 *boneLocationsFirst[9].y, boneLocationsFirst[9].z + distanceFinal);
 
        for (int c = 9; c < 12; c ++){
        line( 8 * boneLocationsFirst[c].x, 8 * boneLocationsFirst[c].y, boneLocationsFirst[c].z + distanceFinal, 
             8 * boneLocationsFirst[c+1].x, 8 *boneLocationsFirst[c+1].y, boneLocationsFirst[c+1].z + distanceFinal);
        }
      }
 
      if (j == 13) { 
        line( 8 * boneLocationsFirst[1].x, 8 * boneLocationsFirst[1].y, boneLocationsFirst[1].z + distanceFinal, 
             8 * boneLocationsFirst[13].x, 8 *boneLocationsFirst[13].y, boneLocationsFirst[13].z + distanceFinal);
 
        for (int d = 13; d < 15; d ++){
        line( 8 * boneLocationsFirst[d].x, 8 * boneLocationsFirst[d].y, boneLocationsFirst[d].z + distanceFinal, 
             8 * boneLocationsFirst[d+1].x, 8 *boneLocationsFirst[d+1].y, boneLocationsFirst[d+1].z + distanceFinal);
        }
      }
 
      if (j == 16) { 
        line( 8 * boneLocationsFirst[1].x, 8 * boneLocationsFirst[1].y, boneLocationsFirst[1].z + distanceFinal, 
             8 * boneLocationsFirst[16].x, 8 *boneLocationsFirst[16].y, boneLocationsFirst[16].z + distanceFinal);
 
        for (int e = 16; e < 18; e ++){
        line( 8 * boneLocationsFirst[e].x, 8 * boneLocationsFirst[e].y, boneLocationsFirst[e].z + distanceFinal, 
             8 * boneLocationsFirst[e+1].x, 8 *boneLocationsFirst[e+1].y, boneLocationsFirst[e+1].z + distanceFinal);
        }
      }
 
      /* translate(0, 0, distance); 
      ellipse(7 * boneLocationsFirst[4].x, 7 * boneLocationsFirst[4].y + 30, 20, 20); */ 
 
      popMatrix(); 
 
 
      // Points of body to backside origin  
 
      pushMatrix(); 
           translate(0, 0, 2400); 
            line( 6 * currentPosFirst.x, 6 * currentPosFirst.y, currentPosFirst.z, 
                  0, 0 , -400); 
            popMatrix(); 
 
 
       // Points of body to backside origin  
 
      pushMatrix(); 
           translate(0, 0, 3200); 
            line( 6 * currentPosFirst.x, 6 * currentPosFirst.y, currentPosFirst.z, 
                  0, 0 , -400); 
            popMatrix(); 
 
 
       //BaseLine
       pushMatrix(); 
          stroke(255); 
          line(
            currentPosFirst.x + 10000, currentPosFirst.y, currentPosFirst.z - 400,
            currentPosSecond.x - 10000, currentPosSecond.y, currentPosSecond.z - 400); 
          popMatrix();
 
 
       //Lines extrapolating to one direction
          pushMatrix(); 
          stroke(255); 
          line(
            currentPosFirst.x + 10, currentPosFirst.y, currentPosFirst.z,
            currentPosFirst.x - 10, currentPosFirst.y, currentPosFirst.z); 
          popMatrix();
 
 
       /* //Lines extrapolating to one direction
          pushMatrix(); 
          stroke(255); 
          line(
            currentPosFirst.x + 50, currentPosFirst.y, currentPosFirst.z + 100,
            currentPosFirst.x - 50, currentPosFirst.y, currentPosFirst.z + 100); 
          popMatrix();
 
       //Lines extrapolating to one direction
          pushMatrix(); 
          stroke(255); 
          line(
            currentPosFirst.x + 25, currentPosFirst.y, currentPosFirst.z + 200,
            currentPosFirst.x - 25, currentPosFirst.y, currentPosFirst.z + 200); 
          popMatrix();
 
 
      //Lines extrapolating to one direction
          pushMatrix(); 
          stroke(255); 
          line(
            currentPosFirst.x + 10, currentPosFirst.y, currentPosFirst.z + 300,
            currentPosFirst.x - 10, currentPosFirst.y, currentPosFirst.z + 300); 
          popMatrix();*/ 
 
 
      //Lines in First Body
 
      line(
        2 * currentPosFirst.x, 2 * currentPosFirst.y, currentPosFirst.z + 400,
        2 * secondPosFirst.z, 2 * secondPosFirst.y, secondPosFirst.z + 400);
 
 
      for (int k = 0; k < 8; k ++){
 
          //Tutu
 
          float angle = map(k, 0, 8, 0, TWO_PI); 
 
          /*if (k % 2 == 0){
          stroke(255, 0, 0);}
 
          else{
          stroke(0, 0, 255);}*/
 
          stroke(255); 
 
          line(
            3 * currentPosFirst.x, 3 * currentPosFirst.y, currentPosFirst.z + 800,
            100 * cos(angle), 50, 100 * sin(angle) + 800); 
 
          /*line(
            5 * currentPosSecond.x, 5 * currentPosSecond.y, currentPosSecond.z, 
            100 * cos(angle), 50, 100 * sin(angle));*/
 
          pushMatrix(); 
 
          /*if (k % 2 == 0){
          stroke(0, 255, 0);}
 
          else{
          stroke(255, 0, 0);}*/ 
 
          stroke(255); 
 
          line(
            4 * currentPosFirst.x, 4 * currentPosFirst.y, currentPosFirst.z + 1600,
            100 * sin(angle), (100 * cos(angle)), 100 * cos(angle) + 1200); 
 
          popMatrix(); 
 
 
 
          /*pushMatrix(); 
          translate(0, 0, 1200); 
          stroke(255, 0, 0); 
          ellipse(4 * currentPosFirst.x, 4 * currentPosFirst.y, 10, 10); 
          popMatrix();*/ 
 
          /*pushMatrix(); 
          translate(0, 0, 2000); 
          stroke(255); 
          ellipse(5 * currentPosFirst.x, 5 * currentPosFirst.y, 5, 5); 
          popMatrix(); */
 
          /*pushMatrix(); 
          translate(0, 0, 2000); 
          stroke(255, 0, 0); 
          ellipse(6 * currentPosFirst.x, 6 * currentPosFirst.y, 50, 50); 
          popMatrix(); 
 
          pushMatrix(); 
          translate(0, 0, 2000); 
          stroke(255, 0, 0); 
          ellipse(6 * currentPosFirst.x, 6 * currentPosFirst.y, 100, 100); 
          popMatrix(); */ 
 
 
          /*pushMatrix(); 
          stroke(255); 
          line(
            4 * currentPosFirst.x, 4 * currentPosFirst.y, currentPosFirst.z + 600,
            5 * currentPosFirst.x, 5 * currentPosFirst.y, currentPosFirst.z + 1000); 
          translate(0,0, 10000); 
          ellipse(currentPosFirst.x, currentPosFirst.y, 50, 50); 
          popMatrix(); */ 
      } 
      }
      }
  }
 
 
          /*pushMatrix(); 
 
          if (k % 2 == 0){
          stroke(0, 255, 0);}
 
          else{
          stroke(255, 0, 0);}
 
          line(
            currentPosFirst.x, currentPosFirst.y, currentPosFirst.z ,
            100 * sin(angle), (100 * sin(angle)) + (100 * cos(angle)), 100 * cos(angle)); 
 
          popMatrix();*/ 
 
 
 
          //Lines extrapolating to one direction to Origin
          /*pushMatrix(); 
          if (k == 0){
            stroke(0, 255, 0);}
          else if (k == 1){
            stroke(255, 0, 0);}
          else {
            stroke(0, 0, 255);}
          translate(-(60*k), 0, 0); 
          line(
            currentPosSecond.x + (60 * k), currentPosSecond.y, currentPosSecond.z,
            0, 200, 200); 
          popMatrix(); */
 
 
 
 
//------------------------------------------------
void setMyCamera() {
 
 
  // Adjust the position of the camera
  float eyeX = 650;          // x-coordinate for the eye
  float eyeY = yCamera; //height/2.0f - 200;   // y-coordinate for the eye
  float eyeZ = mouseY * 8;             // z-coordinate for the eye
  float centerX = width/2.0f;   // x-coordinate for the center of the scene
  float centerY = height/2.0f;  // y-coordinate for the center of the scene
  float centerZ = -400;         // z-coordinate for the center of the scene
  float upX = 0;                // usually 0.0, 1.0, or -1.0
  float upY = 1;                // usually 0.0, 1.0, or -1.0
  float upZ = 0;                // usually 0.0, 1.0, or -1.0
 
  camera(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
 
}
 
//------------------------------------------------
void drawMyGround() {
  // Draw a grid in the center of the ground 
  pushMatrix(); 
  translate(width/2, height/2, 0); // position the body in space
  scale(-1, -1, 1);
 
  stroke(100);
  strokeWeight(1); 
 
  float gridSize = 400; 
  int nGridDivisions = 10; 
 
  for (int col=0; col<=nGridDivisions; col++) {
    float x = map(col, 0, nGridDivisions, -gridSize, gridSize);
    line (x, 0, -gridSize, x, 0, gridSize);
  }
  for (int row=0; row<=nGridDivisions; row++) {
    float z = map(row, 0, nGridDivisions, -gridSize, gridSize); 
    line (-gridSize, 0, z, gridSize, 0, z);
  }
 
  popMatrix();
}

 

 

breep-telematic

Glitch App: Ensure Audio is on (Headphones are optimum for the notion of privacy) 

To log in:

  1. Do Not Click anywhere on the screen or press any keys
  2. Click on Username Input Box
  3. Enter Username
  4. Click on Password Input Box
  5. Enter Password
  6. Press Enter, and you should enter into the chatroom
  7. If nothing happens, refresh the page and try again

Documentation:

All messages received are spoken out to the user with p5.js Speech, and the only hallmark of them within the chat is 'Received Message'. However all text sent to the chat is posted on twitter with the username associated as well as the text and a hashtag. There is no evidence on the group chat of this occurring though, so the allure of privacy is maintained.

Twitter Page

I would like to view this project as a public private chat. I learnt a-lot about TwitterBots in the process of making this piece, as well as html and the connection between servers and clients. I struggled a-lot with implementing libraries initially, with my understanding of where the code should fit into the glitch page. I am happy with the text part of the project, but I feel that more work on the speech element of it would aid in making it seem more polished. I would also dedicate more time to make the chatroom itself more conducive to the audio formatting.

I feel the piece is many to many, given that the population of the chatroom speaks to the population of twitter. It is asynchronous given the disjunction inherent within communication. Everyone has equal roles, there is no special communicator within the chat room. I feel the piece is both anonymous and intimate, given the lack of awareness of the public aspect of it. It is remote collaboration, given that those in chat room would communicate across distance as well as the content on the twitterpage reaching a wider audience. I feel the work is self-reflexive and critical of networked environments, highlighting the faith in privacy on the internet despite the public connections that those stem on.

 

breep-viewing04

Spectacle: Projects made with the intention of impressing the viewer with its surface level ideas/aesthetics, but disregards the technological context of today that leads to the ability to create such projects

Speculation: Projects made with full acknowledgement of the digital process/theory, often critiquing it in a self aware fashion, but disregards the actual practise of creating digital artworks

I decided to highlight Mark Leckey's GreenScreenRefridgeratorAction as to me it is pure spectulation. The work explores the systems inherent in a refrigerator through all the types of style that Alan Warbuton. I highlight also because it was introduced to me in Critical Theory, and I found the disjunction between what I had learnt about the work there in context of Duchamp against the modern technology context of Warburton's video a raw example of the Speculation he talks about.

In my eyes it is very much digital drag, given its simplified commercial like animations and rudimentary use of green-screen. It is much more about visibility, considering both its context as a performance and as a highlighting of the inner mechanisms of this everyday technology system. It weighs more on the surplus side as well, given its over-dissection as a highlighting of what is taken for granted proving worthwhile conceptually rather than wasteful of the technology (which it arguably counteracts). It is most certainly more on the art side, given its strong aesthetic and form inspiration from the artistic technologic context that Warburton describes. I feel that it lies between function and dysfunction, its content highlighting the functionality of things while also dysfunctionally using simplified and overused technology.

 

breep-LookingOutwards03

The eyewriter is a collaborative project that allows individuals who are paralyzed but still retain full brain function and eye movement to draw with the movement of their eyes. Initially teaming up with LA graffiti artist TEMPTONE, who was diagnosed with ALS in 2003, the project aimed to get the artist to be create again despite his condition. I love how the vast respect for this singular artist and the empathy for his condition inspires a hugely impactful project.

I find this project exceptionally praise worthy for its aim to get those who have been given a horrible card in life to fully realize their creative desires and share their creativity with the world. Along with this, I find the parallels between the emotional range that eyes can present in relation to the creation of projects entirely with eyes vastly intriguing its potential. This is one element of the project that I wish was explored more, but given the circumstance and what the EyeWriter accomplishes that is a very minor aspect. The notion of turning this project into a wide bracing international framework is also hugely admirable, sharing this wonderful technology with the world. I find that a-lot of the time we expect the viewer to be able to interact with a work of interactive art, but in this case the viewer interacts with the work through a larger social context which amazed me about this work.

 

breep-clock

Clock:

 

Using The Dot For Every Second In The Day as a launching platform, I wanted to create a clock that helped/reminded the user to optimize their time, through reminding them about the amount they have left. I imagine it to be permanently on the user, and I see it primarily in situ as a digital tattoo which acts as a constant moving reminder (part of me also hates the clunkiness of watches so the unburdened element of a clock tattoo also resonates with me strongly).

While I like the minimalist aesthetic of the clock in terms of its readability, I also feel that a greater graphic quality/style to it would act to help with the element of constantly being reminded as it's quality of being pleasurable to look at would certainly factor into that. I also feel that greater individuality/personally connected tasks would help with a more unique individual experience with the clock.

GIF:

Images:

 

 

Sketches:

 
var prevSec;
var millisRolloverTime;
var loopRunning; 
var button;
var ClockMode = false; 
var AdviceMode = false;
var Width = 800; 
var Height = 300; 
 
var monthAmountTable = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] 
 
var minutesIndex = 0; 
var hoursIndex = 0; 
var daysIndex = 0; 
var monthsIndex = 0;
var yearsIndex = 0; 
var decadesIndex = 0; 
var lifetimesIndex = 0; 
 
var minuteActs = ["Stretching\nyour legs",
                  "Telling\nyour parents\nyou love\nthem", 
                  "Messaging\na friend", 
                  "Asking\nthat person\nout",
                  "Brainstorming\nthat idea", 
                  "Taking\nsome time\nfor yourself",
                  "Sketching\na stranger"] 
 
var hourActs = ["Going\n to the\ngym", 
                "Grabbing\nfood with\na friend"]
 
var dayActs = ["Finishing\na piece\nof work", 
               "Getting\nGroceries", 
               "Making a new playlist", 
               "Watching\n a film"]
 
var monthActs = ["Making\na Website", 
                 "Getting\nover that\nbreakup", 
                 "Finding a new hobby"] 
 
var yearActs = ["Learning\n10 songs\non an\ninstrument", 
                "Writing\na book"] 
 
var decadeActs = ["Working\non your\nmental health", 
                  "Forgiving\nyour parents"] 
 
var lifetimeActs = ["Raising\nHell", 
                    "Living a\nfulfilled life"] 
 
var lastChangeSeconds = 0; 
var waitTimeSeconds = 60000; 
 
var lastChangeMinutes = 0;
var waitTimeMinutes = 60; 
 
var lastChangeHours = 0; 
var waitTimeHours = 24; 
 
var lastChangeMonths = 0; 
 
var lastChangeYears = 0; 
var waitTimeYears = 12; 
 
var lastChangeDecade = 0; 
var waitTimeDecades = 10; 
 
//--------------------------
function setup() {
  createCanvas(800, 300);
  background(0); 
  millisRolloverTime = 0;
 
  loopRunning = false; 
  getInput(); 
	var waitTimeMonths = monthAmountTable[month() -1]; 
}
 
//-------------------------
 
function getInput() { 
 
  input = createInput();
  input.position((Width/2) - 125, Height/2);
 
  button = createButton('Your Time Left');
  button.position(input.x + input.width + 20, Height/2);
 
 
  fill(255); 
  textFont("Futura"); 
  textAlign(CENTER);
  textSize(25);
  text("Your Age in this lifetime", Width/2, Height/2 - 50);  
 
 
  button.mousePressed(modeChange); 
}
 
function modeChange(){
  ClockMode = true;}
 
function keyPressed(){ 
  if (ClockMode == true && keyCode == RIGHT_ARROW) {
    ClockMode = false; 
    AdviceMode = true;}
 
  else if (AdviceMode == true && keyCode == LEFT_ARROW){
    AdviceMode = false;
    ClockMode = true;}
}
 
function changeIndex(){ 
  if (minutesIndex < 4){ 
      minutesIndex += 1}
  else if ( minutesIndex > 4){
      minutesIndex = 0;}
 
} 
 
//--------------------------
function draw() {
 
  if (ClockMode == true) { 
 
  button.remove();
  input.remove();
 
 
  background(0);
 
  var monthKeyTable = [0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6] 
  var dayOfWeekTable = [6, 7, 0, 1, 2, 3, 4, 5] 
 
 
 
  var weekDay = ((year() % 100) / 4 ) - (((year() % 100) / 4 ) % 1) + day() + monthKeyTable[month()] + 6 + 18
 
  var LifeExpectancy =  72.74 - input.value(); 
 
 
 
  var De = 10 / (year() % 10);  
  var Y = (month() / 12);
  var Mo = (day() / monthAmountTable[month() -1]); 
  var W = (weekDay / 7) % 1 ;
  var D = ((hour()+1) / 24); 
  var H = hour();
  var M = minute();
  var S = second();
 
 
 
  // Reckon the current millisecond, 
  // particularly if the second has rolled over.
  // Note that this is more correct than using millis()%1000;
  if (prevSec != S) {
    millisRolloverTime = millis();
  }
  prevSec = S;
  var mils = floor(millis() - millisRolloverTime);
 
  noStroke();
  textAlign(CENTER);
  textSize(15); 
  fill(255); ///////////////////////////////////
  text("seconds left", (56.25 + 25), 65); 
  text("in this minute", (56.25 + 25), 85);   
  text( 60 - second(), (56.25 + 25), 45); 
 
 
  text("minutes left", (56.25 + 25) * 2 + 25, 65); 
  text("in this hour", (56.25 + 25) * 2 + 25, 85); 
  text( 60 - minute(), (56.25 + 25) * 2 + 25, 45); 
 
 
  text("hours left", (56.25 + 25) * 3 + 50, 65); 
  text("in this day", (56.25 + 25) * 3 + 50, 85); 
  text(24 - hour() - 1 , (56.25 + 25) * 3 + 50, 45); 
 
  text("days left", (56.25 + 25) * 4 + 75, 65); 
  text("in this month", (56.25 + 25) * 4 + 75, 85);
  text((monthAmountTable[month() -1] - day()) + 1, (56.25 + 25) * 4 + 75, 45); 
 
 
  text("months left", (56.25 + 25) * 5 + 100, 65);
  text("in this year", (56.25 + 25) * 5 + 100, 85); 
  text((12 - month())+ 1, (56.25 + 25) * 5 + 100, 45); 
 
  text("years left", (56.25 + 25) * 6 + 125, 65); 
  text("in this decade", (56.25 + 25) * 6 + 125, 85); 
  text((10 / (year() % 10)), (56.25 + 25) * 6 + 125, 45); 
 
 
  text("years left\n" + "on average", (56.25 + 25) * 7 + 150, 65); 
  text(round(72.74 - input.value()) - 1, (56.25 + 25) * 7 + 150, 45); 
 
  text("press right key to get some suggestions to fill this time", Width/2, Height - 15); 
 
 
  var lifeExpectancyBarWidth = map(LifeExpectancy, 72.74, 0, 0, 160); 
 
  var decadeBarWidth = map(De, 10, 0, 0, 160); 
 
  var yearBarWidth = map(Y, 1/12, 1, 0, 160); 
 
  var monthBarWidth = map(Mo, 0, 1, 0, 160); 
 
  var dayBarWidth = map(D, (1/24), 1, 0, 160); 
 
  var hourBarWidth   = map(H, 0, 23, 0, 160);
 
  var minuteBarWidth = map(M, 0, 59, 0, 160);
 
  var secondBarWidth = map(S, 0, 59, 0, 160);
 
  // Make a bar which *smoothly* interpolates across 1 minute.
  // We calculate a version that goes from 0...60, 
  // but with a fractional remainder:
  var secondsWithFraction = S + (mils / 1000.0);
  var secondsWithNoFraction = S;
  var secondBarWidthChunky = map(secondsWithNoFraction, 0, 60, 0, width);
  var secondBarWidthSmooth = map(secondsWithFraction,   0, 60, 0, 160);
 
  fill(150); 
  rect((56.25 * 3) + (50 * 2), 100, 50, 160);      //h
  rect((56.25 * 2) + 50, 100, 50, 160);   //m
  rect(56.25, 100, 50,  160); //s
 
 
  rect((56.25 * 4) + (50 * 3), 100, 50, 160); 
  rect((56.25 * 5) + (50 * 4), 100, 50, 160); 
  rect( (56.25 * 6) + (50 * 5), 100, 50, 160); 
 
  rect((56.25 * 7) + (50 * 6), 100, 50, 160);     
 
 
  fill(170, 1, 20);
  rect((56.25 * 3) + (50 * 2), 100, 50, 160 - hourBarWidth);      //h
  rect((56.25 * 2) + 50, 100, 50, 160 - minuteBarWidth);   //m
  rect(56.25, 100, 50,  160 - secondBarWidthSmooth); //s
 
 
  rect((56.25 * 4) + (50 * 3), 100, 50, 160 - monthBarWidth); 
  rect((56.25 * 5) + (50 * 4), 100, 50, 160 - yearBarWidth); 
  rect( (56.25 * 6) + (50 * 5), 100, 50, 160 - decadeBarWidth); 
 
  rect((56.25 * 7) + (50 * 6), 100, 50, 160 - lifeExpectancyBarWidth); 
 
 
  }
 
  else if ( AdviceMode == true){
 
 
 
  var nowSeconds = millis() 
  var elapsedSeconds = nowSeconds - lastChangeSeconds; 
 
  var nowMinutes = minute(); 
  var elapsedMinutes = nowMinutes - lastChangeMinutes; 
 
  var nowHours = hour();
  var elapsedHours = nowHours - lastChangeHours; 
 
  var nowMonths = month();
  var elapsedMonths = nowMonths - lastChangeMonths; 
 
  var nowYears = year(); 
  var elapsedYears = nowYears - lastChangeYears; 
 
  var nowDecade = year() % 10;
  var elapsedDecades = nowDecade - lastChangeDecade; 
 
 
  if (elapsedSeconds > waitTimeSeconds){
    lastChangeSeconds = nowSeconds; 
    minutesIndex = (minutesIndex + 1) % minuteActs.length;}
 
  if (elapsedMinutes > waitTimeMinutes){
    lastChangeMinutes = nowMinutes; 
    hoursIndex = (hoursIndex + 1) % hourActs.length;}
 
  if (elapsedHours > waitTimeHours){
    lastChangeMinutes = nowMinutes; 
    hoursIndex = (hoursIndex + 1) % hourActs.length;}  
 
 
  fill(0); 
  rect(0, 0, 800, 800); 
 
  noStroke();
  textAlign(CENTER);
  textSize(15); 
  fill(255); 
 
 
  text(minuteActs[minutesIndex], (56.25 + 25), Height * (2/5)); 
  text("in this minute", (56.25 + 25), Height -65);   
  //text( 60 - second(), (56.25 + 25), 45); 
 
 
  text(hourActs[hoursIndex], (56.25 + 25) * 2 + 25, Height * (2/5)); 
  text("in this hour", (56.25 + 25) * 2 + 25, Height - 65); 
  //text( 60 - minute(), (56.25 + 25) * 2 + 25, 45); 
 
 
  text(dayActs[daysIndex], (56.25 + 25) * 3 + 50, Height * (2/5));
  text("in this day", (56.25 + 25) * 3 + 50, Height -65); 
  //text(24 - hour() - 1 , (56.25 + 25) * 3 + 50, 45); 
 
  text("try", (56.25 + 25) * 4 + 75, 45); 
 
 
  text(monthActs[monthsIndex], (56.25 + 25) * 4 + 75, Height * (2/5)); 
  text("in this month", (56.25 + 25) * 4 + 75, Height - 65);
  //text((monthAmountTable[month() -1] - day()) + 1, (56.25 + 25) * 4 + 75, 45); 
 
 
  text(yearActs[yearsIndex], (56.25 + 25) * 5 + 100, Height * (2/5)); 
  text("in this year", (56.25 + 25) * 5 + 100, Height - 65); 
  //text((12 - month())+ 1, (56.25 + 25) * 5 + 100, 45); 
 
  text(decadeActs[decadesIndex], (56.25 + 25) * 6 + 125, Height * (2/5));
  text("in this decade", (56.25 + 25) * 6 + 125, Height - 65); 
  //text(10 / (year() % 10), (56.25 + 25) * 6 + 125, 45); 
 
 
  text(lifetimeActs[lifetimesIndex], (56.25 + 25) * 7 + 150, Height * (2/5)); 
  text("in this lifetime", (56.25 + 25) * 7 + 150, Height - 65); 
  //text(round(72.74 - input.value()) - 1, (56.25 + 25) * 7 + 150, 45);   
 
  text("press left key to look at your time", Width/2, Height - 15);  
  } 
}

 

 

breep-LookingOutwards02

I decided to talk about The Binding Of Isaac as my choice of generative art, mostly because its one of the few generated games that I have found myself play over and over and over again, and with my general propensity to not replay games I find this significant to me.

The game follows the story of Isaac, a young boy whose mother is asked by God to sacrifice him as a test of her faith. Upon trying to murder him, Isaac flees to their basement where he must fight for his life against a cohort of monster's and manifestations of traditionally evil elements that faith challenges.  It is this element that I so admire about this work, the complete freedom to enjoy it's gameplay or read into the dense subplot about conflicts over religion and how evil manifests itself within the stereotypes we associate with certain qualities of character (eg Greed, Envy etc).

The floors are generated from a library of rooms, with certain fixed rooms (like the starting room and the boss fight room) acting as cruxes for the rest of the rooms. What makes the game so replay are the endless combinations of items, enemies and rooms which makes every individual room a unique experience, as well as each instance of the game. The system as a whole is very ordered, as multiple replays will make apparent, but its the chaotic nature of every individual room that really makes the game.  It was heavily inspired by the first Legend of Zelda, with the gameplay following a very similar format. The art style of the game stands bold as well, with the combination of the algorithm and the design of the rooms combining to build the overall experience.

Website

Creation: Edmund McMillen and Florian Himsl, initially released in 2011, with a remake (The Binding of Isaac: Rebirth) in 2014

 

 

 

 

breep-Reading03

I find my relationship to technology and art somewhat tenuous. I came into CMU deeply interested in art, and not so much technology and as I have been here those two have swapped, and are swapping back again. For awhile I've viewed technology as a toolkit for art separating the two, but being at CMU has made be realise that in this niche of combining the two, they are one and the same. Advances in technology are advances in art, and art advances technology through experimentation. I compare this to the inception of ideas. Our clock project provides the same baseline, with the same technology available to all of us who undertake it, and yet each of us find new ways to piece together what we are given into entirely different and new manifestations.

However, I've also been struggling with the novelty of what we make. This concept of the first word art really jars with me. I fully accept and acknowledge the experimentation, but at the same time my conception of art/my interest in art history is framed by completed works that leave an impact on the timeline of art. But I also recognize that each novel thing we make leaves an impact on us as creators, something I forget far too often as I make work for assignments rather than for growing myself as an artist.

breep-Scope

My design largely stemmed off the idea of conveying circles within circles. I wanted to show how the movement of the black circle within the larger unit conveys the movement of a larger black circle that is made by the sum of its parts. This was a notion that I wanted to explore in my gif, but never really got round to integrating it, so this was a kind of nod to that idea.

/*
// Template for KidzLabs/4M/Toysmith Animation Praxinoscope
// https://www.amazon.com/4M-3474-Animation-Praxinoscope/dp/B000P02HYC
// https://www.walmart.com/ip/Animation-Praxinoscope-Science-Kits-by-Toysmith-3474/45681503
// Developed for p5.js, September 2018 * Golan Levin 
 
*/
 
 
 
var inch = 72.0; 
var diamArtInner = inch * 1.50; 
var diamArtOuter = inch * 4.80; 
var diamCutInner = inch * 1.41; 
var diamCutOuter = inch * 4.875; 
var holeDy = inch * 0.23;
var holeDx = inch * 0.20;
var holeD = inch * 0.1;
 
var nFrames = 10; 
var myFrameCount = 0;
var exportFrameCount = 0; 
 
var bAnimate = true;
var bExportFrameImages = false;
var bRecordingSinglePNG = false;
 
//-------------------------------------------------------
function setup() {
  createCanvas(792, 612); // 11x8.5" at 72DPI
  frameRate(20);
  smooth();
} 
 
 
//-------------------------------------------------------
function draw() {
  background(240); 
 
  // Do all the drawing. 
  push(); 
  translate(width/2, height/2);
  drawCutLines(); 
  drawGuides(); 
  drawAllFrames();
  pop();
 
 
  if (bExportFrameImages){
    // Note that myFrameCount is incremented elsewhere.
    var filename = "myZoetrope_" + nf(myFrameCount,2) + ".png";
    saveCanvas(filename, 'png');
    if (myFrameCount &gt;= nFrames){
      bExportFrameImages = false;
    }
  }
 
 
  if (bRecordingSinglePNG) {
    saveCanvas('myPraxinoscope.png', 'png');
    bRecordingSinglePNG = false;
  }
}
 
 
//-------------------------------------------------------
function keyPressed() {
  switch (key) {
  case ' ': 
    // Press spacebar to pause/unpause the animation. 
    bAnimate = !bAnimate;
    break;
 
  case 'p':
    case 'P':
      // Press 'p' to export a single PNG for the Zoetrope. 
      // Note: This is for 17x11" paper! 
      // Be sure to print at 100%!
      bRecordingSinglePNG = true;
      break;
 
    case 'f':
    case 'F':
      // Press 'f' to export multiple frames 
      // (in order to make an animated .GIF)
      // such as with http://gifmaker.me/
      myFrameCount = 0;
      exportFrameCount = 0;
      bExportFrameImages = true;
      bAnimate = true;
      break;
  }
}
 
//-------------------------------------------------------
function drawCutLines() {
  fill(0); 
  textAlign(CENTER, BOTTOM); 
  text("Praxinoscope Template", 0, 0-diamCutOuter/2-6); 
 
  stroke(0); 
  strokeWeight(1.0);
 
  noFill(); 
  if (!bRecordingSinglePNG) {
    fill(255); 
  }
  ellipse(0, 0, diamCutOuter, diamCutOuter);
 
  noFill(); 
  if (!bRecordingSinglePNG) {
    fill(240); 
  }
  ellipse(0, 0, diamCutInner, diamCutInner);
 
  noFill(); 
  ellipse(diamCutOuter/2 - holeDx, 0-holeDy, holeD, holeD); 
 
  line (diamCutInner/2, 0, diamCutOuter/2, 0);
}
 
//-------------------------------------------------------
function drawGuides() {
  // This function draws the guidelines. 
  // Don't draw these when we're exporting the PNG. 
  if (!bRecordingSinglePNG) {
 
    noFill(); 
    stroke(128); 
    strokeWeight(0.2); 
    ellipse(0, 0, diamArtInner, diamArtInner); 
    ellipse(0, 0, diamArtOuter, diamArtOuter);
 
    for (var i=0; i&lt;nFrames; i++) {
      var angle = map(i, 0, nFrames, 0, TWO_PI); 
      var pxi = diamArtInner/2 * cos(angle);
      var pyi = diamArtInner/2 * sin(angle);
      var pxo = diamArtOuter/2 * cos(angle);
      var pyo = diamArtOuter/2 * sin(angle);
      stroke(128); 
      strokeWeight(0.2);
      line (pxi, pyi, pxo, pyo);
    }
 
    // Draw the red wedge outline, highlighting the main view.
    var redWedge = 7; // assuming nFrames = 10
    for (var i=redWedge; i&lt;=(redWedge+1); i++) {
      var angle = map(i, 0, nFrames, 0, TWO_PI); 
      var pxi = diamArtInner/2 * cos(angle);
      var pyi = diamArtInner/2 * sin(angle);
      var pxo = diamArtOuter/2 * cos(angle);
      var pyo = diamArtOuter/2 * sin(angle);
      stroke(255, 0, 0); 
      strokeWeight(2.0);
      line (pxi, pyi, pxo, pyo);
    }
    noFill(); 
    stroke(255, 0, 0); 
    strokeWeight(2.0);
    var startAngle = redWedge*TWO_PI/nFrames;
    var endAngle = (redWedge+1)*TWO_PI/nFrames;
    arc(0, 0, diamArtInner, diamArtInner, startAngle, endAngle); 
    arc(0, 0, diamArtOuter, diamArtOuter, startAngle, endAngle); 
 
 
    for (var i=0; i&lt;nFrames; i++) {
      var angle = map(i, 0, nFrames, 0, TWO_PI); 
 
      push();
      rotate(angle); 
      var originY = ((diamArtOuter + diamArtInner)/2)/2;
      translate(0, 0-originY); 
 
      noFill(); 
      stroke(128); 
      strokeWeight(0.2);
      line (-inch/2, 0, inch/2, 0); 
      line (0, -inch/2, 0, inch/2); 
 
      pop();
    }
  }
}
 
//-------------------------------------------------------
function drawAllFrames() {
  for (var i=0; i&lt;nFrames; i++) {
    var angle = map(i, 0, nFrames, 0, TWO_PI); 
    var originY = ((diamArtOuter + diamArtInner)/2)/2;
 
    push();
    rotate(angle); 
    translate(0, 0-originY); 
    scale(0.8, 0.8); // feel free to ditch this 
 
    var whichFrame = i; 
    if (bAnimate) {
      whichFrame = (i+myFrameCount)%nFrames;
    }
    drawArtFrame (whichFrame); 
    // drawArtFrameAlternate (whichFrame); 
 
    pop();
  }
  myFrameCount++;
}
 
 
//-------------------------------------------------------
function drawArtFrame ( whichFrame ) { 
  // Draw the artwork for a generic frame of the Praxinoscope, 
  // given the framenumber (whichFrame) out of nFrames.
  // NOTE #1: The "origin" for the frame is in the center of the wedge.
  // NOTE #2: Remember that everything will appear upside-down!
 
   var nCircles = 10 
   for (var i=0; i &lt;= nCircles; i++) {
     var radius = 20 
     if (whichFrame != i){
       fill(255);}
 
     else {
       fill(0);}
 
     var cx = radius * cos((TWO_PI/10) * i); 
     var cy = radius * sin((TWO_PI/10) * i);
     ellipse(cx, cy, 20, 20);
   }
 
}
 
//-------------------------------------------------------
function drawArtFrameAlternate( whichFrame ) { 
  // An alternate drawing test. 
  // Draw a falling object. 
 
 
  // Draw a little splat on the frame when it hits the ground. 
  if (whichFrame == (nFrames-1)) {
    stroke(0, 0, 0); 
    strokeWeight(0.5); 
    var nL = 10;
    for (var i=0; i&lt;nL; i++) {
      var a = HALF_PI + map(i, 0, nL-1, 0, TWO_PI);
      var cx = 12 * cos(a);
      var cy = 10 * sin(a); 
      var dx = 16 * cos(a);
      var dy = 13 * sin(a); 
      line (cx, 45+cy, dx, 45+dy);
    }
  }
 
  // Draw a little box frame
  fill(255); 
  stroke(0, 0, 0);
  strokeWeight(1); 
  rect(-5, -50, 10, 100); 
 
  // Make the puck accelerate downward
  var t = map(whichFrame, 0, nFrames-1, 0, 1); 
  var t2 = pow(t, 2.0); 
  var rh = 8 + whichFrame * 0.5; // wee stretch
  var ry = map(t2, 0, 1, 0, 100-rh) - 50; 
 
  noStroke(); 
  fill(0, 0, 0);
  rect(-5, ry, 10, rh);
}

 

 

breep-AnimatedLoop

I ended up using the double exponential sigmoid as I wanted the squares to be able to tend toward the centre point from both sides. I initially had blocked out the squares on rectangles which highlighted where the squares would appear and re-appear, but I didn't like how busy they made the image. Once this had been laid out, I had to adjust the percentage amounts of each square on the sigmoid so that they all paused at that common central point. Once this was done I wanted to incorporate some form of spiral motion, but I wanted it to also be somewhat bi-parted as well to go with the squares, hence the two spiralling arms.

I felt I succeeded with the sigmoid nature of the squares, and am pretty proud of how they as a unit follow a curve, but also individually do. I still think the image is a bit too busy, and I still would've liked to incorporate more circular motion but it would have oversaturated the gif with content I think. The squares don't line up as well as I would like, given that I had to adjust the percentages of the sigmoids by eye so a more mathematic approach to that would make it appear that bit more fluid.

 
// Template used from 60-212 Website 
 
// This is a template for creating a looping animation in p5.js (JavaScript). 
// When you press the 'F' key, this program will export a series of images into
// your default Downloads folder. These can then be made into an animated gif. 
// This code is known to work with p5.js version 0.6.0
// Prof. Golan Levin, 28 January 2018
 
// INSTRUCTIONS FOR EXPORTING FRAMES (from which to make a GIF): 
// 1. Run a local server, using instructions from here:
//    https://github.com/processing/p5.js/wiki/Local-server
// 2. Set the bEnableExport variable to true.
// 3. Set the myNickname variable to your name.
// 4. Run the program from Chrome, press 'f'. 
//    Look in your 'Downloads' folder for the generated frames.
// 5. Note: Retina screens may export frames at twice the resolution.
 
 
//===================================================
// User-modifiable global variables. 
var myNickname = "nickname";
var nFramesInLoop = 120;
var bEnableExport = false;
 
// Other global variables you don't need to touch.
var nElapsedFrames;
var bRecording;
var theCanvas;
 
 
 
//===================================================
function setup() {
  theCanvas = createCanvas(640, 640);
  bRecording = false;
  nElapsedFrames = 0;
  frameRate(120); 
}
 
//===================================================
function keyTyped() {
  if (bEnableExport) {
    if ((key === 'f') || (key === 'F')) {
      bRecording = true;
      nElapsedFrames = 0;
    }
  }
}
 
//===================================================
 
function draw() {
 
  // Compute a percentage (0...1) representing where we are in the loop.
  var percentCompleteFraction = 0;
  if (bRecording) {
    percentCompleteFraction = float(nElapsedFrames) / float(nFramesInLoop);
  } else {
    percentCompleteFraction = float(frameCount % nFramesInLoop) / float(nFramesInLoop);
  }
 
  // Render the design, based on that percentage. 
  // This function renderMyDesign() is the one for you to change. 
  renderMyDesign (percentCompleteFraction);
 
  // If we're recording the output, save the frame to a file. 
  // Note that the output images may be 2x large if you have a Retina mac. 
  // You can compile these frames into an animated GIF using a tool like: 
  if (bRecording && bEnableExport) {
    var frameOutputFilename = myNickname + "_frame_" + nf(nElapsedFrames, 4) + ".png";
    print("Saving output image: " + frameOutputFilename);
    saveCanvas(theCanvas, frameOutputFilename, 'png');
    nElapsedFrames++;
 
    if (nElapsedFrames >= nFramesInLoop) {
      bRecording = false;
    }
  }
} 
 
//===================================================
function renderMyDesign (percent) {
  //
  // THIS IS WHERE YOUR ART GOES. 
  // This is an example of a function that renders a temporally looping design. 
  // It takes a "percent", between 0 and 1, indicating where we are in the loop. 
  // Use, modify, or delete whatever you prefer from this example. 
  // This example uses several different graphical techniques. 
  // Remember to SKETCH FIRST!
 
  //----------------------
  // here, I set the background and some other graphical properties
  background(0);
  smooth();
  stroke(0, 0, 0);
  strokeWeight(0);
 
  //----------------------
  // Here, I assign some handy variables. 
  var cx = 100;
  var cy = 100;
 
  //----------------------
 
  // COLOUR NUMBERS FROM BOTTOM
 
  // ORANGE 1 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(192, 576, 384, 32);   
 
  var eased = doubleExponentialSigmoid (percent, 0.9); 
  eased = (eased + 0.319)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 192, 544); 
  fill (253, 106, 2); 
  rect (xPosition1, 576, 32, 32);     
 
  // ORANGE 2 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(160, 512, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.8); 
  eased = (eased + 0.45)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 160, 480); 
  fill (253, 106, 20); 
  rect (xPosition1, 512, 32, 32);  
 
  // ORANGE 3 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(128, 448, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.6); 
  eased = (eased + 0.5)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 128, 480); 
  fill (253, 106, 2); 
  rect (xPosition1, 448, 32, 32);    
 
  // ORANGE 4 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(192, 384, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.4); 
  eased = (eased + 0.3)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 192, 544); 
  fill (253, 106, 20); 
  rect (xPosition1, 384, 32, 32);     
 
  // ORANGE 5 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(64, 320, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.2); 
  eased = (eased + 0.66)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 64, 416); 
  fill (253, 106, 20); 
  rect (xPosition1, 320, 32, 32);  
 
  // ORANGE 6 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(128, 256, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.2); 
  eased = (eased + 0.47)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 128, 480); 
  fill (253, 106, 20); 
  rect (xPosition1, 256, 32, 32);  
 
  // ORANGE 7 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(224, 192, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.4); 
  eased = (eased + 0.19)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 224, 576); 
  fill (253, 106, 20); 
  rect (xPosition1, 192, 32, 32);  
 
  // ORANGE 8
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(156, 128, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.6); 
  eased = (eased + 0.39)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 156, 508); 
  fill (253, 106, 20); 
  rect (xPosition1, 128, 32, 32);   
 
  // ORANGE 9
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(32, 64, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.8); 
  eased = (eased + 0.73)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 32, 384); 
  fill (253, 106, 20); 
  rect (xPosition1, 64, 32, 32);   
 
  // ORANGE 10
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(128, 0, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.9); 
  eased = (eased + 0.47)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 128, 480); 
  fill (253, 106, 2); 
  rect (xPosition1, 0, 32, 32);        
 
  push();
  translate(320, 320);
  var orange = true; 
  for (var squareX = 0; squareX <= width; squareX += 32){
 
   // Here's a linearly-moving square
   var eased = doubleExponentialSigmoid (percent, 0.5); 
   eased = (eased)%1.0; // shifted by a half-loop, for fun
   var yPosition = map(eased, 0, 1, topY, botY);    
 
   var rotatingSquareAngle = percent * TWO_PI
   rotate(rotatingSquareAngle);  
 
   var squareSize = 20;
   var topY = 0 - squareSize - 2;
   var botY = height + 2;
   var sPercent = (percent)%1.0; // shifted by a half-loop
   // var yPosition = map(sPercent, 0, 1, topY, botY);
 
   if (orange == true){
     fill(253, 106, 2);
     orange = false;}
   else{
    fill(60, 170, 230);
    orange = true;}
 
   rect(squareX, yPosition, 20, 20);}   
  pop();  
 
 
  // BLUE 1 
  // strokeWeight(0);
  // fill(120, 253, 106, 2);
  // rect(128, 608, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.2); 
  eased = (eased + 0.5)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 128, 480); 
  fill (60, 170, 230); 
  rect (xPosition1, 608, 32, 32);   
 
  // BLUE 2 
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(64, 544, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.4); 
  eased = (eased + 0.682)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 64, 416); 
  fill (60, 170, 230); 
  rect (xPosition1, 544, 32, 32);     
 
  // BLUE 3 
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(224, 480, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.6); 
  eased = (eased + 0.23)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 224, 576); 
  fill (60, 170, 230); 
  rect (xPosition1, 480, 32, 32);  
 
  // BLUE 4 
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(32, 416, 384, 32);    
 
  var eased = doubleExponentialSigmoid (percent, 0.8); 
  eased = (eased + 0.77)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 32, 384); 
  fill (60, 170, 230); 
  rect (xPosition1, 416, 32, 32);    
 
  // BLUE 5 
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(160, 352, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.9); 
  eased = (eased + 0.39)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 160, 512); 
  fill (60, 170, 230); 
  rect (xPosition1, 352, 32, 32);     
 
  // BLUE 6 
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(256, 288, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.9); 
  eased = (eased + 0.115)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 256, 608); 
  fill (60, 170, 230); 
  rect (xPosition1, 288, 32, 32);    
 
  // BLUE 7 
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(96, 224, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.8); 
  eased = (eased + 0.56)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 96, 448); 
  fill (60, 170, 230); 
  rect (xPosition1, 224, 32, 32);    
 
 
  // BLUE 8
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(64, 160, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.6); 
  eased = (eased + 0.65)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 64, 416); 
  fill (60, 170, 230); 
  rect (xPosition1, 160, 32, 32);    
 
  // BLUE 9 
  //strokeWeight(0);
  //fill(253, 106, 2);
  // rect(192, 96, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.4); 
  eased = (eased + 0.284)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 192, 544); 
  fill (60, 170, 230); 
  rect (xPosition1, 96, 32, 32);    
 
 
  // BLUE 10
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(192, 32, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.2); 
  eased = (eased + 0.27)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 192, 544); 
  fill (60, 170, 230); 
  rect (xPosition1, 32, 32, 32);   
 
 
 
  push();
  translate(320, 320);
  var orange = true; 
  for (var squareX = 0; squareX <= width; squareX += 32){
 
   // Here's a linearly-moving square
   var eased = doubleExponentialSigmoid (percent, 0.5); 
   eased = (eased)%1.0; // shifted by a half-loop, for fun
   var yPosition = map(eased, 0, 1, topY, botY);    
 
   var rotatingSquareAngle = percent * TWO_PI
   rotate(-rotatingSquareAngle);  
 
   var squareSize = 20;
   var topY = 0 - squareSize - 2;
   var botY = height + 2;
   var sPercent = (percent)%1.0; // shifted by a half-loop
   // var yPosition = map(sPercent, 0, 1, topY, botY);
 
   if (orange == true){
     fill(253, 106, 2);
     orange = false;}
   else{
    fill(60, 170, 230);
    orange = true;}
 
   rect(squareX, yPosition, 20, 20);}   
  pop();      
 
}
 
// Symmetric double-element sigmoid function ('_a' is the slope)
// See https://github.com/IDMNYU/p5.js-func/blob/master/lib/p5.func.js
// From: https://idmnyu.github.io/p5.js-func/
//===================================================
function doubleExponentialSigmoid (_x, _a){
  if(!_a) _a = 0.75; // default
 
  var min_param_a = 0.0 + Number.EPSILON;
  var max_param_a = 1.0 - Number.EPSILON;
  _a = constrain(_a, min_param_a, max_param_a);
  _a = 1-_a;
 
  var _y = 0;
  if (_x<=0.5){
    _y = (pow(2.0*_x, 1.0/_a))/2.0;
  }
  else {
    _y = 1.0 - (pow(2.0*(1.0-_x), 1.0/_a))/2.0;
  }
  return(_y);
}

 

 

breep-Reading02

1A

I was immediately reminded of Ian Cheng's work Emissaries in relation to efficient Complexity. The work seems entirely arbitrary, and in some ways his design of it is, but the underlying relationships between his avatars organize this system in a way that is simultaneously perceptible as both ordered and chaotic. I would say that it tends toward the randomness as a viewer unaware in the skills required for generative making, but the underlying narrative and relationship structure is what makes it ordered.

gif courtesy of : http://www.contemporaryartdaily.com/2017/09/ian-cheng-at-moma-ps1/

1B

The Problem of Uniqueness: Given that alot of my work before CMU was primarily in the medium of print making, the idea of the uniqueness of prints strongly echoed for me in this statement. Through this, I fully agree that generative art creates completely new and unique artifacts, which contribute to a larger body that comes together to make that work of art. In a way this problem explores how the same idea can also evolve rapidly with the smallest of changes that generative systems inherently produce.