Вступ до Rive: інтерактивні анімації з State Machine
Ви запускаєте лендинг з анімацією завантаження, яка має реагувати на прогрес. Lottie не підходить — потрібно змінювати стан у відповідь на кліки. Рішення — Rive з State Machine. Типове завдання: кнопка 'Відправити' зі зворотним зв'язком — спочатку блимає, потім показує спіннер, потім галочку успіху. На CSS/JS це десятки рядків коду та синхронізація таймінгів. Rive з State Machine дозволяє дизайнеру закласти логіку переходів, а розробнику керувати нею з JavaScript. Ми використовуємо Rive в комерційних проектах вже понад 5 років — понад 20 успішних інтеграцій. Економія часу розробки порівняно з написанням анімацій на CSS/JS — до 60%, що може становити $500–1500 на проекті. Розмір рантайму Rive ~40 КБ gzip (за даними документації Rive) проти ~150 КБ у Lottie — це в 3,75 раза менше, що дає виграш у швидкості завантаження сторінки та покращує 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 docs) | ~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 переводить анімацію в стан «наведення», клік — у «натискання». Rive State Machine — це ключова фішка, яка відрізняє Rive від Lottie. Завдяки State Machine ви можете створювати складні сценарії взаємодії без написання коду логіки.
Покрокова інтеграція Rive з React
Крок 1: Встановіть пакет
npm install @rive-app/react-canvas
# або WebGL-рендерер (краще для складних сцен):
npm install @rive-app/react-webgl2
Крок 2: Створіть базовий компонент
// 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} />
}
Крок 3: Кнопка зі зворотним зв'язком через 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>
)
}
Крок 4: Керування числовими inputs та подіями
// 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 до 60% порівняно з Canvas 2D. Рекомендується використовувати ліниве завантаження .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. Середня економія бюджету на анімації — $1000 на проекті.
Типові помилки при інтеграції
- Неправильний fit/alignment — анімація може обрізатися
- Відсутність resizeDrawingSurfaceToCanvas — розмиття на retina
- Ігнорування події RiveEvent — втрата інтерактивності
Що входить у роботу з нами
- Створення або оптимізація .riv-файлу (за потреби)
- Інтеграція Rive State Machine з вашим React-проектом
- Налаштування inputs та подій (до 16 inputs)
- Оптимізація продуктивності (WebGL/Canvas, lazy loading)
- Документація з використання компонентів
- Тестування на різних пристроях (retina, мобільні)
- Підтримка після здачі (1 місяць)
Чому варто замовити інтеграцію в нас?
- Понад 5 років досвіду з анімаціями
- 20+ успішних інтеграцій Rive
- Гарантія якості: сертифіковані спеціалісти
- Пропонуємо інтеграцію під ключ за 2–5 днів
- Оцінимо ваш проект безкоштовно — напишіть нам!







