Rive-анимации на сайте: State Machine и интеграция
Вы запускаете лендинг с анимацией загрузки, которая должна реагировать на прогресс. Lottie не подходит — нужно менять состояние в ответ на клики. Решение — Rive с State Machine. Типовая задача: кнопка 'Отправить' с обратной связью — сперва мигает, затем показывает спиннер, потом галку успеха. На CSS/JS это десятки строк кода и синхронизация таймингов. Rive с State Machine позволяет дизайнеру заложить логику переходов, а разработчику управлять ею из JavaScript. Мы используем Rive в коммерческих проектах уже несколько лет — более 20 успешных интеграций. Экономия времени разработки по сравнению с написанием анимаций на CSS/JS — до 60%. Размер рантайма Rive ~40 КБ gzip против ~150 КБ у Lottie, что даёт выигрыш в скорости загрузки страницы и улучшает Core Web Vitals. Rive также поддерживает события RiveEvent для обратной связи с кодом. Например, можно слушать завершение анимации и отправлять аналитику. State Machine поддерживает до 16 inputs, что позволяет реализовать сложные сценарии взаимодействия. Для быстрого выбора подходящего формата сравним Rive с Lottie по ключевым параметрам.
Что такое Rive и почему он лучше Lottie?
| Характеристика | Rive | Lottie |
|---|---|---|
| Тип анимации | Интерактивная (State Machine) | Линейная (воспроизведение) |
| Рендеринг | WebGL / Canvas 2D (GPU) | Canvas 2D (CPU) |
| Размер рантайма | ~40 КБ gzip (по данным документации Rive) | ~150 КБ gzip |
| Управление из JS | Inputs (boolean, number, trigger) | Только play/pause/seek |
| События | Да (RiveEvent) | Нет |
Если ваш проект требует анимаций, которые реагируют на действия пользователя (например, кнопка с обратной связью при загрузке), Rive — лучший выбор. Он даёт полный контроль над поведением анимации через JavaScript, а не просто «зациклить отрезок».
Почему стоит выбрать Rive для интерактивных анимаций?
Интерактивные анимации на основе State Machine открывают возможности, недоступные в Lottie: реагирование на hover, клик, ввод данных. Rive поддерживает три типа inputs (Boolean, Number, Trigger), что позволяет привязать анимацию к любому событию. Например, прогресс-бар может отображать реальный процент загрузки, а при достижении 100% запускать триггер завершения. По нашим данным, использование Rive вместо кастомных CSS-анимаций сокращает время разработки интерактивных элементов на 50–70%.
Как State Machine делает анимации интерактивными?
State Machine — граф переходов между анимациями. Дизайнер создаёт логику в Rive Editor, разработчик управляет inputs из кода. Например, hover переводит анимацию в состояние «наведение», клик — в «нажатие».
npm install @rive-app/react-canvas # или WebGL-рендерер (лучше для сложных сцен): npm install @rive-app/react-webgl2 Интеграция с React: практические примеры
Базовый компонент
// components/RiveAnimation.tsx 'use client' import { useRive, Layout, Fit, Alignment } from '@rive-app/react-canvas' interface RiveAnimationProps { src: string stateMachine?: string animation?: string className?: string } export function RiveAnimation({ src, stateMachine, animation, className, }: RiveAnimationProps) { const { RiveComponent } = useRive({ src, stateMachines: stateMachine ? [stateMachine] : undefined, animations: animation ? [animation] : undefined, autoplay: true, layout: new Layout({ fit: Fit.Contain, alignment: Alignment.Center, }), }) return <RiveComponent className={className} /> } Кнопка с обратной связью через State Machine
// components/InteractiveButton.tsx 'use client' import { useRive, useStateMachineInput } from '@rive-app/react-canvas' export function RiveButton() { const { RiveComponent, rive } = useRive({ src: '/animations/button.riv', stateMachines: 'ButtonSM', autoplay: true, }) const isHoverInput = useStateMachineInput(rive, 'ButtonSM', 'isHover') const isPressedInput = useStateMachineInput(rive, 'ButtonSM', 'isPressed') const isLoadingInput = useStateMachineInput(rive, 'ButtonSM', 'isLoading') const handleClick = async () => { if (isLoadingInput) isLoadingInput.value = true await fetch('/api/action') if (isLoadingInput) isLoadingInput.value = false } return ( <button className="relative w-48 h-14" onMouseEnter={() => isHoverInput && (isHoverInput.value = true)} onMouseLeave={() => isHoverInput && (isHoverInput.value = false)} onMouseDown={() => isPressedInput && (isPressedInput.value = true)} onMouseUp={() => isPressedInput && (isPressedInput.value = false)} onClick={handleClick} > <RiveComponent /> </button> ) } Как управлять числовыми inputs?
State Machine поддерживает три типа inputs: Boolean (hover, active), Number (прогресс, скорость), Trigger (одноразовое событие — клик, успех).
// components/ProgressRive.tsx 'use client' import { useRive, useStateMachineInput } from '@rive-app/react-canvas' interface ProgressRiveProps { progress: number // 0–100 } export function ProgressRive({ progress }: ProgressRiveProps) { const { RiveComponent, rive } = useRive({ src: '/animations/progress.riv', stateMachines: 'ProgressSM', autoplay: true, }) const progressInput = useStateMachineInput(rive, 'ProgressSM', 'progress') const completeTrigger = useStateMachineInput(rive, 'ProgressSM', 'complete', false) if (progressInput) progressInput.value = progress if (progress >= 100 && completeTrigger) completeTrigger.fire() return <RiveComponent style={{ width: 300, height: 80 }} /> } Rive также может отправлять события в JavaScript. Например, при завершении анимации или клике на элемент. Это реализуется через подписку на EventType.RiveEvent.
Оптимизация производительности Rive-анимаций
При интеграции важно выбрать подходящий рендерер: WebGL для сложных сцен с большим количеством объектов, Canvas 2D для простых анимаций. WebGL использует GPU, что снижает нагрузку на CPU. Рекомендуется использовать ленивую загрузку .riv-файлов и выгружать анимации, когда они не в зоне видимости. В наших проектах мы применяем IntersectionObserver и ResizeObserver для адаптации под retina-экраны.
Оптимизация: ручной Canvas для максимального контроля
Если нужно несколько Rive-инстанций или кастомный цикл рендера, используйте низкоуровневый рантайм.
// components/LowLevelRive.tsx 'use client' import { useEffect, useRef } from 'react' import Rive, { Fit } from '@rive-app/canvas' export function LowLevelRive({ src }: { src: string }) { const canvasRef = useRef<HTMLCanvasElement>(null) useEffect(() => { if (!canvasRef.current) return const r = new Rive({ canvas: canvasRef.current, src, autoplay: true, onLoad: () => { r.resizeDrawingSurfaceToCanvas() }, }) const observer = new ResizeObserver(() => { r.resizeDrawingSurfaceToCanvas() }) observer.observe(canvasRef.current) return () => { r.cleanup() observer.disconnect() } }, [src]) return ( <canvas ref={canvasRef} style={{ width: '100%', height: '100%' }} /> ) } Процесс работы и сроки
| Этап | Срок |
|---|---|
| Воспроизведение готового .riv | 2–3 часа |
| Интеграция State Machine + inputs | 1–2 рабочих дня |
| Создание .riv-файла (если нет) | Отдельная задача для дизайнера |
Стоимость интеграции рассчитывается индивидуально и зависит от сложности анимаций и логики State Machine.
Типичные ошибки при интеграции
- Неправильный fit/alignment — анимация может обрезаться
- Отсутствие resizeDrawingSurfaceToCanvas — размытие на retina
- Игнорирование события RiveEvent — потеря интерактивности
Свяжитесь с нами для оценки вашего проекта — получите консультацию инженера с опытом более 20 интеграций. Закажите интеграцию Rive-анимаций на сайт и сократите время разработки.







