import { useEffect, useState } from 'react' import { useGameStore } from './hooks/useGameStore.js' import { useAgentLoop, greedyPick, buildPitch } from './hooks/useAgentLoop.js' import TopBar from './components/TopBar.jsx' import PlaybackControls from './components/PlaybackControls.jsx' import MetricsPanel from './components/MetricsPanel.jsx' import TrustPanel from './components/TrustPanel.jsx' import EventBanner from './components/EventBanner.jsx' import NPCGrid from './components/NPCGrid.jsx' import AgentDecision from './components/AgentDecision.jsx' import VoteTally from './components/VoteTally.jsx' import HistoryTimeline from './components/HistoryTimeline.jsx' import EndScreen from './components/EndScreen.jsx' import RewardTrace from './components/RewardTrace.jsx' export default function App() { const { state, resetGame, stepGame, setSpeed, setPaused } = useGameStore() const { obs, prevObs, done, loading, error, lastReward, lastInfo, speed, paused, rewardTrace, cumReward } = state const [toast, setToast] = useState(null) // Show error toast useEffect(() => { if (error) { setToast(error) const t = setTimeout(() => setToast(null), 5000) return () => clearTimeout(t) } }, [error]) // Boot useEffect(() => { resetGame(42) }, [resetGame]) // Wire agent loop useAgentLoop(state, stepGame) const handleRun = () => setPaused(false) const handlePause = () => setPaused(true) const handleReset = () => { resetGame(Math.floor(Math.random() * 9999)) } const handleReplay = () => { resetGame(Math.floor(Math.random() * 9999)) } const handleStep = async () => { if (!obs || loading || done) return const decision = greedyPick(obs) const pitch = buildPitch(obs, decision) if (decision) await stepGame(decision, pitch) } const round = obs?.round ?? 0 const curState = obs?.state const prevState = prevObs?.state return (
{/* Metrics strip at top — always visible */} {curState && ( )}
{/* Left — Trust + Reward + History */}
{/* Centre — Event + NPCs + Agent Decision */}
{/* Right — Vote Tally */}
{lastInfo?.winning_vote_tally && } {!lastInfo && (
Vote Tally
// vote tally appears after first decision.
)}
{done && obs && } {toast && (
⚠ {toast}
)}
) }