בפרק 8 למדתם SVG — איך לצייר גרפיקה וקטורית בדפדפן ולהנפיש אותה עם CSS ו-GSAP. עכשיו שאלה חשובה: מה קורה כשאתם צריכים אנימציה מורכבת — דמות שמנופפת, אייקון שמשתנה, מעבר loading מרשים — אבל אין לכם את הזמן או המיומנות ליצור אותה מאפס? התשובה: אנימציות מוכנות. Lottie לוקח אנימציות שנוצרו ב-After Effects ומנגן אותן בדפדפן כקבצי JSON קלי משקל. Rive הולך צעד קדימה — הוא מאפשר ליצור אנימציות אינטראקטיביות עם state machines, כך שהאנימציה מגיבה ל-hover, click, ומצבי אפליקציה בזמן אמת. בפרק הזה תלמדו את שניהם: מתי להשתמש ב-Lottie, מתי ב-Rive, ואיך לשלב אנימציות מוכנות בפרויקטים שלכם — עם קוד מינימלי ותוצאות מקסימליות.
בפרק 8 בניתם אנימציות SVG — morphing, draw-on, ואייקונים אנימטיביים. בפרק הזה תוסיפו שכבה חדשה: אנימציות מוכנות שמעלות את הרמה בלי לכתוב הכל מאפס. תשלבו Lottie animation ב-hero section שלכם (loading או success indicator), תוסיפו empty state אנימטיבי עם Lottie, ותבנו אנימציה אינטראקטיבית אחת עם Rive שמגיבה ל-hover ו-click. בפרק 10 תלמדו Canvas — ציור פיקסלי לאנימציות שגם SVG וגם Lottie לא יכולים לעשות.
| מונח (English) | תרגום | הגדרה |
|---|---|---|
| Lottie | לוטי | פורמט אנימציה מבוסס JSON שנוצר על ידי Airbnb. מאפשר לנגן אנימציות After Effects בדפדפן, באפליקציות mobile ובכל פלטפורמה — בגודל קובץ זעיר |
| Rive | רייב | פלטפורמה ליצירת אנימציות אינטראקטיביות עם state machines. מאפשר ליצור אנימציות שמגיבות לקלט משתמש בזמן אמת — דבר ש-Lottie לא תומך בו באופן מקורי |
| Bodymovin | בודימובין | Plugin ל-Adobe After Effects שמייצא אנימציות לפורמט Lottie JSON. הגשר בין עולם ה-motion design לעולם ה-web |
| LottieFiles | לוטיפיילס | Marketplace ופלטפורמה לאנימציות Lottie — חיפוש, תצוגה מקדימה, התאמה אישית, והורדה. אלפי אנימציות חינמיות ובתשלום |
| state machine | מכונת מצבים | מודל שמגדיר מצבים (idle, hover, click, success) ומעברים ביניהם. ב-Rive, state machines שולטים באנימציה — כל מצב מנגן אנימציה אחרת |
| artboard | לוח עבודה | ב-Rive, ה-canvas שבו מעצבים את האנימציה. כל artboard יכול להכיל מספר state machines ואנימציות. דומה ל-layer ב-Photoshop |
| dotlottie (.lottie) | דוט-לוטי | פורמט חדש של Lottie — קובץ דחוס (ZIP) שמכיל JSON + assets. קטן עד פי 10 מ-JSON רגיל, ותומך בכמה אנימציות בקובץ אחד |
| lottie-player | נגן לוטי | Web component רשמי של LottieFiles — תג HTML <lottie-player> שמנגן אנימציות Lottie. הדרך הפשוטה ביותר לשלב Lottie באתר |
| rive-react | רייב-ריאקט | ספריית React רשמית של Rive — hook useRive שמנגן אנימציות Rive בתוך קומפוננטת React עם שליטה מלאה ב-state machine |
| After Effects | אפטר אפקטס | תוכנת motion design מקצועית של Adobe — הכלי הסטנדרטי ליצירת אנימציות מורכבות. Bodymovin מייצא אנימציות AE לפורמט Lottie |
| keyframe export | ייצוא מפתחות | התהליך שבו Bodymovin ממיר keyframes מ-After Effects ל-JSON — כל keyframe הופך לאובייקט JSON עם זמן, ערך, ו-easing |
| segment | מקטע | חלק מאנימציית Lottie — מוגדר על ידי frame התחלה ו-frame סיום. מאפשר לנגן רק חלק מהאנימציה, למשל רק את ה-hover state |
עד עכשיו בקורס הזה, כל אנימציה שבניתם — כתבתם בעצמכם. CSS transitions, GSAP tweens, SVG morphing — קוד שאתם שולטים בכל שורה שלו. וזה מצוין! אבל בעולם האמיתי, יש סוגים של אנימציות שפשוט לא שווה לבנות מאפס.
תחשבו על זה: אנימציית loading מורכבת עם 15 אלמנטים שזוחלים, מסתובבים ומשנים צבעים? זה 200+ שורות CSS או GSAP. דמות מצוירת שמנופפת ביד? אין סיכוי בקוד בלבד — צריך שרטוט, rigging, ו-frame-by-frame animation. אייקון שמשנה צורה מ-hamburger ל-X עם 12 keyframes חלקים? אפשר בקוד, אבל motion designer עם After Effects יעשה את זה טוב יותר בחצי מהזמן.
אנימציות מוכנות (pre-made animations) פותרות את הבעיה הזו. הן נוצרות בכלי עיצוב מקצועיים — After Effects, Rive Editor, Figma — ואז מיוצאות לפורמט שהדפדפן יכול לנגן. אתם לא צריכים לדעת motion design — אתם צריכים לדעת איך לשלב את האנימציה בקוד שלכם.
שתי הטכנולוגיות הדומיננטיות בתחום הזה הן:
| קריטריון | קודד בעצמך (CSS/GSAP/SVG) | אנימציה מוכנה (Lottie/Rive) |
|---|---|---|
| מורכבות ויזואלית | אלמנטים גיאומטריים פשוטים — קוים, עיגולים, מלבנים, טקסט | איורים, דמויות, אנימציות עם עשרות אלמנטים, אפקטים אורגניים |
| שליטה בזמן ריצה | שליטה מלאה בכל פרמטר — אתם כותבים הכל | שליטה דרך API: play, pause, speed, segments, state inputs |
| גודל קובץ | אפס — הקוד כבר בבאנדל | 5KB-200KB (Lottie JSON) / 2KB-50KB (.riv) |
| זמן פיתוח | תלוי במורכבות — דקות עד שעות | דקות — מורידים, משלבים, מתאימים |
| אינטראקטיביות | כל דבר שתקודדו | Lottie: מוגבלת. Rive: state machines מלאים |
| תלות חיצונית | אפס (CSS) או GSAP (JS) | lottie-web (~250KB) או @rive-app/canvas (~150KB) |
כלל אצבע: אם אתם יכולים לתאר את האנימציה ב-3 שורות — קודדו. אם אתם צריכים ציור כדי להסביר אותה — חפשו אנימציה מוכנה.
חשוב להבין: Lottie ו-Rive הם לא מתחרים — הם משלימים. Lottie מצוין כשצריך אנימציה יפה שרצה — loading, success indicator, אייקון אנימטיבי, הנפשת דמות. Rive מצוין כשהאנימציה צריכה להגיב — כפתור שמשנה מצב, avatar שעוקב אחרי העכבר, game-like interaction. ברוב הפרויקטים תשתמשו בשניהם — Lottie לאנימציות "רקע" ו-Rive לאנימציות "אינטראקטיביות".
Lottie נולד ב-2017 כפרויקט פנימי של Airbnb. הצוות רצה אנימציות עשירות באפליקציית המובייל — אבל GIF היו כבדים מדי, וידאו היה יקר, ו-CSS animations היו מוגבלות. הפתרון: plugin ל-After Effects (בשם Bodymovin) שמייצא את האנימציה כ-JSON, ונגן קל שמנגן את ה-JSON בזמן ריצה.
איך Lottie עובד — הצינור המלא:
ככה נראה Lottie JSON מבפנים (גרסה מקוצרת מאוד):
// מבנה בסיסי של Lottie JSON
{
"v": "5.7.1", // גרסת Bodymovin
"fr": 30, // frame rate (30fps)
"ip": 0, // in-point (frame התחלה)
"op": 60, // out-point (frame סיום) → 60/30 = 2 שניות
"w": 200, // רוחב
"h": 200, // גובה
"layers": [ // שכבות האנימציה
{
"ty": 4, // סוג שכבה: 4 = shape layer
"nm": "Circle", // שם השכבה
"ks": { // keyframes לכל property
"o": { "a": 1, "k": [/* opacity keyframes */] },
"p": { "a": 1, "k": [/* position keyframes */] },
"s": { "a": 1, "k": [/* scale keyframes */] }
},
"shapes": [/* SVG path data */]
}
]
}
מה שמדהים בפורמט הזה: הוא וקטורי. כמו SVG, Lottie מבוסס על נתיבים מתמטיים — לא פיקסלים. זה אומר שהאנימציה נראית חדה בכל רזולוציה, בכל גודל מסך. ובגלל שזה JSON — אפשר לדחוס אותו עם gzip ולהקטין עוד 60-70%.
Bodymovin לא תומך ב-100% מהפיצ'רים של After Effects. אפקטים כמו 3D camera, complex expressions, blur/glow, ו-track mattes מסוימים — לא ייוצאו כמו שצריך. כש-Lottie animation נראית שבורה, זו בדרך כלל הסיבה. תמיד בדקו ב-LottieFiles Preview לפני שמשלבים באתר. אם אתם עובדים עם motion designer — בקשו שישתמש רק ב-features נתמכים (shape layers, trim paths, masks, basic effects).
שלושת הרנדרים של Lottie: lottie-web תומך ב-3 מצבי רינדור:
בפועל, SVG הוא כמעט תמיד הבחירה הנכונה. Canvas שווה רק כשיש אנימציות מאוד כבדות (50+ שכבות) והביצועים סובלים. HTML כמעט לא בשימוש ב-2026.
LottieFiles הוא ל-Lottie מה ש-Unsplash הוא לתמונות — marketplace ענק שבו מעצבים מעלים אנימציות, ומפתחים מורידים ומשלבים. נכון ל-2026, יש ב-LottieFiles יותר מ-200,000 אנימציות, רובן חינמיות. זה המקום הראשון שתחפשו בו כשצריכים אנימציית Lottie.
חיפוש חכם ב-LottieFiles:
LottieFiles Editor — התאמה אישית בלי After Effects:
אחד הפיצ'רים הכי שימושיים של LottieFiles הוא ה-Editor המובנה. אחרי שבחרתם אנימציה, אפשר:
רוב האנימציות ב-LottieFiles הן "Free" — אבל יש הבדל בין "free for personal use" לבין "free for commercial use". תמיד בדקו את הרישיון של האנימציה הספציפית. אנימציות Premium דורשות מנוי ($). אם אתם בונים מוצר מסחרי — השקיעו ב-Premium או בדקו שהרישיון החינמי מאפשר שימוש מסחרי. אל תניחו — תבדקו.
יש שלוש דרכים עיקריות לשלב Lottie באתר. נתחיל מהפשוטה ביותר ונתקדם:
דרך 1: lottie-player Web Component (הכי פשוט)
lottie-player הוא web component רשמי של LottieFiles. תג HTML אחד — וזה עובד. זו הדרך המומלצת לרוב הפרויקטים:
<!-- שלב 1: טעינת הספרייה (פעם אחת, ב-head או לפני הסגירה של body) -->
<script src="https://unpkg.com/@lottiefiles/lottie-player@2/dist/lottie-player.js"></script>
<!-- שלב 2: שימוש ב-web component -->
<lottie-player
src="https://lottiefiles.com/animations/success-check"
background="transparent"
speed="1"
style="width: 300px; height: 300px;"
loop
autoplay
></lottie-player>
הפרמטרים העיקריים:
דרך 2: lottie-web ישירות (יותר שליטה)
lottie-web היא הספרייה שמאחורי lottie-player. אם צריכים שליטה מלאה — אפשר להשתמש בה ישירות:
// התקנה: npm install lottie-web
import lottie from 'lottie-web';
// יצירת instance
const animation = lottie.loadAnimation({
container: document.getElementById('lottie-container'),
renderer: 'svg', // 'svg' | 'canvas' | 'html'
loop: true,
autoplay: true,
path: '/animations/loading.json' // URL לקובץ JSON
// או: animationData: jsonObject // JSON ישירות (בלי network request)
});
// שליטה בסיסית
animation.play();
animation.pause();
animation.stop();
animation.setSpeed(1.5); // מהירות
animation.setDirection(-1); // אחורה
animation.goToAndStop(30, true); // קפוץ ל-frame 30 ועצור
animation.goToAndPlay(0, true); // קפוץ ל-frame 0 והתחל
// events
animation.addEventListener('complete', () => {
console.log('Animation finished!');
});
animation.addEventListener('loopComplete', () => {
console.log('Loop completed');
});
דרך 3: React עם @lottiefiles/react-lottie-player
// התקנה: npm install @lottiefiles/react-lottie-player
import { Player } from '@lottiefiles/react-lottie-player';
function SuccessAnimation() {
return (
<Player
autoplay
loop={false}
src="/animations/success.json"
style={{ height: '200px', width: '200px' }}
onEvent={(event) => {
if (event === 'complete') {
console.log('Animation done!');
}
}}
/>
);
}
// עם ref לשליטה מלאה
import { useRef } from 'react';
function ControlledAnimation() {
const playerRef = useRef(null);
return (
<div>
<Player
ref={playerRef}
src="/animations/toggle.json"
style={{ height: '100px', width: '100px' }}
/>
<button onClick={() => playerRef.current?.play()}>Play</button>
<button onClick={() => playerRef.current?.pause()}>Pause</button>
</div>
);
}
דרך 4: dotlottie — הפורמט החדש והקל
dotlottie (.lottie) הוא פורמט חדש יותר — קובץ דחוס (ZIP) שמכיל את ה-JSON + assets (תמונות, פונטים). היתרונות:
<!-- dotlottie player -->
<script src="https://unpkg.com/@dotlottie/player-component@2/dist/dotlottie-player.mjs" type="module"></script>
<dotlottie-player
src="/animations/hero.lottie"
background="transparent"
speed="1"
style="width: 400px; height: 400px;"
loop
autoplay
></dotlottie-player>
קריטריון הצלחה: אנימציית Lottie רצה בדף שלכם, בגודל מתאים, עם background שקוף.
lottie-web (הספרייה שמרנדרת Lottie) שוקלת כ-250KB (minified). זה לא מעט! אם הדף שלכם טוען אנימציית Lottie אחת קטנה — אתם עלולים לטעון 250KB של JavaScript עבור אנימציה של 10KB. שתי אסטרטגיות: (1) השתמשו ב-lottie-light (150KB, בלי expressions ו-canvas renderer) אם מספיק. (2) טענו את lottie-player רק כשצריך — lazy loading עם Intersection Observer (סעיף 9.11). אל תטענו את הספרייה ב-head אם האנימציה ב-footer.
Lottie "וניל" הוא play-and-forget — האנימציה רצה ואתם צופים. אבל עם קצת JavaScript, אפשר להפוך אנימציית Lottie לאינטראקטיבית: להפעיל ב-scroll, לנגן segment ב-hover, לשלוט ב-speed ב-click, ולקשר את ההתקדמות לפעולות משתמש.
תבנית 1: Play on scroll (Intersection Observer)
// האנימציה מתחילה רק כשהאלמנט נכנס ל-viewport
const player = document.querySelector('lottie-player');
// בהתחלה — עצורה
player.removeAttribute('autoplay');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
player.play();
observer.unobserve(entry.target); // פעם אחת בלבד
}
});
}, { threshold: 0.5 }); // 50% מהאלמנט נראה
observer.observe(player);
תבנית 2: Scroll-driven — התקדמות צמודה לגלילה
// האנימציה מתקדמת לפי מיקום הגלילה
const player = document.querySelector('lottie-player');
const container = document.getElementById('scroll-container');
// חישוב אחוז הגלילה
function updateAnimation() {
const rect = container.getBoundingClientRect();
const scrollPercent = Math.max(0, Math.min(1,
(window.innerHeight - rect.top) / (window.innerHeight + rect.height)
));
// המרה ל-frame
const totalFrames = player.getLottie().totalFrames;
const frame = Math.floor(scrollPercent * totalFrames);
player.getLottie().goToAndStop(frame, true);
}
// ביצועים: requestAnimationFrame + passive listener
let ticking = false;
window.addEventListener('scroll', () => {
if (!ticking) {
requestAnimationFrame(() => {
updateAnimation();
ticking = false;
});
ticking = true;
}
}, { passive: true });
תבנית 3: Hover — נגן segment
// ב-hover: נגן frames 0-30 (הופעה)
// ב-leave: נגן frames 30-60 (היעלמות)
const player = document.querySelector('lottie-player');
const lottieInstance = player.getLottie();
player.addEventListener('mouseenter', () => {
lottieInstance.playSegments([0, 30], true);
});
player.addEventListener('mouseleave', () => {
lottieInstance.playSegments([30, 60], true);
});
// true = force — מתחיל מיד, בלי להמתין לסיום הסגמנט הנוכחי
תבנית 4: Click toggle — מעבר בין מצבים
// לחיצה מחליפה בין "on" (frames 0-30) ל-"off" (frames 30-60)
const player = document.querySelector('lottie-player');
const lottieInstance = player.getLottie();
let isOn = false;
player.addEventListener('click', () => {
if (isOn) {
lottieInstance.playSegments([30, 60], true);
} else {
lottieInstance.playSegments([0, 30], true);
}
isOn = !isOn;
});
תבנית 5: Speed control — שליטה דינמית במהירות
// מהירות האנימציה משתנה לפי מיקום העכבר
const player = document.querySelector('lottie-player');
const lottieInstance = player.getLottie();
document.addEventListener('mousemove', (e) => {
// מהירות 0.5x בצד שמאל, 3x בצד ימין
const speed = 0.5 + (e.clientX / window.innerWidth) * 2.5;
lottieInstance.setSpeed(speed);
});
@lottiefiles/lottie-interactivity — ספריית אינטראקטיביות מוכנה:
אם אתם צריכים אינטראקטיביות בלי לכתוב JavaScript מאפס, LottieFiles מציעים ספרייה ייעודית:
<!-- טעינה -->
<script src="https://unpkg.com/@lottiefiles/lottie-interactivity@latest/dist/lottie-interactivity.min.js"></script>
<!-- שימוש: play on scroll -->
<lottie-player
id="scroll-lottie"
src="/animations/progress.json"
style="width: 300px;"
></lottie-player>
<script>
LottieInteractivity.create({
player: '#scroll-lottie',
mode: 'scroll',
actions: [
{
visibility: [0, 1], // 0% עד 100% visibility
type: 'seek', // התקדמות צמודה לגלילה
frames: [0, 120] // frames להתקדמות
}
]
});
</script>
הספרייה תומכת גם ב-cursor position (אנימציה שעוקבת אחרי העכבר), click toggle, ו-chain (רצף פעולות). זו דרך מצוינת להוסיף אינטראקטיביות בלי לכתוב event handlers בעצמכם.
Lottie הוא "נגן" — הוא מנגן אנימציה מ-A ל-Z, ואתם שולטים ב-play/pause. Rive הוא "מנוע" — הוא מריץ state machine שיודע להחליט לבד מה לנגן, בהתאם לקלט שהוא מקבל.
ההבדל הזה הוא מהותי. עם Lottie, אם אתם רוצים כפתור שמנפיש hover, click, ו-loading — אתם צריכים לנהל 3 segments ב-JavaScript, לעקוב אחרי state, ולטפל ב-edge cases (מה קורה אם לוחצים בזמן hover? מה אם ה-loading מסתיים בזמן mouseleave?). עם Rive, כל הלוגיקה הזו מוגדרת בתוך האנימציה עצמה — ה-state machine יודע לנהל מעברים, priorities, ו-blending.
מה Rive יכול לעשות ש-Lottie לא:
מתי Rive עדיף על Lottie?
איך Rive עובד — ארכיטקטורה:
// הזרימה של Rive
[Rive Editor] → [.riv file] → [Rive Runtime] → [Canvas/WebGL]
// המבנה הפנימי
Artboard (לוח עבודה)
├── Animations (אנימציות בסיסיות)
│ ├── idle — אנימציית idle (רגיעה)
│ ├── hover — אנימציית hover
│ ├── click — אנימציית לחיצה
│ └── success — אנימציית הצלחה
│
└── State Machine (מכונת מצבים)
├── States (מצבים)
│ ├── Idle State → מנגן: idle animation
│ ├── Hover State → מנגן: hover animation
│ ├── Pressed State → מנגן: click animation
│ └── Success State → מנגן: success animation
│
├── Transitions (מעברים)
│ ├── Idle → Hover (כש-isHovered = true)
│ ├── Hover → Pressed (כש-trigger "click" מופעל)
│ └── Pressed → Success (כש-isSuccess = true)
│
└── Inputs (קלטים)
├── isHovered: Boolean
├── click: Trigger
└── isSuccess: Boolean
הנקודה המרכזית: ב-Lottie, אתם (המפתח) מנהלים את כל הלוגיקה ב-JavaScript. ב-Rive, ה-state machine מנהל — ואתם רק שולחים inputs. זה הופך את הקוד ליותר נקי, יותר maintainable, ופחות prone to bugs.
Rive Editor הוא כלי עיצוב שרץ בדפדפן (rive.app). זה לא After Effects — הוא נבנה מאפס לאנימציות אינטראקטיביות ב-web. אתם לא צריכים להתקין שום דבר, וה-free plan נדיב מספיק לרוב הפרויקטים.
המושגים המרכזיים ב-Rive Editor:
1. Artboard — לוח העבודה
ה-artboard הוא ה-canvas שבו מעצבים. כל artboard הוא אנימציה עצמאית עם גודל, רקע, ומבנה משלו. קובץ .riv אחד יכול להכיל כמה artboards — למשל, artboard לכפתור ו-artboard ל-icon.
2. Animations — אנימציות בסיסיות
כל artboard מכיל אנימציות — רצפי keyframes שמנפישים properties. זה דומה ל-timeline של GSAP:
3. State Machine — הלב של Rive
ה-state machine מחבר את האנימציות ללוגיקה. זה הדבר שהופך Rive ל-Rive:
// שלושת סוגי ה-inputs ב-Rive
Boolean — true/false. דוגמה: isHovered, isActive, isDark
Number — ערך מספרי. דוגמה: progress (0-100), mouseX, scrollPercent
Trigger — one-shot event. דוגמה: "click", "submit", "reset"
// ההבדל בין Boolean ל-Trigger:
// Boolean = מצב מתמשך. "העכבר מעל הכפתור" (isHovered = true)
// Trigger = אירוע חד-פעמי. "המשתמש לחץ" (fire trigger "click")
4. Transitions — מעברים בין states
כל transition מוגדר עם:
קריטריון הצלחה: יש לכם קובץ .riv עם state machine שעובד — מעבר חלק בין idle ל-hover ובחזרה.
כמו Lottie, גם ל-Rive יש כמה דרכים לשילוב. ההבדל העיקרי: Rive מרנדר ל-Canvas (לא SVG), ולכן הביצועים בדרך כלל טובים יותר — אבל אין גישה ל-DOM elements של האנימציה.
דרך 1: @rive-app/canvas — Vanilla JavaScript
// התקנה: npm install @rive-app/canvas
import { Rive } from '@rive-app/canvas';
// יצירת instance
const rive = new Rive({
src: '/animations/button.riv', // URL לקובץ .riv
canvas: document.getElementById('rive-canvas'), // canvas element
autoplay: true,
stateMachines: 'ButtonState', // שם ה-state machine
onLoad: () => {
// ה-.riv נטען — עכשיו אפשר לשלוט ב-inputs
console.log('Rive loaded!');
// קבלת ה-inputs
const inputs = rive.stateMachineInputs('ButtonState');
console.log(inputs); // [{name: 'isHovered', type: 56}, ...]
}
});
// HTML:
// <canvas id="rive-canvas" width="300" height="200"></canvas>
דרך 2: Rive Web Component (פשוט יותר)
<!-- טעינת הספרייה -->
<script src="https://unpkg.com/@rive-app/canvas@2"></script>
<!-- שימוש -->
<canvas id="rive-canvas" width="400" height="300"></canvas>
<script>
const rive = new RiveCanvas.Rive({
src: '/animations/hero-character.riv',
canvas: document.getElementById('rive-canvas'),
autoplay: true,
stateMachines: 'MainState',
fit: RiveCanvas.Fit.contain, // contain, cover, fill, fitWidth, fitHeight
alignment: RiveCanvas.Alignment.center
});
</script>
דרך 3: rive-react — React integration
// התקנה: npm install @rive-app/react-canvas
import { useRive, useStateMachineInput } from '@rive-app/react-canvas';
function AnimatedButton() {
// useRive — טוען את הקובץ ומחזיר RiveComponent
const { rive, RiveComponent } = useRive({
src: '/animations/button.riv',
stateMachines: 'ButtonState',
autoplay: true,
});
// useStateMachineInput — גישה ל-input ספציפי
const isHovered = useStateMachineInput(rive, 'ButtonState', 'isHovered');
const clickTrigger = useStateMachineInput(rive, 'ButtonState', 'click');
return (
<div
onMouseEnter={() => isHovered && (isHovered.value = true)}
onMouseLeave={() => isHovered && (isHovered.value = false)}
onClick={() => clickTrigger?.fire()}
style={{ width: 200, height: 60, cursor: 'pointer' }}
>
<RiveComponent />
</div>
);
}
// עם מספר inputs
function ProgressIndicator({ progress }) {
const { rive, RiveComponent } = useRive({
src: '/animations/progress.riv',
stateMachines: 'ProgressMachine',
autoplay: true,
});
const progressInput = useStateMachineInput(
rive, 'ProgressMachine', 'progress'
);
// עדכון ה-input כשה-prop משתנה
useEffect(() => {
if (progressInput) {
progressInput.value = progress; // 0-100
}
}, [progress, progressInput]);
return <RiveComponent style={{ width: 300, height: 300 }} />;
}
Rive מרנדר ל-Canvas — וזה אומר שתוכן האנימציה לא נגיש לקוראי מסך. ב-Lottie (SVG renderer), לפחות יש SVG elements שקוראי מסך יכולים לגשת אליהם. עם Rive, אתם חייבים להוסיף: (1) aria-label על ה-canvas element שמתאר את האנימציה, (2) role="img" על ה-canvas, (3) טקסט חלופי ב-HTML שמוסתר ויזואלית אבל נגיש (sr-only). אם האנימציה מכילה תוכן קריטי — שקלו להשתמש ב-Lottie SVG במקום.
<canvas id="rive" width="400" height="400"></canvas>היופי של Rive הוא שה-state machine עושה את רוב העבודה. אתם רק צריכים "להאכיל" אותו ב-inputs — והוא מחליט לבד מה לנגן. בסעיף הזה נראה דפוסים מתקדמים של חיבור state machine inputs לאינטראקציות משתמש.
דפוס 1: Hover + Click עם Boolean ו-Trigger
const rive = new Rive({
src: '/animations/interactive-icon.riv',
canvas: document.getElementById('rive-canvas'),
stateMachines: 'IconState',
autoplay: true,
onLoad: () => {
const inputs = rive.stateMachineInputs('IconState');
// מציאת inputs לפי שם
const isHovered = inputs.find(i => i.name === 'isHovered');
const clickTrigger = inputs.find(i => i.name === 'click');
const isActive = inputs.find(i => i.name === 'isActive');
const canvas = document.getElementById('rive-canvas');
// Hover
canvas.addEventListener('mouseenter', () => {
if (isHovered) isHovered.value = true;
});
canvas.addEventListener('mouseleave', () => {
if (isHovered) isHovered.value = false;
});
// Click — toggle active + fire trigger
canvas.addEventListener('click', () => {
if (clickTrigger) clickTrigger.fire();
if (isActive) isActive.value = !isActive.value;
});
}
});
דפוס 2: Mouse tracking — העכבר שולט באנימציה
const rive = new Rive({
src: '/animations/character-eyes.riv',
canvas: document.getElementById('rive-canvas'),
stateMachines: 'LookAround',
autoplay: true,
onLoad: () => {
const inputs = rive.stateMachineInputs('LookAround');
const mouseX = inputs.find(i => i.name === 'mouseX');
const mouseY = inputs.find(i => i.name === 'mouseY');
const canvas = document.getElementById('rive-canvas');
document.addEventListener('mousemove', (e) => {
if (!mouseX || !mouseY) return;
// נרמול ל-0-100 ביחס ל-canvas
const rect = canvas.getBoundingClientRect();
const x = ((e.clientX - rect.left) / rect.width) * 100;
const y = ((e.clientY - rect.top) / rect.height) * 100;
mouseX.value = Math.max(0, Math.min(100, x));
mouseY.value = Math.max(0, Math.min(100, y));
});
}
});
דפוס 3: Scroll-driven Rive — התקדמות לפי גלילה
const rive = new Rive({
src: '/animations/story.riv',
canvas: document.getElementById('rive-canvas'),
stateMachines: 'StoryProgress',
autoplay: true,
onLoad: () => {
const inputs = rive.stateMachineInputs('StoryProgress');
const progress = inputs.find(i => i.name === 'scrollProgress');
if (!progress) return;
window.addEventListener('scroll', () => {
const scrollPercent = window.scrollY /
(document.documentElement.scrollHeight - window.innerHeight);
progress.value = scrollPercent * 100; // 0-100
}, { passive: true });
}
});
דפוס 4: Application state → Rive state
// חיבור Rive ל-state של האפליקציה
// למשל: form validation שמשנה את האנימציה
const rive = new Rive({
src: '/animations/form-feedback.riv',
canvas: document.getElementById('form-rive'),
stateMachines: 'FormState',
autoplay: true,
onLoad: () => {
const inputs = rive.stateMachineInputs('FormState');
const isValid = inputs.find(i => i.name === 'isValid');
const isError = inputs.find(i => i.name === 'isError');
const submitTrigger = inputs.find(i => i.name === 'submit');
const successTrigger = inputs.find(i => i.name === 'success');
// כשהטופס valid
document.getElementById('email').addEventListener('input', (e) => {
const valid = e.target.value.includes('@');
if (isValid) isValid.value = valid;
if (isError) isError.value = !valid && e.target.value.length > 0;
});
// כשלוחצים submit
document.getElementById('form').addEventListener('submit', async (e) => {
e.preventDefault();
if (submitTrigger) submitTrigger.fire();
try {
await sendForm();
if (successTrigger) successTrigger.fire();
} catch {
if (isError) isError.value = true;
}
});
}
});
שימו לב לדפוס: הקוד שלכם פשוט — הוא רק שולח inputs. כל הלוגיקה של "איך נראה success", "איך נראה error", "מה המעבר בין hover ל-click" — מוגדרת ב-state machine של Rive. זה הפרדת אחריות מצוינת: המעצב מגדיר את ה-look & feel, המפתח מגדיר את ה-data flow.
קריטריון הצלחה: אנימציית Rive בדף שלכם מגיבה ל-hover ו-click — עם מעברים חלקים שה-state machine מנהל.
אחרי שלמדתם את שני הכלים, השאלה הגדולה: מתי Lottie ומתי Rive? הנה framework ברור עם 8 קריטריונים:
| קריטריון | Lottie | Rive | מנצח |
|---|---|---|---|
| שוק אנימציות מוכנות | 200,000+ ב-LottieFiles. שוק ענק, כל סגנון | אלפים ב-Rive Community. שוק קטן אבל גדל | Lottie |
| אינטראקטיביות | בסיסית — play, pause, segments. צריך JS לכל אינטראקציה | State machines מובנים. Hover, click, inputs — בלי JS | Rive |
| גודל קובץ | JSON: 5-200KB. dotlottie: 1-50KB | .riv: 2-50KB (בינארי, דחוס) | Rive (קטן יותר) |
| גודל Runtime | lottie-web: ~250KB. lottie-light: ~150KB | @rive-app/canvas: ~150KB | שווה |
| Renderer | SVG (ברירת מחדל), Canvas, HTML | Canvas בלבד (WebGL אופציונלי) | Lottie (SVG = DOM access) |
| Learning curve | נמוכה — script tag + web component | בינונית — צריך להבין state machines | Lottie |
| כלי יצירה | After Effects + Bodymovin (מקצועי, יקר) | Rive Editor (חינם, בדפדפן) | Rive (נגישות) |
| React integration | @lottiefiles/react-lottie-player — עובד | @rive-app/react-canvas + useStateMachineInput — מצוין | Rive |
| המצב שלכם | בחרו | למה |
|---|---|---|
| צריכים loading/success/error animation מהר | Lottie | שוק ענק, מוצאים ב-30 שניות, שורת קוד אחת |
| צריכים אייקון/איור אנימטיבי ללא אינטראקציה | Lottie | Play and forget — פשוט ויעיל |
| צריכים כפתור/toggle עם hover+click states | Rive | State machine מנהל מעברים — קוד נקי |
| צריכים דמות/avatar שמגיבה למשתמש | Rive | Mouse tracking, bones, blend states |
| צריכים אנימציה שמגיבה ל-app state | Rive | Number/Boolean inputs מחוברים ל-state machine |
| צריכים SVG animation שקוראי מסך יכולים לגשת אליה | Lottie | SVG renderer = DOM elements נגישים |
| צריכים ביצועים מקסימליים עם הרבה אנימציות | Rive | Canvas renderer + קבצים קטנים יותר |
| לא יודעים — ורוצים להתחיל מהר | Lottie | Learning curve נמוכה, שוק ענק, documentation מצוין |
אנימציות מוכנות חינמיות מבחינת זמן פיתוח — אבל לא חינמיות מבחינת ביצועים. כל אנימציה זה קובץ שנטען + ספרייה שמרנדרת. בסעיף הזה נלמד איך לשמור על ביצועים מעולים.
מפת גדלים — מה שוקל כמה:
// גודל Runtime (חד-פעמי — נטען פעם אחת)
lottie-web (full): ~250KB (gzipped: ~75KB)
lottie-web (light): ~150KB (gzipped: ~45KB)
@rive-app/canvas: ~150KB (gzipped: ~50KB)
@dotlottie/player: ~100KB (gzipped: ~35KB)
// גודל קבצים (לכל אנימציה)
Lottie JSON (פשוט): 5-30KB → gzipped: 2-10KB
Lottie JSON (מורכב): 50-200KB → gzipped: 15-60KB
dotlottie (.lottie): 1-50KB (כבר דחוס)
Rive (.riv): 2-50KB (בינארי, כבר דחוס)
GIF (אותה אנימציה): 500KB-5MB (!!!)
MP4 (אותה אנימציה): 200KB-2MB
// לשם השוואה:
תמונת JPEG ממוצעת: 50-200KB
פונט web (woff2): 20-50KB
Lazy loading עם Intersection Observer — הדפוס הזהב:
אם יש אנימציות Lottie או Rive שלא נראות ב-viewport הראשוני — אל תטענו אותן מראש. Intersection Observer מאפשר לטעון את הספרייה + הקובץ רק כשהמשתמש גולל אליהם:
// Lazy loading של Lottie — טעינה רק כשנראה
function lazyLoadLottie(selector) {
const elements = document.querySelectorAll(selector);
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const el = entry.target;
const src = el.dataset.src; // data-src במקום src
// טעינת lottie-player dynamically (אם לא נטען כבר)
if (!customElements.get('lottie-player')) {
const script = document.createElement('script');
script.src = 'https://unpkg.com/@lottiefiles/lottie-player@2/dist/lottie-player.js';
document.head.appendChild(script);
script.onload = () => el.setAttribute('src', src);
} else {
el.setAttribute('src', src);
}
observer.unobserve(el);
}
});
}, {
rootMargin: '200px' // טוען 200px לפני שנכנס ל-viewport
});
elements.forEach(el => observer.observe(el));
}
// HTML:
// <lottie-player data-src="/animations/feature.json"
// style="width:300px; height:300px;"
// loop autoplay>
// </lottie-player>
// JavaScript:
lazyLoadLottie('lottie-player[data-src]');
// Lazy loading של Rive
function lazyLoadRive(canvasId, rivSrc, stateMachine) {
const canvas = document.getElementById(canvasId);
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// טעינה דינמית של Rive runtime
import('@rive-app/canvas').then(({ Rive }) => {
new Rive({
src: rivSrc,
canvas: canvas,
autoplay: true,
stateMachines: stateMachine,
});
});
observer.unobserve(canvas);
}
});
}, { rootMargin: '100px' });
observer.observe(canvas);
}
Best practices לביצועים:
<link rel="preload"> על ה-JSON// עצירת אנימציות שלא נראות — חיסכון CPU
const players = document.querySelectorAll('lottie-player');
const visibilityObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
const player = entry.target;
if (entry.isIntersecting) {
player.play();
} else {
player.pause(); // עוצר כשלא נראה — חוסך CPU
}
});
}, { threshold: 0 });
players.forEach(p => visibilityObserver.observe(p));
מכשירי mobile עם מעבדים חלשים יותר מושפעים במיוחד מאנימציות Lottie/Rive. שלושה כללים: (1) מקסימום 2 אנימציות בו-זמנית ב-mobile. (2) השתמשו ב-lottie-light במקום lottie-web — חוסך 100KB. (3) בדקו ב-Chrome DevTools > Performance > CPU throttling 4x — אם האנימציה לא חלקה ב-4x throttling, היא לא תהיה חלקה במכשירים ישנים.
כלי AI כמו Bolt, Lovable, Cursor ו-Claude מכירים גם Lottie וגם Rive — אבל כמו תמיד, איכות הפרומפט קובעת. הנה 5 פרומפטים שעובדים:
פרומפט 1: Lottie integration בסיסי
"Add a Lottie animation to the hero section.
Use the lottie-player web component from @lottiefiles/lottie-player.
Animation source: [URL from LottieFiles].
Requirements:
- Size: 400x400px, centered
- Background: transparent
- Autoplay with loop
- Speed: 0.8 (slightly slower than default)
- Lazy load: only load when visible (Intersection Observer)
- Add aria-label describing the animation for accessibility"
פרומפט 2: Lottie scroll-driven
"Create a scroll-driven Lottie animation for the features section.
Use lottie-web directly (not web component) for frame-level control.
Animation source: [URL].
Requirements:
- The animation progress should be tied to scroll position
- When the section enters viewport (top 80%), animation starts at frame 0
- When the section leaves viewport (top 20%), animation is at the last frame
- Use requestAnimationFrame for smooth performance
- Use passive scroll listener
- On mobile: fall back to simple autoplay (no scroll-driven)"
פרומפט 3: Lottie hover segments
"Create a set of 4 feature cards, each with a Lottie icon animation.
Each card has:
- A Lottie animation (different for each card)
- On hover: play frames 0-30 (entrance animation)
- On mouse leave: play frames 30-60 (exit animation)
- Use lottie-web with playSegments for frame control
- Cards layout: CSS Grid, 2x2 on desktop, 1 column on mobile
- Ensure animations don't interfere with each other
- Pause animations that are not visible (Intersection Observer)"
פרומפט 4: Rive interactive button
"Create an interactive submit button using Rive.
Rive file: [URL to .riv file].
State machine name: 'ButtonState'.
Inputs: isHovered (Boolean), click (Trigger), isLoading (Boolean), isSuccess (Boolean).
Requirements:
- Hover: set isHovered to true on mouseenter, false on mouseleave
- Click: fire 'click' trigger, then set isLoading to true
- After 2 seconds: set isLoading to false, isSuccess to true
- Use @rive-app/canvas for vanilla JS (or @rive-app/react-canvas for React)
- Canvas size: 200x60px
- Add aria-label='Submit button' and role='img' for accessibility
- Cursor: pointer on hover"
פרומפט 5: Lottie + Rive combined
"Build a landing page section with both Lottie and Rive animations.
Layout: two columns — left side content, right side animations.
Left column:
- Heading with a small Lottie icon (32x32px) next to it — animated checkmark, autoplay loop
- 3 feature bullets, each with a different Lottie icon that plays on scroll (Intersection Observer)
Right column:
- Large Rive animation (400x400px) of an interactive character
- State machine: 'CharacterState'
- The character follows the mouse (Number inputs: mouseX, mouseY)
- Click triggers a wave animation (Trigger input: 'wave')
Performance:
- Lazy load Rive (it's below the fold on mobile)
- Use lottie-light for the small icons
- Pause all animations when tab is not visible (document.visibilitychange)
- Test with Chrome DevTools Performance panel — target 60fps"
אנימציות Lottie ו-Rive לא צריכות להיות "decoration" — הן יכולות לפתור בעיות UX אמיתיות. בסעיף הזה נראה 4 תבניות מקצועיות שכל אפליקציה מודרנית צריכה, עם קוד מוכן.
תבנית 1: Onboarding animation — מסע קבלת פנים
Onboarding טוב מסביר את המוצר בלי טקסט ארוך. אנימציות Lottie מצוינות לזה — כל שלב ב-onboarding מלווה באנימציה שמסבירה את הפיצ'ר:
<!-- Onboarding: 3 שלבים עם Lottie -->
<div class="onboarding">
<div class="step active" data-step="1">
<lottie-player
src="/animations/onboarding-step1.json"
style="width: 300px; height: 300px;"
loop autoplay
></lottie-player>
<h3>ברוכים הבאים!</h3>
<p>הנה מה שתוכלו לעשות...</p>
</div>
<div class="step" data-step="2">
<lottie-player
data-src="/animations/onboarding-step2.json"
style="width: 300px; height: 300px;"
loop
></lottie-player>
<h3>התאימו אישית</h3>
<p>בחרו את ההגדרות שמתאימות לכם...</p>
</div>
<div class="step" data-step="3">
<lottie-player
data-src="/animations/onboarding-step3.json"
style="width: 300px; height: 300px;"
></lottie-player>
<h3>מוכנים!</h3>
<p>הכל מוכן — בואו נתחיל</p>
</div>
<div class="onboarding-nav">
<button class="prev" disabled>הקודם</button>
<div class="dots">
<span class="dot active"></span>
<span class="dot"></span>
<span class="dot"></span>
</div>
<button class="next">הבא</button>
</div>
</div>
<script>
// ניווט בין שלבים — עם lazy loading של אנימציות
let currentStep = 1;
const steps = document.querySelectorAll('.step');
function showStep(n) {
steps.forEach(s => s.classList.remove('active'));
const step = document.querySelector(`[data-step="${n}"]`);
step.classList.add('active');
// Lazy load: טען אנימציה רק כשנכנסים לשלב
const player = step.querySelector('lottie-player');
if (player.dataset.src && !player.getAttribute('src')) {
player.setAttribute('src', player.dataset.src);
player.setAttribute('autoplay', '');
}
// עצור אנימציות בשלבים אחרים
steps.forEach(s => {
if (s !== step) {
const p = s.querySelector('lottie-player');
if (p) p.pause();
}
});
}
document.querySelector('.next').addEventListener('click', () => {
if (currentStep < 3) showStep(++currentStep);
});
document.querySelector('.prev').addEventListener('click', () => {
if (currentStep > 1) showStep(--currentStep);
});
</script>
תבנית 2: Empty state — כשאין תוכן להציג
Empty state הוא מה שהמשתמש רואה כשאין תוכן — רשימה ריקה, חיפוש ללא תוצאות, inbox ריק. אנימציית Lottie הופכת רגע מתסכל לרגע נעים:
<!-- Empty state עם Lottie -->
<div class="empty-state">
<lottie-player
src="/animations/empty-search.json"
style="width: 250px; height: 250px; margin: 0 auto;"
loop
autoplay
speed="0.7"
></lottie-player>
<h3>לא מצאנו תוצאות</h3>
<p>נסו לחפש עם מילים אחרות, או בדקו את האיות</p>
<button class="btn-secondary">נקו את החיפוש</button>
</div>
<style>
.empty-state {
text-align: center;
padding: 3rem 1rem;
max-width: 400px;
margin: 0 auto;
}
.empty-state h3 {
margin-top: 1rem;
font-size: 1.25rem;
color: #333;
}
.empty-state p {
color: #666;
margin: 0.5rem 0 1.5rem;
}
</style>
תבנית 3: Success / Error feedback — משוב מיידי
<!-- Success/Error feedback עם Lottie -->
<script>
// פונקציה כללית להצגת feedback
function showFeedback(type) {
const overlay = document.createElement('div');
overlay.className = 'feedback-overlay';
overlay.innerHTML = `
<lottie-player
src="/animations/${type === 'success' ? 'success-check' : 'error-x'}.json"
style="width: 150px; height: 150px;"
autoplay
></lottie-player>
<p>${type === 'success' ? 'הפעולה הצליחה!' : 'משהו השתבש. נסו שוב.'}</p>
`;
document.body.appendChild(overlay);
// האנימציה רצה פעם אחת (בלי loop) ואז נעלם
const player = overlay.querySelector('lottie-player');
player.addEventListener('complete', () => {
setTimeout(() => {
overlay.classList.add('fade-out');
overlay.addEventListener('animationend', () => overlay.remove());
}, 800);
});
}
// שימוש:
// showFeedback('success');
// showFeedback('error');
</script>
<style>
.feedback-overlay {
position: fixed;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: rgba(255,255,255,0.95);
z-index: 1000;
animation: fadeIn 0.3s ease;
}
.feedback-overlay p {
font-size: 1.2rem;
margin-top: 1rem;
font-weight: 600;
}
.feedback-overlay.fade-out {
animation: fadeOut 0.3s ease forwards;
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } }
</style>
תבנית 4: Loading indicator — טעינה חכמה עם Rive
<!-- Loading indicator אינטראקטיבי עם Rive -->
<!-- ה-state machine מגיב ל-progress input -->
<canvas id="loading-canvas" width="200" height="200"
aria-label="מחוון טעינה" role="img"></canvas>
<script>
let loadingRive;
async function initLoadingIndicator() {
const { Rive } = await import('@rive-app/canvas');
loadingRive = new Rive({
src: '/animations/loading-indicator.riv',
canvas: document.getElementById('loading-canvas'),
stateMachines: 'LoadingState',
autoplay: true,
onLoad: () => {
console.log('Loading indicator ready');
}
});
}
// עדכון progress (0-100)
function updateLoadingProgress(percent) {
if (!loadingRive) return;
const inputs = loadingRive.stateMachineInputs('LoadingState');
const progress = inputs.find(i => i.name === 'progress');
if (progress) progress.value = percent;
}
// הצגת הצלחה
function showLoadingSuccess() {
if (!loadingRive) return;
const inputs = loadingRive.stateMachineInputs('LoadingState');
const success = inputs.find(i => i.name === 'success');
if (success) success.fire();
}
// שימוש בתהליך טעינה אמיתי:
async function fetchData() {
initLoadingIndicator();
const response = await fetch('/api/data');
const reader = response.body.getReader();
const total = parseInt(response.headers.get('content-length'));
let loaded = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
loaded += value.length;
updateLoadingProgress((loaded / total) * 100);
}
showLoadingSuccess();
}
</script>
קריטריון הצלחה: שני מצבים עובדים — empty state עם אנימציה בלופ, ו-success animation שרצה פעם אחת ונעלמת.
עוד תבניות מקצועיות שכדאי להכיר:
המפתח: אנימציה מוכנה צריכה לפתור בעיה, לא "לקשט". Empty state בלי אנימציה = המשתמש חושב שמשהו שבור. Success animation בלי feedback = המשתמש לא בטוח שהפעולה הצליחה. Loading animation = המשתמש יודע שמשהו קורה ולא עוזב. כל אנימציה שאתם מוסיפים צריכה לענות על "למה זה פה?" — אם אין תשובה טובה, אל תוסיפו.
| שלב | פעולה | זמן |
|---|---|---|
| 1. זיהוי | זהו 3-5 מקומות בפרויקט שצריכים אנימציה (loading, empty, success, onboarding, interaction). לכל מקום: Lottie או Rive? | 10 דקות |
| 2. חיפוש | חפשו ב-LottieFiles / Rive Community. בחרו 2-3 אופציות לכל מקום. בדקו רישיון, גודל קובץ, וסגנון | 15 דקות |
| 3. התאמה | התאימו צבעים ומהירות ב-LottieFiles Editor. ב-Rive — בדקו שה-state machine מכסה את כל ה-states שצריך | 10 דקות |
| 4. שילוב | שלבו בקוד — lottie-player לפשוט, lottie-web לשליטה, @rive-app/canvas ל-Rive. חברו inputs | 20 דקות |
| 5. Performance | הוסיפו lazy loading, pause on invisible, preload לקריטיים. בדקו גודלי קבצים | 10 דקות |
| 6. A11y | aria-labels, role="img", prefers-reduced-motion. בדקו עם קורא מסך | 10 דקות |
| 7. Test | בדקו ב-mobile (CPU throttling), בדקו responsive, בדקו edge cases (empty, error, slow network) | 15 דקות |
בפרק הזה למדתם Lottie ו-Rive — אנימציות מוכנות שמעלות את הרמה בזמן מינימלי. אבל יש סוגי אנימציות שגם Lottie, גם Rive, וגם SVG לא יכולים לעשות: particles, generative art, data visualization מורכב, ואפקטים פיקסליים. בפרק 10 תלמדו Canvas API — ציור פיקסלי בדפדפן. תלמדו את ה-API הבסיסי (shapes, paths, colors), אנימציה עם requestAnimationFrame, particles systems, ואיך לשלב Canvas עם GSAP. Canvas הוא הכלי האחרון בארגז — ואיתו תוכלו לבנות כל דבר.