Svelte और SvelteKit में Rive (Svelte 5 गाइड)
Charmotion टीम द्वारा · अपडेट:

Svelte के लिए कोई official Rive runtime नहीं है, इसलिए आप web runtime @rive-app/canvas सीधे इस्तेमाल करते हैं। Instance को onMount के अंदर autoBind: true के साथ बनाएँ, क्योंकि यह server rendering के दौरान कभी नहीं चलता। mood view model number को $effect से अपडेट करें, event handlers से ट्रिगर फ़ायर करें, और एक synchronous cleanup return करें जो r.cleanup() कॉल करे।
मुख्य बातें
- Rive की सूची में कोई Svelte runtime नहीं है;
@rive-app/canvasकिसी भी Svelte 5 component में काम करता है। onMountserver पर नहीं चलता, इसलिए SvelteKit SSR चालू रह सकता है।onMountcallback को synchronous रखें ताकि उसका return किया गया cleanup function चले।- Instance को
$state.rawvariable में रखें ताकि उसके मौजूद होते ही$effectफिर से चले। - .riv फ़ाइलें
static/में रखें और उन्हें root path से लोड करें।
क्या Rive का कोई Svelte पैकेज है?
कोई official पैकेज नहीं है। Rive का documentation web, React, Apple, Android, Flutter, React Native और game engines के official runtimes को कवर करता है, और चार community runtimes की सूची देता है: Angular, C#, Qt और RiveCMP। इसमें Svelte या SvelteKit की कोई entry नहीं है। npm पर कुछ community wrappers मौजूद हैं, लेकिन ये छोटे projects हैं जो runtime से पीछे रह सकते हैं।
भरोसेमंद रास्ता Rive का अपना web runtime है, जो framework-agnostic है। Svelte component पहले से ही वह सब देता है जिसकी इसे ज़रूरत है: bind:this के ज़रिए एक canvas element, एक mount hook और एक teardown hook।
| ज़रूरत | पैकेज |
|---|---|
| स्टेट वाला इंटरैक्टिव कैरेक्टर | @rive-app/canvas (या @rive-app/webgl2) |
| लीनियर Lottie क्लिप | @lottiefiles/dotlottie-svelte |
npm install @rive-app/canvas से install करें। जब किसी पेज पर एक साथ कई एनिमेशन दिखते हों, तो Rive canvas पैकेज की सलाह देता है, क्योंकि इस पर ब्राउज़र की WebGL context limit लागू नहीं होती। अगर आपको Rive Renderer चाहिए, तो WebGL2 पैकेज का API भी यही है।
SSR चालू रहते हुए onMount में Rive को mount कैसे करें?
Svelte के docs के अनुसार onMount server पर render होने वाले component में नहीं चलता, इसलिए वहाँ Rive instance बनाना SSR बंद किए बिना SSR-safe है। यह रहा एक पूरा Svelte 5 component:
<script>
import { onMount } from "svelte";
import { Rive } from "@rive-app/canvas";
let { mood = 0 } = $props();
let canvas;
let r = $state.raw(null);
onMount(() => {
const instance = new Rive({
src: "/character.riv",
canvas,
stateMachine: "CharacterViewModelMachine",
autoplay: true,
autoBind: true,
onLoad: () => {
instance.resizeDrawingSurfaceToCanvas();
r = instance; // ready: the $effect below runs now
},
});
return () => instance.cleanup(); // sync callback, so this runs
});
$effect(() => {
const prop = r?.viewModelInstance?.number("mood");
if (prop) prop.value = mood;
});
export function fire(name) {
r?.viewModelInstance?.trigger(name)?.trigger();
}
</script>
<canvas bind:this={canvas} width="320" height="320"
role="img" aria-label="Animated mascot"></canvas>
SvelteKit में static import ठीक है, क्योंकि onMount तक कुछ भी नहीं चलता। अगर server rendering के दौरान कोई bundler या पैकेज फिर भी शिकायत करे, तो उसे hook के अंदर dynamically import करें, या components के बाहर के कोड को $app/environment से browser के ज़रिए guard करें।
$effect से mood prop को व्यू मॉडल से कैसे bind करें?
$effect तब फिर से चलता है जब उसके द्वारा पढ़ी गई कोई reactive value बदलती है। ऊपर के component में यह दो values पढ़ता है: mood prop और r। इसीलिए r को $state.raw से declare किया गया है और onLoad में assign किया गया है: effect पहली बार तब चलता है जब r अभी null है, कुछ नहीं करता, और फ़ाइल तैयार होते ही फिर से चलकर शुरुआती मूड लागू करता है। इसके बाद हर prop बदलाव सीधे व्यू मॉडल में लिखा जाता है।
$state की जगह $state.raw इस्तेमाल करना ज़रूरी है। सामान्य $state proxies के ज़रिए objects को deeply reactive बना देता है, जो आप किसी WASM-backed runtime object के आसपास नहीं चाहते। Raw variant सिर्फ़ reassignment को track करता है।
फिर parent सामान्य props और एक component reference से मैस्कॉट को चलाता है:
<script>
import Mascot from "$lib/Mascot.svelte";
let mascot;
let saving = $state(false);
async function save() {
saving = true; // mood 5: loading
try { await api.save(); mascot.fire("success"); }
catch { mascot.fire("error"); }
finally { saving = false; } // mood 0: idle
}
</script>
<Mascot bind:this={mascot} mood={saving ? 5 : 0} />
<button onclick={save}>Save</button>

मूड स्टेट हैं, इसलिए वे props में रहते हैं। ट्रिगर एक बार के events हैं, इसलिए वे एक्सपोर्ट किए गए fire() function से जाते हैं।
SvelteKit में .riv फ़ाइलें कहाँ रखें?
इन्हें static/ में रखें। SvelteKit इस folder को site root से serve करता है, इसलिए static/character.riv ठीक ऊपर के component की तरह /character.riv के रूप में लोड होती है। यहाँ की फ़ाइलें बिना hashing के जैसी की तैसी copy होती हैं, इसलिए बदली गई फ़ाइल को नया नाम दें (जैसे character-v2.riv) या अगर आप उसे अक्सर बदलते हैं तो छोटे cache headers सेट करें।
.riv फ़ाइल आमतौर पर छोटी होती है। बड़ा download runtime की rive.wasm है, जिसे web runtime default रूप से unpkg से fetch करता है। इसे खुद serve करने के लिए, पहला instance बनने से पहले runtime को बताएँ कि यह कहाँ है:
import { RuntimeLoader } from "@rive-app/canvas";
import riveWasmUrl from "@rive-app/canvas/rive.wasm?url";
// Run once, before the first new Rive(...)
RuntimeLoader.setWasmUrl(riveWasmUrl);
Vite का ?url import wasm को आपके build में copy करता है और उसका URL return करता है। Rive के docs के अनुसार wasm version installed @rive-app पैकेज से मेल खाना चाहिए, और इसे पैकेज से import करने पर यह पक्का हो जाता है। Offline चलने वाले ऐप, सख्त content security policies और मैस्कॉट को preload करने वाले पेजों के लिए self-hosting करना फ़ायदेमंद है।
Destroy पर cleanup कैसे करें?
onMount से एक function return करें जो instance पर cleanup() कॉल करे, जैसा ऊपर दिखाया गया है। Rive के docs बताते हैं कि cleanup() instance के lifetime में बने low-level C++ objects को हटाता है; इसे छोड़ने पर component को remount करने वाले हर navigation पर memory leak होती है।
यहाँ एक जाल है। Svelte returned function का इस्तेमाल सिर्फ़ तब करता है जब onMount को दिया गया callback synchronous हो। async callback एक promise return करता है, इसलिए आपका cleanup चुपचाप ignore हो जाता है। अगर आपको dynamic import को await करना है, तो cleanup के लिए onDestroy इस्तेमाल करें या बाहरी callback को synchronous रखें:
onMount(() => {
let instance;
import("@rive-app/canvas").then(({ Rive }) => {
instance = new Rive({ /* same options as above */ });
});
return () => instance?.cleanup();
});
Rive के बाहर शुरू किया गया काम भी रोकें: event listeners हटाएँ और एनिमेशन को lazy-start करने के लिए इस्तेमाल किया गया कोई भी IntersectionObserver disconnect करें।
prefers-reduced-motion का ध्यान कैसे रखें?
Play करने से पहले media query जाँचें और अगर यह सेट है तो कैरेक्टर को स्थिर रखें। prefers-reduced-motion विज़िटर के operating system की setting बताता है और इसकी दो values हैं, no-preference और reduce।
const reduce = matchMedia("(prefers-reduced-motion: reduce)").matches;
const instance = new Rive({
// ...same options as above
autoplay: !reduce,
});
autoplay: false के साथ भी runtime state machine का पहला फ़्रेम draw करता है, इसलिए मैस्कॉट एक स्थिर pose में दिखता है। आप अब भी मूड सेट कर सकते हैं ताकि pose स्थिति से मेल खाए। इसे onMount के अंदर कॉल करें, क्योंकि server पर matchMedia मौजूद नहीं होता।
तैयार फ़ाइल के लिए, Charmotion एक कैरेक्टर या लोगो इमेज को कुछ ही मिनटों में 17 एनिमेशन में बदलता है, जो एक Character व्यू मॉडल वाली एक .riv के रूप में मिलती हैं: एक mood नंबर (0 idle, 1 happy, 2 wave, 3 thinking, 4 sad, 5 loading, 6 listening, 7 talking, 8 sleeping, 9 attention) और success, error, yes, no, enter और exit ट्रिगर, साथ में ज़रूरत पर MP4, GIF और ट्रांसपेरेंट WebM और MOV एक्सपोर्ट।
Svelte में Rive vs dotLottie: कौन सा इस्तेमाल करें?
हर बार एक ही तरह चलने वाली क्लिप के लिए dotLottie इस्तेमाल करें, और आपके ऐप पर रिएक्ट करने वाले कैरेक्टर के लिए Rive।
- dotLottie:
npm install @lottiefiles/dotlottie-svelteचलाएँ, फिर .lottie या .json source के साथDotLottieSveltecomponent render करें। यह success checkmark, ऑनबोर्डिंग इलस्ट्रेशन और loaders के लिए अच्छा है। - Rive: एक .riv में idle, loading, success और बाकी सभी स्टेट होते हैं, और transitions स्टेट मशीन संभालती है। आपका Svelte कोड सिर्फ़ एक number लिखता है या ट्रिगर फ़ायर करता है।
फ़ैसला इस सवाल से होता है कि क्या आपके code को बताना है कि आगे क्या होगा। अगर जवाब है "request पूरी होने तक लूप करते रहो, फिर जश्न मनाओ", तो स्टेट मशीन आपको कई फ़ाइलें संभालने और उनके बीच के बदलाव की टाइमिंग खुद तय करने से बचाती है। पूरी तुलना के लिए Rive vs Lottie देखें।
SvelteKit ऐप में Rive कैरेक्टर कैसे जोड़ें
- रनटाइम इंस्टॉल करें.
npm install @rive-app/canvasचलाएँ और .riv फ़ाइल कोstatic/में कॉपी करें। - component बनाएँ.
bind:thisसे एक canvas bind करें और एक synchronousonMountमेंautoBind: trueके साथ Rive instance बनाएँ। - तैयार होने पर नज़र रखें.
onLoadमें instance को एक$state.rawvariable में असाइन करें। - मूड bind करें.
$effectमें prop सेr.viewModelInstance.number("mood").valueसेट करें। - ट्रिगर फ़ायर करें. एक function export करें जो व्यू मॉडल पर
trigger(name).trigger()कॉल करे। - Cleanup करें.
onMountसे() => instance.cleanup()return करें।
अक्सर पूछे जाने वाले सवाल
क्या SvelteKit में Rive इस्तेमाल करने के लिए SSR बंद करना ज़रूरी है?
नहीं। Svelte के docs बताते हैं कि onMount server rendering के दौरान नहीं चलता, इसलिए Rive instance वहाँ बनाने से पेज server-rendered ही रहता है। server से सिर्फ़ canvas markup भेजा जाता है, और component के browser में mount होते ही एनिमेशन शुरू हो जाता है। route के लिए ssr = false सेट करना ज़रूरी नहीं है।
मेरा onMount cleanup क्यों नहीं चलता?
शायद आपका onMount callback async है। Svelte लौटाए गए cleanup function का इस्तेमाल तभी करता है जब callback synchronous हो, क्योंकि async function इसकी जगह एक promise लौटाता है। callback को synchronous रखें और dynamic import को .then() से संभालें, या cleanup को onDestroy में ले जाएँ।
क्या यह Svelte 4 में काम करता है?
रनटाइम calls वही रहती हैं। $props() की जगह export let mood = 0 लिखें, $effect की जगह $: if (r) setMood(mood) जैसा reactive statement इस्तेमाल करें, और r को सामान्य let बनाएँ। onMount, bind:this और cleanup function बिल्कुल वैसे ही काम करते हैं।
इस गाइड से झटपट जवाब
स्रोत
- Web (JS) runtime, Rive
- Web runtime: Data binding, Rive
- Preloading WASM, Rive
- Lifecycle hooks, Svelte
- $effect, Svelte
- $app/environment, SvelteKit
- dotlottie-web: players for web, React, Vue, Svelte and web components, LottieFiles on GitHub
- prefers-reduced-motion, MDN Web Docs