Spoon-Scope

 

This design takes the bouncing rectangle design from my GIF and applies it to the format of a praxinoscope. The side ratios are slightly different, adjusted only so the rectangle would fill the frame well. The motion in the rectangle is fluid as it uses the same adjustable center cosine window function that is used in the GIF for the rectangle.

See my GIF post for sketches.

praxinoscope-output

 

 

// 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;
 
//-------------------------------------------------------
void setup() {
  size(792, 612); // 11x8.5" at 72DPI
  frameRate(15);
  smooth();
} 
 
//-------------------------------------------------------
void draw() {
  background(240); 
  if (bRecordingPDF) {
    beginRecord(PDF, "praxinoscope-output.pdf");
  }
 
  // Do all the drawing. 
  pushMatrix(); 
  translate(width/2, height/2);
  drawCutLines(); 
  drawGuides(); 
  drawAllFrames();
  popMatrix();
 
  if (bExportFrameImages) {
    // If activated, export .PNG frames 
    if (exportFrameCount < nFrames) { String filename = "frame_" + nf((exportFrameCount%nFrames), 3) + ".png"; saveFrame("frames/" + filename); println("Saved: " + filename); exportFrameCount++; if (exportFrameCount >= nFrames) {
        bExportFrameImages = false;
        exportFrameCount = 0;
      }
    }
  }
 
  if (bRecordingPDF) {
    endRecord();
    bRecordingPDF = false;
  }
}
 
 
//-------------------------------------------------------
void keyPressed() {
  switch (key) {
  case ' ': 
    // Press spacebar to pause/unpause the animation. 
    bAnimate = !bAnimate;
    break;
 
  case 'p': 
  case 'P':
    // Press 'p' to export a PDF for the Praxinoscope.
    bRecordingPDF = true; 
    break;
 
  case 'f': 
  case 'F': 
    // Press 'f' to export .png Frames (to make an animated .GIF)
    myFrameCount = 0; 
    exportFrameCount = 0; 
    bExportFrameImages = true;
    bAnimate = true; 
    break;
  }
}
 
//-------------------------------------------------------
void drawCutLines() {
  fill(0); 
  textAlign(CENTER, BOTTOM); 
  text("Praxinoscope Template", 0, 0-diamCutOuter/2-6); 
 
  stroke(0); 
  strokeWeight(1.0);
 
  noFill(); 
  if (!bRecordingPDF) {
    fill(255); 
  }
  ellipse(0, 0, diamCutOuter, diamCutOuter);
 
  noFill(); 
  if (!bRecordingPDF) {
    fill(240); 
  }
  ellipse(0, 0, diamCutInner, diamCutInner);
 
  noFill(); 
  ellipse(diamCutOuter/2 - holeDx, 0-holeDy, holeD, holeD); 
 
  line (diamCutInner/2, 0, diamCutOuter/2, 0);
}
 
//-------------------------------------------------------
void drawGuides() {
  // This function draws the guidelines. 
  // Don't draw these when we're exporting the PDF. 
  if (!bRecordingPDF) {
 
    noFill(); 
    stroke(128); 
    strokeWeight(0.2); 
    ellipse(0, 0, diamArtInner, diamArtInner); 
    ellipse(0, 0, diamArtOuter, diamArtOuter);
 
    for (int i=0; i<nFrames; i++) {
      float angle = map(i, 0, nFrames, 0, TWO_PI); 
      float pxi = diamArtInner/2 * cos(angle);
      float pyi = diamArtInner/2 * sin(angle);
      float pxo = diamArtOuter/2 * cos(angle);
      float pyo = diamArtOuter/2 * sin(angle);
      stroke(128); 
      strokeWeight(0.2);
      line (pxi, pyi, pxo, pyo);
    }
 
    // Draw the red wedge outline, highlighting the main view.
    int redWedge = 7; // assuming nFrames = 10
    for (int i=redWedge; i<=(redWedge+1); i++) {
      float angle = map(i, 0, nFrames, 0, TWO_PI); 
      float pxi = diamArtInner/2 * cos(angle);
      float pyi = diamArtInner/2 * sin(angle);
      float pxo = diamArtOuter/2 * cos(angle);
      float pyo = diamArtOuter/2 * sin(angle);
      stroke(255, 0, 0); 
      strokeWeight(2.0);
      line (pxi, pyi, pxo, pyo);
    }
    noFill(); 
    stroke(255, 0, 0); 
    strokeWeight(2.0);
    float startAngle = redWedge*TWO_PI/nFrames;
    float endAngle = (redWedge+1)*TWO_PI/nFrames;
    arc(0, 0, diamArtInner, diamArtInner, startAngle, endAngle); 
    arc(0, 0, diamArtOuter, diamArtOuter, startAngle, endAngle); 
 
 
    for (int i=0; i<nFrames; i++) {
      float angle = map(i, 0, nFrames, 0, TWO_PI); 
 
      pushMatrix();
      rotate(angle); 
      float originY = ((diamArtOuter + diamArtInner)/2)/2;
      translate(0, 0-originY); 
 
      noFill(); 
      stroke(128); 
      strokeWeight(0.2);
      line (-inch/2, 0, inch/2, 0); 
      line (0, -inch/2, 0, inch/2); 
 
      popMatrix();
    }
  }
}
 
//-------------------------------------------------------
void drawAllFrames() {
  for (int i=0; i<nFrames; i++) {
    float angle = map(i, 0, nFrames, 0, TWO_PI); 
    float originY = ((diamArtOuter + diamArtInner)/2)/2;
 
    pushMatrix();
    rotate(angle); 
    translate(0, 0-originY); 
    scale(0.8, 0.8); // feel free to ditch this 
 
    int whichFrame = i; 
    if (bAnimate) {
      whichFrame = (i+myFrameCount)%nFrames;
    }
    drawArtFrame (whichFrame); 
    // drawArtFrameAlternate (whichFrame); 
 
    popMatrix();
  }
  myFrameCount++;
}
 
 
//-------------------------------------------------------
void drawArtFrame (int whichFrame) { 
  // Draw the artwork for a generic frame of the Praxinoscope, 
  // given the framenumber (whichFrame) out of nFrames.
  // NOTE #1: The "origin" for the frame is in the center of the wedge.
  // NOTE #2: Remember that everything will appear upside-down!
 
  fill(0); 
  noStroke(); 
 
  float multiplier2 = function_AdjustableCenterCosineWindow(
                                              map(whichFrame, 
                                              0, nFrames, 0, 1), 
                                              0.3);
  drawCenteredRectangleFromBottom(0, 30, 
                                  map(multiplier2, 0, 1, 35, 65),
                                  map(multiplier2, 0, 1, 100, 50));
  noFill();
  stroke(255);
  strokeWeight(5);
}
 
//-------------------------------------------------------
 
void drawCenteredRectangleFromBottom(float x, float y, 
                            float width, float height) {
  float upperLeftX = x - (width / 2);
  float upperLeftY = height - y;
  rect(upperLeftX, upperLeftY, width, -height);
}
 
float function_AdjustableCenterCosineWindow (float x, float a) {
  // functionName = "Adjustable Center Cosine Window";
 
  float ah = a/2.0; 
  float omah = 1.0 - ah;
 
  float y = 1.0;
  if (x <= a) {
    y = 0.5 * (1.0 + cos(PI* ((x/a) - 1.0)));
  } 
  else {
    y = 0.5 * (1.0 + cos(PI* (((x-a)/(1.0-a))  )));
  } 
  return y;
}

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

airsun-Scope

For this project, I was new to Java, so I first spent a while trying to learn the syntax. After finding out the syntax shared many similarities with Javascript, I started by experimenting with different ideas and see how it will turn out visually. The idea of the scope is to demonstrate four fingers of a hand, facing downwards, and scratching a surface. The index is the moving and looping object and it will always leave a scratch mark.

Preparatory hand-drawn sketches of my design:

The PNG file:

The loop 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 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;
 
//-------------------------------------------------------
void setup() {
  size(792, 612); // 11x8.5" at 72DPI
  frameRate(15);
  smooth();
} 
 
//-------------------------------------------------------
void draw() {
  background(240); 
  if (bRecordingPDF) {
    beginRecord(PDF, "praxinoscope-output.pdf");
  }
 
  // Do all the drawing. 
  pushMatrix(); 
  translate(width/2, height/2);
  drawCutLines(); 
  drawGuides(); 
  drawAllFrames();
  popMatrix();
 
  if (bExportFrameImages) {
    // If activated, export .PNG frames 
    if (exportFrameCount &lt; nFrames) { String filename = "frame_" + nf((exportFrameCount%nFrames), 3) + ".png"; saveFrame("frames/" + filename); println("Saved: " + filename); exportFrameCount++; if (exportFrameCount &gt;= 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&lt;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&lt;=(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&lt;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&lt;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); 
 
  // Draw some expanding boxes, centered on the local origin
  int nBoxes = 32;
 
  float ry=0;
  float rx=14;
  float rs=11;
  float W1 = whichFrame%nBoxes;
  float Yoffset = 15;
  stroke(0);
  strokeWeight(2.5);
  line(-45,ry, 45,ry);
 
  fill(0);
  strokeWeight(1);
  line(0-rx-2, ry, 0-rx-2, ry+40);
  ellipse(0-rx-2, ry+(W1), rs, rs*5);
  ellipse(0, ry, rs, rs*5);
  ellipse(rx, ry, rs, rs*5);
  ellipse(rx*2, ry, rs, rs*5);
  pushMatrix();
  rotate((7*PI)/4);
  ellipse(18, -3, 10, 35);
  ellipse(28, 8, 10, 35);
  popMatrix();
  pushMatrix();
  rotate((13*PI)/7);
  ellipse(36, 5, 10, 30);
  popMatrix();
 
  fill(255);
  noStroke();
  rect(0-rx-5, ry+(W1)+Yoffset,6.7,8,15,15,45,45);
  fill(200,200,200);
  stroke(255);
  strokeWeight(1);
  line(0-rx-2-rs/4, ry+(W1)+Yoffset-4, 0-rx-2+rs/4, ry+(W1)+Yoffset-4);
  line(0-rx-2-rs/4, ry+(W1)+Yoffset-6, 0-rx-2+rs/4, ry+(W1)+Yoffset-6);
 
  for (int i=0; i&lt;3; i++){
    fill(255);
    rect(-3+14*i, ry+Yoffset,6.7,8,15,15,45,45);
    line(3+14*i, ry+Yoffset-4, 0-rs/4+14*i, ry+Yoffset-4);
    line(3+14*i, ry+Yoffset-6, 0-rs/4+14*i, ry+Yoffset-6);
  }
 
 
}
 
//-------------------------------------------------------
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&lt;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);
}

shuann-Scope

PDF file: shuann-praxinoscope-output

For this exercise I wanted to practice using sin/cos function to create wave patterns so I explored some aspects of that. I also played a little with rotation, transformation, push, pop, and scaling. One challenge I found that it is harder to design for a very limited space. Also, since this is my first time using processing I also tried to familiarized myself with the syntax and the available built-in functions. The good thing is that I did find that it is very similar to javascript which saved my a lot of time.

 

// 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;
 
//-------------------------------------------------------
void setup() {
  size(792, 612); // 11x8.5" at 72DPI
  frameRate(15);
  smooth();
} 
 
//-------------------------------------------------------
void draw() {
  background(240); 
  if (bRecordingPDF) {
    beginRecord(PDF, "praxinoscope-output.pdf");
  }
 
  // Do all the drawing. 
  pushMatrix(); 
  translate(width/2, height/2);
  drawCutLines(); 
  drawGuides(); 
  drawAllFrames();
  popMatrix();
 
  if (bExportFrameImages) {
    // If activated, export .PNG frames 
    if (exportFrameCount < nFrames) {
      String filename = "frame_" + nf((exportFrameCount%nFrames), 3) + ".png";
      saveFrame("frames/" + filename);
      println("Saved: " + filename); 
      exportFrameCount++;
      if (exportFrameCount >= nFrames) {
        bExportFrameImages = false;
        exportFrameCount = 0;
      }
    }
  }
 
  if (bRecordingPDF) {
    endRecord();
    bRecordingPDF = false;
  }
}
 
 
//-------------------------------------------------------
void keyPressed() {
  switch (key) {
  case ' ': 
    // Press spacebar to pause/unpause the animation. 
    bAnimate = !bAnimate;
    break;
 
  case 'p': 
  case 'P':
    // Press 'p' to export a PDF for the Praxinoscope.
    bRecordingPDF = true; 
    break;
 
  case 'f': 
  case 'F': 
    // Press 'f' to export .png Frames (to make an animated .GIF)
    myFrameCount = 0; 
    exportFrameCount = 0; 
    bExportFrameImages = true;
    bAnimate = true; 
    break;
  }
}
 
//-------------------------------------------------------
void drawCutLines() {
  fill(0); 
  textAlign(CENTER, BOTTOM); 
  text("Praxinoscope Template", 0, 0-diamCutOuter/2-6); 
 
  stroke(0); 
  strokeWeight(1.0);
 
  noFill(); 
  if (!bRecordingPDF) {
    fill(255); 
  }
  ellipse(0, 0, diamCutOuter, diamCutOuter);
 
  noFill(); 
  if (!bRecordingPDF) {
    fill(240); 
  }
  ellipse(0, 0, diamCutInner, diamCutInner);
 
  noFill(); 
  ellipse(diamCutOuter/2 - holeDx, 0-holeDy, holeD, holeD); 
 
  line (diamCutInner/2, 0, diamCutOuter/2, 0);
}
 
//-------------------------------------------------------
void drawGuides() {
  // This function draws the guidelines. 
  // Don't draw these when we're exporting the PDF. 
  if (!bRecordingPDF) {
 
    noFill(); 
    stroke(128); 
    strokeWeight(0.2); 
    ellipse(0, 0, diamArtInner, diamArtInner); 
    ellipse(0, 0, diamArtOuter, diamArtOuter);
 
    for (int i=0; i<nFrames; i++) {
      float angle = map(i, 0, nFrames, 0, TWO_PI); 
      float pxi = diamArtInner/2 * cos(angle);
      float pyi = diamArtInner/2 * sin(angle);
      float pxo = diamArtOuter/2 * cos(angle);
      float pyo = diamArtOuter/2 * sin(angle);
      stroke(128); 
      strokeWeight(0.2);
      line (pxi, pyi, pxo, pyo);
    }
 
    // Draw the red wedge outline, highlighting the main view.
    int redWedge = 7; // assuming nFrames = 10
    for (int i=redWedge; i<=(redWedge+1); i++) {
      float angle = map(i, 0, nFrames, 0, TWO_PI); 
      float pxi = diamArtInner/2 * cos(angle);
      float pyi = diamArtInner/2 * sin(angle);
      float pxo = diamArtOuter/2 * cos(angle);
      float pyo = diamArtOuter/2 * sin(angle);
      stroke(255, 0, 0); 
      strokeWeight(2.0);
      line (pxi, pyi, pxo, pyo);
    }
    noFill(); 
    stroke(255, 0, 0); 
    strokeWeight(2.0);
    float startAngle = redWedge*TWO_PI/nFrames;
    float endAngle = (redWedge+1)*TWO_PI/nFrames;
    arc(0, 0, diamArtInner, diamArtInner, startAngle, endAngle); 
    arc(0, 0, diamArtOuter, diamArtOuter, startAngle, endAngle); 
 
 
    for (int i=0; i<nFrames; i++) {
      float angle = map(i, 0, nFrames, 0, TWO_PI); 
 
      pushMatrix();
      rotate(angle); 
      float originY = ((diamArtOuter + diamArtInner)/2)/2;
      translate(0, 0-originY); 
 
      noFill(); 
      stroke(128); 
      strokeWeight(0.2);
      line (-inch/2, 0, inch/2, 0); 
      line (0, -inch/2, 0, inch/2); 
 
      popMatrix();
    }
  }
}
 
//-------------------------------------------------------
void drawAllFrames() {
  for (int i=0; i<nFrames; i++) {
    float angle = map(i, 0, nFrames, 0, TWO_PI); 
    float originY = ((diamArtOuter + diamArtInner)/2)/2;
 
    pushMatrix();
    rotate(angle); 
    translate(0, 0-originY); 
    scale(0.8, 0.8); // feel free to ditch this 
 
    int whichFrame = i; 
    if (bAnimate) {
      whichFrame = (i+myFrameCount)%nFrames;
    }
    drawArtFrame (whichFrame); 
    // drawArtFrameAlternate (whichFrame); 
 
    popMatrix();
  }
  myFrameCount++;
}
 
 
//-------------------------------------------------------
void drawArtFrame (int whichFrame) { 
  // Draw the artwork for a generic frame of the Praxinoscope, 
  // given the framenumber (whichFrame) out of nFrames.
  // NOTE #1: The "origin" for the frame is in the center of the wedge.
  // NOTE #2: Remember that everything will appear upside-down!
 
  pushMatrix();
  noStroke();
  strokeWeight(1); 
  translate(0, 40);
  float t = map(whichFrame, 0, nFrames, 0, 1); 
  float factor = map(cos(t*TWO_PI), -1, 1, 0.3, 1); 
  float col = map(t, 0, 1, 120, 0); 
  fill(col);
  scale(factor, factor);
  triangle(0, -15, 10, 0, -10, 0); 
  triangle(10, 0, 20, 15, 0, 15); 
  triangle(-10, 0, 0, 15, -20, 15); 
  popMatrix();
 
  pushMatrix();
  translate(0, -35);
  noFill();
  stroke(0);
  float ang = map(t, 0, nFrames, 0, TWO_PI); 
  rotate(ang); 
  for (int j=0; j<10; j++){
    rotate(radians(36));
    ellipse(15, 0, 12, 5);
  }
  endShape();
  popMatrix();
 
  //draw waves
  pushMatrix();
  translate(0, 10);
  beginShape(POINTS);
  stroke(0);
  for (int i=0; i<70; i++){
    float h = 0 - map(i, 0, 69, 0, 1);
    if (whichFrame%nFrames<5){
      vertex(i - 35, 18 * cos(h * TWO_PI) + whichFrame);
    } else {
      vertex(i - 35, 18 * cos(h * TWO_PI) + (9-whichFrame));
    }
  }
  endShape();
  popMatrix();
}
 
//-------------------------------------------------------
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);
}

.

dinkolas-Scope

Design PDF: dinkolas-praxinoscope-output

About

I wanted to create a caterpillar-like creature for my praxinoscope. Most of the motion was simple enough, just sines and cosines with offset phases took care of it. However, it took some tricks that I'm pretty happy with to implement knees and a ground. The location of the knees is found by intersecting two circles, one centered at the hip and the other centered at the foot (thanks to johannesvalks on Stack Exchange for the equations for circle intersection). In order for there to be a ground, the feet move in a circle except the y coordinate is clipped to a minimum value. The code is pretty rough, but it works!

Code

I used Golan's Java Processing template. Here's my code in drawArtFrame():

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!
 
  //Intersection of two circles from johannesvalks on Stack Exchange
  stroke(128);
  strokeWeight(1);
  line(50,-29,-50,-29);
  stroke(0);
  strokeWeight(2);
  fill(0);
  float t = map(whichFrame, 0, nFrames, 0, 1); 
  float segments = 6;
  for (float i = 0; i &lt; segments; i++)
  {
    float x1 = map(i,0,segments-1,-35,35);
    x1 += map(-sin(t*TWO_PI-i+.75),-1,1,-1,1);
    float y1 = map(cos(t*TWO_PI-i),-1,1,-10,0);
    ellipse(x1,y1,15,15);
    float x2 = map(-cos(t*TWO_PI-i),-1,1,x1+5,x1-5);
    float y2 = map(sin(t*TWO_PI-i),-1,1,-30,-20);
    y1 -= 15/2;
    y2 = max(y2,-27);
    float mult = sqrt(2*20/(pow((x1-x2),2)+pow((y1-y2),2)));
    float kneexLoc = ((x1+x2)+mult*(y2-y1))/2;
    float kneeyLoc = ((y1+y2)+mult*(x1-x2))/2;
    line(x1,y1,kneexLoc,kneeyLoc);
    line(kneexLoc,kneeyLoc,x2,y2);
    rect(x2-4,y2,4,1);
 
    x2 = map(-cos(t*TWO_PI-i+2.5),-1,1,x1+5,x1-5);
    y2 = map(sin(t*TWO_PI-i+2.5),-1,1,-30,-20);
    y2 = max(y2,-27);
    kneexLoc = ((x1+x2)+mult*(y2-y1))/2;
    kneeyLoc = ((y1+y2)+mult*(x1-x2))/2;
    line(x1,y1,kneexLoc,kneeyLoc);
    line(kneexLoc,kneeyLoc,x2,y2);
    rect(x2-4,y2,4,1);
  }
 
}

 

Sepho-Scope

For my loop I chose to do a pretty simple pulse design that travels around the ring. I made it using a line connecting multiple vertices.

chromsan-Scope

PDF: praxinoscope-output

This design is essentially four triangles whose top point moves towards the center. I made it as a practice for my main GIF, which uses this same effect. I experimented with coloring the triangles, but in the end settled for a black and white combination, which sort of gives the illusion of a 3D space. The triangles move with an easing function so they close faster than they open, which gives a more interesting movement than just a constant open and close.

The relevant code, inserted into the praxinoscope template:

void drawArtFrame (int whichFrame) { 
 
  int height = 40;
  int width = 40;
  translate(-20, -20);
 
  if (whichFrame &lt;= nFrames/2){
    // close quickly 
    float eased = function_DoubleExponentialSigmoid(map(whichFrame, 0, nFrames/2, 0, 1), 0.7);
    fill(50);
    triangle(0, height, width, height, width/2, map(eased, 0, 1, height, height/2 ));
    fill(100);
    triangle(0, 0, 0, height, width/2 * map(eased, 0, 1, 0, 1), height/2);
    fill(150);
    triangle(0, 0, width, 0, width/2, height/2 * map(eased, 0, 1, 0, 1));
    fill(200);
    triangle(width, 0, width, height, map(eased, 0, 1, width, width/2), height/2); 
 
  } else {
    // open slowly
    float eased = function_DoubleExponentialSigmoid(map(whichFrame, nFrames/2, nFrames, 0, 1), 0.05);
    fill(50);
    triangle(0, height, width, height, width/2, map(eased, 0, 1, height/2, height ));
    fill(100);
    triangle(0, 0, 0, height, width/2 * map(eased, 0, 1, 1, 0), height/2);
    fill(150);
    triangle(0, 0, width, 0, width/2, height/2 * map(eased, 0, 1, 1, 0));
    fill(200);
    triangle(width, 0, width, height, map(eased, 0, 1, width/2, width), height/2); 
  }
}
 
// Taken from https://github.com/golanlevin/Pattern_Master
float function_DoubleExponentialSigmoid (float x, float a) {
  // functionName = "Double-Exponential Sigmoid";
 
  float min_param_a = 0.0 + EPSILON;
  float max_param_a = 1.0 - EPSILON;
  a = constrain(a, min_param_a, max_param_a); 
  a = 1-a;
 
  float 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;
}

 

 

ocannoli-Scope

Scope GIF:

Description:

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

Scope PDF:

ocannoli-praxinoscope-output

Scope Code:

import processing.pdf.*;
boolean bRecordingPDF = false;
 
float inch = 72; 
float diamArtInner = inch * 1.50; 
float diamArtOuter = inch * 4.80; 
float diamCutInner = inch * 1.41; 
float diamCutOuter = inch * 4.875; 
float holeDy = inch * 0.23;
float holeDx = inch * 0.20;
float holeD = inch * 0.1;
 
final int nFrames = 10; 
int myFrameCount = 0;
int exportFrameCount = 0; 
boolean bAnimate = true; 
boolean bExportFrameImages = false;
 
//-------------------------------------------------------
void setup() {
  size(792, 612); // 11x8.5" at 72DPI
  frameRate(15);
  smooth();
} 
 
//-------------------------------------------------------
void draw() {
  background(240); 
  if (bRecordingPDF) {
    beginRecord(PDF, "praxinoscope-output.pdf");
  }
 
  // Do all the drawing. 
  pushMatrix(); 
  translate(width/2, height/2);
  drawCutLines(); 
  drawGuides(); 
  drawAllFrames();
  popMatrix();
 
  if (bExportFrameImages) {
    // If activated, export .PNG frames 
    if (exportFrameCount &lt; nFrames) { String filename = "frame_" + nf((exportFrameCount%nFrames), 3) + ".png"; saveFrame("frames/" + filename); println("Saved: " + filename); exportFrameCount++; if (exportFrameCount &gt;= 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&lt;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&lt;=(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&lt;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&lt;nFrames; i++) {
    float angle = map(i, 0, nFrames, 0, TWO_PI); 
    float originY = ((diamArtOuter + diamArtInner)/2)/2;
 
    pushMatrix();
    rotate(angle); 
    translate(0, 0-originY); 
    scale(0.8, 0.8); // feel free to ditch this 
 
    int whichFrame = i; 
    if (bAnimate) {
      whichFrame = (i+myFrameCount)%nFrames;
    }
    drawArtFrame (whichFrame); 
    // drawArtFrameAlternate (whichFrame); 
 
    popMatrix();
  }
  myFrameCount++;
}
 
 
//-------------------------------------------------------
void drawArtFrame (int whichFrame) { 
  // Draw the artwork for a generic frame of the Praxinoscope, 
  // given the framenumber (whichFrame) out of nFrames.
  // NOTE #1: The "origin" for the frame is in the center of the wedge.
  // NOTE #2: Remember that everything will appear upside-down!
 
  // Draw the frame number
  fill(0); 
  noStroke(); 
 
  // Draw a pulsating ellipse
  noFill(); 
  stroke(0);
  strokeWeight(1); 
  float t = map(whichFrame, 0, nFrames, 0, 1); 
  float diam = map(cos(t*TWO_PI), -1, 1, 25, 50); 
  ellipse(0, 0, diam, diam); 
 
  //rotating circle
  float radius = diam/2; 
  float rotatingArmAngle = (whichFrame*.1) * TWO_PI; 
  float px = 0 + radius*cos(rotatingArmAngle); 
  float py = 0 + radius*sin(rotatingArmAngle); 
  fill    (0); 
  stroke(51);
  ellipse(px, py, 8, 8);
 
  //rotating circle
  float rotatingArmAngle2 = (whichFrame*.1) * TWO_PI; 
  float px2 = 15 + radius*cos(rotatingArmAngle2); 
  float py2 = 15 + radius*sin(rotatingArmAngle2); 
  fill    (0); 
  stroke(51);
  ellipse(-px2, -py2, 8, 8);
 
  float px3 = -12 + radius*cos(rotatingArmAngle2); 
  float py3 = -20 + radius*sin(rotatingArmAngle2); 
  fill    (0); 
  stroke(51);
  ellipse(-px3, -py3, 8, 8);
 
  //rect figure
  float amplitude=100;
  float f=.1;
  float xR=160;
  float yR=(160)+amplitude*sin(f*whichFrame);
  rect(xR,yR,10,10); 
}
//-------------------------------------------------------
void drawArtFrameAlternate(int whichFrame) { 
  // An alternate drawing test. 
  // Draw a falling object. 
 
 
  // Draw a little splat on the frame when it hits the ground. 
  if (whichFrame == (nFrames-1)) {
    stroke(0, 0, 0); 
    strokeWeight(0.5); 
    int nL = 10;
    for (int i=0; i&lt;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);
}