chaine-Body

Idle:

Blinking:

Mouth open:

My first idea (scratched):

Idea that I pursued:

Starting off this project, I was debating between two ideas. One where I would play around with rotations, and the other where I would manipulate the eyes depending on the facial expression. (especially the mouth) I decided that I would like to express emotions creatively, so I decided to pursue that. At first, I wanted the face to express sadness by crying whenever the mouth opened and the eyebrows were furrowed, but I had some issues with creating the tears to be more fluid-like, so it kind of just looked like a scary person shooting out spherical beams. I got some new ideas with that mistake; and I thought it would be cool for the person to transform into an evil medusa with red pupils when you made a scary face. Also, I ended up removing the mouth entirely because the focus was in the eyes. Aesthetically speaking, I wish I played around with the eyes' outlines more because I think it's quite distracting especially since none of the other shapes have an outline. I also wish I could diversify the eyes' shapes to make it more evil-looking and scary. (possibly?) Functionally, I wish the eyes would have shot out beams rather than circles or better conveyed the user being frozen by her stone-turning eye beams. In terms of the relationship between the facial motions and the treatment of it, I would say that the motions came first and I only adapted to the possibilities of those motions.

//
// 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;
 
 
//I used Dan Shiffman's box2d adaptation: https://github.com/shiffman/Box2D-for-Processing
import shiffman.box2d.*;
import org.jbox2d.collision.shapes.*;
import org.jbox2d.common.*;
import org.jbox2d.dynamics.*;
import org.jbox2d.dynamics.joints.*;
 
Box2DProcessing box2d;
 
ArrayList<Boundary> boundaries;
ArrayList<ParticleSystem> systems;
ArrayList<Box> boxes;
 
// 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;
 
PImage outerEye;
 
float aVelocity = .05;
boolean mouseVelocity = false;
float angle = 0;
float amplitudeX = 200;
float amplitudeY = 200;
float theta = 0;
PVector location;
float centerX;
float centerY;
 
void setup() {
  size(640, 480);
  frameRate(30);
  smooth();
 
  box2d = new Box2DProcessing(this);
  box2d.createWorld();
 
  box2d.setGravity(0, -20);
 
  systems = new ArrayList<ParticleSystem>();
  boundaries = new ArrayList<Boundary>();
  boxes = new ArrayList<Box>();
 
  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");
 
 
  outerEye = loadImage("circlebig.png");
 
  //boundaries.add(new Boundary(0,490,1280,10,0));
 
}
 
void draw() {  
  semiTransparent();
 
  box2d.step();
 
  for (ParticleSystem system: systems) {
    system.run();
 
    int n = (int) random(0, 2);
    system.addParticles(n);
  }
 
  for (Boundary wall: boundaries) {
    wall.display();
  }
 
  float varVelocity = calcVelocity(aVelocity);
  PVector angularVelocity = new PVector (angle, varVelocity);
  PVector amplitude = new PVector (amplitudeX, amplitudeY);
  PVector location = calculateCircle(angularVelocity, amplitude);
  //PVector centerCircle = calculateCenter(centerX, centerY);
 
  pushMatrix();
  if(found > 0) {
    drawOscillatingX(location);
  }
  popMatrix();
 
  for (Box b: boxes) {
    b.display();
  }
}
 
void semiTransparent() {
  rectMode(CORNER);
  noStroke();
  float backColor = map (mouthHeight, 1, 5, 255, 0);
  fill(backColor, backColor, backColor, 40);
  rect(0,0, width, height);
  stroke(0);
  noFill();
}
 
//basics of eye blink, iris movement from: https://raw.githubusercontent.com/jayjaycody/ComputationalCameras/master/wk3_Face/jai_face_keyPressComplexity/jai_face_keyPressComplexity.pde
 
float calcVelocity(float aVelocity) {
  float velocity = aVelocity;
  if (mouseVelocity == false) {
  }
  if (mouseVelocity == true) {
    velocity = map(mouseX, 0, width, -1, 1);
  }
  return velocity;
}
 
PVector calculateCircle (PVector angularVelocity, PVector amplitude) {
  float x = amplitude.x * cos (theta);
  float y = amplitude.y * sin (theta);
  location = new PVector (x, y);
  theta += angularVelocity.y;
  return location;
}
 
PVector calculateCenter (float centerX, float centerY) {
  PVector centerCircle = new PVector (centerX, centerY);
  return centerCircle;
}
 
void drawOscillatingX (PVector location) {
 
    float mouthScalar = map(mouthWidth, 10, 18, 0, 1.5); // make a scalar for location.x as a function of mouth
    location.mult(mouthScalar);
 
    float newPosX = map (posePosition.x, 0, 640, 0, width);
    float newPosY = map(posePosition.y, 0, 480, 0, height);  
    translate(width - newPosX, newPosY-100);
    scale(poseScale*.3);
    float irisColR = map (mouthHeight, 1, 5, 102, 204);
    float irisColG = map (mouthHeight, 1, 5, 204, 51);
    float irisColB = map (mouthHeight, 1, 5, 255, 0);
 
    float leftEyeMove = map(location.x, - amplitudeX, amplitudeX, -25, 33);
    pushMatrix();
    translate (leftEyeMove, 0);
    //Left iris
    fill(irisColR, irisColG, irisColB);
    noStroke();
 
    float eyeMult = map (mouthHeight, 1, 5, 1, 2);
 
    float irisSizeL = map (eyeLeft, 2, 3.5, 0, 50);
    ellipse(-100, 0, irisSizeL * eyeMult, irisSizeL * eyeMult);
 
    ////LeftPupil
    float eyeOutlineCol = map (mouthHeight, 1, 5, 0, 255);
 
    popMatrix();
 
    float rightEyeMove = map(location.x, - amplitudeX, amplitudeX, -33, 25);
    pushMatrix();   
    translate(rightEyeMove, 0);
    //right EYE
    //Right Iris
    fill(irisColR, irisColG, irisColB);
    noStroke();
 
    float irisSizeR = map (eyeRight, 2, 3.5, 0, 50);
    ellipse(100, 0, irisSizeR * eyeMult, irisSizeR * eyeMult);
 
    //Right Pupil
    stroke(eyeOutlineCol); 
    popMatrix();
    noFill();
 
 
    //get eye informatio and set scalar
    float blinkAmountRight = map (eyeRight, 2.5, 3.8, 0, 125);
    float blinkAmountLeft = map (eyeLeft, 2.5, 3.8, 0, 125);
 
 
    float eyeMultiplier = map (mouthHeight, 1, 5, 1, 3);
    // right eye size, blink and movement
    ellipse (100, 0, amplitudeX *.6, blinkAmountRight * eyeMultiplier); //scalar added to eyeHeight
    if (eyeRight < 2.7) {
      fill(255, 230, 204);
      ellipse (100, 0, amplitudeX *.6, blinkAmountRight*1.6 * (4 * eyeMultiplier/5)); //scalar added to eyeHeight
      noFill();
    }
 
    //left eye size, blink, and movement
    ellipse (-100, 0, amplitudeX *.6, blinkAmountLeft * eyeMultiplier); 
    if (eyeLeft < 2.7) {
      fill(255, 230, 204);
      ellipse (-100, 0, amplitudeX *.6, blinkAmountLeft*1.6 * (4 * eyeMultiplier/5)); //scalar added to eyeHeight
      noFill();
    }
 
    if (mouthHeight > 3.3) {
      //float mapScale = map (poseScale, 0, 4, 0, 1);
      pushMatrix();
      //translate(posePosition.x, posePosition.y);
      //scale(poseScale);
      Box p = new Box((width - posePosition.x - 100), (posePosition.y - 50));
      Box q = new Box((width - posePosition.x + 100), (posePosition.y - 50));
      boxes.add(p);
      boxes.add(q);
      popMatrix();
    }
 
}
 
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);
  }
}

chaine-LookingOutwards03

Nova Jiang's "Figurative Drawing Device" (link here) was exhibited at the New Wight Gallery in Los Angeles. This device requires two people, a designated tracer and the person to be outlined, and graphs the outline with imperfections that are clearly evident. I was drawn to this piece because of its personal and irregular nature. No two outlines would be the same and it was also dependent on the tracer. The device seems to be made up of a series of metal bars that translate the bigger outline of the tracer's drawing to something that could be fit into a sketchbook's size. Although overall, I love this piece, I wonder how the traces would look if the outline was completely black, creating a stronger contrast with the white paper's background. I respect the social and psychological elements in this piece within the relationships that it creates and also the fact that a single outline is not something that can be done quickly and perfectly. The poser must stay relatively still in poses that may be hard to maintain while the outliner must focus on doing his/her best in creating the drawing. Within completion, the drawing serves as an interpretation of the participants' combined effects, which is something I find exciting.

chaine-telematic

This app is for however many people you want there to be, as it is an interactive drawing canvas. Simply click on the screen to shoot out paint balls the same color as you, press left/right to grow smaller/bigger, press q for "party mode" (anyone could toggle it on or off), and any other key to respawn with a different size/color.

Gif:

The agario canvas is a drawing board that changes its brush quality according to the player itself.
Originally, I wanted to make an endless platformer of some sort with randomly generated holes--when a player crashes into the walls, they would explode and carve out this platformer for other people to get further. I tried creating this at first using the agario template's centering functionality already set for me. There were a lot of issues with this, however, and I decided to scrap that idea and create something entirely different while still using the agario template. I liked the idea of being able to move around freely as a player in his/her own painting. The trickiest part of this assignment was getting players to shoot out paint and make their mark stay relative to a bigger canvas than just a simple width and height. Although I implemented the core functions, I wish there were some more functions available. Some other ideas I had were players turning into different shapes to shoot something other than a circle, players being able to control their own paintballs (sway back and forth), etc. In terms of design issues, my canvas is based on equal roles with many people painting with many other people. It is a shared space where people can paint with their own "bodies".

Previous ideas:

chaine-viewing04

Spectacle vs. speculation: A spectacle is something commonly associated with the "higher end" while its purpose is more often than not profit-oriented and less about its own awareness. Speculation is more related to the social engagement that is more ambiguous with its goals, but it is focused on the actual content itself (radicality, relativity, disempowerment, etc.) rather than for an ulterior motive.

One of my previous looking outwards project describes the AIBO (or Artificial Intelligence Robot). Although at first, I assumed it would be more related to being a spectacle in its mass production and appeal to the crowd (design and functionality wise), I believe it is, in a way, both a spectacle and speculation. I think it's inherently tied with speculation in that the AIBO soccer matches were started as a way to further AI technology, with groups around the world participating on advancing their own AIBOs to improve and share information with others. Acceleration: The AIBO are constantly being renewed and improved not just from one company, but by other groups and individuals across the world. Visibility: They are creating events like the soccer tournaments to raise awareness of AI technology. Surplus: Each generation of AIBOs have the potential to be further renovated by others; nothing is "wasted". Commerce: Production of AIBOs were created with its introductory goal being commerce.

chaine-clock

My actual clock:

When I was working on sketching ideas for this assignment last Friday during class, I struggled quite a bit. I think I had too many ideas that were too different. I thought of incorporating trees and seasons, planets and its rotations, but I found myself constantly at a block that I couldn't get past. Throughout the week I pondered about time and I think I put too much pressure on time being a grandiose thing that needed a counterpart grandiose object to represent it. I took myself away from that thought and reflected upon my time spent living in a new building for the fall semester. My kitchen sink had had a leak in it and my parents and I had to put a container under it for the first few days to prevent it from spilling out everywhere. After it was filled, we'd empty it and the cycle began again. I decided to incorporate that as my clock to represent time in my own trivial, personal way.

Clock at 1:39 AM to 1:40 AM:

Clock at 10:02 PM:

Clock at 11:59 AM to 12 PM (you can see a small light green square forming on the lower middle with each new hour):

function setup(){
// Simple p5.js Clock Template
// Golan Levin, 2016
 
var prevSec;
var prevMin;
var prevHour;
var millisRolloverTime;
var secRolloverTime;
var hourRolloverTime;
var cubeList;
var x = [];
var squareSize;
 
//--------------------------
function setup() {
  createCanvas(400, 650);
  millisRolloverTime = 0;
  secRolloverTime = 0;
  hourRolloverTime = 0;
  cubeList = [];
  squareSize = 15;
  for (var k = 0; k < 24; k++){
    randomX = int(random(35, width - squareSize - 20));
    randomY = int(random(200, height - squareSize - 20));
    append(x, randomX);
    append(x, randomY);
    append(x, int(random(0,230)));
    append(x, int(random(0,230)));
    append(x, int(random(0,230)));
    append(x, int(random(1, 9)));
    append(cubeList, x);
    x = [];
  }
  print(cubeList);
}
//--------------------------
 
//--------------------------
function draw() {
  background(255,255,255,150); // My favorite pink
 
  // Fetch the current time
  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;
 
  if (prevMin != M) {
    secRolloverTime = millis();
  }
  prevMin = M;
 
  if (prevHour != H) {
    hourRolloverTime = millis();
  }
  prevHour = H;
 
  var smoothMin = floor(millis() - secRolloverTime);
  var mils = floor(millis() - millisRolloverTime);
  var smoothHour = floor(millis() - hourRolloverTime);
 
  //var leftMinDiv = map(height, 0, 800, 
 
 
  //fill(128,100,100);
  //text("Hour: "   + H, 10, 22);
  //text("Minute: " + M, 10, 42);
  //text("Second: " + S, 10, 62);
  //text("Millis: " + mils, 10, 82);
  //text("SmoothHour: " + smoothHour, 10, 102);
 
  var hourBarWidth   = map(H, 0, 23, 0, width);
  var minuteBarWidth = map(M, 0, 59, 0, width);
  var secondBarWidth = map(S, 0, 59, 0, width);
 
  // 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, width);
  var smoothMinFraction = M + secondsWithFraction;
  var smoothMinBar = map(smoothMinFraction, 0, (M*60) + 60, 0, width);
 
  //////////
 
  //noStroke();
  //fill(40);
  //rect(0, 100, hourBarWidth, 50);
  //fill(80);
  //rect(0, 150, minuteBarWidth, 50);
  //fill(120);
  //rect(0, 200, secondBarWidthChunky, 50);
  //fill(160);
  //rect(0, 250, secondBarWidthSmooth, 50);
  //fill(200);
  //rect(0, 50, smoothMinBar, 50);
  noStroke();
  var circleSize = 20;
 
  if (mils >= 300){
    var mapping2 = map(mils, 300, 999, 15, (height - (M * 10) - 10));
    fill(255, 153, 153);
    ellipse(width/2, mapping2, circleSize, circleSize);
  }
 
  var hourMap = map(smoothHour, 0, 3600000, height, 190);
  var minMap = map(smoothMin, 0, 60000, 10, 0);
  var minAdj = map(M, 0, 59, height - 15, 180);
 
  beginShape();
  for (var i = 0; i <= width+1; i++) {
    var mapWidth = map(i, i, width, PI, 2*PI); 
    var x = float(i);
    var mapping = map(mils, 0, 500, -PI, 0);
    var bounce = map(mils, 0,999, 9, 0);
    var y = 10 * sin(bounce * mapWidth * 0.1 * mapping) + (height - (M * 10) - 10);
    if (x >= 0 && x <= width+1){
      vertex(x, y);
    }
  }
 
 
  mapTankColR = map(M, 0, 60, 204, 255);
  mapTankColG = map(M, 0, 60, 255, 200);
  mapTankColB = map(M, 0, 60, 255, 200);
 
  fill(mapTankColR, mapTankColG, mapTankColB, 150);
  vertex(width, height);
  vertex(0, height);
  endShape();
 
  var minCount = 5;
 
  //255,200,200
  for (var j = height - 45; j > 50; j -= 50) {
    push();
    fill(128, 100, 100);
    text(minCount, 15, j);
    minCount += 5;
    pop();
  }
 
  for (var j = height - 10; j > 50; j -= 10) {
    push();
    stroke(0,0,0);
    strokeWeight(1);
    line(0, j, 10, j);
    pop();  
  }
 
  if (M == 59 && S == 59) {
    if (H == 23) {
      cubeAppear(0, mils);
    }
    else{
      cubeAppear(H+1, mils);
    }
  }
  for (var hor = 0; hor < H; hor++){
    push();
    var mapRotate = map(mils, 0, 999, 0, 2*PI);
    noFill();
    stroke(cubeList[hor][2],cubeList[hor][3],cubeList[hor][4]);
    rect(cubeList[hor][0] + (squareSize*cos(mapRotate * cubeList[hor][5]))/4, cubeList[hor][1] + (squareSize*sin(mapRotate * cubeList[hor][5]))/4,squareSize,squareSize);
    pop();
  }
  //0 0 153
}
 
function cubeAppear(hour, mils){
  if (hour == 0){
    setup();
    return;
  }
  else{
    noFill();
    strokeWeight(1);
    mapOpp = map(mils, 0, 800, 0, 255);
    stroke(cubeList[hour - 1][2],cubeList[hour - 1][3],cubeList[hour - 1][4], mapOpp);
    rect(cubeList[hour - 1][0],cubeList[hour - 1][1],squareSize,squareSize);
  //for (var cube = 0; cube < cubeList.length; cube++){
  //  push();
  //  noFill();
  //  stroke(cubeList[cube][2],cubeList[cube][3],cubeList[cube][4]);
  //  rect(cubeList[cube][0],cubeList[cube][1],squareSize,squareSize);
  //  pop();
  //}
  }
}

chaine-LookingOutwards02

"Amoeba Dance" by Memo Akten is an interactive sound-reactive installation which features an amoeba-like 3D life form responding to sound in real time. Although the year of creation is ambiguous, a video of the dance was published by Akten in March 2008. I really admire the fact that this project is happening in real-time and it can be a continuous life form until powered off. "Amoeba Dance" is known to use 1ch HD video, a microphone, and custom software.

Although the methods of its algorithmic creations are unknown, I can suppose that Akten played around a lot with geometrics and reflections. In the artist's own words, this was an "exploration of abstract anthropomorphism and unconventional computer generated visuals and 3D aesthetics." Throughout the amoeba's transformations, it still has a sense of balance and likeness even while rotating and changing shape. It's movements, while sometimes rigid and seemingly unpredictable, are actually just following the sound patterns. Loud noises jerk the amoeba forward while it has a constant, slower rotation it follows. Therefore, I would place this piece nearer to being balanced. It moves and transforms in a way that is predictable--less dictated by chaos.

Link to dance below:

http://www.memo.tv/portfolio/amoeba-dance/

chaine-Reading03

I definitely agree with the thinking that there is both first word art and last word art. In my opinion, the two feed off of each other in a way. Variations of already "invented" last word art can evolve to maybe create first word art. Further studies into the field of first word art can generate new interest for new branches of art. The interest in something new and exciting appealing to new artists--the cycle continues.

The new technologies constantly arising may be revolutionary in innovation, convenience, or entertainment. Since those three fields have such dominance over everyone's lives, it is not surprising to see why technologies shape culture. For example, today's prevalence of convenient taxi systems such as Uber or Lyft have almost a culture of its own. Furthermore, technological development can also be shaped by culture. Using the same example as before, the culture today seems to be busier and faster than it used to be. There are always things to do and places to be. Inventions like the Uber was created directly to combat that; being affordable, able to get a ride quickly, and using a trustworthy review system.

 

chaine-AnimatedLoop

When I was first brainstorming ideas for my looping gif, I wanted to involve something "gobstopper-esque" just because of its simple but striking colors. I also somehow wanted to convey bursts of "flavor" and change into my gif, so I already knew from the start that I wanted to use the mapping function a lot on the colors. Looking back, I thought my sketches were very basic and almost too simple. I ended up making it more complicated both to make my gif more interesting and also to test myself. I started off with the given double exponential sigmoid function to drag my gobstopper down from the top to the center of the canvas, but I decided that starting straight from the center looked better because the circle wasn't chopped up in the beginning. Then I used the bounce in, bounce out, and bounce in and out functions to make my gobstoppers pop, and I thought that this function suited how they tasted. And finally, I used the exponential for the circle directly in the center to overtake the canvas as the frames went on. I think I did alright with the color palettes and color changes, but I would have liked to incorporate more functions and more elements to this gif. I also think the way the white circle grows larger is awkward and would like to make it maybe so that it "bounces" like its other circular counterparts and finds a more natural way of clearing the canvas.

// 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 = "chaine";
var nFramesInLoop = 240;
var bEnableExport = true;
 
// 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;
}
 
//===================================================
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 &amp;&amp; bEnableExport) {
    var frameOutputFilename = myNickname + "_frame_" + nf(nElapsedFrames, 4) + ".png";
    print("Saving output image: " + frameOutputFilename);
    saveCanvas(theCanvas, frameOutputFilename, 'png');
    nElapsedFrames++;
 
    if (nElapsedFrames &gt;= 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(255);
  smooth();
  stroke(0, 0, 0);
  strokeWeight(2);
 
  //----------------------
  // Here, I assign some handy variables. 
  var cx = 320;
  var cy = 320;
  noStroke();
  var arcSize = 20;
  var topY = 0 - arcSize - 2;
  var botY = height + 2;
 
    push();
 
    //I ended up not using this because it looked better starting centered
    //var eased = doubleExponentialSigmoid ((percent), 0.7); 
    //eased = (eased)%1.0; 
    //var yPosition2 = map(eased, 0, 1, topY, botY/2); 
 
    var eased2 = exponential (percent*1.2);
    var circleGrow = map(eased2, 0, 2, 0, 600);
    //ellipse (width/2, yPosition2, 20, 20);
 
    var eased3 = bounceInOut (percent * 0.5);
    var circle2Grow = map(eased3, 0, 1, 0, 2000);
 
    var eased4 = bounceInOut (percent * 0.5);
    var circle3Grow = map(eased4, 0, 1, 0, 1500);
 
    var eased5 = bounceInOut (percent * 0.5);
    var circle4Grow = map(eased5, 0, 1, 0, 1000);
 
    var easedLast = exponential (percent);
    var easedGrow = map(easedLast, 0, 1, 0, 1000);
 
    //black arc
    var test = map(percent, 0, 1, 0, 2*PI);
    //neon green arc
    var test1 = map(percent, 0, 1, 0, (3 * PI)/2);
    //light green arc
    var test2 = map(percent, 0, 1, 0, PI);
    //pink arc
    var test3 = map(percent, 0, 1, 0, PI/2);
 
 
    var arcCol1 = map(percent, 0.2, 1, 255, 204);
    var arcCol11 = map(percent, 0.2, 1, 204, 0);
    var arcCol111 = map(percent, 0.2, 1, 229, 102);
 
    //arc 1 light pink 255 204 229 -&gt; 204 0 102
    fill (arcCol1,arcCol11,arcCol111);
    arc(width/2, height/2, 1100*percent,1100*percent,0,test);
 
    var arcCol2 = map(percent, 0.2, 1, 204, 76);
    var arcCol22 = map(percent, 0.2, 1, 255, 153);
    var arcCol222 = map(percent, 0.2, 1, 229, 0);
 
    //arc 2 light green 204 255 229 -&gt; 76 153 0
    fill (arcCol2, arcCol22, arcCol222);
    arc(width/2, height/2, 1100*percent,1100*percent,0,test1);
 
 
    var arcCol3 = map(percent, 0.2, 1, 200, 0);
    var arcCol33 = map(percent, 0.2, 1, 255, 102);
    var arcCol333 = map(percent, 0.2, 1, 200, 102);
 
    //arc 3 200 255 200 -&gt; 0 102 102
    fill (arcCol3, arcCol33, arcCol333);
    arc(width/2, height/2, 1100*percent,1100*percent,0,test2);
 
    var arcCol4 = map(percent, 0.2, 1, 204, 76);
    var arcCol44 = map(percent, 0.2, 1, 229, 0);
    var arcCol444 = map(percent, 0.2, 1, 255, 153);
 
    //arc 4 light blue 204 229 255 -&gt; 76 0 153
    fill (arcCol4, arcCol44, arcCol444);
    arc(width/2, height/2, 1100*percent,1100*percent,0,test3);
 
 
    var circleCol1 = map(eased3, 0, 0.5, 102, 0);
    var circleCol11 = map(eased3, 0, 0.5, 178, 0);
    var circleCol111 = map(eased3, 0, 0.5, 255, 0);
 
    //center circle 1 pink 255 102 178
    fill (circleCol111,circleCol1,circleCol11); 
    ellipse (width/2, height/2, circle2Grow, circle2Grow); 
 
    var circleCol2 = map(eased4, 0, 0.75, 255, 0);
    var circleCol22 = map(eased4, 0, 0.75, 102, 0);
    var circleCol222 = map(eased4, 0, 0.75, 255, 0);
 
    //center circle 2 lighter pink 255 102 255
    fill (circleCol2, circleCol22, circleCol222); 
    ellipse (width/2, height/2, circle3Grow, circle3Grow); 
 
    var circleCol3 = map(eased5, 0, 1, 255, 0);
    var circleCol33 = map(eased5, 0, 1, 204, 0);
    var circleCol333 = map(eased5, 0, 1, 255, 0);
 
    //center circle 2 lightest pink 255 204 255
    fill (circleCol3, circleCol33, circleCol333); 
    ellipse (width/2, height/2, circle4Grow, circle4Grow); 
 
 
    var circleCol0 = map(easedLast, 0.1, 0.15, 200, 255);
    var circleCol00 = map(easedLast, 0.1, 0.15, 200, 255);
    var circleCol000 = map(easedLast, 0.1, 0.15, 200, 255);
 
    //center circle 2 white
    fill (circleCol0, circleCol00, circleCol000); 
    ellipse (width/2, height/2, easedGrow, easedGrow); 
 
 
    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&lt;=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);
}
 
function exponential (_x){
  return((_x == 0.0) ? _x : pow(2, 10 * (_x - 1)));
}
 
function bounceIn (_x){
  return(1 - this.bounceOut(1 - _x));
}
 
function bounceOut (_x){
    if(_x &lt; 4/11.0)
    {
      return((121 * _x * _x)/16.0);
    }
    else if(_x &lt; 8/11.0)
    {
      return((363/40.0 * _x * _x) - (99/10.0 * _x) + 17/5.0);
    }
    else if(_x &lt; 9/10.0)
    {
      return((4356/361.0 * _x * _x) - (35442/1805.0 * _x) + 16061/1805.0);
    }
    else
    {
      return((54/5.0 * _x * _x) - (513/25.0 * _x) + 268/25.0);
    }
}
 
function bounceInOut (_x){
      if(_x &lt; 0.5)
    {
      return(0.5 * this.bounceIn(_x*2));
    }
    else
    {
      return(0.5 * this.bounceOut(_x * 2 - 1) + 0.5);
    }
}
 
function exponentialEmphasis (_x, _a){
    if(!_a) _a = 0.25; // 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);
 
    if (_a &lt; 0.5) {
      // emphasis
      _a = 2*(_a);
      var _y = pow(_x, _a);
      return(_y);
    }
    else {
      // de-emphasis
      _a = 2*(_a-0.5);
      var _y = pow(_x, 1.0/(1-_a));
      return(_y);
    }
}

chaine-Scope

My zoetrope was the main reason behind my looping gif. I wanted to mostly play around with circles and how multiple circles can create different illusions. For example, a growing and shrinking circle can look like a person blinking. Incorporating multiple circles growing at different speeds can give off an alien feel and it could look like a signal receiver. I decided to use part of the template of the elongating ellipse to create the shadow at the base depending on the "growth" of the circle while it was bouncing and being enveloped by two larger circles.

/*
// 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!
 
  push();
  fill(0); 
  noStroke(); 
 
  // Draw a pulsating ellipse
 
  //draw the shadow
  noStroke();
  fill(150,150,150);
  var t = map(whichFrame, 0, nFrames, 0, 1); 
  var shadow = map(cos(t*TWO_PI), 1, -1, 10, 30); 
  ellipse(0, 45, shadow, shadow*0.5);
 
 
  noFill(); 
  stroke(0);
  strokeWeight(1); 
 
  var diam = map(cos(t*TWO_PI), -1, 1, -30, 50); 
 
  //first circle (biggest)
  var ell1 = map(cos(t * TWO_PI), 1, -1, 17, (30*(whichFrame/3)));
  ellipse(0, diam, ell1, ell1);
 
  //second circle (second biggest)
  var ell2 = map(cos(t * TWO_PI), 1, -1, 16, (30*(whichFrame/4)));
  ellipse(0, diam, ell2, ell2);
 
  //center black circle
  fill(0);
  var diam2 = map(cos(t * TWO_PI), 1, -1, 15, 30);
  ellipse(0, diam, diam2, diam2);
  pop();
 
}
 
//-------------------------------------------------------
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);
}

chaine-Reading02

Question 1A: I had already known before reading this that there was a complexity to biological life that seemed generated or highly ordered, but I really enjoyed reading about this scale of total order and randomness. When thinking of an example, my mind automatically goes to the appearance of the golden ratio in nature. For example, these flower heads:

And plenty of other examples from https://io9.gizmodo.com/5985588/15-uncanny-examples-of-the-golden-ratio-in-nature.

In terms of its effective complexity, disregarding its microscopic, structured atoms, it also displays a highly structured form. This example would be closer to total order, near crystal lattices.

Question 1B: "The Problem of Dynamics" is something I am currently struggling with. I always question what defines a certain subset within art. I always feel like generative art is art that is constantly "generating" itself, but I think that generation can also happen behind the scenes. For example, while a piece of code is in the process of generating art, it is still generating.