~/wiki / motion-i-animatsiya / animatsiya-progressa-ai-agenta-ux

Как показывать что AI думает: паттерны анимации прогресса агента

Основной чат

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

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

Спиннер придуман для операций длиной 0.5–2 секунды. LLM-запрос занимает 4–15 секунд. Многошаговая задача агента — до нескольких минут. За это время спиннер перестаёт работать как индикатор прогресса и становится источником тревоги: «что-то происходит?», «система зависла?», «стоит ли ждать?»

Проектирование AI-интерфейсов требует нового motion-словаря.


Почему старые паттерны не работают

Традиционный загрузчик предполагает бинарное состояние: либо готово, либо нет. Кнопка — спиннер — результат.

AI-процессинг другой. Это серия шагов с разной длительностью, с промежуточными результатами, с возможностью частичного ответа который уже несёт ценность. И — главное — пользователь не знает как долго ждать. Нет progress bar который доходит до 100%. Это принципиально другой тип неопределённости.

Три проблемы которые решает правильная анимация AI-прогресса:

Тревога. «Система работает или зависла?» — спиннер не отвечает. Streaming output или progress log отвечает.

Потеря контроля. Пользователь не видит что происходит. Expandable process details дают контроль не прерывая работу.

Непредсказуемость. Неизвестно когда закончится. Конкретные шаги в progress log делают ожидание осмысленным.


Пять паттернов

Streaming output — самый эффективный

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

Почему работает: нет ощущения ожидания. Процесс видим. Можно оценить направление ответа раньше чем он завершён — и при необходимости остановить.

Анимация: тихая. Только появление новых символов. Cursor-blink не нужен, typing indicator поверх не нужен.

javascript
// React: накопление токенов в state
const [text, setText] = useState('')

// При получении каждого токена:
setText(prev => prev + token)

// Рендеринг с автоскроллом к низу
useEffect(() => {
  containerRef.current?.scrollTo(0, containerRef.current.scrollHeight)
}, [text])

Progress log — нарратив вместо спиннера

Последовательность коротких сообщений о том что агент делает прямо сейчас. Не статус — нарратив.

plaintext
Анализирую запрос...
Ищу релевантные данные в 3 источниках...
Нашёл 12 совпадений, фильтрую по дате...
Формирую ответ...

Почему работает: пользователь понимает что система активна и что именно делает. Ожидание становится осмысленным — у него есть структура.

Анимация: каждая строка появляется fade-in (opacity 0→1, translateY 4→0, 200мс). Текущий шаг — с пульсирующей точкой. Завершённые — с галочкой.

css
@keyframes logEntry {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

.log-item { animation: logEntry 0.2s ease-out forwards; }

.log-item.active::after {
  content: '●';
  animation: pulse 1s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.3; }
}

Skeleton с постепенным заполнением

Структура ответа показывается заранее как skeleton — заполняется по мере готовности. Для структурированного контента: карточки, таблицы, списки.

Почему работает: пользователь видит что придёт. Нет пустоты. Нет тревоги о неизвестности — форма результата уже известна.

css
.skeleton {
  background: linear-gradient(
    90deg,
    var(--color-surface) 25%,
    var(--color-surface-hover) 50%,
    var(--color-surface) 75%
  );
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
}

@keyframes shimmer {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}

Animated thinking indicator

Три точки с typing-анимацией — стандарт мессенджеров. Работает для conversational AI с коротким временем ответа (до 3–4 секунд).

После 5 секунд начинает выглядеть как зависание. Использовать только как первый шаг — потом переключать на progress log или streaming.

Expandable process details

Агент работает — пользователь видит краткий статус. По клику — детальный лог каждого шага. Progressive disclosure: детали доступны, но не навязаны.

Паттерн: collapsed by default с иконкой «показать подробности». Разворачивается через height: 0 → auto (interpolate-size: allow-keywords в CSS или через JavaScript).


Что не работает

Determinate progress bar без реального прогресса. Если bar движется независимо от реального состояния — пользователь чувствует это. Доверие падает быстро.

Percentage без контекста. «47% выполнено» — что именно? Без понимания что считается — число бессмысленно и создаёт ложное ощущение предсказуемости.

Спиннер дольше 4 секунд как единственный индикатор. После 4 секунд пользователь не знает ждать ли ещё, закрыть ли страницу. Нужен дополнительный сигнал.

Анимация прогресса без кнопки «Стоп». Многошаговая задача агента может пойти не туда. Пользователь должен иметь возможность остановить в любой момент.


Промпт для Codex / Claude Code

markdown
Реализуй паттерн отображения прогресса AI-ответа для [компонент].

Паттерны в зависимости от типа ответа:
1. Текстовый ответ < 5 сек: streaming output (накопление токенов в state)
2. Текстовый ответ > 5 сек: typing indicator (3 сек) → streaming
3. Многошаговая задача: progress log с конкретными шагами
4. Структурированный контент: skeleton с shimmer → постепенное заполнение

Общие требования:
- Кнопка «Стоп» видна всё время пока агент работает
- После 4 сек без изменений: показать текстовый статус "всё ещё работаю..."
- При streaming: автоскролл к последнему токену
- При ошибке: явное сообщение с кнопкой "Попробовать снова"
plaintext
Короткий ответ (< 5 сек):
☐ Streaming output или typing indicator

Длинный ответ (> 5 сек):
☐ Progress log с конкретными шагами
☐ Кнопка «Стоп» всегда видна

Структурированный контент:
☐ Skeleton с shimmer → заполнение

Любой AI-процессинг:
☐ Нет спиннера как единственного индикатора > 3 сек
☐ После 4 сек: текстовый статус "всё ещё работаю"
☐ Есть cancel/stop механизм
☐ При ошибке: конкретное сообщение + retry

Почему это важнее чем кажется

В 2023 году большинство AI-интерфейсов показывали спиннер пока модель думает. Пользователи привыкли. Ждали. Иногда обновляли страницу — не понимая зависло ли.

В 2026 году ожидания изменились. Пользователи знают что LLM может думать секунды и минуты. Они знают что можно видеть процесс через streaming. Спиннер без прогресса воспринимается не как «нормально» а как «этот продукт не позаботился».

Motion для AI-прогресса — это уже не «приятное дополнение». Это базовое ожидание которое влияет на доверие к продукту.


Разные паттерны для разных типов AI-задач

Не все AI-задачи одинаковы с точки зрения UX прогресса.

Синхронные запросы (< 3 сек). Пользователь нажал → ждёт → получил результат. Typing indicator или skeleton достаточно. Streaming не нужен — ответ приходит быстро.

Асинхронные запросы (3–15 сек). Пользователь нажал → видит процесс → получает результат по мере готовности. Streaming для текста, skeleton для структуры. Кнопка «Стоп» обязательна.

Агентные задачи (> 15 сек, возможно минуты). Пользователь дал задание → агент работает несколько шагов → результат. Progress log с конкретными шагами. Expandable details. Уведомление когда готово (если пользователь ушёл делать другое).

Один паттерн на все три типа — это ошибка.


Когда показывать кнопку «Стоп»

Всегда. Без исключений.

Любой AI-процесс может пойти не туда: неправильная интерпретация запроса, бесконечный loop, слишком долгое время. Пользователь должен иметь возможность остановить в любой момент.

Кнопка «Стоп» должна быть:

  • Видима всё время пока агент работает (не скрыта за кликом)
  • Достаточно большой для уверенного нажатия (минимум 44×44px)
  • Деструктивной по виду — но не пугающей (не красная кнопка с иконкой опасности)

После нажатия «Стоп» — показать что успело сделать, не просто очистить экран.


Что происходит когда ответ приходит частями

Многие AI-системы возвращают результат не одним куском а частями по мере готовности. Первая карточка готова через 2 секунды, вторая через 4, третья через 7.

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

Пример: дашборд с четырьмя метриками. Каждая загружается независимо. Не показывать skeleton 7 секунд а потом все четыре сразу — показывать каждую по мере готовности. Пользователь уже читает первую пока загружаются остальные.


Accessibility: анимации прогресса и assistive technology

Screen readers не видят анимированный прогресс. Если progress log обновляется визуально но без ARIA-анонсов — пользователь со screen reader не знает что происходит.

Минимальное решение: aria-live="polite" на контейнере progress log. Каждое новое сообщение будет озвучено автоматически.

html
<div aria-live="polite" aria-label="Статус выполнения задачи">
  <p>Анализирую запрос...</p>
</div>

Для streaming output: aria-live="off" на потоковом контейнере (каждый токен отдельно слишком шумно) + aria-live="polite" на финальном результате.

Кнопка «Стоп» должна иметь понятный aria-label: «Остановить выполнение задачи», не просто «Стоп».

$ cd ../ ← назад к Motion и анимация