File size: 4,823 Bytes
9cb3002
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5b8d71e
9cb3002
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5b8d71e
 
 
 
 
9cb3002
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import React from 'react';
import { Play, SkipForward, Square } from 'lucide-react';

import { BalancePanel } from './components/BalancePanel';
import { MarketPanel } from './components/MarketPanel';
import { MetricsPanel } from './components/MetricsPanel';
import { OfficeScene } from './components/OfficeScene';
import { useSimulationStore } from './store';

function App() {
  const {
    simState,
    portfolioHistory,
    priceHistory,
    lastPortfolioDelta,
    lastPriceDelta,
    lastError,
    toggleSimulation,
    fetchState,
    stepSimulation,
  } = useSimulationStore();

  React.useEffect(() => {
    fetchState();
    const interval = window.setInterval(() => {
      fetchState();
    }, 600);
    return () => window.clearInterval(interval);
  }, [fetchState]);

  return (
    <div className="min-h-screen bg-[linear-gradient(180deg,#f9eadb_0%,#f6ddc6_42%,#ecd0bb_100%)] px-6 py-8 text-stone-800 md:px-8">
      <div className="mx-auto max-w-[1500px]">
        <div className="mb-8 flex flex-col gap-5 rounded-[2.2rem] border border-[#7d5a4f]/15 bg-[#fff8ef]/78 px-6 py-6 shadow-[0_24px_55px_rgba(77,44,26,0.12)] backdrop-blur md:flex-row md:items-end md:justify-between">
          <div className="max-w-3xl">
            <div className="inline-flex items-center gap-2 rounded-full bg-white/80 px-4 py-1 text-[11px] font-semibold uppercase tracking-[0.32em] text-stone-500">
              <span className={`h-2.5 w-2.5 rounded-full ${simState.is_running ? 'bg-emerald-500' : 'bg-stone-400'}`} />
              Wild Card Demo
            </div>
            <h1 className="mt-4 text-4xl font-semibold tracking-tight text-stone-900 md:text-5xl">
              Indie quant floor with live agent choreography
            </h1>
            <p className="mt-3 max-w-2xl text-sm leading-7 text-stone-600 md:text-base">
              The scene updates off the running trading environment: signals travel desk to desk, the trader fires orders, and the balance reacts to the trades in real time.
            </p>
          </div>

          <div className="flex flex-wrap items-center gap-3">
            {lastError ? (
              <div className="rounded-full border border-rose-200 bg-rose-50 px-4 py-2 text-[11px] font-semibold uppercase tracking-[0.18em] text-rose-600 shadow-sm">
                Demo error: {lastError}
              </div>
            ) : null}
            <div className="rounded-full bg-white/85 px-4 py-2 text-[11px] font-semibold uppercase tracking-[0.24em] text-stone-500 shadow-sm">
              Step {simState.current_step}
            </div>
            <div className="rounded-full bg-white/85 px-4 py-2 text-[11px] font-semibold uppercase tracking-[0.24em] text-stone-500 shadow-sm">
              {simState.engine?.mode}
            </div>
            <button
              onClick={() => stepSimulation()}
              className="inline-flex items-center gap-2 rounded-full border border-[#7d5a4f]/15 bg-white px-5 py-3 text-sm font-semibold text-stone-700 shadow-sm transition hover:bg-stone-50"
            >
              <SkipForward size={16} />
              Step
            </button>
            <button
              onClick={() => toggleSimulation(simState.is_running)}
              className={`inline-flex items-center gap-2 rounded-full px-5 py-3 text-sm font-semibold shadow-sm transition ${
                simState.is_running
                  ? 'bg-rose-500 text-white hover:bg-rose-600'
                  : 'bg-emerald-500 text-white hover:bg-emerald-600'
              }`}
            >
              {simState.is_running ? <Square size={16} /> : <Play size={16} />}
              {simState.is_running ? 'Stop Demo' : 'Run Demo'}
            </button>
          </div>
        </div>

        <div className="grid gap-6 xl:grid-cols-[minmax(0,1fr)_360px]">
          <OfficeScene
            agents={simState.agents}
            flow={simState.flow}
            trade={simState.trade}
            currentStep={simState.current_step}
            isRunning={simState.is_running}
            engine={simState.engine}
          />

          <div className="flex flex-col gap-6">
            <BalancePanel
              portfolio={simState.portfolio}
              history={portfolioHistory}
              lastDelta={lastPortfolioDelta}
              trade={simState.trade}
            />
            <MarketPanel
              chart={simState.chart}
              history={priceHistory}
              trade={simState.trade}
              engine={simState.engine}
              lastPriceDelta={lastPriceDelta}
            />
          </div>
        </div>

        <div className="mt-6">
          <MetricsPanel metrics={simState.metrics} trade={simState.trade} agents={simState.agents} />
        </div>
      </div>
    </div>
  );
}

export default App;