कंटेंट पर जाएँ
charmotion

React और Next.js में Rive का इस्तेमाल कैसे करें

Charmotion टीम द्वारा · अपडेट:

गाइड का कवर इलस्ट्रेशन: React और Next.js में Rive कैसे इस्तेमाल करें, Charmotion डेमो कैरेक्टर के साथ

React में Rive इस्तेमाल करने के लिए @rive-app/react-webgl2 install करें, useRive({ src, stateMachine, autoplay: true }) कॉल करें, और लौटाया गया RiveComponent render करें। इनपुट वाली फ़ाइलों के लिए useStateMachineInput से, और data-bound files के लिए view model hooks से स्टेट बदलें। Next.js में इसे client component में render करें।

मुख्य बातें

  • Rive ज़्यादातर प्रोजेक्ट के लिए @rive-app/react-webgl2 की सलाह देता है; react-canvas अभी भी काम करता है।
  • useRive रेंडर करने के लिए rive instance और एक RiveComponent लौटाता है।
  • useStateMachineInput legacy इनपुट कंट्रोल करता है; view model hooks data-bound files कंट्रोल करते हैं।
  • Next.js में Rive को "use client" component में रखें या ssr: false के साथ लोड करें।

कौन-सा Rive React package install करें?

Rive rive-react repository से तीन React packages publish करता है। इनका API एक जैसा है, फ़र्क सिर्फ़ draw करने के तरीके में है:

पैकेजRendererकब इस्तेमाल करें
@rive-app/react-webgl2WebGL2 पर Rive RendererDefault विकल्प; vector feathering समेत सभी features सपोर्ट करता है
@rive-app/react-canvasBrowser Canvas2Dएक पेज पर कई instances, या जहाँ WebGL उपलब्ध न हो
@rive-app/react-canvas-liteCanvas2D, सीमित featuresसबसे छोटा डाउनलोड, जब फ़ाइल को छूटे हुए features की ज़रूरत न हो
npm install @rive-app/react-webgl2

Rive के web docs अब ज़्यादातर मामलों में WebGL2 इस्तेमाल करने की सलाह देते हैं। एक सावधानी: ब्राउज़र हर पेज पर WebGL contexts की संख्या सीमित रखते हैं। अगर किसी पेज पर एक साथ कई Rive एनिमेशन दिखते हैं, तो या तो canvas पैकेज इस्तेमाल करें या useOffscreenRenderer: true पास करें, ताकि सभी instances एक ही offscreen context शेयर करें।

रनटाइम एक WASM module है, इसलिए डाउनलोड साइज़ का सबसे बड़ा हिस्सा यही है। Rive के अनुसार brotli compression के बाद canvas WASM का साइज़ 567 KB और WebGL2 build का 648 KB है (जनवरी 2026)। इसे सिर्फ़ उन्हीं routes पर लोड करें जहाँ इसकी ज़रूरत हो।

useRive से .riv फ़ाइल कैसे रेंडर करें?

.riv फ़ाइल को अपने static folder में रखें (उदाहरण के लिए public/character.riv) और useRive कॉल करें। यह hook rive instance लौटाता है, जो फ़ाइल लोड होने तक null रहता है, और साथ में एक RiveComponent भी, जो canvas रेंडर करता है।

import { useRive } from "@rive-app/react-webgl2";

export function Character() {
  const { rive, RiveComponent } = useRive({
    src: "/character.riv",
    stateMachine: "CharacterStateMachine",
    autoplay: true,
  });

  return (
    <div style={{ width: 240, height: 240 }}>
      <RiveComponent aria-label="Animated character" />
    </div>
  );
}

RiveComponent अपने parent को पूरा भर देता है, इसलिए साइज़ wrapper का तय करें, canvas का नहीं। अगर एनिमेशन कोई अर्थ बताता है तो उसे accessible label दें, और अगर वह सिर्फ़ सजावट के लिए है तो उसे assistive technology से छिपा दें।

एकवचन stateMachine option इस्तेमाल करें। Rive के web रनटाइम ने v2.41.0 में बहुवचन stateMachines parameter की जगह इसे लागू किया, पर पुराने tutorials अब भी बहुवचन रूप दिखाते हैं। अगर आप स्टेट मशीन नहीं देते, तो फ़ाइल अपना default एनिमेशन चलाती है और आपके इनपुट कोई जवाब नहीं देंगे।

React से स्टेट कैसे बदलें?

फ़ाइल को कैसे कंट्रोल करें, यह इस पर निर्भर है कि फ़ाइल क्या expose करती है।

स्टेट मशीन इनपुट वाली फ़ाइलें (legacy)

useStateMachineInput(rive, stateMachineName, inputName) फ़ाइल लोड होने के बाद इनपुट लौटाता है। numbers और booleans पर .value सेट करें; ट्रिगर पर .fire() कॉल करें।

import { useEffect } from "react";
import { useRive, useStateMachineInput } from "@rive-app/react-webgl2";

const SM = "CharacterStateMachine";

export function Character({ mood, successCount }: { mood: number; successCount: number }) {
  const { rive, RiveComponent } = useRive({ src: "/character.riv", stateMachine: SM, autoplay: true });
  const moodInput = useStateMachineInput(rive, SM, "mood");
  const success = useStateMachineInput(rive, SM, "success");

  useEffect(() => {
    if (moodInput) moodInput.value = mood;
  }, [moodInput, mood]);

  // Fire the one-shot whenever the parent bumps successCount.
  useEffect(() => {
    if (successCount > 0) success?.fire();
  }, [success, successCount]);

  return (
    <div style={{ width: 240, height: 240 }}>
      <RiveComponent />
    </div>
  );
}

view model वाली फ़ाइलें (data binding)

autoBind: true पास करें, फिर rive?.viewModelInstance के साथ view model hooks इस्तेमाल करें:

const { rive, RiveComponent } = useRive({ src: "/character.riv", stateMachine: SM, autoplay: true, autoBind: true });
const vmi = rive?.viewModelInstance;
const { value: mood, setValue: setMood } = useViewModelInstanceNumber("mood", vmi);
const { trigger: celebrate } = useViewModelInstanceTrigger("success", vmi);
success: एक ट्रिगर जो एक बार चलता है, फिर मौजूदा मूड पर लौट आता है।

आप किसी event handler से भी सीधे ट्रिगर फ़ायर कर सकते हैं, जैसे किसी button के click handler से, success?.fire() के ज़रिए।

Rive नए काम के लिए data binding की सलाह देता है, लेकिन इनपुट-आधारित फ़ाइलें React में काम करती रहती हैं। वही API इस्तेमाल करें जो फ़ाइल से मेल खाता हो।

दोनों तरह के hooks फ़ाइल लोड होने तक कुछ काम का नहीं लौटाते, इसलिए हर कॉल को optional chaining से सुरक्षित रखें। रेंडर के दौरान रनटाइम कॉल करने के बजाय values को props या state से चलाएँ, जैसा ऊपर useEffect में है। इससे एनिमेशन आपकी UI state के साथ sync रहता है और component को साधारण props से टेस्ट करना आसान हो जाता है।

Next.js App Router में Rive कैसे इस्तेमाल करें?

Rive ब्राउज़र में canvas पर ड्रॉ करता है, इसलिए इसे client component में चलना ज़रूरी है। App Router में components default रूप से server components होते हैं। जिस फ़ाइल में useRive कॉल होता है, उसके सबसे ऊपर "use client" लिखें:

"use client";

import { useRive } from "@rive-app/react-webgl2";

export default function HeroCharacter() {
  const { RiveComponent } = useRive({
    src: "/character.riv",
    stateMachine: "CharacterStateMachine",
    autoplay: true,
  });
  return <div className="h-60 w-60"><RiveComponent /></div>;
}

फिर इसे हमेशा की तरह किसी server page से import करें। पेज अब भी server पर रेंडर होता है; सिर्फ़ यह component ब्राउज़र में hydrate होता है।

.riv फ़ाइल को public/ में रखें, ताकि यह स्थिर URL के साथ static asset के रूप में serve हो। CSS में box का साइज़ पहले से तय करें, ताकि canvas दिखने पर लेआउट शिफ़्ट न हो। हीरो एनिमेशन के लिए canvas के पीछे एक static poster image रखने से लोडिंग के दौरान खाली box नहीं दिखता।

Pages Router में भी यही नियम लागू होता है: Rive सिर्फ़ ब्राउज़र में चलना चाहिए। अगर server-side errors दिखें, तो अगले सेक्शन वाला dynamic import pattern इस्तेमाल करें।

"window is not defined" एरर कैसे ठीक करें?

इस एरर का मतलब है कि जिस कोड को browser globals चाहिए, वह server rendering के दौरान चल गया। Rive के साथ यह आमतौर पर तब होता है जब component किसी server component से रेंडर होता है, या जब Rive पैकेज किसी ऐसे module में import होता है जिसे server evaluate करता है।

समाधान, प्राथमिकता के क्रम में:

  1. पक्का करें कि Rive import करने वाला component "use client" से शुरू होता है।
  2. अगर एरर बना रहे, तो next/dynamic से component को सिर्फ़ ब्राउज़र में लोड करें:
"use client";

import dynamic from "next/dynamic";

const HeroCharacter = dynamic(() => import("./HeroCharacter"), {
  ssr: false,
  loading: () => <img src="/character-poster.png" alt="" width={240} height={240} />,
});

Next.js के हाल के versions में ssr: false सिर्फ़ client component के अंदर ही allowed है, इसीलिए ऊपर वाला wrapper भी "use client" से marked है।

  1. module के top level पर कभी भी window, document या Rive instance को न छुएँ। यह काम useEffect या event handlers के अंदर करें, जो सिर्फ़ ब्राउज़र में चलते हैं।

ssr: false के साथ लेज़ी लोडिंग से WASM रनटाइम initial bundle से बाहर भी रहता है, जो उन पेजों के लिए फ़ायदेमंद है जहाँ एनिमेशन fold के नीचे है।

prefers-reduced-motion का ध्यान कैसे रखें?

यूज़र ऑपरेटिंग सिस्टम से मोशन कम करने को कह सकते हैं, और ब्राउज़र इसे prefers-reduced-motion media query के ज़रिए बताते हैं, जो 2020 से व्यापक रूप से उपलब्ध है। हर लूपिंग कैरेक्टर के लिए इसका पालन करें।

"use client";

import { useEffect, useState } from "react";

function usePrefersReducedMotion() {
  const [reduce, setReduce] = useState(false);
  useEffect(() => {
    const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
    setReduce(mq.matches);
    const onChange = () => setReduce(mq.matches);
    mq.addEventListener("change", onChange);
    return () => mq.removeEventListener("change", onChange);
  }, []);
  return reduce;
}

export function MaybeAnimated() {
  const reduce = usePrefersReducedMotion();
  return reduce
    ? <img src="/character-poster.png" alt="" width={240} height={240} />
    : <Character mood={0} successCount={0} />;
}

मोशन कम करने की सेटिंग के लिए static image रेंडर करना सबसे सुरक्षित विकल्प है, और इससे रनटाइम डाउनलोड भी नहीं होता। अगर कैरेक्टर कोई स्टेट बताता है, जैसे loading, तो वह अर्थ टेक्स्ट या accessible status message में बनाए रखें। WCAG से जुड़ी जानकारी के लिए accessible एनिमेशन और reduced motion देखें।

React या Next.js ऐप में Rive एनिमेशन जोड़ें

  1. रनटाइम इंस्टॉल करें. npm install @rive-app/react-webgl2 चलाएँ (या एक पेज पर कई instances के लिए @rive-app/react-canvas)।
  2. फ़ाइल जोड़ें. .riv फ़ाइल को public/ में रखें, ताकि यह /character.riv जैसे स्थिर URL पर serve हो।
  3. client component बनाएँ. फ़ाइल की शुरुआत "use client" से करें और useRive({ src, stateMachine, autoplay: true }) कॉल करें।
  4. render करें और साइज़ तय करें. RiveComponent को fixed width और height वाले wrapper के अंदर रेंडर करें।
  5. स्टेट मशीन कंट्रोल करें. इनपुट-आधारित फ़ाइलों के लिए useStateMachineInput इस्तेमाल करें, या data-bound फ़ाइलों के लिए view model hooks के साथ autoBind: true।
  6. मोशन कम करें सेटिंग को संभालें. prefers-reduced-motion चेक करें और जब यह reduce पर सेट हो, तो उसकी जगह static poster image रेंडर करें।

अक्सर पूछे जाने वाले सवाल

@rive-app/react-canvas इस्तेमाल करूँ या @rive-app/react-webgl2?

ज़्यादातर प्रोजेक्ट के लिए @rive-app/react-webgl2 इस्तेमाल करें; Rive इसकी सलाह देता है और यह vector feathering जैसे फ़ीचर सपोर्ट करता है। @rive-app/react-canvas तब चुनें जब किसी पेज पर एक साथ कई एनिमेशन दिखते हों और आप WebGL context limits से बचना चाहते हों, या जब WebGL उपलब्ध न हो। दोनों एक ही API देते हैं।

React में मेरा Rive इनपुट null क्यों है?

useStateMachineInput तब तक null लौटाता है जब तक फ़ाइल लोड न हो जाए और स्टेट मशीन चलने न लगे। कॉल्स को optional chaining से सुरक्षित रखें, useRive और hook दोनों को स्टेट मशीन का बिल्कुल सही नाम दें, और इनपुट नामों में case और spacing चेक करें। view models में बदली गई फ़ाइलों में अब इनपुट नहीं होते।

क्या Rive, React Server Components के साथ काम करता है?

Rive components को ब्राउज़र में चलना ज़रूरी है, इसलिए वे server components नहीं हो सकते। Rive कोड को "use client" से marked component में रखें और उसे server component से import करें। server आसपास का पेज रेंडर करता है, जबकि Rive component client पर hydrate होकर ड्रॉ करता है।

क्या मैं stateMachine की जगह stateMachines इस्तेमाल कर सकता हूँ?

पुराना कोड बहुवचन stateMachines option इस्तेमाल करता है, जिसे Rive ने web रनटाइम v2.41.0 में deprecated करके एकवचन stateMachine को अपनाया। पुराना कोड शायद अब भी चले, लेकिन नए कोड में stateMachine इस्तेमाल करें, ताकि यह मौजूदा documentation से मेल खाए और deprecated options हटने पर भविष्य में कुछ न टूटे।

इस गाइड से झटपट जवाब

स्रोत

संबंधित गाइड