Линейная интерполяция является базовым механизмом построения анимаций в mo.js и в большинстве современных систем визуальных эффектов. Она определяет способ вычисления промежуточных значений между двумя состояниями, обеспечивая плавный переход параметров объекта во времени.
Линейная интерполяция (LERP) задаётся формулой:
[ LERP(a, b, t) = a + (b - a) t]
где:
При t = 0 результат равен начальному значению, при t = 1 — конечному. Все промежуточные значения формируют прямую траекторию перехода без ускорений и замедлений.
В контексте анимации это означает, что каждый кадр вычисляется новое состояние свойства объекта как функция времени.
В системах анимации значение t не задаётся напрямую, а вычисляется из текущего времени:
Формально:
[ t = ]
При превышении длительности t ограничивается значением 1.
В mo.js линейная интерполяция используется как базовый механизм
изменения свойств объектов Tween, Shape,
Burst и других анимационных сущностей. Несмотря на наличие
easing-функций, именно LERP остаётся фундаментом, на котором строится
любое изменение параметров.
Любое анимируемое свойство в mo.js можно представить как интерполяцию между двумя состояниями:
function lerp(a, b, t) {
return a + (b - a) * t;
}
Применение:
const start = 0;
const end = 200;
const value = lerp(start, end, 0.5); // 100
В анимации это значение обновляется на каждом кадре.
В mo.js основной строительный блок анимации — Tween. Он
описывает переход свойств объекта во времени.
Пример логики:
const tween = new mojs.Tween({
duration: 1000,
onUpdate(progress) {
const x = lerp(0, 300, progress);
element.style.transform = `translateX(${x}px)`;
}
});
Здесь progress — это нормализованное значение t,
вычисляемое движком.
Линейная интерполяция применяется ко всем числовым параметрам. Для каждого свойства создаётся независимая функция LERP.
x = lerp(x1, x2, t);
y = lerp(y1, y2, t);
scale = lerp(1, 2, t);
opacity = lerp(1, 0, t);
Плавное исчезновение достигается прямой интерполяцией без дополнительных вычислений.
Для объектов с несколькими измерениями используется покомпонентная интерполяция:
function lerpVec2(a, b, t) {
return {
x: a.x + (b.x - a.x) * t,
y: a.y + (b.y - a.y) * t
};
}
mo.js использует аналогичный подход для координат и трансформаций объектов.
Линейная интерполяция обеспечивает равномерное изменение параметров, однако визуально такие анимации выглядят механически.
Easing-функции преобразуют t:
t' = ease(t)
и уже затем применяется LERP:
value = lerp(a, b, t')
Таким образом, линейная интерполяция остаётся базовым слоем, а easing — надстройкой над ней.
Низкоуровневая реализация анимации сводится к циклу:
let start = null;
function animate(timestamp) {
if (!start) start = timestamp;
const time = timestamp - start;
let t = time / 1000;
if (t > 1) t = 1;
const x = lerp(0, 500, t);
element.style.transform = `translateX(${x}px)`;
if (t < 1) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
mo.js автоматизирует эту модель, скрывая вычисление t и управление кадрами.
В сложных сценах mo.js использует последовательности анимаций, где каждая часть имеет собственный диапазон времени.
Если существует timeline с двумя последовательными tween:
то интерполяция выполняется локально внутри каждого сегмента:
t_local = (t - t_start) / (t_end - t_start);
Каждый сегмент применяет собственный LERP.
В анимациях форм (shape animations) интерполяция применяется не только к позициям, но и к геометрии.
Пример изменения радиуса:
radius = lerp(10, 80, t);
или изменения количества элементов:
count = Math.round(lerp(3, 12, t));
Для burst-анимаций это особенно важно, так как создаётся эффект расширения или распада.
Помимо стандартных числовых значений, LERP используется для:
Интерполяция цвета:
function lerpColor(c1, c2, t) {
return {
r: lerp(c1.r, c2.r, t),
g: lerp(c1.g, c2.g, t),
b: lerp(c1.b, c2.b, t)
};
}
Линейная модель имеет ряд особенностей:
По этой причине она почти всегда комбинируется с нелинейными функциями.
В сложных анимациях применяется вложенная интерполяция:
value = lerp(a, b, ease(lerp(0, 1, t)));
или обратная схема:
value = ease(lerp(a, b, t));
В зависимости от архитектуры системы mo.js может применять обе модели в разных слоях.
Линейная интерполяция является одной из самых дешёвых операций:
Это делает её оптимальной для массовых анимаций, особенно в burst-сценах, где одновременно обновляются сотни объектов.
Любая анимация в mo.js сводится к набору интерполяций:
Даже сложные визуальные эффекты представляют собой композицию простых LERP-операций, синхронизированных по времени и сгруппированных в структуры tween и timeline.