breep-AnimatedLoop

I ended up using the double exponential sigmoid as I wanted the squares to be able to tend toward the centre point from both sides. I initially had blocked out the squares on rectangles which highlighted where the squares would appear and re-appear, but I didn't like how busy they made the image. Once this had been laid out, I had to adjust the percentage amounts of each square on the sigmoid so that they all paused at that common central point. Once this was done I wanted to incorporate some form of spiral motion, but I wanted it to also be somewhat bi-parted as well to go with the squares, hence the two spiralling arms.

I felt I succeeded with the sigmoid nature of the squares, and am pretty proud of how they as a unit follow a curve, but also individually do. I still think the image is a bit too busy, and I still would've liked to incorporate more circular motion but it would have oversaturated the gif with content I think. The squares don't line up as well as I would like, given that I had to adjust the percentages of the sigmoids by eye so a more mathematic approach to that would make it appear that bit more fluid.

 
// Template used from 60-212 Website 
 
// This is a template for creating a looping animation in p5.js (JavaScript). 
// When you press the 'F' key, this program will export a series of images into
// your default Downloads folder. These can then be made into an animated gif. 
// This code is known to work with p5.js version 0.6.0
// Prof. Golan Levin, 28 January 2018
 
// INSTRUCTIONS FOR EXPORTING FRAMES (from which to make a GIF): 
// 1. Run a local server, using instructions from here:
//    https://github.com/processing/p5.js/wiki/Local-server
// 2. Set the bEnableExport variable to true.
// 3. Set the myNickname variable to your name.
// 4. Run the program from Chrome, press 'f'. 
//    Look in your 'Downloads' folder for the generated frames.
// 5. Note: Retina screens may export frames at twice the resolution.
 
 
//===================================================
// User-modifiable global variables. 
var myNickname = "nickname";
var nFramesInLoop = 120;
var bEnableExport = false;
 
// Other global variables you don't need to touch.
var nElapsedFrames;
var bRecording;
var theCanvas;
 
 
 
//===================================================
function setup() {
  theCanvas = createCanvas(640, 640);
  bRecording = false;
  nElapsedFrames = 0;
  frameRate(120); 
}
 
//===================================================
function keyTyped() {
  if (bEnableExport) {
    if ((key === 'f') || (key === 'F')) {
      bRecording = true;
      nElapsedFrames = 0;
    }
  }
}
 
//===================================================
 
function draw() {
 
  // Compute a percentage (0...1) representing where we are in the loop.
  var percentCompleteFraction = 0;
  if (bRecording) {
    percentCompleteFraction = float(nElapsedFrames) / float(nFramesInLoop);
  } else {
    percentCompleteFraction = float(frameCount % nFramesInLoop) / float(nFramesInLoop);
  }
 
  // Render the design, based on that percentage. 
  // This function renderMyDesign() is the one for you to change. 
  renderMyDesign (percentCompleteFraction);
 
  // If we're recording the output, save the frame to a file. 
  // Note that the output images may be 2x large if you have a Retina mac. 
  // You can compile these frames into an animated GIF using a tool like: 
  if (bRecording && bEnableExport) {
    var frameOutputFilename = myNickname + "_frame_" + nf(nElapsedFrames, 4) + ".png";
    print("Saving output image: " + frameOutputFilename);
    saveCanvas(theCanvas, frameOutputFilename, 'png');
    nElapsedFrames++;
 
    if (nElapsedFrames >= nFramesInLoop) {
      bRecording = false;
    }
  }
} 
 
//===================================================
function renderMyDesign (percent) {
  //
  // THIS IS WHERE YOUR ART GOES. 
  // This is an example of a function that renders a temporally looping design. 
  // It takes a "percent", between 0 and 1, indicating where we are in the loop. 
  // Use, modify, or delete whatever you prefer from this example. 
  // This example uses several different graphical techniques. 
  // Remember to SKETCH FIRST!
 
  //----------------------
  // here, I set the background and some other graphical properties
  background(0);
  smooth();
  stroke(0, 0, 0);
  strokeWeight(0);
 
  //----------------------
  // Here, I assign some handy variables. 
  var cx = 100;
  var cy = 100;
 
  //----------------------
 
  // COLOUR NUMBERS FROM BOTTOM
 
  // ORANGE 1 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(192, 576, 384, 32);   
 
  var eased = doubleExponentialSigmoid (percent, 0.9); 
  eased = (eased + 0.319)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 192, 544); 
  fill (253, 106, 2); 
  rect (xPosition1, 576, 32, 32);     
 
  // ORANGE 2 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(160, 512, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.8); 
  eased = (eased + 0.45)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 160, 480); 
  fill (253, 106, 20); 
  rect (xPosition1, 512, 32, 32);  
 
  // ORANGE 3 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(128, 448, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.6); 
  eased = (eased + 0.5)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 128, 480); 
  fill (253, 106, 2); 
  rect (xPosition1, 448, 32, 32);    
 
  // ORANGE 4 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(192, 384, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.4); 
  eased = (eased + 0.3)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 192, 544); 
  fill (253, 106, 20); 
  rect (xPosition1, 384, 32, 32);     
 
  // ORANGE 5 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(64, 320, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.2); 
  eased = (eased + 0.66)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 64, 416); 
  fill (253, 106, 20); 
  rect (xPosition1, 320, 32, 32);  
 
  // ORANGE 6 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(128, 256, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.2); 
  eased = (eased + 0.47)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 128, 480); 
  fill (253, 106, 20); 
  rect (xPosition1, 256, 32, 32);  
 
  // ORANGE 7 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(224, 192, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.4); 
  eased = (eased + 0.19)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 224, 576); 
  fill (253, 106, 20); 
  rect (xPosition1, 192, 32, 32);  
 
  // ORANGE 8
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(156, 128, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.6); 
  eased = (eased + 0.39)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 156, 508); 
  fill (253, 106, 20); 
  rect (xPosition1, 128, 32, 32);   
 
  // ORANGE 9
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(32, 64, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.8); 
  eased = (eased + 0.73)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 32, 384); 
  fill (253, 106, 20); 
  rect (xPosition1, 64, 32, 32);   
 
  // ORANGE 10
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(128, 0, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.9); 
  eased = (eased + 0.47)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 128, 480); 
  fill (253, 106, 2); 
  rect (xPosition1, 0, 32, 32);        
 
  push();
  translate(320, 320);
  var orange = true; 
  for (var squareX = 0; squareX <= width; squareX += 32){
 
   // Here's a linearly-moving square
   var eased = doubleExponentialSigmoid (percent, 0.5); 
   eased = (eased)%1.0; // shifted by a half-loop, for fun
   var yPosition = map(eased, 0, 1, topY, botY);    
 
   var rotatingSquareAngle = percent * TWO_PI
   rotate(rotatingSquareAngle);  
 
   var squareSize = 20;
   var topY = 0 - squareSize - 2;
   var botY = height + 2;
   var sPercent = (percent)%1.0; // shifted by a half-loop
   // var yPosition = map(sPercent, 0, 1, topY, botY);
 
   if (orange == true){
     fill(253, 106, 2);
     orange = false;}
   else{
    fill(60, 170, 230);
    orange = true;}
 
   rect(squareX, yPosition, 20, 20);}   
  pop();  
 
 
  // BLUE 1 
  // strokeWeight(0);
  // fill(120, 253, 106, 2);
  // rect(128, 608, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.2); 
  eased = (eased + 0.5)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 128, 480); 
  fill (60, 170, 230); 
  rect (xPosition1, 608, 32, 32);   
 
  // BLUE 2 
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(64, 544, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.4); 
  eased = (eased + 0.682)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 64, 416); 
  fill (60, 170, 230); 
  rect (xPosition1, 544, 32, 32);     
 
  // BLUE 3 
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(224, 480, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.6); 
  eased = (eased + 0.23)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 224, 576); 
  fill (60, 170, 230); 
  rect (xPosition1, 480, 32, 32);  
 
  // BLUE 4 
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(32, 416, 384, 32);    
 
  var eased = doubleExponentialSigmoid (percent, 0.8); 
  eased = (eased + 0.77)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 32, 384); 
  fill (60, 170, 230); 
  rect (xPosition1, 416, 32, 32);    
 
  // BLUE 5 
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(160, 352, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.9); 
  eased = (eased + 0.39)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 160, 512); 
  fill (60, 170, 230); 
  rect (xPosition1, 352, 32, 32);     
 
  // BLUE 6 
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(256, 288, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.9); 
  eased = (eased + 0.115)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 256, 608); 
  fill (60, 170, 230); 
  rect (xPosition1, 288, 32, 32);    
 
  // BLUE 7 
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(96, 224, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.8); 
  eased = (eased + 0.56)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 96, 448); 
  fill (60, 170, 230); 
  rect (xPosition1, 224, 32, 32);    
 
 
  // BLUE 8
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(64, 160, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.6); 
  eased = (eased + 0.65)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 64, 416); 
  fill (60, 170, 230); 
  rect (xPosition1, 160, 32, 32);    
 
  // BLUE 9 
  //strokeWeight(0);
  //fill(253, 106, 2);
  // rect(192, 96, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.4); 
  eased = (eased + 0.284)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 192, 544); 
  fill (60, 170, 230); 
  rect (xPosition1, 96, 32, 32);    
 
 
  // BLUE 10
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(192, 32, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.2); 
  eased = (eased + 0.27)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 192, 544); 
  fill (60, 170, 230); 
  rect (xPosition1, 32, 32, 32);   
 
 
 
  push();
  translate(320, 320);
  var orange = true; 
  for (var squareX = 0; squareX <= width; squareX += 32){
 
   // Here's a linearly-moving square
   var eased = doubleExponentialSigmoid (percent, 0.5); 
   eased = (eased)%1.0; // shifted by a half-loop, for fun
   var yPosition = map(eased, 0, 1, topY, botY);    
 
   var rotatingSquareAngle = percent * TWO_PI
   rotate(-rotatingSquareAngle);  
 
   var squareSize = 20;
   var topY = 0 - squareSize - 2;
   var botY = height + 2;
   var sPercent = (percent)%1.0; // shifted by a half-loop
   // var yPosition = map(sPercent, 0, 1, topY, botY);
 
   if (orange == true){
     fill(253, 106, 2);
     orange = false;}
   else{
    fill(60, 170, 230);
    orange = true;}
 
   rect(squareX, yPosition, 20, 20);}   
  pop();      
 
}
 
// Symmetric double-element sigmoid function ('_a' is the slope)
// See https://github.com/IDMNYU/p5.js-func/blob/master/lib/p5.func.js
// From: https://idmnyu.github.io/p5.js-func/
//===================================================
function doubleExponentialSigmoid (_x, _a){
  if(!_a) _a = 0.75; // default
 
  var min_param_a = 0.0 + Number.EPSILON;
  var max_param_a = 1.0 - Number.EPSILON;
  _a = constrain(_a, min_param_a, max_param_a);
  _a = 1-_a;
 
  var _y = 0;
  if (_x<=0.5){
    _y = (pow(2.0*_x, 1.0/_a))/2.0;
  }
  else {
    _y = 1.0 - (pow(2.0*(1.0-_x), 1.0/_a))/2.0;
  }
  return(_y);
}