yalbert-Reading02

1. One example of effective complexity that I am particularly fond of is the sound of shoes walking through gravel. Initially I assumed that similar to white noise and static, this would be an example of total randomness. However, upon further thought it occurred to me that there is some order and rhythm to it because of the way a shoe distributes weight as it steps.

 

2. I relate to the problem of authenticity. This is because I often times see generative art as an opportunity to solve technical problems and get lost in these challenges as opposed to the form of expression itself. However, in the end the value I derive from such projects is the self expression, so I would say that generative art is authentic.

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);
}

 

sapeck-AnimatedLoop


1920x1920 H.264 (MP4) video version (2.8 MB)

I began this piece by mapping my pixel art from my sketchbook into a spreadsheet. This gave me a grid of 0's and 1's to create my stick figure bitmaps. I gave each row the same Generalized Blackman Window easing function but with slightly different parameters based based on Perlin noise. The differing parameters adds the "lagging" effect to the animation. The Blackman Window function starts with a slowly-ramping curve that then spikes and returns slows down. I feel that the animation is a little boring. A continuous scroll of five or so figures would be more interesting. The background gradient reminds me more of Nyan Cat than I want it to. A single-tone gradient for each row would be less eye-straining and just as appealing.

/* Sapeck    9/12/2017
"sapeck-AnimatedLoop"
Based on a template for creating a looping animation in Processing/Java by Prof. Golan Levin, January 2018
60-212                        Carnegie Mellon University
Copyright (C) 2018-present  Sapeck, Prof. Golan Levin
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*/
 
//===================================================
// Global variables. 
String  myNickname = "sapeck"; 
int     nFramesInLoop = 500;
int     nElapsedFrames;
boolean bRecording; 
 
//===================================================
void setup() {
  size (640, 640);
  noiseSeed(283092);
  colorMode(HSB, 100);
  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"+width+"/" + myNickname + "_frame_" + nf(nElapsedFrames, 4) + ".png");
    nElapsedFrames++; 
    if (nElapsedFrames >= nFramesInLoop) {
      bRecording = false;
    }
  }
}
 
int DIMENSION = 20;
int colorFilled = color(0,0,100,255);
int LOOPS = 3;
PVector easeCurveBase = new PVector(0.1, 0);
int NOISESEED = 283092;
 
void renderMyDesign (float percent) {
  background(0);
  smooth();
 
  for (int y=0;y<DIMENSION;y++) {
    pushMatrix();
    boolean right = (y % 2 == 0);
    right = false;
    int moveX = 0;
    int startRow = 0;
    PVector thisEaseCurve = new PVector(easeCurveBase.x+0.3*noise(y*10)/1, easeCurveBase.y+noise(y*10)/1);
    if (y > (DIMENSION-1)/2) thisEaseCurve = new PVector(easeCurveBase.x-0.3*noise(y*10)/1, easeCurveBase.y-noise(y*10)/1);
    float thisPercent = percent;
    thisPercent = function_GeneralizedBlackmanWindow(percent,thisEaseCurve.x);
    if (right) {
      startRow = -1*(LOOPS-1)*width;
      moveX = int(thisPercent*(LOOPS-1)*width);
    } else {
      moveX = int(-1*thisPercent*(LOOPS-1)*width);
    }
    translate(moveX ,0);
    for (int loop=0;loop<LOOPS;loop++) {
      for (int x=0;x<DIMENSION;x++) {
        int thisBox = 0;
        if (loop == LOOPS-1 && right) thisBox = MAN1[y][x];
        else if (loop == LOOPS-1 && !right) thisBox = MAN2[y][x];
        else if (loop == 0 && right) thisBox = MAN2[y][x];
        else if (loop == 0 && !right) thisBox = MAN1[y][x];
        PVector thisLoc = new PVector(x*(width/DIMENSION)+(loop*width)+startRow, y*(height/DIMENSION));
        if (thisBox == 1) {
          fill(colorFilled);
          rect(thisLoc.x, thisLoc.y, width/DIMENSION, height/DIMENSION);
        } else {
          int colorX = x+y;
          if (colorX > DIMENSION) colorX -= DIMENSION;
          fill(color(map(colorX,0,DIMENSION,0,100),
                     100,
                     100));
          rect(thisLoc.x, thisLoc.y, width/DIMENSION, height/DIMENSION);
        }
      }
    }
    popMatrix();
  }
}
 
int[][] MAN1 = {
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0},
  {0,0,0,1,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,0},
  {0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
int[][] MAN2 = {
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,1,1,1,0,0,1,1,1,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
 
 
//===================================================
// Taken from https://github.com/golanlevin/Pattern_Master
float function_GeneralizedBlackmanWindow (float x, float a) {
  // http://en.wikipedia.org/wiki/Window_function
  float a0 = (1.0 - a)/2.0;
  float a1 = 0.5;
  float a2 = a / 2.0;
 
  float pix = PI*x;
  float y = a0 - a1*cos(2*pix) + a2*cos(4*pix);
  return y;
}

Sepho – Reading02

Slime mold is a super interesting system with effective complexity. Being organic, slime mold is pretty close to being right in the middle of total order and randomness, but due to it's behavior it leans more towards order. Slime mold works by first reaching out and finding food, then by forming efficient paths to the food, creating amazing synthesized systems to get to and from resources.

 

 

I really don't think that with generative art there is a "problem of authorship." I think the "artists hand" is an interesting notion that was questioned by people like Duchamp and Pollock and I think that generative art is another way of experimenting with that concept. Its also interesting to think about separation between arts and crafts, what turns a painter into an artist or a painting into art? well what turns computer code into art? Intention? The audience? The art-world? I think that these are important concepts to ponder and generative artists explore them, but through their artwork. 

weirdie-AnimatedLoop

My initial inspiration for the piece was simply thinking about how objects could visually track movement, and because I'm me I wanted to do that in kind of a weird way. The first step was creating the eyes that would be able to track movement, initially using the mouse for testing. After that, I tried a bunch of functions to find a path for the fly that I liked, eventually picking a 3-petaled polar graph "flower" because of the way it looped around 3 of the eyes. Getting the fly to face the direction it was traveling was a little tricky, as that involved calculating the direction of the next frame of the fly and rotating it towards that. I chose the Double Exponential Ogee function because I wanted the fly to slow down slightly going around corners, and speed up when it was traveling in more of a straight line, and the Ogee function had that pattern - fast, slow, fast - and so I used that while phase-shifting it a bit. Overall, I'm pretty pleased with the result, as I came pretty close to that concept that I had in mind and I learned a lot about mapping and direction changes in the process. I initially thought about having some of the eyes blink randomly or blink in response to the fly coming too close. However, with the short length of the GIF I chose not too, but it could be something to try in the future. I also think the addition of motion blur to the fly would have made the appearance more smooth.

Sketches:

Code:

function renderMyDesign(percent) {
 
  // here, I set the background
	background(255, 147, 140);
  smooth();
 
  // coordinates of the fly
  var flyx = 0;
  var flyy = 0;
 
  var p = map(percent, 0, 1, 0, 3.14);
 
  if(percent &gt;=0 &amp;&amp; percent &lt;= 0.3333) { var frac = map(percent, 0, 0.3333, 0, 1); var speed = function_DoubleExponentialOgee(frac, 0.15); p = map(speed, 0, 1, 0, PI/3); } else if(percent &gt; 0.333 &amp;&amp; percent &lt;= 0.666)
  {
    var frac = map(percent, 0.3333, 0.666, 0, 1);
  	var speed = function_DoubleExponentialOgee(frac, 0.15);
  	p = map(speed, 0, 1, PI/3, 2*PI/3);
  }
  else
  {
    var frac = map(percent, 0.666, 1, 0, 1);
  	var speed = function_DoubleExponentialOgee(frac, 0.15);
  	p = map(speed, 0, 1, 2*PI/3, PI);
  }
 
  var r = cos(3*(p+PI/2));
  var nr = cos(3*(p+0.0157+PI/2));
 
  var jousx = map(r*cos((p+PI/3+PI/2)), -1, 1, 30, 630);
  var jousy = map(r*sin((p+PI/3+PI/2)), -1, 1, 30, 630);
  var nextx = map(nr*cos((p+0.0157 + PI/3+PI/2)), -1, 1, 30, 630);
  var nexty = map(nr*sin((p+0.0157 + PI/3+PI/2)), -1, 1, 30, 630);
 
  var jx = map(jousx, 30, 630, -1, 1);
  var jy = map(jousy, 30, 630, -1, 1);
  var nx = map(nextx, 30, 630, -1, 1);
  var ny = map(nexty, 30, 630, -1, 1);
 
  var direction = atan2((ny - jy), (nx - jx)) + PI/2.2;
 
  flyx = jousx;
  flyy = jousy;
 
  //eyeballs!!!
  noStroke();
 
  for (var r = 0; r &lt; 5; r++) {
    for (var c = 0; c &lt; 4; c++) {
      var midx = 0;
      var midy = 0;
      if (r % 2 == 0) {
        midx = 106.66 + c * 213.33;
        midy = 160 * r;
      } else {
        midx = 213.333 * c;
        midy = 160 * r
      }
 
      //direction of the fly
      var fx = map(flyx, 0, width, -1, 1);
      var fy = map(flyy, 0, height, -1, 1);
      var mx = map(midx, 0, width, -1, 1);
      var my = map(midy, 0, height, -1, 1);
      var dir = atan2((fy - my), (fx - mx));
 
      var amp = 30;
      if (dist(midx, midy, flyx, flyy) &lt;= 30)
        amp = dist(midx, midy, flyx, flyy);
 
      //white of eye
      fill(244, 244, 233);
      ellipse(midx, midy, 130, 130);
 
      push();
      translate(midx + amp * cos(dir), midy + amp * sin(dir));
      rotate(dir);
 
      //distortion value
      var d = constrain(dist(midx, midy, flyx, flyy), 0, 30);
      var squish = map(d, 0, 30, 1, 0.9);
 
      //cornea
      stroke(20, 114, 80);
      strokeWeight(3);
      fill(61, 249, 187);
      ellipse(0, 0, 70 * squish, 70);
      noStroke();
      //pupil
      fill(19, 20, 45);
      ellipse(0, 0, 30 * squish, 30);
      pop();
    }
  }
 
  push();
  fill(19, 20, 45);
 
  translate(flyx, flyy);
  rotate(direction);
  stroke(19, 20, 45);
  strokeWeight(1.5);
 
  ellipse(0, 0, 20, 30);
  ellipse(0, -15, 16, 10);
 
  line(0, 0, -17, -17);
  line(0, 0, 17, -17);
  line(-17, -17, -20, -15);
  line(17, -17, 20, -15);
 
  line(0, -10, 17, 3);
  line(0, -10, -17, 3);
  line(17, 3, 20, 6);
  line(-17, 3, -20, 6);
 
  line(0, 0, 17, 17);
  line(0, 0, -17, 17);
 
  fill(255, 89, 0);
  noStroke();
  ellipse(6, -17, 6, 8);
  ellipse(-6, -17, 6, 8);
 
  fill(160, 255, 223, 150);
  beginShape();
  vertex(0, -10);
  vertex(-15, 0);
  vertex(-15, 25);
  vertex(-4, 15);
  vertex(0, -10);
  endShape();
 
  beginShape();
  vertex(0, -10);
  vertex(15, 0);
  vertex(15, 25);
  vertex(4, 15);
  vertex(0, -10);
  endShape();
  pop();
 
} 
// Double Exponential Ogee function ('_a' is the slope)
//(it goes fast, slowwww, fast)
// See https://github.com/IDMNYU/p5.js-func/blob/master/lib/p5.func.js
// From: https://idmnyu.github.io/p5.js-func/
//===================================================
  function function_DoubleExponentialOgee (x, a){
  functionName = "Double-Exponential Ogee";
 
  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); 
 
  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;
}

airsun-AnimatedLoop

 

Overall, I am happy that this work turned out to be something similar to what I have imagined when doing the sketches. The choice of color and the overall style goes well with the theme. The idea here is about having an elevator going up and down as the eyeball of the eye. However, I do wish to spend more time on this project to increase the complexity of the gif. Currently, I feel there is something missing in the background. For more improvements, I can add more features to identify the elevator in a clearer way. For example, adding the button that controls the elevator going "up" and "down".

Brainstorm and sketch before starting the project (majority of the sketch was done in ps)

//Name: AirSun
//Sijings
//60-212
//code modified from Code Template for Looping GIFS
 
//===================================================
var myNickname = "airsun";
var nFramesInLoop = 120;
var bEnableExport = true;
var nElapsedFrames;
var bRecording;
var theCanvas;
var frames = [];
 
//===================================================
function setup() {
  theCanvas = createCanvas(640, 640);
  bRecording = false;
  nElapsedFrames = 0;
}
 
//===================================================
function keyTyped() {
  if (bEnableExport) {
    if ((key === 'f') || (key === 'F')) {
      bRecording = true;
      nElapsedFrames = 0;
    }
  }
}
 
//===================================================
function preload(){
  var filenames = [];
  filenames[0] = "https://i.imgur.com/4SUU0dP.png";
  filenames[1] = "https://i.imgur.com/ZkRe8eA.png";
  filenames[2] = "https://i.imgur.com/htCZu9X.png";
  filenames[3] = "https://i.imgur.com/oymFCPW.png";
  filenames[4] = "https://i.imgur.com/ahNh0P1.png";
  for (i=0; i&lt;filenames.length; i++){ frames.push(loadImage(filenames[i])); } } //=================================================== function draw() { var percentCompleteFraction = 0; if (bRecording) { percentCompleteFraction = float(nElapsedFrames) / float(nFramesInLoop); } else { percentCompleteFraction = float(frameCount % nFramesInLoop) / float(nFramesInLoop); } renderMyDesign (percentCompleteFraction); 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) {
  background(216,195,131);
  smooth();
  stroke(0, 0, 0);
  strokeWeight(2);
 
  //----------------------
  // Here, I assign some handy variables. 
  var cx = 100;
  var cy = 100;
 
  //----------------------
  // Here, I use trigonometry to render a rotating element.
  var radius = 80;
  var rotatingArmAngle = percent * TWO_PI;
  var px = cx + radius * cos(rotatingArmAngle);
  var py = cy + radius * sin(rotatingArmAngle);
 
 
 
  //----------------------
  // Here's a linearly-moving square
  var squareSize = 20;
  var topY = height/3 - squareSize - 2;
  var botY = height-height/3 + 2;
  var eyeL = width/10;
  var eyeR = width-width/10;
  var eyeW = 200;
 
  strokeWeight(2);
  fill(248,242,231);
  beginShape();
  noStroke();
  //upper part of the eye
  curveVertex(eyeR, topY+(botY-topY)/2);
  curveVertex(eyeR, topY+(botY-topY)/2);
  curveVertex(eyeL+(eyeR-eyeL)*2/3, topY);
  curveVertex(eyeL+(eyeR-eyeL)/3, topY);
  curveVertex(eyeL, topY+(botY-topY)/2);
  curveVertex(eyeL, topY+(botY-topY)/2);
  //lower part of the eye
  endShape();
 
  beginShape();
  curveVertex(eyeR, topY+(botY-topY)/2);
  curveVertex(eyeR, topY+(botY-topY)/2);
  curveVertex(eyeL+(eyeR-eyeL)*2/3, botY);
  curveVertex(eyeL+(eyeR-eyeL)/3, botY);
  curveVertex(eyeL, topY+(botY-topY)/2);
  curveVertex(eyeL, topY+(botY-topY)/2);
  endShape();
 
 
 
  //other facial features
  noFill();
  stroke(90,84,68);
  strokeWeight(4);
  arc(eyeL+5, topY+(botY-topY)/2, 50, 50, 7/4*PI, 1/4*PI);
 
  beginShape();
  curveVertex(100, height);
  curveVertex(170, height);
  curveVertex(60, height/2+200);
 
  curveVertex(21, height/2);
  curveVertex(65, 91);
  curveVertex(65, 91);
  endShape();
  fill(90,84,68);
  ellipse(70, height, 80, 40);
 
 
 
  //eyeballs' drawing
  var eased = DoublePolynomialSigmoid (percent, 1); 
  if (percent &lt; 0.5) {
  //eased = (eased + 0.5)%2; // shifted by a half-loop, for fun
    var yPosition2 = map(eased, 0, 1, topY-150, botY-100);
  //print(yPosition2, botY-200)
  }else{
    var yPosition2 = map(eased, 0, 1, botY-100, topY-150);
  }
 
  fill (165, 73, 59); 
  //ellipse (eyeL+(eyeR-eyeL)/2, yPosition2, eyeW, eyeW); 
  var currentY=eyeL+(eyeR-eyeL)/5-70;
  var currenyX=yPosition2-150;
  var numofF=0;
  if (frameCount % 5 == 0){
    numofF +=1;
  }
  var framesC = numofF % 5;
 
  image(frames[framesC], currentY, currenyX, 430, 700);
 
 
 
  push();
  fill(216,195,131);
  noStroke();
  rect(width/3, height-180, 400, 200);
  pop();
 
  noFill();
  stroke(216,195,131);
  strokeWeight(200);
  beginShape();
  //upper part of the eye
  curveVertex(eyeR, topY+(botY-topY)/2-125);
  curveVertex(eyeR, topY+(botY-topY)/2-140);
  curveVertex(eyeL+(eyeR-eyeL)*2/3, topY-105);
  curveVertex(eyeL+(eyeR-eyeL)/3, topY-105);
  curveVertex(eyeL, topY+(botY-topY)/2-140);
  curveVertex(eyeL, topY+(botY-topY)/2-125);
  //lower part of the eye
  endShape();
  strokeWeight(70);
  beginShape();
  curveVertex(eyeR, topY+(botY-topY)/2+50);
  curveVertex(eyeR, topY+(botY-topY)/2+50);
  curveVertex(eyeL+(eyeR-eyeL)*2/3, botY+40);
  curveVertex(eyeL+(eyeR-eyeL)/3, botY+40);
  curveVertex(eyeL, topY+(botY-topY)/2+50);
  curveVertex(eyeL, topY+(botY-topY)/2+50);
  endShape();
 
  //eyeLash
  var eyeLashAngel = 45;
  var centerx = width / 2;
  var centery = botY-90;
  var radius = 240;
  stroke(90,84,68);
  strokeWeight(4);
  for (i = 0; i &lt; 10; i++){
    var x = cos(radians(eyeLashAngel)) * radius;
    var y = sin(radians(eyeLashAngel)) * radius;
    var increasement;
    if (i &lt; 5) {
      increasement = i * 15;
    }else{
      increasement = (10 - (i+1)) * 15;}
    line(centerx + x/1.2 , centery - y/1.2, centerx + 1.2*x , centery - y - increasement);
    eyeLashAngel = eyeLashAngel+10;
  }
  centery = topY + 90;
  eyeLashAngel = 225;
  for (i = 0; i &lt; 10; i++){
    var x = cos(radians(eyeLashAngel)) * radius;
    var y = sin(radians(eyeLashAngel)) * radius;
    var increasement;
    if (i &lt; 5) {
      increasement = i * 15;
    }else{
      increasement = (10 - (i+1)) * 15;}
    line(centerx + x/1.2 , centery - y/1.2, centerx + 1.2*x, centery - y + increasement);
    eyeLashAngel = eyeLashAngel+10;
  }
}
 
//following code got from https://github.com/golanlevin/Pattern_Master
//------------------------------------------------------------------
function DoublePolynomialSigmoid (_x, _a){
  var n = _a;
  var _y = 0;
  if (n%2 == 0){ 
    // even polynomial
    if (_x&lt;=0.5){
      _y = pow(2.0*_x, n)/2.0;
    } 
    else {
      _y = 1.0 - pow(2*(_x-1.0), n)/2.0;
    }
  } 
 
  else { 
    // odd polynomial
    if (_x&lt;=0.5){
      _y = pow(2.0*_x, n)/2.0;
    } 
    else {
      _y = 1.0 + pow(2.0*(_x-1.0), n)/2.0;
    }
 
  }
 
  return (_y);
}

shuann-AnimatedLoop

Overall I am pretty satisfied with how this turned out, and it looks very close to what I had on my sketch. For the background switch I decided to use the EaseInOutElastic function after trying out a hand full of different easing functions because this one looks almost exactly like what I imagined the transition to be when I made my sketch. I believe the bounciness really suites the style of the visuals that I created here and defiantly adds to the overall quality of the piece. The hardest part about this assignment was defiantly the fact that I had to think and calculate everything based on the percentage frame rate. It was not so easy to wrap my head around that and when I ran into a glitch I have to really sit down and think about where the problem is. Did I lose count on the frame somewhere or was it something else. For example this one:

I also wish that I can spend more time to make the movement of the boat more natural. Maybe with some tilt at appropriate time.s

My Sketch:

The Code:

// 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 = "shuann";
var nFramesInLoop = 120;
var bEnableExport = true;
var myScale = 0.006;
var myLoopingNoiseArray0 = [];
var myLoopingNoiseArray1 = [];
var myLoopingNoiseArray2 = [];
var myLoopingNoiseArray3 = [];
var myLoopingNoiseArray4 = [];
var myLoopingNoiseArray5 = [];
var myLoopingNoiseArray6 = [];
var myLoopingNoiseArray7 = [];
var myLoopingNoiseArray8 = [];
var myLoopingNoiseArray9 = [];
 
// 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;
 
  var radius = 60;
  noiseSeed(40);
  //waves at the bottom
  //sorry the style is horrible
  for (var i = 0; i < nFramesInLoop; i++){
    var rotatingArmAngle = map(i, 0 ,120, 0, TWO_PI);
    var px = width/2 + radius * cos(rotatingArmAngle);
    var py = height/2 + radius * sin(rotatingArmAngle);
    var noiseAtLoc0 = height - 50 * noise(myScale * px, myScale * py);
    var noiseAtLoc1 = height - 80 * noise(myScale * px, myScale * py);
    var noiseAtLoc2 = height - 150 * noise(myScale * px, myScale * py);
    var noiseAtLoc3 = height - 200 * noise(myScale * px, myScale * py);
    var noiseAtLoc4 = height - 300 * noise(myScale * px, myScale * py);
    myLoopingNoiseArray0[i] = round(noiseAtLoc0);
    myLoopingNoiseArray1[i] = round(noiseAtLoc1);
    myLoopingNoiseArray2[i] = round(noiseAtLoc2);
    myLoopingNoiseArray3[i] = round(noiseAtLoc3);
    myLoopingNoiseArray4[i] = round(noiseAtLoc4);
 
    var px1 = width/2 + radius * 0.7 * cos(rotatingArmAngle);
    var py1 = height/2 + radius * 0.7 * sin(rotatingArmAngle);
    var noiseAtLoc5 = height - 60 * noise(myScale * px1, myScale * py1);
    var noiseAtLoc6 = height - 130 * noise(myScale * px1, myScale * py1);
    var noiseAtLoc7 = height - 230 * noise(myScale * px1, myScale * py1);
    var noiseAtLoc8 = height - 330 * noise(myScale * px1, myScale * py1);
    var noiseAtLoc9 = height - 450 * noise(myScale * px1, myScale * py1);
    myLoopingNoiseArray5[i] = round(noiseAtLoc5);
    myLoopingNoiseArray6[i] = round(noiseAtLoc6);
    myLoopingNoiseArray7[i] = round(noiseAtLoc7);
    myLoopingNoiseArray8[i] = round(noiseAtLoc8);
    myLoopingNoiseArray9[i] = round(noiseAtLoc9);
  }
 
}
 
 
//===================================================
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 && bEnableExport) {
    var frameOutputFilename = myNickname + "_frame_" + nf(nElapsedFrames, 4) + ".png";
    print("Saving output image: " + frameOutputFilename);
    saveCanvas(theCanvas, frameOutputFilename, 'png');
    nElapsedFrames++;
 
    if (nElapsedFrames >= 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!
 
  //----------------------
  smooth();
  var cx = 100;
  var cy = 100;
 
  push();
  translate(width/2, height/2);
 
  if (percent < 0.5){
    var ang = function_PennerEaseInOutElastic(percent*2)*180;
    rotate(radians(ang));
    drawbackdrop(percent);
  } else {
    var ang = function_PennerEaseInOutElastic(map(percent, 0.5, 1, 0, 1))*180;
    rotate(radians(ang) + TWO_PI/2);
    drawbackdrop(percent);
  }
 
  drawbackdrop(percent);
  pop();
 
 
  noStroke();
  push();
  translate(0, -100);
  drawboat(percent,-0.1);
  drawWave(percent, 88, 176, 230, myLoopingNoiseArray9, -0.1);
  drawWave(percent, 80, 160, 210, myLoopingNoiseArray8, 0);
  drawWave(percent, 22, 132, 200, myLoopingNoiseArray7, 0.6);
  drawWave(percent, 49, 80, 152, myLoopingNoiseArray6, 0.8);
  drawWave(percent, 54, 100, 160, myLoopingNoiseArray5, 0.8);
  pop();
  drawWave(percent, 45, 183, 212, myLoopingNoiseArray4, -0.2);
  drawWave(percent, 45, 167, 212, myLoopingNoiseArray3, -0.2);
  drawWave(percent, 65, 130, 190, myLoopingNoiseArray2, -0.2);
  drawWave(percent, 54, 100, 160, myLoopingNoiseArray1, 0.5);
  drawWave(percent, 49, 80, 152, myLoopingNoiseArray0, 0.5);
}
 
function drawbackdrop(p){
  fill(235,219,190);
  rect(-width, -height, width*3, height);
  fill(18,24,56);
  rect(-width, 0, width*3, height);
 
  //draw sun
  push();
  strokeWeight(3);
  stroke(235,172, 45);
  fill(235,172, 45);
  ellipse(200, -200, 50, 50);
  translate(200, -200);
  rotate(0.2 * p * TWO_PI);
  push();
  for (var a = 0; a < 10; a++){
    rotate(TWO_PI/10);
    line (50, 0, 70, 0);
  }
  pop();
  pop();
 
  //draw moon
  push();
  noStroke();
  fill(255);
  translate(-200, 200);
  ellipse(0, 0, 80, 80);
  fill(18,24,56);
  ellipse(-20, -10, 50, 50);
  pop();
 
  //draw star
  push();
  translate(-100, 110);
  noStroke();
  fill(255);
  star(0, 0, 5, 10, 5); 
  star(50, 110, 5, 10, 5); 
  star(80, 90, 3, 6, 5); 
  star(100, 105, 3, 6, 5); 
  pop();
 
}
 
function drawboat(p, tilt){
  currStep = round(p * nFramesInLoop);
  var nx = map(40, 0, nFramesInLoop, 0, width);
  var ny = myLoopingNoiseArray9[(currStep+40)%nFramesInLoop]
  // var newy = doubleExponentialSigmoid(map(y, 315, 370, 0, 1), 0.7);//does not look good
  // var y = map(newy, 0, 1, 315, 370);
  fill(255);
  beginShape();
  vertex(nx - 50, ny - 10);
  vertex(nx + 50, ny - 10);
  vertex(nx + 30, ny + 20);
  vertex(nx - 30, ny + 20);
  endShape();
  stroke(255);
  line(nx, ny, nx, ny - 50);
  triangle(nx, ny - 50, nx + 20, ny - 40, nx, ny - 30);
}
 
function drawWave(p, r, g, b, wave, tilt){
  currStep = round(p * nFramesInLoop);
  fill(r, g, b);
  noStroke();
  beginShape();
  vertex(0,height+50);
  for (var i = 0; i < wave.length; i++) {
    var nx = map(i, 0, nFramesInLoop - 1, 0, width);
    if (i + currStep >= nFramesInLoop) {
      var ny = wave[(i + currStep)-nFramesInLoop] - i*tilt;
    } else {
      var ny = wave[i + currStep] - i*tilt;
    }
    vertex(nx, ny);
  }
  vertex(width,height+50);
  endShape();
}
 
 
// symmetric double-element sigmoid function (a is 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<=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);
}
 
//From: https://github.com/golanlevin/Pattern_Master/blob/master/pattern_master/F00.pde
//------------------------------------------------------------------
function function_PennerEaseInOutElastic (t) {
 
  if (t===0) return 0; 
  if ((t/=0.5)==2) return 1;
  var p=(.3 * 1.5);
  var a=1;
  var s=p/4;
 
  if (t < 1) {
    var postFix = pow(2, 10*(t-=1)); // postIncrement is evil
    return -0.5 * (postFix* sin( (t-s)*(2*PI)/p ));
  } 
 
  var postFix = pow(2, -10*(t-=1)); // postIncrement is evil
  return postFix * sin( (t-s)*(2*PI)/p )*.5 + 1;
}
 
//From: https://p5js.org/examples/form-star.html
//------------------------------------------------------------------
function star(x, y, radius1, radius2, npoints) {
  var angle = TWO_PI / npoints;
  var halfAngle = angle/2.0;
  beginShape();
  for (var a = 0; a < TWO_PI; a += angle) {
    var sx = x + cos(a) * radius2;
    var sy = y + sin(a) * radius2;
    vertex(sx, sy);
    sx = x + cos(a+halfAngle) * radius1;
    sy = y + sin(a+halfAngle) * radius1;
    vertex(sx, sy);
  }
  endShape(CLOSE);
}

.
 

harsh-Scope

praxinoscope-output

Here's an interpolation between Batman and a Coorgi - I'm not sure there's much else to say beyond that I would like to improve the interpolation between these two beings in the near future.

 
 
 
double[][] points = {
 
  {86.920948, -23.249132}, 
 
  {86.664672, -24.823893}, 
 
  {86.175996, -26.342519}, 
 
  {85.463499, -27.769999}, 
 
  {84.557778, -29.083769}, 
 
  {83.499422, -30.278466}, 
 
  {82.332896, -31.368541}, 
 
  {81.149804, -32.441065}, 
 
  {79.973249, -33.520753}, 
 
  {78.804825, -34.609233}, 
 
  {77.646171, -35.708105}, 
 
  {76.498983, -36.818939}, 
 
  {75.365020, -37.943267}, 
 
  {74.246116, -39.082578}, 
 
  {73.144184, -40.238308}, 
 
  {72.061223, -41.411829}, 
 
  {70.972337, -42.579390}, 
 
  {69.761074, -43.618243}, 
 
  {68.418840, -44.480833}, 
 
  {66.966098, -45.140455}, 
 
  {65.435219, -45.590573}, 
 
  {63.859903, -45.846697}, 
 
  {62.266241, -45.938590}, 
 
  {60.670160, -45.900258}, 
 
  {59.079093, -45.765953}, 
 
  {57.495346, -45.562513}, 
 
  {55.921415, -45.293435}, 
 
  {54.359616, -44.961068}, 
 
  {52.811914, -44.568224}, 
 
  {51.279888, -44.118075}, 
 
  {49.764723, -43.614049}, 
 
  {48.267215, -43.059734}, 
 
  {46.787793, -42.458789}, 
 
  {45.326554, -41.814870}, 
 
  {43.883302, -41.131573}, 
 
  {42.455647, -40.416190}, 
 
  {41.029901, -39.696975}, 
 
  {39.603639, -38.978787}, 
 
  {38.177011, -38.261328}, 
 
  {36.750165, -37.544299}, 
 
  {35.323253, -36.827402}, 
 
  {33.896425, -36.110339}, 
 
  {32.469830, -35.392812}, 
 
  {31.043618, -34.674523}, 
 
  {29.617942, -33.955174}, 
 
  {28.192952, -33.234467}, 
 
  {26.768798, -32.512105}, 
 
  {25.345168, -31.788715}, 
 
  {23.953224, -31.009128}, 
 
  {22.902710, -29.831666}, 
 
  {22.680213, -28.269473}, 
 
  {23.119263, -26.745011}, 
 
  {24.109144, -25.503345}, 
 
  {25.432246, -24.616583}, 
 
  {26.880274, -23.943827}, 
 
  {28.355004, -23.331482}, 
 
  {29.844053, -22.754683}, 
 
  {31.337536, -22.189417}, 
 
  {32.829143, -21.619219}, 
 
  {34.321058, -21.049826}, 
 
  {35.813617, -20.482123}, 
 
  {37.307001, -19.916596}, 
 
  {38.801390, -19.353730}, 
 
  {40.296962, -18.794014}, 
 
  {41.793891, -18.237937}, 
 
  {43.292349, -17.685990}, 
 
  {44.792498, -17.138667}, 
 
  {46.294506, -16.596460}, 
 
  {47.798529, -16.059869}, 
 
  {49.304718, -15.529390}, 
 
  {50.813220, -15.005525}, 
 
  {52.324176, -14.488776}, 
 
  {53.837714, -13.979648}, 
 
  {55.353963, -13.478649}, 
 
  {56.873039, -12.986285}, 
 
  {58.395047, -12.503068}, 
 
  {59.920088, -12.029507}, 
 
  {61.448249, -11.566115}, 
 
  {62.979608, -11.113404}, 
 
  {64.514231, -10.671886}, 
 
  {66.052173, -10.242072}, 
 
  {67.593476, -9.824473}, 
 
  {69.138972, -9.422747}, 
 
  {70.696441, -9.070563}, 
 
  {72.264665, -8.769725}, 
 
  {73.840441, -8.511216}, 
 
  {75.421355, -8.286148}, 
 
  {77.010010, -8.129169}, 
 
  {78.605791, -8.140331}, 
 
  {80.180613, -8.391741}, 
 
  {81.669897, -8.958155}, 
 
  {82.980798, -9.863096}, 
 
  {84.054231, -11.041537}, 
 
  {84.902440, -12.392737}, 
 
  {85.573674, -13.840886}, 
 
  {86.109564, -15.344604}, 
 
  {86.500435, -16.892308}, 
 
  {86.756509, -18.468101}, 
 
  {86.900946, -20.058175}, 
 
  {86.960155, -21.653820}, 
 
  {-92.890651, -19.904734}, 
 
  {-92.758800, -18.310670}, 
 
  {-92.471637, -16.737408}, 
 
  {-92.016404, -15.204235}, 
 
  {-91.449681, -13.708261}, 
 
  {-90.762578, -12.264018}, 
 
  {-89.904046, -10.915597}, 
 
  {-88.818938, -9.743826}, 
 
  {-87.491318, -8.858478}, 
 
  {-85.987059, -8.323836}, 
 
  {-84.404541, -8.101408}, 
 
  {-82.805413, -8.104900}, 
 
  {-81.213356, -8.260255}, 
 
  {-79.633312, -8.511646}, 
 
  {-78.059562, -8.800258}, 
 
  {-76.491277, -9.117235}, 
 
  {-74.928640, -9.460988}, 
 
  {-73.371745, -9.829889}, 
 
  {-71.820604, -10.222284}, 
 
  {-70.275145, -10.636502}, 
 
  {-68.735225, -11.070864}, 
 
  {-67.200631, -11.523689}, 
 
  {-65.671088, -11.993299}, 
 
  {-64.146266, -12.478025}, 
 
  {-62.625786, -12.976208}, 
 
  {-61.109226, -13.486201}, 
 
  {-59.596125, -14.006370}, 
 
  {-58.085991, -14.535094}, 
 
  {-56.578306, -15.070764}, 
 
  {-55.072531, -15.611780}, 
 
  {-53.568110, -16.156552}, 
 
  {-52.064477, -16.703494}, 
 
  {-50.561059, -17.251026}, 
 
  {-49.057280, -17.797568}, 
 
  {-47.552568, -18.341535}, 
 
  {-46.046930, -18.882933}, 
 
  {-44.543998, -19.431792}, 
 
  {-43.044152, -19.989031}, 
 
  {-41.546932, -20.553289}, 
 
  {-40.051859, -21.123215}, 
 
  {-38.558441, -21.697462}, 
 
  {-37.066172, -22.274690}, 
 
  {-35.574540, -22.853560}, 
 
  {-34.083026, -23.432738}, 
 
  {-32.602190, -24.038181}, 
 
  {-31.188586, -24.784709}, 
 
  {-29.920084, -25.757031}, 
 
  {-28.873428, -26.961008}, 
 
  {-28.366090, -28.458148}, 
 
  {-28.837907, -29.958080}, 
 
  {-29.979152, -31.068115}, 
 
  {-31.364692, -31.864293}, 
 
  {-32.799297, -32.572786}, 
 
  {-34.229666, -33.289793}, 
 
  {-35.656745, -34.013328}, 
 
  {-37.081507, -34.741413}, 
 
  {-38.504946, -35.472085}, 
 
  {-39.928063, -36.203384}, 
 
  {-41.351862, -36.933352}, 
 
  {-42.777344, -37.660029}, 
 
  {-44.205493, -38.381447}, 
 
  {-45.637276, -39.095625}, 
 
  {-47.073627, -39.800568}, 
 
  {-48.515442, -40.494263}, 
 
  {-49.963570, -41.174676}, 
 
  {-51.418802, -41.839756}, 
 
  {-52.881861, -42.487433}, 
 
  {-54.353390, -43.115622}, 
 
  {-55.843187, -43.698704}, 
 
  {-57.360900, -44.204745}, 
 
  {-58.901183, -44.637333}, 
 
  {-60.459110, -45.001394}, 
 
  {-62.030409, -45.302675}, 
 
  {-63.611515, -45.547465}, 
 
  {-65.199561, -45.742361}, 
 
  {-66.792327, -45.894092}, 
 
  {-68.389148, -45.989422}, 
 
  {-69.986322, -45.913703}, 
 
  {-71.558823, -45.625548}, 
 
  {-73.072593, -45.111904}, 
 
  {-74.494369, -44.381058}, 
 
  {-75.801778, -43.460694}, 
 
  {-76.987623, -42.387789}, 
 
  {-78.090404, -41.228551}, 
 
  {-79.204089, -40.079757}, 
 
  {-80.332115, -38.945038}, 
 
  {-81.472894, -37.823139}, 
 
  {-82.624892, -36.712761}, 
 
  {-83.786625, -35.612569}, 
 
  {-84.956653, -34.521201}, 
 
  {-86.133574, -33.437269}, 
 
  {-87.316018, -32.359364}, 
 
  {-88.502641, -31.286059}, 
 
  {-89.662006, -30.183974}, 
 
  {-90.710170, -28.976114}, 
 
  {-91.607478, -27.652752}, 
 
  {-92.309427, -26.216646}, 
 
  {-92.772766, -24.687142}, 
 
  {-92.970204, -23.101314}, 
 
  {-92.902345, -21.504445}, 
 
  {-129.502091, 180.180550}, 
 
  {-129.507482, 164.442770}, 
 
  {-129.513007, 148.705005}, 
 
  {-129.518513, 132.967252}, 
 
  {-129.523847, 117.229485}, 
 
  {-129.528855, 101.491718}, 
 
  {-129.533384, 85.753951}, 
 
  {-129.537280, 70.016183}, 
 
  {-129.540391, 54.278430}, 
 
  {-129.542563, 38.540675}, 
 
  {-129.543643, 22.802917}, 
 
  {-129.543478, 7.065147}, 
 
  {-129.541914, -8.672636}, 
 
  {-129.510250, -24.410276}, 
 
  {-128.922206, -40.135459}, 
 
  {-127.518102, -55.808502}, 
 
  {-125.221334, -71.375413}, 
 
  {-121.966708, -86.770227}, 
 
  {-117.706449, -101.917288}, 
 
  {-112.464760, -116.753698}, 
 
  {-106.223176, -131.197025}, 
 
  {-98.879381, -145.111265}, 
 
  {-90.364763, -158.340456}, 
 
  {-80.660813, -170.722832}, 
 
  {-69.780142, -182.082796}, 
 
  {-57.521073, -191.926997}, 
 
  {-58.772610, -185.584243}, 
 
  {-67.867493, -172.742816}, 
 
  {-76.128119, -159.351540}, 
 
  {-83.232804, -145.315234}, 
 
  {-88.701519, -130.574089}, 
 
  {-91.396571, -115.096454}, 
 
  {-90.763584, -99.402505}, 
 
  {-80.036844, -92.128944}, 
 
  {-64.313423, -91.457100}, 
 
  {-48.591017, -90.761965}, 
 
  {-32.870304, -90.029598}, 
 
  {-18.688792, -95.010335}, 
 
  {-6.490756, -104.952791}, 
 
  {7.097693, -99.136269}, 
 
  {20.286833, -90.562913}, 
 
  {35.920805, -89.863825}, 
 
  {51.657024, -90.078996}, 
 
  {67.389870, -90.469174}, 
 
  {82.866490, -91.885923}, 
 
  {83.592484, -107.469820}, 
 
  {82.098356, -123.128586}, 
 
  {78.826175, -138.512956}, 
 
  {73.710584, -153.385459}, 
 
  {66.795536, -167.511537}, 
 
  {58.231384, -180.704310}, 
 
  {48.064174, -192.693474}, 
 
  {56.484543, -188.494910}, 
 
  {68.265753, -178.083644}, 
 
  {78.744886, -166.351783}, 
 
  {88.011195, -153.638207}, 
 
  {96.142146, -140.168805}, 
 
  {103.159462, -126.086670}, 
 
  {109.081474, -111.509484}, 
 
  {113.961065, -96.550422}, 
 
  {117.876295, -81.309913}, 
 
  {120.822162, -65.853597}, 
 
  {122.772684, -50.239291}, 
 
  {123.930784, -34.545743}, 
 
  {124.381162, -18.815322}, 
 
  {124.415292, -3.077775}, 
 
  {124.363530, 12.659900}, 
 
  {124.556184, 28.396048}, 
 
  {124.916964, 44.129654}, 
 
  {125.200108, 59.864862}, 
 
  {125.426946, 75.600990}, 
 
  {125.618815, 91.337587}, 
 
  {125.797050, 107.074340}, 
 
  {125.982987, 122.811015}, 
 
  {126.142263, 138.547961}, 
 
  {126.306783, 154.284848}, 
 
  {126.637997, 170.018978}, 
 
  {126.998187, 185.752555}, 
 
  {123.113824, 192.106662}, 
 
  {113.081976, 179.980683}, 
 
  {103.050481, 167.854411}, 
 
  {93.021684, 155.725898}, 
 
  {82.992929, 143.597374}, 
 
  {72.969703, 131.464277}, 
 
  {63.030681, 119.262190}, 
 
  {49.152882, 121.381742}, 
 
  {34.321587, 126.606509}, 
 
  {18.920668, 129.793153}, 
 
  {3.251805, 131.194827}, 
 
  {-12.476601, 130.991172}, 
 
  {-28.067009, 128.918767}, 
 
  {-43.284620, 124.948457}, 
 
  {-57.811610, 118.931459}, 
 
  {-69.911034, 123.154878}, 
 
  {-79.780560, 135.413353}, 
 
  {-89.653501, 147.669061}, 
 
  {-99.526905, 159.924395}, 
 
  {-119.263262, 184.443480}, 
 
  {-129.361095, 195.914930}, 
 
  {-109.397811, 172.181740}
};
 
double[][] points2 =
  {
 
 
  {23.808966, -113.235216}, 
 
  {16.635916, -112.718379}, 
 
  {10.350569, -109.414393}, 
 
  {9.787917, -102.591103}, 
 
  {14.697923, -97.775923}, 
 
  {21.683358, -96.093647}, 
 
  {27.760598, -92.266242}, 
 
  {32.959011, -87.276243}, 
 
  {38.112019, -82.237850}, 
 
  {40.135701, -76.239025}, 
 
  {33.162074, -76.496060}, 
 
  {25.971810, -76.250705}, 
 
  {19.412552, -73.533725}, 
 
  {19.375470, -66.845310}, 
 
  {25.648075, -63.928877}, 
 
  {32.458588, -65.927568}, 
 
  {37.550441, -70.980427}, 
 
  {43.095733, -68.889276}, 
 
  {43.306455, -61.722080}, 
 
  {42.182402, -54.609678}, 
 
  {39.647631, -47.879381}, 
 
  {35.368905, -42.113381}, 
 
  {29.496984, -37.982276}, 
 
  {22.694314, -35.651093}, 
 
  {15.572475, -34.549303}, 
 
  {8.381446, -34.068737}, 
 
  {1.175449, -34.196535}, 
 
  {-5.995360, -34.920180}, 
 
  {-13.004710, -36.533705}, 
 
  {-19.331836, -39.942841}, 
 
  {-24.559522, -44.878857}, 
 
  {-28.394366, -50.961248}, 
 
  {-30.564968, -57.814209}, 
 
  {-30.806298, -64.995263}, 
 
  {-28.179931, -71.428779}, 
 
  {-22.504746, -68.424416}, 
 
  {-16.557793, -64.484394}, 
 
  {-9.470728, -64.501048}, 
 
  {-5.402746, -69.961212}, 
 
  {-9.237203, -75.334086}, 
 
  {-16.316738, -76.556345}, 
 
  {-23.509609, -76.213244}, 
 
  {-27.774878, -79.315776}, 
 
  {-22.801899, -84.446119}, 
 
  {-17.794330, -89.632110}, 
 
  {-12.273657, -94.247705}, 
 
  {-5.656351, -96.997920}, 
 
  {1.022123, -99.393558}, 
 
  {3.565160, -105.911456}, 
 
  {0.115215, -111.654576}, 
 
  {-6.944447, -113.001965}, 
 
  {-14.150145, -112.991888}, 
 
  {-15.991661, -115.214339}, 
 
  {-9.821899, -118.885535}, 
 
  {-2.922179, -120.935067}, 
 
  {4.229913, -121.784446}, 
 
  {11.430442, -121.590557}, 
 
  {18.519665, -120.324183}, 
 
  {25.245947, -117.769912}, 
 
  {31.006976, -113.495662}, 
 
  {61.769050, 0.148968}, 
 
  {60.506181, 0.298494}, 
 
  {59.258436, 0.543902}, 
 
  {58.034888, 0.890169}, 
 
  {56.846253, 1.341809}, 
 
  {55.705058, 1.902470}, 
 
  {54.625694, 2.574379}, 
 
  {53.624268, 3.357601}, 
 
  {52.718089, 4.249192}, 
 
  {51.924670, 5.242375}, 
 
  {51.260217, 6.326028}, 
 
  {50.737782, 7.484829}, 
 
  {50.365561, 8.700256}, 
 
  {50.145883, 9.952332}, 
 
  {50.075800, 11.221653}, 
 
  {50.169674, 12.489172}, 
 
  {50.434694, 13.732246}, 
 
  {50.862390, 14.929202}, 
 
  {51.439025, 16.062047}, 
 
  {52.148122, 17.117157}, 
 
  {52.972582, 18.084914}, 
 
  {53.896019, 18.958830}, 
 
  {54.903377, 19.734612}, 
 
  {55.981057, 20.409391}, 
 
  {57.116769, 20.981199}, 
 
  {58.299291, 21.448653}, 
 
  {59.518206, 21.810823}, 
 
  {60.763684, 22.067221}, 
 
  {62.026337, 22.217873}, 
 
  {63.297142, 22.263428}, 
 
  {64.567284, 22.202720}, 
 
  {65.827524, 22.033238}, 
 
  {67.068329, 21.755193}, 
 
  {68.279977, 21.369465}, 
 
  {69.452469, 20.877424}, 
 
  {70.575344, 20.280821}, 
 
  {71.637431, 19.581767}, 
 
  {72.626547, 18.782862}, 
 
  {73.529207, 17.887506}, 
 
  {74.330452, 16.900448}, 
 
  {75.013948, 15.828582}, 
 
  {75.562596, 14.681929}, 
 
  {75.959913, 13.474561}, 
 
  {76.192239, 12.224980}, 
 
  {76.252197, 10.955376}, 
 
  {76.155592, 9.687826}, 
 
  {75.905593, 8.441491}, 
 
  {75.501295, 7.236374}, 
 
  {74.947676, 6.092139}, 
 
  {74.255056, 5.026245}, 
 
  {73.437704, 4.052627}, 
 
  {72.512110, 3.181166}, 
 
  {71.495388, 2.417865}, 
 
  {70.404110, 1.765454}, 
 
  {69.253608, 1.224131}, 
 
  {68.057651, 0.792256}, 
 
  {66.828379, 0.466920}, 
 
  {65.576369, 0.244373}, 
 
  {64.310760, 0.120322}, 
 
  {63.039413, 0.090151}, 
 
  {23.145407, -16.569632}, 
 
  {31.407213, -22.473820}, 
 
  {39.364234, -28.808981}, 
 
  {46.229010, -36.313033}, 
 
  {51.846433, -44.792493}, 
 
  {56.216224, -53.980719}, 
 
  {59.670030, -63.554621}, 
 
  {62.255874, -73.398170}, 
 
  {64.431294, -83.314028}, 
 
  {73.583158, -84.001785}, 
 
  {82.405532, -79.001163}, 
 
  {89.120694, -71.413967}, 
 
  {93.196416, -62.118915}, 
 
  {95.246725, -52.156101}, 
 
  {95.989943, -42.007343}, 
 
  {95.838591, -31.829269}, 
 
  {95.231246, -21.666633}, 
 
  {98.822119, -12.569717}, 
 
  {105.572084, -4.960520}, 
 
  {113.730059, 1.081138}, 
 
  {122.570998, 6.031498}, 
 
  {127.963270, 14.533056}, 
 
  {129.967263, 24.488706}, 
 
  {129.978649, 34.660827}, 
 
  {136.481603, 40.896205}, 
 
  {145.954738, 44.575234}, 
 
  {154.409211, 50.210262}, 
 
  {161.481541, 57.509949}, 
 
  {167.108658, 65.980932}, 
 
  {171.581032, 75.123461}, 
 
  {175.353007, 84.577760}, 
 
  {178.487040, 94.262667}, 
 
  {181.043772, 104.116137}, 
 
  {183.046785, 114.095927}, 
 
  {181.275910, 123.614825}, 
 
  {171.317668, 124.193373}, 
 
  {161.295997, 122.400646}, 
 
  {151.331419, 120.314525}, 
 
  {141.449706, 117.866719}, 
 
  {131.685071, 114.988121}, 
 
  {122.080674, 111.614143}, 
 
  {112.688536, 107.688677}, 
 
  {103.567770, 103.169047}, 
 
  {94.724927, 98.125753}, 
 
  {86.179872, 92.593630}, 
 
  {78.010688, 86.520949}, 
 
  {70.303655, 79.872219}, 
 
  {63.147133, 72.634804}, 
 
  {55.084571, 66.560119}, 
 
  {45.106691, 66.299406}, 
 
  {35.222399, 68.505619}, 
 
  {25.098334, 67.633681}, 
 
  {16.411610, 62.855009}, 
 
  {13.323250, 53.275827}, 
 
  {13.293436, 43.111661}, 
 
  {14.657844, 33.024943}, 
 
  {16.483712, 23.009311}, 
 
  {18.393108, 13.008972}, 
 
  {19.988524, 2.954796}, 
 
  {20.893476, -7.182849}, 
 
  {-49.122441, 22.217810}, 
 
  {-47.860844, 22.067039}, 
 
  {-46.616729, 21.809128}, 
 
  {-45.399560, 21.444695}, 
 
  {-44.219091, 20.974835}, 
 
  {-43.085543, 20.401000}, 
 
  {-42.009847, 19.724966}, 
 
  {-41.003955, 18.948939}, 
 
  {-40.081149, 18.075825}, 
 
  {-39.256276, 17.109749}, 
 
  {-38.545743, 16.056828}, 
 
  {-37.967042, 14.926184}, 
 
  {-37.537513, 13.730982}, 
 
  {-37.272200, 12.489043}, 
 
  {-37.181056, 11.222393}, 
 
  {-37.259653, 9.954679}, 
 
  {-37.494533, 8.706459}, 
 
  {-37.884483, 7.497691}, 
 
  {-38.423085, 6.347414}, 
 
  {-39.099191, 5.272134}, 
 
  {-39.898479, 4.284898}, 
 
  {-40.805077, 3.395099}, 
 
  {-41.802878, 2.608830}, 
 
  {-42.876407, 1.929487}, 
 
  {-44.011289, 1.358393}, 
 
  {-45.194422, 0.895340}, 
 
  {-46.413987, 0.538990}, 
 
  {-47.659374, 0.287159}, 
 
  {-48.921096, 0.137011}, 
 
  {-50.190692, 0.085191}, 
 
  {-51.460735, 0.125786}, 
 
  {-52.724424, 0.258709}, 
 
  {-53.974083, 0.488573}, 
 
  {-55.200754, 0.819717}, 
 
  {-56.394032, 1.256000}, 
 
  {-57.541913, 1.800499}, 
 
  {-58.630707, 2.455079}, 
 
  {-59.645082, 3.219809}, 
 
  {-60.568363, 4.092235}, 
 
  {-61.383234, 5.066596}, 
 
  {-62.072924, 6.133165}, 
 
  {-62.622859, 7.278032}, 
 
  {-63.022482, 8.483619}, 
 
  {-63.266719, 9.730044}, 
 
  {-63.356550, 10.997059}, 
 
  {-63.291323, 12.265438}, 
 
  {-63.058264, 13.513884}, 
 
  {-62.662688, 14.720765}, 
 
  {-62.116354, 15.867389}, 
 
  {-61.434461, 16.939049}, 
 
  {-60.633519, 17.925015}, 
 
  {-59.729842, 18.817866}, 
 
  {-58.738729, 19.612637}, 
 
  {-57.674177, 20.306042}, 
 
  {-56.548906, 20.895909}, 
 
  {-55.374547, 21.380809}, 
 
  {-54.161861, 21.759882}, 
 
  {-52.920944, 22.032778}, 
 
  {-51.661371, 22.199695}, 
 
  {-50.392274, 22.261463}, 
 
  {-170.029712, 112.646242}, 
 
  {-167.878571, 102.750798}, 
 
  {-165.143284, 92.955007}, 
 
  {-161.988301, 83.287202}, 
 
  {-158.180015, 73.859166}, 
 
  {-153.539639, 64.812700}, 
 
  {-147.950196, 56.325429}, 
 
  {-140.854960, 49.074473}, 
 
  {-131.949641, 44.267443}, 
 
  {-122.617962, 40.342771}, 
 
  {-117.143744, 32.074879}, 
 
  {-116.810525, 21.942561}, 
 
  {-114.676831, 12.084432}, 
 
  {-107.922918, 4.673181}, 
 
  {-98.968563, -0.122670}, 
 
  {-91.171855, -6.627108}, 
 
  {-84.514767, -14.307625}, 
 
  {-82.460242, -24.008103}, 
 
  {-83.069300, -34.160061}, 
 
  {-83.062854, -44.328172}, 
 
  {-82.026737, -54.439867}, 
 
  {-79.569790, -64.296816}, 
 
  {-74.918582, -73.302787}, 
 
  {-67.681553, -80.378620}, 
 
  {-58.552911, -84.779207}, 
 
  {-50.814140, -81.202803}, 
 
  {-48.842995, -71.226384}, 
 
  {-46.140336, -61.424398}, 
 
  {-42.508198, -51.929298}, 
 
  {-37.795316, -42.923865}, 
 
  {-31.915224, -34.635452}, 
 
  {-24.893712, -27.289902}, 
 
  {-16.877927, -21.043334}, 
 
  {-8.837724, -14.968966}, 
 
  {-7.823433, -5.007337}, 
 
  {-6.894073, 5.115414}, 
 
  {-5.125987, 15.130290}, 
 
  {-3.157561, 25.108817}, 
 
  {-1.402295, 35.127041}, 
 
  {-0.208894, 45.222097}, 
 
  {-0.773757, 55.354816}, 
 
  {-4.757859, 64.499935}, 
 
  {-14.198983, 67.964996}, 
 
  {-24.335335, 68.166945}, 
 
  {-34.271283, 66.056079}, 
 
  {-44.001896, 67.288219}, 
 
  {-51.438635, 74.213193}, 
 
  {-58.878796, 81.147278}, 
 
  {-66.638185, 87.720472}, 
 
  {-74.825785, 93.751064}, 
 
  {-83.411227, 99.200610}, 
 
  {-92.339443, 104.068714}, 
 
  {-101.553467, 108.371995}, 
 
  {-110.998679, 112.141585}, 
 
  {-120.625822, 115.419562}, 
 
  {-130.392640, 118.255225}, 
 
  {-140.264313, 120.701829}, 
 
  {-160.228011, 124.577380}, 
 
  {-170.029712, 122.817151}, 
 
  {-150.213054, 122.814114}
 
};
 
 
 
 
// 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 Processing 3.3.6 * http://processing.org
// 23 January 2018 * Golan Levin 
 
// See information about Processing PDF export at: 
// https://processing.org/reference/libraries/pdf/index.html
// PDF generated by Processing can be opened in Adobe Illustrator.
import processing.pdf.*;
boolean bRecordingPDF = false;
 
float inch = 72; 
float 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;
 
 
 
 
//////////////////////////////////////////////////////////
 
int lenPoints = points2.length;
 
double[][] scaledPoints = new double [lenPoints][2];
 
double[][] squishedPoints = new double [lenPoints][2];
 
double[][] squishedDiff = new double [lenPoints][2];
 
double[][] repPoints = new double [lenPoints][2];
 
//-------------------------------------------------------
void setup() {
  size(792, 612); // 11x8.5" at 72DPI
  frameRate(15);
  smooth();
 
 
 
for (int j =0; j <points.length; j++) {
  double pointX = points2[j][0]*0.2;
  double pointY = -1*(points2[j][1]*0.2);
  scaledPoints[j][0] = pointX;
  scaledPoints[j][1] = pointY;
}
 
 
for (int i=0; i<points.length; i++) {
  double pointX = (points[i][0]*0.2);
  double pointY = (-1*(points[i][1]*0.2));
  squishedPoints[i][0] = pointX; 
  squishedPoints[i][1] = pointY;
}
 
for (int i=0; i<points.length; i++) {
  double squishedPointX = squishedPoints[i][0];
  double squishedPointY = squishedPoints[i][1];
 
  double scaledPointX = scaledPoints[i][0];
  double scaledPointY = scaledPoints[i][1];
 
  double diffX = squishedPointX-scaledPointX;
  double diffY = squishedPointY-scaledPointY;
  squishedDiff[i][0] = diffX;
  squishedDiff[i][1] = diffY;
}
 
for (int i=0; i<points.length; i++) {
  double pointX = scaledPoints[i][0];
  double pointY = scaledPoints[i][1];
 
  repPoints[i][0] = pointX;
  repPoints[i][1] = pointY;
}
} 
 
//-------------------------------------------------------
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(); 
  //textAlign(CENTER, CENTER); 
  //text (whichFrame, -1, -47);
 
 
 
  if (whichFrame<5) {
    for (int i=0; i<points.length; i++) {
      double[] curPoint = scaledPoints[i];
      double curX = curPoint[0];
      double curY = curPoint[1];
      double diffX = squishedDiff[i][0];
      double diffY = squishedDiff[i][1];
      double fMapped = map(whichFrame, 0, 5, 0, 1);
      double newX = curX+(diffX*fMapped);
      double newY = curY+(diffY*fMapped);
 
      repPoints[i][0] = newX;
      repPoints[i][1] = newY;
    }
  }
 
  else if (whichFrame>=5) {
    for (int i=0; i<points.length; i++) {
      double[] curPoint = squishedPoints[i];
      double curX = curPoint[0];
      double curY = curPoint[1];
      double diffX = squishedDiff[i][0];
      double diffY = squishedDiff[i][1];
      double fMapped = map(whichFrame, 5, 10, 0, 1);
      double newX = -1*((diffX*fMapped)-curX);
      double newY = -1*((diffY*fMapped)-curY);
 
      repPoints[i][0] = newX;
      repPoints[i][1] = newY;     
    }
  }
 
 
 
//if(whichFrame == 9){
//      pushMatrix();
//  fill(0);
//  beginShape();
//  for (int i=200; i<300; i++) {
//    float[] curPoint = repPoints[i];
//    //float[] nextPoint = repPoints[i+1];
//    vertex(curPoint[0], curPoint[1]);
//      //ellipse(curPoint[0],curPoint[1],2,2);
//  }
//  endShape();
//  popMatrix();
 
 
//  pushMatrix();
//  fill(0);
//  beginShape();
//  for (int i=0; i<100; i++) {
//    float[] curPoint = repPoints[i];
//    //float[] nextPoint = repPoints[i+1];
//    vertex(curPoint[0], curPoint[1]);
//      //ellipse(curPoint[0],curPoint[1],2,2);
//  }
//  endShape();
//  popMatrix();
 
//   pushMatrix();
//  fill(255);
//  beginShape();
//  for (int i=100; i<200; i++) {
//    float[] curPoint = repPoints[i];
//    //float[] nextPoint = repPoints[i+1];
//    vertex(curPoint[0], curPoint[1]);
//      //ellipse(curPoint[0],curPoint[1],2,2);
//  }
//  endShape();
//  popMatrix();
 
 
 
//}
 
 
 
//else if(whichFrame == 0){
//  pushMatrix();
//  fill(255);
//  beginShape();
//  for (int i=0; i<60; i++) {
//    float[] curPoint = repPoints[i];
//    //float[] nextPoint = repPoints[i+1];
//    vertex(curPoint[0], curPoint[1]);
//      //ellipse(curPoint[0],curPoint[1],2,2);
//  }
//  endShape();
//  popMatrix();
 
//   pushMatrix();
//  fill(0);
//  beginShape();
//  for (int i=60; i<120; i++) {
//    float[] curPoint = repPoints[i];
//    //float[] nextPoint = repPoints[i+1];
//    vertex(curPoint[0], curPoint[1]);
//      //ellipse(curPoint[0],curPoint[1],2,2);
//  }
//  endShape();
//  popMatrix();
 
//    pushMatrix();
//  fill(0);
//  beginShape();
//  for (int i=120; i<180; i++) {
//    float[] curPoint = repPoints[i];
//    //float[] nextPoint = repPoints[i+1];
//    vertex(curPoint[0], curPoint[1]);
//      //ellipse(curPoint[0],curPoint[1],2,2);
//  }
//  endShape();
//  popMatrix();
 
//      pushMatrix();
//  fill(0);
//  beginShape();
//  for (int i=180; i<240; i++) {
//    float[] curPoint = repPoints[i];
//    //float[] nextPoint = repPoints[i+1];
//    vertex(curPoint[0], curPoint[1]);
//      //ellipse(curPoint[0],curPoint[1],2,2);
//  }
//  endShape();
//  popMatrix();
 
 
//      pushMatrix();
//  fill(0);
//  beginShape();
//  for (int i=240; i<300; i++) {
//    float[] curPoint = repPoints[i];
//    //float[] nextPoint = repPoints[i+1];
//    vertex(curPoint[0], curPoint[1]);
//      //ellipse(curPoint[0],curPoint[1],2,2);
//  }
//  endShape();
//  popMatrix();
//}
 
 
  pushMatrix();
  fill(255);
  stroke(0);
  strokeWeight(1);
  //beginShape();
  for (int i=0; i<points.length-1; i++) {
    if ((i+1)%60==0 || (i+1)%100==0 ) {
      continue;
    }
    double[] curPoint = repPoints[i];
    double[] nextPoint = repPoints[i+1];
    //double[] nextNextPoint = repPoints[i+2];
 
    line((float)curPoint[0], (float)curPoint[1],(float)nextPoint[0],(float)nextPoint[1]);
    //vertex((float)curPoint[0],(float)curPoint[1]);
    //bezierVertex((float)nextPoint[0],(float)nextPoint[1],(float)nextNextPoint[0],(float)nextNextPoint[1],(float)nextNextNextPoint[0],(float)nextNextNextPoint[1]);
     // ellipse((float)curPoint[0],(float)curPoint[1],2,2);
 
  }
  //endShape();
popMatrix();
 
  //line(repPoints[0][0], repPoints[0][1], repPoints[repPoints.length-1][0], repPoints[repPoints.length-1][1]);
  //line( repPoints[repPoints.length-1][0], repPoints[repPoints.length-1][1],repPoints[0][0], repPoints[0][1]);
 
}
 
//-------------------------------------------------------
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);
}

breep-Scope

My design largely stemmed off the idea of conveying circles within circles. I wanted to show how the movement of the black circle within the larger unit conveys the movement of a larger black circle that is made by the sum of its parts. This was a notion that I wanted to explore in my gif, but never really got round to integrating it, so this was a kind of nod to that idea.

/*
// 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!
 
   var nCircles = 10 
   for (var i=0; i &lt;= nCircles; i++) {
     var radius = 20 
     if (whichFrame != i){
       fill(255);}
 
     else {
       fill(0);}
 
     var cx = radius * cos((TWO_PI/10) * i); 
     var cy = radius * sin((TWO_PI/10) * i);
     ellipse(cx, cy, 20, 20);
   }
 
}
 
//-------------------------------------------------------
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);
}

 

 

paukparl-Scope

pdf:
praxinoscope-paukparl

thoughts:
I thought it would be fun to animate a random looking scribble like the one in the sketch below. In the setup() function, I created an array of random vertices to be connected by bezier curves, then added periodical offsets created by noise() function to each vertex just before drawing the shape. While it took me longer than I expected to implement the code, the outcome didn't seem as interesting as I thought, mainly due to the periodicity of the movement.

sketch:

gif:

 

...
 
float[][] line = new float[120][6];
float[] num = new float[120];
int count = 0;
 
void setup() {
  size(792, 612); // 11x8.5" at 72DPI
  frameRate(15);
  smooth();
  int i = 0;
  for (int y = 60; y&gt; -60; y-=5) {
    line[i][0] = random(-60+y/3, 60-y/3);
    line[i][1] = random(-20, 20)+y;
    line[i][2] = random(-60+y/3, 60-y/3);
    line[i][3] = random(-20, 20)+y;
    line[i][4] = 0;
    line[i][5] = random(-5, 5)+y;
    i++;
    num[i] = random(50);
  }
} 
 
...
 
void drawArtFrame (int whichFrame) { 
  stroke(0);
  strokeWeight(0.5);
  beginShape();
  vertex(0, 60);
  println(line[3][4]);
  int count = 0;
  for (int i =0; i&lt;23; i++) {
    bezierVertex(
    line[i][0]+80*(getNoise(whichFrame, 0.05, num[count], num[count])-0.5),
    line[i][1]+40*(getNoiseSlow(whichFrame, 0.1, num[count], num[count])-0.5),
    line[i][2]+80*(getNoiseSlow(whichFrame, 0.1, num[count], num[count])-0.5),
    line[i][3]+40*(getNoise(whichFrame, 0.05, num[count], num[count])-0.5),
    line[i][4]+80*(getNoiseSlow(whichFrame, 0.1, num[count], num[count])-0.5),
    line[i][5]+40*(getNoiseSlow(whichFrame, 0.1, num[count], num[count])-0.5));
    count++;
  }
  endShape();
}