Спиральные движения в анимации обычно строятся на основе параметрического задания координат во времени. Классическая форма задаётся через тригонометрические функции:
где радиус r(t) и угол θ(t) изменяются независимо. Именно разделение этих двух параметров позволяет формировать широкий класс спиралей: Архимедовы, логарифмические, затухающие и комбинированные.
В контексте mo.js такие траектории реализуются через пользовательские tween-значения, где каждый кадр пересчитывает координаты объекта.
const spiralPath = (t, centerX, centerY) => {
const angle = t * Math.PI * 8;
const radius = 4 + t * 120;
return {
x: centerX + Math.cos(angle) * radius,
y: centerY + Math.sin(angle) * radius
};
};
Здесь t нормализован в диапазоне от 0 до 1. Увеличение коэффициента при угле формирует плотность витков, а линейное увеличение радиуса создаёт раскрывающуюся спираль.
Библиотека mo.js предоставляет механизм кастомных tween-значений
через MojsTween и модификаторы onUpdate.
Основной принцип заключается в том, что позиция объекта обновляется
вручную на каждом шаге анимации.
const circle = new mojs.Shape({
shape: 'circle',
radius: 10,
fill: '#4A90E2'
});
new mojs.Tween({
duration: 3000,
onUpdate: (progress) => {
const pos = spiralPath(progress, 300, 300);
circle
.tune({
x: pos.x,
y: pos.y
})
.replay();
}
}).play();
В подобных конструкциях важно учитывать, что tune() в
mo.js не создаёт новую анимацию, а обновляет параметры существующего
объекта. Это позволяет избегать лишних перерасчётов DOM и сохранять
производительность при сложных траекториях.
Архимедова спираль характеризуется линейным ростом радиуса:
При реализации в JavaScript это упрощается до линейной зависимости от прогресса анимации.
const archimedeanSpiral = (t, a, b, cx, cy) => {
const angle = t * Math.PI * 10;
const radius = a + b * angle;
return {
x: cx + Math.cos(angle) * radius,
y: cy + Math.sin(angle) * radius
};
};
При малых значениях b движение становится плотным и равномерным, при увеличении коэффициента витки начинают быстро расходиться. В mo.js такие траектории часто используются для частиц и burst-анимаций, создавая эффект расширяющегося вихря.
Логарифмическая спираль отличается экспоненциальным увеличением радиуса:
В анимации это создаёт визуально более «живое» расширение, характерное для природных форм.
const logarithmicSpiral = (t, a, b, cx, cy) => {
const angle = t * Math.PI * 8;
const radius = a * Math.exp(b * angle);
return {
x: cx + Math.cos(angle) * radius,
y: cy + Math.sin(angle) * radius
};
};
В mo.js подобная кривая часто применяется для создания эффектов распада или взрывного движения частиц, поскольку ускорение визуально воспринимается как естественное затухание структуры.
При работе с несколькими объектами, движущимися по спирали, требуется
синхронизация фаз. mo.js предоставляет Timeline,
позволяющий объединять несколько tween-объектов в единую систему
времени.
const timeline = new mojs.Timeline();
const createSpiralParticle = (delay, color) => {
const shape = new mojs.Shape({
shape: 'circle',
radius: 6,
fill: color
});
const tween = new mojs.Tween({
delay,
duration: 2500,
onUpdate: (p) => {
const pos = archimedeanSpiral(p, 0, 20, 300, 300);
shape.tune({
x: pos.x,
y: pos.y
});
}
});
timeline.add(tween);
};
createSpiralParticle(0, '#E74C3C');
createSpiralParticle(200, '#2ECC71');
createSpiralParticle(400, '#3498DB');
timeline.play();
Смещение delay создаёт эффект закручивания нескольких
слоёв спирали, где каждый новый элемент повторяет траекторию с фазовым
сдвигом.
Спиральные движения становятся значительно более выразительными при применении easing-функций не только ко времени, но и к радиусу. Это позволяет управлять плотностью витков.
const easeInOut = (t) =>
t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
Применение easing к радиусу:
const easedSpiral = (t, cx, cy) => {
const e = easeInOut(t);
const angle = e * Math.PI * 10;
const radius = 20 + e * 150;
return {
x: cx + Math.cos(angle) * radius,
y: cy + Math.sin(angle) * radius
};
};
Такая модификация создаёт эффект «разгона», где частица начинает движение медленно, затем ускоряется и выходит на стабильную траекторию.
mo.js поддерживает работу с SVG-путями через интерполяцию координат. Это позволяет заменить аналитические функции на заранее подготовленные кривые.
SVG-спираль может быть описана как path:
const spiralPathSVG = "M300,300 C350,250 400,350 450,300 S500,250 550,300";
Использование через shape с path:
const swirl = new mojs.Shape({
shape: 'path',
path: spiralPathSVG,
stroke: '#8E44AD',
strokeWidth: 3,
fill: 'none'
});
При необходимости анимации вдоль пути используется модификация progress:
new mojs.Tween({
duration: 3000,
onUpdate: (p) => {
const point = swirl.el.getPointAtLength(p * swirl.el.getTotalLength());
swirl.tune({
x: point.x,
y: point.y
});
}
}).play();
SVG-подход позволяет создавать сложные спиральные структуры, которые трудно выразить аналитически.
Сложные визуальные эффекты достигаются через наложение нескольких спиралей с различными параметрами: скоростью вращения, радиусом и фазой.
const layers = 5;
for (let i = 0; i < layers; i++) {
const offset = i * 0.6;
new mojs.Tween({
duration: 4000,
repeat: 999,
onUpdate: (p) => {
const t = (p + offset) % 1;
const pos = {
x: 300 + Math.cos(t * Math.PI * 12) * (20 + t * 140),
y: 300 + Math.sin(t * Math.PI * 12) * (20 + t * 140)
};
new mojs.Shape({
shape: 'circle',
radius: 4,
fill: `rgba(52, 152, 219, ${1 - t})`,
x: pos.x,
y: pos.y
}).play();
}
}).play();
}
В подобных системах ключевым моментом становится контроль количества создаваемых объектов. Без ограничения частоты генерации возникает перегрузка памяти и падение FPS.
При построении плотных спиральных структур критически важно
минимизировать математические операции внутри onUpdate.
Тригонометрия и экспоненты становятся узким местом при большом
количестве частиц.
Используются следующие подходы:
Пример кэширования:
const sinTable = Array.from({ length: 1000 }, (_, i) =>
Math.sin((i / 1000) * Math.PI * 2)
);
const cosTable = Array.from({ length: 1000 }, (_, i) =>
Math.cos((i / 1000) * Math.PI * 2)
);
Использование:
const fastSpiral = (t) => {
const idx = Math.floor(t * 999);
const angle = t * Math.PI * 10;
const radius = 30 + t * 120;
return {
x: 300 + cosTable[idx] * radius,
y: 300 + sinTable[idx] * radius
};
};
Спираль не ограничивается двумерной плоскостью. В mo.js возможно создание псевдо-3D эффектов через масштабирование и изменение z-index через scale.
const pseudo3DSpiral = (t) => {
const angle = t * Math.PI * 8;
const radius = 20 + t * 160;
const depth = t;
return {
x: 300 + Math.cos(angle) * radius,
y: 300 + Math.sin(angle) * radius,
scale: 0.3 + depth
};
};
Изменение масштаба создаёт иллюзию приближения и удаления объекта, усиливая восприятие глубины спирали.
mo.js Burst позволяет генерировать радиальные выбросы частиц. При замене радиального распределения на спиральное получается эффект закрученного взрыва.
const burst = new mojs.Burst({
radius: { 0: 200 },
count: 20,
children: {
shape: 'circle',
radius: 5,
fill: '#F39C12'
}
});
burst.play();
Модификация через пост-обработку координат:
burst.children.forEach((child, i) => {
const angle = i * 0.3;
const radius = i * 8;
child.tune({
x: Math.cos(angle) * radius,
y: Math.sin(angle) * radius
});
});
Это превращает радиальный burst в закрученную структуру, визуально напоминающую вихрь энергии.
Добавление перлин-подобного шума позволяет разрушить идеальную геометрию спирали и приблизить её к природным формам.
const noise = (t) => Math.sin(t * 12.9898) * 43758.5453 % 1;
const noisySpiral = (t) => {
const angle = t * Math.PI * 10;
const radius = 20 + t * 140;
const n = noise(t);
return {
x: 300 + Math.cos(angle + n) * radius,
y: 300 + Math.sin(angle + n) * radius
};
};
Такое искажение особенно эффективно в визуализациях частиц, где идеальная симметрия воспринимается как искусственная.