Live HL data → in-browser TA → 4-agent committee → LONG/SHORT/SKIP verdict. Terminal grid command bar + interactive agent-workflow graph. Paper-trading worker reuses the browser brain (dry-run + Telegram). Forgejo static deploy. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5.1 KiB
$QUANT Terminal — interface design system
Direction: "Carbon Desk" — a serious institutional quant trading terminal (Linear × Bloomberg). Dark, dense, calm. The product is the live decision pipeline; the agent committee → verdict is the hero. Reading order everywhere: CALL → WHY → EVIDENCE.
Feel: precise, quiet, instrument-like. No marketing voice. Craft whispers.
Depth strategy
Borders + surface lightness — NO shadows. Elevation by lightness:
- page
--color-paper#0B0C0E → panel chrome--color-panel#111316 → raised/hover/active--color-panel-2#181B20. Data cells & wells recede to--color-inset#0E0F12. - Borders are light-on-dark rgba:
line.10 (standard),line-soft.06 (dividers),line-strong.16 (emphasis / zero-axis).line-amber.45 only for the verdict accent. - Bar/ring tracks use
--color-trackrgba(255,255,255,.09) — a carved channel, neverline-soft.
Color
- One accent: amber
--color-accent#FFB020 — reserved for "the call" (verdict accent strip, L4 pipeline dot, active tab, PAPER chip). Do not spread it. - Semantic only: long
#2BD974, short#F2444D(+-dim14% fills). Never decorative. - Direction must never be color-only — pair with a glyph/sign (▲ ▼ —, +/−).
Text hierarchy (all AA on panel)
--color-bone #E8EAED primary · --color-bone-dim #AAB1BA secondary/prose ·
--color-muted #828A94 labels · --color-faint #727983 captions/ticks.
Rule: value=bone, supporting prose=bone-dim, labels=muted, codes/units/ticks=faint.
Type
- Display/UI Geist, data Geist Mono. All numbers mono +
.tnum(tabular). - Scale tokens:
--text-micro10px ·--text-label11px ·--text-read12px ·--text-data13px. Big display via inlineclamp()(verdict glyph clamp(3rem,6vw,5rem)). - Labels:
.label(11px, .14em) and.label-sm(10px, .1em) are the ONLY label recipes. Two letter-spacings, not eight. - Weight: bold (700) reserved for display (verdict glyph, masthead, QUANT). Data = 500/medium.
Spacing & radius
- 4px base. Panel inset =
px-4 py-3. Hairline grids viagap-pxoverbg-line-soft. - Radius scale 2/4/6/10. Panels
rounded-md+overflow-hidden; nested wells clip to parent.
Key patterns
- Panel —
rounded-md border border-line bg-panel overflow-hidden; header =.label+ faint meta. Accent panel adds a 2px amber top strip as a child div (clean rounded corners). - Cell — recessed
bg-inset,.label-smover.tnummono value; optionalsub(agent tag) and a thin--color-trackbar. - DivergeBar — the signature: shared zero-axis; LONG fills right (green), SHORT left (red), SKIP a centred muted tick. Conviction = length. Committee ends in a NET LEAN row whose amber marker is the aggregate — visually ties votes → verdict.
- VerdictHero — full-width band, the hero: clamp() decision glyph in dir color + arrow, quorum ticks, big ConfidenceRing, then size/TP/SL/RR cells. Amber accent strip.
- Pipeline — honest L1→L6 with status dots (live=green, neutral=muted, the call=amber on L4, off-terminal=faint). Never overclaim what the page doesn't do.
Terminal layout (workspace)
The terminal is a multi-pane workspace, not tabs — everything visible at once like a real desk.
Order: status bar → masthead + coin tabs → reading guide → VERDICT band on top (the call,
full width) → 3-column grid lg:grid-cols-[280px_minmax(0,1fr)_360px] (stacks to 1 col below lg):
- Left —
PipelineRail(vertical L1→L6) + Market + Indicators stat cells (the "numbers"). - Center — the candlestick chart (the dominant pane).
- Right —
AgentGraph(signature) + Committee analytics list.
AgentGraph (components/viz/AgentGraph.tsx) is hub-and-spoke: 4 agent nodes feed one central
verdict node; edge colour = vote (long/short/skip), edge weight + node fill = conviction; the
centre shows decision + confidence. Honest (exactly the 4 real agents), animated between states.
Charts
Charts come from bklit-ui (shadcn registry @bklit, built on @visx + motion), installed as
source under src/components/charts/. The price panel uses the candlestick-chart
(src/components/viz/PriceCandles.tsx) fed by real Hyperliquid OHLC, themed to Carbon Desk:
positiveFill=var(--color-long), negativeFill=var(--color-short). Dark chart vars are
activated via class="dark" on <html>. Add more charts with
npx shadcn@latest add @bklit/<slug>.
Two gotchas (already handled): (1) the alpha @visx ParentSize fails to size under React 19 —
candlestick-chart.tsx was patched to use a useElementSize ResizeObserver hook instead.
(2) Keep the global * { min-width: 0 } reset inside @layer base, or it (unlayered) beats
Tailwind's min-w-* utilities and breaks flex-wrap layouts.
States
Seeded-vs-live is flagged (verdict shows a "seed · awaiting live" chip when live===false);
StatusBar surfaces stale/error (DATA STALE when fetch errors or ago>40s); footer copy
degrades the "live" claim accordingly. Global amber :focus-visible ring on all interactives.