JSFiddle - React, Tailwind, and code Playground
by soulwire
HTML
<canvas id="b"></canvas>
CSS
html, body {
background: #222;
margin: 0;
}
JavaScript
const c = b.getContext('2d');
const camera = {
x: 0,
y: 0,
z: 1,
s: 0.4
}
let vines = [{
x: 0,
y: 0,
a: 0,
ai: 0,
w: 4,
l: 200,
p: []
}];
let frame = 0;
const tick = () => {
requestAnimationFrame(tick);
b.width = innerWidth;
b.height = innerHeight;
camera.x += (vines[0].x - camera.x) * camera.s;
camera.y += (vines[0].y - camera.y) * camera.s;
camera.z = 0.5 + (Math.sin(frame * 0.01) / 2 + 1) * 1.5;
c.translate(innerWidth / 2, innerHeight / 2);
c.scale(camera.z, camera.z);
c.translate(-camera.x, -camera.y);
vines = vines.filter((v, i) => {
if (i === 0) return true;
return --v.l > 0;
});
vines.forEach(v => {
// update
const dx = Math.cos(v.a) * v.w / 2;
const dy = Math.sin(v.a) * v.w / 2;
v.p.push({ x: v.x, y: v.y });
v.a += v.ai / v.w / 2;
v.x += dx;
v.y += dy;
//if (Math.random() < 0.1) {
if (frame % 30 === 0) {
v.ai = Math.random() - .5;
}
if (v.p.length > 200) {
v.p.shift();
}
if (
vines.length < 100 &&
v.l > 50 &&
Math.random() < 0.02
) {
vines.push({
x: v.x,
y: v.y,
a: v.a,
ai: v.ai,
w: v.w / 2,
p: [],
l: v.l
})
}
// render
c.beginPath();
c.strokeStyle = '#fff';
c.moveTo(v.x, v.y);
let l = v.p.length - 1;
for (let p, i = l; p = v.p[i]; i--) {
c.lineTo(p.x, p.y);
}
c.stroke();
});
frame++;
}
tick();