Анимация частиц — это подход, при котором большое количество небольших объектов (частиц) управляются как единая система. Каждая частица обладает минимальным набором свойств: координаты, скорость, размер, прозрачность, цвет и время жизни. Вместе они формируют визуально сложные эффекты: дым, огонь, искры, снег, дождь.
В контексте библиотеки anime.js частицы не являются встроенной сущностью, поэтому система строится вручную на основе массивов объектов и анимации их свойств.
Базовая модель частицы:
const particle = {
x: 0,
y: 0,
vx: 0,
vy: 0,
size: 5,
opacity: 1,
life: 100
};
Ключевые параметры:
Система частиц обычно представляется массивом:
const particles = [];
function createParticle(x, y) {
return {
x,
y,
vx: (Math.random() - 0.5) * 4,
vy: (Math.random() - 0.5) * 4,
size: Math.random() * 6 + 2,
opacity: 1,
life: 100
};
}
Добавление частиц:
for (let i = 0; i < 100; i++) {
particles.push(createParticle(300, 300));
}
Для визуализации чаще всего используется
<canvas>:
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
function drawParticles() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
particles.forEach(p => {
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
ctx.fillStyle = `rgba(255, 100, 100, ${p.opacity})`;
ctx.fill();
});
}
Каждый кадр частицы обновляют свои параметры:
function updateParticles() {
particles.forEach(p => {
p.x += p.vx;
p.y += p.vy;
p.life--;
p.opacity = p.life / 100;
});
}
Удаление “мертвых” частиц:
particles = particles.filter(p => p.life > 0);
Библиотека anime.js позволяет анимировать свойства объектов, включая пользовательские:
anime({
targets: particles,
x: p => p.x + (Math.random() - 0.5) * 200,
y: p => p.y + (Math.random() - 0.5) * 200,
opacity: 0,
size: 0,
duration: 2000,
easing: 'easeOutExpo',
update: drawParticles
});
Здесь:
update перерисовывает сцену на каждом
кадреТипичный эффект — разлет частиц из одной точки:
function explode(x, y) {
const explosionParticles = [];
for (let i = 0; i < 50; i++) {
explosionParticles.push({
x,
y,
angle: Math.random() * Math.PI * 2,
distance: Math.random() * 150,
size: Math.random() * 4 + 2,
opacity: 1
});
}
anime({
targets: explosionParticles,
x: p => p.x + Math.cos(p.angle) * p.distance,
y: p => p.y + Math.sin(p.angle) * p.distance,
opacity: 0,
size: 0,
duration: 1200,
easing: 'easeOutCubic',
update: () => drawExplosion(explosionParticles)
});
}
Создание шлейфа за движением мыши:
document.addEventListener('mousemove', e => {
particles.push(createParticle(e.clientX, e.clientY));
anime({
targets: particles[particles.length - 1],
opacity: 0,
size: 0,
duration: 1000,
easing: 'linear',
complete: () => particles.shift()
});
});
Добавление простейшей физики:
const gravity = 0.2;
function updateParticles() {
particles.forEach(p => {
p.vy += gravity;
p.x += p.vx;
p.y += p.vy;
p.life--;
});
}
Эффекты:
Для усложнения движения:
p.vx += (Math.random() - 0.5) * 0.2;
p.vy += (Math.random() - 0.5) * 0.2;
Это создаёт эффект:
При работе с сотнями и тысячами элементов важно:
1. Минимизировать количество объектов anime.js
2. Использовать requestAnimationFrame
function loop() {
updateParticles();
drawParticles();
requestAnimationFrame(loop);
}
loop();
3. Ограничивать количество частиц
if (particles.length > 500) {
particles.splice(0, 100);
}
Анимация цвета через anime.js:
anime({
targets: particles,
color: ['#ff0000', '#ffff00'],
duration: 2000,
easing: 'linear'
});
При использовании canvas цвет обычно вычисляется вручную:
ctx.fillStyle = `hsl(${p.life * 3}, 100%, 50%)`;
Система частиц раскрывается при комбинировании:
Пример:
anime({
targets: particles,
x: p => p.x + Math.cos(p.angle) * 100,
y: p => p.y + Math.sin(p.angle) * 100,
opacity: [1, 0],
size: [5, 0],
easing: 'easeOutQuad',
duration: 1500,
update: drawParticles
});
Ключевые техники:
Типичная структура системы:
class ParticleSystem {
constructor() {
this.particles = [];
}
add(x, y) {
this.particles.push(createParticle(x, y));
}
update() {
this.particles.forEach(p => {
p.x += p.vx;
p.y += p.vy;
p.life--;
});
this.particles = this.particles.filter(p => p.life > 0);
}
draw(ctx) {
this.particles.forEach(p => {
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
ctx.fill();
});
}
}
Интеграция с anime.js позволяет гибко управлять поведением:
Вместо линейного уменьшения:
p.opacity = Math.pow(p.life / 100, 2);
Это даёт:
Система частиц обычно развивается по этапам:
Такой подход позволяет контролировать сложность и производительность, постепенно создавая насыщенные визуальные сцены.