A10 ·
The Core
html,
body {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
overflow: hidden;
background-color: #361D48;
} function Cuboid(s, col, off, time) {
this.s = s;
this.col = col;
this.off = off;
this.start = 0;
this.time = time;
this.now = [
new p5.Vector(0, 0),
new p5.Vector(0, 0),
new p5.Vector(0, 0),
new p5.Vector(0, 0),
new p5.Vector(0, 0),
new p5.Vector(0, 0)
];
var o_x = this.off * cos(PI/3);
var o_y = this.off * sin(PI/3);
this.delta = [
new p5.Vector(- 1.25 * o_x, 1.25 * o_y),
new p5.Vector(1.25 * o_x, - 1.25 * o_y),
new p5.Vector(1.25 * o_x, - 1.25 * o_y),
new p5.Vector(1.25 * o_x, - 1.25 * o_y),
new p5.Vector(- 1.25 * o_x, 1.25 * o_y),
new p5.Vector(- 1.25 * o_x, 1.25 * o_y)
];
this.startPos = [
new p5.Vector(-s + 0.25 * o_x, - 0.25 * o_y),
new p5.Vector(-s + s * cos(PI/3) - 0.25 * o_x, 0.25 * o_y - s * sin(PI/3)),
new p5.Vector(s * cos(PI/3) - 0.25 * o_x, 0.25 * o_y - s * sin(PI/3)),
new p5.Vector(s - 0.25 * o_x, 0.25 * o_y),
new p5.Vector(s * cos(PI/3) + 0.25 * o_x, - 0.25 * o_y + s * sin(PI/3)),
new p5.Vector(-s + s * cos(PI/3) + 0.25 * o_x, - 0.25 * o_y + s * sin(PI/3))
];
this.reset();
}
Cuboid.prototype.run = function() {
this.update();
this.render();
};
Cuboid.prototype.impulse = function() {
this.reset();
this.start = frameCount;
};
Cuboid.prototype.update = function() {
if (frameCount < this.start + this.time) {
for (var i = this.now.length - 1; i >= 0; i--) {
this.now[i].x = bounce(frameCount - this.start, this.startPos[i].x, this.delta[i].x, this.time);
this.now[i].y = bounce(frameCount - this.start, this.startPos[i].y, this.delta[i].y, this.time);
}
}
};
Cuboid.prototype.reset = function() {
for (var i = this.now.length - 1; i >= 0; i--) {
this.now[i] = this.startPos[i].get();
// this.now[i].x = this.startPos[i].x + this.delta[i].x;
// this.now[i].y = this.startPos[i].y + this.delta[i].y;
};
}
Cuboid.prototype.render = function() {
noStroke();
fill(this.col);
beginShape();
for (var i = 0; i < this.now.length; i++) {
vertex(this.now[i].x, this.now[i].y);
};
endShape(CLOSE);
};
var delta;
var s = 120;
var start = 0;
var time = 60;
var gradSize;
var startPos;
var cuboids;
var now = [
new p5.Vector(0, 0),
new p5.Vector(0, 0),
new p5.Vector(0, 0),
new p5.Vector(0, 0),
new p5.Vector(0, 0),
new p5.Vector(0, 0)
];
var purple, pink, orange;
// -------------
// Setup
// -------------
function setup() {
createCanvas(windowWidth, windowHeight);
purple = color(54,29,72);
pink = color(252,23,125);
orange = color(253,125,36);
fill(pink);
var o_x = 80 * cos(PI/3);
var o_y = 80 * sin(PI/3);
gradSize = 2 * (s + o_x + 80 * cos(PI/3));
delta = [
// new p5.Vector(-s - o_x, o_y),
// new p5.Vector(-s + s * cos(PI/3) + o_x, - o_y - s * sin(PI/3)),
// new p5.Vector(s * cos(PI/3) + o_x, - o_y - s * sin(PI/3)),
// new p5.Vector(s + o_x, - o_y),
// new p5.Vector(s * cos(PI/3) - o_x, o_y + s * sin(PI/3)),
// new p5.Vector(-s + s * cos(PI/3) - o_x, o_y + s * sin(PI/3))
new p5.Vector(- o_x, o_y),
new p5.Vector(o_x, - o_y),
new p5.Vector(o_x, - o_y),
new p5.Vector(o_x, - o_y),
new p5.Vector(- o_x, o_y),
new p5.Vector(- o_x, o_y)
];
startPos = [
// new p5.Vector(0, 0),
// new p5.Vector(0, 0),
// new p5.Vector(0, 0),
// new p5.Vector(0, 0),
// new p5.Vector(0, 0),
// new p5.Vector(0, 0)
new p5.Vector(-s, 0),
new p5.Vector(-s + s * cos(PI/3), - s * sin(PI/3)),
new p5.Vector(s * cos(PI/3), - s * sin(PI/3)),
new p5.Vector(s, 0),
new p5.Vector(s * cos(PI/3), s * sin(PI/3)),
new p5.Vector(-s + s * cos(PI/3), s * sin(PI/3))
// new p5.Vector(-s + o_x, - o_y),
// new p5.Vector(-s + s * cos(PI/3) - o_x, o_y - s * sin(PI/3)),
// new p5.Vector(s * cos(PI/3) - o_x, o_y - s * sin(PI/3)),
// new p5.Vector(s - o_x, o_y),
// new p5.Vector(s * cos(PI/3) + o_x, - o_y + s * sin(PI/3)),
// new p5.Vector(-s + s * cos(PI/3) + o_x, - o_y + s * sin(PI/3))
];
cuboids = [
new Cuboid(20, color(255, 255, 171, 100), 80, 35),
new Cuboid(40, color(255, 239, 171, 100), 80, 40),
new Cuboid(60, color(255, 221, 171, 100), 80, 45),
new Cuboid(80, color(255, 171, 171, 100), 80, 50),
new Cuboid(100, color(255, 153, 171, 100), 80, 55)
];
reset();
}
// -------------
// Draw
// -------------
function draw() {
background(purple);
if (frameCount < start + time) {
for (var i = now.length - 1; i >= 0; i--) {
now[i].x = bounce(frameCount - start, startPos[i].x, delta[i].x, time);
now[i].y = bounce(frameCount - start, startPos[i].y, delta[i].y, time);
}
}
push();
translate(width/2, height/2);
setGradient(-gradSize, -gradSize, 2*gradSize, 2*gradSize, pink, orange);
fill(purple);
noStroke();
beginShape();
// Exterior
vertex(-4*s, -4*s);
vertex(4*s, -4*s);
vertex(4*s, 4*s);
vertex(-4*s, 4*s);
// Interior
beginContour();
for (var i = 0; i < now.length; i++) {
vertex(now[i].x, now[i].y);
};
endContour();
endShape(CLOSE);
for (var i = cuboids.length - 1; i >= 0; i--) {
cuboids[i].run();
};
pop();
}
function setGradient(x, y, w, h, c1, c2) {
noFill();
for (var i = y; i <= y+h; i++) {
var inter = map(i, y, y+h, 0, 1);
var c = lerpColor(c1, c2, inter);
stroke(c);
line(x, i, x+w, i);
}
}
function mouseClicked() {
reset();
start = frameCount;
for (var i = cuboids.length - 1; i >= 0; i--) {
cuboids[i].start = frameCount;
};
}
function reset() {
for (var i = now.length - 1; i >= 0; i--) {
now[i] = startPos[i].get();
};
}
// @t is the current time (or position) of the tween. This can be seconds or frames, steps, seconds, ms, whatever – as long as the unit is the same as is used for the total time [3].
// @b is the beginning value of the property.
// @c is the change between the beginning and destination value of the property.
// @d is the total time of the tween.
function bounce(t, b, c, d) {
var ts=(t/=d)*t;
var tc=ts*t;
return b+c*(33*tc*ts + -106*ts*ts + 126*tc + -67*ts + 15*t);
} Another p5js/Codepen.io experiment. This time playing around with contours and lerp to get gradient fills inside a polygon.
I’ve been trying to learn a bit more about easing functions. More specifically elastic easing. It is fairly easy to do a single bounce with CSS. Tools such as bounce.js can be used to generate more complex versions. However, I had no idea how to do this with JS or what the underlying equations were …
Despite the commonality of the classic easing equations, largely attributed to Penner, there doesn’t seem to be the in-depth examination of “how it works” that a lot of code is subject to nowadays.
— Explaining Penner’s equations – JavaScript and ActionScript
We start with this basic equation where:
tis the current time (or position) of the tween. This can be seconds or frames, steps, seconds, ms, whatever – as long as the unit is the same as is used for the total time.bis the beginning value of the property.cis the change between the beginning and destination value of the property.dis the total time of the tween.
function noEasing (t, b, c, d) {
return c * t / d + b;
}
And then use polynomial functions to create all kinds of easing effects:
function bounce(t, b, c, d) {
var ts = (t /= d) * t;
var tc = ts * t;
return b + c * (33 * tc * ts + -106 * ts * ts + 126 * tc + -67 * ts + 15 * t);
}
Tim Groleau built this a really cool Easing Function Generator which I used to generate the bounce easing function.