AoE2 · LLM Arena

ADR 0005 — Vite + React 19 + Tailwind v4 + Radix UI for the arena UI

Status: Accepted (2026-05). Shipped as the Phase-2 frontend scaffold. Context: Chapter 19 — Arena Web Architecture.

Decision

Build the arena replay UI as a Vite-bundled React 19 SPA, styled with Tailwind v4 via @tailwindcss/vite, with Radix UI primitives wrapped in shadcn-style local components. Use Bun for package management and the dev server. Use plain EventSource + custom hooks for SSE; no data-fetching library.

What we considered

OptionProsCons
Vite + ReactMature SPA story; great dev UX; fast HMR.Yet another React app to maintain.
Next.jsApp router, server components.Server-side machinery wasted on a local-dev tool that needs SSE + REST against an existing FastAPI; routing collisions.
HTMX over FastAPINo JS build pipeline; small ops surface.Timeline scrubber + diff panel are stateful and would fight the model.
Streamlit / GradioZero frontend code.Both are opinionated about layout and don’t do SSE / live timelines well.
Svelte / SolidJSSmaller bundles; finer reactivity.Team is more familiar with React; the operator UI complexity doesn’t justify the switch.

Why Vite + React 19 + Tailwind v4

Why no data-fetching library

useRuns is one fetch('/runs') on mount. useEvents is new EventSource(...). Adding TanStack Query / SWR would buy retries and caching neither hook actually wants — runs are listed once per session; events are a fresh stream per selected run, and reconnect on overflow is a custom path the library would not understand. 1.5 KB of hook code is the right size.

Why Bun

Consequences

Positive

Negative