import { type AgentMascot, type AgentState } from '../lib/types' interface AgentAvatarProps { name: AgentMascot state: AgentState size?: 'sm' | 'md' | 'lg' showName?: boolean } const AVATAR_COLORS: Record = { Spark: { primary: '#3B82F6', secondary: '#60A5FA', accent: '#DBEAFE' }, // Blue robot Fizz: { primary: '#F97316', secondary: '#FB923C', accent: '#FFEDD5' }, // Orange fox Octo: { primary: '#8B5CF6', secondary: '#A78BFA', accent: '#EDE9FE' }, // Purple octopus Hoot: { primary: '#22C55E', secondary: '#4ADE80', accent: '#DCFCE7' }, // Green owl Buzz: { primary: '#EAB308', secondary: '#FACC15', accent: '#FEF9C3' }, // Yellow bee } const SIZES = { sm: { svg: 32, font: 'text-xs' }, md: { svg: 48, font: 'text-sm' }, lg: { svg: 64, font: 'text-base' }, } // SVG mascot definitions - simple cute characters function SparkSVG({ colors, size }: { colors: typeof AVATAR_COLORS.Spark; size: number }) { return ( {/* Robot body */} {/* Robot head */} {/* Antenna */} {/* Eyes */} {/* Mouth */} {/* Arms */} ) } function FizzSVG({ colors, size }: { colors: typeof AVATAR_COLORS.Fizz; size: number }) { return ( {/* Ears */} {/* Head */} {/* Face */} {/* Eyes */} {/* Nose */} {/* Whiskers */} ) } function OctoSVG({ colors, size }: { colors: typeof AVATAR_COLORS.Octo; size: number }) { return ( {/* Tentacles */} {/* Head */} {/* Eyes */} {/* Smile */} ) } function HootSVG({ colors, size }: { colors: typeof AVATAR_COLORS.Hoot; size: number }) { return ( {/* Ear tufts */} {/* Body */} {/* Head */} {/* Eye circles */} {/* Eyes */} {/* Beak */} {/* Belly */} ) } function BuzzSVG({ colors, size }: { colors: typeof AVATAR_COLORS.Buzz; size: number }) { return ( {/* Wings */} {/* Body stripes */} {/* Head */} {/* Antennae */} {/* Eyes */} {/* Smile */} ) } const MASCOT_SVGS: Record = { Spark: SparkSVG, Fizz: FizzSVG, Octo: OctoSVG, Hoot: HootSVG, Buzz: BuzzSVG, } // Animation classes based on state function getStateAnimation(state: AgentState): string { switch (state) { case 'idle': return 'animate-bounce-gentle' case 'thinking': return 'animate-thinking' case 'working': return 'animate-working' case 'testing': return 'animate-testing' case 'success': return 'animate-celebrate' case 'error': case 'struggling': return 'animate-shake-gentle' default: return '' } } // Glow effect based on state function getStateGlow(state: AgentState): string { switch (state) { case 'working': return 'shadow-[0_0_12px_rgba(0,180,216,0.5)]' case 'thinking': return 'shadow-[0_0_8px_rgba(255,214,10,0.4)]' case 'success': return 'shadow-[0_0_16px_rgba(112,224,0,0.6)]' case 'error': case 'struggling': return 'shadow-[0_0_12px_rgba(255,84,0,0.5)]' default: return '' } } // Get human-readable state description for accessibility function getStateDescription(state: AgentState): string { switch (state) { case 'idle': return 'waiting' case 'thinking': return 'analyzing' case 'working': return 'coding' case 'testing': return 'running tests' case 'success': return 'completed successfully' case 'error': return 'encountered an error' case 'struggling': return 'having difficulty' default: return state } } export function AgentAvatar({ name, state, size = 'md', showName = false }: AgentAvatarProps) { const colors = AVATAR_COLORS[name] const { svg: svgSize, font } = SIZES[size] const SvgComponent = MASCOT_SVGS[name] const stateDesc = getStateDescription(state) const ariaLabel = `Agent ${name} is ${stateDesc}` return (
{showName && ( {name} )}
) } // Get mascot name by index (cycles through available mascots) export function getMascotName(index: number): AgentMascot { const mascots: AgentMascot[] = ['Spark', 'Fizz', 'Octo', 'Hoot', 'Buzz'] return mascots[index % mascots.length] }