nannon-Scope

Kit Kat Scope

 

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

 
/*
// Template for KidzLabs/4M/Toysmith Animation Praxinoscope
// https://www.amazon.com/4M-3474-Animation-Praxinoscope/dp/B000P02HYC
// https://www.walmart.com/ip/Animation-Praxinoscope-Science-Kits-by-Toysmith-3474/45681503
// Developed for p5.js, September 2018 * Golan Levin 
 
*/
 
 
 
var inch = 72.0; 
var diamArtInner = inch * 1.50; 
var diamArtOuter = inch * 4.80; 
var diamCutInner = inch * 1.41; 
var diamCutOuter = inch * 4.875; 
var holeDy = inch * 0.23;
var holeDx = inch * 0.20;
var holeD = inch * 0.1;
 
var nFrames = 10; 
var myFrameCount = 0;
var exportFrameCount = 0; 
 
var bAnimate = true;
var bExportFrameImages = false;
var bRecordingSinglePNG = false;
 
//-------------------------------------------------------
function setup() {
  createCanvas(792, 612); // 11x8.5" at 72DPI
  frameRate(20);
  smooth();
} 
 
 
//-------------------------------------------------------
function draw() {
  background(240); 
 
  // Do all the drawing. 
  push(); 
  translate(width/2, height/2);
  drawCutLines(); 
  drawGuides(); 
  drawAllFrames();
  pop();
 
 
  if (bExportFrameImages){
    // Note that myFrameCount is incremented elsewhere.
    var filename = "myZoetrope_" + nf(myFrameCount,2) + ".png";
    saveCanvas(filename, 'png');
    if (myFrameCount >= nFrames){
      bExportFrameImages = false;
    }
  }
 
 
  if (bRecordingSinglePNG) {
    saveCanvas('myPraxinoscope.png', 'png');
    bRecordingSinglePNG = false;
  }
}
 
 
//-------------------------------------------------------
function mouseClicked() {
  console.log(mouseX, mouseY);
}
 
function keyPressed() {
  switch (key) {
  case ' ': 
    // Press spacebar to pause/unpause the animation. 
    bAnimate = !bAnimate;
    break;
 
  case 'p':
    case 'P':
      // Press 'p' to export a single PNG for the Zoetrope. 
      // Note: This is for 17x11" paper! 
      // Be sure to print at 100%!
      bRecordingSinglePNG = true;
      break;
 
    case 'f':
    case 'F':
      // Press 'f' to export multiple frames 
      // (in order to make an animated .GIF)
      // such as with http://gifmaker.me/
      myFrameCount = 0;
      exportFrameCount = 0;
      bExportFrameImages = true;
      bAnimate = true;
      break;
  }
}
 
//-------------------------------------------------------
function drawCutLines() {
  fill(0); 
  textAlign(CENTER, BOTTOM); 
  text("Praxinoscope Template", 0, 0-diamCutOuter/2-6); 
 
  stroke(250); 
  strokeWeight(1.0);
 
 
  if (bRecordingSinglePNG) {
    fill(0); 
  }
  ellipse(0, 0, diamCutOuter, diamCutOuter);
 
 
  if (bRecordingSinglePNG) {
    fill(0); 
  }
  ellipse(0, 0, diamCutInner, diamCutInner);
 
  fill(255); 
  ellipse(diamCutOuter/2 - holeDx, 0-holeDy, holeD, holeD); 
 
  stroke(240)
  line (diamCutInner/2, 0, diamCutOuter/2, 0);
}
 
//-------------------------------------------------------
function drawGuides() {
  // This function draws the guidelines. 
  // Don't draw these when we're exporting the PNG. 
  if (!bRecordingSinglePNG) {
 
    noFill(); 
    stroke(128); 
    strokeWeight(0.2); 
    ellipse(0, 0, diamArtInner, diamArtInner); 
    ellipse(0, 0, diamArtOuter, diamArtOuter);
 
    for (var i=0; i<nFrames; i++) {
      var angle = map(i, 0, nFrames, 0, TWO_PI); 
      var pxi = diamArtInner/2 * cos(angle);
      var pyi = diamArtInner/2 * sin(angle);
      var pxo = diamArtOuter/2 * cos(angle);
      var pyo = diamArtOuter/2 * sin(angle);
      stroke(128); 
      strokeWeight(0.2);
      line (pxi, pyi, pxo, pyo);
    }
 
    // Draw the red wedge outline, highlighting the main view.
    // var redWedge = 7; // assuming nFrames = 10
    // for (var i=redWedge; i<=(redWedge+1); i++) {
    //   var angle = map(i, 0, nFrames, 0, TWO_PI); 
    //   var pxi = diamArtInner/2 * cos(angle);
    //   var pyi = diamArtInner/2 * sin(angle);
    //   var pxo = diamArtOuter/2 * cos(angle);
    //   var pyo = diamArtOuter/2 * sin(angle);
    //   stroke(255, 0, 0); 
    //   strokeWeight(2.0);
    //   line (pxi, pyi, pxo, pyo);
    // }
    // noFill(); 
    // stroke(255, 0, 0); 
    // strokeWeight(2.0);
    // var startAngle = redWedge*TWO_PI/nFrames;
    // var endAngle = (redWedge+1)*TWO_PI/nFrames;
    // arc(0, 0, diamArtInner, diamArtInner, startAngle, endAngle); 
    // arc(0, 0, diamArtOuter, diamArtOuter, startAngle, endAngle); 
 
 
    for (var i=0; i<nFrames; i++) {
      var angle = map(i, 0, nFrames, 0, TWO_PI); 
 
      push();
      rotate(angle); 
      var originY = ((diamArtOuter + diamArtInner)/2)/2;
      translate(0, 0-originY); 
 
      noFill(); 
      stroke(128); 
      strokeWeight(0.2);
      line (-inch/2, 0, inch/2, 0); 
      line (0, -inch/2, 0, inch/2); 
 
      pop();
    }
  }
}
 
//-------------------------------------------------------
function drawAllFrames() {
  for (var i=0; i<nFrames; i++) {
    var angle = map(i, 0, nFrames, 0, TWO_PI); 
    var originY = ((diamArtOuter + diamArtInner)/2)/2;
 
    push();
    rotate(angle); 
    translate(0, 0-originY); 
    scale(0.8, 0.8); // feel free to ditch this 
 
    var whichFrame = i; 
    if (bAnimate) {
      whichFrame = (i+myFrameCount)%nFrames;
    }
    drawArtFrame (whichFrame); 
    // drawArtFrameAlternate (whichFrame); 
 
    pop();
  }
  myFrameCount++;
}
 
 
//-------------------------------------------------------
function drawArtFrame ( whichFrame ) { 
  // Draw the artwork for a generic frame of the Praxinoscope, 
  // given the framenumber (whichFrame) out of nFrames.
  // NOTE #1: The "origin" for the frame is in the center of the wedge.
  // NOTE #2: Remember that everything will appear upside-down!
 
  // Draw the frame number
  fill(0); 
  noStroke(); 
  textAlign(CENTER, CENTER); 
  text (whichFrame, 0, -45);
 
  // Draw eyes
  fill(255); 
  stroke(255);
  strokeWeight(1); 
 
  ellipse(-18, -48, 28,28); 
  ellipse(18, -48, 28,28); 
  ellipse(0,-33,15,10);
 
 
  //draw eye balls
  fill(0);
  noStroke();
  var xAxis = map(whichFrame, 0,nFrames, 0,PI)
  arc(sin(xAxis)*16-18-14+6, -48, 12,12,PI/6,(11*PI)/6, PIE);
 
  arc(sin(xAxis)*16-18-14+6+36 , -48, 12,12,PI/6,(11*PI)/6, PIE);
 
  //clock
  fill(255);
  stroke(255);
  rect(-25,-23, 50, 70, 10);
 
//clock tix
  stroke(0);
  strokeWeight(2 );
  line (0, -13, 0, -18);
 
  line (0, -13, 0, -18);
  line (0, 35, 0, 40);
  line (-18,12, -13,12);
 
   line (18,12, 13,12);
 
  //whiskers 
  stroke(255)
  line (-20,-30, -45,-35);
  line (-20,-25, -45,-20);
  line (20,-30, 45,-35);
  line (20,-25, 43,-20);
 
 
 
 
 
  // Draw some rotating spokes
    var cx = 0; 
    var cy = 12; 
    var u = 0 - map(whichFrame, 0, nFrames, 0, 1);
    var sx = cx + 15 * cos(u * TWO_PI); 
    var sy = cy + 15 * sin(u* TWO_PI); 
    stroke(0); 
 
    line (cx, cy, sx, sy);
 
 
  	var dx = 0; 
    var dy = 12; 
    var u2 = 0 - map(whichFrame, 0, nFrames/2, 0, 1);
    var vx = dx + 20 * cos(u2 * (TWO_PI+1.2)); 
    var vy = dy + 20 * sin(u2* (TWO_PI+1.2)); 
    stroke(0); 
    strokeWeight(1);
    line (dx, dy, vx, vy);
}

sapeck-Scope

My design is a simple yet slightly humorous attempt to animate an emoji. The head and eyes move with in a sinusoidal manner, and the tongue stays stationary but lengthens in accordance with the frame number.

sapeck-praxinoscope-output (PDF download)

/* Sapeck    9/12/2017
"sapeck-Scope"
60-212                        Carnegie Mellon University
Copyright (C) 2018-present  Sapeck
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.
*/
void drawArtFrame (int whichFrame) { 
  pushMatrix();
  // move the head up and down sinusoidally
  translate(0, -10+30*sin(map(whichFrame, 0, 10, 0, 6)));
 
  // draw the head
  fill(0);
  ellipse(0, 0, 50, 50);
 
  // draw the eye sockets
  fill(255);
  ellipse(-10, -10, 20, 20);
  ellipse(10, -10, 20, 20);
 
  // draw the eyes
  fill(0);
  int eyeSize = 6+int(6*sin(map(whichFrame, 0, 10, 6, 2)));
  ellipse(-10, -10, eyeSize, eyeSize);
  ellipse(10, -10, eyeSize, eyeSize);
 
  // draw the tongue
  fill(color(255,0,0,255));
  rect(-10, 10, 20, 10+2*whichFrame, 7);
 
  popMatrix();
}

lass-Scope

download png 

For my praxinoscope, I decided to create an animation of a russian matryoshka doll opening. I liked this idea because it loops easily.
I drew the doll using p5's beginShape() and curveVertex(), but in hindsight I probably could have done it a lot more easily if I just uploaded png images for the top and bottom halves. Still, I got to experiment with drawing curves and using the p5 transformations, which was fun.

Initially, I couldn't decide between doing matryoshkas or the same concept with eggs. I think eggs would have been cool too.

function drawArtFrame ( whichFrame ) { 
  push(); 
  rotate(Math.PI); //because i made it upside down on accident. haha
  fill(255); 
  //vertices form the upper and lower matryoshka halves
  var upperHalf = [ [1.3, 2], [1.3, 0], [1.2, 1.3], [.8, 2], [0, 2.3]];
  var lowerHalf = [[1.3, 2], [1.3, 0], [1.5, -1.8], [0, -2.3]];
 
  //drawing the outer matryoshka
  sWidth = map((whichFrame ) % 10, 0, 9, 6, 12); 
  sHeight = map((whichFrame ) % 10, 0, 9, 7, 14); 
  var heightChange = 0
  fill(200);
 
  strokeWeight(1); 
  stroke(0); 
  fill(0);
  drawMatryoshka(lowerHalf, sWidth, sHeight, -1 * heightChange); 
  fill(255);
  drawMatryoshka(upperHalf, sWidth, sHeight, heightChange); 
  drawDetails(heightChange, sHeight, sWidth, 255); 
 
  //drawing the inner matryoshka
  whichFrame = (whichFrame + 0) % 10; 
  sWidth = map(whichFrame, 0, 9, 12, 15); 
  sHeight = map(whichFrame , 0, 9, 14, 20); 
  var heightChange = map(whichFrame, 0, 9, 6, 80); 
 
  var opacity =   map(whichFrame, 0, 10, 255, 0);
 
  fill(0, opacity);
  fill(0, opacity);
  stroke(0, opacity); 
  drawMatryoshka(lowerHalf, sWidth, sHeight, -1 * heightChange); 
  fill(255, opacity);
  drawMatryoshka(upperHalf, sWidth, sHeight, heightChange); 
  drawDetails(heightChange, sHeight, sWidth, opacity); 
  pop(); 
}
 
//draws shape based on the vertices w/ vertical symmetry 
function drawMatryoshka(verts, sWidth, sHeight, heightChange){
  beginShape();
  for(var i = 0; i  < verts.length; i++ ){
    curveVertex(verts[i][0] * sWidth, verts[i][1] * sHeight + heightChange); 
  }
  for(var i = verts.length - 2; i  >=0; i-- ){
    curveVertex(verts[i][0] * sWidth * -1, verts[i][1] * sHeight + heightChange); 
  }
  endShape(); 
  line(-1.3 * sWidth + .5,  heightChange, sWidth * 1.3 - .5,  heightChange);
}
 
function drawDetails(heightChange, sHeight, sWidth, opacity){
  //face
  strokeWeight(1); 
  fill(255, opacity); 
  ellipse(0, heightChange + sHeight * 1.3, sWidth * 1.7, sWidth * 1.7); 
 
  //hair
  fill(0, opacity);
  arc(0, heightChange + sHeight * 1.3, sWidth * 1.7, sWidth * 1.7, PI * 2, HALF_PI, CHORD); 
  arc(0, heightChange + sHeight * 1.3, sWidth * 1.7, sWidth * 1.7, HALF_PI, PI , CHORD); 
  strokeWeight(0); 
 
  //blush
  fill(255, 150, 150, opacity); 
  ellipse(.4 * sWidth, heightChange + sHeight * 1.2,sWidth * .4, sWidth * .4); 
  ellipse(- .4 * sWidth, heightChange + sHeight * 1.2, sWidth * .4, sWidth * .4); 
 
  //eyes and mouth
  fill(0,  opacity); 
  ellipse(.25 * sWidth, heightChange + sHeight * 1.4, sWidth * .2, sWidth * .2); 
  ellipse(- .25 * sWidth, heightChange + sHeight * 1.4, sWidth * .2, sWidth * .2); 
  ellipse(0, heightChange + sHeight , sWidth * .5, sHeight * .05);
 
  //bow
  fill(255, opacity);
  push(); 
  translate(0, -1 * heightChange);
  rotate(10); 
  ellipse(.2 * sWidth,  -.1 * sHeight, sWidth * .6, sWidth * .3); 
  rotate(-20); 
  ellipse(-.2 * sWidth,  -.1 * sHeight, sWidth * .6, sWidth * .3); 
  pop(); 
 
  //flower
  fill(255, opacity); 
  push();
  translate(0, -1.1 * sHeight -1 * heightChange);
  rotate(sWidth * .2); 
  for(var i = 0; i < 3; i++){
    ellipse(0,  0, sWidth * .3, sWidth * 1.2); 
    rotate(PI / 1.5 ); 
  }
  pop(); 
  fill(0, opacity);
  ellipse(0, -1.1 * sHeight -1 * heightChange, sWidth * .4, sWidth * .4); 
  fill(255); 
  strokeWeight(1); 
}

yuvian-Scope

download design as pdf here

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


void drawArtFrame (int whichFrame) { 

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

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

weirdie-Scope

http://cmuems.com/2018/60212f/wp-content/uploads/2018/09/Buggos.png

For the praxinoscope I just wanted to make some little bugs crawling around. There are two bugs coded that start from opposite ends and walk along a sine curve. It was a good learning process in making the legs draw properly and for all of the pieces to move together. Pretty simple, but this partially inspired my final GIF design.

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!
 
stroke(0);
strokeWeight(1.5);
fill(0);
 
//bug one!
var moveY = whichFrame * 17;
var a = 20*cos(whichFrame*0.5 + 50);
 
ellipse(0+a, 80-moveY, 12, 20);
ellipse(0+a, 70-moveY, 5, 5);
 
line(0+a, 80-moveY, 10+a, 70-moveY);
line(0+a, 80-moveY, -10+a, 70-moveY);
 
line(0+a, 75-moveY, 10+a, 90-moveY);
line(0+a, 75-moveY, -10+a, 90-moveY);
 
line(0+a, 75-moveY, 12+a, 80-moveY);
line(0+a, 75-moveY, -12+a, 80-moveY);
 
line(0+a, 70-moveY, 5+a, 65-moveY);
line(0+a, 70-moveY, -5+a, 65-moveY);
 
//bug two!
 
rotate(PI);
var a = -20*cos(whichFrame*0.2 + 50);
 
ellipse(0+a, 60-moveY, 12, 20);
ellipse(0+a, 50-moveY, 5, 5);
 
line(0+a, 60-moveY, 10+a, 50-moveY);
line(0+a, 60-moveY, -10+a, 50-moveY);
 
line(0+a, 55-moveY, 10+a, 70-moveY);
line(0+a, 55-moveY, -10+a, 70-moveY);
 
line(0+a, 55-moveY, 12+a, 60-moveY);
line(0+a, 55-moveY, -12+a, 60-moveY);
 
line(0+a, 50-moveY, 5+a, 45-moveY);
line(0+a, 50-moveY, -5+a, 45-moveY);
 
}

 

chaine-Scope

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

/*
// Template for KidzLabs/4M/Toysmith Animation Praxinoscope
// https://www.amazon.com/4M-3474-Animation-Praxinoscope/dp/B000P02HYC
// https://www.walmart.com/ip/Animation-Praxinoscope-Science-Kits-by-Toysmith-3474/45681503
// Developed for p5.js, September 2018 * Golan Levin 
 
*/
 
var inch = 72.0; 
var diamArtInner = inch * 1.50; 
var diamArtOuter = inch * 4.80; 
var diamCutInner = inch * 1.41; 
var diamCutOuter = inch * 4.875; 
var holeDy = inch * 0.23;
var holeDx = inch * 0.20;
var holeD = inch * 0.1;
 
var nFrames = 10; 
var myFrameCount = 0;
var exportFrameCount = 0; 
 
var bAnimate = true;
var bExportFrameImages = false;
var bRecordingSinglePNG = false;
 
//-------------------------------------------------------
function setup() {
  createCanvas(792, 612); // 11x8.5" at 72DPI
  frameRate(20);
  smooth();
} 
 
 
//-------------------------------------------------------
function draw() {
  background(240); 
 
  // Do all the drawing. 
  push(); 
  translate(width/2, height/2);
  drawCutLines(); 
  drawGuides(); 
  drawAllFrames();
  pop();
 
 
  if (bExportFrameImages){
    // Note that myFrameCount is incremented elsewhere.
    var filename = "myZoetrope_" + nf(myFrameCount,2) + ".png";
    saveCanvas(filename, 'png');
    if (myFrameCount &gt;= nFrames){
      bExportFrameImages = false;
    }
  }
 
 
  if (bRecordingSinglePNG) {
    saveCanvas('myPraxinoscope.png', 'png');
    bRecordingSinglePNG = false;
  }
}
 
 
//-------------------------------------------------------
function keyPressed() {
  switch (key) {
  case ' ': 
    // Press spacebar to pause/unpause the animation. 
    bAnimate = !bAnimate;
    break;
 
  case 'p':
    case 'P':
      // Press 'p' to export a single PNG for the Zoetrope. 
      // Note: This is for 17x11" paper! 
      // Be sure to print at 100%!
      bRecordingSinglePNG = true;
      break;
 
    case 'f':
    case 'F':
      // Press 'f' to export multiple frames 
      // (in order to make an animated .GIF)
      // such as with http://gifmaker.me/
      myFrameCount = 0;
      exportFrameCount = 0;
      bExportFrameImages = true;
      bAnimate = true;
      break;
  }
}
 
//-------------------------------------------------------
function drawCutLines() {
  fill(0); 
  textAlign(CENTER, BOTTOM); 
  text("Praxinoscope Template", 0, 0-diamCutOuter/2-6); 
 
  stroke(0); 
  strokeWeight(1.0);
 
  noFill(); 
  if (!bRecordingSinglePNG) {
    fill(255); 
  }
  ellipse(0, 0, diamCutOuter, diamCutOuter);
 
  noFill(); 
  if (!bRecordingSinglePNG) {
    fill(240); 
  }
  ellipse(0, 0, diamCutInner, diamCutInner);
 
  noFill(); 
  ellipse(diamCutOuter/2 - holeDx, 0-holeDy, holeD, holeD); 
 
  line (diamCutInner/2, 0, diamCutOuter/2, 0);
}
 
//-------------------------------------------------------
function drawGuides() {
  // This function draws the guidelines. 
  // Don't draw these when we're exporting the PNG. 
  if (!bRecordingSinglePNG) {
 
    noFill(); 
    stroke(128); 
    strokeWeight(0.2); 
    ellipse(0, 0, diamArtInner, diamArtInner); 
    ellipse(0, 0, diamArtOuter, diamArtOuter);
 
    for (var i=0; i&lt;nFrames; i++) {
      var angle = map(i, 0, nFrames, 0, TWO_PI); 
      var pxi = diamArtInner/2 * cos(angle);
      var pyi = diamArtInner/2 * sin(angle);
      var pxo = diamArtOuter/2 * cos(angle);
      var pyo = diamArtOuter/2 * sin(angle);
      stroke(128); 
      strokeWeight(0.2);
      line (pxi, pyi, pxo, pyo);
    }
 
    // Draw the red wedge outline, highlighting the main view.
    var redWedge = 7; // assuming nFrames = 10
    for (var i=redWedge; i&lt;=(redWedge+1); i++) {
      var angle = map(i, 0, nFrames, 0, TWO_PI); 
      var pxi = diamArtInner/2 * cos(angle);
      var pyi = diamArtInner/2 * sin(angle);
      var pxo = diamArtOuter/2 * cos(angle);
      var pyo = diamArtOuter/2 * sin(angle);
      stroke(255, 0, 0); 
      strokeWeight(2.0);
      line (pxi, pyi, pxo, pyo);
    }
    noFill(); 
    stroke(255, 0, 0); 
    strokeWeight(2.0);
    var startAngle = redWedge*TWO_PI/nFrames;
    var endAngle = (redWedge+1)*TWO_PI/nFrames;
    arc(0, 0, diamArtInner, diamArtInner, startAngle, endAngle); 
    arc(0, 0, diamArtOuter, diamArtOuter, startAngle, endAngle); 
 
 
    for (var i=0; i&lt;nFrames; i++) {
      var angle = map(i, 0, nFrames, 0, TWO_PI); 
 
      push();
      rotate(angle); 
      var originY = ((diamArtOuter + diamArtInner)/2)/2;
      translate(0, 0-originY); 
 
      noFill(); 
      stroke(128); 
      strokeWeight(0.2);
      //line (-inch/2, 0, inch/2, 0); 
      //line (0, -inch/2, 0, inch/2); 
 
      pop();
    }
  }
}
 
//-------------------------------------------------------
function drawAllFrames() {
  for (var i=0; i&lt;nFrames; i++) {
    var angle = map(i, 0, nFrames, 0, TWO_PI); 
    var originY = ((diamArtOuter + diamArtInner)/2)/2;
 
    push();
    rotate(angle); 
    translate(0, 0-originY); 
    scale(0.8, 0.8); // feel free to ditch this 
 
    var whichFrame = i; 
    if (bAnimate) {
      whichFrame = (i+myFrameCount)%nFrames;
    }
    drawArtFrame (whichFrame); 
    // drawArtFrameAlternate (whichFrame); 
 
    pop();
  }
  myFrameCount++;
}
 
 
//-------------------------------------------------------
function drawArtFrame ( whichFrame ) { 
  // Draw the artwork for a generic frame of the Praxinoscope, 
  // given the framenumber (whichFrame) out of nFrames.
  // NOTE #1: The "origin" for the frame is in the center of the wedge.
  // NOTE #2: Remember that everything will appear upside-down!
 
  push();
  fill(0); 
  noStroke(); 
 
  // Draw a pulsating ellipse
 
  //draw the shadow
  noStroke();
  fill(150,150,150);
  var t = map(whichFrame, 0, nFrames, 0, 1); 
  var shadow = map(cos(t*TWO_PI), 1, -1, 10, 30); 
  ellipse(0, 45, shadow, shadow*0.5);
 
 
  noFill(); 
  stroke(0);
  strokeWeight(1); 
 
  var diam = map(cos(t*TWO_PI), -1, 1, -30, 50); 
 
  //first circle (biggest)
  var ell1 = map(cos(t * TWO_PI), 1, -1, 17, (30*(whichFrame/3)));
  ellipse(0, diam, ell1, ell1);
 
  //second circle (second biggest)
  var ell2 = map(cos(t * TWO_PI), 1, -1, 16, (30*(whichFrame/4)));
  ellipse(0, diam, ell2, ell2);
 
  //center black circle
  fill(0);
  var diam2 = map(cos(t * TWO_PI), 1, -1, 15, 30);
  ellipse(0, diam, diam2, diam2);
  pop();
 
}
 
//-------------------------------------------------------
function drawArtFrameAlternate( whichFrame ) { 
  // An alternate drawing test. 
  // Draw a falling object. 
 
 
  // Draw a little splat on the frame when it hits the ground. 
  if (whichFrame == (nFrames-1)) {
    stroke(0, 0, 0); 
    strokeWeight(0.5); 
    var nL = 10;
    for (var i=0; i&lt;nL; i++) {
      var a = HALF_PI + map(i, 0, nL-1, 0, TWO_PI);
      var cx = 12 * cos(a);
      var cy = 10 * sin(a); 
      var dx = 16 * cos(a);
      var dy = 13 * sin(a); 
      line (cx, 45+cy, dx, 45+dy);
    }
  }
 
  // Draw a little box frame
  fill(255); 
  stroke(0, 0, 0);
  strokeWeight(1); 
  rect(-5, -50, 10, 100); 
 
  // Make the puck accelerate downward
  var t = map(whichFrame, 0, nFrames-1, 0, 1); 
  var t2 = pow(t, 2.0); 
  var rh = 8 + whichFrame * 0.5; // wee stretch
  var ry = map(t2, 0, 1, 0, 100-rh) - 50; 
 
  noStroke(); 
  fill(0, 0, 0);
  rect(-5, ry, 10, rh);
}

nerual-Scope

Process:

I really liked the aesthetics of the line pop explosion thing, so I wanted to make use of it somehow. I was also fixated on making something meta, in preparation for the GIF project.

Actual Code:

function drawArtFrame(whichFrame) {
  // Draw the artwork for a generic frame of the Zoetrope, 
  // given the framenumber (whichFrame) out of nFrames.

  drawMyArtFrame(whichFrame);
}
  
function drawMyArtFrame(whichFrame){
  noFill();
  stroke(0);
  strokeWeight(1);
  var padding = 30;
  var pos = map(whichFrame, 0, nFrames, artAreaHeight-padding, padding);
  var t = map(whichFrame, 0, nFrames, 0, 1);
  var diam = map(cos(t * TWO_PI), -1, 1, artAreaHeight-padding, padding+10);
  //ellipse(0, pos, 10, 10);
  var dir = map(whichFrame, 0, nFrames, -1, 1);
  if(whichFrame > 9 || whichFrame < 3) 
    drawPop(0, padding-10, 5, 10);
  drawMouseScaled(0, diam, 5);
}

 

casher-Scope

Since I am still new to Javascript/p5.js, I didn't totally understand what the code in the template meant when I began this assignment. As a result, most of my design is from experimentation. I started out by writing some groups of statements similar to the template's, and then I just started changing values of variables and parameters, testing the limits of the application. I spent a long time perfecting everything so it looked aesthetic.

There's not much else to explain, but I love the way it turned out! And I am pleased with the effort I put in because now I definitely better understand how the code works.

/*
// 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 bRecordingPNG = false;
 
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;
 
//-------------------------------------------------------
function setup() {
  createCanvas(792, 612); // 11x8.5" at 72DPI
  frameRate(20);
  smooth();
} 
 
 
//-------------------------------------------------------
function draw() {
  background(255); 
 
  // Do all the drawing. 
  push(); 
  translate(width/2, height/2);
  drawCutLines(); 
  //drawGuides(); 
  drawAllFrames();
  pop();
 
 
  if (bRecordingPNG) {
    saveCanvas('myPraxinoscope.png', 'png');
    bRecordingPNG = 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 PNG for the Praxinoscope.
    bRecordingPNG = 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;
 
      if (bExportFrameImages) {
        var recordFramerate = 1.0;
        var recordDuration = nFrames * 1.01; 
        frameRate(recordFramerate); // 1 FPS baby
        saveFrames('Praxinoscope_', 'png', recordDuration, recordFramerate); 
        bExportFrameImages = false;
      }
 
      break;
  }
}
 
//-------------------------------------------------------
function drawCutLines() {
  fill(0); 
  textAlign(CENTER, BOTTOM); 
  text("Praxinoscope Template", 0, 0-diamCutOuter/2-6); 
 
  stroke(0); 
  strokeWeight(1.0);
 
  noFill(); 
  if (!bRecordingPNG) {
    fill(255); 
  }
  ellipse(0, 0, diamCutOuter, diamCutOuter);
 
  noFill(); 
  if (!bRecordingPNG) {
    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 (!bRecordingPNG) {
 
    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 ) { 
 
  //ellipses
  fill(random(0, 255), random(150,200), random(200,230));
  stroke(255);
  strokeWeight(2);
  for (var i = 0; i &lt; nFrames; i++)
  {
    var t = map(whichFrame, 1, nFrames, 1, i*.38);
  	var diam = map(cos(t*TWO_PI*.22), -1, 1, -i*8, i*8);
  	ellipse(0,i*7-10,diam*.7,diam*0.4);
  }
 
  //lines
  p1 = -45;
  p2 = 70;
  p3 = -0;
  p4 = 54;
  stroke(100);
  strokeWeight(1.2);
  line2 = map(whichFrame, -1, 1, -50, 50);
  for (var i = 0; i &lt; nFrames; i++) {
    line(p1+8*whichFrame,p2,p3,p4);
  }
 
  //triangles
  var p1x = 50;
  var p1y = -25;
  var p2x = 60;
  var p2y = -60;
  var p3x = -40;
  var p3y = -10;
  strokeWeight(2);
  stroke(255);
  for (var i = 0; i &lt; nFrames; i++) {
    fill(25*whichFrame);
    triangle(p1x/(whichFrame*-1)-10, p1y-40, p2x/(whichFrame**2)+20, p2y+20, p3x+whichFrame*10, p3y);
    fill(30*whichFrame);
    triangle(p1x/(whichFrame*2)-3, p1y-30, p2x/(whichFrame)+20, p2y+20, p3x+whichFrame*-2+15, p3y);
  }
 
  //circles
  var p1 = -50;
  var p2 = 0;
  noFill();
  stroke(50);
  strokeWeight(1);
  for (var i = 0; i &lt; nFrames-4; i+=2) {
    stroke(2**whichFrame);
    ellipse(p1-whichFrame*5, p2+20, 10, 10);
    p1 = 0;
    p2 = 0;
  }
}

nixel-Scope

 

pdf: zoetrope-output

For my zoetrope design, I experimented a lot with arcs. I started off with just one eye because I wanted to make some sort of illuminati related loop, but then decided to go in a simpler direction. I like the result, although I wish there was more time to make the animation actually loop instead of clearly starting over every time.

Here are some very rough initial designs. My first idea was a jump roping ball. Second was a blinking eye looking around. I initially programmed this one using ellipses but was not satisfied so I switched to arcs and got the final result you see.

 
// Processing Template for Zoetrope toy by Eye Think
// https://www.amazon.com/Zoetrope-Animation-Toy-Victorian-Illusion/dp/B007VM9HZO/
// Developed for Processing 3.3.6 * http://processing.org
// 24 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 paperStripWidth = inch * 12.625;
float paperStripHeight = inch * 1.3125;
float overlapMargin = inch * 0.4375;
float artAreaWidth = paperStripWidth - overlapMargin;
float artAreaHeight = paperStripHeight;
 
final int nFrames = 11; 
int myFrameCount = 0;
int exportFrameCount = 0; 
boolean bAnimate = true; 
boolean bExportFrameImages = false;
 
//-------------------------------------------------------
void setup() {
  size(1224, 792); // 17x11" at 72DPI
  frameRate(15);
  smooth();
} 
 
//-------------------------------------------------------
void draw() {
  background(240); 
  if (bRecordingPDF) {
    beginRecord(PDF, "zoetrope-output.pdf");
  }
 
  // Do all the drawing. 
  pushMatrix(); 
  translate(width/2, height/2);
  translate(0-paperStripWidth/2, 0-paperStripHeight/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 Zoetrope. 17x11" paper!
    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("Zoetrope Template", paperStripWidth/2, -20); 
 
  stroke(0); 
  strokeWeight(1.0);
  noFill(); 
  if (!bRecordingPDF) {
    fill(255);
  }
  rect(0, 0, paperStripWidth, paperStripHeight);
}
 
//-------------------------------------------------------
void drawGuides() {
  // This function draws the guidelines. 
  // Don't draw these when we're exporting the PDF. 
  if (!bRecordingPDF) {
    float frameSpacing = artAreaWidth / nFrames;
 
    stroke(128); 
    strokeWeight(0.2);
    for (int i=0; i<nFrames; i++) {
      pushMatrix();
      translate(i * frameSpacing, 0);
      rect(0, 0, frameSpacing, artAreaHeight); 
      popMatrix();
    }
  }
}
 
//-------------------------------------------------------
void drawAllFrames() {
  for (int i=0; i<nFrames; i++) {
 
    float frameSpacing = artAreaWidth / nFrames;
 
    pushMatrix();
    translate((i + 0.5) * frameSpacing, 0);
 
    int whichFrame = i; 
    if (bAnimate) {
      whichFrame = (i+myFrameCount)%nFrames;
    }
     drawArtFrame (whichFrame); 
 
 
    popMatrix();
  }
  myFrameCount++;
}
 
 
 
//-------------------------------------------------------
//thank you to golan for the template and examples
void drawArtFrame(int whichFrame) { 
 
  noFill();
  strokeWeight(2);
  stroke(0,0,0);
  float eyeY = map(whichFrame, 0, nFrames-1, 0, artAreaHeight*0.30);
  float eyeLid = map(whichFrame, 0, nFrames-1, artAreaHeight*0.30, 0);
  float irisY = map(whichFrame, 0, nFrames-1, 0, artAreaHeight*0.15);
  float eyebrow = map(whichFrame, 0, nFrames-1, 0, artAreaHeight*0.1);
  float tearY = map(whichFrame, 0, nFrames-1, artAreaHeight*0.7, artAreaHeight*1.1);
  float tearY2 = map(whichFrame, 0, nFrames-1, artAreaHeight*0.9, artAreaHeight*1.2);
 
  //right eye
  fill(255,255,255);
  stroke(0,0,0);
  arc(20, artAreaHeight/2, 30, eyeY, 0, PI);
  stroke(50,100,200);
  strokeWeight(2);
  fill(0,0,0);
  arc(20, artAreaHeight/2+1, 15, irisY, 0, PI);
  stroke(0,0,0);
  strokeWeight(3);
  fill(255,255,255);
  arc(20, artAreaHeight/2-1, 30, eyeLid, 0, PI);
 
 
  //left eye
  fill(255,255,255);
  stroke(0,0,0);
  arc(-20, artAreaHeight/2, 30, eyeY, 0, PI);
  stroke(50,100,200);
  strokeWeight(2);
  fill(0,0,0);
  arc(-20, artAreaHeight/2+1, 15, irisY, 0, PI);
  stroke(0,0,0);
  strokeWeight(3);
  fill(255,255,255);
  arc(-20, artAreaHeight/2-1, 30, eyeLid, 0, PI);
 
  //eyebrows
  strokeWeight(2);
  line(7, -eyebrow+40, 35, 40);
  line(-35, 40, -7, -eyebrow+40);
 
  //sad water
  fill(10,50,200,whichFrame*0.9+200);
  noStroke();
  ellipse(-25, tearY, 2, 10);
  ellipse(-25, tearY2, 2, 10);
}