Реализация процедурных анимаций в мобильном приложении
Процедурные анимации — это анимации, которые вычисляются в реальном времени по алгоритму, а не воспроизводят заранее записанные кадры. Частицы, следующие за пальцем. Волна, реагирующая на звук. Фон, меняющий форму в зависимости от данных. Это отдельный класс задач, требующий понимания физического моделирования и работы с GPU.
Когда это нужно
Процедурная анимация оправдана когда:
- Анимация реагирует на input в реальном времени (касание, акселерометр, микрофон)
- Анимация зависит от данных, которые неизвестны заранее
- Вариативность бесконечна и keyframe-подход нереален
- Нужен эффект «живого» фона или ambient animation
Системы частиц
На iOS — CAEmitterLayer + CAEmitterCell. Встроенный particle engine с поддержкой gravity, emissionRange, velocity, lifetime. Производительный, работает на GPU. Ограничение: каждая частица идентична по форме (bitmap или shape), нет кастомного поведения per-частицу.
let emitter = CAEmitterLayer()
emitter.emitterPosition = CGPoint(x: view.center.x, y: -10)
emitter.emitterShape = .line
emitter.emitterSize = CGSize(width: view.bounds.width, height: 1)
let cell = CAEmitterCell()
cell.contents = UIImage(named: "particle")?.cgImage
cell.birthRate = 50
cell.lifetime = 4
cell.velocity = 100
cell.velocityRange = 50
cell.emissionRange = .pi / 4
cell.scale = 0.1
cell.scaleRange = 0.05
emitter.emitterCells = [cell]
Для кастомного поведения частиц — Metal shader или SpriteKit с SKEmitterNode. SpriteKit поддерживает .sks файлы редактора частиц в Xcode — визуальную настройку без кода.
На Android — нет встроенного particle engine. Используем Canvas с ValueAnimator или OpenGL ES через GLSurfaceView. Для продуктового использования — библиотека Konfetti (простые случаи) или написание кастомного View с Canvas.drawBitmap в цикле через Choreographer.FrameCallback.
В Flutter — пакеты particles_flutter, flame (game engine с particle support). Для простых случаев — CustomPainter с AnimationController и списком объектов-частиц, каждый со своей физикой.
Физическое моделирование: пружины и инерция
Процедурная анимация на основе физики — это не spring(dampingRatio:). Это численное интегрирование уравнений движения на каждом кадре.
Простейшая пружинная система (Verlet integration):
// Обновляем каждый кадр через CADisplayLink
func update(dt: Double) {
let springForce = (targetPosition - currentPosition) * stiffness
let dampingForce = velocity * -damping
let acceleration = (springForce + dampingForce) / mass
velocity += acceleration * dt
currentPosition += velocity * dt
}
Это даёт поведение, которое не ограничено библиотечными параметрами: можно задать любую массу, жёсткость, затухание. Используется для «тянущихся» элементов, следующих за пальцем с задержкой, анимации волос/хвостов, флагов.
Шумовые алгоритмы для органичного движения
Perlin noise и Simplex noise — основа для органичных ambient-анимаций. Фон, «дышащий» без повторяющихся паттернов; форма, медленно деформирующаяся; цвет, плавно меняющийся.
На iOS через Metal или simd:
// Simplex noise функция → значение float в диапазоне [-1, 1]
let noiseValue = simplexNoise2D(x: Float(time * 0.3), y: Float(index) * 0.5)
let yOffset = noiseValue * amplitude
В Flutter — пакет noise или написание на Dart. В шейдерах Flutter (Flutter GPU API, доступен с Flutter 3.10+) — float noise(vec2 p) прямо в GLSL.
Производительность
Главное правило: никакой логики частиц на main thread. CADisplayLink с preferredFramesPerSecond = 60 (или 120 для ProMotion) — минимум. Для сложных сцен — Metal compute shader, который обновляет позиции частиц параллельно на GPU.
Профилируем через Instruments → Core Animation / Metal System Trace. Цель: GPU utilization < 60% при idle, frame time < 8ms для 120Hz.
Что входит в работу
Прорабатываем алгоритм анимации по ТЗ или референсам. Реализуем с оптимизацией под целевой FPS. Интегрируем с системой событий приложения (input, data updates). Профилируем и оптимизируем.
Срок: 3–5 дней в зависимости от сложности физической модели и целевой платформы.







