Процедурная генерация движения — это подход, при котором анимация формируется не заранее заданными ключевыми кадрами, а вычисляется на основе алгоритмов, математических функций и параметров. В контексте библиотеки anime.js это означает динамическое управление свойствами объектов с помощью функций, циклов, случайных значений и временных зависимостей.
Ключевая особенность — отказ от статичных значений в пользу
вычисляемых. Вместо фиксированного translateX: 250
используется функция, возвращающая разные значения для каждого элемента
или кадра.
В anime.js практически любое анимационное свойство может быть задано функцией:
anime({
targets: '.item',
translateX: function(el, i) {
return i * 50;
},
delay: function(el, i) {
return i * 100;
}
});
Параметры функции:
el — текущий DOM-элементi — индекс элементаl — общее количество элементовЭто позволяет:
Процедурность часто подразумевает вариативность. anime.js предоставляет встроенный генератор случайных чисел:
anime({
targets: '.particle',
translateX: function() {
return anime.random(-200, 200);
},
translateY: function() {
return anime.random(-200, 200);
},
duration: function() {
return anime.random(500, 2000);
}
});
Особенности:
anime.random(min, max) возвращает целое числоЗначения могут задаваться как массивы, что позволяет формировать сложные траектории:
anime({
targets: '.box',
translateX: [0, 100, -50, 200],
easing: 'easeInOutSine',
duration: 2000
});
Для процедурной генерации массивы создаются динамически:
const path = Array.from({ length: 10 }, () => anime.random(-100, 100));
anime({
targets: '.box',
translateX: path,
duration: 3000
});
Процедурное движение может зависеть от времени, создавая эффекты волн, колебаний и циклов.
anime({
targets: '.wave',
translateY: function(el, i) {
return Math.sin(i + anime.random(0, 10)) * 50;
},
duration: 2000,
direction: 'alternate',
loop: true
});
Применение:
Функции сглаживания (easing) влияют на характер движения. anime.js поддерживает кастомные кривые:
anime({
targets: '.box',
translateX: 250,
easing: 'cubicBezier(0.5, 0.05, 0.1, 0.3)'
});
Процедурный подход позволяет варьировать easing:
const easings = ['easeInQuad', 'easeOutElastic', 'linear'];
anime({
targets: '.item',
translateX: 200,
easing: function(el, i) {
return easings[i % easings.length];
}
});
anime.js предоставляет мощный инструмент stagger,
который можно использовать процедурно:
anime({
targets: '.grid div',
translateX: 100,
delay: anime.stagger(100, {
grid: [10, 10],
from: 'center'
})
});
Процедурная генерация усиливается параметрами:
from: 'center' | 'first' | 'last'axis: 'x' | 'y'easing внутри staggerДля создания сложных движений используются математические функции:
anime({
targets: '.dot',
translateX: function(el, i) {
return Math.cos(i) * 100;
},
translateY: function(el, i) {
return Math.sin(i) * 100;
},
loop: true,
direction: 'alternate'
});
anime({
targets: '.dot',
translateX: function(el, i) {
return Math.cos(i) * i * 5;
},
translateY: function(el, i) {
return Math.sin(i) * i * 5;
}
});
Процедурная генерация часто имитирует физические процессы:
anime({
targets: '.ball',
translateY: [
{ value: 300, easing: 'easeInQuad', duration: 500 },
{ value: 0, easing: 'easeOutQuad', duration: 500 }
],
loop: true
});
anime({
targets: '.spring',
translateX: 250,
easing: 'easeOutElastic(1, .5)'
});
Таймлайны позволяют объединять процедурные элементы:
const tl = anime.timeline({
loop: true
});
tl.add({
targets: '.box',
translateX: () => anime.random(0, 300),
duration: 1000
}).add({
targets: '.box',
translateY: () => anime.random(0, 300),
duration: 1000
});
Каждый шаг генерирует новые значения, создавая непредсказуемое движение.
Типичный пример процедурной анимации — частицы:
function createParticle() {
const particle = document.createElement('div');
particle.classList.add('particle');
document.body.appendChild(particle);
anime({
targets: particle,
translateX: anime.random(-200, 200),
translateY: anime.random(-200, 200),
opacity: [1, 0],
duration: anime.random(1000, 3000),
easing: 'easeOutQuad',
complete: () => particle.remove()
});
}
Запуск генерации:
setInterval(createParticle, 100);
Процедурное движение может адаптироваться:
anime({
targets: '.item',
translateX: function(el, i) {
return i * 100;
},
duration: function(el, i) {
return 500 + i * 200;
}
});
Это формирует ритмические структуры:
Процедурность усиливается реакцией на события:
document.addEventListener('mousemove', (e) => {
anime({
targets: '.cursor',
translateX: e.clientX,
translateY: e.clientY,
duration: 300,
easing: 'easeOutExpo'
});
});
Большое количество вычислений требует внимания к производительности:
Рекомендации:
requestAnimationFrame косвенно через
anime.jsПроцедурная генерация бывает двух типов:
Детерминированная:
Случайная:
Пример детерминированного подхода:
anime({
targets: '.item',
translateX: (el, i) => i * 100
});
Пример случайного:
anime({
targets: '.item',
translateX: () => anime.random(0, 300)
});
Наиболее выразительные анимации получаются при смешении методов:
anime({
targets: '.item',
translateX: (el, i) => i * 50 + anime.random(-20, 20),
translateY: () => anime.random(-50, 50),
delay: anime.stagger(100),
easing: 'easeInOutSine'
});
Так формируется баланс:
1. UI-анимации
2. Игровые интерфейсы
3. Декоративные эффекты
4. Data-driven анимации
Баланс достигается через:
Процедурная генерация не ограничена встроенными средствами:
function noise(x) {
return Math.sin(x) * Math.cos(x * 0.5);
}
anime({
targets: '.item',
translateY: (el, i) => noise(i) * 100
});
Это открывает возможности:
Процедурная анимация часто строится пошагово:
Каждый этап усложняет движение, делая его более естественным и выразительным.