11. Lenticular Animation

A Looping, Computationally-Generated Animated GIF…
…and a Lenticular GIFPOP Print

The looping image, as a medium of artistic expression, occupies a special niche between the static image of photography, and the linearly-advancing, beginning-middle-end format of traditional film and video. It found popularity in the Victorian era in zoetropes and phenakistoscopes (see this great article here from ThisIsColossal)…



… it has found meaning again in classy and poetic cinemagraphs:


…and in an amazingly wide efflorescence of vernacular internet graphics: the animated GIF.

Founded by IACD friends — the computational designer-entrepreneurs Rachel Binx and Sha Hwang — GIFPOP! is a recently Kickstarted enterprise which “creates custom cards from animated GIFs, using the magic of lenticular printing”. In this warm-up exercise, you will write Processing code to create a brief looping animation, using computationally-generated graphics, suitable for both online and lenticular publishing. Then, Rachel and Sha will help us print awesome gifpops!

In this exercise, you will write code that generates a sequence of images suitable for a short looping animation. In particular, you are asked to export the visual results of your code in two versions, with careful attention to specific pixel dimensions and framecounts:

  • A high-resolution (1500×1500) animated GIF, with no more than 10 frames, which will be used to generate a lenticular GIFPOP! print.
  • A low-resolution (500×500) animated GIF, with as many frames as you please, suitable for embedding in a web page. (You can downscale the graphics in your code or in Photoshop, it doesn’t matter.)

Learning Objectives.
This exercise is a prompt to test and hone your craft as a creative technologist. Upon completion of this exercise, you will be able to:

  • Create computational animations using an arts-engineering toolkit*;
  • Prepare animated imagery for publication in GIF and lenticular formats;
  • Conceive and appraise graphical concepts within the constraints of the GIF format.

More details about the project requirements are discussed below. But first…


Some Inspirations

There are a burgeoning number of computational artists and designers who are discovering vast and expressive new worlds in the constraints of this durable format for dynamic imaging. Here’s a list of some leading practitioners; please spend some time with their work:



Before starting, please read the following suggestions.

  1. SKETCH FIRST! Before doing anything, make some (real) sketches in your notebook. Try to come up with graphical concepts.
  2. Your design may be abstract, figurative, etc. according to your tastes.
  3. GIFS are palette-based images, which means that they must represent all of your frames with a single common palette of just 256 colors. For this reason, you may obtain better results with imagery that just uses a small number of colors, or is monochromatic.
  4. In this assignment, you are restricted from using recorded (i.e. photographic and/or video) media, except in interesting combinations with your own computationally-generated graphics.
  5. Export a series of frames, and compile these into an animated GIF. Here is a helpful tutorial for creating animated GIFs from folders of images, using Photoshop. Remember to set its duration to “forever”, and to adjust the frame durations to something appropriate.
  6. Your GIF can be any length, but keeping it under 2MB would be sensible, and there is a hard upload limit of 12MB per file for our WordPress site.
  7. Test out your GIF to make sure it animates as you expect! You can open most animated GIFs with web browsers to test them out.

Our friends at GIFPOP also offer the following suggestions for creating lenticular prints with their system:

  • Looping in 10 frames is great. It makes the effect that much more magical as you don’t get that “seam” of the animation restarting. 
  • There will always be some ghosting in high frame-count lenticular printing. A good way to imagine (or simulate!) this is that every frame you see will have 10-20% opacity visible of the frames on either side.
  • Smooth movements will work well. 10 completely different images won’t be super legible. The “cinematography” here is important: less slam cuts, more long takes.
  • Geometric patterns are great, bright colors work well. Thin lines are harder to see without enough contrast.
  • By default, our 5″x5″ cards are printed so that you rotate them up/down to see them. Left/right rotation gives blurrier animation when your head is close to the card because of the spacing of your eyes, but if you rotate your animation 90 degrees it will print left/right. For example, Jono did this and rotated his; see https://vine.co/v/h0er7X3Z02F

*Joel Simon asked: “Do we have to use Processing?” The answer is “no… but” you are required to work computationally, with code. For this assignment, if you would prefer to work with a different arts-engineering environment, such as openFrameworks, Cinder or Jitter, you may. The key constraint is that you may not create the animated GIF using an animation tool like Flash (unless you’re scripting in ActionScript), Maya (unless you’re scripting in MEL), AfterEffects (unless you’re scripting in MotionScript), Blender (unless you’re scripting in Blender/Python), Houdini (unless you’re scripting in HScript/Python), etcetera.

Instructions & Deliverables

  1. No later than 11:59am (noon) Eastern Time on Tuesday January 21, upload your 1500×1500 animated GIF to GIFPOP. Don’t miss the boat, kids. You will have been given discount codes in class, so you won’t have to pay; these discount codes should all be good for one 5×5″ card each. The discount codes are entered on the second page of the checkout process. You should choose standard shipping, using the address of the Frank-Ratchye STUDIO for Creative Inquiry.
  2. In a blog post, upload and embed your 500×500 animated GIF.
  3. Write a paragraph about the experience of creating the piece. What inspired your design? Critique your work: where do you feel you succeeded? Where do you feel you fell short of what you’d hoped to achieve?
  4. Include a scan or photo of your pen-and-paper sketches.
  5. Embed your Processing code into the blog, using the WP-Syntax plugin. Instructions for doing so are here and here. Note that you may need to switch to the WordPress “Text”-editing mode (not Visual) editing mode at this point. (Otherwise, code with < and > characters can get messed up.)
  6. Label your blog post with the Category, 11-Lenticular-GIF. That’s important!

Here is an animated GIF, and the Processing code template that produced it. iacd-anim-demo

Some things to observe about this animated GIF:

  • It uses a simple color palette.
  • Visual elements move smoothly and in small increments. 
  • It has 30 frames, at 30fps, which looks nice in a webpage. But for Gifpop lenticular prints, you’ll need to export a version which has no more than 10 frames. 
// This is a template for creating a looping animation in Processing. 
// When you press a key, this program will export a series of images
// into an "output" directory located in its sketch folder. 
// These can then be combined into an animated GIF. 
// Prof. Golan Levin, January 2014 - CMU IACD
// Global variables. 
int     nFramesInLoop = 30; // for lenticular export, change this to 10!
int     nElapsedFrames;
boolean bRecording; 
String  myName = "golanlevin";
void setup() {
  size (400, 200); 
  bRecording = false;
  nElapsedFrames = 0;
  frameRate (nFramesInLoop); 
void keyPressed() { 
  // Press a key to export frames to the output folder
  bRecording = true;
  nElapsedFrames = 0;
void draw() {
  // Compute a percentage (0...1) representing where we are in the loop.
  float percentCompleteFraction = 0; 
  if (bRecording) {
    percentCompleteFraction = (float) nElapsedFrames / (float)nFramesInLoop;
  else {
    float modFrame = (float) (frameCount % nFramesInLoop);
    percentCompleteFraction = modFrame / (float)nFramesInLoop;
  // Render the design, based on that percentage. 
  renderMyDesign (percentCompleteFraction);
  // If we're recording the output, save the frame to a file. 
  if (bRecording) {
    saveFrame("output/"+ myName + "-loop-" + nf(nElapsedFrames, 4) + ".png");
    if (nElapsedFrames == nFramesInLoop) {
      bRecording = false;
void renderMyDesign (float percent) {
  // This is an example of a function that renders a temporally looping design. 
  // It takes a "percent", between 0 and 1, indicating where we are in the loop. 
  // This example uses two different graphical techniques. 
  // Use or delete whatever you prefer from this example. 
  // Remember to SKETCH FIRST!
  // here, I set the background and some other graphical properties
  background (180);
  stroke (0, 0, 0); 
  strokeWeight (2); 
  // Here, I assign some handy variables. 
  float cx = 100;
  float cy = 100;
  // Here, I use trigonometry to render a rotating element.
  float radius = 80; 
  int nSpokes = 7; 
  for (int i=0; i < nSpokes; i++) {
    float armAngle = (percent + i) * (TWO_PI/nSpokes); 
    float px = cx + radius*cos(armAngle); 
    float py = cy + radius*sin(armAngle); 
    fill    (255); 
    line    (cx, cy, px, py); 
    ellipse (px, py, 20, 20);
  // Here, I use graphical transformations 
  // to render a rotated square. 
  translate (cx, cy);
  float rotatingSquareAngle =  percent * TWO_PI * -0.25;
  rotate (rotatingSquareAngle); 
  fill (255, 128); 
  rect (-40, -40, 80, 80);
  // Here's a set of linearly-moving circles
  float ballSize = 20;
  float topY = 0 - ballSize - 2;
  float botY = height;
  float spanY = botY - topY; 
  int nMovingBalls = 5; 
  for (int i=0; i <= nMovingBalls; i++) {
    float ballSpacing = spanY / (float)nMovingBalls;
    float yBase = topY + ballSize/2; // offset for radius of ball 
    float yPercent = map(percent, 0, 1, topY, topY+ballSpacing);
    float yPosition = yBase + (yPercent + (i*ballSpacing))%spanY; 
    fill (255, 255, 255); 
    ellipse (250, yPosition, ballSize, ballSize);
  // Here's a pulsating ellipse
  float ellipsePulse = cos ( percent * TWO_PI); 
  float ellipseW = map(ellipsePulse, -1, 1, 20.0, 80.0); 
  float ellipseH = map(ellipsePulse, -1, 1, 80.0, 20.0); 
  float ellipseColor = map(ellipsePulse, -1, 1, 0, 255); 
  fill (ellipseColor, ellipseColor, ellipseColor); 
  ellipse (340, cy, ellipseW, ellipseH); 
  fill (0, 0, 0);
  textAlign (CENTER); 
  String percentDisplayString = nf(percent, 1, 3);
  text (percentDisplayString, 340, 40);