DEV Community

Cover image for How I Built a "Living" AI Chatbot with Next.js, Mistral, and Framer Motion
Talha Kazmi
Talha Kazmi

Posted on

How I Built a "Living" AI Chatbot with Next.js, Mistral, and Framer Motion

πŸš€ 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. I wanted a bot that felt "alive",an assistant that acknowledges your presence before you even start typing.

In this post, I’ll show you how I built a futuristic, robot-faced AI coach using Mistral AI, Next.js, and some clever Framer Motion math to make its eyes follow your cursor.

πŸ€– 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.

Close-up of the Trainlytic AI interactive robot face featuring glowing emerald eyes and a metallic visor

πŸ‘οΈ The "Eye" Logic: Mathematical Cursor Tracking
The standout feature is the eye-tracking. The eyes don't just move; they calculate the distance between your cursor and the center of the bot's face using a limited "visor" range.

I used useEffect to listen for mouse movements. Here is the core logic:

TypeScript
// 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]);
Enter fullscreen mode Exit fullscreen mode

⚑ The Brain: Mistral AI & Streaming
For the "brain," I chose Mistral AI. It’s incredibly fast and perfect for the specific fitness and nutrition prompts I use to help guys reach their goals.

To prevent a clunky user experience, I implemented Streaming Responses. Instead of waiting for the full response, the text "flows" into the bubble using a ReadableStream.

The full Trainlytic AI chat interface showing glassmorphism design, neon accents, and a fitness coaching conversation

🎨 UI/UX: Natural Blinking
I wrote a performDoubleBlink function that triggers at random intervals. This small detail makes the bot feel less like an icon and more like an entity.

TypeScript
const performDoubleBlink = () => {
  setIsBlinking(true); // First blink
  setTimeout(() => {
    setIsBlinking(false);
    setTimeout(() => {
      setIsBlinking(true); // Second rapid blink
      setTimeout(() => setIsBlinking(false), 100);
    }, 150);
  }, 100);
};

Enter fullscreen mode Exit fullscreen mode

πŸ’‘ 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!

Top comments (0)