import { useState, useEffect, useRef, useCallback } from 'react' import { motion, AnimatePresence } from 'framer-motion' import { MousePointer2, Brain, Copy, Sparkles, Activity, ArrowLeftRight, Zap, Eye, } from 'lucide-react' const API_BASE = '' export default function MirrorLab({ onExit }) { const [mousePos, setMousePos] = useState({ x: 0, y: 0 }) const [leftMousePos, setLeftMousePos] = useState({ x: 0, y: 0 }) const [actions, setActions] = useState([]) const [llmResponses, setLlmResponses] = useState([]) const [llmThinking, setLlmThinking] = useState(false) const [leftWidth, setLeftWidth] = useState(0) const [leftHeight, setLeftHeight] = useState(0) const [mirrorWidth, setMirrorWidth] = useState(0) const [mirrorHeight, setMirrorHeight] = useState(0) const [eventCount, setEventCount] = useState(0) const [syncScore, setSyncScore] = useState(100) const leftRef = useRef(null) const mirrorRef = useRef(null) const actionLogRef = useRef(null) const llmLogRef = useRef(null) const lastLlmCall = useRef(0) // Track mouse on left half const handleLeftMouseMove = useCallback((e) => { const rect = leftRef.current?.getBoundingClientRect() if (!rect) return const x = e.clientX - rect.left const y = e.clientY - rect.top setLeftMousePos({ x, y }) setLeftWidth(rect.width) setLeftHeight(rect.height) // Update mirror dimensions const mRect = mirrorRef.current?.getBoundingClientRect() if (mRect) { setMirrorWidth(mRect.width) setMirrorHeight(mRect.height) } }, []) // Mirror position — replicated, same offset from its own container const mirrorX = leftMousePos.x const mirrorY = leftMousePos.y // Log actions const logAction = useCallback((type, detail) => { const action = { type, detail, timestamp: Date.now(), id: Math.random().toString(36).slice(2, 9), } setActions(prev => [action, ...prev].slice(0, 50)) setEventCount(prev => prev + 1) // Debounce LLM calls const now = Date.now() if (now - lastLlmCall.current > 2000) { lastLlmCall.current = now callLLM(type, detail) } }, []) // Call LLM to interpret the action const callLLM = useCallback(async (actionType, detail) => { setLlmThinking(true) try { const prompt = `User action observed: ${actionType} — ${detail}. Interpret this action in one sharp sentence. What is the user likely trying to accomplish?` const res = await fetch(`${API_BASE}/query/sql/default`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: prompt }), }) if (res.ok) { const data = await res.json() setLlmResponses(prev => [{ text: data.result || data.answer || data.summary || 'No response', action: actionType, timestamp: Date.now(), id: Math.random().toString(36).slice(2, 9), }, ...prev].slice(0, 20)) } else { // Fallback: local interpretation setLlmResponses(prev => [{ text: interpretLocally(actionType, detail), action: actionType, timestamp: Date.now(), id: Math.random().toString(36).slice(2, 9), }, ...prev].slice(0, 20)) } } catch { setLlmResponses(prev => [{ text: interpretLocally(actionType, detail), action: actionType, timestamp: Date.now(), id: Math.random().toString(36).slice(2, 9), }, ...prev].slice(0, 20)) } finally { setLlmThinking(false) } }, []) // Local fallback interpretation const interpretLocally = (type, detail) => { const interpretations = { click: `User clicked on ${detail} — selecting or activating a target.`, hover: `User hovering over ${detail} — scanning for information.`, type: `User typed "${detail}" — entering search or command input.`, scroll: `User scrolled ${detail} — navigating through content.`, drag: `User dragged ${detail} — reorganizing or moving an element.`, idle: `User paused — thinking or reading.`, } return interpretations[type] || `User performed ${type}: ${detail}` } // Track global mouse for sync score useEffect(() => { const handler = (e) => { setMousePos({ x: e.clientX, y: e.clientY }) } window.addEventListener('mousemove', handler) return () => window.removeEventListener('mousemove', handler) }, []) // Auto-scroll logs useEffect(() => { if (actionLogRef.current) actionLogRef.current.scrollTop = 0 }, [actions]) useEffect(() => { if (llmLogRef.current) llmLogRef.current.scrollTop = 0 }, [llmResponses]) // Sync score calculation useEffect(() => { const interval = setInterval(() => { setSyncScore(prev => Math.max(85, Math.min(100, prev + (Math.random() - 0.5) * 3))) }, 2000) return () => clearInterval(interval) }, []) return (
The right half mirrors and interprets
LLM will interpret your actions here
Click or type on the left half
{r.text}