For my animated loop, I kept the concept simple and straightforward and focused more on the expressiveness of the face. In my loop, I've made a crying face. The eyebrows raise and fall whereas the eyes open and squeeze shut. The lips stretch and thin out as well. The cheeks flush and pale. And finally, a tear drop falls from the left eye.
I think the design is successful as the colors work well together and the gif loops seamlessly. However, I wish I had had more time to create a more complex looping animation. In other words, I succeeded with the simplistic vision I had in mind but wished I had more time to create something more creative and complex.
function renderMyDesign (percent) { background(40, 54, 111); smooth(); // face fill(236, 241, 217); ellipse(width/2, height/2, 520, 530); push(); rectMode(CORNER); rect(0,0,width, 300); pop(); // move everything down a bit translate(0, 120) // cheeks if (percent >= 0 && percent <= 0.5) { var cheekColor = map(percent, 0, 1, 150, 40); } else if (percent > 0.5 && percent <= 1.0) { var cheekColor = map(percent, 0, 1, 40, 150); } fill(251, cheekColor, cheekColor, 80); ellipse(width/2 - 180, 230, 120, 60) ellipse(width/2 + 180, 230, 120, 60) // falling tear var ease = doubleExponentialSigmoid(percent); ease = (ease + 0.3) % 1.0; var r = 15; var x = width/2 - 150; var topY = 220; var botY = height + 30; var yPosition = map(percent, 0, 3, topY, botY); var y = map(ease, 0, 1, topY, botY); var triHeight = 12; // tear shape fill(173, 206, 214); noStroke(); triangle(x - r/2, y, x + r/2, y, x, y - r/2 - triHeight); ellipse(x, y, r - 1, r); // eyes fill(10, 56, 164); stroke(10, 56, 164); var eyeRad = 70 var eyeHeight = 30 if (percent >= 0 && percent <= 0.5) { eyeRad = map(percent, 0, 1, 60, 80); eyeHeight = map(percent, 0, 1,30,10); } else if (percent > 0.5 && percent <= 1.0) { eyeRad = map(percent, 0, 1, 80, 60); eyeHeight = map(percent, 0, 1,10,30); } // left eye push(); translate(-150,-130); beginShape(); vertex(width/2 - eyeRad, height/2); bezier(width/2 - eyeRad, height/2, width/2, height/2 - eyeHeight, width/2, height/2 - eyeHeight, width/2 + eyeRad, height/2); vertex(width/2 + eyeRad, height/2); bezier(width/2 + eyeRad, height/2, width/2, height/2 + eyeHeight, width/2, height/2 + eyeHeight, width/2 - eyeRad, height/2); vertex(width/2 - eyeRad, height/2); endShape(); pop(); // right eye push(); translate(150,-130); beginShape(); vertex(width/2 - eyeRad, height/2); bezier(width/2 - eyeRad, height/2, width/2, height/2 - eyeHeight, width/2, height/2 - eyeHeight, width/2 + eyeRad, height/2); vertex(width/2 + eyeRad, height/2); bezier(width/2 + eyeRad, height/2, width/2, height/2 + eyeHeight, width/2, height/2 + eyeHeight, width/2 - eyeRad, height/2); vertex(width/2 - eyeRad, height/2); endShape(); pop(); // mouth from https://www.openprocessing.org/sketch/464492 push(); fill(184, 36, 58); noStroke(); translate(width/2,350); // var yScale = map(percent, 0, 1, 1.5, 1) // scale(2,yScale) if (percent >= 0 && percent <= 0.5) { var yScale = map(percent, 0, 1, 1.3, 1) scale(2,yScale) } else if (percent > 0.5 && percent <= 1.0) { var yScale = map(percent, 0, 1, 1, 1.3) scale(2,yScale) } beginShape(); vertex(-36,0); bezierVertex(-36,0,-30,-4,-26,-7); bezierVertex(-18,-14,-15,-19,-10,-19); bezierVertex(-8,-20,-4,-20,0,-15); vertex(0,-15); bezierVertex(4,-20,8,-20,10,-19); bezierVertex(15,-19,18,-14,26,-7); bezierVertex(30,-4,34,-1,36,0); vertex(36,0); bezierVertex(35,2,23,19,0,20); bezierVertex(-18,19,-23,13,-27,10); bezierVertex(-30,7,-35, 2,-36,0); endShape(); pop(); // nose fill(192, 205, 148); noStroke(); rectMode(CENTER); rect(width/2, height/2 - 45, 11, 45, 5); //eyebrows fill(167, 12, 73); if (percent >= 0 && percent <= 0.5) { var eyebrowY = map(percent, 0, 1, height/2 - 200, height/2 - 240); } else if (percent > 0.5 && percent <= 1.0) { var eyebrowY = map(percent, 0, 1, height/2 - 240, height/2 - 200); } push(); rectMode(CENTER); rect(width/2 - 150, eyebrowY, 130, 15, 10); pop(); push(); rect(width/2 + 150, eyebrowY, 130, 15, 10); pop(); // hair translate(0,-120); rectMode(CORNER); fill(0); rect(0, 0, 100, height); rect(width-75, 0, 100, height); rect(width-100, 0, 8, height); beginShape(); vertex(0,0); vertex(0, 100); bezierVertex(0,100, 400, 250, 600, 30); vertex(600,40); vertex(600,0); vertex(0,0); endShape(); } // symmetric double-element sigmoid function (a is 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); } |