I don't know why but my computer was having an incredibly hard time exporting my frames -- some were being skipped, and everything was patchy. I had Char help me export and the GIF still ended up being way too slow. Click the link above it or here ( to see it in the p5.js editor. Sorry about this.

Anyway, I am mostly happy with this project. I wish I had had more time to make it more fancy, and a better laptop so that I wouldn't have gotten so frustrated at the lag, but overall I am proud. It took a little while to come up with the idea, but once I knew what I wanted to do, I had to make it happen. Again I had Char talk through the syntax I didn't know, but a lot of it I figured out myself this time. For the easing function, I knew that I was probably going to need one to simulate the "bouncing" of the ball, so I looked for one that matched that motion the most. I went through a couple of them before concluding that the doubleExponentialSigmoid, which Golan had already used in the template, was actually the best one. Having that as a guide was helpful.

I'm proud of myself for having a set idea in mind and then putting in the effort to execute it, even though it was hard. I also really like the simplicity of my GIF. At one point I was about to add some flashing circles in the background, but Char told me that the minimalist-ness of it was what made it so nice. However, I think it is only that way because I hadn't allotted enough time to make it super grand. If I had more time and had known more of the p5.js syntax, I definitely would have made it more complicated.  As you can see in my sketch (bottom left), I started an idea that branched off of the flipping square -- a skillet flipping a pancake. I stopped myself there though, as I knew I probably didn't know enough to do that. I hope I can come back to this project when I have time and make the pancake idea.


// User-modifiable global variables. 
var myNickname = "Cassie";
var nFramesInLoop = 120;
var bEnableExport = true;
// Other global variables you don't need to touch.
var nElapsedFrames;
var bRecording;
var theCanvas;
var canvaswidth = 645;
var canvasheight = 645;
var flipper = false;
function setup() {
  theCanvas = createCanvas(canvaswidth, canvasheight);
  bRecording = false;
  nElapsedFrames = 0;
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');
    if (nElapsedFrames >= nFramesInLoop) {
      bRecording = false;
function renderMyDesign (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. 
  // 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
  var x = abs(cos(percent*TWO_PI))
  var y = doubleExponentialSigmoid(x, 0.25);
  var squish =  map(y, 0, 1, 10, 30);
  // flipping base
  translate(width / 2 + 20*sin(TWO_PI*percent), height-250);
  var flipx = map(-cos(frameCount/9.5), -1, 1, 0, 200);
  if (frameCount % 120 >= 60) {
		fill(200, 100, 200);
  else {
  rect(0, 20, flipx, 200);
  translate(width / 2, height / 2);
  // ball shadow
  var shadowbounce = map(y, 0, 1, 100, 40);
  ellipse(0, shadowbounce, cos(frameCount/20)*20, cos(frameCount/20)*15);
  // ball
	var ballbounce = map(-y,0,1,100,360);
  distance = height - ballbounce;
  ellipse(0, ballbounce, 30, squish);
// Symmetric double-element sigmoid function ('_a' is the slope)
// See
// From:
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;