JSFiddle - React, Tailwind, and code Playground
HTML
<canvas width="800" height="500"></canvas>
CSS
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #121212;
display: grid;
place-items: center;
min-height: 100vh;
}
canvas {
border: 1px solid #7dff19;
border-radius: 5px;
}
JavaScript
const canvas = document.querySelector("canvas");
const context = canvas.getContext("2d");
const worms = [];
init();
//---------------------
function init() {
for (let i = 0; i < 100; i++) {
const worm = [];
const position = {
x: random(0, canvas.width),
y: random(-500, canvas.height)
};
for (let i = 0; i < 10; i++) {
worm[i] = {
x: position.x,
y: position.y
};
}
worms.push(worm);
}
anime();
}
function anime() {
context.clearRect(0, 0, canvas.width, canvas.height);
for (let worm of worms) {
draw_worm(worm);
move_worm(worm, {
x: random(-10, 10),
y: random(-5, 15)
});
}
requestAnimationFrame(anime);
}
function draw_worm(worm) {
context.beginPath();
context.fillStyle = "#c6fdfd";
context.strokeStyle = "#56fdad";
context.arc(worm[0].x, worm[0].y, 2, 0, Math.PI * 2);
context.fill();
for (let seg of worm)
context.lineTo(seg.x, seg.y);
context.stroke();
}
function move_worm(worm, v) {
for (let i = worm.length - 1; i > 0; i--)
worm[i] = {
x: worm[i - 1].x,
y: worm[i - 1].y
};
worm[0] = {
x: clamp(worm[0].x + v.x, 0, canvas.width),
y: worm[0].y + v.y
};
if (worm[worm.length - 1].y > canvas.height)
for (let seg of worm)
seg.y -= random(600, 1000);
}
function random(min, max) {
return min + Math.random() * (max - min);
}
function clamp(number, min, max) {
if (number < min)
return min;
if (number > max)
return max;
return number;
}