ocannoli-Body

Star Collector

Move your face to direct the telescope (the blue circle) to the special yellow stars. Once a star is in your sights, open your mouth to collect it and get a point. But be careful not to raise your eyebrows too high or the aliens will attack and take your points.

Going into this project, brainstorming for ideas was difficult for me. I had a lot of shallow, surface level ideas but no a lot of concepts I thought were good enough. A lot of my process started conceptually with an idea of the project or the narrative rather than understanding the full relationship with the body; therefore, I never fully landed on something I thought was interesting or in depth enough. For the star collector idea I liked the idea of the the ability for the body or even simply the face to control space or the cosmos. I wanted to add more features and a different style which would limit the players view to just that circle and have the board be much bigger. I also wanted players to find patterns, or maybe constellations rather than other "stars".  I used face OSC in processing which was both an intentional move but also somewhat guided the relationship between the body and the interface. Overall, I enjoyed the experience of working with motion capture for the first time and if I were to redo this project I'd like to come up with something more complex either conceptually or in execution.

 //
// 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;
 
// 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;
float circleX;
float circleY; 
PImage starSky;
PImage aliens; 
int score; 
FloatList specialStars;
PFont fjFont;
int numOfStars; 
boolean doneOnce;
 
 
 
void setup() {
  size(800, 800);
  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");
  starSky = loadImage("stars.png");
  aliens= loadImage("ALIENS.png");
  score=0; 
  specialStars = new FloatList();
  numOfStars=7;
  for (int i=0; i<numOfStars;i++){ createSpecialStar(); } fjFont = createFont("FjallaOne-Regular.ttf",32); doneOnce=false; } public void createSpecialStar(){ float x= random(0,width); float y=random(85,height-180); specialStars.append(x); specialStars.append(y); } public void newSpecialStars(){ for (int i=specialStars.size()-1;i>-1; i--){
     specialStars.remove(i);
   }
   for (int i=0; i<numOfStars; i++){
     createSpecialStar(); 
   }
 }
 
void draw() {  
  image(starSky,0,0);
  int seconds = second();
  //refreshes special stars every 5 seconds
  if ((seconds-1)%5==0 && doneOnce==true){
    doneOnce=false; 
  }
  if (seconds%5==0 &&doneOnce==false){
    newSpecialStars(); 
    doneOnce=true; 
 
  }
  //tint(255,255,255); 
  float radius=40; 
  textFont(fjFont);
  textSize(50); 
  text("Score: "+score,10,height-10); 
  fill(255,255,102);
  noStroke(); 
  //makes special stars
  for (int i=0; i<specialStars.size(); i+=2){
    float starX=specialStars.get(i);
    float starY=specialStars.get(i+1);
    ellipse(starX, starY, 10,10);   
  }
 
  //Makes telescope Circle
  stroke(0);
  noFill(); 
  stroke(204,229,255);
  strokeWeight(4);
  ellipse(circleX,circleY,radius*2,radius*2); 
 
  for (int i=0; i<specialStars.size(); i+=2){
    float starX=specialStars.get(i);
    float starY=specialStars.get(i+1);
    //makes stars then checks valid to eat star
    if (starX<circleX+(radius/2) && starX>circleX-(radius/2) && starY<circleY+(radius/2) && starY>circleY-(radius/2)){ 
        if(jaw>23.5){
          specialStars.remove(i+1);
          specialStars.remove(i);
          score+=1; 
          createSpecialStar(); 
        }
 
    }
  }
 
  if (eyebrowLeft>9.2){
    image(aliens,width/6,height/4,592,326.5);
    if (score<=5){ score=0; } else if (score>5){
      score=score-5; 
    }
  }
 
}
 
 
 
// 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);
  circleX=x+(posePosition.x-150);
  circleY=y+(posePosition.y-150);
 
 
}
 
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);
  }
}

 

Trucker Chat:

Chatroom for Incoherent CB Radio Communication Between "Truckers"

 

 

In the beginning phases of working on this project my ambitions were much higher, possibly wanting to work with Spotify/music APIs and drum machines. However, I quickly decided that I just wanted to make something simple and fun to allow me to spend time learning and experimenting with new techniques, features etc. A constant concept through my process, has been the idea of equal roles between all users. When text is manipulated and messed with to a point of incoherence, it really puts all users on the same level of not understanding what's going on and having a good laugh. Experimenting with Rita and regex really shaped most of this project because I was mainly text focused and had also never used either one of those ever before. Although there are a lot of bugs and the project could be a lot more, I had a lot of fun and I learned a lot. (Also all of the trucker slang is real, here is a breakdown of what most of it means)

Trucker Slang Meanings 

ocannoli-LookingOutwards03.

Fragments of RGB is an interactive installation made by Onformative which experiments with the concept of human perception. In this work, projected light points on an LED screen react to the viewer of the work by changing the content as they approach. I find the concept and the commentary of the piece extremely interesting and intriguing to consider the relativity of the world based on our perceptions. Although the topic is large and broad, the execution of the piece is very elegant and communicates that idea subtly but clearly. I appreciated how the creator of the piece left the message they were trying to communicate not be simply stated but required to be discovered through interaction which I think makes the piece more powerful. However, I think the piece could have been stronger if there was something that indicated a bit clearer that the viewer was in the variable controlling the perspective changes but there is equally something to be said about elegant simplicity. Overall, I thought it was extremely inspiring how combing RGB values and having human influenced transformation of the perspective had not only an extremely beautiful result but also carried a lot of meaningful commentary.

ocannoli-viewing04

According to Warburton, spectacle refers to the type of art that tries new things in the realm of digital media more for the sake of commercial novelty rather than to address issues or discuss implications. Speculation refers to digital media that aims to address possibly some of the oblique areas spectacle art does not however it often is guilty of disregarding the impact of the practice.

As discussed in Friday's lecture about multi-user environments, the nVidia Holodeck project I believe is a spectacle type projects. Although the project utilizes new technology to discuss the how this interactivity is an important element they are advancing, the use of technology and new VR equipment feels novel for the sake of novelty. Essentially, not saying whether or not it was a good project, just simply addressing its commercialization and lack of content brings up a lot of material to talk about. Given these opinions there is definitely a quality of expertise, refinement, and skill that went into making this environment to the quality it is; however, the project seems to lack much depth in regards to discussing any topic along the lines of outsourced labor, supply chains or other gray areas that obviously were an important part of a project of this scale.  Therefore due to the projects innovation, skill, and lack of an overall discussion of theory of digital practice, this project leans more toward spectacle a

 

ocannoli-clock

Big Brother's Clock

Replacing Minutes with Seconds View:

Explanation:

From the beginning, I knew I wanted to experiment with time unconventionally because I love the relativity of time and how it is interpreted.  I began to mess around with the concept of taking time and making each minute into a year by adding the hours and minutes to create the decade in the 1900s. Although it is not an "accurate" representation of time, I liked that it furthered the idea of time's interpretive nature. Originally, I was thinking of sampling a song from a certain year and possibly using APIs to gain access to a variety of music. However, as I experimented with how to compute the year, I was fascinated that although there are technically 24 hours in a day and 60 minutes in a hour, the clock never reaches this technically real but not real time. Furthermore, when inserted into my formula of computing the year, this "ideal" year was 1984. I found that an extremely interested premise that time somewhat revolved around this number and subsequently considering that time revolved around the ideas about society and humanity within the novel. From here, my concept shifted from music to literature considering the significance of the book 1984. Although not complex in code, each book was picked to embody some of the morals shown in 1984.  Each book serves an important purpose and therefore the projection of time through these books is personal and biased based on my experiences. Overall, "Big Brother's Clock" was made through an exploration of the conceptual more than the visual or mathematical.

//The Clock of 1984
PImage bookBack;
int circleX, circleY;
int circleSize = 50;
color circleColor;
color currentColor;
boolean circleOver = false;
int visible; 
 
 
void setup() {
  size(800, 570);
  bookBack=loadImage("oldBook.jpg");
  circleColor = color(255);
  currentColor=color(209, 142,8);
  circleX = 180;
  circleY = 70;
  visible=-1; 
  ellipseMode(CENTER);
}
 
void draw() {
  image(bookBack,0,0);
 
  //All 83 Books
   String[] books = {"The Wonderful Wizard of Oz",
    "The First Men in the Moon",
    "Just So Stories",
    "The People of the Abyss",
    "The Tale of Peter Rabbit\nand Benjamin Bunny",
    "The Gift of the Magi",
    "The Future in America:\nA Search After Realities",
    "Cautionary Tales for Children",
    "The Man Who Was Thursday",
    "The Machine Stops",
    "Howards End",
    "The Secret Garden",
    "The Problems of Philosophy",
    "The Google Book",
    "The Beasts of Tarzan",
    "The Metamorphosis",
    "Relativity: The Special\nand the General Theory",
    "His Family",
    "The Decline of the West:\nPerspectives of world-history",
    "Strange News from Another Star",
    "The Age of Innocence",
    "How to Analyze\nPeople on Sight",
    "The Velveteen Rabbit",
    "The Ego and the Id",
    "So Big",
    "The Great Gatsby",
    "Winnie-the-Pooh",
    "Being and Time",
    "Nadja",
    "Is Sex Necessary? Or,\nWhy You Feel the Way You Do",
    "The Mysterious Universe",
    "The Story of Babar,\nthe Little Elephant",
    "Journey to the End\nof the Night",
    "Lord Edgware Dies",
    "The Logic of\nScientific Discovery",
    "It Can't Happen Here",
    "How to Win Friends\nand Influence People",
    "The Hobbit",
    "The Sword in the Stone",
    "The Secret Life\nof Walter Mitty",
    "Portrait of the\nArtist as a Young Dog",
    "The Garden of Forking Paths",
    "The Stranger",
    "The Little Prince",
    "What Is Life?",
    "Animal Farm",
    "The Common Sense Book\nof Baby and Child Care",
    "The Age of Anxiety",
    "No Longer Human",
    "Death of a Salesman",
    "The Martian Chronicles",
    "The Catcher in the Rye",
    "The Borrowers",
    "Fahrenheit 451",
    "Lord of the Flies",
    "I can jump puddles",
    "Aniara",
    "The Cat in the Hat",
    "The Computer and the Brain",
    "Sweet Bird of Youth",
    "The Weirdstone of Brisingamen",
    "James and the Giant Peach",
    "A Wrinkle in Time",
    "Where the Wild Things Are",
    "The Giving Tree",
    "The Autobiography of Malcolm X",
    "Rosencrantz and\nGuilderstern Are Dead",
    "The Medium is the Massage:\nAn Inventory of Effects",
    "Do Androids Dream\nof Electric Sheep?",
    "Slaughterhouse-Five",
    "Fantastic Mr. Fox",
    "A Happy Death",
    "Frog and Toad Together",
    "Momo",
    "The Chocolate War",
    "Tuck Everlasting",
    "The Alteration",
    "Bridge to Terabithia",
    "The World According to Garp",
    "The Neverending Story",
    "Cosmos: A Personal Voyage",
    "A Light in the Attic",
    "Life, the\nUniverse and Everything",
    "Pet Sematary"
   };
 
 
  // Fetch the current time
  int H = hour();
  int M = minute();
  int arrSpot = H+M;
  int year = 1900 + (H + M);
 
 
 
  noStroke();
  PFont font = createFont("BonvenoCF-Light.otf",32);
  textFont(font); 
  fill(255,255,255);
  textSize(20);
  String currTimeString = "19: " + (H) + "+" + nf(M, 2);
  if (visible>0){
  text(currTimeString, 10, 25);
  text("Hour: " + H, 10, 50);
  text("Minute: " + M, 10, 75);
  text(year, 10, 100);
  }
  textSize(25);
  text(books[arrSpot], 300,80);
 
  update(mouseX, mouseY); 
  if (circleOver) {
    fill(currentColor);
  } else {
    fill(circleColor);
  }
  ellipse(circleX, circleY, circleSize, circleSize);
  fill(51); 
  textSize(7);
  text("   Clock\nBreakdown", circleX-19,circleY-5); 
  text("   Clock\nBreakdown", circleX-19.5,circleY-5); 
}
 
 
//Code Modified From Processing Site
void update(int x, int y) {
  if ( overCircle(circleX, circleY, circleSize) ) {
    circleOver = true;
  }
  else{
    circleOver=false; 
  }
}
 
void mousePressed() {
  if (circleOver) {
    visible=visible*-1; 
    color temp= circleColor;
     circleColor=currentColor;
     currentColor=temp; 
  }
}
boolean overCircle(int x, int y, int diameter) {
  float disX = x - mouseX;
  float disY = y - mouseY;
  if (sqrt(sq(disX) + sq(disY)) < diameter/2 ) {
    return true;
  } else {
    return false;
  }
}
 
//Image Credits: BuyBackdrops.com
//https://www.buy-backdrop.com/bmz_cache/e/e7d916a4073273331838331e718c7a53.image.300x200.jpg

 

 

ocannoli-Reading03

Although I find the notion of first word art and last word art interesting, I am of the belief that everything is inspired by something and that no work of art is exactly the same as the next. Therefore, it is hard for me to locate a position even along the spectrum since I see it more as a continuum of thought constantly going forward and back, following and breaking form. Even direct copy and pasted code can be different due to the creator, intention, or context in which it was made. This being said, in such a fast paced and constantly changing technological society, novelty is a quality highly valued by a lot of people. Typically, novelty for the sake of novelty does not age well; however, when novelty comes about in the process of creating something one is extremely passionate about or during the process of problem solving, the chances for that technology aging well is greater. Overall, I believe that it is difficult to confine any art form into specific categories for there are so many possibilities and outliers that need to be considered especially regarding the topic of novelty in technology.

ocannoli-LookingOutwards02

Roger Water's project "A Journey into Hyperland" is a 360 VR live experience where the user can fly around an environment and launch items and creatures in order to interact. An aspect of this piece that is so fascinating is that many aspects of the environment such as shape, colors, mountain and marine shape are all determined in real time by the music of band Niagra. I admire the simplicity and elegance of the execution of the design but I also admire the concept of a generative environment spawning from music. Considering that the program reacts differently based on time and location of the user, I suppose that the algorithm behind the work was definitely heavily guided by the idea of generativity rather than it being added later or as an extra experiment. I believe Water did a pretty great job having an effective complexity considering a random environment that looks very clean yet is powered by a song.

Click here to experience his project

ocannoli-AnimatedLoop

Sketches:

GIF:

Description:

In conceptualizing the piece, I had a lot of grand ideas about recreating something in 8-Bit from the original Legend of Zelda game or making a pong-like loop with new colors. Mainly, I was experimenting with circles and opacity to ultimately just mess around. There were many experiments with small pong sized rotating circles and creating weird shapes but eventually my sketches ended up morphing into to creating a minimalist start button for a game. I used PennerEaseOutExpo easing function for the background white circle to create a slight scrolling effect and add more movement. Admittedly, I did not spend as much time as I wished I could on the project; therefore, I'm not very proud of the results, but it was a good introduction to start thinking about experimenting with graphics and the many possibilities regarding such. I feel like I succeeded in some aesthetic aspects and creating a good basis but not the strongest for a final product.

Code:

// Global variables. 
String  myNickname = "nickname"; 
int     nFramesInLoop = 120;
int     nElapsedFrames;
boolean bRecording; 
 
//===================================================
void setup() {
  size (640, 640); 
  bRecording = false;
  nElapsedFrames = 0;
}
//===================================================
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 (5, 44, 64);
  smooth(); 
  stroke (0, 0, 0); 
  strokeWeight (2); 
  // Here, I assign some handy variables. 
  float cx = 100;
  float cy = 100;
    //----------------------
   //Here's a sigmoidally-moving pink square!
   //This uses the "Double-Exponential Sigmoid" easing function 
   //from https://github.com/golanlevin/Pattern_Master
  float eased = function_PennerEaseOutExpo (percent); 
  float yPosition2 = map(eased, 0, 1, 0, 640); 
  noStroke();
  fill (255, 255, 255);
  yPosition2=yPosition2-600;
  for(int j=0; j<=9;j++){
    int rX=-40;
    for(int i=0; i<10; i++){
    rX=rX+90;
    if(i!=2 && i!=3 && i!=4){
    ellipse (rX, yPosition2, 15, 15);
    }
    }
    yPosition2+=120;
  }
  //----------------------
  // Here's a pulsating ellipse
  float ellipsePulse = sin ( 1.0 * percent * TWO_PI); 
  float ellipseW = map(ellipsePulse, -1, 1, 200, 400); 
  float ellipseH = map(ellipsePulse, -1, 1, 200, 400); 
  float ellipseColor = map(ellipsePulse, -1, 1, 239, 200); 
  float ellipsePulse2 = sin ( 2.0 * percent * TWO_PI); 
  float ellipseW2 = map(ellipsePulse2, -1, 1, 200, 350); 
  float ellipseH2 = map(ellipsePulse2, -1, 1, 200, 350);
  float ellipsePulse3 = sin ( 1.7* percent * TWO_PI); 
  float ellipseW3= map(ellipsePulse3, -1, 1, 10, 250); 
  float ellipseH3 = map(ellipsePulse3, -1, 1, 10, 250);
  noStroke();
  fill (252, ellipseColor, ellipseColor, 70); 
  ellipse (325, 300, ellipseW, ellipseH); 
  ellipse (325, 300, ellipseW2-30, ellipseH2-30);  
  ellipse (325, 300, ellipseW2-30, ellipseH2-30);
}
//===================================================
// Taken from https://github.com/golanlevin/Pattern_Master
float function_PennerEaseOutExpo(float t) {
  //functionName = "Penner's EaseOut Exponential";
  return (t==1) ? 1 : (-pow(2, -10 * t) + 1);
}

 

ocannoli-Scope

Scope GIF:

Description:

My praxinoscope is a very simple design, centered around rotating circles. Initially, I was really inspired by planets and was thinking about maybe having a planet with a single asteroid. However, I thought that looked boring and decided to play around with rotation patterns and spirals. There is not much conceptually behind the design, instead it was mainly an experimentation with rotation patterns and how to make a trippy image that hurts your eyes.

Scope PDF:

ocannoli-praxinoscope-output

Scope Code:

import processing.pdf.*;
boolean bRecordingPDF = false;
 
float inch = 72; 
float diamArtInner = inch * 1.50; 
float diamArtOuter = inch * 4.80; 
float diamCutInner = inch * 1.41; 
float diamCutOuter = inch * 4.875; 
float holeDy = inch * 0.23;
float holeDx = inch * 0.20;
float holeD = inch * 0.1;
 
final int nFrames = 10; 
int myFrameCount = 0;
int exportFrameCount = 0; 
boolean bAnimate = true; 
boolean bExportFrameImages = false;
 
//-------------------------------------------------------
void setup() {
  size(792, 612); // 11x8.5" at 72DPI
  frameRate(15);
  smooth();
} 
 
//-------------------------------------------------------
void draw() {
  background(240); 
  if (bRecordingPDF) {
    beginRecord(PDF, "praxinoscope-output.pdf");
  }
 
  // Do all the drawing. 
  pushMatrix(); 
  translate(width/2, height/2);
  drawCutLines(); 
  drawGuides(); 
  drawAllFrames();
  popMatrix();
 
  if (bExportFrameImages) {
    // If activated, export .PNG frames 
    if (exportFrameCount < nFrames) { String filename = "frame_" + nf((exportFrameCount%nFrames), 3) + ".png"; saveFrame("frames/" + filename); println("Saved: " + filename); exportFrameCount++; if (exportFrameCount >= nFrames) {
        bExportFrameImages = false;
        exportFrameCount = 0;
      }
    }
  }
 
  if (bRecordingPDF) {
    endRecord();
    bRecordingPDF = false;
  }
}
 
 
//-------------------------------------------------------
void keyPressed() {
  switch (key) {
  case ' ': 
    // Press spacebar to pause/unpause the animation. 
    bAnimate = !bAnimate;
    break;
 
  case 'p': 
  case 'P':
    // Press 'p' to export a PDF for the Praxinoscope.
    bRecordingPDF = true; 
    break;
 
  case 'f': 
  case 'F': 
    // Press 'f' to export .png Frames (to make an animated .GIF)
    myFrameCount = 0; 
    exportFrameCount = 0; 
    bExportFrameImages = true;
    bAnimate = true; 
    break;
  }
}
 
//-------------------------------------------------------
void drawCutLines() {
  fill(0); 
  textAlign(CENTER, BOTTOM); 
  text("Praxinoscope Template", 0, 0-diamCutOuter/2-6); 
 
  stroke(0); 
  strokeWeight(1.0);
 
  noFill(); 
  if (!bRecordingPDF) {
    fill(255); 
  }
  ellipse(0, 0, diamCutOuter, diamCutOuter);
 
  noFill(); 
  if (!bRecordingPDF) {
    fill(240); 
  }
  ellipse(0, 0, diamCutInner, diamCutInner);
 
  noFill(); 
  ellipse(diamCutOuter/2 - holeDx, 0-holeDy, holeD, holeD); 
 
  line (diamCutInner/2, 0, diamCutOuter/2, 0);
}
 
//-------------------------------------------------------
void drawGuides() {
  // This function draws the guidelines. 
  // Don't draw these when we're exporting the PDF. 
  if (!bRecordingPDF) {
 
    noFill(); 
    stroke(128); 
    strokeWeight(0.2); 
    ellipse(0, 0, diamArtInner, diamArtInner); 
    ellipse(0, 0, diamArtOuter, diamArtOuter);
 
    for (int i=0; i<nFrames; i++) {
      float angle = map(i, 0, nFrames, 0, TWO_PI); 
      float pxi = diamArtInner/2 * cos(angle);
      float pyi = diamArtInner/2 * sin(angle);
      float pxo = diamArtOuter/2 * cos(angle);
      float pyo = diamArtOuter/2 * sin(angle);
      stroke(128); 
      strokeWeight(0.2);
      line (pxi, pyi, pxo, pyo);
    }
 
    // Draw the red wedge outline, highlighting the main view.
    int redWedge = 7; // assuming nFrames = 10
    for (int i=redWedge; i<=(redWedge+1); i++) {
      float angle = map(i, 0, nFrames, 0, TWO_PI); 
      float pxi = diamArtInner/2 * cos(angle);
      float pyi = diamArtInner/2 * sin(angle);
      float pxo = diamArtOuter/2 * cos(angle);
      float 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);
    float startAngle = redWedge*TWO_PI/nFrames;
    float endAngle = (redWedge+1)*TWO_PI/nFrames;
    arc(0, 0, diamArtInner, diamArtInner, startAngle, endAngle); 
    arc(0, 0, diamArtOuter, diamArtOuter, startAngle, endAngle); 
 
 
    for (int i=0; i<nFrames; i++) {
      float angle = map(i, 0, nFrames, 0, TWO_PI); 
 
      pushMatrix();
      rotate(angle); 
      float 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); 
 
      popMatrix();
    }
  }
}
 
//-------------------------------------------------------
void drawAllFrames() {
  for (int i=0; i<nFrames; i++) {
    float angle = map(i, 0, nFrames, 0, TWO_PI); 
    float originY = ((diamArtOuter + diamArtInner)/2)/2;
 
    pushMatrix();
    rotate(angle); 
    translate(0, 0-originY); 
    scale(0.8, 0.8); // feel free to ditch this 
 
    int whichFrame = i; 
    if (bAnimate) {
      whichFrame = (i+myFrameCount)%nFrames;
    }
    drawArtFrame (whichFrame); 
    // drawArtFrameAlternate (whichFrame); 
 
    popMatrix();
  }
  myFrameCount++;
}
 
 
//-------------------------------------------------------
void drawArtFrame (int 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(); 
 
  // Draw a pulsating ellipse
  noFill(); 
  stroke(0);
  strokeWeight(1); 
  float t = map(whichFrame, 0, nFrames, 0, 1); 
  float diam = map(cos(t*TWO_PI), -1, 1, 25, 50); 
  ellipse(0, 0, diam, diam); 
 
  //rotating circle
  float radius = diam/2; 
  float rotatingArmAngle = (whichFrame*.1) * TWO_PI; 
  float px = 0 + radius*cos(rotatingArmAngle); 
  float py = 0 + radius*sin(rotatingArmAngle); 
  fill    (0); 
  stroke(51);
  ellipse(px, py, 8, 8);
 
  //rotating circle
  float rotatingArmAngle2 = (whichFrame*.1) * TWO_PI; 
  float px2 = 15 + radius*cos(rotatingArmAngle2); 
  float py2 = 15 + radius*sin(rotatingArmAngle2); 
  fill    (0); 
  stroke(51);
  ellipse(-px2, -py2, 8, 8);
 
  float px3 = -12 + radius*cos(rotatingArmAngle2); 
  float py3 = -20 + radius*sin(rotatingArmAngle2); 
  fill    (0); 
  stroke(51);
  ellipse(-px3, -py3, 8, 8);
 
  //rect figure
  float amplitude=100;
  float f=.1;
  float xR=160;
  float yR=(160)+amplitude*sin(f*whichFrame);
  rect(xR,yR,10,10); 
}
//-------------------------------------------------------
void drawArtFrameAlternate(int 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); 
    int nL = 10;
    for (int i=0; i<nL; i++) {
      float a = HALF_PI + map(i, 0, nL-1, 0, TWO_PI);
      float cx = 12 * cos(a);
      float cy = 10 * sin(a); 
      float dx = 16 * cos(a);
      float 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
  float t = map(whichFrame, 0, nFrames-1, 0, 1); 
  float t2 = pow(t, 2.0); 
  float rh = 8 + whichFrame * 0.5; // wee stretch
  float ry = map(t2, 0, 1, 0, 100-rh) - 50; 
 
  noStroke(); 
  fill(0, 0, 0);
  rect(-5, ry, 10, rh);
}