Ring

Click the button to start call and the ring will animate to your voice agent.

Preview

Code

Copy the following code to your component file for example ring.tsx.

import React, { useEffect, useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import useWebRTCAudioSession from '@/hooks/use-webrtc';
import { Button } from '@/components/ui/button';
import { MicIcon, PhoneOff } from 'lucide-react';
 
const Visualizer: React.FC = () => {
  const { currentVolume, isSessionActive, handleStartStopClick } = useWebRTCAudioSession('alloy');
  const [bars, setBars] = useState(Array(50).fill(5));
 
  console.log(currentVolume);
 
  useEffect(() => {
    if (isSessionActive) {
      updateBars(currentVolume);
    } else {
      resetBars();
    }
  }, [currentVolume, isSessionActive]);
 
  const updateBars = (volume: number) => {
    if (volume > 0.002) {
      setBars(bars.map(() => Math.random() * volume * 500));
    } else {
      setBars(Array(50).fill(5));
    }
  };
 
  const resetBars = () => {
    setBars(Array(50).fill(5));
  };
 
  const micPulseAnimation = {
    scale: [1, 1.2, 1],
    opacity: [1, 0.8, 1],
    transition: { duration: 0.8, repeat: Infinity }
  };
 
  return (
    <div className="flex flex-col items-center justify-center p-6 rounded">
      <AnimatePresence>
        {isSessionActive && (
          <motion.div
            className="flex items-center justify-center w-full h-full"
            initial={{ opacity: 0, scale: 0.8 }}
            animate={{ opacity: 1, scale: 1 }}
            exit={{ opacity: 0, scale: 0.8 }}
            transition={{ duration: 0.5 }}
          >
            <svg width="100%" height="100%" viewBox="0 0 1000 200" preserveAspectRatio="xMidYMid meet">
              {bars.map((height, index) => (
                <React.Fragment key={index}>
                  <rect
                    x={500 + index * 20 - 490}
                    y={100 - height / 2}
                    width="10"
                    height={height}
                    className={`fill-current ${isSessionActive ? 'text-black dark:text-white opacity-70' : 'text-gray-400 opacity-30'}`}
                  />
                  <rect
                    x={500 - index * 20 - 10}
                    y={100 - height / 2}
                    width="10"
                    height={height}
                    className={`fill-current ${isSessionActive ? 'text-black dark:text-white opacity-70' : 'text-gray-400 opacity-30'}`}
                  />
                </React.Fragment>
              ))}
            </svg>
          </motion.div>
        )}
      </AnimatePresence>
      <motion.div
        className="mt-4"
        animate={isSessionActive && currentVolume === 0 ? micPulseAnimation : {}}
      >
        <Button onClick={handleStartStopClick} className="flex items-center justify-center w-12 h-12 rounded-full shadow-lg">
          <AnimatePresence>
            {isSessionActive ? (
              <motion.div
                key="phone-off"
                initial={{ opacity: 0, scale: 0.8 }}
                animate={{ opacity: 1, scale: 1 }}
                exit={{ opacity: 0, scale: 0.8 }}
                transition={{ duration: 0.3 }}
              >
                <PhoneOff size={24} />
              </motion.div>
            ) : (
              <motion.div
                key="mic-icon"
                initial={{ opacity: 0, scale: 0.8 }}
                animate={{ opacity: 1, scale: 1 }}
                exit={{ opacity: 0, scale: 0.8 }}
                transition={{ duration: 0.3 }}
              >
                <MicIcon size={24} />
              </motion.div>
            )}
          </AnimatePresence>
        </Button>
      </motion.div>
    </div>
  );
};
 
export default Visualizer;

Usage

Import the component in your file and then use it in your page. Ensure the use-webrtc hook is copied over to your project.

Note: This component uses Tailwind CSS, make sure to have it installed in your project.

import Visualizer from "@/components/openai-blocks/classic";
 
export default function Home() {
  return (
    <main className="flex items-center justify-center h-screen">
      <Visualizer />
    </main>
  );
}