import React from 'react'; import { AnimatePresence, motion } from 'framer-motion'; import officeBg from '../assets/office_bg.png'; /* ──────────────────────── theme & layout ──────────────────────── */ const AGENT_THEMES = { Researcher: { accent: '#f28c6f', bubble: 'from-rose-100/95 via-orange-50/95 to-amber-50/90', icon: '🔍', label: 'Signal Lab', }, 'Risk Manager': { accent: '#5f8b7e', bubble: 'from-emerald-100/95 via-teal-50/95 to-lime-50/90', icon: '🛡️', label: 'Guard Rail', }, 'Portfolio Manager': { accent: '#e2a63b', bubble: 'from-amber-100/95 via-yellow-50/95 to-orange-50/90', icon: '💼', label: 'Capital Desk', }, 'Fundamental Analyst': { accent: '#7f8ce6', bubble: 'from-sky-100/95 via-indigo-50/95 to-cyan-50/90', icon: '📊', label: 'Macro Wire', }, Trader: { accent: '#e36b5f', bubble: 'from-red-100/95 via-orange-50/95 to-yellow-50/90', icon: '⚔️', label: 'Execution', }, }; /* Stacks cards neatly on the left while lines connect to the pixel-art desks */ const STATIONS = { Researcher: { left: '2%', top: '12%', anchor: [100, 140] }, 'Fundamental Analyst':{ left: '2%', top: '28%', anchor: [230, 430] }, 'Risk Manager': { left: '2%', top: '44%', anchor: [420, 120] }, 'Portfolio Manager': { left: '2%', top: '60%', anchor: [730, 140] }, Trader: { left: '2%', top: '76%', anchor: [700, 430] }, }; const MARKET_ANCHOR = [950, 280]; const LINK_TONES = { signal: '#f28c6f', research: '#f0a95b', macro: '#7f8ce6', risk: '#5f8b7e', approval: '#e2a63b', buy: '#52b788', sell: '#d95d5d', hold: '#8d99ae', }; const trimMessage = (m = '') => (m.length <= 80 ? m : `${m.slice(0, 77)}…`); /* ──────────────────────── data-link SVG ──────────────────────── */ const DataLink = ({ flow, isRunning }) => { const start = flow.from === 'Market' ? MARKET_ANCHOR : STATIONS[flow.from]?.anchor; const end = flow.to === 'Market' ? MARKET_ANCHOR : STATIONS[flow.to]?.anchor; if (!start || !end) return null; const color = LINK_TONES[flow.tone] || '#8d99ae'; return ( <> {flow.active && ( )} ); }; /* ──────────────────────── agent speech bubble ──────────────────────── */ const AgentBubble = ({ name, agent, isRunning }) => { const theme = AGENT_THEMES[name]; const station = STATIONS[name]; const conf = agent?.confidence || 0; const active = agent?.status === 'active'; return ( {/* speech bubble */} {agent?.message && (
{theme.icon} {theme.label} {active ? 'LIVE' : 'IDLE'}
{trimMessage(agent.message)}
{/* confidence bar */}
)}
{/* role tag — always visible */}
{theme.icon} {name}
); }; /* ──────────────────────── trade flash overlay ──────────────────────── */ const TradeFlash = ({ trade, isRunning }) => { if (!trade || trade.side === 'HOLD') return null; const isBuy = trade.side === 'BUY'; return ( ); }; /* ──────────────────────── main scene ──────────────────────── */ export const OfficeScene = ({ agents, flow, trade, currentStep, isRunning, engine }) => { const tradeTone = trade?.side === 'BUY' ? 'text-emerald-600' : trade?.side === 'SELL' ? 'text-rose-600' : 'text-stone-500'; return (
{/* pixel-art background */} Quant Office {/* slight gradient overlay so text is readeable */}
{/* trade flash */} {/* header bar */}
Wild Card Floor

🏢 Cutesy Quant Office

Five desks, one coordinated loop. Watch signals travel desk-to-desk in real time.

{/* engine + trade info card */}
Engine
{engine?.name || 'Desk Policy'}
{engine?.mode || 'Rule Fallback'}
{trade?.side || 'HOLD'} · ${trade?.price?.toFixed(0) || '—'} · Step {currentStep}
{/* data-link SVG layer */} {flow?.map((item) => ( ))} {/* market board overlay (right side) */}
📈 Market Board
{trade?.side || 'HOLD'}
Size
{trade?.size?.toFixed(2) || '0.00'}
Price
${trade?.price?.toFixed(0) || '—'}
SL
${trade?.sl?.toFixed(0) || '—'}
TP
${trade?.tp?.toFixed(0) || '—'}
{/* agent speech bubbles */} {Object.entries(STATIONS).map(([name]) => ( ))}
); };