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