About the Project: AniFriend: Valentine's Day Dating Simulator
Inspiration
Valentine's Day can be a lonely time for many people. Whether you're single, separated from loved ones, or simply want to experience something unique, we wanted to create an interactive experience that brings warmth and connection to everyone. The inspiration came from the Japanese visual novel and dating simulator genre, combined with modern AI technology to create truly dynamic, emotionally intelligent conversations.
We wanted to prove that AI companions could provide meaningful interactions while maintaining appropriate boundaries and healthy relationship dynamics. The goal wasn't just to create a chatbot, but to craft an immersive experience complete with:
- Live2D animated characters that react with genuine expressions
- Voice synthesis that brings text to life
- Progressive relationship systems that reward meaningful interaction
- Interactive cafe dates that simulate real romantic experiences
What We Learned
Technical Skills
Live2D Integration with Web Technologies
- Integrating Cubism SDK with PIXI.js for real-time 2D animation
- Managing model expressions and animations dynamically
- Handling multiple character models with different rigs and expressions
AI Prompt Engineering
- Crafting system prompts that maintain consistent character personalities
- Implementing dynamic affection systems that influence AI behavior
- Balancing creativity with appropriate content boundaries
Multi-Modal AI Integration
- Combining text generation (Google Gemini)
- Text-to-speech synthesis (ElevenLabs)
- Speech-to-text transcription for voice input
- Synchronizing all these systems seamlessly
State Management in React
- Managing complex state with affection levels, milestones, and chat history
- Implementing real-time emotion analysis and expression updates
- Handling async operations across multiple API services
Soft Skills
- Emotional Design: Understanding how UI/UX affects user emotional engagement
- Narrative Design: Creating compelling character backstories and interaction patterns
- Ethical AI: Establishing boundaries for AI interactions to promote healthy behaviors
How We Built It
Architecture Overview
The project is built with a modern web stack:
Next.js 14 (App Router) + TypeScript
↓
┌─────────────────────────────────────────┐
│ Frontend Layer │
│ - React Components │
│ - PIXI.js + Live2D Display │
│ - State Management (useState/useEffect)│
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ API Layer (Next.js Route Handlers) │
│ - /api/chat → Gemini AI + TTS │
│ - /api/stt → Speech-to-Text │
│ - /api/tts → Text-to-Speech │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ External Services │
│ - Google Gemini API (Text Generation) │
│ - ElevenLabs API (Voice Synthesis) │
└─────────────────────────────────────────┘
Key Components
ModelCanvas Component
- Loads and renders Live2D models using
pixi-live2d-display - Dynamically switches between characters (Arisa/Chitose)
- Maps emotion strings to model expressions
- Handles scaling and positioning for responsive display
- Loads and renders Live2D models using
Chat System
- Maintains conversation history for context-aware responses
- Implements affection calculation: \(A_{new} = A_{current} + (B \times M_e)\)
- Where \(A = affection \ level \)
- \(B= base \ change (5 \ points) \)
- \(M_e = emotion \ multiplier (-3 \ to \ +3)\)
- Progressive milestone system at thresholds: \({25, 50, 75, 100}\)
Emotion Analysis System
- Uses regex pattern matching to detect emotional indicators in AI responses
- Different emotion mappings for each character:
- Arisa: Smile, Angry, Sad, Surprised, Normal
- Chitose: Smile, Angry, Sad, Surprised, Normal, Blushing
- Real-time expression updates synchronized with text
Cafe Date Feature
- Unlocks at affection level ≥ 50
- Virtual currency system for ordering
- Menu categories with item costs
- Receipt generation with timestamps
Development Process
graph LR
A[Character Design] --> B[Live2D Integration]
B --> C[AI Personality Crafting]
C --> D[Voice Synthesis]
D --> E[Affection System]
E --> F[Cafe Date Feature]
F --> G[Polish & Testing]
Challenges We Faced
1. Live2D SDK Compatibility Issues
Problem: The Live2D Cubism SDK requires specific loading order and has conflicts with Next.js SSR.
Solution:
- Disabled SSR for the ModelCanvas component using
dynamicimport withssr: false - Manually loaded the Cubism Core script before the display library
- Exposed PIXI globally before Live2D initialization
// This order is critical!
await loadScript("/live2d.min.js");
await loadScript("https://cubism.live2d.com/.../live2dcubismcore.min.js");
const { Live2DModel } = await import('pixi-live2d-display');
2. Expression Mapping Complexity
Problem: Different Live2D models have different expression file names and structures.
Solution: Created character-specific expression mappings:
const chitoseExpressions = {
'Angry': 'Angry',
'Sad': 'Sad',
'Smile': 'Smile',
// ... maps emotion concepts to actual .exp3.json files
};
3. Emotion Detection Accuracy
Problem: Simple keyword matching produced inconsistent results.
Solution: Implemented priority-based regex patterns with context awareness:
- Check for specific emotion indicators in order of uniqueness
- Use word boundaries (
\b) to avoid false positives - Consider punctuation patterns (e.g.,
[!?]{2,}for surprise)
4. Audio Streaming Performance
Problem: ElevenLabs TTS returns streaming data that needed buffering.
Solution: Implemented chunk-based buffering and Base64 encoding:
const chunks: Uint8Array[] = [];
const reader = audio.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
}
const audioBuffer = Buffer.concat(chunks);
5. Affection System Balance
Problem: Initial affection changes were too rapid, making progression feel unrealistic.
Solution:
- Tuned multipliers based on extensive testing
- Made affection changes proportional to emotional response intensity
- Implemented character-specific multipliers (Chitose has gentler progression)
6. State Synchronization
Problem: Expression changes, audio playback, and text updates needed perfect timing.
Solution: Used React's useEffect dependencies carefully and implemented callback-based sequencing for critical updates.
About the Side Project: Button Tag
Track: Useless Hacks Button Tag is an interactive React web application built with TypeScript and Parcel that features a playful cat-and-mouse game where users attempt to click an elusive button that moves around the screen to avoid the cursor. The app includes two game modes (escape and chase), an inventory system for placing decorative "stick" shapes on the canvas, and defensive abilities like shrinking and becoming translucent that activate when the button is cornered. Built with a minimalist setup using Parcel as the build tool, the project demonstrates creative UI interactions and game mechanics in a browser-based environment.
Built With
- css
- elevenlabs
- gemini
- javascript
- pixi
- react
- typescript
Log in or sign up for Devpost to join the conversation.