Кастомные функции плавности (easing) в mo.js представляют собой механизм управления временным распределением анимации через математическое преобразование нормализованного времени. В базовом виде easing принимает параметр t в диапазоне от 0 до 1 и возвращает преобразованное значение, определяющее, как именно изменяется анимационное свойство во времени.
Внутри mo.js easing используется как функция вида:
function easing(t) {
return value;
}
где:
t — нормализованное время анимации (0 — старт, 1 —
завершение)Система анимации mo.js применяет easing ко всем tween-значениям, включая трансформации, opacity, масштабирование, перемещение и параметры эффектов.
Библиотека предоставляет набор встроенных кривых: линейные, квадратичные, кубические, экспоненциальные, эластичные и “bounce”-подобные функции. Однако архитектура позволяет подключать полностью произвольные алгоритмы интерполяции.
Базовый вариант кастомной функции строится напрямую:
const customEasing = function (t) {
return t;
};
Любая функция, удовлетворяющая контракту t ∈ [0,1] → R,
может использоваться как easing. При этом результат не обязан оставаться
в диапазоне 0–1, что позволяет создавать overshoot-эффекты и инерционные
колебания.
Пример нелинейного ускорения:
const customEase = function (t) {
return t * t * (3 - 2 * t);
};
Такая функция формирует плавное ускорение с замедлением на концах, аналогичное smoothstep-поведению.
Кастомные функции могут передаваться напрямую в параметры tween-объектов:
import mojs from 'mo-js';
const animation = new mojs.Html({
el: '.box',
x: { 0: 300 },
duration: 1000,
easing: function (t) {
return Math.pow(t, 3);
}
});
Здесь используется кубическая кривая ускорения, усиливающая динамику движения ближе к завершению анимации.
Для повторного использования функции удобно добавлять её в глобальный реестр easing:
mojs.easing.customSoft = function (t) {
return t * t * (3 - t);
};
После регистрации функция становится доступной по имени:
const anim = new mojs.Html({
el: '.circle',
scale: { 0: 1 },
easing: 'customSoft'
});
Такой подход позволяет централизовать библиотеку кривых и переиспользовать их между различными сценами и компонентами анимации.
Одним из наиболее распространённых способов создания кастомной плавности является кубическая кривая Безье. В mo.js она используется через генерацию функции из контрольных точек.
Общий вид:
const cubicBezier = function (p0, p1, p2, p3) {
return function (t) {
// вычисление значения кривой
};
};
В реальных сценариях чаще применяется готовая реализация через интерполяцию:
const easeInOut = mojs.easing.path('M0,0 C0.42,0 0.58,1 1,1');
Такой подход позволяет задавать поведение easing через SVG-подобное описание кривой.
mo.js поддерживает создание easing-функций на основе SVG path. Это один из наиболее гибких механизмов, позволяющий визуально проектировать кривые.
const customPathEase = mojs.easing.path('M0 0 C0.2 0.8 0.2 1 1 1');
Функция интерпретирует путь как кривую зависимости времени от прогресса.
Использование в анимации:
const anim = new mojs.Html({
el: '.square',
x: { 0: 400 },
duration: 1200,
easing: customPathEase
});
Кастомные easing-функции часто применяются для имитации физического поведения: упругости, трения, инерции.
function elasticOut(t) {
return Math.sin(-13 * (t + 1) * Math.PI / 2) * Math.pow(2, -10 * t) + 1;
}
Функция создаёт эффект пружины, где объект выходит за пределы целевого значения и возвращается обратно.
function bounceOut(t) {
const n1 = 7.5625;
const d1 = 2.75;
if (t < 1 / d1) {
return n1 * t * t;
} else if (t < 2 / d1) {
t -= 1.5 / d1;
return n1 * t * t + 0.75;
} else if (t < 2.5 / d1) {
t -= 2.25 / d1;
return n1 * t * t + 0.9375;
} else {
t -= 2.625 / d1;
return n1 * t * t + 0.984375;
}
}
Такие функции применяются для анимаций, имитирующих падение объектов и отскоки.
Кастомные функции можно комбинировать для создания сложных кривых поведения.
function combineEase(t) {
const easeIn = t * t;
const easeOut = 1 - Math.pow(1 - t, 2);
return t < 0.5
? easeIn * 2
: easeOut * 2 - 1;
}
Такой подход позволяет вручную формировать easing-in-out без использования встроенных кривых.
В отличие от линейных интерполяций, easing-функции не обязаны возвращать строго ограниченные значения. Однако в контексте mo.js важно учитывать поведение трансформаций:
Для стабилизации используется clamp:
function safeEase(t) {
const v = t * t * (3 - t);
return Math.max(0, Math.min(1, v));
}
Easing-функции вызываются на каждом шаге анимации, часто десятки или сотни раз в кадре при сложных сценах. Это делает критичным их вычислительную стоимость.
Оптимизации включают:
Пример табличного подхода:
const table = new Array(1000).fill(0).map((_, i) => {
const t = i / 999;
return t * t;
});
function tableEase(t) {
return table[Math.floor(t * 999)];
}
В сложных сценах easing применяется не только к отдельным tween-объектам, но и к временным линиям.
const timeline = new mojs.Timeline({
children: [
new mojs.Html({
el: '.a',
x: { 0: 200 },
easing: function (t) {
return Math.pow(t, 2);
}
}),
new mojs.Html({
el: '.b',
scale: { 0: 1 },
easing: 'elastic.out'
})
]
});
Сочетание разных easing внутри одной timeline позволяет создавать сложные синхронизированные движения.
При разработке сложных функций часто требуется визуальная проверка поведения. Для этого используется вывод значений функции на график:
const points = [];
for (let i = 0; i <= 100; i++) {
const t = i / 100;
points.push({ t, v: customEase(t) });
}
Анализ распределения значений позволяет выявлять резкие скачки, неестественные ускорения и выходы за диапазон.
Часто используемые структуры:
Мягкое ускорение с инерцией
t * t * (2 - t)
Глубокое замедление
1 - Math.pow(1 - t, 4)
Пульсирующая динамика
function pulse(t) {
return t + 0.1 * Math.sin(t * Math.PI * 4);
}
Каждый паттерн формирует характер движения интерфейса, влияя на восприятие скорости, веса и физической достоверности объектов в сцене.