<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mascot Engine</title>
    <description>The latest articles on DEV Community by Mascot Engine (@mascotengine).</description>
    <link>https://dev.to/mascotengine</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3886587%2F646fcf6a-296f-4c3b-8328-42b466258287.png</url>
      <title>DEV Community: Mascot Engine</title>
      <link>https://dev.to/mascotengine</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mascotengine"/>
    <language>en</language>
    <item>
      <title>AI Mascots for Apps: How Interactive AI Characters Can Make Your Product Feel Alive</title>
      <dc:creator>Mascot Engine</dc:creator>
      <pubDate>Sun, 23 Aug 2026 12:35:42 +0000</pubDate>
      <link>https://dev.to/mascotengine/ai-mascots-for-apps-how-interactive-ai-characters-can-make-your-product-feel-alive-2d1c</link>
      <guid>https://dev.to/mascotengine/ai-mascots-for-apps-how-interactive-ai-characters-can-make-your-product-feel-alive-2d1c</guid>
      <description>&lt;p&gt;AI products are becoming smarter every month.&lt;/p&gt;

&lt;p&gt;But there’s still one problem: &lt;strong&gt;most AI apps look and feel the same.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A chat box. A loading animation. A few buttons. Maybe a voice waveform.&lt;/p&gt;

&lt;p&gt;What if your AI could have its own character?&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;AI mascot&lt;/strong&gt; or &lt;strong&gt;interactive AI character&lt;/strong&gt; can give your product a recognizable personality while also communicating what the AI is doing.&lt;/p&gt;

&lt;p&gt;At &lt;strong&gt;Mascot Engine&lt;/strong&gt;, we design and animate interactive mascots for web apps, mobile apps, SaaS products, and AI experiences using &lt;strong&gt;Rive animation&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is an AI Mascot?
&lt;/h2&gt;

&lt;p&gt;An AI mascot is an animated character connected to the behavior of an AI-powered product.&lt;/p&gt;

&lt;p&gt;It doesn't need to be a complicated human avatar.&lt;/p&gt;

&lt;p&gt;An AI character could be a cute mascot, abstract creature, robot, floating orb, brand character, simple face, or completely original visual identity.&lt;/p&gt;

&lt;p&gt;The important part is that the character can &lt;strong&gt;react to the product in real time&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Idle → Listening → Thinking → Speaking → Success → Error → Resting&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When the AI starts processing a request, your app can trigger the mascot's &lt;strong&gt;Thinking&lt;/strong&gt; animation.&lt;/p&gt;

&lt;p&gt;When a voice assistant starts listening, it can switch to &lt;strong&gt;Listening&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When the AI responds, the character can move into &lt;strong&gt;Speaking&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This makes an AI mascot more than an animation.&lt;/p&gt;

&lt;p&gt;It becomes part of the interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why AI Products Need Better Characters
&lt;/h2&gt;

&lt;p&gt;AI is becoming integrated into customer support, education, productivity, healthcare, finance, SaaS, mobile apps, and many other digital products.&lt;/p&gt;

&lt;p&gt;As the technology becomes more common, branding becomes increasingly important.&lt;/p&gt;

&lt;p&gt;Your AI assistant shouldn't necessarily look like every other AI assistant.&lt;/p&gt;

&lt;p&gt;A custom &lt;strong&gt;AI mascot design&lt;/strong&gt; gives your product something users can recognize.&lt;/p&gt;

&lt;p&gt;Instead of displaying:&lt;/p&gt;

&lt;p&gt;“Thinking…”&lt;/p&gt;

&lt;p&gt;You could have your mascot visibly thinking.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;p&gt;“Listening…”&lt;/p&gt;

&lt;p&gt;Your AI character could become attentive and react to the user's voice.&lt;/p&gt;

&lt;p&gt;Instead of another generic success icon, your mascot could celebrate with the user.&lt;/p&gt;

&lt;p&gt;The interface becomes more emotional without becoming complicated.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI Character Animation with Rive
&lt;/h2&gt;

&lt;p&gt;For interactive product mascots, we primarily work with &lt;strong&gt;Rive&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Rive is different from simply adding a GIF, MP4, or traditional character animation to an app.&lt;/p&gt;

&lt;p&gt;A Rive character can contain an interactive &lt;strong&gt;State Machine&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Developers can control the character using inputs and triggers from their application.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;idle&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;listening&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;thinking&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;speaking&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;success&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;error&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;celebrate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sleep&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Your application logic determines which animation plays.&lt;/p&gt;

&lt;p&gt;That makes Rive particularly useful for an &lt;strong&gt;AI character animator system&lt;/strong&gt;, where the character needs to respond dynamically rather than play one predefined video.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI Mascots for Voice Assistants
&lt;/h2&gt;

&lt;p&gt;One of the most interesting applications is voice AI.&lt;/p&gt;

&lt;p&gt;Imagine an AI companion inside an iOS, Android, or web application.&lt;/p&gt;

&lt;p&gt;Before interaction, the mascot stays in a subtle idle loop.&lt;/p&gt;

&lt;p&gt;When the microphone detects the user:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Idle → Listening&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While the AI generates the answer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Listening → Thinking&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When the response begins:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thinking → Speaking&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After the conversation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Speaking → Idle&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The mascot visually communicates the AI's current state without requiring additional UI elements.&lt;/p&gt;

&lt;p&gt;You can also add facial expressions, eye movement, blinking, mouth animation, lip sync, reactions, and emotional states.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI Character Creator for Startups
&lt;/h2&gt;

&lt;p&gt;You don't necessarily need an existing mascot.&lt;/p&gt;

&lt;p&gt;At &lt;strong&gt;Mascot Engine&lt;/strong&gt;, we can start from an existing PNG, SVG, illustration, sketch, brand identity, or simply a character idea.&lt;/p&gt;

&lt;p&gt;A typical workflow can be:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI Mascot Concept → Character Design → Vector Illustration → Rive Rigging → Character Animation → State Machine → Developer-ready Rive File&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you already have a character, we can prepare it for animation instead of redesigning everything.&lt;/p&gt;

&lt;p&gt;This makes Mascot Engine useful for founders and developers searching for an &lt;strong&gt;AI character creator&lt;/strong&gt;, &lt;strong&gt;AI mascot designer&lt;/strong&gt;, or &lt;strong&gt;Rive character animator&lt;/strong&gt; for their product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interactive Mascots Aren't Just for AI
&lt;/h2&gt;

&lt;p&gt;The same system can work across many product experiences.&lt;/p&gt;

&lt;p&gt;A fintech mascot might celebrate a savings goal.&lt;/p&gt;

&lt;p&gt;A fitness mascot could react when someone completes a workout.&lt;/p&gt;

&lt;p&gt;A learning app character could encourage students.&lt;/p&gt;

&lt;p&gt;A productivity mascot could celebrate completed tasks.&lt;/p&gt;

&lt;p&gt;A SaaS mascot could guide users through onboarding.&lt;/p&gt;

&lt;p&gt;A game character could respond to rewards, levels, streaks, and achievements.&lt;/p&gt;

&lt;p&gt;The mascot becomes a small &lt;strong&gt;interactive character system inside your UI&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the Mascot Lightweight
&lt;/h2&gt;

&lt;p&gt;A product mascot doesn't need huge animations or complex scenes.&lt;/p&gt;

&lt;p&gt;In many cases, subtle animation works better.&lt;/p&gt;

&lt;p&gt;Breathing.&lt;/p&gt;

&lt;p&gt;Blinking.&lt;/p&gt;

&lt;p&gt;Looking around.&lt;/p&gt;

&lt;p&gt;Thinking.&lt;/p&gt;

&lt;p&gt;Listening.&lt;/p&gt;

&lt;p&gt;Speaking.&lt;/p&gt;

&lt;p&gt;A small celebration.&lt;/p&gt;

&lt;p&gt;Even these simple states can make a static illustration feel alive.&lt;/p&gt;

&lt;p&gt;Because Rive is designed for real-time vector animation, we can focus on creating lightweight interactive experiences suitable for modern websites and mobile applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Need an AI Mascot Animator?
&lt;/h2&gt;

&lt;p&gt;If you're searching for an:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI mascot designer&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;AI mascot animator&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;AI character animator&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;AI character creator&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Rive animator&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Rive character animator&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;interactive mascot designer&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;animated mascot for an app&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;AI assistant character designer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;…this is exactly what we're building at &lt;strong&gt;Mascot Engine&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We work with developers, founders, startups, SaaS teams, and product designers who want to give their products more personality.&lt;/p&gt;

&lt;p&gt;You can start small with an idle animation and a few core states, then continue adding new expressions, actions, props, and interactions as your product grows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bring Your AI Character to Life
&lt;/h2&gt;

&lt;p&gt;Your AI already has intelligence.&lt;/p&gt;

&lt;p&gt;Now give it a personality users can see.&lt;/p&gt;

&lt;p&gt;Whether you're building an &lt;strong&gt;AI assistant, AI companion, voice AI app, SaaS product, mobile app, or interactive web experience&lt;/strong&gt;, Mascot Engine can help you create a mascot that becomes part of the product itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mascot Engine — Interactive Mascots for Digital Products&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🌐 &lt;strong&gt;mascotengine.com&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;💬 &lt;strong&gt;WhatsApp: +94 71 700 0999&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Have an existing mascot? Send it to us.&lt;/p&gt;

&lt;p&gt;Starting from an idea? We can build the character with you.&lt;/p&gt;

&lt;p&gt;AI Mascot, AI Mascot Design, AI Mascot Animator, AI Character Animator, AI Character Creator, Interactive AI Character, Animated AI Character, Rive Character Animation, Rive Animator, Interactive Mascot, App Mascot, SaaS Mascot, AI Assistant Character, Voice AI Character, Web App Animation, Mobile App Character Animation.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mascot</category>
      <category>app</category>
      <category>webanimation</category>
    </item>
    <item>
      <title>5 Rive State Machine Tricks Every Flutter Developer Should Know</title>
      <dc:creator>Mascot Engine</dc:creator>
      <pubDate>Fri, 31 Jul 2026 23:48:09 +0000</pubDate>
      <link>https://dev.to/mascotengine/5-rive-state-machine-tricks-every-flutter-developer-should-know-239</link>
      <guid>https://dev.to/mascotengine/5-rive-state-machine-tricks-every-flutter-developer-should-know-239</guid>
      <description>&lt;h1&gt;
  
  
  5 Rive State Machine Tricks Every Flutter Developer Should Know
&lt;/h1&gt;

&lt;p&gt;When developers first discover &lt;strong&gt;Rive&lt;/strong&gt;, they usually focus on the animations.&lt;/p&gt;

&lt;p&gt;The real magic isn't the animation.&lt;/p&gt;

&lt;p&gt;It's the &lt;strong&gt;State Machine&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;State Machines transform animations into interactive experiences that react to your application's logic.&lt;/p&gt;

&lt;p&gt;Instead of playing a timeline from start to finish, your UI becomes alive.&lt;/p&gt;

&lt;p&gt;After building multiple interactive mascots and product animations, these are the five techniques I use in almost every project.&lt;/p&gt;




&lt;h1&gt;
  
  
  1. Don't Create Multiple Animation Files
&lt;/h1&gt;

&lt;p&gt;One mistake beginners make is exporting separate animations for every interaction.&lt;/p&gt;

&lt;p&gt;❌ Idle.riv&lt;/p&gt;

&lt;p&gt;❌ Happy.riv&lt;/p&gt;

&lt;p&gt;❌ Success.riv&lt;/p&gt;

&lt;p&gt;❌ Thinking.riv&lt;/p&gt;

&lt;p&gt;Instead...&lt;/p&gt;

&lt;p&gt;Keep everything inside &lt;strong&gt;one State Machine&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Entry

↓

Idle

↓

Hover

↓

Happy

↓

Thinking

↓

Success
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes your Flutter code much cleaner and reduces asset management.&lt;/p&gt;




&lt;h1&gt;
  
  
  2. Use Boolean Inputs for Simple States
&lt;/h1&gt;

&lt;p&gt;Not everything needs a Trigger.&lt;/p&gt;

&lt;p&gt;Boolean Inputs are perfect for states like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dark Mode&lt;/li&gt;
&lt;li&gt;AI Thinking&lt;/li&gt;
&lt;li&gt;Online Status&lt;/li&gt;
&lt;li&gt;Hover&lt;/li&gt;
&lt;li&gt;Loading&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Flutter example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;thinkingInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The animation instantly reacts without restarting.&lt;/p&gt;




&lt;h1&gt;
  
  
  3. Reserve Triggers for Events
&lt;/h1&gt;

&lt;p&gt;Triggers are ideal for one-time interactions.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Success&lt;/li&gt;
&lt;li&gt;Error&lt;/li&gt;
&lt;li&gt;Celebration&lt;/li&gt;
&lt;li&gt;Button Click&lt;/li&gt;
&lt;li&gt;Achievement Unlocked
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;successTrigger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fire&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unlike Booleans, Triggers automatically reset.&lt;/p&gt;




&lt;h1&gt;
  
  
  4. Blend Animations Naturally
&lt;/h1&gt;

&lt;p&gt;Instead of instantly switching between animations...&lt;/p&gt;

&lt;p&gt;Blend them.&lt;/p&gt;

&lt;p&gt;A smooth transition from Idle → Happy feels much more professional than snapping between states.&lt;/p&gt;

&lt;p&gt;Small details like this dramatically improve the user experience.&lt;/p&gt;




&lt;h1&gt;
  
  
  5. Design for User Experience First
&lt;/h1&gt;

&lt;p&gt;The biggest mistake isn't technical.&lt;/p&gt;

&lt;p&gt;It's adding animation everywhere.&lt;/p&gt;

&lt;p&gt;Animation should communicate.&lt;/p&gt;

&lt;p&gt;Ask yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does this help the user?&lt;/li&gt;
&lt;li&gt;Does it explain something?&lt;/li&gt;
&lt;li&gt;Does it provide feedback?&lt;/li&gt;
&lt;li&gt;Does it make the interface feel alive?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the answer is yes...&lt;/p&gt;

&lt;p&gt;Keep it.&lt;/p&gt;

&lt;p&gt;If not...&lt;/p&gt;

&lt;p&gt;Remove it.&lt;/p&gt;

&lt;p&gt;Good animation is invisible.&lt;/p&gt;

&lt;p&gt;Great animation feels natural.&lt;/p&gt;




&lt;p&gt;State Machines are the reason Rive feels different from traditional animation tools.&lt;/p&gt;

&lt;p&gt;Instead of simply decorating your UI...&lt;/p&gt;

&lt;p&gt;They become part of your application's logic.&lt;/p&gt;

&lt;p&gt;That's why Rive works so well for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI Assistants&lt;/li&gt;
&lt;li&gt;Interactive Mascots&lt;/li&gt;
&lt;li&gt;SaaS Dashboards&lt;/li&gt;
&lt;li&gt;Flutter Apps&lt;/li&gt;
&lt;li&gt;React Native Apps&lt;/li&gt;
&lt;li&gt;Gamified Products&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you start thinking in states instead of timelines, you'll never build interactive animations the same way again.&lt;/p&gt;




&lt;h2&gt;
  
  
  What are your favorite Rive State Machine tips?
&lt;/h2&gt;

&lt;p&gt;I'd love to hear how you're using Rive in your projects.&lt;/p&gt;

&lt;p&gt;👇 Share your workflow in the comments.&lt;/p&gt;




&lt;h3&gt;
  
  
  About Me
&lt;/h3&gt;

&lt;p&gt;I'm building &lt;strong&gt;Mascot Engine&lt;/strong&gt;, where I create interactive mascots and Rive animations for Flutter, React Native, SaaS products, and AI applications.&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://mascotengine.com" rel="noopener noreferrer"&gt;https://mascotengine.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📱 WhatsApp: +94 71 700 0999&lt;/p&gt;

&lt;p&gt;Happy animating! 🚀&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>rive</category>
      <category>animation</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Rive vs Lottie: Which Animation Tool Should Flutter Developers Choose in 2026?</title>
      <dc:creator>Mascot Engine</dc:creator>
      <pubDate>Fri, 31 Jul 2026 23:43:31 +0000</pubDate>
      <link>https://dev.to/mascotengine/rive-vs-lottie-which-animation-tool-should-flutter-developers-choose-in-2026-lp5</link>
      <guid>https://dev.to/mascotengine/rive-vs-lottie-which-animation-tool-should-flutter-developers-choose-in-2026-lp5</guid>
      <description>&lt;h1&gt;
  
  
  Rive vs Lottie: Which Animation Tool Should Flutter Developers Choose in 2026?
&lt;/h1&gt;

&lt;p&gt;If you're building a Flutter application today, you've probably asked yourself this question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Should I use Rive or Lottie?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Both tools are excellent.&lt;/p&gt;

&lt;p&gt;Both create beautiful animations.&lt;/p&gt;

&lt;p&gt;Both are widely used by modern apps.&lt;/p&gt;

&lt;p&gt;But they're designed for different purposes.&lt;/p&gt;

&lt;p&gt;After working on interactive mascot animations, onboarding experiences, and AI assistants for Flutter apps, I've learned that choosing the right tool depends entirely on what you're building.&lt;/p&gt;

&lt;p&gt;Let's compare them.&lt;/p&gt;




&lt;h1&gt;
  
  
  What Is Lottie?
&lt;/h1&gt;

&lt;p&gt;Lottie is an animation format created by Airbnb.&lt;/p&gt;

&lt;p&gt;It exports animations from Adobe After Effects using Bodymovin and allows developers to play them inside applications.&lt;/p&gt;

&lt;p&gt;Lottie is perfect for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Splash screens&lt;/li&gt;
&lt;li&gt;Loading animations&lt;/li&gt;
&lt;li&gt;Success animations&lt;/li&gt;
&lt;li&gt;Empty states&lt;/li&gt;
&lt;li&gt;Marketing illustrations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The animation simply plays from beginning to end.&lt;/p&gt;




&lt;h1&gt;
  
  
  What Is Rive?
&lt;/h1&gt;

&lt;p&gt;Rive is a real-time interactive animation tool.&lt;/p&gt;

&lt;p&gt;Unlike Lottie, Rive animations aren't limited to a timeline.&lt;/p&gt;

&lt;p&gt;Instead, they can react instantly to user input.&lt;/p&gt;

&lt;p&gt;A single &lt;code&gt;.riv&lt;/code&gt; file can contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Idle animations&lt;/li&gt;
&lt;li&gt;Hover states&lt;/li&gt;
&lt;li&gt;Click animations&lt;/li&gt;
&lt;li&gt;Happy expressions&lt;/li&gt;
&lt;li&gt;Thinking animations&lt;/li&gt;
&lt;li&gt;State Machines&lt;/li&gt;
&lt;li&gt;Interactive UI logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of simply watching an animation...&lt;/p&gt;

&lt;p&gt;Users interact with it.&lt;/p&gt;




&lt;h1&gt;
  
  
  Quick Comparison
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Rive&lt;/th&gt;
&lt;th&gt;Lottie&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Interactive Animations&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State Machines&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real-time Inputs&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timeline Animation&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flutter Support&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;React Native Support&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI Assistant Animation&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Button Interaction&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h1&gt;
  
  
  When Lottie Is the Better Choice
&lt;/h1&gt;

&lt;p&gt;Lottie is fantastic when your animation never changes.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logo animations&lt;/li&gt;
&lt;li&gt;Loading indicators&lt;/li&gt;
&lt;li&gt;Splash screens&lt;/li&gt;
&lt;li&gt;Marketing illustrations&lt;/li&gt;
&lt;li&gt;Success checkmarks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the animation simply plays once, Lottie is lightweight and easy to implement.&lt;/p&gt;




&lt;h1&gt;
  
  
  When Rive Wins
&lt;/h1&gt;

&lt;p&gt;Rive becomes incredibly powerful when animations need to respond to users.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interactive onboarding&lt;/li&gt;
&lt;li&gt;AI assistants&lt;/li&gt;
&lt;li&gt;Dashboard mascots&lt;/li&gt;
&lt;li&gt;Animated buttons&lt;/li&gt;
&lt;li&gt;Progress tracking&lt;/li&gt;
&lt;li&gt;Character emotions&lt;/li&gt;
&lt;li&gt;Product walkthroughs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of creating multiple animation files, everything lives inside one interactive animation.&lt;/p&gt;




&lt;h1&gt;
  
  
  Flutter Developers Love Rive
&lt;/h1&gt;

&lt;p&gt;One of the biggest advantages of Rive is how naturally it fits into Flutter applications.&lt;/p&gt;

&lt;p&gt;You can connect animations directly to your app logic.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;taskCompleted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;stateMachine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isThinking&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;thinkingInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of switching between separate animation files, the State Machine handles everything.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why State Machines Matter
&lt;/h1&gt;

&lt;p&gt;Imagine building an AI assistant.&lt;/p&gt;

&lt;p&gt;The assistant should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Idle while waiting&lt;/li&gt;
&lt;li&gt;Think while processing&lt;/li&gt;
&lt;li&gt;Celebrate success&lt;/li&gt;
&lt;li&gt;Show concern during errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With Lottie...&lt;/p&gt;

&lt;p&gt;You would typically manage multiple animation files.&lt;/p&gt;

&lt;p&gt;With Rive...&lt;/p&gt;

&lt;p&gt;Everything exists inside one animation.&lt;/p&gt;

&lt;p&gt;The application simply changes the current state.&lt;/p&gt;

&lt;p&gt;This makes development much cleaner.&lt;/p&gt;




&lt;h1&gt;
  
  
  Performance
&lt;/h1&gt;

&lt;p&gt;Both Rive and Lottie perform well.&lt;/p&gt;

&lt;p&gt;However, Rive often becomes the better solution when applications require dozens of interactive animations.&lt;/p&gt;

&lt;p&gt;Because the animation is controlled internally, developers spend less time switching between assets.&lt;/p&gt;




&lt;h1&gt;
  
  
  Which One Should You Choose?
&lt;/h1&gt;

&lt;p&gt;Choose &lt;strong&gt;Lottie&lt;/strong&gt; if you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple timeline animations&lt;/li&gt;
&lt;li&gt;Marketing graphics&lt;/li&gt;
&lt;li&gt;Loading animations&lt;/li&gt;
&lt;li&gt;Logo reveals&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choose &lt;strong&gt;Rive&lt;/strong&gt; if you're building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SaaS products&lt;/li&gt;
&lt;li&gt;AI assistants&lt;/li&gt;
&lt;li&gt;Interactive mascots&lt;/li&gt;
&lt;li&gt;Flutter applications&lt;/li&gt;
&lt;li&gt;React Native applications&lt;/li&gt;
&lt;li&gt;Gamified experiences&lt;/li&gt;
&lt;li&gt;Modern product interfaces&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  My Experience
&lt;/h1&gt;

&lt;p&gt;Over the last few years I've worked on interactive character animation for mobile apps.&lt;/p&gt;

&lt;p&gt;One thing became obvious very quickly.&lt;/p&gt;

&lt;p&gt;Users don't remember static animations.&lt;/p&gt;

&lt;p&gt;They remember interactions.&lt;/p&gt;

&lt;p&gt;A mascot that waves.&lt;/p&gt;

&lt;p&gt;A character that celebrates.&lt;/p&gt;

&lt;p&gt;An assistant that reacts while thinking.&lt;/p&gt;

&lt;p&gt;Those small details create products people actually enjoy using.&lt;/p&gt;

&lt;p&gt;That's where Rive really shines.&lt;/p&gt;




&lt;p&gt;Lottie isn't being replaced.&lt;/p&gt;

&lt;p&gt;It's simply solving a different problem.&lt;/p&gt;

&lt;p&gt;If your animation is passive, Lottie is a fantastic choice.&lt;/p&gt;

&lt;p&gt;If your animation needs to think, react, respond, and become part of the interface...&lt;/p&gt;

&lt;p&gt;Rive is the better tool.&lt;/p&gt;

&lt;p&gt;As more AI products, SaaS platforms, and mobile applications adopt interactive experiences, I believe we'll continue seeing Rive become a standard part of modern product design.&lt;/p&gt;




&lt;h1&gt;
  
  
  Need Help Building Interactive Rive Animations?
&lt;/h1&gt;

&lt;p&gt;At &lt;strong&gt;Mascot Engine&lt;/strong&gt;, we create:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🐉 Interactive Mascots&lt;/li&gt;
&lt;li&gt;🎨 Character Rigging&lt;/li&gt;
&lt;li&gt;⚡ Rive State Machines&lt;/li&gt;
&lt;li&gt;📱 Flutter Integration&lt;/li&gt;
&lt;li&gt;⚛️ React Native Integration&lt;/li&gt;
&lt;li&gt;🤖 AI Assistant Animation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🌐 &lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://mascotengine.com" rel="noopener noreferrer"&gt;https://mascotengine.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📱 &lt;strong&gt;WhatsApp:&lt;/strong&gt; +94 717000999&lt;/p&gt;

&lt;p&gt;If you're building a product that deserves more personality, I'd love to hear about it.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Thanks for reading!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Have you used &lt;strong&gt;Rive&lt;/strong&gt; or &lt;strong&gt;Lottie&lt;/strong&gt; in your projects? Let me know your experience in the comments.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>rive</category>
      <category>lottie</category>
      <category>animation</category>
    </item>
    <item>
      <title>Why Every SaaS Product Needs an Interactive Mascot in 2026</title>
      <dc:creator>Mascot Engine</dc:creator>
      <pubDate>Fri, 31 Jul 2026 23:37:52 +0000</pubDate>
      <link>https://dev.to/mascotengine/why-every-saas-product-needs-an-interactive-mascot-in-2026-229c</link>
      <guid>https://dev.to/mascotengine/why-every-saas-product-needs-an-interactive-mascot-in-2026-229c</guid>
      <description>&lt;h1&gt;
  
  
  Why Every SaaS Product Needs an Interactive Mascot in 2026
&lt;/h1&gt;

&lt;p&gt;Modern SaaS products are no longer competing only on features.&lt;/p&gt;

&lt;p&gt;Today, users expect products that feel intuitive, engaging, and enjoyable to use. While beautiful UI and smooth performance are essential, there's another element that helps products stand out—&lt;strong&gt;personality&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One of the best ways to add personality is through &lt;strong&gt;interactive mascots&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Using tools like &lt;strong&gt;Rive&lt;/strong&gt;, companies can create animated characters that react to user actions, celebrate achievements, explain features, and make products feel more alive.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is an Interactive Mascot?
&lt;/h2&gt;

&lt;p&gt;An interactive mascot is much more than an animated illustration.&lt;/p&gt;

&lt;p&gt;Unlike traditional GIFs or videos, interactive mascots respond to user actions in real time.&lt;/p&gt;

&lt;p&gt;For example, a mascot can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;👋 Welcome new users&lt;/li&gt;
&lt;li&gt;🎉 Celebrate completed tasks&lt;/li&gt;
&lt;li&gt;🤔 Think while AI generates responses&lt;/li&gt;
&lt;li&gt;📈 React to achievements&lt;/li&gt;
&lt;li&gt;💬 Guide users through onboarding&lt;/li&gt;
&lt;li&gt;❤️ Build emotional connections&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of watching an animation, users interact with it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Users Remember Products With Personality
&lt;/h2&gt;

&lt;p&gt;Think about the apps you use every day.&lt;/p&gt;

&lt;p&gt;Many have excellent features.&lt;/p&gt;

&lt;p&gt;Many have beautiful dashboards.&lt;/p&gt;

&lt;p&gt;Yet most of them feel exactly the same.&lt;/p&gt;

&lt;p&gt;Now imagine opening an application where a small dragon welcomes you, celebrates your progress, and reacts every time you complete an important action.&lt;/p&gt;

&lt;p&gt;Suddenly the product feels different.&lt;/p&gt;

&lt;p&gt;That emotional connection helps users remember your brand.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Rive Is Perfect for Interactive Characters
&lt;/h2&gt;

&lt;p&gt;Unlike GIFs or videos, &lt;strong&gt;Rive&lt;/strong&gt; creates real-time animations.&lt;/p&gt;

&lt;p&gt;Instead of exporting dozens of animation files, developers work with a single &lt;code&gt;.riv&lt;/code&gt; file containing multiple animation states.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Idle&lt;/li&gt;
&lt;li&gt;Happy&lt;/li&gt;
&lt;li&gt;Thinking&lt;/li&gt;
&lt;li&gt;Success&lt;/li&gt;
&lt;li&gt;Error&lt;/li&gt;
&lt;li&gt;Celebration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these states can be connected using &lt;strong&gt;State Machines&lt;/strong&gt;, allowing animations to respond instantly to user input.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Interactive Mascots Make the Biggest Impact
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🚀 SaaS Products
&lt;/h3&gt;

&lt;p&gt;Interactive onboarding&lt;/p&gt;

&lt;p&gt;Dashboard assistants&lt;/p&gt;

&lt;p&gt;Achievement celebrations&lt;/p&gt;

&lt;p&gt;Progress tracking&lt;/p&gt;




&lt;h3&gt;
  
  
  🤖 AI Applications
&lt;/h3&gt;

&lt;p&gt;Thinking animations&lt;/p&gt;

&lt;p&gt;Listening states&lt;/p&gt;

&lt;p&gt;Speaking animations&lt;/p&gt;

&lt;p&gt;Friendly AI assistants&lt;/p&gt;




&lt;h3&gt;
  
  
  💰 FinTech
&lt;/h3&gt;

&lt;p&gt;Savings celebrations&lt;/p&gt;

&lt;p&gt;Investment milestones&lt;/p&gt;

&lt;p&gt;Budget assistants&lt;/p&gt;




&lt;h3&gt;
  
  
  📚 Education
&lt;/h3&gt;

&lt;p&gt;Learning companions&lt;/p&gt;

&lt;p&gt;Interactive tutors&lt;/p&gt;

&lt;p&gt;Gamified experiences&lt;/p&gt;




&lt;h3&gt;
  
  
  🏥 Healthcare
&lt;/h3&gt;

&lt;p&gt;Friendly patient assistants&lt;/p&gt;

&lt;p&gt;Medication reminders&lt;/p&gt;

&lt;p&gt;Progress tracking&lt;/p&gt;




&lt;h2&gt;
  
  
  Flutter + Rive
&lt;/h2&gt;

&lt;p&gt;Flutter developers love Rive because it provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lightweight vector animations&lt;/li&gt;
&lt;li&gt;High performance&lt;/li&gt;
&lt;li&gt;Interactive State Machines&lt;/li&gt;
&lt;li&gt;Responsive animations&lt;/li&gt;
&lt;li&gt;Native integration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Perfect for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Login screens&lt;/li&gt;
&lt;li&gt;Splash screens&lt;/li&gt;
&lt;li&gt;Empty states&lt;/li&gt;
&lt;li&gt;AI assistants&lt;/li&gt;
&lt;li&gt;Gamification&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  React Native + Rive
&lt;/h2&gt;

&lt;p&gt;React Native applications also benefit from Rive.&lt;/p&gt;

&lt;p&gt;Interactive animations improve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User onboarding&lt;/li&gt;
&lt;li&gt;Dashboard experiences&lt;/li&gt;
&lt;li&gt;AI assistants&lt;/li&gt;
&lt;li&gt;Loading screens&lt;/li&gt;
&lt;li&gt;Success messages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because Rive uses vector graphics, applications stay lightweight while delivering premium animations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Not Just Use Lottie?
&lt;/h2&gt;

&lt;p&gt;Lottie is fantastic for timeline animations.&lt;/p&gt;

&lt;p&gt;However, when applications require interaction, Rive offers much more flexibility.&lt;/p&gt;

&lt;p&gt;Rive supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State Machines&lt;/li&gt;
&lt;li&gt;Boolean Inputs&lt;/li&gt;
&lt;li&gt;Trigger Inputs&lt;/li&gt;
&lt;li&gt;Number Inputs&lt;/li&gt;
&lt;li&gt;Interactive Logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's why many modern applications choose Rive for interactive experiences.&lt;/p&gt;




&lt;h2&gt;
  
  
  Choosing the Right Rive Animator
&lt;/h2&gt;

&lt;p&gt;A professional Rive animator should understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Character Rigging&lt;/li&gt;
&lt;li&gt;Animation Principles&lt;/li&gt;
&lt;li&gt;UX Design&lt;/li&gt;
&lt;li&gt;State Machines&lt;/li&gt;
&lt;li&gt;Flutter&lt;/li&gt;
&lt;li&gt;React Native&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Animation isn't just about movement.&lt;/p&gt;

&lt;p&gt;It's about creating interactions that feel natural.&lt;/p&gt;




&lt;p&gt;The future of product design isn't just better interfaces.&lt;/p&gt;

&lt;p&gt;It's better experiences.&lt;/p&gt;

&lt;p&gt;Interactive mascots make applications more engaging, memorable, and enjoyable to use.&lt;/p&gt;

&lt;p&gt;Whether you're building a SaaS platform, AI assistant, fintech app, or education product, adding an interactive character can dramatically improve the user experience.&lt;/p&gt;

&lt;p&gt;Modern users don't just remember great features.&lt;/p&gt;

&lt;p&gt;They remember products with personality.&lt;/p&gt;




&lt;h2&gt;
  
  
  Need a Rive Character Animator?
&lt;/h2&gt;

&lt;p&gt;At &lt;strong&gt;Mascot Engine&lt;/strong&gt;, we build interactive Rive characters for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flutter Apps&lt;/li&gt;
&lt;li&gt;React Native Apps&lt;/li&gt;
&lt;li&gt;SaaS Products&lt;/li&gt;
&lt;li&gt;AI Assistants&lt;/li&gt;
&lt;li&gt;Mobile Applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🌐 &lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://mascotengine.com" rel="noopener noreferrer"&gt;https://mascotengine.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📱 &lt;strong&gt;WhatsApp:&lt;/strong&gt; +94717000999&lt;/p&gt;

&lt;p&gt;Let's build an interactive experience your users will remember.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Thanks for reading!&lt;/strong&gt; If you're using Rive in your projects, I'd love to hear how you're bringing your interfaces to life.&lt;/p&gt;

</description>
      <category>rive</category>
      <category>flutter</category>
      <category>react</category>
      <category>saas</category>
    </item>
    <item>
      <title>Hire a Rive Character Animator: The Complete Guide for Startups in 2026</title>
      <dc:creator>Mascot Engine</dc:creator>
      <pubDate>Fri, 31 Jul 2026 23:34:46 +0000</pubDate>
      <link>https://dev.to/mascotengine/hire-a-rive-character-animator-the-complete-guide-for-startups-in-2026-1ika</link>
      <guid>https://dev.to/mascotengine/hire-a-rive-character-animator-the-complete-guide-for-startups-in-2026-1ika</guid>
      <description>&lt;h1&gt;
  
  
  Hire a Rive Character Animator: The Complete Guide for Startups in 2026
&lt;/h1&gt;

&lt;p&gt;Modern applications are no longer judged only by their features.&lt;/p&gt;

&lt;p&gt;Users expect products that feel fast, interactive, and enjoyable to use. Small animations, delightful micro-interactions, and intelligent characters are becoming part of great product experiences.&lt;/p&gt;

&lt;p&gt;This is exactly why &lt;strong&gt;Rive&lt;/strong&gt; has become one of the fastest-growing animation technologies for Flutter, React Native, and modern web applications.&lt;/p&gt;

&lt;p&gt;If you're building a SaaS platform, AI application, fintech product, education app, or mobile startup, hiring a professional &lt;strong&gt;Rive Character Animator&lt;/strong&gt; can significantly improve the user experience.&lt;/p&gt;

&lt;p&gt;In this guide, you'll learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What Rive is&lt;/li&gt;
&lt;li&gt;Why startups choose Rive&lt;/li&gt;
&lt;li&gt;What a Rive Character Animator actually does&lt;/li&gt;
&lt;li&gt;How interactive mascots improve engagement&lt;/li&gt;
&lt;li&gt;How much Rive animation costs&lt;/li&gt;
&lt;li&gt;How to choose the right animator&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  What is Rive?
&lt;/h1&gt;

&lt;p&gt;Rive is a real-time interactive animation tool.&lt;/p&gt;

&lt;p&gt;Unlike GIFs or videos, Rive animations can react instantly to user input.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Button Hover&lt;/li&gt;
&lt;li&gt;Login Success&lt;/li&gt;
&lt;li&gt;Error States&lt;/li&gt;
&lt;li&gt;Loading Animation&lt;/li&gt;
&lt;li&gt;AI Assistant&lt;/li&gt;
&lt;li&gt;Mascot Emotions&lt;/li&gt;
&lt;li&gt;Progress Indicators&lt;/li&gt;
&lt;li&gt;Interactive Onboarding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything happens in real time.&lt;/p&gt;

&lt;p&gt;Instead of exporting dozens of animation files, developers work with one optimized &lt;code&gt;.riv&lt;/code&gt; file that contains multiple animation states.&lt;/p&gt;

&lt;p&gt;This keeps applications lightweight while delivering premium interactions.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why Rive Is Becoming So Popular
&lt;/h1&gt;

&lt;p&gt;Traditional animation workflows often rely on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GIFs&lt;/li&gt;
&lt;li&gt;MP4 videos&lt;/li&gt;
&lt;li&gt;Lottie JSON files&lt;/li&gt;
&lt;li&gt;Sprite Sheets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While these methods work well for simple motion graphics, they become difficult to manage when animations need to respond dynamically.&lt;/p&gt;

&lt;p&gt;Rive solves this problem through State Machines.&lt;/p&gt;

&lt;p&gt;State Machines allow characters to respond instantly based on application events.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;User logs in&lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;Character waves&lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;User completes onboarding&lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;Character celebrates&lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;User becomes inactive&lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;Character returns to idle&lt;/p&gt;

&lt;p&gt;Everything exists inside one optimized animation file.&lt;/p&gt;

&lt;p&gt;This dramatically simplifies development while improving the user experience.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why Interactive Characters Matter
&lt;/h1&gt;

&lt;p&gt;Think about the products people love using.&lt;/p&gt;

&lt;p&gt;Many of them have personality.&lt;/p&gt;

&lt;p&gt;Interactive characters transform ordinary applications into memorable experiences.&lt;/p&gt;

&lt;p&gt;Instead of showing another loading spinner...&lt;/p&gt;

&lt;p&gt;Imagine a friendly dragon that smiles while your dashboard loads.&lt;/p&gt;

&lt;p&gt;Imagine an AI assistant that reacts while thinking.&lt;/p&gt;

&lt;p&gt;Imagine a mascot celebrating when users reach a milestone.&lt;/p&gt;

&lt;p&gt;These interactions create emotional connections with users.&lt;/p&gt;

&lt;p&gt;Products become easier to understand.&lt;/p&gt;

&lt;p&gt;Users stay engaged longer.&lt;/p&gt;

&lt;p&gt;People remember the experience.&lt;/p&gt;




&lt;h1&gt;
  
  
  Industries Using Rive
&lt;/h1&gt;

&lt;p&gt;Interactive animation is no longer limited to gaming.&lt;/p&gt;

&lt;p&gt;Some of the fastest growing industries using Rive include:&lt;/p&gt;

&lt;h2&gt;
  
  
  SaaS
&lt;/h2&gt;

&lt;p&gt;Interactive onboarding&lt;/p&gt;

&lt;p&gt;Achievement celebrations&lt;/p&gt;

&lt;p&gt;Dashboard assistants&lt;/p&gt;

&lt;p&gt;Progress indicators&lt;/p&gt;




&lt;h2&gt;
  
  
  AI Products
&lt;/h2&gt;

&lt;p&gt;Thinking animations&lt;/p&gt;

&lt;p&gt;Listening states&lt;/p&gt;

&lt;p&gt;Speaking animations&lt;/p&gt;

&lt;p&gt;Assistant personalities&lt;/p&gt;




&lt;h2&gt;
  
  
  Fintech
&lt;/h2&gt;

&lt;p&gt;Saving celebrations&lt;/p&gt;

&lt;p&gt;Investment milestones&lt;/p&gt;

&lt;p&gt;Budget assistants&lt;/p&gt;

&lt;p&gt;Progress tracking&lt;/p&gt;




&lt;h2&gt;
  
  
  Healthcare
&lt;/h2&gt;

&lt;p&gt;Friendly patient assistants&lt;/p&gt;

&lt;p&gt;Medication reminders&lt;/p&gt;

&lt;p&gt;Progress tracking&lt;/p&gt;




&lt;h2&gt;
  
  
  Education
&lt;/h2&gt;

&lt;p&gt;Learning mascots&lt;/p&gt;

&lt;p&gt;Interactive tutors&lt;/p&gt;

&lt;p&gt;Gamified lessons&lt;/p&gt;

&lt;p&gt;Achievement rewards&lt;/p&gt;




&lt;h2&gt;
  
  
  Productivity
&lt;/h2&gt;

&lt;p&gt;Task completion&lt;/p&gt;

&lt;p&gt;Daily streaks&lt;/p&gt;

&lt;p&gt;Focus assistants&lt;/p&gt;

&lt;p&gt;Interactive dashboards&lt;/p&gt;




&lt;h1&gt;
  
  
  What Does a Rive Character Animator Do?
&lt;/h1&gt;

&lt;p&gt;Many people think character animation simply means making a character move.&lt;/p&gt;

&lt;p&gt;Professional Rive animation goes much further.&lt;/p&gt;

&lt;p&gt;A Rive Character Animator builds intelligent animation systems.&lt;/p&gt;

&lt;p&gt;Typical animation states include:&lt;/p&gt;

&lt;h2&gt;
  
  
  Idle
&lt;/h2&gt;

&lt;p&gt;The character breathes naturally while waiting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Happy
&lt;/h2&gt;

&lt;p&gt;The mascot celebrates completed actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thinking
&lt;/h2&gt;

&lt;p&gt;Perfect for AI assistants.&lt;/p&gt;

&lt;h2&gt;
  
  
  Speaking
&lt;/h2&gt;

&lt;p&gt;Lip sync and subtle body motion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loading
&lt;/h2&gt;

&lt;p&gt;Keeps users entertained during wait times.&lt;/p&gt;

&lt;h2&gt;
  
  
  Success
&lt;/h2&gt;

&lt;p&gt;Celebrates user achievements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error
&lt;/h2&gt;

&lt;p&gt;Responds naturally without creating frustration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hover
&lt;/h2&gt;

&lt;p&gt;Adds delightful interactions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Click
&lt;/h2&gt;

&lt;p&gt;Provides immediate visual feedback.&lt;/p&gt;

&lt;p&gt;These animations are connected through State Machines rather than individual exported videos.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why Startups Prefer Interactive Mascots
&lt;/h1&gt;

&lt;p&gt;Startups often compete against companies with much larger budgets.&lt;/p&gt;

&lt;p&gt;A memorable product experience becomes a competitive advantage.&lt;/p&gt;

&lt;p&gt;Interactive mascots help by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increasing engagement&lt;/li&gt;
&lt;li&gt;Improving onboarding&lt;/li&gt;
&lt;li&gt;Explaining features naturally&lt;/li&gt;
&lt;li&gt;Creating emotional connections&lt;/li&gt;
&lt;li&gt;Encouraging retention&lt;/li&gt;
&lt;li&gt;Making products memorable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of another generic dashboard...&lt;/p&gt;

&lt;p&gt;Users remember the friendly character that guided them through the experience.&lt;/p&gt;




&lt;h1&gt;
  
  
  Flutter + Rive
&lt;/h1&gt;

&lt;p&gt;Flutter has become one of the most popular frameworks for cross-platform development.&lt;/p&gt;

&lt;p&gt;Rive integrates beautifully with Flutter.&lt;/p&gt;

&lt;p&gt;Benefits include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Native performance&lt;/li&gt;
&lt;li&gt;Lightweight assets&lt;/li&gt;
&lt;li&gt;Responsive layouts&lt;/li&gt;
&lt;li&gt;State Machine support&lt;/li&gt;
&lt;li&gt;Real-time animation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Popular Flutter use cases include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Splash Screens&lt;/li&gt;
&lt;li&gt;Empty States&lt;/li&gt;
&lt;li&gt;Login Screens&lt;/li&gt;
&lt;li&gt;AI Assistants&lt;/li&gt;
&lt;li&gt;Onboarding&lt;/li&gt;
&lt;li&gt;Gamification&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  React Native + Rive
&lt;/h1&gt;

&lt;p&gt;React Native developers increasingly choose Rive because it delivers premium animations without relying on large video assets.&lt;/p&gt;

&lt;p&gt;Interactive characters improve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User onboarding&lt;/li&gt;
&lt;li&gt;Dashboard experiences&lt;/li&gt;
&lt;li&gt;AI assistants&lt;/li&gt;
&lt;li&gt;Success messages&lt;/li&gt;
&lt;li&gt;Loading screens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because animations remain vector-based, applications stay lightweight.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why Not Just Use Lottie?
&lt;/h1&gt;

&lt;p&gt;Lottie is excellent for playing timeline animations.&lt;/p&gt;

&lt;p&gt;However, when applications require real interaction, Rive becomes much more powerful.&lt;/p&gt;

&lt;p&gt;Rive supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State Machines&lt;/li&gt;
&lt;li&gt;Boolean Inputs&lt;/li&gt;
&lt;li&gt;Number Inputs&lt;/li&gt;
&lt;li&gt;Trigger Inputs&lt;/li&gt;
&lt;li&gt;Interactive Logic&lt;/li&gt;
&lt;li&gt;Blend Trees&lt;/li&gt;
&lt;li&gt;Nested Animations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes Rive ideal for applications rather than advertisements.&lt;/p&gt;




&lt;h1&gt;
  
  
  What Makes a Great Rive Character Animator?
&lt;/h1&gt;

&lt;p&gt;Choosing an animator isn't just about finding someone who knows Rive.&lt;/p&gt;

&lt;p&gt;Look for someone who understands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UX Design&lt;/li&gt;
&lt;li&gt;Product Design&lt;/li&gt;
&lt;li&gt;Character Rigging&lt;/li&gt;
&lt;li&gt;Vector Illustration&lt;/li&gt;
&lt;li&gt;Animation Principles&lt;/li&gt;
&lt;li&gt;State Machines&lt;/li&gt;
&lt;li&gt;Flutter&lt;/li&gt;
&lt;li&gt;React Native&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The best Rive animators think like product designers rather than traditional motion designers.&lt;/p&gt;




&lt;h1&gt;
  
  
  Questions to Ask Before Hiring
&lt;/h1&gt;

&lt;p&gt;Before hiring, ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can you build State Machines?&lt;/li&gt;
&lt;li&gt;Have you animated AI assistants?&lt;/li&gt;
&lt;li&gt;Do you optimize performance?&lt;/li&gt;
&lt;li&gt;Have you worked with Flutter?&lt;/li&gt;
&lt;li&gt;Have you worked with React Native?&lt;/li&gt;
&lt;li&gt;Can you animate existing illustrations?&lt;/li&gt;
&lt;li&gt;Do you provide source files?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These questions quickly reveal real experience.&lt;/p&gt;




&lt;h1&gt;
  
  
  Typical Project Workflow
&lt;/h1&gt;

&lt;p&gt;A professional workflow usually looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Character illustration&lt;/li&gt;
&lt;li&gt;Layer organization&lt;/li&gt;
&lt;li&gt;Rigging&lt;/li&gt;
&lt;li&gt;Bone setup&lt;/li&gt;
&lt;li&gt;Mesh deformation&lt;/li&gt;
&lt;li&gt;Idle animation&lt;/li&gt;
&lt;li&gt;Secondary animations&lt;/li&gt;
&lt;li&gt;State Machine creation&lt;/li&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;li&gt;Integration support&lt;/li&gt;
&lt;/ol&gt;




&lt;h1&gt;
  
  
  How Much Does Rive Animation Cost?
&lt;/h1&gt;

&lt;p&gt;Pricing depends on complexity.&lt;/p&gt;

&lt;p&gt;Simple mascot animation usually includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Idle&lt;/li&gt;
&lt;li&gt;Blink&lt;/li&gt;
&lt;li&gt;Hover&lt;/li&gt;
&lt;li&gt;Click&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More advanced projects include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI Assistant&lt;/li&gt;
&lt;li&gt;State Machines&lt;/li&gt;
&lt;li&gt;Multiple emotions&lt;/li&gt;
&lt;li&gt;Lip Sync&lt;/li&gt;
&lt;li&gt;Interactive onboarding&lt;/li&gt;
&lt;li&gt;Achievement systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;High-quality animation is an investment that improves product quality for years.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why Choose Mascot Engine?
&lt;/h1&gt;

&lt;p&gt;At &lt;strong&gt;Mascot Engine&lt;/strong&gt;, we specialize in building interactive Rive characters for modern applications.&lt;/p&gt;

&lt;p&gt;Services include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Character Rigging&lt;/li&gt;
&lt;li&gt;Rive Animation&lt;/li&gt;
&lt;li&gt;Interactive Mascots&lt;/li&gt;
&lt;li&gt;Flutter Integration&lt;/li&gt;
&lt;li&gt;React Native Integration&lt;/li&gt;
&lt;li&gt;State Machines&lt;/li&gt;
&lt;li&gt;AI Assistant Animation&lt;/li&gt;
&lt;li&gt;SaaS Product Animation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of creating simple timeline animations, we build characters that become part of your product experience.&lt;/p&gt;




&lt;h1&gt;
  
  
  Frequently Asked Questions
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Is Rive better than Lottie?
&lt;/h2&gt;

&lt;p&gt;For interactive applications, yes.&lt;/p&gt;

&lt;p&gt;Rive supports State Machines and real-time interaction that Lottie cannot provide in the same way.&lt;/p&gt;




&lt;h2&gt;
  
  
  Can I use Rive with Flutter?
&lt;/h2&gt;

&lt;p&gt;Yes.&lt;/p&gt;

&lt;p&gt;Flutter has excellent Rive support.&lt;/p&gt;




&lt;h2&gt;
  
  
  Can I use Rive with React Native?
&lt;/h2&gt;

&lt;p&gt;Yes.&lt;/p&gt;

&lt;p&gt;Interactive animations work well with React Native applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  Can I animate an existing character?
&lt;/h2&gt;

&lt;p&gt;Absolutely.&lt;/p&gt;

&lt;p&gt;Many clients already have illustrations.&lt;/p&gt;

&lt;p&gt;They only need professional rigging and animation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Do I need multiple animation files?
&lt;/h2&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;Most interactions can exist inside a single optimized &lt;code&gt;.riv&lt;/code&gt; file.&lt;/p&gt;




&lt;p&gt;Modern products need more than beautiful interfaces.&lt;/p&gt;

&lt;p&gt;They need personality.&lt;/p&gt;

&lt;p&gt;Interactive characters help users understand products, enjoy onboarding, celebrate achievements, and build stronger emotional connections.&lt;/p&gt;

&lt;p&gt;Whether you're building an AI application, SaaS platform, fintech product, or education app, investing in professional Rive animation can make your product stand out.&lt;/p&gt;

&lt;p&gt;If you're looking for interactive character animation for Flutter, React Native, or web applications, working with an experienced Rive Character Animator can save development time while creating a significantly better user experience.&lt;/p&gt;




&lt;h1&gt;
  
  
  Ready to Build an Interactive Mascot?
&lt;/h1&gt;

&lt;p&gt;Whether you already have character artwork or need help bringing an idea to life, &lt;strong&gt;Mascot Engine&lt;/strong&gt; specializes in professional Rive character animation for startups, SaaS products, AI tools, and mobile applications.&lt;/p&gt;

&lt;p&gt;🌐 &lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://mascotengine.com" rel="noopener noreferrer"&gt;https://mascotengine.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📱 &lt;strong&gt;WhatsApp:&lt;/strong&gt; +94 71 700 0999&lt;/p&gt;

&lt;p&gt;Let's build an interactive experience your users will remember.&lt;/p&gt;




&lt;p&gt;hire rive animator, rive character animator, rive animation services, flutter rive animation, react native rive, interactive mascot, ai mascot, state machine, rive animation, mascot engine&lt;/p&gt;

</description>
      <category>rive</category>
      <category>flutter</category>
      <category>reactnative</category>
      <category>animation</category>
    </item>
    <item>
      <title>Rive Data Binding and ViewModels for Interactive Characters</title>
      <dc:creator>Mascot Engine</dc:creator>
      <pubDate>Fri, 17 Jul 2026 21:06:32 +0000</pubDate>
      <link>https://dev.to/mascotengine/rive-data-binding-and-viewmodels-for-interactive-characters-kcl</link>
      <guid>https://dev.to/mascotengine/rive-data-binding-and-viewmodels-for-interactive-characters-kcl</guid>
      <description>&lt;p&gt;At Mascot Engine, we build interactive character systems that connect animation, product behaviour, and application data.&lt;/p&gt;

&lt;p&gt;In this tutorial, we will use a sample Rive file named &lt;code&gt;mascotengine.riv&lt;/code&gt; to demonstrate how Rive Data Binding and ViewModels can control an interactive character.&lt;/p&gt;

&lt;p&gt;The sample Mascot Engine character will be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Change emotions&lt;/li&gt;
&lt;li&gt;Enter listening, thinking, and talking states&lt;/li&gt;
&lt;li&gt;Follow pointer or touch positions&lt;/li&gt;
&lt;li&gt;Display dynamic text&lt;/li&gt;
&lt;li&gt;Change its colors at runtime&lt;/li&gt;
&lt;li&gt;React to success and error events&lt;/li&gt;
&lt;li&gt;Connect to React or Next.js application logic&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sample Mascot Engine file structure
&lt;/h2&gt;

&lt;p&gt;Our sample &lt;code&gt;mascotengine.riv&lt;/code&gt; file uses the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mascotengine.riv
├── Artboard: Mascot Engine
├── State Machine: Mascot Engine State Machine
└── ViewModel: MascotEngineViewModel
    ├── displayName
    ├── emotion
    ├── activity
    ├── isTalking
    ├── lookX
    ├── lookY
    ├── accentColor
    ├── celebrate
    └── showError
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ViewModel becomes the public interface between the Mascot Engine character and the application.&lt;/p&gt;

&lt;p&gt;The internal character rig, animation timelines, transitions, and blend states can change without requiring the developer to rewrite the integration, provided the ViewModel contract remains stable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add the Mascot Engine file
&lt;/h2&gt;

&lt;p&gt;Place the sample file inside the application’s public directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public/
└── mascotengine.riv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file can then be loaded using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/mascotengine.riv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  React implementation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;useRive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useViewModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useViewModelInstance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useViewModelInstanceBoolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useViewModelInstanceColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useViewModelInstanceEnum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useViewModelInstanceNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useViewModelInstanceString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useViewModelInstanceTrigger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@rive-app/react-webgl2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MascotEngineCharacter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RiveComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRive&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/mascotengine.riv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;artboard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mascot Engine&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;stateMachines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mascot Engine State Machine&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;autoplay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;autoBind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mascotViewModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useViewModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MascotEngineViewModel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mascotInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useViewModelInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;mascotViewModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MascotEngineDefault&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;rive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;setDisplayName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useViewModelInstanceString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;displayName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;mascotInstance&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;emotion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;setEmotion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useViewModelInstanceEnum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;emotion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;mascotInstance&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;setIsTalking&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useViewModelInstanceBoolean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;isTalking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;mascotInstance&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;setLookX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useViewModelInstanceNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lookX&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;mascotInstance&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;setLookY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useViewModelInstanceNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lookY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;mascotInstance&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;setRgb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;setAccentColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useViewModelInstanceColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;accentColor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;mascotInstance&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;celebrate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useViewModelInstanceTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;celebrate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;mascotInstance&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
        &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0 auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RiveComponent&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Character: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;displayName&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mascot Engine&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Emotion: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;emotion&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Loading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setDisplayName&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Nova&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Change Name
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setEmotion&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;thinking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Think
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setIsTalking&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Start Talking
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;setLookX&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;setLookY&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Look Right
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setAccentColor&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;246&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Change Theme
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;celebrate&lt;/span&gt;&lt;span class="p"&gt;?.()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Celebrate
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How Mascot Engine structures interactive characters
&lt;/h2&gt;

&lt;p&gt;At Mascot Engine, we treat the ViewModel as a stable contract between the character system and the application.&lt;/p&gt;

&lt;p&gt;The application controls clear product-level properties such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;activity = thinking
emotion = happy
isTalking = true
lookX = 0.5
lookY = -0.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The developer does not need to control individual bones, timelines, mouth shapes, eye layers, or internal animation transitions.&lt;/p&gt;

&lt;p&gt;Those details remain inside &lt;code&gt;mascotengine.riv&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This makes the character easier to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integrate&lt;/li&gt;
&lt;li&gt;Test&lt;/li&gt;
&lt;li&gt;Update&lt;/li&gt;
&lt;li&gt;Reuse&lt;/li&gt;
&lt;li&gt;Hand over to developers&lt;/li&gt;
&lt;li&gt;Connect to AI or audio systems&lt;/li&gt;
&lt;li&gt;Support across multiple platforms&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building an AI assistant with Mascot Engine
&lt;/h2&gt;

&lt;p&gt;The sample Mascot Engine character can respond to an AI application lifecycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User starts recording
→ activity = listening

Application processes the request
→ activity = thinking

Audio response begins
→ activity = talking

Audio response finishes
→ activity = idle
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setMascotActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;listening&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;thinking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;talking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;setActivity&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="nx"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;activity&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;thinking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setEmotion&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;thinking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;activity&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;talking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setEmotion&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;happy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;activity&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setEmotion&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;neutral&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows &lt;code&gt;mascotengine.riv&lt;/code&gt; to function as a complete interactive character system instead of a collection of disconnected animation clips.&lt;/p&gt;

&lt;h2&gt;
  
  
  Need a production-ready interactive character?
&lt;/h2&gt;

&lt;p&gt;Mascot Engine creates interactive character systems for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI products&lt;/li&gt;
&lt;li&gt;SaaS platforms&lt;/li&gt;
&lt;li&gt;Educational applications&lt;/li&gt;
&lt;li&gt;Mobile apps&lt;/li&gt;
&lt;li&gt;React and Next.js products&lt;/li&gt;
&lt;li&gt;Flutter and React Native applications&lt;/li&gt;
&lt;li&gt;Onboarding experiences&lt;/li&gt;
&lt;li&gt;Virtual assistants and support agents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our work can include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Character preparation and rigging&lt;/li&gt;
&lt;li&gt;Emotional animation systems&lt;/li&gt;
&lt;li&gt;Interactive State Machines&lt;/li&gt;
&lt;li&gt;Data Binding and ViewModels&lt;/li&gt;
&lt;li&gt;Listening, thinking, and talking states&lt;/li&gt;
&lt;li&gt;Pointer, touch, and gaze controls&lt;/li&gt;
&lt;li&gt;Lip-sync and viseme systems&lt;/li&gt;
&lt;li&gt;Runtime customization&lt;/li&gt;
&lt;li&gt;Developer-ready documentation&lt;/li&gt;
&lt;li&gt;Web and mobile integration preparation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We do not deliver only a looping character animation.&lt;/p&gt;

&lt;p&gt;Mascot Engine builds a reusable character system that can respond to real application logic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mascotengine.com/" rel="noopener noreferrer"&gt;Explore Mascot Engine&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mascotengine.com/contact/" rel="noopener noreferrer"&gt;Start an interactive mascot project&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About the author&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Praneeth Kawya Thathsara is a Rive Animator and Interactive Motion Designer specializing in production-ready character systems for AI, SaaS, web, and mobile products.&lt;/p&gt;

&lt;p&gt;He is the founder of &lt;a href="https://mascotengine.com/" rel="noopener noreferrer"&gt;Mascot Engine&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>rive</category>
      <category>databinding</category>
      <category>interactive</category>
      <category>character</category>
    </item>
    <item>
      <title>How to Integrate an Interactive Rive Mascot into a React or Next.js Web App</title>
      <dc:creator>Mascot Engine</dc:creator>
      <pubDate>Fri, 17 Jul 2026 20:48:04 +0000</pubDate>
      <link>https://dev.to/mascotengine/how-to-integrate-an-interactive-rive-mascot-into-a-react-or-nextjs-web-app-412j</link>
      <guid>https://dev.to/mascotengine/how-to-integrate-an-interactive-rive-mascot-into-a-react-or-nextjs-web-app-412j</guid>
      <description>&lt;p&gt;A mascot inside a web application should do more than play the same looping animation.&lt;/p&gt;

&lt;p&gt;A properly designed interactive mascot can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React to application events&lt;/li&gt;
&lt;li&gt;Follow the user's pointer&lt;/li&gt;
&lt;li&gt;Change emotions&lt;/li&gt;
&lt;li&gt;Enter listening, thinking, and talking states&lt;/li&gt;
&lt;li&gt;Celebrate successful actions&lt;/li&gt;
&lt;li&gt;Respond to errors&lt;/li&gt;
&lt;li&gt;Guide users through onboarding&lt;/li&gt;
&lt;li&gt;Connect to an AI assistant or text-to-speech system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this tutorial, we will integrate an interactive Rive mascot into a React or Next.js application and control it using application logic.&lt;/p&gt;

&lt;p&gt;We will build a mascot with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pointer-controlled eye movement&lt;/li&gt;
&lt;li&gt;Multiple emotional states&lt;/li&gt;
&lt;li&gt;Talking controls&lt;/li&gt;
&lt;li&gt;A celebration trigger&lt;/li&gt;
&lt;li&gt;Rive Data Binding and ViewModels&lt;/li&gt;
&lt;li&gt;A reusable React component&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why use Rive for an interactive mascot?
&lt;/h2&gt;

&lt;p&gt;Traditional GIF, video, and Lottie animations are useful for linear playback. However, an interactive product mascot needs to respond dynamically to what is happening inside the application.&lt;/p&gt;

&lt;p&gt;Rive allows designers and developers to place multiple character behaviours inside a single &lt;code&gt;.riv&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;The application can then control properties such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;emotion = happy
isTalking = true
lookX = 0.65
lookY = -0.20
celebrate = trigger
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the character part of the product interface rather than a decorative animation placed on top of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we are building
&lt;/h2&gt;

&lt;p&gt;Our React component will communicate with a Rive ViewModel containing these properties:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;emotion&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enum&lt;/td&gt;
&lt;td&gt;Changes the mascot's emotional state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isTalking&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Boolean&lt;/td&gt;
&lt;td&gt;Starts or stops the talking behaviour&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lookX&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number&lt;/td&gt;
&lt;td&gt;Controls horizontal gaze&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lookY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number&lt;/td&gt;
&lt;td&gt;Controls vertical gaze&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;celebrate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Trigger&lt;/td&gt;
&lt;td&gt;Plays a celebration reaction&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The exact property names are not required by Rive. They are simply a clean naming convention that both the animator and developer can agree on.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Prepare the Rive file
&lt;/h2&gt;

&lt;p&gt;Before writing React code, the &lt;code&gt;.riv&lt;/code&gt; file should contain:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A character artboard&lt;/li&gt;
&lt;li&gt;Idle and reaction animations&lt;/li&gt;
&lt;li&gt;A State Machine&lt;/li&gt;
&lt;li&gt;A ViewModel connected to the State Machine&lt;/li&gt;
&lt;li&gt;A default ViewModel instance&lt;/li&gt;
&lt;li&gt;Runtime properties such as &lt;code&gt;emotion&lt;/code&gt;, &lt;code&gt;isTalking&lt;/code&gt;, &lt;code&gt;lookX&lt;/code&gt;, and &lt;code&gt;lookY&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A useful character structure might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mascot
├── Artboard: Mascot
├── State Machine: Mascot State Machine
└── ViewModel: MascotViewModel
    ├── emotion
    ├── isTalking
    ├── lookX
    ├── lookY
    └── celebrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set the ViewModel and its default instance inside the Rive editor. This allows the React runtime to bind to it automatically.&lt;/p&gt;

&lt;p&gt;Export the file as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mascot.riv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Add the Rive file to the project
&lt;/h2&gt;

&lt;p&gt;For a React or Next.js project, place the file inside the &lt;code&gt;public&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public/
└── mascot.riv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will then be available from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/mascot.riv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Install the React runtime
&lt;/h2&gt;

&lt;p&gt;Install the Rive React WebGL2 package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @rive-app/react-webgl2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or with pnpm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add @rive-app/react-webgl2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or Yarn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add @rive-app/react-webgl2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The WebGL2 React package provides the &lt;code&gt;useRive&lt;/code&gt; hook, the Rive rendering component, and Data Binding hooks.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Create the interactive mascot component
&lt;/h2&gt;

&lt;p&gt;Create a new component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;components/InteractiveMascot.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PointerEvent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;useRive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useViewModelInstanceBoolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useViewModelInstanceEnum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useViewModelInstanceNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useViewModelInstanceTrigger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@rive-app/react-webgl2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./InteractiveMascot.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;InteractiveMascot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isTalking&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTalkingState&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RiveComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRive&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/mascot.riv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;artboard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mascot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;stateMachines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mascot State Machine&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;autoplay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;autoBind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;viewModelInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rive&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;viewModelInstance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;emotion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;setEmotion&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nf"&gt;useViewModelInstanceEnum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;emotion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;viewModelInstance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;setIsTalking&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nf"&gt;useViewModelInstanceBoolean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;isTalking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;viewModelInstance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;setLookX&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nf"&gt;useViewModelInstanceNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lookX&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;viewModelInstance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;setLookY&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nf"&gt;useViewModelInstanceNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lookY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;viewModelInstance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;celebrate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nf"&gt;useViewModelInstanceTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;celebrate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;viewModelInstance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handlePointerMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PointerEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLDivElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bounds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBoundingClientRect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;relativeX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;bounds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;bounds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;relativeY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientY&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;bounds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;bounds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;normalizedX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;relativeX&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;normalizedY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;relativeY&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clampedX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;normalizedX&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clampedY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;normalizedY&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="nx"&gt;setLookX&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="nx"&gt;clampedX&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;setLookY&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="nx"&gt;clampedY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;resetGaze&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setLookX&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;setLookY&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;toggleTalking&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isTalking&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;setTalkingState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nextValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;setIsTalking&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="nx"&gt;nextValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;section&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
        &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mascotContainer&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onPointerMove&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handlePointerMove&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onPointerLeave&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;resetGaze&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;aria-label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Interactive animated mascot"&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RiveComponent&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;riveCanvas&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;controls&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Current emotion: &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;emotion&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Loading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buttonGroup&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
            &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setEmotion&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;happy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            Happy
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
            &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setEmotion&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;thinking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            Thinking
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
            &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setEmotion&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;confused&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            Confused
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
            &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;toggleTalking&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isTalking&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Stop Talking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Start Talking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
            &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;celebrate&lt;/span&gt;&lt;span class="p"&gt;?.()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            Celebrate
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the artboard, State Machine, property, and enum names with the exact names used inside your Rive file.&lt;/p&gt;

&lt;p&gt;For example, the following values must exist inside the &lt;code&gt;emotion&lt;/code&gt; enum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;happy
thinking
confused
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Add the component styles
&lt;/h2&gt;

&lt;p&gt;Create:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;components/InteractiveMascot.module.css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.section&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;760px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.mascotContainer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;480px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#e5e7eb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f8fafc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;touch-action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.riveCanvas&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.controls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.buttonGroup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-wrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.buttonGroup&lt;/span&gt; &lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#d1d5db&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;999px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ffffff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#111827&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;inherit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.buttonGroup&lt;/span&gt; &lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f3f4f6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.buttonGroup&lt;/span&gt; &lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="nd"&gt;:focus-visible&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;outline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;37&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;235&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;outline-offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;640px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.section&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nc"&gt;.mascotContainer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;360px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Rive canvas receives its dimensions from its container. If the animation does not appear, first check that the parent element has an explicit width and height.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Use it in a React application
&lt;/h2&gt;

&lt;p&gt;Import the component into your page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;InteractiveMascot&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/InteractiveMascot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Meet our interactive assistant&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InteractiveMascot&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Use it in a Next.js App Router project
&lt;/h2&gt;

&lt;p&gt;Rive rendering and pointer interactions require browser-side JavaScript.&lt;/p&gt;

&lt;p&gt;That is why the component begins with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rest of your Next.js page can remain a Server Component.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;InteractiveMascot&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/InteractiveMascot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;HomePage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Your AI learning assistant&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Ask a question and receive help from an interactive
          animated character.
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InteractiveMascot&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only the interactive mascot component needs to be a Client Component. You do not need to convert the entire page or layout into one.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the pointer-controlled gaze works
&lt;/h2&gt;

&lt;p&gt;Browser pointer coordinates are measured in pixels.&lt;/p&gt;

&lt;p&gt;Rive character controls are easier to manage using normalized values such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-1 = left or top
 0 = centre
 1 = right or bottom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pointer position is first calculated relative to the mascot container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;relativeX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;bounds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;bounds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That returns a value between &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We then convert it to a value between &lt;code&gt;-1&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;normalizedX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;relativeX&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is passed to the character:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;setLookX&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="nx"&gt;normalizedX&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside Rive, &lt;code&gt;lookX&lt;/code&gt; and &lt;code&gt;lookY&lt;/code&gt; can control eye position, head rotation, body lean, or a mixture of all three.&lt;/p&gt;

&lt;p&gt;For a more natural result, avoid moving only the pupils. Add a small amount of head movement and use smoothing inside the Rive State Machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting the mascot to application events
&lt;/h2&gt;

&lt;p&gt;The mascot becomes useful when it reacts to real product logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Form validation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setEmotion&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;happy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;celebrate&lt;/span&gt;&lt;span class="p"&gt;?.();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setEmotion&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;confused&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Loading an AI response
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;askAssistant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;setEmotion&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;thinking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;setIsTalking&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/assistant&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;question&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setEmotion&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The assistant request failed.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;setEmotion&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;happy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;setIsTalking&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Onboarding progress
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleStepComplete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;step&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;step&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;celebrate&lt;/span&gt;&lt;span class="p"&gt;?.();&lt;/span&gt;
    &lt;span class="nx"&gt;setEmotion&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;happy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Authentication errors
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleLoginError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;setEmotion&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;concerned&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The animation system does not need to understand your complete application. It only needs a clear set of properties that map product events to character behaviours.&lt;/p&gt;

&lt;h2&gt;
  
  
  State Machine inputs or Data Binding?
&lt;/h2&gt;

&lt;p&gt;Older Rive projects often expose Boolean, Number, and Trigger inputs directly from a State Machine.&lt;/p&gt;

&lt;p&gt;Those inputs can still exist in legacy projects. However, Rive now recommends Data Binding and ViewModels for new implementations.&lt;/p&gt;

&lt;p&gt;Data Binding provides a more structured contract between the &lt;code&gt;.riv&lt;/code&gt; file and application code.&lt;/p&gt;

&lt;p&gt;Instead of searching for several unrelated inputs, developers can work with a defined model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MascotViewModel
├── emotion
├── isTalking
├── lookX
├── lookY
└── celebrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also allows properties such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Strings&lt;/li&gt;
&lt;li&gt;Colors&lt;/li&gt;
&lt;li&gt;Enums&lt;/li&gt;
&lt;li&gt;Images&lt;/li&gt;
&lt;li&gt;Nested ViewModels&lt;/li&gt;
&lt;li&gt;Lists&lt;/li&gt;
&lt;li&gt;Artboards&lt;/li&gt;
&lt;li&gt;Triggers&lt;/li&gt;
&lt;li&gt;Numbers&lt;/li&gt;
&lt;li&gt;Booleans&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This becomes especially useful when the same mascot needs different names, themes, outfits, expressions, or user-specific data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structuring a production-ready mascot
&lt;/h2&gt;

&lt;p&gt;A scalable mascot system should not contain dozens of disconnected animations controlled by unclear input names.&lt;/p&gt;

&lt;p&gt;A better structure is to separate the character into behavioural groups.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core states
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;idle
listening
thinking
talking
success
error
sleeping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Emotional states
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;neutral
happy
excited
confused
concerned
sad
surprised
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Continuous controls
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lookX
lookY
talkIntensity
energy
progress
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  One-time reactions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;celebrate
wave
blink
notice
correct
incorrect
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The animator and developer should agree on this contract before integration begins.&lt;/p&gt;

&lt;p&gt;A small integration document can prevent many problems later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Property: emotion
Type: Enum
Values: neutral, happy, thinking, confused, error

Property: isTalking
Type: Boolean
Default: false

Property: lookX
Type: Number
Range: -1 to 1
Default: 0

Property: lookY
Type: Number
Range: -1 to 1
Default: 0

Property: celebrate
Type: Trigger
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common integration problems
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The mascot is not visible
&lt;/h3&gt;

&lt;p&gt;Check that the parent container has a defined height:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.mascotContainer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;480px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A canvas inside a container with no height may appear as if it failed to load.&lt;/p&gt;

&lt;h3&gt;
  
  
  The ViewModel properties are unavailable
&lt;/h3&gt;

&lt;p&gt;Confirm that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The artboard has a ViewModel assigned&lt;/li&gt;
&lt;li&gt;A default ViewModel instance exists&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;autoBind: true&lt;/code&gt; is enabled&lt;/li&gt;
&lt;li&gt;The property names exactly match the Rive file&lt;/li&gt;
&lt;li&gt;The correct artboard and State Machine are loading&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Property names are case-sensitive.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;isTalking
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is not the same as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;istalking
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The character animation restarts unexpectedly
&lt;/h3&gt;

&lt;p&gt;Keep the &lt;code&gt;useRive&lt;/code&gt; hook and the returned &lt;code&gt;RiveComponent&lt;/code&gt; together inside a dedicated wrapper component.&lt;/p&gt;

&lt;p&gt;Avoid frequently unmounting and remounting the canvas or changing its React key.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pointer tracking works on desktop but not mobile
&lt;/h3&gt;

&lt;p&gt;Use Pointer Events rather than mouse-only events.&lt;/p&gt;

&lt;p&gt;This works across mouse, pen, and touch input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;onPointerMove&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handlePointerMove&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, mobile devices do not have a persistent cursor. For mobile interfaces, consider controlling gaze using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Touch position&lt;/li&gt;
&lt;li&gt;Device orientation&lt;/li&gt;
&lt;li&gt;Face tracking&lt;/li&gt;
&lt;li&gt;UI element location&lt;/li&gt;
&lt;li&gt;App-provided &lt;code&gt;lookX&lt;/code&gt; and &lt;code&gt;lookY&lt;/code&gt; values&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not design a critical character behaviour that depends only on desktop hover.&lt;/p&gt;

&lt;h3&gt;
  
  
  The mascot keeps talking forever
&lt;/h3&gt;

&lt;p&gt;Do not connect talking to a permanent looping animation without application control.&lt;/p&gt;

&lt;p&gt;Use an explicit Boolean:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;setIsTalking&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then stop it when audio playback finishes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ended&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;setIsTalking&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For accurate speech animation, use viseme timing rather than a simple random mouth loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance recommendations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Keep Rive isolated in its own component
&lt;/h3&gt;

&lt;p&gt;This prevents unrelated React state changes from unnecessarily recreating the Rive canvas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoid unmounting the canvas repeatedly
&lt;/h3&gt;

&lt;p&gt;Show and hide the surrounding section when possible instead of constantly destroying and recreating the component.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep the &lt;code&gt;.riv&lt;/code&gt; file focused
&lt;/h3&gt;

&lt;p&gt;Remove unused assets, unnecessary paths, hidden artboards, and animations that are not required at runtime.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoid permanently active animations
&lt;/h3&gt;

&lt;p&gt;An idle state can contain occasional blinking and breathing without requiring every layer to animate continuously.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test on real devices
&lt;/h3&gt;

&lt;p&gt;A mascot that performs well on a desktop computer may behave differently on lower-powered mobile devices.&lt;/p&gt;

&lt;p&gt;Test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loading time&lt;/li&gt;
&lt;li&gt;Canvas resolution&lt;/li&gt;
&lt;li&gt;Memory usage&lt;/li&gt;
&lt;li&gt;Multiple mascot instances&lt;/li&gt;
&lt;li&gt;Touch interactions&lt;/li&gt;
&lt;li&gt;Long-running State Machines&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Accessibility considerations
&lt;/h2&gt;

&lt;p&gt;An animated mascot should support the interface, not become the only way to understand it.&lt;/p&gt;

&lt;p&gt;Make sure that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Important messages are also displayed as text&lt;/li&gt;
&lt;li&gt;Controls are keyboard accessible&lt;/li&gt;
&lt;li&gt;The mascot does not block form fields&lt;/li&gt;
&lt;li&gt;Fast flashing effects are avoided&lt;/li&gt;
&lt;li&gt;Sound does not autoplay unexpectedly&lt;/li&gt;
&lt;li&gt;Reduced-motion preferences are respected&lt;/li&gt;
&lt;li&gt;The product remains usable if the animation fails&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mascot can improve personality and guidance, but core product functionality should never depend entirely on animation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Taking the mascot further
&lt;/h2&gt;

&lt;p&gt;Once the basic integration is working, the same system can support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI assistant states&lt;/li&gt;
&lt;li&gt;Text-to-speech lip sync&lt;/li&gt;
&lt;li&gt;Viseme-based mouth animation&lt;/li&gt;
&lt;li&gt;Runtime theme colors&lt;/li&gt;
&lt;li&gt;Dynamic character names&lt;/li&gt;
&lt;li&gt;Different outfits or accessories&lt;/li&gt;
&lt;li&gt;Progress-based reactions&lt;/li&gt;
&lt;li&gt;User achievements&lt;/li&gt;
&lt;li&gt;Notification reactions&lt;/li&gt;
&lt;li&gt;Scroll-driven behaviour&lt;/li&gt;
&lt;li&gt;Multiple character personalities&lt;/li&gt;
&lt;li&gt;Context-aware emotional responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The strongest interactive mascots are designed as product systems from the beginning.&lt;/p&gt;

&lt;p&gt;Animation quality matters, but the runtime architecture, property naming, transitions, developer handoff, and application integration matter just as much.&lt;/p&gt;

&lt;h2&gt;
  
  
  Need an interactive mascot for your product?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://mascotengine.com/" rel="noopener noreferrer"&gt;Mascot Engine&lt;/a&gt; designs and builds production-ready interactive Rive mascots for AI products, SaaS platforms, mobile apps, and web experiences.&lt;/p&gt;

&lt;p&gt;The work can include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Character preparation and rigging&lt;/li&gt;
&lt;li&gt;Emotional animations&lt;/li&gt;
&lt;li&gt;Interactive State Machines&lt;/li&gt;
&lt;li&gt;Data Binding and ViewModels&lt;/li&gt;
&lt;li&gt;Pointer and touch interactions&lt;/li&gt;
&lt;li&gt;Mobile-ready gaze controls&lt;/li&gt;
&lt;li&gt;AI listening, thinking, and talking states&lt;/li&gt;
&lt;li&gt;Viseme lip sync&lt;/li&gt;
&lt;li&gt;Flutter, React Native, and web preparation&lt;/li&gt;
&lt;li&gt;Developer-ready input documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of delivering only a looping animation, Mascot Engine creates a character system that can connect to real product logic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mascotengine.com/contact/" rel="noopener noreferrer"&gt;Start an interactive mascot project with Mascot Engine&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Official resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://rive.app/docs/runtimes/react/react" rel="noopener noreferrer"&gt;Rive React runtime documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rive.app/docs/runtimes/react/data-binding" rel="noopener noreferrer"&gt;Rive React Data Binding documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rive.app/docs/runtimes/react/best-practices" rel="noopener noreferrer"&gt;Rive React best practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/app/api-reference/directives/use-client" rel="noopener noreferrer"&gt;Next.js Client Components documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;About the author&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Praneeth Kawya Thathsara is a Rive Animator and Interactive Product Designer specializing in production-ready mascot systems for AI, SaaS, mobile, and web products. He is the founder of &lt;a href="https://mascotengine.com/" rel="noopener noreferrer"&gt;Mascot Engine&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>nextjs</category>
      <category>webdev</category>
      <category>animation</category>
    </item>
    <item>
      <title>Your SaaS Mascot Should Do More Than Just Sit There</title>
      <dc:creator>Mascot Engine</dc:creator>
      <pubDate>Mon, 13 Jul 2026 00:11:45 +0000</pubDate>
      <link>https://dev.to/mascotengine/your-saas-mascot-should-do-more-than-just-sit-there-38oe</link>
      <guid>https://dev.to/mascotengine/your-saas-mascot-should-do-more-than-just-sit-there-38oe</guid>
      <description>&lt;p&gt;Interactive Rive mascots can react, think, talk, and connect to real AI, SaaS, web, and mobile products.&lt;/p&gt;

&lt;h1&gt;
  
  
  Your SaaS Mascot Should Do More Than Just Sit There 👀
&lt;/h1&gt;

&lt;p&gt;A lot of products have mascots.&lt;/p&gt;

&lt;p&gt;They look great on landing pages.&lt;/p&gt;

&lt;p&gt;Maybe they wave.&lt;/p&gt;

&lt;p&gt;Maybe they blink.&lt;/p&gt;

&lt;p&gt;Maybe there is a small looping animation.&lt;/p&gt;

&lt;p&gt;And that's it.&lt;/p&gt;

&lt;p&gt;But I think a product mascot can do much more.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What if your mascot actually knew what was happening inside your&lt;br&gt;
product?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's the idea I've been exploring with &lt;strong&gt;Mascot Engine&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I don't just want to animate characters.&lt;/p&gt;

&lt;p&gt;I want to build &lt;strong&gt;interactive mascot systems that connect to real&lt;br&gt;
products&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  From a mascot animation to a product system
&lt;/h2&gt;

&lt;p&gt;Imagine you're building an AI app.&lt;/p&gt;

&lt;p&gt;A user opens the app.&lt;/p&gt;

&lt;p&gt;The mascot is &lt;strong&gt;idle&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The user sends a message.&lt;/p&gt;

&lt;p&gt;The mascot starts &lt;strong&gt;thinking&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The AI begins responding.&lt;/p&gt;

&lt;p&gt;The mascot switches to &lt;strong&gt;talking&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The task completes.&lt;/p&gt;

&lt;p&gt;The mascot &lt;strong&gt;celebrates&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Something goes wrong?&lt;/p&gt;

&lt;p&gt;The mascot reacts to the &lt;strong&gt;error&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The flow could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Action
    ↓
Product State
    ↓
Runtime Input
    ↓
Rive State Machine
    ↓
Mascot Reaction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't a video.&lt;/p&gt;

&lt;p&gt;It isn't a GIF.&lt;/p&gt;

&lt;p&gt;It isn't a pre-rendered animation playing randomly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The product controls the mascot at runtime.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's where things become interesting.&lt;/p&gt;




&lt;h2&gt;
  
  
  A mascot can understand product states
&lt;/h2&gt;

&lt;p&gt;Well... not literally understand them 😄&lt;/p&gt;

&lt;p&gt;The application still owns the logic.&lt;/p&gt;

&lt;p&gt;But we can expose a small runtime contract from the Rive file.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;emotion = 2
isTalking = true
lookX = 40
lookY = -10
celebrate = trigger
error = false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The developer controls these values from the application.&lt;/p&gt;

&lt;p&gt;The Rive State Machine handles the character behavior.&lt;/p&gt;

&lt;p&gt;The application controls &lt;strong&gt;what happened&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The mascot system controls &lt;strong&gt;how the character reacts&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I really like this separation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I use Rive for interactive mascots
&lt;/h2&gt;

&lt;p&gt;Traditional animation tools are great for videos and motion design.&lt;/p&gt;

&lt;p&gt;But product animation has different requirements.&lt;/p&gt;

&lt;p&gt;The character needs to react to application events.&lt;/p&gt;

&lt;p&gt;The animation may need runtime values.&lt;/p&gt;

&lt;p&gt;Developers may need to control emotions.&lt;/p&gt;

&lt;p&gt;An AI assistant may need lip sync.&lt;/p&gt;

&lt;p&gt;A character's eyes may need to follow a pointer or touch position.&lt;/p&gt;

&lt;p&gt;This is where Rive becomes interesting.&lt;/p&gt;

&lt;p&gt;With Rive, I can build systems using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  State Machines&lt;/li&gt;
&lt;li&gt;  Data Binding&lt;/li&gt;
&lt;li&gt;  Number inputs&lt;/li&gt;
&lt;li&gt;  Boolean inputs&lt;/li&gt;
&lt;li&gt;  Triggers&lt;/li&gt;
&lt;li&gt;  Runtime properties&lt;/li&gt;
&lt;li&gt;  Nested artboards&lt;/li&gt;
&lt;li&gt;  Interactive vector animation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of delivering:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mascot-animation.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I can deliver something closer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mascot.riv

State Machine: MascotState

Inputs:
- emotion
- isTalking
- lookX
- lookY
- celebrate
- error
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the mascot is part of the product.&lt;/p&gt;

&lt;p&gt;Not just decoration.&lt;/p&gt;




&lt;h2&gt;
  
  
  AI products make mascots much more interesting
&lt;/h2&gt;

&lt;p&gt;AI apps are one of my favorite use cases for this.&lt;/p&gt;

&lt;p&gt;Most AI interfaces currently look similar.&lt;/p&gt;

&lt;p&gt;You have an input, a send button, a loading indicator, and a response.&lt;/p&gt;

&lt;p&gt;It works.&lt;/p&gt;

&lt;p&gt;But sometimes the experience can feel a little lifeless.&lt;/p&gt;

&lt;p&gt;Now imagine an AI character.&lt;/p&gt;

&lt;p&gt;When you're speaking, it &lt;strong&gt;listens&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When the model is processing, it &lt;strong&gt;thinks&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When TTS starts, it &lt;strong&gt;talks&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Its mouth reacts using &lt;strong&gt;viseme-based lip sync&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Its eyes can move using runtime gaze values.&lt;/p&gt;

&lt;p&gt;The product can change its emotion based on the current experience.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Listening
    ↓
Thinking
    ↓
Answering
    ↓
Talking
    ↓
Idle
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is that these states aren't random.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They can be connected to actual product events.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  TTS and viseme lip sync
&lt;/h2&gt;

&lt;p&gt;This is another area I've been exploring.&lt;/p&gt;

&lt;p&gt;If an AI assistant uses Text-to-Speech, the mascot shouldn't just play a&lt;br&gt;
generic talking loop.&lt;/p&gt;

&lt;p&gt;We can create different mouth shapes.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REST
A
E
I
O
U
MBP
FV
L
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application or TTS pipeline provides the current viseme value.&lt;/p&gt;

&lt;p&gt;The mascot reacts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TTS Audio
    ↓
Viseme Data
    ↓
Runtime Value
    ↓
Rive Mouth Shape
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is a character that feels more connected to the voice.&lt;/p&gt;

&lt;p&gt;For AI tutors, assistants, learning apps, and companion products, this&lt;br&gt;
can completely change the personality of the experience.&lt;/p&gt;


&lt;h2&gt;
  
  
  Gaze should also be controlled by the product
&lt;/h2&gt;

&lt;p&gt;Pointer tracking is fun on the web.&lt;/p&gt;

&lt;p&gt;The mascot can follow your mouse.&lt;/p&gt;

&lt;p&gt;But what happens on mobile?&lt;/p&gt;

&lt;p&gt;There is no mouse cursor.&lt;/p&gt;

&lt;p&gt;That's why I prefer exposing runtime gaze values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lookX = -100 to 100
lookY = -100 to 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Flutter, React Native, React, or web application can control these&lt;br&gt;
values.&lt;/p&gt;

&lt;p&gt;The mascot can look at touch positions, UI elements, notifications,&lt;br&gt;
buttons, user interactions, or camera-based face tracking.&lt;/p&gt;

&lt;p&gt;The Rive animation handles the visual movement.&lt;/p&gt;

&lt;p&gt;The application provides the data.&lt;/p&gt;


&lt;h2&gt;
  
  
  A beautiful Rive file isn't enough
&lt;/h2&gt;

&lt;p&gt;Working with developers taught me something important.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A beautiful animation can still be difficult to integrate.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imagine receiving a Rive file with inputs like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input 1
Bool 2
Trigger
New Number
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;😅&lt;/p&gt;

&lt;p&gt;Now the developer has to guess everything.&lt;/p&gt;

&lt;p&gt;I try to think about the runtime structure while building the mascot.&lt;/p&gt;

&lt;p&gt;Inputs should be predictable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;emotion
ageMode
isTalking
lookX
lookY
Celebrating
Error
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The developer shouldn't need to reverse-engineer the animation.&lt;/p&gt;

&lt;p&gt;That's also why I've started building &lt;strong&gt;Mascot Engine Developer Docs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The goal is to create a practical integration reference for Web,&lt;br&gt;
JavaScript, React, Flutter, React Native, State Machines, Data Binding,&lt;br&gt;
pointer interactions, TTS, viseme lip sync, and runtime inputs.&lt;/p&gt;

&lt;p&gt;Because delivering the &lt;code&gt;.riv&lt;/code&gt; file is only part of the job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The mascot needs to work inside the real product.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Vibe coders are welcome too 😄
&lt;/h2&gt;

&lt;p&gt;Maybe you're using AI coding tools.&lt;/p&gt;

&lt;p&gt;Maybe you're building a SaaS alone.&lt;/p&gt;

&lt;p&gt;Maybe you're an indie hacker.&lt;/p&gt;

&lt;p&gt;Maybe you're shipping a strange app at 3 AM because the idea wouldn't&lt;br&gt;
leave your head 😄&lt;/p&gt;

&lt;p&gt;That's fine.&lt;/p&gt;

&lt;p&gt;If you can explain your product flow, I can help think about the mascot&lt;br&gt;
behavior.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User opens app
→ Mascot wakes up

User starts typing
→ Mascot watches the input

AI is processing
→ Mascot thinks

AI starts TTS
→ Mascot talks

Task completed
→ Mascot celebrates

API error
→ Mascot reacts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't need to know everything about Rive State Machines.&lt;/p&gt;

&lt;p&gt;Tell me what happens inside your product.&lt;/p&gt;

&lt;p&gt;We can turn those events into character behavior.&lt;/p&gt;




&lt;h2&gt;
  
  
  Mascots shouldn't be random decoration
&lt;/h2&gt;

&lt;p&gt;I don't think every product needs a mascot.&lt;/p&gt;

&lt;p&gt;The mascot should have a purpose.&lt;/p&gt;

&lt;p&gt;Maybe it guides the user.&lt;/p&gt;

&lt;p&gt;Maybe it represents the AI.&lt;/p&gt;

&lt;p&gt;Maybe it reacts to progress.&lt;/p&gt;

&lt;p&gt;Maybe it makes an educational product friendlier.&lt;/p&gt;

&lt;p&gt;Maybe it gives a SaaS product a recognizable personality.&lt;/p&gt;

&lt;p&gt;The question I like asking is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What does the mascot know about the current product state?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the answer is &lt;strong&gt;nothing&lt;/strong&gt;, it's probably just decoration.&lt;/p&gt;

&lt;p&gt;If the product can control the character, that's where we can build&lt;br&gt;
something interesting.&lt;/p&gt;


&lt;h2&gt;
  
  
  I'm opening a few discounted Mascot Engine slots 👀
&lt;/h2&gt;

&lt;p&gt;I'm currently opening a limited number of project slots for AI, SaaS,&lt;br&gt;
web, and mobile products.&lt;/p&gt;
&lt;h3&gt;
  
  
  Quick Mascot --- \$350
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  4 animated states&lt;/li&gt;
&lt;li&gt;  Rive mascot animation&lt;/li&gt;
&lt;li&gt;  Basic State Machine&lt;/li&gt;
&lt;li&gt;  Production-ready &lt;code&gt;.riv&lt;/code&gt; delivery&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Interactive Mascot --- \$750
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  7 animated states&lt;/li&gt;
&lt;li&gt;  Runtime controls&lt;/li&gt;
&lt;li&gt;  Interactive State Machine&lt;/li&gt;
&lt;li&gt;  Developer-ready input structure&lt;/li&gt;
&lt;li&gt;  Rive source delivery&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  AI Mascot --- \$1,200+
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  AI assistant mascot system&lt;/li&gt;
&lt;li&gt;  TTS-ready animation&lt;/li&gt;
&lt;li&gt;  Viseme-based lip sync&lt;/li&gt;
&lt;li&gt;  Runtime gaze controls&lt;/li&gt;
&lt;li&gt;  Emotion states&lt;/li&gt;
&lt;li&gt;  Developer integration support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Built for real products using Rive.&lt;/p&gt;


&lt;h2&gt;
  
  
  Building an AI app, SaaS, web app, or mobile product?
&lt;/h2&gt;

&lt;p&gt;Send me your product.&lt;/p&gt;

&lt;p&gt;I'll take a look.&lt;/p&gt;

&lt;p&gt;If I see an interesting way an interactive mascot could fit into the&lt;br&gt;
experience, I'll tell you.&lt;/p&gt;

&lt;p&gt;No complicated animation brief needed.&lt;/p&gt;

&lt;p&gt;You can simply send me:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Product link:
What the product does:
Framework:
What the mascot should react to:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visit:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mascotengine.com" rel="noopener noreferrer"&gt;https://mascotengine.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm &lt;strong&gt;Praneeth Kawya Thathsara&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I'm a Rive animator and interactive product designer building &lt;strong&gt;Mascot&lt;br&gt;
Engine&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I don't just want to make mascots move.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I want to connect them to products.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Make them react.&lt;/p&gt;

&lt;p&gt;Make them think.&lt;/p&gt;

&lt;p&gt;Make them talk.&lt;/p&gt;

&lt;p&gt;Make the product feel a little more alive. 👀&lt;/p&gt;




&lt;p&gt;If you're building something interesting, feel free to reach out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vibe coders welcome too 😄⚙️&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>rive</category>
      <category>webdev</category>
      <category>ai</category>
      <category>saas</category>
    </item>
    <item>
      <title>Stop Shipping Static Mascots: Building Interactive Mascot Systems for Modern Apps</title>
      <dc:creator>Mascot Engine</dc:creator>
      <pubDate>Mon, 20 Apr 2026 15:37:12 +0000</pubDate>
      <link>https://dev.to/mascotengine/stop-shipping-static-mascots-building-interactive-mascot-systems-for-modern-apps-2a2f</link>
      <guid>https://dev.to/mascotengine/stop-shipping-static-mascots-building-interactive-mascot-systems-for-modern-apps-2a2f</guid>
      <description>&lt;h2&gt;
  
  
  Stop Shipping Static Mascots: Building Interactive Mascot Systems for Modern Apps
&lt;/h2&gt;

&lt;p&gt;Most product teams treat mascots as visual assets. A nice illustration placed in onboarding, empty states, or marketing pages.&lt;/p&gt;

&lt;p&gt;But in production environments, static mascots quickly become invisible.&lt;/p&gt;

&lt;p&gt;They don’t react.&lt;br&gt;&lt;br&gt;
They don’t guide.&lt;br&gt;&lt;br&gt;
They don’t contribute to the product experience.&lt;/p&gt;

&lt;p&gt;This article introduces a different approach: treating mascots as &lt;strong&gt;interactive systems&lt;/strong&gt;, not visuals.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem with Static Mascots
&lt;/h2&gt;

&lt;p&gt;In real-world applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users ignore static illustrations after the first view&lt;/li&gt;
&lt;li&gt;They don’t communicate system state&lt;/li&gt;
&lt;li&gt;They don’t assist onboarding or flows&lt;/li&gt;
&lt;li&gt;They add visual weight without functional value&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For product designers and developers, this creates a gap:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You have a character, but it does nothing.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Shift: Mascots as Systems
&lt;/h2&gt;

&lt;p&gt;Instead of thinking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“Where do we place the mascot?”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start thinking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“What does the mascot do inside the product?”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An interactive mascot system should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React to user actions (clicks, taps, gestures)&lt;/li&gt;
&lt;li&gt;Reflect real-time states (loading, success, error)&lt;/li&gt;
&lt;li&gt;Guide onboarding flows&lt;/li&gt;
&lt;li&gt;Integrate with product logic&lt;/li&gt;
&lt;li&gt;Optionally connect with AI for dynamic responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This transforms the mascot from decoration into a &lt;strong&gt;UI component with behavior&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Core Architecture of a Mascot System
&lt;/h2&gt;

&lt;p&gt;A production-ready mascot system typically includes:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. State Machine
&lt;/h3&gt;

&lt;p&gt;The mascot is driven by states such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Idle&lt;/li&gt;
&lt;li&gt;Thinking&lt;/li&gt;
&lt;li&gt;Talking&lt;/li&gt;
&lt;li&gt;Success&lt;/li&gt;
&lt;li&gt;Error&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Transitions between these states are triggered by events.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Event Layer
&lt;/h3&gt;

&lt;p&gt;Events come from your application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User clicks&lt;/li&gt;
&lt;li&gt;API responses&lt;/li&gt;
&lt;li&gt;Navigation changes&lt;/li&gt;
&lt;li&gt;Form submissions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These events control mascot behavior.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Animation Engine
&lt;/h3&gt;

&lt;p&gt;This is where tools like Rive become critical.&lt;/p&gt;

&lt;p&gt;Rive allows you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define state machines visually&lt;/li&gt;
&lt;li&gt;Control animations via inputs&lt;/li&gt;
&lt;li&gt;Sync UI events with animation transitions&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. Integration Layer
&lt;/h3&gt;

&lt;p&gt;Your frontend (Flutter, Web, React Native) connects to the mascot system and sends events.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example: Flutter Integration
&lt;/h2&gt;

&lt;p&gt;Below is a simplified example of controlling a mascot using Rive in a Flutter app.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import 'package:flutter/material.dart';&lt;br&gt;
import 'package:rive/rive.dart';

&lt;p&gt;class MascotWidget extends StatefulWidget {&lt;br&gt;
  @override&lt;br&gt;
  _MascotWidgetState createState() =&amp;gt; _MascotWidgetState();&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;class _MascotWidgetState extends State&amp;lt;MascotWidget&amp;gt; {&lt;br&gt;
  late StateMachineController _controller;&lt;br&gt;
  SMIInput&amp;lt;bool&amp;gt;? isHappy;&lt;br&gt;
  SMIInput&amp;lt;bool&amp;gt;? isError;&lt;/p&gt;

&lt;p&gt;void _onRiveInit(Artboard artboard) {&lt;br&gt;
    _controller = StateMachineController.fromArtboard(&lt;br&gt;
      artboard,&lt;br&gt;
      'MascotStateMachine',&lt;br&gt;
    )!;&lt;br&gt;
    artboard.addController(_controller);&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;isHappy = _controller.findInput&amp;amp;lt;bool&amp;amp;gt;('isHappy');
isError = _controller.findInput&amp;amp;lt;bool&amp;amp;gt;('isError');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;void onSuccess() {&lt;br&gt;
    isHappy?.value = true;&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;void onError() {&lt;br&gt;
    isError?.value = true;&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;@override&lt;br&gt;
  Widget build(BuildContext context) {&lt;br&gt;
    return Column(&lt;br&gt;
      children: [&lt;br&gt;
        SizedBox(&lt;br&gt;
          height: 200,&lt;br&gt;
          child: RiveAnimation.asset(&lt;br&gt;
            'assets/mascot.riv',&lt;br&gt;
            onInit: _onRiveInit,&lt;br&gt;
          ),&lt;br&gt;
        ),&lt;br&gt;
        ElevatedButton(&lt;br&gt;
          onPressed: onSuccess,&lt;br&gt;
          child: Text('Trigger Success'),&lt;br&gt;
        ),&lt;br&gt;
        ElevatedButton(&lt;br&gt;
          onPressed: onError,&lt;br&gt;
          child: Text('Trigger Error'),&lt;br&gt;
        ),&lt;br&gt;
      ],&lt;br&gt;
    );&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  What’s happening here:&lt;br&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The mascot is driven by a state machine&lt;/li&gt;
&lt;li&gt;UI actions trigger state changes&lt;/li&gt;
&lt;li&gt;The mascot visually reflects system feedback&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not animation playback.&lt;br&gt;&lt;br&gt;
This is &lt;strong&gt;behavior-driven UI&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real Product Use Cases
&lt;/h2&gt;

&lt;p&gt;Interactive mascots can be used across real applications:&lt;/p&gt;

&lt;h3&gt;
  
  
  Onboarding
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Guide users through steps&lt;/li&gt;
&lt;li&gt;React when users complete actions&lt;/li&gt;
&lt;li&gt;Provide contextual hints&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  System Feedback
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Show loading (thinking state)&lt;/li&gt;
&lt;li&gt;Confirm success (happy state)&lt;/li&gt;
&lt;li&gt;Alert errors (error state)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  AI Interfaces
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Act as a conversational UI layer&lt;/li&gt;
&lt;li&gt;Sync lip movements with speech&lt;/li&gt;
&lt;li&gt;Represent system intelligence visually&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Engagement Layer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;React to hover/click events&lt;/li&gt;
&lt;li&gt;Create micro-interactions that increase retention&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why This Matters for Product Teams
&lt;/h2&gt;

&lt;p&gt;For designers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You design behavior, not just visuals&lt;/li&gt;
&lt;li&gt;You define how the mascot responds to real interactions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For developers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You integrate a controllable UI component&lt;/li&gt;
&lt;li&gt;You connect animation logic with product logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For founders:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You differentiate your product experience&lt;/li&gt;
&lt;li&gt;You create a more engaging and memorable interface&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common Mistakes to Avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Treating the mascot as a one-time animation&lt;/li&gt;
&lt;li&gt;Over-animating without purpose&lt;/li&gt;
&lt;li&gt;Not connecting mascot behavior to real system events&lt;/li&gt;
&lt;li&gt;Ignoring performance considerations in production&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A mascot should not be noisy.&lt;br&gt;&lt;br&gt;
It should be &lt;strong&gt;precise, responsive, and meaningful&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Static mascots belong to marketing pages.&lt;/p&gt;

&lt;p&gt;Interactive mascots belong inside products.&lt;/p&gt;

&lt;p&gt;If your application already has a mascot, the real question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What does it actually do?&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Need Help Building a Production-Ready Mascot System?
&lt;/h2&gt;

&lt;p&gt;If you’re working on a real product and want to implement interactive mascots properly — from design to animation to integration — you can reach out:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mascotengine.com/" rel="noopener noreferrer"&gt;https://mascotengine.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;call&lt;br&gt;&lt;br&gt;
WhatsApp&lt;br&gt;&lt;br&gt;
+94717000999  &lt;/p&gt;

&lt;p&gt;Email&lt;br&gt;&lt;br&gt;
&lt;a href="mailto:mascotengine@gmail.com"&gt;mascotengine@gmail.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>mascot</category>
    </item>
  </channel>
</rss>
