~/wiki / prototipy-i-handoff / peredacha-animatsiy-i-sostoyaniy-v-razrabotku

Как передать анимации разработчику так, чтобы он их не упростил до статики

Основной чат

Чат для вайбкодеров: новости, гайды, поиск исполнителей, маркетплейс и разбор реальных кейсов.

$ cd раздел/ $ join vibe dev
Как передать анимации разработчику так, чтобы он их не упростил до статики - обложка

Анимация в Figma выглядит как магия: easing мягкий, элементы дышат, переходы держат внимание. Открываешь продакшен через две недели — и видишь fade-in длиной 200 мс на всё, что двигалось. Кнопка просто появляется. Карточка просто разворачивается. Магии нет.

И обычно это не саботаж разработчика. Это естественный результат того, как анимация передаётся: словами «ну, тут должно красиво выехать», ссылкой на прототип, который никто не открывал, и комментарием в Jira «добавить плавность». На таком брифе любой нормальный фронтендер сделает минимум — потому что максимум не описан, не оценён и не защищён.

Эта статья — про то, как описывать движение так, чтобы оно дошло до пользователя в том виде, в котором задумано. Без «давай посмотрим вместе на созвоне» каждый раз.

Почему анимации стабильно теряются на хэндоффе

Анимация — это самый плохо документируемый слой дизайна. Шрифты лежат в токенах, цвета — в библиотеке, отступы — в auto layout. А движение существует как видео в Loom, прототип в Figma и устная договорённость. Любое из этих звеньев рвётся первым.

Несколько типичных причин, по которым анимация превращается в статику:

  • Нет численных параметров. «Плавно», «мягко», «как у Apple» — это не спецификация. Разработчик подставит дефолт фреймворка.
  • Нет приоритета. В тикете анимация — последний пункт. Когда дедлайн жмёт, отрезают именно её.
  • Не понятна цель. Если непонятно, зачем элемент двигается, движение воспринимается как украшение. Украшения режут первыми.
  • Нет способа проверить. QA не знает, как тестировать «правильность» анимации. Раз нельзя зафейлить — можно не делать.
  • Производительность пугает. Разработчик не уверен, что 60fps реально достижим, и упрощает превентивно.

Если хочется, чтобы движение выжило, нужно закрыть все пять причин — не только первую.

Сначала договоритесь, зачем тут вообще движение

Прежде чем описывать кривые и тайминги, ответьте на один вопрос: что эта анимация делает для пользователя? Если ответа нет — анимацию правда стоит выкинуть, и разработчик прав.

Рабочие функции движения, под которые стоит защищать бюджет:

  • Сохранение контекста. Элемент не исчезает и не появляется из ниоткуда — пользователь видит, откуда он пришёл (открытие карточки в её же месте, выезд панели сбоку).
  • Иерархия внимания. Что-то одно двигается медленнее или позже — туда смотрят.
  • Обратная связь. Нажатие, загрузка, успех, ошибка — без движения они читаются хуже.
  • Объяснение состояния. Скелетоны, прогресс, переходы между режимами — движение показывает, что система делает.

Если анимация не попадает ни в одну категорию — это декорация. На ревью её срежут, и это нормально.

Вопросы, на которые должен отвечать каждый кусок движения

  • Что пользователь должен понять благодаря этому движению?
  • Что сломается, если убрать анимацию совсем?
  • Что сломается, если оставить только 150 мс fade?
  • Это блокирующая анимация или фоновая?

Последний вопрос особенно важен. Блокирующая (модалка открывается, кнопка отвечает на тап) — критичная, её нельзя резать. Фоновая (параллакс, лёгкое дыхание иконки) — приятная, её можно отключить на слабых устройствах. Эти две категории нужно различать в спеке явно, иначе разработчик усреднит обе.

Опишите движение так, чтобы его можно было закодить без вас

Минимальная спецификация одного перехода — это не «открыть прототип и посмотреть». Это набор параметров, которые можно прочитать, ввести в код и проверить.

Что должно быть в описании каждой анимации

  • Триггер. Что её запускает: маунт, клик, hover, изменение состояния, скролл, появление в viewport.
  • Что именно двигается. Свойство: opacity, transform (translate / scale / rotate), color, размер. Не «карточка появляется», а «opacity 0 → 1 и translateY 12px → 0».
  • Длительность. В миллисекундах. Не «быстро».
  • Easing. Конкретная кривая: cubic-bezier(0.2, 0, 0, 1) или имя из вашей токен-системы (ease-out-standard). «Ease» по умолчанию — это не easing, это лотерея.
  • Задержка. Если есть. Особенно важна при оркестрации нескольких элементов.
  • Конечное состояние. Что должно остаться на экране после завершения.
  • Прерывание. Что происходит, если пользователь нажал ещё раз во время анимации. Реверс? Игнор? Перезапуск с текущей позиции?

Последний пункт — самый недооценённый. Половина «глючных» анимаций в продакшене — это не плохой easing, а неотработанное прерывание.

Рабочий процесс передачи: от макета к спецификации

Большинство студий передают анимацию одним из двух способов: «вот прототип в Figma, посмотри» или «вот видео из After Effects, повтори». Оба способа ломаются по одной причине — разработчику негде взять числа. Прототип Figma не показывает easing в формате кривой Безье, а видео не различает 280 мс и 320 мс на глаз. В результате он лепит что-то близкое и отдаёт в ревью.

Рабочий процесс, который не разваливается на втором спринте, выглядит примерно так.

Шаги, которые стоит зафиксировать в команде

  1. Маркируйте анимации в макете. Прямо на фрейме — точка, бейдж, слой MOTION. Любой способ, чтобы при взгляде на экран было видно: «здесь движение, его нельзя пропустить».
  2. Заведите motion-спеку рядом с UI-спекой. Не отдельный документ в Notion, который никто не откроет. Это либо страница в файле Figma рядом с экраном, либо комментарий в Storybook/коде. Главное — рядом.
  3. Договоритесь о токенах движения. Длительности и easing должны жить в дизайн-системе, как цвета. duration-fast, duration-base, ease-out-standard. Когда разработчик пишет код, он подставляет токен, а не магическое число.
  4. Дайте видеореференс — но только в дополнение. Видео полезно как «вот так должно ощущаться», но числа всегда главнее. Если видео и спека противоречат — побеждает спека.
  5. Проведите motion review до релиза. Отдельная встреча на 20 минут, где дизайнер и разработчик прокликивают анимации вместе. Не на демо со всей командой — там их не разглядеть.

Что класть в motion-токены, а что нет

В токены идут параметры, которые повторяются. Длительности уровней (75 / 150 / 250 / 400 мс), стандартные easing (ease-out-standard, ease-in-out-standard, ease-spring-soft), задержки оркестрации (stagger 40 мс).

В токены не идут уникальные анимации — фирменный логотип, посадка иллюстрации на онбординге, празднование успеха. Их описывают как разовый спек с числами и видео. Не пытайтесь токенизировать всё — вы получите систему, которой никто не пользуется.

Как диагностировать, что движение «упростили»

Часто дизайнер видит, что «что-то не так», но не может сформулировать, что именно. Полезно иметь чеклист быстрой диагностики.

Симптомы и что они обычно значат

  • Всё двигается одинаково. Скорее всего, разработчик подставил один transition на все элементы. Иерархии нет.
  • Анимация работает на маунте, но не на размонтировании. Стандартная история React/Vue: появление дёшево, исчезновение требует библиотеки. Если её не заложили, элементы просто пропадают.
  • На hover всё дёргается. Свойство анимируется не то — например, width вместо transform: scale. Браузер пересчитывает layout, кадры теряются.
  • Анимация ускоряется при быстром клике. Прерывание не обработано: каждый клик запускает новый твин поверх старого.
  • На слабом телефоне всё лагает. Анимируется тяжёлое свойство или их слишком много одновременно. Фоновые движения не выключены.
  • На демо всё ок, в проде — статика. В сборку не попала библиотека анимаций или сработал prefers-reduced-motion, который никто не настраивал осознанно.

Вопросы для ревью с разработчиком

  • Какие свойства реально анимируются — transform/opacity или layout-свойства?
  • Что происходит при повторном триггере во время анимации?
  • Что происходит при prefers-reduced-motion: reduce? Полное отключение или сокращённая версия?
  • Что произойдёт, если анимация запустится во время скролла или открытия клавиатуры?
  • Тестировали на самом слабом устройстве из support-матрицы?

Если на половину вопросов ответ «не думал», у вас не анимация, а её черновик.

Типичные ошибки дизайнера, из-за которых движение режут

Разработчик не всегда виноват. Часто анимацию упрощают, потому что дизайнер сам сделал её необязательной.

  • Отдал прототип без чисел. «Там же видно» — нет, не видно. 200 мс и 400 мс на превью почти неразличимы, а в продукте это разные ощущения.
  • Сделал анимацию ради портфолио. 12 элементов влетают с задержкой, общий вход — 1.4 секунды. На демо красиво, в реальном использовании раздражает после третьего раза. Разработчик это чувствует и режет.
  • Не подумал про пустые и ошибочные состояния. Спека есть только для happy path. Что происходит при ошибке, при медленной сети, при пустом списке — не описано. Разработчик додумывает сам, обычно плохо.
  • Игнорировал accessibility. Если у анимации нет режима reduce, её либо оставят как есть (и поломают людям с вестибулярными нарушениями), либо отключат полностью.
  • Сделал движение единственным сигналом. Если ошибка показывается только покачиванием поля, без цвета и текста — это не доступно. На ревью такое справедливо упрощают.

Как применять это прямо в макете

Не обязательно сразу строить большую систему. Начать можно с одного экрана.

  • Возьмите ближайший флоу, который уходит в разработку. Перечислите все переходы и микровзаимодействия списком — сколько их вообще.
  • Для каждого пункта проставьте: триггер, свойство, длительность, easing, прерывание. Если не знаете — это и есть та дырка, через которую утечёт движение.
  • Отметьте, что блокирующее, а что фоновое. Фоновое подпишите как «можно резать на low-end».
  • Соберите 2–3 коротких видео — не один большой ролик, а отдельные клипы по 3–5 секунд на каждый ключевой переход. Их разработчик реально посмотрит.
  • На motion review пройдите по списку и поставьте галочки. То, что не реализовано — заведите тикетами с приоритетом, а не пунктами в Notion.

Короткий итог сегмента

Анимация выживает не там, где её красиво показали, а там, где её невозможно случайно потерять: числа в токенах, спека рядом с экраном, прерывание описано, фон отделён от блокирующего, ревью проведено отдельно. Всё остальное — вопрос вкуса, который проиграет дедлайну.

Продвинутые сценарии: где движение ломается чаще всего

Простые hover и появления почти всегда переживают разработку. Сложнее с состояниями, которые редко встречаются в макете, но постоянно — в продукте.

Анимации внутри списков и виртуализированных коллекций

Списки с большим количеством элементов часто рендерятся через виртуализацию — карточки появляются и исчезают из DOM по мере скролла. Если вы заложили анимацию входа карточки, она будет проигрываться каждый раз при возврате к этому элементу. На третьем проскролле это уже не «живой интерфейс», а нервный тик.

Что зафиксировать в спеке:

  • Анимация входа проигрывается один раз за сессию или только при первом маунте.
  • При reorder (drag, фильтр, сортировка) используется отдельный transition — обычно через FLIP-технику, а не повторный mount-анимация.
  • Скролл во время анимации её не прерывает рывком, а гасит плавно.

Переходы между экранами и shared element

Если в макете карточка «превращается» в детальный экран, разработчик почти наверняка реализует это как два независимых экрана с fade между ними. Shared element требует либо нативной поддержки (View Transitions API, Navigation на мобильных), либо ручной синхронизации позиций.

Здесь важно заранее ответить: что происходит, если пользователь нажал «назад» в середине перехода? Что — если данные детального экрана ещё не пришли? Без этих ответов shared element выкинут и заменят на cross-fade.

Анимации, завязанные на данные

Счётчики, прогресс-бары, графики, которые «доезжают» до значения. Типичная ошибка — описать их как «плавно меняется до X». В жизни значение может прийти дважды за секунду, прийти с задержкой или вернуться к старому при ошибке. Опишите три случая: первое появление, обновление в полёте, откат при ошибке. Иначе разработчик поставит мгновенное присваивание и будет прав.

AI и Figma MCP: где это помогает, а где мешает

Сейчас часто звучит «отдадим макет в AI, он сам соберёт анимации». На практике это работает только при одном условии: спека и токены уже есть. Тогда AI-ассистент в IDE может корректно подставить длительности, easing и привязать prefers-reduced-motion. Без токенов он выдумает значения, и они будут разными в каждом файле.

Где AI реально ускоряет работу:

  • Сгенерировать код hover/focus-состояний по описанию «scale 1.02, 120 мс, ease-out, transform-only».
  • Переписать анимацию с layout-свойств на transform.
  • Добавить обработку прерывания в существующий компонент.
  • Сделать reduce-motion вариант по основному.

Где он стабильно ошибается:

  • Сложные оркестрации между компонентами.
  • Сценарии, где нужно понимать продуктовый контекст: какие анимации блокирующие, какие фоновые.
  • Производительность на конкретном устройстве — модель не знает вашей support-матрицы.

Figma MCP и аналогичные мосты «макет → код» полезны для статики и базовых интеракций. Анимацию они передают плохо: в макете её попросту нет в полном виде. Поэтому видео-референс и числовая спека остаются обязательными, даже если остальную разметку собирает агент.

Отдельный риск: AI охотно «улучшает» анимации, делая их более выразительными, чем вы задумали. На ревью это ловится тем же чеклистом, что и работу человека — какие свойства, какие длительности, что с прерыванием.

Как проверять качество движения, а не только наличие

«Реализовано» и «реализовано правильно» — разные вещи. Чтобы не спорить на вкусовщине, заведите измеримые проверки.

  • Снимите экран с анимацией на 60 и 120 fps замедленной съёмкой телефона. Видно ли проскоки кадров, рывки на старте, дрожание в конце.
  • Откройте DevTools Performance, запустите анимацию. Смотрите на длинные таски в main thread и на то, какие свойства триггерят layout/paint. Идеал — composite-only.
  • Проверьте на самом слабом устройстве из support-матрицы, а не на своём ноутбуке. Если у команды нет такого — это отдельная проблема, не про анимацию.
  • Включите prefers-reduced-motion в системе и пройдите тот же флоу. Должна работать сокращённая версия, а не сломанный интерфейс с пропавшими переходами.
  • Запустите анимацию, прервите её на середине новым триггером. Поведение должно быть описано в спеке и совпадать с реализацией.

Чеклист motion review

  • Все блокирующие переходы укладываются в заявленные длительности.
  • Фоновые анимации можно отключить флагом или они отключаются на low-end.
  • Анимируются только transform и opacity, кроме случаев, явно согласованных.
  • Прерывание описано и работает: новый триггер не стакается с предыдущим.
  • Reduce-motion даёт осмысленный результат, а не пустые экраны.
  • Анимация не единственный сигнал состояния — есть текст, цвет, иконка.
  • На самом слабом устройстве из матрицы нет дропов кадров на ключевых переходах.

Как объяснить решение команде

Самая частая причина, по которой движение упрощают, — никто, кроме дизайнера, не понимает, зачем оно. Разработчик видит работу, продакт видит срок, QA видит баг «непонятное мерцание». Если вы не объяснили роль анимации, её будут резать как украшение.

Что работает на встречах:

  • Покажите два варианта экрана подряд: без анимации и с ней. Не для красоты, а чтобы зафиксировать, какую информацию движение несёт — иерархию, причинно-следственную связь, обратную связь на действие.
  • Привяжите каждую анимацию к продуктовой задаче: «этот переход показывает, что данные обновились, без него пользователь нажимает кнопку второй раз». Это аргумент, который останется после вас в тикете.
  • Разделите движение на «обязательное для смысла» и «приятное, но опциональное». Первое защищайте, второе спокойно отдавайте на сокращение. Если вы защищаете всё одинаково, не защитите ничего.
  • На ретро после релиза возвращайтесь к анимациям: что выжило, что упростили, что сломалось в проде. Это превращает движение из вкусовщины в нормальный инженерный объект, у которого есть история и метрики.

Короткий итог сегмента

Сложные сценарии — списки, переходы между экранами, данные — теряются чаще простых, потому что для них редко пишут полную спеку. AI и MCP помогают только поверх готовой системы токенов и правил, иначе размножают разнобой. Качество проверяется на слабом устройстве, в DevTools и с включённым reduce-motion, а не на ноутбуке дизайнера. И главное: анимация выживает там, где команда понимает её роль в продукте, а не там, где её красиво защищали один раз на питче.

Финальный сегмент — про то, как не наступить на типовые грабли и что спрашивать у себя и команды, прежде чем считать передачу анимаций завершённой. Чеклисты ниже работают как фильтр: если хоть один пункт «не знаю», передача ещё не готова, как бы красиво ни выглядел Figma-файл.

Анти-паттерны, из-за которых движение упрощают до статики

Это не про злую волю разработчика. Это про дыры в постановке, в которые любая команда провалится по умолчанию.

«Анимация есть в макете, остальное понятно»

Самая массовая ошибка. В макете лежит прототип на 200 мс, без кривой, без описания прерывания, без поведения на медленной сети. Разработчик честно делает «как в Figma» — и получает плоский fade, потому что больше там ничего не было.

Одна спека на всё приложение

«Используем ease-out 250 мс для всего» — звучит как система, работает как уравниловка. Маленькие тосты при таких параметрах ощущаются вялыми, большие шторки — рваными. Спека должна различать классы движения: микро-фидбек, переходы внутри экрана, смена экранов, фоновые процессы.

Видео-референс без числовой спеки

Запись из Principle или After Effects убеждает на питче, но не передаёт длительности и кривые. Разработчик снимает на глаз, и любое расхождение списывается на «ну, примерно так и есть». Через месяц вы не докажете, что было задумано иначе.

Анимация как единственный сигнал состояния

Кнопка «отправлено» только мигает и исчезает. На reduce-motion и на медленном устройстве сигнала нет вообще. Любое движение, которое несёт смысл, должно дублироваться текстом, цветом или иконкой.

«Допилим в полировке»

Анимации, отложенные на этап полировки, не доезжают до релиза примерно никогда. К этому моменту есть скоуп новой фичи, баги и дедлайн. Если движение важно — оно часть основной задачи, а не приложение к ней.

Защита всех анимаций как обязательных

Если на ревью вы спорите одинаково яростно за переход модалки и за параллакс на лендинге, вас перестают слушать. Команда учится резать всё подряд, потому что не видит границы между «нужно» и «приятно».

Финальный чеклист передачи

  • Для каждой анимации указаны: триггер, свойства, длительность, кривая, задержка.
  • Описано поведение при прерывании и при повторном триггере.
  • Есть версия для prefers-reduced-motion, и она осмысленная.
  • Указано, на каких устройствах анимация обязательна, а где может деградировать.
  • Анимации привязаны к токенам движения, а не к магическим числам в коде.
  • Видео-референс приложен в реальной скорости, без замедления для красоты.
  • Сложные сценарии (списки, переходы между экранами, загрузка данных) расписаны отдельно, а не «по аналогии».
  • Для каждой анимации понятно, какую продуктовую задачу она решает.
  • Согласован способ проверки: что именно открывает QA, чтобы сказать «сделано».

Вопросы для ревью

Эти вопросы стоит задавать и на дизайн-ревью спеки, и на code review реализации. Они быстро вскрывают слабые места.

  • Что произойдёт, если пользователь нажмёт триггер второй раз во время анимации?
  • Что увидит человек с включённым reduce-motion на этом экране?
  • Какие свойства анимируются и почему именно они?
  • Как эта анимация ведёт себя на самом слабом устройстве из support-матрицы?
  • Если убрать движение полностью, какая информация потеряется?
  • Где описана длительность — в коде, в токенах, в макете? Совпадают ли значения?
  • Эта анимация обязательна для смысла или это приятное украшение? И защищаем ли мы её соответствующим образом?
  • Что мы измеряем после релиза, чтобы понять, что движение работает?

Короткий практический итог

Анимации упрощают до статики не потому, что разработчики не умеют их делать. Их режут, когда у движения нет ясной роли, нет числовой спеки, нет места в системе токенов и нет способа проверить результат. Всё это решается не уговорами на ретро, а инженерной аккуратностью на стороне дизайна: тайминги, кривые, прерывания, поведение на reduce-motion и на слабых устройствах прописаны до того, как тикет попадает в разработку.

Дальше работает простое правило: защищайте обязательное, спокойно отдавайте опциональное, и каждый раз после релиза возвращайтесь посмотреть, что выжило в проде. Через несколько итераций движение в вашем продукте перестанет быть вкусовщиной и станет такой же нормальной частью системы, как сетка и типографика — со своими правилами, своими метриками и своей историей решений.

$ cd ../ ← назад к Прототипы и handoff