Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<title>Fetti</title>
<style>
div {
left: 50%;
right: 50%;
top: 50vh;
position: absolute;
}
</style>
</head>
<body>
<button>go</button>
<script>
function tween(callback, ticks = 500) {
let timer = performance.now();
~(function frame() {
let diff = performance.now() - timer;
if (diff < ticks) {
requestAnimationFrame(frame);
callback(diff / ticks);
} else {
callback(1);
}
})();
}
function lerp(start, end, i) {
return start + (end - start) * i;
}
function ease(t) {
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
}
const { PI, cos, sin, random } = Math;
function getParticle() {
const node = Object.assign(
document.body.appendChild(document.createElement('div')),
{ innerHTML: '■' },
);
const part = {};
part.theta = lerp(-35, 35, random()) * (PI / 180);
part.force = lerp(50, 350, random());
part.x = 0;
part.y = 0;
let seed = lerp(0, 360, random());
part.setPos = (x, y) => {
Object.assign(part, { x, y });
seed += 3;
node.style.transform = `translate(${x}px,${y}px) rotate3d(1, 1, 1, ${seed}deg)`;
};
part.setOpacity = (o) => {
node.style.opacity = o;
};
part.remove = () => {
node.remove();
};
return part;
}
document.querySelector('button').addEventListener('click', () => {
const particles = Array.from({ length: 20 }, getParticle);
tween(linear => {
const i = ease(linear);
particles.forEach(({ force, theta, setPos }) => {
const h = i * force;
const y = 0 | (cos(theta) * h);
const x = 0 | (sin(theta) * h);
setPos(x, -y);
});
if (linear == 1) {
tween(linear => {
particles.forEach(({ x, y, setPos, setOpacity }) => {
setPos(x, y + 3);
setOpacity(1-linear);
});
if (linear == 1) {
particles.forEach(p => p.remove());
}
}, 1000);
}
}, 330);
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment