nixel-Body

Video:

Gif:

Description:

This project came naturally to me since I'm interested in dance and videography. From the beginning, I was curious about how I could convey movement, choreography, and group dynamics with the motion capture resources provided.  I wanted to study how choreography that relied on more than one dancer created compositions with bodies and movements on screen.

Process:

I went through several iterations of how I could convey what I wanted to, so after figuring out how Posenet worked, I ended up making a lot of visual representations of bodies in movement using some of my favorite dance videos. A lot of these I trashed because they looked too clunky and didn't feel right. It felt eh getting rid of several hundred lines of usable material, but in the end, I decided that visual simplicity and readability was more important than the technical work behind it.

I was not aiming for accuracy with this project, and I was okay with an end result that was not so minutely tied to the body in particular since I wanted to visualize several bodies in relation to each other. I wanted some sort of big picture, wholistic experience rather than something dependent on accuracy. Early on, I found that Posenet would never be able to capture the bodies as well as I wanted to, so I decided to use that messiness as an advantage. I kind of like how it sometimes mistakes body parts for each other, or sees a phantom body part in the wall somewhere.

The first, second, and fourth video in the compilation are all choreographies/videographies that I love a lot. The third video is one that I filmed for KPDC, a dance club on campus. I was interested to see how a video that I produced compared to those that I admired.

Still Images:

Code:

// Copyright (c) 2018 ml5
// Copyright (c) 2018 ml5
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
 
/* ===
ml5 Example
PoseNet example using p5.js
=== */
 
// PoseNet with a pre-recorded video, modified from:
// https://github.com/ml5js/ml5-examples/blob/master/p5js/PoseNet/sketch.js
 
let poseNet;
let poses = [];
let poseArray = [];
let noseArray = [];
let leftWristArray = [];
let rightWristArray = [];
let rightAnkleArray = [];
 
let video;
var videoIsPlaying;
 
function setup() {
  frameRate(10);
  videoIsPlaying = false;
  createCanvas(833, 480);
  video = createVideo('yabbay.mp4', vidLoad);
  video.size(width, height);
  poseNet = ml5.poseNet(video, modelReady);
  poseNet.on('pose', function(results) {
    poses = results;
    if(poses.length > 0){
      poseArray.push(poses);
    }
  });
 
  video.hide();
}
 
function modelReady() {
    console.log('Model Loaded');
}
 
function mousePressed(){
  vidLoad();
}
 
function draw() {
  image(video, 0, 0, width, height);
  //background(0);
  drawKeypoints();
}
 
function drawKeypoints()  {
//   for (let i = 0; i < poses.length; i++) {
//
//     let pose = poses[i].pose;
//
//     for (let j = 2; j < pose.keypoints.length; j=j+10) {
//       for (let k = 3; k < pose.keypoints.length; k=k+10){
//         for (let l = 4; l < pose.keypoints.length; l=l+10){
//           for (let m = 5; m < pose.keypoints.length; m=m+10){ // let keypoint = pose.keypoints[j]; // let keypoint2 = pose.keypoints[k]; // let keypoint3 = pose.keypoints[l]; // let keypoint4 = pose.keypoints[m]; // // if (keypoint.score > 0.2) {
//         strokeWeight(1);
//         stroke(255,0,0);
//
//         beginShape();
//         curveVertex(keypoint.position.x, keypoint.position.y);
//         curveVertex(keypoint2.position.x, keypoint2.position.y);
//         curveVertex(keypoint3.position.x, keypoint3.position.y);
//         curveVertex(keypoint4.position.x, keypoint4.position.y);
//         endShape();
//       }
//     }
//   }
//   }
// }
// }
 
  for (var i = 0; i < poses.length; i++){
    let pose = poses[i].pose;
    for (var j = 0; j < pose.keypoints.length; j++){ noFill(); strokeWeight(1); makeVectors("nose", pose, j, noseArray); makeVectors("leftWrist", pose, j, leftWristArray); makeVectors("rightAnkle", pose, j, rightAnkleArray); stroke(255); makeConnections(leftWristArray); makeConnections(noseArray); makeConnections(rightAnkleArray); } } } function makeVectors(part, pose, j, partArray){ if(pose.keypoints[j].part == part){ stroke(0, 0, 255); ellipse(pose.keypoints[j].position.x,pose.keypoints[j].position.y, 10); partArray.push(createVector(pose.keypoints[j].position.x,pose.keypoints[j].position.y)); if (partArray.length > 4){
      partArray.splice(0,1);
    }
  }
}
 
function makeConnections(partArray){
  beginShape();
  for (let k = 0; k < partArray.length; k++){
    curveVertex(partArray[k].x, partArray[k].y);
  }
  endShape();
}
 
function vidLoad() {
  video.stop();
  video.loop();
  videoIsPlaying = true;
}
 
function keyPressed(){
  if (videoIsPlaying) {
    video.pause();
    videoIsPlaying = false;
  } else {
    video.loop();
    videoIsPlaying = true;
  }
}

nixel-telematic

Embedded app:

Direct Link:

Custom Emoji Creator

How to interact:

Simply click on the small icons to customize the big one. There are 4 clear categories: eyebrows, eyes, mouth, and accessories. There can ever only be one (or none) of each type on the big emoji at once. Click the X if you ever want to clear that feature. You can interact with many people at once who are on their own browsers.

Description:

Sometimes you want to express an emotion that the current range of emoji's just don't cover. That was the purpose of this project. I took inspiration from iconic internet created emoji's like: Image result and wondered how many other emotions we feel but aren't able to express.

Gif of me playing with it along with a few friends:

My process:

For this project, I essentially mashed together two of the given prompts for when we're 'stuck for ideas': making a space where people can only interact with emoji's, and having the participants construct a monster corpse through body parts. And this is what I ended up with.

My process was pretty straightforward. I looked for existing dress up games on glitch to reference from, and found this one for cats and based the majority of my structure off of it. I spent a long time cutting apart emojis, formatting HTML, CSS, and messing with jQuery, all of which I'd never worked with before. I hit some pretty dumb bugs that I fought with for a long time (for example, not realizing I didn't import jQuery). I struggled a little with understanding the client-server stuff in application to my own project, but it was a lot simpler than it looked once I broke down the pathways.

Here are some notes I took on the given templates:

I made remixes of all of the templates and took notes on how each one worked with socket.io. This is how I brainstormed to apply it to my program:

I think a part of this project is that I want it to be kind of chaotic and unpredictable. I want multiple people to be able to explore the different options available and experiment. By having many people on at once, everyone with equal roles, it allows for lots of surprises. It is also good as a solo experience. I think of the multi-user interaction as a feature and not a defining point.

I shared it with my friends, and they had a lot of fun with it. At most, I think there were around 6 people messing with it at once, and everyone was amused at the results we were getting.

By the end of this project, I'd learned a lot about HTML, CSS, jQuery, socket.io, and glitch, and made something that made my friends laugh, so  it is pretty successful by my standards.

nixel-LookingOutwards03

I played flute for 8 years but still only have surface level knowledge of music. I think this exhibition, which takes a rather abstract concept and turns it into concrete physical representations, is neat. Music and sound usually exist invisibly, without physical indicators. Even when playing instruments, there is a disconnect between where to move your fingers and the ink on the page.  By linking different aspects of sound and music to physicality, it makes the process of learning and creating intuitive. If created on smaller scale, I could see this becoming part of early music education.

Another reason why I like this exhibition because it is very simple on the surface level, and any person with any amount of music knowledge can interact with and enjoy it, but if you're practiced and educated  in the craft, the exhibition also has a lot of potential to create great compositions.

nixel-viewing04

From what I am able to understand:

Spectacle is computer art that is technically proficient, aesthetically pleasing, and made for consumers.

Speculation is art that is aware of its limitations and materials and uses those to create self aware work that usually engages broad non-art related issues.

The first thing I thought of when Warburton started to discuss spectacle art was the iconic Gatorade water ad. It's brought up again and again in different classes over the years, but it is... nearly 100% spectacle I think. It creates animation in such a laborious and complex manner that emphasizes the technical brilliance that it required.  It brings all the attention to how unique and beautiful the end result is, and how it was done in a superfluous manner. It very much reminds me of the commercial that he shows in the beginning of the video. The same result could have easily been achieved using CGI, but instead they used something experimental. In terms of not being speculation, it doesn't really represent or deal with any sort of issue outside of itself, exploit the materials or techniques used, and was definitely very expensive to make.

I had a difficult time figuring out exactly what each scale meant, but this is my guess for the ad. (Like, doesn't surplus and waste essentially mean the same thing...I'm not sure).

nixel-clock

7:10AM

11:30PM

12:01AM

I had a tough time with this project, not because of a lack of ideas, but because of an excess. I'd brainstormed a ton of ideas, all of them relating to the concept of time, but not necessarily to clocks. Below is a snapshot of all the things I was pondering.

My problem was that I didn't know how exactly to relate these ideas to clocks, and how to represent them in an interesting visual way. I honestly think if I'd just focused on one and did some more research it would have turned out fine.

I was still stuck between ideas half way through the week when I thought of hourglasses. Hourglasses are a very visual object that help to keep time, so I started brainstorming for that.

I wanted to create one hourglass to cover the span of one day with day draining into night, then flipping it at sundown and having night drain into day. I was even going to extract the realtime sunrise and sunsets on weather websites to make it more accurate, however this was too difficult to implement in a short amount of time.

The underlying concept behind the hourglass was to represent how much time we have left rather than how much time has passed like a regular clock.  So once again, due to my awareness of the extent of my coding skills and the amount of time (haha) I had left to finish this, I decided to simplify my concept. It ended up being 3 glasses...an hourglass, a minuteglass, and a secondglass. There are a lot of things I want to fix about this...like making the 'sand' more lively, lining up the drop of the ball with the rise of the sand at the bottom, doing an actual flipping animation, somehow coding gravity for the sand, and making everything just flow smoother. My code is also clumsy and could be much more refined and efficient.

However, I think finished is better than perfect, and what I ended up with is an accumulation of many mistakes I made in the process, and I think this needed to happen so that I could learn from it and get it out of the way.

//thank you golan for the template
var millisRolloverTime;
var prevSec;
 
function setup() {
  createCanvas(750, 400);
  rectMode(CORNERS);
  noStroke();
  }
 
function draw() {
  background(200);
  var H = hour();
  var M = minute();
  var S = second();
  if (prevSec != S) {
    millisRolloverTime = millis();
  }
  prevSec = S;
  var mils = (floor(millis() - millisRolloverTime))/1000.0;
  var secmils = S + mils;
  var mins = M+(map(secmils, 0, 59, 0, 1));
  var hours = (H%12)+(map(mins, 0, 59, 0, 1));
 
  //hourglass
  fill(19, 70, 70);
  rect(0, 0, 250, height/2);
  rect(0, height/2 , 250, height);
 
  //minuteglass
  fill(19, 86, 86);
  rect(250, 0, 500, height/2);
  rect(250, height/2 , 500, height);
 
  //secondglass
  fill(52, 119, 106);
  rect(500, 0, width, height/2);
  rect(500, height/2 , width, height);
 
  hrglassBottom();
  hrglassTop();
  minglassBottom();
  minglassTop();
  secglassBottom();
  secglassTop();
 
  secBall(mils);
  minBall(secmils);
  hrBall(mins);
 
  fill(255);
 
  //hr mask
  triangle(250, 0,  145, height/2 , 250, height/2 );
  triangle(0, 0,  110, height/2 , 0, height/2 );
  triangle(0, height/2,  110, height/2 , 0, height);
  triangle(145, height/2,  250, height , 250, height/2);
 
  //min mask
  triangle(250, 0,  360, height/2 , 250, height/2 );
  triangle(250, height/2,  360, height/2 , 250, height );
  triangle(500, 0,  390, height/2 , 500, height/2);
  triangle(390, height/2,  500, height , 500, height/2);
 
  //sec mask
  triangle(500, 0,  610, height/2 , 500, height/2 );
  triangle(500, height/2,  610, height/2 , 500, height );
  triangle(width, 0,  645, height/2 , width, height/2);
  triangle(645, height/2,  width, height , width, height/2);
}
 
 
function minBall(mils){
  var y = map(mils, 0, 1, height/2, 435);
  var x = width/2;
  ellipse(x, y, 30, 30);
}
 
function secBall(mils){
  var x = 625;
  var y = map(mils, 0, 1, height/2, 435);
  ellipse(x, y, 30, 30);
}
 
function hrBall(mils){
    var r = map(hour(), 0, 60, 0, 255);
    fill(r, 0, 100);
    var x = 125;
    var y = map(mils, 0, 1, height/2, 435);
    ellipse(x, y, 30, 30);
}
 
//hr
function hrglassTop(){
  var r = map(hour(), 0, 24, 110, 190);
  fill(r, 9, 9);
  let glassHeight = map(hour(), 0, 24, 0, height/2);
 
  rect(0, glassHeight, 250, height/2);
}
 
function hrglassBottom(){
  let glassHeight = map(hour(), 0, 24, height, height/2);
  beginShape();
  var r = map(hour(), 0, 24, 110, 190);
  fill(r, 9, 9);
  vertex(0, height);
  for (var i = 0; i <= 250; i++){
    vertex(i, glassHeight);
  }
  vertex(250, height);
  endShape();
}
 
//minute
function minglassTop(){
  let glassHeight = map(minute(), 0, 60, 0, height/2);
  var r = map(minute(), 0, 60, 255, 100);
  fill(r, 0, 0);
  rect(250, glassHeight, 500, height/2);
}
 
function minglassBottom(){
let glassHeight = map(minute(), 0, 60, height, height/2);
  beginShape();
  var r = map(minute(), 0, 60, 255, 100);
  fill(r, 0, 0);
  vertex(250, height);
  for (var i = 250; i <= 500; i++){
    vertex(i, glassHeight);
  }
  vertex(500, height);
  endShape();
}
 
//second
function secglassTop(){
  let glassHeight = map(second(), 0, 60, 0, height/2);
  var g = map(second(), 0, 60, 150, 100);
  fill(255, g, g);
    rect(500, glassHeight, width, height/2);
}
 
function secglassBottom(){
  let glassHeight = map(second(), 0, 60, height, height/2+20);
  beginShape();
  var g = map(second(), 0, 60, 150, 100);
  fill(255, g, g);
  vertex(500, height);
  for (var i = 500; i <= width; i++){
    vertex(i, glassHeight);
  }
  vertex(width, height);
  endShape();
}

nixel-Reading03

"Why bother if it's already been done?"

Not to be overly critical but this phrase has rubbed me the wrong way every time I've heard it. I don't understand the obsession with wanting to create new, novel, and mind-blowing art. In my opinion, striving to only create first word art, or seeing first word art as the only true art, will bring a great deal of turmoil and suffering upon the artist.

Categorizing everything that is an iteration or inspired from existing work as "merely entertainment, not art" is pretty pretentious.  It insinuates that entertainment and art can't coexist within a piece, as if art can't be entertaining, or something entertaining can't be art. If we forever strive to make only first word art, then where is the substance? First word art is a proposal for the future. Without further iterations and deep dives into what that art could become, it remains quite useless. And at the same time, last word art can't exist without first word art.

I guess I just don't understand the need to categorize art in this way at all.  First and last word art can't exist without each other, and they can't exist without everything that comes in between, so why bother with the distinction? Why try to create black and white borders where there don't need to be any?

 

 

nixel-AnimatedLoop

I had a lot of fun with this project!

My process:

I started with some messy brainstorms from when we first got the prompt:

I thought that loops of characters bouncing down stairs, or being transported by a never ending escalator would be fun. I also considered doing skyscapes that looped between sunrise and sunset and a swinging character. In the end, I went with rain because it was the simplest in terms of shape and color design.

I thought that I would do some sort of walk cycle and plotted some leg rotations.

I went online and found a shape-heavy walk cycle gif and spliced some frames out to break it down.

However, when I began to code and actually look into the easing functions, I realized that it would be simpler to pair them with a bouncing animation instead of a walking one. It was sad to leave all the walking animation work I did, but I think I made a better choice in terms of time and simplicity. I think I will go back one day and make all of the ideas I had initially.

After a lot of experimentation (and suffering) I chose to use primarily the Flat Top Window easing function since it was bouncy, playful, and worked well for a looping animation since it was symmetrical.

Here is a thumbnail I made half way through coding in order to hash out the locations of some body parts.

I struggled with the rain since I thought it added to the narrative of the gif, but didn't necessarily loop. I also struggled with the umbrella since it's an interesting visual element but doesn't make much sense since the character isn't holding on to it. I did at one point code an umbrella handle and hands, but it made the image too complex so I got rid of them.

Critiquing myself, I think that I did well in keeping the design simple and appealing. I could have been more ambitious with connecting the umbrella to the character and been more efficient with my code (I organized it in groups of body parts but ended up repeating a lot of simple functions like noStroke() or fill() when I could have just organized the code more efficiently).

 

 
// This is a template for creating a looping animation in Processing/Java. 
// When you press the 'F' key, this program will export a series of images
// into a "frames" directory located in its sketch folder. 
// These can then be combined into an animated gif. 
// Known to work with Processing 3.3.6
// Prof. Golan Levin, January 2018
 
 
//===================================================
// Global variables. 
String  myNickname = "nixel"; 
int     nFramesInLoop = 60;
int     nElapsedFrames;
boolean bRecording; 
Drop[] drops = new Drop[50];
 
//===================================================
void setup() {
  size (640, 640); 
  bRecording = false;
  nElapsedFrames = 0;  
  for (int i = 0; i < drops.length; i++) {
   drops[i] = new Drop(); 
  }
}
//===================================================
void keyPressed() {
  if ((key == 'f') || (key == 'F')) {
    bRecording = true;
    nElapsedFrames = 0;
  }
}
//===================================================
void draw() {
  // Compute a percentage (0...1) representing where we are in the loop.
  float percentCompleteFraction = 0; 
  if (bRecording) {
    percentCompleteFraction = (float) nElapsedFrames / (float)nFramesInLoop;
  } else {
    percentCompleteFraction = (float) (frameCount % nFramesInLoop) / (float)nFramesInLoop;
  }
 
  // Render the design, based on that percentage. 
  renderMyDesign (percentCompleteFraction);
 
  // If we're recording the output, save the frame to a file. 
  if (bRecording) {
    saveFrame("frames/" + myNickname + "_frame_" + nf(nElapsedFrames, 4) + ".png");
    nElapsedFrames++; 
    if (nElapsedFrames >= nFramesInLoop) {
      bRecording = false;
    }
  }
}
//===================================================
void renderMyDesign (float percent) {
  int bgColor = 255;
  background (bgColor);
  stroke (0, 0, 0); 
  strokeWeight (2); 
  float pennerEase = FlatTopWindow(percent);
  noStroke();
 
  //umbrella
  float umbrellashift = (map(pennerEase, 0, 1, -50, -20)); 
  fill(255, 0, 0);
  ellipse(width/2, 240 + umbrellashift, 360, 360);
 
  //cutout umbrella
  fill(bgColor);
  int r = 250;
  for (int i = 0; i < 360; i += 30){
  float dy = sin(radians(i)) * r;
  float dx = cos(radians(i)) * r;
  ellipse(width/2 + dx, 240 + umbrellashift + dy, 180, 180);
  }
 
  rectMode(CENTER);
 
  //ground
  fill(10, 95, 223);
  rect(width/2, 600, width, 200);
 
  //puddle
  noFill();
  stroke(255);
  float jumpWeight = map(percent, 0, 1, 15, 0);
  float puddleEase = map(PennerEaseOutExpo(percent-0.7), 0, 1, 100, 1000);
  float puddleEaseY = map(PennerEaseOutExpo(percent), 0, 1, 0, 50); 
  strokeWeight(jumpWeight);
 
  if (percent >= 0.7){
    ellipse(355, 530, puddleEase, puddleEaseY);
    ellipse(200, 560, puddleEase, puddleEaseY);
    ellipse(300, 600, puddleEase, puddleEaseY);
    ellipse(50, 650, puddleEase, puddleEaseY);
    ellipse(550, 610, puddleEase, puddleEaseY);
  }
 
  //hair
  noStroke();
  float hairshift = (map(pennerEase, 0, 1, 60, -40)); 
  fill(0);
  arc(width/2, 240 + hairshift, 180, 300, PI, TWO_PI);
 
 
  //legs 
  float rX = map(pennerEase, 0, 1, 350, 340);
  float Y = map(pennerEase, 0, 1, 560, 510);
  float squishX = map(pennerEase, 0, 1, 10, 0);
  float lX = map(pennerEase, 0, 1, width - 360, width - 350);
  fill(247,227,40);
 
  //right leg
  triangle(rX, Y, rX - 5 - squishX, Y - 150, rX + 10 + squishX, Y - 150);
 
  //left leg
  triangle(lX, Y, lX - 5 - squishX, Y - 150, lX + 10 + squishX, Y - 150);
 
  //body
	float bsquish = map(pennerEase, 0, 1, 10, -10);
  float bodyshift = (map(pennerEase, 0, 1, 50, -20)); 
  fill(247, 227, 40);
  triangle(width/2, 170 + bodyshift, width/2 - 100 - bsquish, 380 + bodyshift, width/2 + 100 + bsquish, 380 + bodyshift);
 
  //mirrored legs 
  float mrX = map(pennerEase, 0, 1, 350, 340);
  float mrY = map(pennerEase, 0, 1, 510, 560);
  float msquishX = map(pennerEase, 0, 1, 10, 0);
  float mlX = map(pennerEase, 0, 1, width - 360, width - 350);
  fill(247,227,40);
 
  //right leg
  triangle(mrX, mrY + 50, mrX - 5 - msquishX, mrY + 175, mrX + 10 + msquishX, mrY + 175);
 
  //left leg
  triangle(mlX, mrY + 50, mlX - 5 - msquishX, mrY + 175, mlX + 10 + msquishX, mrY + 175);
  //head
  float headshift = (map(pennerEase, 0, 1, 55, -30)); 
  fill(255);
  ellipse(width/2, 170 + headshift, 100, 100);
 
  //mouth
  float mouthshift = (map(pennerEase, 0, 1, 30, -70)); 
  float mouthY = (map(pennerEase, 0, 1, -5, 10)); 
  fill(255, 0, 0);
  ellipse(width/2, 225 + mouthshift, 20, 15 + mouthY);
 
  //bangs  
  fill(0);
  arc(width/2, 150 + hairshift, 100, 100, PI, TWO_PI);
 
  //eyes
  float eyeY = (map(pennerEase, 0, 1, 1, 5)); 
  float eyeX = (map(pennerEase, 0, 1, 1, 5)); 
  ellipse(width/2 - 30, 200 + mouthshift, 10 + eyeX, 15 + eyeY);
  ellipse(width/2 + 30, 200 + mouthshift, 10 + eyeX, 15 + eyeY);
 
  //arms
  fill(247,227,40);
 
  float Ya = map(pennerEase, 0, 1, 10, 80);
  //right arm
  triangle(345, 230 + bodyshift, 345, 260 + bodyshift, 450, 250 + Ya);
 
  //left arm
  triangle(width - 345, 230 + bodyshift, width - 345, 260 + bodyshift, width - 450, 250 + Ya);
 
  //rain
  for (int i = 0; i < drops.length; i++){
  drops[i].fall();
  drops[i].show();
  }
 
}
 
//===================================================
//rain code refenced from Dan Shiffman's Purple Rain Coding Challenge
class Drop {
 float x = random(width);
 float y = random(0, height);
 float yspeed = 11;
 float len = 15;
 
 void fall(){
   y += yspeed;
 
  if (y > height) {
   y = 0;
   yspeed = 11;
  }
 
   }
 
 void show(){
  stroke(10, 95, 223);
  strokeWeight(2);
  line(x, y, x, y+len);
 }
}
 
//===================================================
float FlatTopWindow (float x) {
  //easing functions from Pattern Master https://github.com/golanlevin/Pattern_Master
  // http://en.wikipedia.org/wiki/Window_function 
 
  final float a0 = 1.000;
  final float a1 = 1.930;
  final float a2 = 1.290;
  final float a3 = 0.388;
  final float a4 = 0.032;
 
  float pix = PI*x;
  float y = a0 - a1*cos(2*pix) + a2*cos(4*pix) - a3*cos(6*pix) + a4*cos(8*pix);
  y /= (a0 + a1 + a2 + a3 + a4); 
 
  return y;
}
 
float PennerEaseOutExpo(float t) {
  return (t==1) ? 1 : (-pow(2, -10 * t) + 1);
}

nixel-Scope

 

pdf: zoetrope-output

For my zoetrope design, I experimented a lot with arcs. I started off with just one eye because I wanted to make some sort of illuminati related loop, but then decided to go in a simpler direction. I like the result, although I wish there was more time to make the animation actually loop instead of clearly starting over every time.

Here are some very rough initial designs. My first idea was a jump roping ball. Second was a blinking eye looking around. I initially programmed this one using ellipses but was not satisfied so I switched to arcs and got the final result you see.

 
// Processing Template for Zoetrope toy by Eye Think
// https://www.amazon.com/Zoetrope-Animation-Toy-Victorian-Illusion/dp/B007VM9HZO/
// Developed for Processing 3.3.6 * http://processing.org
// 24 January 2018 * Golan Levin 
 
// See information about Processing PDF export at: 
// https://processing.org/reference/libraries/pdf/index.html
// PDF generated by Processing can be opened in Adobe Illustrator.
import processing.pdf.*;
boolean bRecordingPDF = false;
 
float inch = 72; 
float paperStripWidth = inch * 12.625;
float paperStripHeight = inch * 1.3125;
float overlapMargin = inch * 0.4375;
float artAreaWidth = paperStripWidth - overlapMargin;
float artAreaHeight = paperStripHeight;
 
final int nFrames = 11; 
int myFrameCount = 0;
int exportFrameCount = 0; 
boolean bAnimate = true; 
boolean bExportFrameImages = false;
 
//-------------------------------------------------------
void setup() {
  size(1224, 792); // 17x11" at 72DPI
  frameRate(15);
  smooth();
} 
 
//-------------------------------------------------------
void draw() {
  background(240); 
  if (bRecordingPDF) {
    beginRecord(PDF, "zoetrope-output.pdf");
  }
 
  // Do all the drawing. 
  pushMatrix(); 
  translate(width/2, height/2);
  translate(0-paperStripWidth/2, 0-paperStripHeight/2); 
 
  drawCutLines(); 
  drawGuides(); 
  drawAllFrames();
  popMatrix();
 
  if (bExportFrameImages) {
    // If activated, export .PNG frames 
    if (exportFrameCount < nFrames) {
      String filename = "frame_" + nf((exportFrameCount%nFrames), 3) + ".png";
      saveFrame("frames/" + filename);
      println("Saved: " + filename); 
      exportFrameCount++;
      if (exportFrameCount >= nFrames) {
        bExportFrameImages = false;
        exportFrameCount = 0;
      }
    }
  }
 
  if (bRecordingPDF) {
    endRecord();
    bRecordingPDF = false;
  }
}
 
 
//-------------------------------------------------------
void keyPressed() {
  switch (key) {
  case ' ': 
    // Press spacebar to pause/unpause the animation. 
    bAnimate = !bAnimate;
    break;
 
  case 'p': 
  case 'P':
    // Press 'p' to export a PDF for the Zoetrope. 17x11" paper!
    bRecordingPDF = true; 
    break;
 
  case 'f': 
  case 'F': 
    // Press 'f' to export .png Frames (to make an animated .GIF)
    myFrameCount = 0; 
    exportFrameCount = 0; 
    bExportFrameImages = true;
    bAnimate = true; 
    break;
  }
}
 
//-------------------------------------------------------
void drawCutLines() {
  fill(0); 
  textAlign(CENTER, BOTTOM); 
  text("Zoetrope Template", paperStripWidth/2, -20); 
 
  stroke(0); 
  strokeWeight(1.0);
  noFill(); 
  if (!bRecordingPDF) {
    fill(255);
  }
  rect(0, 0, paperStripWidth, paperStripHeight);
}
 
//-------------------------------------------------------
void drawGuides() {
  // This function draws the guidelines. 
  // Don't draw these when we're exporting the PDF. 
  if (!bRecordingPDF) {
    float frameSpacing = artAreaWidth / nFrames;
 
    stroke(128); 
    strokeWeight(0.2);
    for (int i=0; i<nFrames; i++) {
      pushMatrix();
      translate(i * frameSpacing, 0);
      rect(0, 0, frameSpacing, artAreaHeight); 
      popMatrix();
    }
  }
}
 
//-------------------------------------------------------
void drawAllFrames() {
  for (int i=0; i<nFrames; i++) {
 
    float frameSpacing = artAreaWidth / nFrames;
 
    pushMatrix();
    translate((i + 0.5) * frameSpacing, 0);
 
    int whichFrame = i; 
    if (bAnimate) {
      whichFrame = (i+myFrameCount)%nFrames;
    }
     drawArtFrame (whichFrame); 
 
 
    popMatrix();
  }
  myFrameCount++;
}
 
 
 
//-------------------------------------------------------
//thank you to golan for the template and examples
void drawArtFrame(int whichFrame) { 
 
  noFill();
  strokeWeight(2);
  stroke(0,0,0);
  float eyeY = map(whichFrame, 0, nFrames-1, 0, artAreaHeight*0.30);
  float eyeLid = map(whichFrame, 0, nFrames-1, artAreaHeight*0.30, 0);
  float irisY = map(whichFrame, 0, nFrames-1, 0, artAreaHeight*0.15);
  float eyebrow = map(whichFrame, 0, nFrames-1, 0, artAreaHeight*0.1);
  float tearY = map(whichFrame, 0, nFrames-1, artAreaHeight*0.7, artAreaHeight*1.1);
  float tearY2 = map(whichFrame, 0, nFrames-1, artAreaHeight*0.9, artAreaHeight*1.2);
 
  //right eye
  fill(255,255,255);
  stroke(0,0,0);
  arc(20, artAreaHeight/2, 30, eyeY, 0, PI);
  stroke(50,100,200);
  strokeWeight(2);
  fill(0,0,0);
  arc(20, artAreaHeight/2+1, 15, irisY, 0, PI);
  stroke(0,0,0);
  strokeWeight(3);
  fill(255,255,255);
  arc(20, artAreaHeight/2-1, 30, eyeLid, 0, PI);
 
 
  //left eye
  fill(255,255,255);
  stroke(0,0,0);
  arc(-20, artAreaHeight/2, 30, eyeY, 0, PI);
  stroke(50,100,200);
  strokeWeight(2);
  fill(0,0,0);
  arc(-20, artAreaHeight/2+1, 15, irisY, 0, PI);
  stroke(0,0,0);
  strokeWeight(3);
  fill(255,255,255);
  arc(-20, artAreaHeight/2-1, 30, eyeLid, 0, PI);
 
  //eyebrows
  strokeWeight(2);
  line(7, -eyebrow+40, 35, 40);
  line(-35, 40, -7, -eyebrow+40);
 
  //sad water
  fill(10,50,200,whichFrame*0.9+200);
  noStroke();
  ellipse(-25, tearY, 2, 10);
  ellipse(-25, tearY2, 2, 10);
}

nixel-LookingOutwards02

I've chosen to talk about a fellow CMU student's project for this Looking Outwards report. The project, Hermit, was made by Lingdong Huang for his 15-112 term project in 2015 and is fairly well known throughout the school. It is a procedurally generated interactive environment.

I like this work because I think it's elegant and sophisticated, especially considering the constraints under which it was made (python, 112 term project deadlines).  It is aesthetically pleasing, and it has a narrative. The elements of the project all work together to create something that is able to give the viewer a peaceful feeling.

I did open up the code for the project, but I don't think I'm well versed enough in generative art to know what each part of the program is doing. I do know that it is recursive at its root, but I don't know how he used that to get the generative result achieved.

In terms of effective complexity, I would say it leans more on the side of order rather than chaos. The project is predictable and clean but still interesting in the many possibilities it offers in terms of interaction and uniquely generated landscapes and creatures.

Check it out here:

nixel-Reading02

 

Question 1A. 

In my experience, learning to dance, like most art, has two main components: technical understanding and intuitive understanding. The technical side is orderly and logical, and you can apply any number of systems in order to understand it. However, the intuitive side is chaotic and often illogical, and results in many different interpretations by different people. You can't go extreme on either side because that risks oversimplification and a lack of true understanding of the art, so in employing a mix of the two, you achieve successful execution and therefore effective complexity.

 

Question 1B.

For my personal work, relating to the problem of intent, I don't see why I would use generative methods to create art over other more meaningful and comfortable methods for me. When I look at generative art, I'm not always able to identify the intent behind using that method, and I don't exactly know why people would choose to make art that way, but I think this is just a side effect of me needing to study and understand [technological] art in general.