import React, { useRef, useEffect, useState } from 'react';
import { Canvas, useFrame, useThree } from '@react-three/fiber';
import { OrbitControls, Text, Sphere, Line } from '@react-three/drei';
import * as THREE from 'three';
import { motion } from 'framer-motion';
// Emotion space visualization component
function EmotionSpace({ analysisData, isActive }) {
const meshRef = useRef();
const pointsRef = useRef();
const [emotionHistory, setEmotionHistory] = useState([]);
useEffect(() => {
if (analysisData && isActive) {
setEmotionHistory(prev => [...prev.slice(-50), analysisData]);
}
}, [analysisData, isActive]);
useFrame((state) => {
if (meshRef.current) {
meshRef.current.rotation.y += 0.005;
}
});
// Convert emotion probabilities to 3D coordinates
const getEmotionCoordinates = (emotions) => {
if (!emotions || emotions.length !== 7) return [0, 0, 0];
// Map emotions to 3D space: valence (x), arousal (y), dominance (z)
const valence = emotions[3] - emotions[4]; // happy - sad
const arousal = (emotions[0] + emotions[2] + emotions[5]) - (emotions[1] + emotions[6]); // angry + fear + surprise - disgust - neutral
const dominance = emotions[6] - (emotions[1] + emotions[2]); // neutral - (disgust + fear)
return [valence * 2, arousal * 2, dominance * 2];
};
return (
{/* Emotion axes */}
{/* Axis labels */}
Valence
Arousal
Dominance
{/* Current emotion point */}
{analysisData && (
)}
{/* Emotion trajectory */}
{emotionHistory.length > 1 && (
getEmotionCoordinates(data.emotion?.probabilities))}
color="cyan"
lineWidth={3}
/>
)}
{/* Emotion labels at corners */}
Happy
Sad
Angry
Surprised
);
}
// Intent visualization component
function IntentVisualization({ analysisData, isActive }) {
const groupRef = useRef();
const [intentHistory, setIntentHistory] = useState([]);
useEffect(() => {
if (analysisData && isActive) {
setIntentHistory(prev => [...prev.slice(-30), analysisData]);
}
}, [analysisData, isActive]);
useFrame((state) => {
if (groupRef.current) {
groupRef.current.rotation.z += 0.01;
}
});
// Convert intent to radial coordinates
const getIntentPosition = (intent, index) => {
const angle = (index / 5) * Math.PI * 2;
const radius = intent * 2;
return [Math.cos(angle) * radius, Math.sin(angle) * radius, 0];
};
return (
{/* Intent radar chart */}
{analysisData?.intent?.probabilities?.map((prob, idx) => (
))}
{/* Intent labels */}
{['Agreement', 'Confusion', 'Hesitation', 'Confidence', 'Neutral'].map((intent, idx) => {
const angle = (idx / 5) * Math.PI * 2;
const x = Math.cos(angle) * 2.5;
const y = Math.sin(angle) * 2.5;
return (
{intent}
);
})}
{/* Connecting lines */}
{analysisData?.intent?.probabilities && (
getIntentPosition(prob, idx)),
getIntentPosition(analysisData.intent.probabilities[0], 0) // Close the shape
]}
color="lime"
lineWidth={2}
/>
)}
);
}
// Modality fusion visualization
function ModalityFusion({ analysisData, isActive }) {
const fusionRef = useRef();
useFrame((state) => {
if (fusionRef.current) {
fusionRef.current.rotation.x += 0.005;
fusionRef.current.rotation.y += 0.003;
}
});
return (
{/* Vision sphere */}
{/* Audio sphere */}
{/* Text sphere */}
{/* Fusion center */}
{/* Connection lines */}
{/* Labels */}
Vision
Audio
Text
Fusion
);
}
// Main 3D visualization component
export default function Advanced3DVisualization({ analysisData, isActive }) {
const [activeView, setActiveView] = useState('emotion');
return (
{/* View Controls */}
{[
{ key: 'emotion', label: 'Emotion Space', icon: '🧠' },
{ key: 'intent', label: 'Intent Radar', icon: '🎯' },
{ key: 'fusion', label: 'Modality Fusion', icon: '🔗' }
].map(({ key, label, icon }) => (
setActiveView(key)}
className={`px-3 py-2 rounded-lg text-sm font-medium transition-colors ${
activeView === key
? 'bg-cyan-600 text-white'
: 'bg-white/10 text-gray-300 hover:bg-white/20'
}`}
>
{icon} {label}
))}
{/* 3D Canvas */}
{/* Info Panel */}
3D Analysis
{activeView === 'emotion' && 'Visualizing emotion in 3D valence-arousal-dominance space'}
{activeView === 'intent' && 'Intent analysis as radar chart with temporal tracking'}
{activeView === 'fusion' && 'Multi-modal fusion showing contribution weights'}
Drag to rotate • Scroll to zoom • Right-click to pan
);
}