yuvian-Body

flappy face

note: this is not working 100% smoothly yet (collision detection is buggy sometimes)

For this project, I worked with clmtrackr.js in order to take input from the user's face to control a game. More specifically, I took note of where the user's face was positioned within the frame and the width of their smile. The more the user smiles, the higher the red "bird" flies. Moving his/her face from side to side also changes the bird's x-position on the canvas. I developed this project by getting clmtrackr to work first, then pulling data from the array of points it had given me, and then styling and implementing the game aspect. I didn't want to work from a motion capture because I wanted it to be more interactive, which is why I chose to get the user's face from his/her webcam. But with this also comes the potential for buggy face tracking as I have found while testing the project. I chose a flappy bird-esque game to implement because I wanted the game to be simple, easily understood, and somewhat recognizable. I had made another duplicate side-project in which the "bird" goes around eating berries but it seemed less like a game and more like a task.

how to play:
- smile widely to move bird up
- move head side to side to move bird left and right
- avoid white blocks

smile

open mouth

var ctracker;
var video;
var positions;
var bird;
var blockSpeed = 5
var blocks = [];
var score = 0;
var startGame = false;

function setup() {

  // setup webcam video capture
  video = createCapture(VIDEO);
  video.size(600, 450);
  video.position(0, 0);

  //hide video feed
  video.hide();

  // setup canvas
  createCanvas(600, 450);

  // setup tracker
  ctracker = new clm.tracker();
  ctracker.init(pModel);
  ctracker.start(video.elt);

  noStroke();

  // add block to blocks array
  for (var i = 0; i < 1; i++) {
    blocks[i] = new Block(random(40, 100), random(50, 100))
  }

}

function draw() {
  
  background(0);
  
  push();
  translate(video.width, 0);
  scale(-1, 1);

  image(video, 0, 0, width, height)

  positions = ctracker.getCurrentPosition();
  for (var i = 0; i < positions.length; i++) {
    fill(255, 80);
    // for when clmtracker is being weird in p5js editor
    // ellipse(positions[i][0] - 20, positions[i][1] - 10, 4, 4);
    // for online p5js editor
    ellipse(positions[i][0], positions[i][1], 2.5, 2.5);
  }
  pop();
  
  if (!startGame) {
    textAlign(CENTER)
    fill(255);
    text("press the space bar to start", width/2, height/2);
  }

  // if face is found, commence the game
  if (positions.length > 0 && startGame) {
    playGame()
  }
}

function keyPressed() {
  if (key == " ") {
    startGame = true
  } 
  else if (key == "R") {
    print('restart')
    setup();
  }
}


function playGame() {
    // blocks
    for (var i = 0; i < blocks.length; i++) {
      blocks[i].move();
      blocks[i].display();

      // remove block when it goes off screen and add a new block
      if (blocks[i].x < 25) {
        score += 1;
        blocks = []
        blocks.push(new Block(random(40, 100), random(50, 300)))
        // gradually increase speed of the moving blocks
        if (blockSpeed < 13) {
          blockSpeed = blockSpeed * 1.05
        } else {
          blockSpeed = blockSpeed * 1.005
        }
      }
  
      push();
        // display score
        fill(0);
        rectMode(CENTER);
        rect(80, 47, 70, 25)
        fill(255);
        textAlign(CENTER);
        text('score: ' + score, 80, 50);
      pop();
    }

    // background of smile bar
    fill(255);
    rect(20, 20, 15, height - 40);

    // smile bar
    var mouthLeft = createVector(positions[44][0], positions[44][1]);
    var mouthRight = createVector(positions[50][0], positions[50][1]);
    var smileDistance = Math.round(mouthLeft.dist(mouthRight));

    smile = map(smileDistance, 60, 75, 17, 0); // mapped smile distance to chopped up parts so bird doesn't jitter as much
    
    // prevent smile bar from going beyond bottom of bar
    rectSmile = smile * 20
    rectSmile = constrain(rectSmile, 20, height - 20)
    fill(50);
    rect(20, 20, 15, rectSmile);

    // smile number next to smile bar
    fill(255);
    smileText = height - 40 - Math.round(smile)
    // text(smileText, 50, constrain(smile, 30, height - 20))

    // bird
    push();
    translate(video.width, 0);
    scale(-1, 1);
    var noseX = positions[37][0]; // get nose x position to determine center of face
    noseX = noseX - 25 // wack p5js editor positioning
    birdY = smile * 20
    birdY = constrain(smile * 20, 50, height - 50); //prevent bird from moving offscreen
    bird = new Bird(noseX, birdY); // bird's x is nose position, y depends on width of smile
    bird.display();
    pop();
    
    // if bird collides with block, freeze everything and display game over message
    // for (var i = 0; i < blocks.length; i++) {
    block = blocks[0]
    if (bird.x >= block.x  && bird.x <= block.x + block.width) {
      bottomHeight = height - block.opening - block.height
      if (bird.y <= block.height || bird.y >= bottomHeight) {
        print('collision')
        // freeze webcam video, blocks, and bird
        video.stop()
        block.speed = 0
        // bird.y = height/2
        gameOver();
      }
    }
    
    // check top collision,
    // count = 0
    // d = getDistance(block.x, block.height, bird.x, bird.y)
    // if ( d < block.width/2) {
    //   count += 1
    //   print('hit' +  count)
    // }
  
    
    // alert user to fix positioning if bird is too high or too low
    if (smileText < 0) {
      fill(226, 74, 92);
      strokeWeight(3);
      text('move closer', 80, 100);
    }
    else if (smileText > 900) {
      fill(226, 74, 92);
      strokeWeight(3);
      text('move farther away', 80, 100);
    }
}

function gameOver() {
  fill(255);
  text("GAME OVER", width/2, height/2)
}

function Bird(x, y) {
  this.x = x;
  this.y = y;

  this.display = function() {
    fill(226, 74, 92);
    ellipse(this.x, this.y, 25, 25);
  }
}

function Block(w, h) {
  this.x = width - w / 2;
  this.width = w;
  this.height = h;
  this.speed = blockSpeed;
  this.opening = random(90, height / 2 - 50);

  this.display = function() {
    fill(255);
    // top block
    rect(this.x, 0, this.width, this.height)
      // bottom block
    rect(this.x, this.height + this.opening, this.width, height - this.opening - this.height)
  }

  this.move = function() {
    this.x = this.x - this.speed
  }
}

// from https://gist.github.com/timohausmann/5003280
function getDistance(x1,y1,x2,y2) {
  var 	xs = x2 - x1,
	ys = y2 - y1;		
	xs *= xs;
	ys *= ys;
	return Math.sqrt( xs + ys );
}

yuvian-viewing04

When Wharburton refers to a work as a "spectacle", he implies that the project may be technically astounding and visually interesting but is lacking in content and self-awareness.

Conversely, computer art that is "speculation" deals heavily with conceptual and theory-based ideas but may not have strong technical applications.

Studio Moniker's "Do Not Touch" (2013) is an example of a "spectacle". Visually, the project is interesting and compelling to look at while the video plays but substance-wise, there's not much to be said about the concept. Using the dichotomies from Wharburton's video, "Do Not Touch" leans more towards commerce than art as it is a music video intended to sell copies of the band's albums. Furthermore, it does nothing to increase awareness/visibility of pressing social issues. The only compelling aspect of the project is its "interactivity" with the band's fans. One could argue that the tracking of the users' mice allow us to visualize the obedient and disobedient tendencies of the users. But not much else can be said about the work as a whole.

yuvian-telematic

click here to play

note: webcam does not work in the embedded iframe below. please click the above link to play in glitch

Trace/sketch from your webcam. See webcam sketches from other people. Can you understand where they are, what they're doing, what they look like from their tracings?

So this project turned out a lot different than what I originally had in mind. First, I played around with clmtrackr.js because I wanted to make a multi-user sketching game where clmtrackr would generate a very simplified outline of a user's face from their webcam feed and other users would be able to add features such as facial hair, hairstyles, etc. That didn't work out too great because although I got clmtrackr.js to work in p5, I couldn't figure out how to draw on it. So then, I decided to retain the webcam input idea but without facial tracking. Eventually, it got to the point where it was very simplified - use the webcam feed to capture snapshots of the user's environment, ask them to trace/sketch over it, and show that sketch within a shared environment. I wanted the webcam snapshot to only be seen by its user because I wanted to retain some anonymity. The purpose of tracing/sketching over the webcam is to simulate a video call while forcing users to rely on their creativity and artistic ability to "show" themselves rather than reveal everything about them from live video. Because of this, this project is synchronous, because it requires users to be active and drawing at the same time. It's pretty anonymous because although you're trying to represent yourself through tracings of your image, it's unlikely that other users will be able to tell who you really are. In addition, you can manipulate your features at will.

yuvian-LookingOutwards02

Strata #3 - Excerpt from Quayola on Vimeo.

"Strata #3" is a film and installation project commissioned by Evento and Lumin for the 2009 Bordeaux Art & Architecture Biennale. Directed by Quayola, the project utilizes the aesthetics of classical architecture and Renaissance art combined with generative patterns and technological analysis of the original artwork in order to create a psychedelic and fragmented artistic experience.

One thing that inspired me is the creative use of "old" art and new technologies in one project. I love how the project feels familiar and yet completely new at the same time. The music in the video also pairs very well with the artistic direction of the film. The visuals are stunning and the concept itself is brilliant. I'm not sure how this would have looked in real-life as it was mentioned that this is an installation as well, but from the video, it is amazing to look at.

yuvian-Reading03

I found Naimark's short essay on "first word art" and "last word art" interesting and novel as I had never previously considered why it mattered when artworks are deemed experimental and new or just a continuation within well-known territory. Personally, I'm not quite sure where my interests lie along this spectrum. I think it's daring to create something entirely new and although it may be exciting, the fact that nothing else like it exists seems to pose a challenge within its creation. To me, it seems that the world has been inundated with "new" ideas and paradoxically, nothing seems truly "new" anymore. Although the author mentions that some believe that "last word art" must not really be art because it is nothing never-before-seen, I would have to disagree because I think artists can always find ways to evolve an existing idea, adapting to our ever-changing environments. Our society constantly demands artists and designers to create something novel yet this request is nothing new. Quick, bold ideas that change every quarter seem to be most desirable within technology whereas the art world generally likes to cling onto the work of the past. Thus the middle-ground between these two worlds must be an environment in which we are heavily influenced by past ideas while at the same time, being driven to create something entirely new.

yuvian-clock

new clock

For my first clock, I chose to represent time in a way similar to that of a normal clock. With a familiar elliptical shape, I used three rings to represent the hour, minute, and second. According to the time, I placed dots along the three rings which are evenly divided between the 360 degrees of a circle. Because it may get hard to read at times, I also added a feature that would allow the user to see the actual time when they move their mouse over the center of the clock. Afterwards, I added some styling to the clock - namely, the grey ring and circle to help differentiate between hours, minutes, and seconds.

//60212 CLOCK SKETCH

var h, m, s;

function setup() {
  createCanvas(500,500);
}

function draw() {
  background(0);
  
  h = hour();
  m = minute();
  s = second();
  
  ellipseMode(CENTER);
  
  //white circle bg for hours
  stroke(90);
  noFill();
  strokeWeight(15)
  ellipse(width/2,height/2, 380)
  
  
  //grey circle bg for seconds
  fill(30);
  noStroke();
  ellipse(width/2,height/2, 200,200)
  
  if (mouseX > 200 && mouseX < 300 && mouseY > 200 && mouseY < 300) {
    displayTime();
  }
  
  push();
    translate(width/2, height/2);
    angleMode(DEGREES)
    rotate(-90)
    dotSize = 3;
    noStroke();
    ///////////////////////////////////
    var hRad = 190;
    // var hColor = map(h,0,23,50,255);
    var hColor = color(0)
    // var hColor = color(226, 9, 63)
    var hDotSize = 5;
    fill(hColor);
    for (var i = 0; i <= 360; i+= 360/h) {
			if (h == 0) {
				h = 12
			} else {
				ellipse(cos(i) * hRad, sin(i) * hRad,hDotSize,hDotSize);
			}
      
    }
    ///////////////////////////////////
    var mRad = 130;
    var mColor = map(m,0,59,50,255);
    // var mColor = color(53, 87, 255)
    fill(mColor);
    for (var i = 0; i <= 360; i+= 360/m) {
      if (m > 0) {
        ellipse(cos(i) * mRad, sin(i) * mRad,dotSize,dotSize);
      }
    }
    ///////////////////////////////////
    var sRad= 90;
    var sColor = map(s,0,59,50,255);
    // var sColor = color(255, 86, 128)
    fill(sColor)
    for (var i = 0; i <= 360; i+= 360/s) {
      if (s > 0) {
        ellipse(cos(i) * sRad, sin(i) * sRad,dotSize,dotSize);
      }
    }
    ///////////////////////////////////
  pop();
}

function displayTime() {
  noStroke();
  fill(255);
  textAlign(CENTER);
  textSize(15);
  // xTime = 60
  // yTime = 40
  xTime = width/2;
  yTime = height/2;
	
	if (h==0) {
		h = 12
	}
  
	//display zero in front of single digit second
  if (s < 10 && m >= 10) {
    text(h + " : " + m + " : 0" + s, xTime, yTime);
	}
	//display zero in front of single digit minute
  else if (s >= 10 && m < 10) {
    text(h + " : 0" + m + " : " + s, xTime, yTime);
	}
	//display zeroes in front of single digit seconds and minutes
  else if (s < 10 && m < 10) {
    text(h + " : 0" +m + " : 0" + s, xTime, yTime);
	}
	//keep seconds and minutes as is when two digits
  else {
    text(h + " : " + m + " : " + s, xTime, yTime);
	}
}

face clock


Now this clock is much more interesting to look at. For this project, I altered another clock I had previously made. In this sketch, I incorporated color, animation (somewhat), and gave this "clock" a lot more personality.

var hr, mn, sc;
var end_hr, end_mn, end_sc;

function setup() {
 createCanvas(400,400); 
}

function draw() {
  background(255);
  
  hr = hour();
  mn = minute();
  sc = second();
  end_hr = map(hr % 12,0,12,0,360);
  end_mn = map(mn, 0, 60, 0, 360);
  end_sc = map(sc, 0, 60, 0, 360);
  
  /////////// time /////////////////////////
  
  //Display time
  if (sc < 10) {
    noStroke();
    fill(135, 158, 163);
    textAlign(CENTER);
    textSize(20);
    strokeWeight(5);
    text(hr + " : " + mn + " : 0" + sc, 80, 30);
  } else {
    noStroke();
    fill(135, 158, 163);
    textAlign(CENTER);
    textSize(20);
    strokeWeight(5);
    text(hr + " : " + mn + " : " + sc, 80, 30);
  }
  
  push();
  strokeWeight(8);
  noFill();
  angleMode(DEGREES);
  translate(width/2,height/2);
  rotate(-90);
  //seconds - innermost
  stroke(164, 206, 216);
  arc(0, 0, 250, 250, 0, end_sc);
	
  //minutes - middle
  stroke(35, 126, 196); 
  arc(0, 0, 320, 320, 0, end_mn);

  //hours - outside
  stroke(31, 56, 119); 
  arc(0,0,345,345,0,end_hr);
  pop();
  
  ///////////// static face ///////////////
  push();
  angleMode(DEGREES);
  translate(width/2,height/2);
  rotate(-90);
  
  //Top of face
  stroke(0);
  strokeWeight(7);
  noFill();
  arc(0,0,280,280,280,80);
  
  //Bottom of face
  noFill();
  arc(0,0,300,300,150,210);
  pop();

  //black eyebrows 
  stroke(0);
  fill(0);
  rectMode(CENTER);
  rect(130, 150, 25, 5, 15);
  rect(270, 150, 25, 5, 15);
  
  //eyes
  ellipseMode(CENTER);
  ellipse(120, 200, 20, 20);
  ellipse(280, 200, 20, 20);
  
  //nose
  noStroke();
  strokeWeight(6);
  fill(204, 95, 95);
  rect(width/2, 230, 15, 30, 20);
  
  //lips
  stroke(0);
  noFill();
  rect(width/2, 280, 60, 20, 20);
  
  //teeth
  line(width/2, 270, width/2, 290);
  line(width/2 - 15, 270, width/2 - 15, 290);
  line(width/2 + 15, 270, width/2 + 15, 290);
  
  ///////// face animations ///////////////
  
  if (sc % 2 == 0) {
    //eyebrows raise
    //cover old eyebrows w white
      stroke(255);
      strokeWeight(8);
      rectMode(CENTER);
      rect(130, 150, 25, 5, 15);
      rect(270, 150, 25, 5, 15);
    //new raised eyebrows
      strokeWeight(5);
      stroke(0);
      rect(130, 140, 25, 5, 15);
      rect(270, 140, 25, 5, 15);
    
    //mouth becomes smaller
    //cover old mouth
      //lips
      strokeWeight(10);
      stroke(255);
      noFill();
      rect(width/2, 280, 60, 20, 20);
      //teeth
      line(width/2, 270, width/2, 290);
      line(width/2 - 15, 270, width/2 - 15, 290);
      line(width/2 + 15, 270, width/2 + 15, 290);
    //new small mouth
      strokeWeight(6);
      stroke(0);
      ellipse(width/2, 280, 20,20);
	}
}

yuvian-Scope

download design as pdf here

For my praxinoscope design, I chose to keep it simple. In order to create this sketch, I first conducted research on bezier vertices and objects in Java and learned how to implement them in this project. In this praxinoscope, I used two, pulsing hearts - inspired by this heart emoji because it's one of my favorite emojis ¯\_(ツ)_/¯.


void drawArtFrame (int whichFrame) { 

  // Draw the frame number
  fill(0); 
  noStroke(); 
  textAlign(CENTER, CENTER); 
  text (whichFrame, -1, -47);

  // Draw expanding double heart emojis
  int nHearts = 3;
  for (int i=0; i
	

yuvian-Interruptions

Observations:
- The artwork is square.
- The artwork consists of many short black lines, on a white background.
- The lines all have the same length.
- The artwork is basically composed of a 60 * 60 grid.
- Horizontal lines show up less frequently than vertical lines.
- Lines take up more than half of the space.

The most challenging part of this assignment was understanding Perlin noise. I've used it in the past but not much. The concept of noise and trigonometric functions in order to randomize the angles of the lines took a while for me to figure out. Something that I understood almost at once was the gridlike structure of Molnár's "Interruptions". I immediately noticed the 56X56 grid upon which the lines were fixed. I think I was generally successful at recreating the artist's work but my lines are not as randomized as the original. This is probably an easy fix as I would have to go back in and manipulate some of the variables within noise but for now, it is a close representation of Molnár's work. I appreciate how seemingly simple the original work appears at first when in actuality, it is a lot more complex than I had originally thought.

yuvian-Reading

The Critical Engineer recognises that each work of engineering engineers its user, proportional to that user's dependency upon it.

A critical engineer's work is understood to have an effect on its user corresponding to degree in which the user relies on it. Thus, the more a user depends on the work, the more they will be influenced by its content.

This is an interesting thought regarding the relationship between a product and its user/audience. I can see this belief reflected in popular culture regarding the prevalence of smartphones in our current society. It is often joked that as our phones become "smarter" we become less so. Nowadays, it is easy to see the influence technology has on our lives. Recently, research has shown the detrimental effects of blue light on our Circadian clock, our postures suffer due to long hours in front of a computer screen, and average time spent outdoors is quickly decreasing. In the same way our technology is continuously engineered and altered throughout the years, so have our lifestyles. Because of this, the fifth tenet of the "Critical Engineering Manifesto" rings true.

yuvian-lookingoutwards01

As a preface, I did not know of many interactive/computational artworks before this class and most of my exposure to this field has been from looking through OpenProcessing.

One project I remember distinctly is Jason Labbe's sketch entitled "Frozen Brush"

The user interacts with this sketch by moving their mouse across the screen, dragging the "frozen brush" along with it.

<

Jason Labbe is an artist with a strong background in visual effects, game development, and 3d animation. He has worked on films such as "Avatar", "The Avengers: Age of Ultron", and other projects that require the use of sophisticated special effects. Thus, one can assume that he is inspired by game engine physics and other aspects of computer-generated simulations.

Before coming across this project, I had just begun experimenting with Processing and P5, playing around with simple blocks and shapes. It was only after seeing this project and those similar to it that I realized how dynamic, intelligent, artistic, and interactive computational artworks could be. I admire the colors within this sketch and the fluidity of the movement of the "ice" as your mouse interacts with the code. Although simplistic, I think that this sketch is really beautiful because it's straightforward but also seems well-thought out. I aspire to make computational artwork that seems a lot simpler than it is while maintaining a level of artistic complexity.

One thing I would have liked to see in this project is -surprisingly- more interactivity. It would have been interesting to take in the pressure of the user's mouseclick and use that information to affect the movement of the brush. In addition, since it is titled "Frozen Brush", I would have enabled a function that allows the user to actually paint onto the screen. Another feature that would have made this project more interesting and interactive is the use of sound. For some reason, I naturally associated the movement of the brush with sound. An implementation of the visual effects of this project with another associating the position of the brush with sound would be very interesting to interact with.