How I Built a 'Living' AI Chatbot with Next.js, Mistral, and Framer Motion
Source: Dev.to
🚀 The Introduction
Most AI chatbots are boring. They are usually just a static box in the corner of the screen. When I was building the AI assistant for Trainlytic, I wanted something different—a bot that felt “alive,” an assistant that acknowledges your presence before you even start typing.
🤖 The Vision: A Bot with Personality
I didn’t want a “wrapper.” I wanted a UI that felt like the year 3026. The goal was to combine glassmorphism, neon accents, and interactive animation to create a high‑fidelity user experience.
Key Features
- Cursor Tracking: Eyes follow the user’s mouse movement.
- Natural Blinking: Randomized double‑blinks to mimic biological behavior.
- Mistral AI Integration: Specialized fitness and nutrition coaching.

👁️ The “Eye” Logic: Mathematical Cursor Tracking
The standout feature is the eye‑tracking. The eyes calculate the distance between the cursor and the center of the bot’s face, limiting movement to a natural range.
// Cursor tracking for eyes
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
if (!robotRef.current || isOpen) return;
const rect = robotRef.current.getBoundingClientRect();
const robotCenterX = rect.left + rect.width / 2;
const robotCenterY = rect.top + rect.height / 2;
const deltaX = e.clientX - robotCenterX;
const deltaY = e.clientY - robotCenterY;
// Limit eye movement range (max 4px offset for natural movement)
const maxOffset = 4;
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
const normalizedDistance = Math.min(distance / 300, 1);
const offsetX = (deltaX / (Math.abs(deltaX) + 100)) * maxOffset * normalizedDistance;
const offsetY = (deltaY / (Math.abs(deltaY) + 100)) * maxOffset * normalizedDistance;
setEyeOffset({ x: offsetX, y: offsetY });
};
window.addEventListener("mousemove", handleMouseMove);
return () => window.removeEventListener("mousemove", handleMouseMove);
}, [isOpen]);
⚡ The Brain: Mistral AI & Streaming
For the “brain,” I chose Mistral AI. It’s fast and well‑suited for the fitness and nutrition prompts I use to help users reach their goals. To avoid a clunky experience, I implemented streaming responses so the text flows into the chat bubble as it arrives.

🎨 UI/UX: Natural Blinking
A performDoubleBlink function triggers at random intervals, giving the bot a more lifelike presence.
const performDoubleBlink = () => {
setIsBlinking(true); // First blink
setTimeout(() => {
setIsBlinking(false);
setTimeout(() => {
setIsBlinking(true); // Second rapid blink
setTimeout(() => setIsBlinking(false), 100);
}, 150);
}, 100);
};
💡 Conclusion
Building this taught me that UX engineering is just as important as the AI itself. People stay on the page longer just to play with the bot’s eyes!
Check it out live at Trainlytic.net and let me know what you think of the design in the comments!