Skip to content

Instantly share code, notes, and snippets.

@aldoyh
Last active February 24, 2025 07:31
Show Gist options
  • Save aldoyh/9a09ce783e042d01239f272773c19833 to your computer and use it in GitHub Desktop.
Save aldoyh/9a09ce783e042d01239f272773c19833 to your computer and use it in GitHub Desktop.
Genuary 18: wind visualization
<canvas id="c">
const c = document.querySelector('#c');
const ctx = c.getContext('2d');
const dpr = Math.min(2, window.devicePixelRatio);
c.width = window.innerWidth * dpr;
c.height = window.innerHeight * dpr;
c.style.imageRendering = 'pixelated';
c.style.width = '100vw';
c.style.height = '100vh';
const palette = [
'#f72585',
'#b5179e',
'#7209b7',
'#560bad',
'#480ca8',
'#3a0ca3',
'#3f37c9',
'#4361ee',
'#4895ef',
'#4cc9f0',
'#ffffff80',
]
const points = []
const createPoint = (x, y, color) => ({
x, y, color
})
for (let i = 0; i < 250; i++) {
points.push(createPoint(
Math.random() * c.width,
Math.random() * c.height,
Math.floor(Math.random() * palette.length) % palette.length
))
}
const mouse = { x: c.width / 2, y: c.height / 2 };
window.addEventListener("mousemove", (e) => {
mouse.x = e.clientX;
mouse.y = e.clientY;
});
function getAngle(cx, cy, ex, ey) {
const dy = ey - cy;
const dx = ex - cx;
const theta = Math.atan2(dy, dx);
return theta;
}
ctx.filter = 'blur(1px)';
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, c.width, c.height);
const drawWind = (time) => {
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
ctx.fillRect(0, 0, c.width, c.height);
const cx = c.width / 2;
const cy = c.height / 2;
for (let i = 0; i < points.length; i++) {
const point = points[i];
const p = i / points.length;
const mx = (mouse.x * dpr) + Math.cos(p * Math.PI * 2) * 25;
const my = (mouse.y * dpr) + Math.sin(p * Math.PI * 2) * 25;
const mouseAngle = getAngle(point.x, point.y, mx, my) - Math.PI / 2;
// Increased animation speed by 20%
const angle = mouseAngle + (Math.sin((i * 50 + time) / 1600) * i / 500);
ctx.fillStyle = palette[point.color];
ctx.fillStyle = palette[Math.floor((angle * 2) + (i / 15)) % palette.length] + '40';
for (let p = 4; p > 0; p-=0.75) {
ctx.beginPath();
ctx.arc(point.x, point.y, p, 0, Math.PI * 2);
ctx.fill();
// Increased movement speed by 20%
point.x = (point.x + Math.cos(angle) * 1.8);
if (point.x > c.width) {
point.x = 0;
} else if (point.x < 0) {
point.x = c.width;
}
point.y = (point.y + Math.sin(angle) * 1.8);
if (point.y > c.height) {
point.y = 0;
} else if (point.y < 0) {
point.y = c.height;
}
}
// Adjusted bounce back speed
point.x = (point.x - Math.cos(angle) * 12);
if (point.x > c.width) {
point.x = 0;
} else if (point.x < 0) {
point.x = c.width;
}
point.y = (point.y - Math.sin(angle) * 12);
if (point.y > c.height) {
point.y = 0;
} else if (point.y < 0) {
point.y = c.height;
}
}
}
const animate = (time) => {
requestAnimationFrame(animate);
drawWind(time);
}
window.addEventListener('resize', () => {
c.width = window.innerWidth * dpr;
c.height = window.innerHeight * dpr;
ctx.filter = 'blur(1px)';
})
animate(0);
html, body {
margin: 0;
padding: 0;
overflow: hidden;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment