Процедурные анимации

Процедурные анимации в контексте Lottie Web строятся на сочетании заранее подготовленных векторных сцен и динамического управления их параметрами во время выполнения. В отличие от полностью статических JSON-анимаций, процедурный подход предполагает генерацию вариативности, поведения и состояния без пересборки исходного файла в After Effects, за счёт использования JavaScript API и структуры данных Lottie.


Lottie Web работает с JSON-описанием анимации, экспортированной из After Effects через Bodymovin. Внутри файла содержатся:

  • слои (layers)
  • ключевые кадры (keyframes)
  • кривые интерполяции
  • трансформации (position, scale, rotation, opacity)
  • векторные контуры и формы

Процедурность возникает не на этапе рендеринга, а на этапе управления этим JSON-деревом после загрузки в runtime.

Основной объект управления:

const animation = lottie.loadAnimation({
  container: document.getElementById('anim'),
  renderer: 'svg',
  loop: true,
  autoplay: true,
  path: 'animation.json'
});

После инициализации доступ к внутренним структурам позволяет изменять поведение анимации без изменения исходного файла.


Управление временной осью как основа процедурности

Ключевой механизм процедурных эффектов — контроль времени воспроизведения.

animation.goToAndStop(120, true);
animation.playSegments([30, 90], true);
animation.setSpeed(1.5);

Сегментирование позволяет использовать один Lottie-файл как набор состояний. При процедурном подходе сегменты становятся аналогом конечного автомата:

  • idle
  • hover
  • active
  • transition

Динамическое переключение сегментов создаёт псевдособытийную модель анимации.


Манипуляция свойствами слоёв

После загрузки анимации доступна модификация внутренних свойств через getElementById-подобные механизмы Lottie (через композицию слоёв и data interfaces).

На практике чаще используется обход структуры:

const layers = animation.renderer.elements;

layers.forEach(layer => {
  if (layer.data.nm === 'Circle') {
    layer.updateDocumentData && layer.updateDocumentData({ 
      text: 'dynamic' 
    });
  }
});

Более устойчивый подход — работа через expressions в After Effects или через dataInterface при экспорте.


Процедурное управление трансформациями

Наиболее распространённый сценарий — изменение transform-параметров в runtime.

animation.addEventListener('enterFrame', () => {
  const progress = animation.currentFrame / animation.totalFrames;

  const scale = 100 + Math.sin(progress * Math.PI * 2) * 20;

  animation.renderer.elements.forEach(el => {
    if (el.transform) {
      el.transform.scale.setValue([scale, scale]);
    }
  });
});

Такой подход превращает статическую анимацию в реактивную систему, где поведение определяется математическими функциями.


Встраивание случайности как механизм генеративности

Процедурные анимации часто опираются на псевдослучайные значения для создания вариативности.

function randomRange(min, max) {
  return Math.random() * (max - min) + min;
}

setInterval(() => {
  const x = randomRange(-50, 50);
  const y = randomRange(-50, 50);

  animation.renderer.elements.forEach(el => {
    if (el.transform && el.transform.position) {
      el.transform.position.setValue([x, y]);
    }
  });
}, 1000);

Такой механизм используется для:

  • дрожания объектов
  • генерации органических движений
  • имитации физического шума
  • вариативных UI-переходов

Синхронизация с внешним состоянием приложения

Процедурность в Lottie Web усиливается при связывании с состоянием интерфейса.

function updateState(state) {
  switch(state) {
    case 'loading':
      animation.playSegments([0, 45], true);
      break;

    case 'success':
      animation.playSegments([45, 90], true);
      break;

    case 'error':
      animation.playSegments([90, 135], true);
      break;
  }
}

Таким образом анимация становится визуальным отражением бизнес-логики.


Реактивное управление через requestAnimationFrame

Более низкоуровневый способ процедурного контроля заключается в привязке к циклу рендера.

function loop() {
  const t = performance.now() * 0.001;

  const offset = Math.sin(t) * 10;

  animation.renderer.elements.forEach(el => {
    if (el.transform && el.transform.rotation) {
      el.transform.rotation.setValue(offset);
    }
  });

  requestAnimationFrame(loop);
}

loop();

Этот подход используется для создания непрерывных живых анимаций, не зависящих от таймлайна Lottie.


Использование expressions из After Effects

Часть процедурной логики переносится на этап экспорта через expressions:

  • wiggle()
  • loopOut()
  • time * multiplier
  • linear() интерполяции

Пример expression:

wiggle(2, 30)

После экспорта такие выражения сохраняют процедурное поведение внутри JSON, уменьшая необходимость JS-манипуляций.


Динамическая подмена источника данных

Lottie позволяет подменять JSON-анимации на лету, что создаёт эффект генерации различных вариантов одной сцены.

animation.destroy();

lottie.loadAnimation({
  container: document.getElementById('anim'),
  renderer: 'svg',
  loop: true,
  autoplay: true,
  path: dynamicPath
});

Этот механизм применяется для:

  • тематических скинов
  • A/B вариантов интерфейса
  • адаптивных визуальных состояний

Комбинирование нескольких Lottie-сцен

Процедурность усиливается при компоновке нескольких анимаций в одном контейнере.

const animA = lottie.loadAnimation({...});
const animB = lottie.loadAnimation({...});

function sync(progress) {
  animA.goToAndStop(progress * 100, true);
  animB.goToAndStop((1 - progress) * 100, true);
}

Такой подход формирует композитные визуальные системы, где отдельные Lottie-файлы становятся слоями общей сцены.


Физически-ориентированные процедуры

Имитация физики достигается через математические модели, накладываемые на параметры анимации:

  • пружинное движение
  • затухание
  • инерция
let velocity = 0;
let position = 0;

function tick() {
  const target = 100;
  const stiffness = 0.1;

  velocity += (target - position) * stiffness;
  velocity *= 0.8;
  position += velocity;

  animation.renderer.elements.forEach(el => {
    if (el.transform) {
      el.transform.position.setValue([position, 0]);
    }
  });

  requestAnimationFrame(tick);
}

tick();

Процедурная генерация вариаций интерфейса

Один Lottie-файл может использоваться как база для множества визуальных состояний:

  • изменение цветов через fill
  • масштабирование отдельных слоёв
  • смещение групп элементов
  • управление прозрачностью
function applyTheme(color) {
  animation.renderer.elements.forEach(el => {
    if (el.styles && el.styles.fill) {
      el.styles.fill.setValue(color);
    }
  });
}

Ограничения процедурного подхода

Глубокая модификация Lottie-структуры в runtime сопровождается ограничениями:

  • SVG-рендерер не всегда стабильно обновляет сложные трансформации
  • Canvas-режим ограничивает доступ к внутренним слоям
  • JSON не предназначен для высокочастотного реального времени
  • сложные сцены приводят к деградации производительности

Поэтому процедурность чаще реализуется через управление временем и сегментами, а не через прямое изменение векторной геометрии.


Оптимизационные модели процедурных анимаций

Для поддержания производительности применяется:

  • кэширование экземпляров анимаций
  • ограничение частоты обновлений
  • использование requestAnimationFrame вместо интервалов
  • минимизация обращения к внутренним слоям
  • предрасчёт процедурных значений

Такая архитектура позволяет сочетать генеративное поведение с предсказуемой нагрузкой на рендерер.