Skip to content

About

Apex Arena is an AI-powered Formula 1 fan experience that turns live and historical race data into interactive race rooms, automated commentary, telemetry-driven insights, and replayable event discussions.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Apex Arena

Formula racing, interpreted live.

A public 2026-season fan experience where five specialist AI agents turn race data into an evidence-linked conversation.

Version Verify and publish Backend image Frontend image License

Apex Arena landing experience

The race is more than a timing screen

Apex Arena follows Formula racing as a living argument. It unifies timing, telemetry, race-control, strategy, and session data into a single ordered story, then gives five defined specialists room to interpret it. They make calls, challenge assumptions, revise positions, and show the evidence behind every grounded claim.

The result feels closer to a great post-race debrief unfolding in real time than a conventional dashboard.

What makes Apex Arena different

  • Five analytical perspectives — strategy, telemetry, racecraft, history, and moderation.
  • Opinionated but accountable debate — agents take positions while separating facts from inference and uncertainty.
  • Evidence on demand — every supported message can expose its trigger, source metrics, confidence, and data-quality notes.
  • Agents with memory — a read offered at lap 15 is recalled and revised out loud when the evidence behind it moves, rather than quietly disappearing.
  • Deterministic race intelligence — battles, tyre and stint context, pit windows, undercut and overcut conditions and weather changes are derived from source facts before anything is written about them.
  • Fan and Analyst modes — one room, two depths: a plain-language read of what is happening and why it matters, or the full evidence, units, assumptions and limitations behind it.
  • Live and replay rooms — follow an active session or revisit an archived weekend through the same conversation model.
  • Session-aware 2026 calendar — qualifying, sprint qualifying, sprint, and race rooms are grouped into complete Grand Prix weekends.
  • Accurate circuit artwork — 2026 layouts are sourced from Jules Roy's f1-circuits-svg archive.
  • Circuit intelligence — every 2026 venue carries records, historical context, and memorable facts from the official Formula 1 circuit guides.
  • Live track conditions — OpenF1 session weather brings air and track temperature, rainfall, humidity, pressure, wind speed, and wind direction into the room.
  • Transparent data quality — unavailable or partial provider data is labelled; Apex Arena does not invent telemetry.
  • Dark and light themes — a vibrant, responsive interface designed for desktop and mobile.

The 2026 season, session by session

Apex Arena Race Rooms catalog

The Race Rooms catalog turns the season into an editorial archive. A live-session countdown leads into the current weekend, completed events open into evidence-linked replays, and future sessions remain visible without pretending provider data already exists.

Visitors can filter by:

  • Grand Prix, circuit, or country
  • live, completed, or upcoming weekends
  • qualifying, sprint qualifying, sprint, or race
  • standard and sprint-weekend formats

Inside a Race Room

Apex Arena circuit records and OpenF1 weather

Each room brings together four connected surfaces:

  1. Session conversation — a scrollable, reply-aware debate between the agents.
  2. Conversation map — key moments arranged across the session timeline.
  3. Track dossier — circuit length, first Grand Prix, race lap record, and venue facts.
  4. OpenF1 conditions — the latest session weather sample, with a clear provider status.

The circuit and weather panels are deliberately resilient. Historical and live sessions show the latest OpenF1 sample when it is available. Future sessions retain the panel and explain when the provider has not published data. A weather-provider interruption never takes the race room offline.

Meet the room

Agent Lens What they bring to the debate
Mira Vale Race strategy Pit windows, tyre life, traffic, undercuts, and strategic trade-offs
Theo Voss Telemetry Lap deltas, sector trends, consistency, and measured pace claims
Lena Cross Racecraft Overtakes, defensive driving, incidents, and track-position battles
Arjun Reyes Championship history Season form, circuit precedent, records, and historical context
Nova Room host Moderation, evidence quality, uncertainty, and room verdicts

Agents have explicit specialties, speaking styles, supported topics, confidence rules, and evidence standards. Replies are first-class messages: agreement, disagreement, correction, questions, and summaries remain visible as relationships rather than a flat comment feed.

Circuit intelligence and weather

Apex Arena V1 ships a verified dossier for every circuit in its 22-event 2026 catalog. Circuit profiles include:

  • circuit length
  • first Formula 1 Grand Prix
  • current race lap record and holder
  • two venue-specific facts
  • a link to the official Formula 1 circuit guide

Weather is fetched through the OpenF1 /v1/weather endpoint using the room's session key. The backend selects the latest sample and safely normalizes:

Measurement Display
Air temperature °C
Track temperature °C
Rainfall detected / none
Humidity percent
Atmospheric pressure mbar
Wind speed m/s
Wind direction compass point and degrees

Provider failures, empty responses, malformed samples, and sessions without a provider key all have tested fallback states.

2026 championship standings

/standings presents the current drivers' and constructors' championships without embedding any season results in the frontend. The backend builds a provider-neutral snapshot from OpenF1's championship and driver metadata endpoints, then enriches it with season-wide Jolpica race, qualifying, sprint, identity, and calendar data. Jolpica standings are also the fallback when an OpenF1 championship snapshot is unavailable.

The public endpoints are:

  • GET /api/v1/championship/drivers
  • GET /api/v1/championship/constructors
  • GET /api/v1/championship/summary

Driver statistics include wins, podiums, top-five and top-ten finishes, classified finishes, DNFs, DSQs, fastest laps, grid and qualifying averages, Q3 appearances, sprint performance, points per race, position gain/loss, and latest-event championship movement where the source data supports the metric. Constructor statistics aggregate race, qualifying, and sprint results without counting an event once per driver; the response also includes the current driver pairing and points contributions.

Redis caches the three normalized responses for ten minutes during normal periods and 30 seconds during a live event. A seven-day last_available snapshot allows the API and UI to degrade to the last known standings when a provider refresh fails. Normalized session-finish and result events invalidate the current cache keys while retaining that fallback. Response metadata reports the season, source, generation time, cache age, latest completed event, race counts, and whether the snapshot is live, provisional, or stale. The UI polls in the background every five minutes normally and every 20 seconds while an event is live; provisional data is explicitly labelled LIVE / PROVISIONAL and returns to CURRENT STANDINGS once official event results are available.

Data architecture

flowchart LR
    A[OpenF1 REST + live feed] --> D[Ingestion and normalization]
    B[Jolpica season calendar] --> C[Session catalog]
    C --> D
    D --> E[(PostgreSQL event archive)]
    D --> F[(Redis event bus)]
    E --> G[Race state + replay engine]
    F --> G
    G --> K[Battle + strategy intelligence]
    K --> L[Event importance]
    L --> H[Discussion engine]
    H --> M[Agent claim memory]
    H --> N{Generation opted in?}
    N -- no --> I[Evidence-linked Race Room API]
    N -- yes --> O[Language provider] --> I
    I --> J[Next.js Fan and Analyst experience]
Loading

Facts flow left to right and never depend on anything to their right. Language generation sits at the far end on purpose: it can only rephrase a conclusion the deterministic layer already reached, and when it is off, failing or over budget the room publishes that conclusion verbatim.

Backend

  • FastAPI and Pydantic contracts
  • asynchronous SQLAlchemy with PostgreSQL
  • Redis-backed event streaming
  • OpenF1 REST and MQTT provider clients
  • Jolpica season-calendar synchronization
  • deterministic normalization, ordering, and deduplication
  • race-state snapshots and replay coordination
  • guarded critical projection committing derived rows, snapshot and progress as one unit
  • bounded evidence-addressable lap, stint, pit, weather and control history
  • deterministic battle, tyre and strategy intelligence with explicit uncertainty
  • bounded agent claim memory with cursor-bounded recall
  • evidence-linked multi-agent discussion engine
  • optional language generation behind budgets, a kill switch and deterministic fallback

Frontend

  • Next.js App Router
  • React and TypeScript
  • accessible, theme-aware component system
  • live Server-Sent Events room updates
  • grouped session catalog and countdown experience
  • replay controls, message filters, evidence drawer, and conversation map
  • Fan and Analyst modes over one shared evidence model
  • driver telemetry comparison drawn as inline SVG, with no charting dependency
  • official 2026 circuit artwork with responsive rendering

Race intelligence engines

Every conclusion the product presents is derived deterministically from stored source facts first. Language is applied afterwards, or not at all.

Battle engine

Battles are detected from observed proximity, position and interval facts, then enriched with the context that makes them worth watching: tyre compounds and ages, relative pace over comparable clean laps, how long the fight has run, whether the gap is closing, whether the drivers are team-mates, and multi-car trains.

Two distinctions are deliberate and load-bearing:

  • Proximity is not DRS usage. Being within a second is a position, and DRS permission is a track state. Only an observed open rear wing is evidence that DRS was used.
  • Attempt and championship context are reported as undetermined, not as "no attempts" or "not championship relevant". The system cannot currently establish either, and saying so is different from asserting the negative.

Strategy engine

Eight situation families are derived where, and only where, evidence supports them: stint divergence, relative pace, pit window, undercut condition, overcut condition, neutralized pit context, extra-stop consequence and weather change.

Each carries the evidence behind it, its assumptions, its limitations and an availability of available, partial or unavailable. Capabilities the session cannot support are published with the reason, so the interface can show what the system cannot determine rather than an empty panel.

Pace uses comparable green-flag samples with pit, neutralized, deleted and outlier laps excluded. Pit loss is an observed same-driver baseline, not a circuit constant. Tyre degradation is treated as uncertain rather than linear, and no situation claims a predicted outcome.

Agent architecture

Five specialists react to events that clear an importance threshold; routine timing samples never reach the discussion engine at all.

Messages are generated deterministically and validated for grounding before publication. An agent records the position a strategy observation commits it to, and when that observation is later revised or withdrawn it says so — replying to its own earlier message. Recall is cut to the consumed source cursor, so a replay seek backwards cannot surface a position the viewer has not reached, and memory is scoped to the discussion generation so a reset starts clean.

Language generation is optional, off by default, and requires AI_GENERATION_OPT_IN explicitly. AI_ENABLED and a stored API key are deliberately not sufficient, because both predate any working generation path and an upgrade must not start billable traffic. Generation runs after grounding validation, so it can only change how a supported claim reads, never what it asserts.

Testing

# Backend, from backend/
python -m pytest -q
python -m ruff check .
python -m ruff format --check .

# Frontend, from frontend/
npm run lint
npm run typecheck
npm test
npm run build

Most of the suite is hermetic. Integration coverage that needs real infrastructure is opt-in and gated behind environment variables, so it skips rather than failing on a machine without it:

Variable Enables
TEST_INGESTION_POSTGRES_URL Guarded projection, history checkpoint and lifecycle SQL coverage
TEST_REPLAY_POSTGRES_URL Replay ownership, lease fencing and claim-memory coverage
LIVE_REPAIR_INTEGRATION=1 Live pipeline and Redis rate-limit coverage
TEST_E2E_DATABASE_URL E2E room seeding against an isolated apex_e2e* database

Each of these must point at a disposable local database. The tests validate the target and refuse to run against anything else.

The browser suite runs against freshly built production images in a self-contained stack with a synthetic provider, so it does not depend on a real Grand Prix taking place:

cp scripts/e2e.env.example .env.e2e.local   # then set a unique COMPOSE_PROJECT_NAME
docker compose --env-file .env.e2e.local -f docker-compose.e2e.yml up -d --build --wait
docker compose --env-file .env.e2e.local -f docker-compose.e2e.yml exec -T backend \
  python -m app.cli.seed_e2e_room --scenario normal-race --slug e2e-normal-race
docker compose --env-file .env.e2e.local -f docker-compose.e2e.yml run --build --rm browser-tests
docker compose --env-file .env.e2e.local -f docker-compose.e2e.yml down --volumes

Mobile and native clients

The race domain is server-side, and the API is designed so a native client renders state rather than re-deriving race meaning. docs/native-client-contracts.md documents the versioning rules, authentication boundaries, endpoints, SSE event names and resumption semantics, the error contract, and the data honesty rules a client must preserve.

No native application exists in this repository, and none is required — the contract is the deliverable.

Known limitations

Stated plainly, because the product's core claim is that it does not sound more certain than its data:

  • Overtake attempts and championship relevance are not established. Battle context reports both as undetermined.
  • Provider lap-start timing is approximate. Lap intervals derived from it are labelled as such.
  • Tyre degradation is not predicted. Stint context describes what was observed; it does not forecast a crossover.
  • Only one browser scenario is seeded. The normal-race fixture drives the E2E suite; sprint, red-flag and wet-weather paths are covered by backend tests rather than browser runs.
  • Historical projections written before the current semantic identity are readable but explicitly unverified. They are never silently adopted or rewritten.
  • Language generation has not been exercised against a real provider. All generation coverage uses fake providers, by design — the suite cannot make a paid call.
  • A session with no retained car data has no telemetry trace. The endpoint reports this rather than interpolating one.

Data integrity principles

Apex Arena is designed around a simple rule: the interface must never sound more certain than the data.

  • Raw provider events are preserved before normalization.
  • Normalized events have stable ordering and deduplication keys.
  • Messages carry confidence and evidence-availability states.
  • Partial telemetry narrows agent conclusions.
  • Results-only rooms do not manufacture lap-by-lap analysis.
  • Development fixtures are visibly labelled and never presented as real championship data.
  • Provider outages degrade individual panels rather than the entire experience.

Public API surface

The V1 API is organized around stable public resources:

Area Responsibility
Health application and dependency readiness
Calendar authoritative 2026 season summary
Event weekends grouped Grand Prix and session catalog
Race rooms room metadata, circuit dossier, weather, and playback state
Messages filtered conversation and pagination
Evidence source metrics, trigger events, and data-quality flags
Streaming live room messages and session events over SSE
Replay start, pause, resume, speed, lap, phase, and sequence control
Championship normalized 2026 driver, constructor, and title-battle standings
Factual history cursor-bounded lap, stint, pit, weather and control detail
Telemetry history bounded car-data series for up to two drivers, with per-channel coverage

Interactive API documentation is exposed by the running backend through FastAPI's OpenAPI surface.

V1 release pipeline

Version 1.0.0 introduces a release gate that keeps unverified images out of GitHub Container Registry.

Every pull request, main update, and version tag must pass:

  • backend formatting and lint checks
  • the complete backend test suite
  • frontend linting and TypeScript checks
  • the complete frontend component test suite
  • a production Next.js build
  • production backend and frontend Docker builds
  • critical-vulnerability scans for both images

Only verified builds can publish images. Version tags publish multi-platform release images:

  • ghcr.io/csingh26/apex-arena-backend
  • ghcr.io/csingh26/apex-arena-frontend

Published release images receive semantic-version, major/minor, major, latest, and commit-SHA tags. The same verified publish matrix also publishes multi-platform backend release artifacts after the full main workflow succeeds:

  • ghcr.io/csingh26/apex-arena-backend:main
  • ghcr.io/csingh26/apex-arena-backend:<full-commit-sha>

Railway deploys from the GitHub-connected main branch. The container tags remain available as verified release artifacts and exact rollback references; publishing them does not trigger a second Railway deployment.

Deployment

Apex Arena runs in production at https://chaitanyasingh.org/apex-arena.

The public domain belongs to the portfolio project, which rewrites /apex-arena/* to the Apex Arena frontend on Vercel. The frontend proxies API calls server-side to the FastAPI backend on Railway, which reads from Neon PostgreSQL and Upstash Redis. No infrastructure hostname is ever exposed to the browser.

main is the canonical deployment source branch. The backend supports three process roles:

  • api — serves HTTP and SSE only.
  • ingestor — owns OpenF1 worker duties behind a singleton advisory lease.
  • combined — serves the API and runs narrowly scoped worker duties in one process.

For the next deployment pass, Apex Arena is prepared around one combined backend service from main, with OPENF1_INGESTION_MODE=rest, live MQTT off, and recent-session reconciliation on. Full-season historical backfill remains manual-only; automatic recovery is limited to recently completed competitive sessions after OpenF1 publishes real data.

Backend deployment is automatic after a normal push to GitHub: Railway observes main, reads the tracked service manifest, builds, and deploys. The repository intentionally has no Railway CLI deploy wrapper or GitHub Actions job that uploads the same source a second time.

Deployment documentation

Local development URL

The mount point is controlled by a single variable, NEXT_PUBLIC_APP_BASE_PATH, from which next.config.ts derives the Next.js basePath. This changes where the development server serves the application:

NEXT_PUBLIC_APP_BASE_PATH Local URL Notes
unset (or empty) http://localhost:3000 The app is served at the origin root. Convenient for day-to-day local work
/apex-arena http://localhost:3000/apex-arena Mirrors production. http://localhost:3000 itself returns 404 — this is correct, not a broken build

Production always uses the prefixed form, because Apex Arena is mounted beneath the portfolio domain rather than served from its own root. If you are testing anything that depends on URL construction — canonical tags, Open Graph metadata, share links, the API prefix, or the static asset path — run locally with NEXT_PUBLIC_APP_BASE_PATH=/apex-arena so the local URLs match production. Note that the browser-facing API prefix follows the base path: it defaults to <base path>/api, and can be overridden with NEXT_PUBLIC_API_BASE_PATH.

Project documentation

Attribution

  • Timing, telemetry, session, and weather data are provided by OpenF1.
  • Season calendar metadata is sourced through Jolpica F1.
  • Circuit artwork is adapted from julesr0y/f1-circuits-svg, licensed CC BY 4.0.
  • Circuit records and venue facts link to the corresponding official Formula 1 circuit guides.

License and disclaimer

Apex Arena source code is licensed under GNU Affero General Public License v3.0 only. See NOTICE and COPYRIGHT for attribution details.

Apex Arena is an independent, unofficial fan project. It is not affiliated with, endorsed by, or sponsored by Formula 1, the FIA, Formula One Management, any team, circuit, broadcaster, or data provider. Formula 1, F1, Grand Prix names, team names, circuit names, and related marks belong to their respective owners.

About

Apex Arena is an AI-powered Formula 1 fan experience that turns live and historical race data into interactive race rooms, automated commentary, telemetry-driven insights, and replayable event discussions.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages