npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@khaveeai/react

v0.2.6

Published

React components and hooks for VRM AI avatars

Readme

@khaveeai/react

🎭 React components and hooks for intelligent VRM AI avatars with advanced animation and lip synchronization.

npm version License: MIT

Features

  • 🤖 Smart VRM Avatars - 3D character rendering with Three.js/R3F
  • 🎤 Real-time Voice Chat - OpenAI Realtime API integration with WebRTC
  • 👄 Automatic Lip Sync - MFCC-based phoneme detection works automatically with OpenAI Realtime
  • 💬 Talking Animations - Automatic gesture animations during AI speech
  • 🎬 Animation System - FBX animation loading with automatic Mixamo remapping
  • 😊 Facial Expressions - Smooth VRM expression control with transitions
  • 👁️ Natural Blinking - Randomized blinking animations for lifelike characters
  • 🔊 Audio Lip Sync - File-based lip sync analysis with MFCC and DTW algorithms
  • 🛠️ Function Calling - OpenAI tool integration for RAG and custom functions
  • High Performance - Optimized rendering with automatic cleanup

Installation

# Core SDK
npm install @khaveeai/react @khaveeai/core

# Peer dependencies
npm install react @react-three/fiber @react-three/drei

# Optional: Provider packages for LLM/TTS/Realtime features
npm install @khaveeai/providers-mock             # Development/testing
npm install @khaveeai/providers-openai           # OpenAI LLM/TTS
npm install @khaveeai/providers-openai-realtime  # OpenAI Realtime API
npm install @khaveeai/providers-azure            # Azure Cognitive Services

Quick Start

Basic VRM Avatar

import { Canvas } from '@react-three/fiber';
import { KhaveeProvider, VRMAvatar } from '@khaveeai/react';

function App() {
  return (
    <KhaveeProvider>
      <Canvas>
        <ambientLight intensity={0.5} />
        <directionalLight position={[10, 10, 5]} />
        
        <VRMAvatar 
          src="/models/character.vrm"
          position={[0, -1, 0]}
        />
      </Canvas>
    </KhaveeProvider>
  );
}

Animation System

import { VRMAvatar, useVRMAnimations } from '@khaveeai/react';

function AnimatedAvatar() {
  const { animate } = useVRMAnimations();
  
  // Define animations (just provide URLs!)
  const animations = {
    idle: '/animations/idle.fbx',           // Auto-plays
    dance: '/animations/dance.fbx',
    wave: '/animations/wave.fbx'
  };
  
  return (
    <>
      <VRMAvatar 
        src="/models/character.vrm"
        animations={animations}  // SDK handles everything!
      />
      
      <button onClick={() => animate('dance')}>💃 Dance</button>
      <button onClick={() => animate('wave')}>👋 Wave</button>
    </>
  );
}

Facial Expressions

import { VRMAvatar, useVRMExpressions } from '@khaveeai/react';

function ExpressiveAvatar() {
  const { setExpression } = useVRMExpressions();
  
  return (
    <>
      <VRMAvatar src="/models/character.vrm" />
      
      <button onClick={() => setExpression('happy', 1)}>😊 Happy</button>
      <button onClick={() => setExpression('sad', 1)}>😢 Sad</button>
    </>
  );
}

Audio-Based Lip Sync

import { useAudioLipSync } from '@khaveeai/react';

function LipSyncDemo() {
  const { analyzeLipSync, stopLipSync, isAnalyzing, currentPhoneme } = useAudioLipSync();
  
  return (
    <div>
      <button 
        onClick={() => analyzeLipSync('/audio/speech.wav', {
          sensitivity: 0.8,
          intensityMultiplier: 3.0
        })}
        disabled={isAnalyzing}
      >
        {isAnalyzing ? 'Analyzing...' : 'Start Lip Sync'}
      </button>
      
      <button onClick={stopLipSync}>Stop</button>
      
      {currentPhoneme && (
        <div>
          <p>Phoneme: {currentPhoneme.phoneme}</p>
          <p>Intensity: {(currentPhoneme.intensity * 100).toFixed(1)}%</p>
        </div>
      )}
    </div>
  );
}

API Reference

Components

<KhaveeProvider>

Root provider that manages VRM state and optional provider configuration.

interface KhaveeConfig {
  llm?: LLMProvider;           // Optional: Chat AI provider
  tts?: TTSProvider;           // Optional: Text-to-speech provider  
  realtime?: RealtimeProvider; // Optional: Real-time voice chat provider
  tools?: RealtimeTool[];      // Optional: Custom functions
}

<KhaveeProvider config={khaveeConfig}>  {/* config is optional */}
  {children}
</KhaveeProvider>

<VRMAvatar>

3D VRM character component with automatic animation, lip sync, and talking animations.

interface VRMAvatarProps {
  src: string;                    // Path to .vrm file
  position?: [number, number, number];
  rotation?: [number, number, number];  
  scale?: [number, number, number];
  animations?: AnimationConfig;   // FBX animation URLs
  enableBlinking?: boolean;       // Enable natural blinking (default: true)
  enableTalkingAnimations?: boolean; // Enable gestures during AI speech (default: true)
}

Animation Config:

interface AnimationConfig {
  [name: string]: string;  // Animation name -> FBX file URL
}

// Example
const animations = {
  idle: '/animations/breathing.fbx',     // Auto-plays on load
  walk: '/animations/walking.fbx',
  dance: '/animations/dancing.fbx',
  talking: '/animations/talking.fbx',    // Played during AI speech
  gesture1: '/animations/gesture.fbx'    // Also played during speech
};
// Note: Animations with 'talk', 'gesture', or 'speak' in the name
// are automatically played randomly when chatStatus === 'speaking'

Hooks

useRealtime()

Real-time voice chat with OpenAI Realtime API.

const {
  // Connection
  isConnected: boolean,
  connect: () => Promise<void>,
  disconnect: () => Promise<void>,
  
  // Chat state  
  chatStatus: 'stopped' | 'ready' | 'listening' | 'speaking' | 'thinking',
  conversation: Conversation[],
  currentVolume: number,
  isThinking: boolean,
  
  // Lip sync (automatic with VRMAvatar)
  currentPhoneme: PhonemeData | null,
  startAutoLipSync: () => Promise<void>,
  stopAutoLipSync: () => void,
  
  // Actions
  sendMessage: (text: string) => Promise<void>,
  interrupt: () => void,
  registerFunction: (tool: RealtimeTool) => void
} = useRealtime();

useAudioLipSync()

Analyze audio files for phoneme detection and lip sync.

const {
  analyzeLipSync: (audioUrl: string, options?: {
    sensitivity?: number;         // 0.1 to 1.0
    smoothing?: number;          // 0.1 to 1.0  
    intensityMultiplier?: number; // 1.0 to 5.0
    minIntensity?: number;       // 0.0 to 1.0
    onPhonemeChange?: (phoneme: PhonemeData) => void;
  }) => Promise<void>,
  stopLipSync: () => void,
  isAnalyzing: boolean,
  mouthState: MouthState,        // Current mouth state
  currentPhoneme: PhonemeData | null,
  audioElement: HTMLAudioElement | null
} = useAudioLipSync();

useVRMExpressions()

Control VRM facial expressions with smooth transitions.

const {
  expressions: Record<string, number>,
  setExpression: (name: string, value: number) => void,
  resetExpressions: () => void,
  setMultipleExpressions: (expressions: Record<string, number>) => void
} = useVRMExpressions();

useVRMAnimations()

Control VRM body animations with smooth transitions.

const {
  currentAnimation: string | null,
  animate: (name: string) => void,       // Play animation by name
  stopAnimation: () => void,             // Stop current animation
  availableAnimations: string[]          // List of loaded animations
} = useVRMAnimations();

useVRM()

Access the raw VRM model instance.

const vrm: VRM | null = useVRM();

useKhavee()

Access the complete SDK context (advanced usage).

const {
  config,              // Optional provider config
  vrm,                // VRM instance
  setVrm,             // Set VRM instance
  expressions,        // Current expressions
  setExpression,      // Set single expression
  resetExpressions,   // Reset all expressions
  setMultipleExpressions, // Set multiple expressions
  currentAnimation,   // Current animation name
  animate,           // Play animation
  stopAnimation,     // Stop animation
  availableAnimations, // Available animations
  realtimeProvider   // Realtime provider instance
} = useKhavee();

Advanced Usage

Automatic Lip Sync with OpenAI Realtime

When using VRMAvatar with OpenAIRealtimeProvider, lip sync happens automatically! The avatar's mouth movements are synchronized with the AI's speech using MFCC-based phoneme detection:

import { KhaveeProvider, VRMAvatar } from '@khaveeai/react';
import { OpenAIRealtimeProvider } from '@khaveeai/providers-openai-realtime';

const realtime = new OpenAIRealtimeProvider({
  apiKey: process.env.NEXT_PUBLIC_OPENAI_API_KEY!,
  voice: 'coral',
});

function App() {
  return (
    <KhaveeProvider config={{ realtime }}>  
      <Canvas>
        {/* Lip sync happens automatically when AI speaks! */}
        <VRMAvatar 
          src="/models/avatar.vrm"
          enableBlinking={true}              // Natural blinking
          enableTalkingAnimations={true}     // Gestures during speech
        />
      </Canvas>
    </KhaveeProvider>
  );
}

The system automatically:

  • ✅ Analyzes AI voice audio in real-time
  • ✅ Detects phonemes (aa, ee, ih, ou, oh)
  • ✅ Applies mouth shapes to VRM expressions
  • ✅ Plays talking/gesture animations randomly
  • ✅ Resets mouth to neutral when AI stops speaking

Audio File Lip Sync

For pre-recorded audio files, use the useAudioLipSync hook with advanced MFCC (Mel-Frequency Cepstral Coefficients) analysis and Dynamic Time Warping:

import { useAudioLipSync } from '@khaveeai/react';

function AdvancedLipSync() {
  const { analyzeLipSync, currentPhoneme, mouthState } = useAudioLipSync();
  
  const startAnalysis = () => {
    analyzeLipSync('/audio/speech.wav', {
      sensitivity: 0.8,           // Higher = more sensitive
      intensityMultiplier: 3.0,   // Boost mouth movement
      minIntensity: 0.3,          // Minimum threshold
      onPhonemeChange: (phoneme) => {
        console.log('Detected:', phoneme.phoneme, phoneme.intensity);
      }
    });
  };
  
  return (
    <div>
      <button onClick={startAnalysis}>Analyze Audio</button>
      
      {/* Real-time mouth state display */}
      <div>
        <h3>Mouth State:</h3>
        {Object.entries(mouthState || {}).map(([viseme, value]) => (
          <div key={viseme}>
            {viseme}: {(value * 100).toFixed(1)}%
            <div style={{ 
              width: `${value * 100}%`, 
              height: '20px', 
              backgroundColor: '#3b82f6' 
            }} />
          </div>
        ))}
      </div>
    </div>
  );
}

Custom Expression Presets

import { useVRMExpressions } from '@khaveeai/react';

function EmotionalPresets() {
  const { setMultipleExpressions, resetExpressions } = useVRMExpressions();
  
  const emotions = {
    happy: { happy: 0.9, relaxed: 0.3 },
    sad: { sad: 0.8, relaxed: 0.2 },
    surprised: { surprised: 0.9, aa: 0.4 },
    confused: { confused: 0.7, worried: 0.3 },
    excited: { happy: 0.8, surprised: 0.6 },
  };
  
  return (
    <div>
      {Object.entries(emotions).map(([name, expression]) => (
        <button 
          key={name}
          onClick={() => setMultipleExpressions(expression)}
        >
          {name}
        </button>
      ))}
      <button onClick={resetExpressions}>Reset</button>
    </div>
  );
}

Animation Sequences

import { useVRMAnimations } from '@khaveeai/react';

function AnimationSequence() {
  const { animate, currentAnimation } = useVRMAnimations();
  
  const playSequence = async () => {
    animate('walk');
    await new Promise(resolve => setTimeout(resolve, 3000));
    
    animate('dance');
    await new Promise(resolve => setTimeout(resolve, 5000));
    
    animate('idle');
  };
  
  return (
    <div>
      <p>Current: {currentAnimation}</p>
      <button onClick={playSequence}>Play Sequence</button>
    </div>
  );
}

Providers

OpenAI Realtime Provider

import { OpenAIRealtimeProvider } from '@khaveeai/providers-openai-realtime';

const provider = new OpenAIRealtimeProvider({
  apiKey: string,                    // OpenAI API key (required)
  model?: string,                    // Model name (default: 'gpt-4o-realtime-preview-2025-06-03')
  voice?: 'alloy' | 'coral' | 'echo' | 'sage' | 'shimmer', // Voice selection
  instructions?: string,             // System prompt
  temperature?: number,              // Response randomness (0-1)
  tools?: RealtimeTool[],           // Custom functions for RAG, etc.
  language?: string,                // Response language code
  turnServers?: RTCIceServer[]      // Custom TURN servers for WebRTC
});

// Lip sync is automatic when used with VRMAvatar!

Mock Providers (Development)

import { MockLLM, MockTTS } from '@khaveeai/providers-mock';

const mockConfig = {
  llm: new MockLLM(),     // Simulated AI responses
  tts: new MockTTS(),     // Simulated voice synthesis
  tools: []
};

Examples

Complete VRM Character App

import React from 'react';
import { Canvas } from '@react-three/fiber';
import { Environment, OrbitControls } from '@react-three/drei';
import { 
  KhaveeProvider, 
  VRMAvatar, 
  useRealtime,
  useAudioLipSync,
  useVRMExpressions,
  useVRMAnimations
} from '@khaveeai/react';
import { OpenAIRealtimeProvider } from '@khaveeai/providers-openai-realtime';

const realtimeProvider = new OpenAIRealtimeProvider({
  apiKey: process.env.REACT_APP_OPENAI_API_KEY,
  voice: 'shimmer',
  instructions: 'You are a friendly AI assistant.',
});

function ControlPanel() {
  const { isConnected, connect, disconnect, conversation } = useRealtime();
  const { analyzeLipSync, stopLipSync, isAnalyzing, currentPhoneme } = useAudioLipSync();
  const { setExpression, resetExpressions } = useVRMExpressions();
  const { animate, currentAnimation } = useVRMAnimations();
  
  return (
    <div className="controls">
      {/* Realtime Voice Chat */}
      <div>
        <h3>Voice Chat</h3>
        <button onClick={isConnected ? disconnect : connect}>
          {isConnected ? '🔴 Disconnect' : '🎤 Connect'}
        </button>
      </div>
      
      {/* Lip Sync Controls */}
      <div>
        <h3>Lip Sync</h3>
        <button 
          onClick={() => analyzeLipSync('/audio/sample.wav')}
          disabled={isAnalyzing}
        >
          {isAnalyzing ? 'Analyzing...' : 'Test Lip Sync'}
        </button>
        <button onClick={stopLipSync}>Stop</button>
        {currentPhoneme && (
          <p>Phoneme: {currentPhoneme.phoneme} ({currentPhoneme.intensity.toFixed(2)})</p>
        )}
      </div>
      
      {/* Expression Controls */}
      <div>
        <h3>Expressions</h3>
        <button onClick={() => setExpression('happy', 1)}>😊 Happy</button>
        <button onClick={() => setExpression('sad', 1)}>😢 Sad</button>
        <button onClick={() => setExpression('surprised', 1)}>😲 Surprised</button>
        <button onClick={resetExpressions}>Reset</button>
      </div>
      
      {/* Animation Controls */}
      <div>
        <h3>Animations</h3>
        <p>Current: {currentAnimation}</p>
        <button onClick={() => animate('idle')}>🧍 Idle</button>
        <button onClick={() => animate('walk')}>🚶 Walk</button>
        <button onClick={() => animate('dance')}>💃 Dance</button>
      </div>
      
      {/* Conversation History */}
      <div>
        <h3>Conversation</h3>
        {conversation.map((msg, i) => (
          <div key={i}>
            <strong>{msg.role}:</strong> {msg.text}
          </div>
        ))}
      </div>
    </div>
  );
}

function Avatar3D() {
  const animations = {
    idle: '/animations/breathing.fbx',
    walk: '/animations/walking.fbx',
    dance: '/animations/dancing.fbx'
  };
  
  return (
    <Canvas camera={{ position: [0, 1, 3] }}>
      <Environment preset="studio" />
      <ambientLight intensity={0.5} />
      <directionalLight position={[5, 5, 5]} />
      
      <VRMAvatar
        src="/models/avatar.vrm"
        animations={animations}
        position={[0, -1, 0]}
      />
      
      <OrbitControls 
        target={[0, 0.5, 0]}
        enablePan={false}
        minDistance={1}
        maxDistance={5}
      />
    </Canvas>
  );
}

export default function App() {
  return (
    <KhaveeProvider config={{ realtime: realtimeProvider }}>
      <div className="app">
        <div className="avatar-container">
          <Avatar3D />
        </div>
        <div className="controls-container">
          <ControlPanel />
        </div>
      </div>
    </KhaveeProvider>
  );
}
}

TypeScript Support

Full TypeScript support with comprehensive type definitions:

import type {
  VRMAvatarProps,
  AnimationConfig,
  KhaveeConfig,
  RealtimeProvider,
  RealtimeTool,
  MouthState,
  PhonemeData,
  ChatStatus,
  Conversation
} from '@khaveeai/react';

Performance Tips

  • Frustum Culling: Disabled automatically for VRM models
  • Vertex Optimization: Uses VRMUtils for performance optimization
  • Smooth Transitions: Configurable lerp factors for animations (delta * 8)
  • MFCC Audio Analysis: Optimized real-time frequency analysis for lip sync
  • Memory Management: Automatic cleanup of audio contexts and animation mixers

Browser Support

  • ✅ Chrome 88+
  • ✅ Firefox 85+
  • ✅ Safari 14.1+
  • ✅ Edge 88+

Requirements:

  • WebRTC support (for real-time features)
  • Web Audio API (for lip sync analysis)
  • WebGL 2.0 (for VRM rendering)
  • Meyda library (for MFCC analysis)

Troubleshooting

Common Issues

Audio Analysis Not Working:

// Check Meyda import and audio context
const { analyzeLipSync, isAnalyzing } = useAudioLipSync();

if (!isAnalyzing) {
  console.log('Make sure Meyda is installed: npm install meyda');
}

VRM Model Not Loading:

// Check model format and path
<VRMAvatar 
  src="/models/character.vrm"  // Must be .vrm format
  onLoad={() => console.log('VRM loaded successfully')}
/>

Animations Not Playing:

// Check FBX file paths and format
const animations = {
  idle: '/animations/idle.fbx',  // Must be accessible FBX files
  walk: '/animations/walk.fbx'
};

// Check if animations are loaded
const { availableAnimations } = useVRMAnimations();
console.log('Available animations:', availableAnimations);

Expressions Not Working:

// Check VRM model has expression support
const { expressions } = useVRMExpressions();
const vrm = useVRM();

if (vrm?.expressionManager) {
  console.log('Expression support:', Object.keys(vrm.expressionManager.expressionMap));
}

Contributing

We welcome contributions! Please see our Contributing Guide.

License

MIT © KhaveeAI


Need help? Check out our examples or open an issue.