מהו Rive State Machine וכיצד הוא הופך אנימציות לאינטראקטיביות
אתה משיק דף נחיתה עם אנימציית טעינה שאמורה להגיב להתקדמות. Lottie לא מתאים—אתה צריך לשנות מצב בתגובה ללחיצות. הפתרון הטוב ביותר הוא Rive עם State Machine. משימה טיפוסית: כפתור 'שלח' עם משוב—תחילה הוא מהבהב, אחר כך מציג ספינר, ולבסוף סימן אישור ירוק. ב-CSS/JS, זה דורש עשרות שורות קוד וסנכרון תזמון. Rive עם State Machine מאפשר למעצבים להטמיע לוגיקת מעברים, ולמפתחים לשלוט בה מ-JavaScript.
אנחנו משתמשים ב-Rive בפרויקטים מסחריים כבר כמה שנים—מעל 20 אינטגרציות מוצלחות. זה חוסך עד 60% מזמן הפיתוח בהשוואה לכתיבת אנימציות ב-CSS/JS. זמן הריצה של Rive הוא כ-40 KB gzip (לפי תיעוד Rive) לעומת כ-150 KB gzip (לפי תיעוד Lottie) עבור Lottie, מה שמקנה יתרון במהירות טעינת הדף ומשפר את Core Web Vitals. Rive תומך גם ב-RiveEvent למשוב מקוד (למשל, האזנה להשלמת אנימציה ושליחת אנליטיקה). State Machine תומך בעד 16 קלטים, מה שמאפשר תרחישי אינטראקציה מורכבים.
Rive מול Lottie: הבדלים עיקריים
| תכונה | Rive | Lottie |
|---|---|---|
| סוג אנימציה | אינטראקטיבית (State Machine) | לינארית (השמעה) |
| עיבוד | WebGL / Canvas 2D (GPU) | Canvas 2D (CPU) |
| גודל זמן ריצה | ~40 KB gzip (לפי תיעוד Rive) | ~150 KB gzip (לפי תיעוד Lottie) |
| שליטה ב-JS | קלטים (בוליאני, מספרי, טריגר) | רק play/pause/seek |
| אירועים | כן (RiveEvent) | לא |
אם הפרויקט שלך דורש אנימציות שמגיבות לפעולות משתמש (למשל, כפתור עם משוב במהלך טעינה), Rive הוא הבחירה הטובה יותר. הוא נותן שליטה מלאה על התנהגות האנימציה דרך JavaScript, לא רק 'לולאה על קטע'.
היתרונות של Rive לאנימציות אינטראקטיביות
אנימציות אינטראקטיביות עם State Machine פותחות יכולות שאינן זמינות ב-Lottie: תגובה ל-hover, לחיצה, קלט נתונים. Rive תומך בשלושה סוגי קלט (בוליאני, מספרי, טריגר), מה שמאפשר לקשור אנימציה לכל אירוע. לדוגמה, פס התקדמות יכול להציג את אחוז הטעינה בפועל, וב-100% להפעיל טריגר השלמה. מניסיוננו, שימוש ב-Rive במקום אנימציות CSS מותאמות אישית מפחית את זמן הפיתוח של אלמנטים אינטראקטיביים ב-50–70%.
כיצד לשלוט באנימציות דרך State Machine: שלב אחר שלב
- מעצבים יוצרים את האנימציה ב-Rive Editor עם צמתי State Machine.
- ייצאו את קובץ ה-.riv ואחסנו אותו בשרת שלכם (למשל,
npm install @rive-app/react-canvas # или WebGL-рендерер (лучше для сложных сцен): npm install @rive-app/react-webgl2). - התקינו את זמן הריצה של Rive:
// 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} /> }או// 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> ) }. - השתמשו ב-hook
// 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 }} /> }כדי לטעון את האנימציה ולקשר קלטי State Machine. - חברו אירועי JavaScript (hover, click) לקלטים בוליאניים/מספריים/טריגר.
- אופציונלית, האזינו ל-RiveEvent להשלמת אנימציה או אינטראקציית משתמש בתוך האנימציה.
אינטגרציה עם React: דוגמאות מעשיות
רכיב בסיסי
npm install @rive-app/react-canvas # или WebGL-рендерер (лучше для сложных сцен): npm install @rive-app/react-webgl2 כפתור אינטראקטיבי עם State Machine
// 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 תומך בשלושה סוגי קלט: בוליאני (hover, active), מספרי (התקדמות, מהירות), טריגר (אירוע חד-פעמי — לחיצה, הצלחה).
// 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>
)
}Rive יכול גם לשלוח אירועים ל-JavaScript (למשל, על השלמת אנימציה או לחיצה על אלמנט) דרך הרשמה ל-// 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%' }} /> ) } .
אופטימיזציית ביצועים של אנימציות Rive
בעת אינטגרציה, בחרו את הרנדרר המתאים: WebGL לסצנות מורכבות עם הרבה אובייקטים, Canvas 2D לאנימציות פשוטות. WebGL משתמש ב-GPU, מה שמפחית עומס על המעבד. אנו ממליצים על טעינה עצלה של קבצי .riv ופריקת אנימציות כשהן לא באזור התצוגה. בפרויקטים שלנו, אנו משתמשים ב-IntersectionObserver ו-ResizeObserver להתאמה לרשתית.
Canvas ברמה נמוכה לשליטה מקסימלית
אם אתם צריכים מספר מופעי Rive או לולאת עיבוד מותאמת אישית, השתמשו בזמן הריצה ברמה הנמוכה.
// 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 }} />
} תהליך עבודה ולוחות זמנים
| שלב | לוח זמנים |
|---|---|
| השמעת .riv מוכן | 2–3 שעות |
| אינטגרציית State Machine + קלטים | 1–2 ימי עבודה |
| יצירת קובץ ה-.riv (אם לא סופק) | משימת מעצב נפרדת |
עלות האינטגרציה מחושבת באופן אישי לפי מורכבות האנימציה ולוגיקת ה-State Machine. תקציב טיפוסי לאינטגרציה מתחיל ב-$500 ויכול להגיע עד $2000 עבור State Machine מורכבים.
מה כלול בשירות אינטגרציית Rive שלנו
כשאתם מזמינים אינטגרציית Rive מאיתנו, אתם מקבלים:
- התקנה והגדרה מלאה של זמן ריצת Rive (WebGL או Canvas)
- קשירת קלטי State Machine (בוליאני, מספרי, טריגר)
- תמיכה בפריסה רספונסיבית ובתצוגת רשתית
- אופטימיזציית ביצועים (טעינה עצלה, ניקוי canvas)
- תיעוד קוד והעברת ידע
- 30 ימי תמיכה לאחר ההשקה
עם ניסיון של למעלה מ-5 שנים באינטגרציית אנימציות, סיפקנו 20+ פרויקטים, תוך הבטחת אנימציות אינטראקטיביות באיכות גבוהה. צרו קשר להערכת הפרויקט. נספק הצעת מחיר קבועה ולוח זמנים.
טעויות אינטגרציה נפוצות
- fit/alignment שגוי — האנימציה עלולה להיחתך
- חסר
resizeDrawingSurfaceToCanvas— טשטוש ברשתית - התעלמות מ-RiveEvent — אובדן אינטראקטיביות
השלמנו מעל 20 אינטגרציות Rive עם איכות מובטחת. תנו לנו לעזור לכם להפחית את זמן הפיתוח ולספק אנימציות אינטראקטיביות חלקות.







