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-анимаций на сайт и сократите время разработки.







