nannon-Body

Face Face Revolution 

Vimeo

(sadly the "levels" label disappears!!)

 
 
 

-----
GIF

 
 
 

----
Still

 
 
 
 

Though I was super impressed/awed by all the examples shown in class of digital interactive artworks, I personally had a hard time coming up with an idea for this project. My DDR concept still seems a bit boring to me, but I'm glad I got it to work in a reasonable amount of time (relative to how stressed I was about previous assignmentS). The game itself is mildly fun, if a little hard. In coming up with this concept, I wanted to make sure I wasn't scaling out of proportion, so I looked at the templates carefully first before trying to figure out what to do, which really helped me scope down my project. Moving forwards, if this project were to be improved, I think it'd be really fun to try to get people to contort their faces to match what comes up in the grid--though I can imagine that being 1) really hard to play and 2) needing to randomize the grid in a really careful way i.e. the mouth is never above the eyes.

 
 
 
 

//
// a template for receiving face tracking osc messages from
// Kyle McDonald's FaceOSC https://github.com/kylemcdonald/ofxFaceTracker
//
// 2012 Dan Wilcox danomatika.com
// for the IACD Spring 2012 class at the CMU School of Art
//
// adapted from from Greg Borenstein's 2011 example
// http://www.gregborenstein.com/
// https://gist.github.com/1603230
//
import oscP5.*;
OscP5 oscP5;
 
 
PFont intersect50;
PFont intersect25;
 
 
//game bools
boolean pressplay =false;
boolean gameOver = false;
 
int level;
 
// num faces found
int found;
 
// pose
float poseScale;
PVector posePosition = new PVector();
PVector poseOrientation = new PVector();
 
 
 
 
 
// gesture
float mouthHeight;
float mouthWidth;
float eyeLeft;
float eyeRight;
float eyebrowLeft;
float eyebrowRight;
float jaw;
float nostrils;
 
 
//mouth, left eye, right eye, nose
String[] parts = {"mouth", "left eye", "right eye","nose"};
int partsActive; 
 
// grid variables
int[][] grid = new int[10][10];
 
int gridNum = 2;
 
int gridSize = 700;
int margin = 100;
 
int sqSize;
int randX;
int randY;
int points;
//timer
 
int time;
int wait = 8000;
float countdown;
 
 
void setup() {
  // Uncomment the following two lines to see the available fonts 
  //String[] fontList = PFont.list();
  //printArray(fontList);
  //String[] fontList = PFont.list();
  //for (int i =300;i<700; i++) { // println(fontList[i]); //} intersect50 = createFont("IntersectB44Solid", 120); intersect25 = createFont("IntersectB24", 30); translate(0,0); size(700,700); frameRate(30); oscP5 = new OscP5(this, 8338); oscP5.plug(this, "found", "/found"); oscP5.plug(this, "poseScale", "/pose/scale"); oscP5.plug(this, "posePosition", "/pose/position"); oscP5.plug(this, "poseOrientation", "/pose/orientation"); oscP5.plug(this, "mouthWidthReceived", "/gesture/mouth/width"); oscP5.plug(this, "mouthHeightReceived", "/gesture/mouth/height"); oscP5.plug(this, "eyeLeftReceived", "/gesture/eye/left"); oscP5.plug(this, "eyeRightReceived", "/gesture/eye/right"); oscP5.plug(this, "eyebrowLeftReceived", "/gesture/eyebrow/left"); oscP5.plug(this, "eyebrowRightReceived", "/gesture/eyebrow/right"); oscP5.plug(this, "jawReceived", "/gesture/jaw"); oscP5.plug(this, "nostrilsReceived", "/gesture/nostrils"); points = 0; getNewRand(); //timer time = millis();//store the current time println("time", time); //game level =1; partsActive = int(random(4)); } void draw() { if (!pressplay && !gameOver) { gameStart(); } else if (pressplay && !gameOver){ game(); } else if (pressplay && gameOver) { gameend(); } } void gameStart(){ background(1, 34, 160); textAlign(CENTER, CENTER); textFont(intersect50); fill(133,242,231); text("face", width/2-3,height/2-100); text("face", width/2-3, height/2); fill(0,222,190); text("face", width/2, height/2-100+3); text("face", width/2, height/2+3); textFont(intersect25); int passedMillis = millis() - time; // calculates passed milliseconds if(passedMillis >= 300){
      time = millis();
      fill(1, 34, 160);  // if more than 215 milliseconds passed set fill color to red
  }
  else {
    fill (0,222,190);
  }
   text("free play", width/2, 490);
   if (keyPressed) {
     if (key=='p' || key=='P') {
       pressplay = true;
     }
   }
}
 
void gameend() {
  background(1, 34, 160);
   textAlign(CENTER, CENTER);
   textFont(intersect50);
   fill(133,242,231);
   text("game", width/2-3,height/2-100);
   text("over", width/2-3, height/2);
   fill(0,222,190);
   text("game", width/2, height/2-100+3);
   text("over", width/2, height/2+3);
   textFont(intersect25);
   int passedMillis = millis() - time; // calculates passed milliseconds
  if(passedMillis >= 300){
      time = millis();
      fill(1, 34, 160);  // if more than 215 milliseconds passed set fill color to red
  }
  else {
    fill (0,222,190);
  }
   text("good bye", width/2, 490);
   if (keyPressed) {
     if (key=='s' || key=='S') {
       gameOver =false;
       pressplay = false;
       //level =0;
       //points =0;
       setup();
     }
   }
 
}
 
void game() {
 
if (points<40) {
   level =1;
 }
 
 else if (points<70) {
   level =2;
 }
 
 else if (points<100) {
   level =3;
 }
 
   else if (points<130) {
   level =4;
 }
 
 else {
 level =5;
 }
 
  pushMatrix();
  background(0);
   translate(sqSize/2,sqSize/2);
 
 
  fill(0);
 
  gridNum=level+1;
  sqSize = (gridSize-margin*2)/gridNum;
  //500/3
  //
  println(sqSize);
 
  for (int i=0; i<gridNum; i++) {
        for (int j=0; j<gridNum; j++) { //size/ grid size stroke(133,242,231); //noFill();222 //println(i, j, sqSize, sqSize*j+margin); rect(sqSize*j+margin, sqSize*i+margin, sqSize, sqSize); } } textFont(intersect25); fill (0,222,190); textAlign(LEFT); text("level "+str(level), -50,-50); fill(133,242,231); rect(sqSize*randX+margin, sqSize*randY+margin, sqSize, sqSize); fill(0); rect(sqSize*randX+margin, sqSize*randY+margin, sqSize-20, sqSize-20); fill(133,242,231); rect(sqSize*randX+margin, sqSize*randY+margin, sqSize-40, sqSize-40); //rect(300,300,40,40); popMatrix(); pushMatrix(); textFont(intersect25,40); textAlign(CENTER,CENTER); fill(0); text(parts[partsActive], sqSize*randX+margin+sqSize/2, sqSize*randY+margin+sqSize/2); popMatrix(); //write points count fill(133,242,231); textSize(60); //println(points); text(str(points), 350, 630); //timer if(millis() - time >= wait){
      gameOver = true;
      //also update the stored time
 
    }
    else {
      countdown = (millis()-time);
 
      //println("wait", wait);
      //println("test", millis()-time);
 
      countdown = countdown/wait;
      //println("countdown", countdown);
    }
    //println((3*PI)/2, ((3*PI)/2)*countdown);
    pushMatrix();
    noFill();
    stroke(133,242,231);
    strokeWeight(7);
    arc(600, 70, 30,30, 3*(PI/2)*countdown, 3*(PI/2), OPEN);
    popMatrix();
 
    strokeWeight(1);
 
  //translate(width,0);
  //  scale(-1,1);
  //facial data
  if(found > 0) {
 
    pushMatrix();
 
    translate(posePosition.x, posePosition.y);
    scale(poseScale);
    noFill();
    ellipse(-20, eyeLeft * -9, 7, 7);
    ellipse(20, eyeRight * -9, 7, 7);
    ellipse(0, 20, 7, 7);
    ellipse(0, nostrils * -1, 7, 7);
    rectMode(CENTER);
    fill(0);
    rect(-20, eyebrowLeft * -5, 25, 5);
    rect(20, eyebrowRight * -5, 25, 5);
    popMatrix();
 
 
    //gamify your LEFT eye
    float realMouthX = (posePosition.x);
    float realMouthY = posePosition.y+((eyeLeft*7)*poseScale);
 
 
    //gamify your LEFT eye
    float realLeftEyeX = (posePosition.x-(20*poseScale));
    float realLeftEyeY = posePosition.y+((eyeLeft*-9)*poseScale);
 
     //gamify your RIGHT eye
    float realRightEyeX = (posePosition.x+(20*poseScale));
    float realRightEyeY = posePosition.y+((eyeLeft*-9)*poseScale);
 
     //gamify your NOOOSE
    float realNoseX = (posePosition.x);
    float realNoseY = posePosition.y+((eyeLeft*-1)*poseScale);
 
 
    //translate(125,125);
    stroke(255,0,0);
 
 
    //MOUTH POINTS
     if (partsActive==0) {
      ellipse(realMouthX, realMouthY, 20,20);
        if (realMouthX >= sqSize*randX+margin && realMouthX <= sqSize*randX+sqSize+margin && realMouthY>= sqSize*randY+margin && realMouthY<= sqSize*randY+sqSize+margin) { //println("hello"); points+=10; getNewRand(); } } //LEFT EYE POINTS if (partsActive==1) { ellipse(realLeftEyeX, realLeftEyeY, 20,20); if (realLeftEyeX >= sqSize*randX+margin && realLeftEyeX <= sqSize*randX+sqSize+margin && realLeftEyeY>= sqSize*randY+margin && realLeftEyeY<= sqSize*randY+sqSize+margin) { //println("hello"); points+=10; getNewRand(); } } //RIGHT EYE POINTS if (partsActive==2) { ellipse(realRightEyeX, realRightEyeY, 20,20); if (realRightEyeX >= sqSize*randX+margin && realRightEyeX <= sqSize*randX+sqSize+margin && realRightEyeY>= sqSize*randY+margin && realRightEyeY<= sqSize*randY+sqSize+margin) { //println("hello"); points+=10; getNewRand(); } } if (partsActive==3) { ellipse(realNoseX, realNoseY, 20,20); if (realNoseX >= sqSize*randX+margin && realNoseX <= sqSize*randX+sqSize+margin && realNoseY>= sqSize*randY+margin && realNoseY<= sqSize*randY+sqSize+margin) {
        //println("hello");
        points+=10;
        getNewRand();
      }  
    }
 
  }
}
 
 
 
void getNewRand() {
  randX = int(random(0,gridNum));
  randY = int(random(0,gridNum));
  partsActive = int(random(4));
  time = millis();
}
 
void mouseClicked() {
  randX = int(random(0,gridNum));
  randY = int(random(0,gridNum));
  partsActive = int(random(4));
  time = millis();
}
 
// OSC CALLBACK FUNCTIONS
 
public void found(int i) {
  //println("found: " + i);
  found = i;
}
 
public void poseScale(float s) {
  //println("scale: " + s);
  poseScale = s;
}
 
public void posePosition(float x, float y) {
  //println("pose position\tX: " + x + " Y: " + y );
  posePosition.set(x, y, 0);
}
 
public void poseOrientation(float x, float y, float z) {
  //println("pose orientation\tX: " + x + " Y: " + y + " Z: " + z);
  poseOrientation.set(x, y, z);
}
 
public void mouthWidthReceived(float w) {
  //println("mouth Width: " + w);
  mouthWidth = w;
}
 
public void mouthHeightReceived(float h) {
  //println("mouth height: " + h);
  mouthHeight = h;
}
 
public void eyeLeftReceived(float f) {
  //println("eye left: " + f);
  eyeLeft = f;
}
 
public void eyeRightReceived(float f) {
  //println("eye right: " + f);
  eyeRight = f;
}
 
public void eyebrowLeftReceived(float f) {
  //println("eyebrow left: " + f);
  eyebrowLeft = f;
}
 
public void eyebrowRightReceived(float f) {
  //println("eyebrow right: " + f);
  eyebrowRight = f;
}
 
public void jawReceived(float f) {
  //println("jaw: " + f);
  jaw = f;
}
 
public void nostrilsReceived(float f) {
  //println("nostrils: " + f);
  nostrils = f;
}
 
// all other OSC messages end up here
void oscEvent(OscMessage m) {
  if(m.isPlugged() == false) {
    println("UNPLUGGED: " + m);
  }
}

 

nannon-viewing04

Spectacle is most easily recognized in works that milk the most out of current technology--it's usually flashy, engaging, easy to understand, for capital gain.

Speculation pushes the edge of understanding + technology--it is not self conscious, can also be flashy, but also confusing, uncomfortable, in the midst of coming to terms with itself.

Trimalchio, AES+F, 2010

Image result for aes+f trimalchio

AES+F is an art collective that plays a lot of faux realistic 3D through 3D modeling and photo manipulation. This particular piece, Trimalchio, was made in 2010. It's hard to categorize this as either speculation or spectacle because I think it's so much both (maybe it does reclaim spectacle into speculation). At first glance, the aesthetic is very beautiful, with many references to renaissance/greek god type imagery. But as you watch the videos, the references to all kinds of humanity + culture come out of nowhere, seamlessly blending into this utopic world. I think AES+F uses 3D in an interesting way because it's not the tip top frontier of 3D imaging, yet the blend of photo+manipulation makes it look extremely real. It's the photography that brings it out of uncanny valley, and the very intentional play with scale, imagery, and context that bring it into the weird, which I think is awesome.

nannon-reading03

At first thought, I want to say that my interests lie with last word art. There's something extremely daunting about making something that radically transforming from a medium or concept that most people already take for granted. At the same time, people around me are often very first-word oriented; looking at my recent work for this class, I believe that I've been drawn into the first-word realm of things.

Technology has shaped culture at almost every step of the way--of course, the obvious examples are things such as agriculture, industrial revolution, the internet, etc. But something I think that is very interesting happening in our culture today is the way the internet has shaped very different cultures in the West and in China. Technology today being tied up largely in software has also widened an intellectual + educational gap, exacerbating existing income/wage/socioeconomic gaps. On the flip side, I think small sub cultures can drive technologies as well. For example, niche music and art tech is drive by those who need it and make the case and perhaps build it.

The phrase technologically novel immediately brings to mind countless examples that exist in today's world. AR/VR, blockchain, etc are examples of technologies that people are working immensely hard to try to find uses for, but 99% of what's made/exists will not be remembered beyond the year its made. However, I do think that this kind of research will influence the 1% of products that are the last word, and that the last word wouldn't have existed without the first word. In addition, obsoletism has never been more pervasive than today, and software changes so fast that the foundational value of products can't be based purely on its technology. I think last word stuff is not only technologically novel, but also conceptually, philosophically, and aesthetically challenging.

nannon-telematic

A kitchen chat room where you show up as a chair. Inspired by my own kitchen, where my roommates and friends have had many long nights of fun chats, deep talks, and laughs. Also doubles as a place where chairs can comfortably hang out with other chairs.

 

 

The regular chair is taken directly from my kitchen, but in this digital kitchen, you can be any chair you want. 

Kitchen Chat v1 (New):  Use arrow keys to move around!
Kitchen Chat V0 (Broken) :

(Different possibilities of chairs)

 

 

Sept 28:I wanted this chat room to be a literal room where users could move around and chat with each other. However, one of the biggest obstacles was getting the images to load correctly. In addition, I had a lot of trouble keeping track of who was in the room--as such, when a new user joins a room, they won't see people who arrived previously, but users can see new people joining the room live. To be continued.

Oct 2 Update: 
The chat works! Used the agar.io template as a base, instead of the drawing template. Helped a lot, since I realized the agar.io template solved all my previous problems with users showing up. The hardest part was learning how it worked, and understanding the socket code. Will be adding new chairs (currently only 3), and a prettier log in page, including explanations for each chair) soon.

 

nannon-LookingOutwards02

I had completely forgotten I had come across Mokafolio years before until Golan presented his work again a couple weeks ago. I had loved the artful, analog quality of his work then, and I still do love it. When I first encountered his work, I had no idea that there was so much technology behind the pieces. I especially love the vending machine pieces because not only are they generative, they are so in a very engaging way. Vending machines are great because the user never knows exactly what they're getting, yet they choose to receive something anyway.

In a lot of the generative art examples, there's a certain "generative art" aesthetic that is extremely telling of how the results are made. I love Mokafolio's work because it's decidedly not that--not that any aesthetic is better or worse than another, I just think in terms of uniqueness, this work stands out (going back to Galanter's Problem of Uniqueness).

nannon-03-clock

 

This is a 24 hour clock that grows back into itself. I actually had a hard time coming up with a solid concept for this project, and it definitely impacted the work. I originally wanted to do a "clock" based on the days of the user's life, with multiple spheres representing each day--spheres would alter in size and color, with different layers representing amount of fulfillment in relationships, work, etc. I had the sphere code from the beginning, but it became hard to scrape data and/or create user input in processing, at which point I decided to scope down. I'm not totally satisfied with =the simplification of the representation of multiple days to just a single day with a sphere, since it falls to close to just a normal clock. However, I like the emphasis on the regrowth visual/symbolism in the piece. Definitely need to focus on scoping down and making sure I have the capabilities for my vision in the next project thank you for the real talk @golan!!

 

 

 

--Process --

playing around with adding spheres (layers) on key pressed (earlier idea).

import peasy.*;
 
PeasyCam cam;
 
int time = 6;
int time2;
 void keyPressed() {
   if (keyCode == UP) {
     time2 = time++%24;
     println(time2);
   }
   if (keyCode == DOWN) {
     time2 = time--%24;
   }
 }
 
 
PVector[][] globe;
int total = 72;
float[][] firsts = new float[total+1][3];
float[][] lasts =  new float[total+1][3];
 
 
 
void setup() {
  size(640, 640, P3D);
  cam = new PeasyCam(this, 500);
  globe = new PVector[total+1][total+1];
 
 
}
 
void draw() {
 
 
 
  //println(hour());
  background(255);
  pushMatrix();
  textSize(20);
 
  fill(100);
 
  text(str(time2)+":00", -30,300);
  popMatrix();
  noFill();
  stroke(240);
  lights();
  float smallRad = map(time2*3, 0, 72,0,200);
  sphere(smallRad);
 
  float r = 200;
  for (int i = 0; i < total+1; i++) {
    float lat = map(i, 0, total, 0, PI);
    for (int j = 0; j < total+1; j++) {
      float lon = map(j, 0, total, 0, TWO_PI);
      float x = r * sin(lat) * cos(lon);
      float y = r * sin(lat) * sin(lon);
      float z = r * cos(lat);
      globe[i][j] = new PVector(x, y, z);
    }
  }
 
  for (int i = 0; i < total; i++) {
    beginShape(TRIANGLE_STRIP);
    int curHour= 72-(time2*72)/24;
    //println(curHour);
    for (int j = 0; j < curHour; j++) {
 
      PVector v1 = globe[i][j];
      vertex(v1.x, v1.y, v1.z);
      PVector v2 = globe[i+1][j];
      vertex(v2.x, v2.y, v2.z);
      if (j==0) {
        firsts[i][0] = v1.x;
        firsts[i][1] = v1.y;
        firsts[i][2] = v1.z;
      }
      if (j==curHour-1) {
        lasts[i][0] = v2.x;
        lasts[i][1] = v2.y;
        lasts[i][2] = v2.z;
      }
 
    }
    endShape();
  }
 
  fill(100);
  beginShape();
  vertex(0,0,0);
  for (int i=0; i < total; i++) {
    vertex(firsts[i][0], firsts[i][1], firsts[i][2]);
  }
   vertex(0,0,cos(72)*200);
  endShape();
 
  fill(100);
  beginShape();
  vertex(0,0,0);
 vertex(firsts[0][0], firsts[0][1], firsts[0][2]);
  for (int i=0; i < total; i++) {
    vertex(lasts[i][0], lasts[i][1], lasts[i][2]);
  }
  //vertex(firsts[0][0], firsts[0][1], firsts[0][2]);
  vertex(0,0,cos(2*PI)*r);
  endShape();
 
 
}

nannon-Reading-02

1A: Effective Complexity--Kyuha Shim's Generative Typography

In the past two years (mostly), I've become very interested in typography, how it moves and how it scales. However, it wasn't until last year that I really encountered Kyu's work as his student in his Computational Design class. Kyu's work in generative typography has greatly effected and also falls in line with broad movements towards parametric design in the visual design world. I love this work because it gives the very language and content of our world character and movement, engages the viewer in completely new ways. In terms of Galanter's article, I would say that this kind of generative typography, that is, typography that changes based on external input(s), still definitely leans towards order (crystal lattice). No matter what, typography is still driven by language/linguistics, and whatever alphabet its shape is taking. That line is extremely concrete. However, I love that it finally is offering a source of variation within the previously static world of type.

Peep it here: http://generativetypography.com/

1B: The problem of uniqueness

"Whether in the context of market value or cultural value, traditional works of art have been treasured as unique and thus rare objects. "

"Digital generative art introduces a completely new problem: rather than offering an endless supply of copies, it provides an endless supply of original and unique artifacts. "

Generative art is by nature repetitive in some way, and I don't believe the same problem of uniqueness that might arise in non-generative art can apply, at least without differentiation. When it comes to generative art, I believe that the more important point/source of uniqueness is the generator (code, etc), not the generated content.

nannon-AnimatedLoop

I originally wanted to do something totally different (a set of eyes that opened into new eyes), but I eventually thought that it was too complicated and illustrative and decided to invest my time in doing something 3D instead. I saw this cool gif with rotating text in a cylinder in the spirit of Zach Lieberman the other day, and wanted to do something similar. Unfortunately, I decided all of the Wednesday night, and only had Thursday to do it. Having never worked in 3D before, this was really torturous, but still kind of rewarding. I'm disappointed I didn't get the final (as of now) to how I imagined it in my head, but I'm going to keep working on this. Ultimately, I want the text to actually be a coherent sentence, and have different text on the inside of the cylinder and out. A lot of time was spent figuring out Geomerative and cyinder geometry, but I did really learn a lot. I didn't have time to use p5_func, but hopefully will get around to it as I continue to flesh this guy out.

Thank you Golan  for taking the time to explain a ton mathematics.

// 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
import geomerative.*;
 
RFont f;
RShape fire;
RPoint[] points;
RShape[] letterShapes;
//===================================================
// Global variables. 
String  myNickname = "nannon"; 
int     nFramesInLoop = 120;
int     nElapsedFrames;
boolean bRecording; 
 
//===================================================
void setup() {
  size (640, 640, P3D); 
  lights();
  background(0);
  bRecording = false;
  nElapsedFrames = 0;
 
  RG.init(this);
  fire = RG.getText("x", "Optimo.ttf", 72, CENTER);
 
  RG.setPolygonizer(RG.UNIFORMLENGTH);
  RG.setPolygonizerLength(1);
  fill(255);
 
  letterShapes = fire.children;
 
 
  smooth();
}
//===================================================
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) {
  //
  background(0);
  translate(320, 320, 200);
  rotateX(PI);
  rotateY(map(percent,0,1,0,PI/2));
  rotateZ(sin(PI));
  stroke(255);
  noFill(); 
 
 
  int r= 100;
  int nSlices = 50;
  int zA = -20;
  int zB = 20;
 
 
 
 
 
  rotateY(PI/2);
  rotateX(PI/2);
  noFill();
 
  // draw a cylinder
  noFill(); 
  stroke(255); 
  beginShape(TRIANGLE_STRIP);
  for (int i=0; i<=nSlices; i++) {
    float theta = map(i, 0, nSlices, 0, 2*PI);
    float pX = r*cos(theta);
    float pY = r*sin(theta);
    vertex(pX, pY, zA);
    vertex(pX, pY, zB);
  }
  endShape();
 
  // print("x1:"+points[0].x+" "+"y:"+ points[0].y+"    ");
  // print("x2:"+points[points.length-1].x+" "+"y:"+ points[points.length-1].y+"    ");
 
 
 
   //beginShape();
   //for (int i=0; i<points.length; i++) {
   //  float newX = map(points[i].x, -187, 189, 0, 0.6*(2*PI));
   //  float newZ = map(points[i].y, -24, 0, 0, 0.6*(2*PI));
   //  vertex(r*cos(newX), points[i].y, abs(r*cos(newZ)));
 
   //  endShape();
   //}
 
 
 
  noFill(); 
  stroke(255); 
  //int nLetters = 16; 
  //for (int i=0; i<nLetters; i++) {
 
 
 
 
    //int nPointsInThisContour = 16;
    for (int k=0; k<10; k++) {
      pushMatrix();
      float letterTheta = k* radians(45.0);
 
 
      float letterX = r * cos(letterTheta);
      float letterY = r * sin(letterTheta); 
 
 
      //float eased = function_DoubleExponentialSigmoid(percent, 0.7);
      //float newletterY = map(eased, 0,1,0,PI);
 
      translate(letterX, letterY);
      rotateX( radians(90)); 
      rotateY(letterTheta+ radians(90));
 
      fill(255);
      stroke(255);
      beginShape();
      RPoint[] points = letterShapes[0].getPoints();
      for (int j=0; j<points.length; j++) {
 
        //print(points[j].x);
        //float ht = map(j, 0, nPointsInThisContour, 0, TWO_PI); 
        float hpx = points[j].x; 
        float hpy =  points[j].y; 
        float hpz =0;
 
 
        vertex(hpx, hpy, hpz);
 
        //ellipse(hpx,hpy,10,10);
      }
      endShape();
      popMatrix();
    }
 
}
float function_DoubleExponentialSigmoid (float x, float a) {
  // functionName = "Double-Exponential Sigmoid";
 
  float min_param_a = 0.0 + EPSILON;
  float max_param_a = 1.0 - EPSILON;
  a = constrain(a, min_param_a, max_param_a); 
  a = 1-a;
 
  float 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;
}

nannon-Scope

Kit Kat Scope

 

Originally, I wanted to do an animation using eyes for my Looping Gif assignment, but I ultimately decided not to. However, since I had a lot of sketches left over from that idea, I put them to use here instead. After drawing the eyes, and having them animate side to side, it actually reminded me a lot of the Kit Kat clocks, which I was belatedly inspired by. The starter code was super helpful, and this assignment was a fun break for the Looping Gif.

 
/*
// 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 >= nFrames){
      bExportFrameImages = false;
    }
  }
 
 
  if (bRecordingSinglePNG) {
    saveCanvas('myPraxinoscope.png', 'png');
    bRecordingSinglePNG = false;
  }
}
 
 
//-------------------------------------------------------
function mouseClicked() {
  console.log(mouseX, mouseY);
}
 
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(250); 
  strokeWeight(1.0);
 
 
  if (bRecordingSinglePNG) {
    fill(0); 
  }
  ellipse(0, 0, diamCutOuter, diamCutOuter);
 
 
  if (bRecordingSinglePNG) {
    fill(0); 
  }
  ellipse(0, 0, diamCutInner, diamCutInner);
 
  fill(255); 
  ellipse(diamCutOuter/2 - holeDx, 0-holeDy, holeD, holeD); 
 
  stroke(240)
  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<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<=(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<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<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!
 
  // Draw the frame number
  fill(0); 
  noStroke(); 
  textAlign(CENTER, CENTER); 
  text (whichFrame, 0, -45);
 
  // Draw eyes
  fill(255); 
  stroke(255);
  strokeWeight(1); 
 
  ellipse(-18, -48, 28,28); 
  ellipse(18, -48, 28,28); 
  ellipse(0,-33,15,10);
 
 
  //draw eye balls
  fill(0);
  noStroke();
  var xAxis = map(whichFrame, 0,nFrames, 0,PI)
  arc(sin(xAxis)*16-18-14+6, -48, 12,12,PI/6,(11*PI)/6, PIE);
 
  arc(sin(xAxis)*16-18-14+6+36 , -48, 12,12,PI/6,(11*PI)/6, PIE);
 
  //clock
  fill(255);
  stroke(255);
  rect(-25,-23, 50, 70, 10);
 
//clock tix
  stroke(0);
  strokeWeight(2 );
  line (0, -13, 0, -18);
 
  line (0, -13, 0, -18);
  line (0, 35, 0, 40);
  line (-18,12, -13,12);
 
   line (18,12, 13,12);
 
  //whiskers 
  stroke(255)
  line (-20,-30, -45,-35);
  line (-20,-25, -45,-20);
  line (20,-30, 45,-35);
  line (20,-25, 43,-20);
 
 
 
 
 
  // Draw some rotating spokes
    var cx = 0; 
    var cy = 12; 
    var u = 0 - map(whichFrame, 0, nFrames, 0, 1);
    var sx = cx + 15 * cos(u * TWO_PI); 
    var sy = cy + 15 * sin(u* TWO_PI); 
    stroke(0); 
 
    line (cx, cy, sx, sy);
 
 
  	var dx = 0; 
    var dy = 12; 
    var u2 = 0 - map(whichFrame, 0, nFrames/2, 0, 1);
    var vx = dx + 20 * cos(u2 * (TWO_PI+1.2)); 
    var vy = dy + 20 * sin(u2* (TWO_PI+1.2)); 
    stroke(0); 
    strokeWeight(1);
    line (dx, dy, vx, vy);
}

nannon-Reading-01

2. The Critical Engineer raises awareness that with each technological advance our techno-political literacy is challenged.

This document struck me immediately as extremely idealistic, though also extremely desirable and hopeful. Though the tone acknowledges the power of computing, it also implies that the original authors know how far technology can take us.

What stood out to me is that about half the tenets could explicitly applied to many other fields, but particularly design. These tenets, including 2,3,6 and 8 especially, are very close to the philosophy over in the School of Design. It's an emphasis on how our built (designed) world is converging more and more with the engineered (digital) world. A huge majority of college graduates in this decade will work in some kind of technological field, and this manifesto applies to anyone who will influence a new product or object.

I believe that engineers who are on the front line literally writing the code that powers almost all our products today should hold these tents close at hand, but others who will be involved with building products should be self-aware of their actions + consequences as well.

The second tenet rings so true in 2018, especially in light of GDPR and the Facebook testimonies. The tech-literacy gap is going to be a shattering crisis soon (if not already), and it's very clear in how government is interacting with private tech companies.