import { useEffect, useRef, useState } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { Cpu, Zap, Clock } from 'lucide-react'; import type { ModelMode, PredictionResponse } from '../types'; interface Props { prediction: PredictionResponse | null; isConnected: boolean; latency: number; lowBandwidth?: boolean; selectedModel: ModelMode; } const PIPELINE_COLORS: Record = { A: 'text-emerald-400', B: 'text-sky-400', C: 'text-purple-400', ensemble: 'text-amber-400', }; const PIPELINE_LABELS: Record = { A: 'XGBoost', B: 'AE + LGBM', C: 'CNN + SVM', ensemble: 'A -> B -> C fallback', }; function confidenceColor(c: number) { if (c >= 0.85) return '#00f5d4'; // neon-cyan if (c >= 0.60) return '#fee440'; // yellow return '#f15bb5'; // pink-red } function ConfidenceBar({ value }: { value: number }) { return (
); } /** * Floating HUD panel that shows the current sign prediction, confidence, * active pipeline, latency and a rolling history of the last 10 signs. */ export function PredictionHUD({ prediction, isConnected, latency, lowBandwidth = false, selectedModel }: Props) { const [history, setHistory] = useState([]); const prevSignRef = useRef(null); // Add to history only when the sign changes useEffect(() => { if (!prediction) return; if (prediction.sign === prevSignRef.current) return; prevSignRef.current = prediction.sign; setHistory(prev => [prediction, ...prev].slice(0, 10)); }, [prediction]); const pipelineKey = prediction?.pipeline ?? 'A'; const pipelineColor = PIPELINE_COLORS[pipelineKey] ?? 'text-slate-400'; const pipelineLabel = PIPELINE_LABELS[pipelineKey] ?? pipelineKey; const selectedLabel = PIPELINE_LABELS[selectedModel] ?? selectedModel; return (
{/* Connection status */}
{isConnected ? 'Connected' : 'Reconnecting…'} {latency > 0 ? `${latency}ms` : '—'} {lowBandwidth && ( LB )}
{/* Main content: sign + history side by side on mobile, stacked on lg */}
{/* Main sign display */}
{prediction ? ( {prediction.sign} ) : ( ? )} Current sign
{/* Right column on mobile: confidence + pipeline + history */}
{/* Confidence bar */} {prediction && (
Confidence {Math.round(prediction.confidence * 100)}%
)} {/* Pipeline badge */} {prediction && (
Pipeline {pipelineKey} · {pipelineLabel}
)}
Selected mode: {selectedModel} ({selectedLabel})
{/* History */}

Recent signs

{history.map((h, i) => ( {h.sign} ))} {history.length === 0 && ( None yet )}
); }