Arcade Quick Start
End-user guide for running the F1 StratLab arcade replay with the live strategy surfaces. Aimed at someone who has cloned the repository and wants everything on screen inside ten minutes.
One command launches everything. The arcade process owns the simulation loop and broadcasts merged state on a local TCP port; the follower surfaces subscribe and render.
One follower stack. PITWALL (two pywebview windows rendering React) is the whole strategy surface. The original PySide6 pair ran beside it through the migration so every PITWALL panel could be compared against the window it replaced while that window still existed; it has now been retired, along with the PySide6 and pyqtgraph dependencies. The comparison baseline is not lost with it: the Qt windows' rendered output is committed as screenshots under documents/dev_docs/migration/pitwall/. The pyglet replay is unchanged either way.
The arcade: 2D replay, strategy dashboard and live telemetry, all in sync. Recorded before PITWALL joined; the pyglet replay on the left is unchanged.
Prerequisites
- Python: 3.10 or newer. The project pins dependencies with
uv. - Dependencies: run
uv syncfrom the repo root. The lockfile pullsarcade,pywebview,fastf1,langchain-openai, the model stack (xgboost,lightgbm,torch), and the NLP stack (transformers,sentence-transformers,setfit). No manual install steps required beyonduv sync. - LLM credentials: either set
OPENAI_API_KEYin a repo-root.env(the canonical TFG setup) or run LM Studio locally onhttp://localhost:1234/v1and pass--provider lmstudioon the command line (the arcade's own flag; its default isopenai, independent of theF1_LLM_PROVIDERenv var the backend and CLI read). Only the wording of the orchestrator's reasoning changes. - Race data cache: the replay reads
data/raw/{year}/{Location}/laps.parquetand optionallyweather.parquet. The parquet files are produced by FastF1 on first run. Expect a 20-40 second delay on the first launch of a round. - Vector store (optional): the N30 RAG agent reads a local Qdrant index under
data/rag/. If missing, the orchestrator degrades gracefully, regulation lookups return an empty context. Runpython scripts/build_rag_index.pyonce to build it.
One-command launch
From the repository root:
python -m src.arcade.main --viewer --year 2025 --round 3 --driver VER --team "Red Bull Racing" --driver2 LEC --strategy
What happens:
src.arcade.mainparses the CLI and opens the arcadeWindow.- The
--viewerflag skips the menu and goes straight toF1ArcadeView. - The view loads the 2025 Round 3 (Suzuka) parquet for Verstappen.
- With
--strategyset, the view starts aTelemetryStreamServeron127.0.0.1:9998, owns aStrategyState, and spawnspython -m src.pitwall. - PITWALL opens PITWALL · DATA and PITWALL · AGENTS, two pywebview windows rendering React against the same broadcast, through a single shared TCP client.
The arcade window drives playback; every other window reacts to broadcasts. PITWALL additionally serves the same two pages over loopback, and prints the URL on startup, so they can be opened in a browser (and get devtools) instead of, or as well as, the windows.
What each window shows
Arcade replay (pyglet)
Track outline with the DRS zones drawn in green, two driver icons (our driver in team colour, rival in rival-team colour), a leaderboard on the right with compound pills and gaps, a weather panel, a driver-info strip, and a progress bar with the current lap.
PITWALL · AGENTS
Four strata, top to bottom: header, decision band, agent grid, status bar. The band runs left to right in the order a reader asks the questions, which is what the orchestrator is doing, why, on what evidence, and what happens next: the orchestrator card with its action badge and confidence bar, the reasoning panel, the scenario bars (STAY_OUT / PIT_NOW / UNDERCUT / OVERCUT, scored by the Monte Carlo over the agents' own distributions) and the plan strip.
Under it a grid places its cards by name rather than in reading order, because three of them want a shape reading order does not give them:
pace tire side
radio exit rag
side stacks Situation (N27) and Pit (N28); exit is the PIT EXIT card, which answers what position a stop taken on this lap rejoins in and which cars land either side. Pace (N25) and Tire (N26) carry embedded ECharts plots, and Radio (N29) and RAG (N30) dim when inactive.
PITWALL · DATA
A full-width status strip over two columns. Left: the twenty-row timing tower and the session bests. Right: a tab strip over TRACES (the own-car 2x2 telemetry grid, the track ring and the radio / RCM feed), RACE PACE (a lap-by-lap grid coloured by each lap's own ranking) and RACE TRACE (accumulated time against the leader, the field average or our own car).
Menu mode vs --viewer
Drop the --viewer flag and the arcade opens MenuView first:
python -m src.arcade.main --strategy
MenuView is a pure-keyboard navigator (Arrow keys + Enter, Escape to go back). It lists years (2023-2025), rounds per year, drivers, and teams. The --viewer shortcut exists for regression testing and for the "I know what I want" path.
Single-driver vs two-driver mode
Omit --driver2 and only the main driver renders on track and in the telemetry charts. The Delta trace in the telemetry window stays empty (no rival to compare against) and the Situation card focuses solely on safety-car probability.
Pass --driver2 LEC and:
- The rival icon appears on the track in the rival-team colour.
- The Delta plot renders the rolling gap between our driver and the rival.
- The Situation card gains the overtake-probability gauge driven by the N27 LightGBM model.
- The Pit card's undercut probability is computed against the rival.
Playback controls
Hotkeys handled by F1ArcadeView.on_key_press:
| Key | What it does |
|---|---|
Space |
pause / resume |
Left / Right |
hold to scrub backwards or forwards. Holding pauses playback; releasing restores whatever state was active before. Not a one-lap step |
Up / Down |
next / previous playback speed |
1 2 3 4 |
jump straight to 0.5x, 1x, 2x, 4x |
R |
restart: back to frame zero, default speed, playing |
D |
show / hide the DRS zones on the track |
B |
show / hide the progress bar |
A |
show / hide the eighteen non-featured cars |
C |
show / hide the controls list itself |
Escape |
close the window |
Escape quits rather than returning to the menu, and it does so whether or not
--viewer was used at launch.
The controls list collapses to a single C Controls line when the column above
it has no room. The list needs 158 px, and the left column leaves 263 at the
default 1280x720 whether one driver is followed or two, so the collapse fires
only on a window dragged below 615 px tall. C opens the list anyway
where it does not fit, on the grounds that a list you asked for is one you can
dismiss with the same key.
The telemetry under the weather card is one table with a column per driver. It used to be a card each, which repeated the same six labels under two headers and took 354 px of the column for twelve values; at the default height that left 146 px against a list needing 158, and the list drew over the second card.
The window has no minimum size, and below about 475 px tall the table reaches the collapsed hint line. Nothing collapses further at that point. Before the table replaced the two cards the same crossing happened at about 652.
Known limitations
- First-lap warmup: the orchestrator runs cold for the first ~15 seconds while agent models load.
- Cold FastF1 cache: the first time a given round is requested, FastF1 downloads the session. Expect roughly 30 seconds on cold cache.
- Port 9998: the TCP broadcaster binds
127.0.0.1:9998. If another process holds the port, the dashboard cannot connect. - Strategy mode requires year 2025: the multi-agent pipeline only ships with 2025-season features. Running
--strategyagainst 2023 or 2024 falls back to arcade-only replay.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
FileNotFoundError: data/raw/.../laps.parquet |
the race is not in the local cache | uv run python -c "from src.f1_strat_manager.data_cache import ensure_race; ensure_race(2025, 'Melbourne')", or just pick the race from the f1-strat menu, which calls the same function |
| "Backend offline" / "Connection refused" | Arcade did not start the stream server | Restart the arcade with --strategy |
| "OpenAI api_key missing" | .env missing or OPENAI_API_KEY unset |
Add the key to .env, or F1_LLM_PROVIDER=lmstudio |
| PITWALL renders but charts stay empty | First broadcast carries only the arcade frame | Per-agent outputs arrive on the second broadcast |
PITWALL needs its UI bundle on startup |
the React bundle was never built | npm ci && npm run build in src/pitwall/ui |
Related reading
- PITWALL windows, the two React surfaces and the client they share.
- Arcade dashboard (legacy), the retired PySide6 package PITWALL replaced.
- Arcade strategy pipeline, why the arcade delegates to the shared engine instead of keeping its own copy of the orchestrator.
- Multi-agent system: N25-N31 multi-agent pipeline reference.