# hp6/ai-arena architecture

> Architecture diagram of the GitHub repository hp6/ai-arena, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-29). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/hp6/ai-arena
- Repository: https://github.com/hp6/ai-arena

## Overview

Tiny AI Arena is a browser-based spectator and replay app for four-model battles on an 8×8 grid. A spectator starts a match from the menu; the API starts a background game loop, which requests model actions, validates and resolves turns, and saves frames for live viewing and later replay. The client also presents leaderboard and match history, while recorded matches can be exported for offline static viewing. The graph follows sampled call sites and README-documented features; unsampled internals are represented only where their paths are supported by the tree.

Main entry points: [`server/src/game/GameRunner.ts`](https://github.com/hp6/ai-arena/blob/master/server/src/game/GameRunner.ts) (Game loop), [`server/src/db/database.ts`](https://github.com/hp6/ai-arena/blob/master/server/src/db/database.ts) (SQLite records), [`client/src/scenes/ArenaScene.ts`](https://github.com/hp6/ai-arena/blob/master/client/src/scenes/ArenaScene.ts) (Replay scene), [`server/src/ai/OpenRouterClient.ts`](https://github.com/hp6/ai-arena/blob/master/server/src/ai/OpenRouterClient.ts) (OpenRouter client)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_web["Spectator client"]
  node_client_entry["Client startup<br/>[main.ts]"]
  node_app_shell["App shell<br/>[AppShell.ts]"]
  node_menu["Menu and stats<br/>[MenuView.ts]"]
  node_arena_scene["Replay scene<br/>[ArenaScene.ts]"]
  node_arena_render["Arena renderer<br/>[Arena.ts]"]
  node_fighter_render["Fighter renderer<br/>[Fighter.ts]"]
  node_hud["Arena HUD<br/>[ArenaHud.ts]"]
  node_client_api["API URLs<br/>[api.ts]"]
end

subgraph group_server["Match server"]
  node_server_entry["Server startup<br/>[index.ts]"]
  node_game_routes["Game API<br/>[game.ts]"]
  node_stats["Leaderboard stats<br/>[stats.ts]"]
  node_exporter["Replay export<br/>[export.ts]"]
end

subgraph group_domain["Game and AI"]
  node_runner["Game loop<br/>[GameRunner.ts]"]
  node_game_state["Game setup<br/>[GameState.ts]"]
  node_validator["Action referee<br/>[MoveValidator.ts]"]
  node_combat["Combat resolver<br/>[CombatResolver.ts]"]
  node_agent_config["Model roster<br/>[AgentConfig.ts]"]
  node_prompt["Prompt builder<br/>[PromptBuilder.ts]"]
  node_move_schema["Move schema<br/>[MoveSchema.ts]"]
  node_ai_client["OpenRouter client"]
  node_shared["Shared game types<br/>[index.ts]"]
end

subgraph group_records["Match records"]
  node_database[("SQLite records<br/>[database.ts]")]
end

node_spectator(("Spectator"))
node_server_actor(("HTTP client"))
node_model_service{{"OpenRouter"}}
node_sqlite[("Arena database")]

node_spectator -->|"uses"| node_menu
node_client_entry -->|"creates"| node_app_shell
node_app_shell -->|"shows"| node_menu
node_app_shell -->|"switches to"| node_arena_scene
node_menu -->|"requests stats"| node_client_api
node_menu -->|"selects match"| node_arena_scene
node_arena_scene -->|"requests game data"| node_client_api
node_arena_scene -->|"renders board"| node_arena_render
node_arena_scene -->|"renders fighters"| node_fighter_render
node_arena_scene -->|"updates display"| node_hud
node_client_api -->|"sends requests"| node_server_actor
node_server_actor -->|"calls API"| node_server_entry
node_server_entry -->|"mounts routes"| node_game_routes
node_server_entry -->|"computes stats"| node_stats
node_game_routes -->|"starts match"| node_runner
node_game_routes -->|"reads records"| node_database
node_runner -->|"creates state"| node_game_state
node_runner -->|"selects models"| node_agent_config
node_runner -->|"requests moves"| node_ai_client
node_runner -->|"validates actions"| node_validator
node_runner -->|"resolves attacks"| node_combat
node_runner -->|"writes frames"| node_database
node_ai_client -->|"builds prompts"| node_prompt
node_ai_client -->|"formats moves"| node_move_schema
node_ai_client -->|"requests completion"| node_model_service
node_ai_client -->|"logs calls"| node_database
node_server_entry -->|"initializes records"| node_database
node_stats -->|"reads match data"| node_database
node_exporter -->|"exports matches"| node_database
node_database -->|"reads and writes"| node_sqlite
node_shared -.->|"defines game types"| node_runner

click node_client_entry "https://github.com/hp6/ai-arena/blob/master/client/src/main.ts"
click node_app_shell "https://github.com/hp6/ai-arena/blob/master/client/src/ui/AppShell.ts"
click node_menu "https://github.com/hp6/ai-arena/blob/master/client/src/ui/MenuView.ts"
click node_arena_scene "https://github.com/hp6/ai-arena/blob/master/client/src/scenes/ArenaScene.ts"
click node_arena_render "https://github.com/hp6/ai-arena/blob/master/client/src/objects/Arena.ts"
click node_fighter_render "https://github.com/hp6/ai-arena/blob/master/client/src/objects/Fighter.ts"
click node_hud "https://github.com/hp6/ai-arena/blob/master/client/src/ui/ArenaHud.ts"
click node_client_api "https://github.com/hp6/ai-arena/blob/master/client/src/utils/api.ts"
click node_server_entry "https://github.com/hp6/ai-arena/blob/master/server/src/index.ts"
click node_game_routes "https://github.com/hp6/ai-arena/blob/master/server/src/routes/game.ts"
click node_stats "https://github.com/hp6/ai-arena/blob/master/server/src/stats.ts"
click node_exporter "https://github.com/hp6/ai-arena/blob/master/server/src/export.ts"
click node_runner "https://github.com/hp6/ai-arena/blob/master/server/src/game/GameRunner.ts"
click node_game_state "https://github.com/hp6/ai-arena/blob/master/server/src/game/GameState.ts"
click node_validator "https://github.com/hp6/ai-arena/blob/master/server/src/game/MoveValidator.ts"
click node_combat "https://github.com/hp6/ai-arena/blob/master/server/src/game/CombatResolver.ts"
click node_agent_config "https://github.com/hp6/ai-arena/blob/master/server/src/ai/AgentConfig.ts"
click node_prompt "https://github.com/hp6/ai-arena/blob/master/server/src/ai/PromptBuilder.ts"
click node_move_schema "https://github.com/hp6/ai-arena/blob/master/server/src/ai/MoveSchema.ts"
click node_ai_client "https://github.com/hp6/ai-arena/blob/master/server/src/ai/OpenRouterClient.ts"
click node_shared "https://github.com/hp6/ai-arena/blob/master/shared/src/index.ts"
click node_database "https://github.com/hp6/ai-arena/blob/master/server/src/db/database.ts"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_client_entry,node_app_shell,node_menu,node_arena_scene,node_arena_render,node_fighter_render,node_hud,node_client_api,node_server_actor toneBlue
class node_server_entry,node_game_routes,node_stats,node_exporter,node_sqlite toneAmber
class node_runner,node_game_state,node_validator,node_combat,node_agent_config,node_prompt,node_move_schema,node_ai_client,node_shared,node_model_service toneMint
class node_database toneRose
class node_spectator toneIndigo
```

## Components

### Spectator client

- [Client startup](https://github.com/hp6/ai-arena/blob/master/client/src/main.ts): `client/src/main.ts`
- [App shell](https://github.com/hp6/ai-arena/blob/master/client/src/ui/AppShell.ts): `client/src/ui/AppShell.ts`
- [Menu and stats](https://github.com/hp6/ai-arena/blob/master/client/src/ui/MenuView.ts): `client/src/ui/MenuView.ts`
- [Replay scene](https://github.com/hp6/ai-arena/blob/master/client/src/scenes/ArenaScene.ts): `client/src/scenes/ArenaScene.ts`
- [Arena renderer](https://github.com/hp6/ai-arena/blob/master/client/src/objects/Arena.ts): `client/src/objects/Arena.ts`
- [Fighter renderer](https://github.com/hp6/ai-arena/blob/master/client/src/objects/Fighter.ts): `client/src/objects/Fighter.ts`
- [Arena HUD](https://github.com/hp6/ai-arena/blob/master/client/src/ui/ArenaHud.ts): `client/src/ui/ArenaHud.ts`
- [API URLs](https://github.com/hp6/ai-arena/blob/master/client/src/utils/api.ts): `client/src/utils/api.ts`

### Match server

- [Server startup](https://github.com/hp6/ai-arena/blob/master/server/src/index.ts): `server/src/index.ts`
- [Game API](https://github.com/hp6/ai-arena/blob/master/server/src/routes/game.ts): `server/src/routes/game.ts`
- [Leaderboard stats](https://github.com/hp6/ai-arena/blob/master/server/src/stats.ts): `server/src/stats.ts`
- [Replay export](https://github.com/hp6/ai-arena/blob/master/server/src/export.ts): `server/src/export.ts`

### Game and AI

- [Game loop](https://github.com/hp6/ai-arena/blob/master/server/src/game/GameRunner.ts): `server/src/game/GameRunner.ts`
- [Game setup](https://github.com/hp6/ai-arena/blob/master/server/src/game/GameState.ts): `server/src/game/GameState.ts`
- [Action referee](https://github.com/hp6/ai-arena/blob/master/server/src/game/MoveValidator.ts): `server/src/game/MoveValidator.ts`
- [Combat resolver](https://github.com/hp6/ai-arena/blob/master/server/src/game/CombatResolver.ts): `server/src/game/CombatResolver.ts`
- [Model roster](https://github.com/hp6/ai-arena/blob/master/server/src/ai/AgentConfig.ts): `server/src/ai/AgentConfig.ts`
- [Prompt builder](https://github.com/hp6/ai-arena/blob/master/server/src/ai/PromptBuilder.ts): `server/src/ai/PromptBuilder.ts`
- [Move schema](https://github.com/hp6/ai-arena/blob/master/server/src/ai/MoveSchema.ts): `server/src/ai/MoveSchema.ts`
- [OpenRouter client](https://github.com/hp6/ai-arena/blob/master/server/src/ai/OpenRouterClient.ts): `server/src/ai/OpenRouterClient.ts`
- [Shared game types](https://github.com/hp6/ai-arena/blob/master/shared/src/index.ts): `shared/src/index.ts`

### Match records

- [SQLite records](https://github.com/hp6/ai-arena/blob/master/server/src/db/database.ts): `server/src/db/database.ts`

### Other components

- **Spectator**
- **HTTP client**
- **OpenRouter**
- **Arena database**

## Connections

- Spectator → Menu and stats: uses
- Client startup → App shell: creates
- App shell → Menu and stats: shows
- App shell → Replay scene: switches to
- Menu and stats → API URLs: requests stats
- Menu and stats → Replay scene: selects match
- Replay scene → API URLs: requests game data
- Replay scene → Arena renderer: renders board
- Replay scene → Fighter renderer: renders fighters
- Replay scene → Arena HUD: updates display
- API URLs → HTTP client: sends requests
- HTTP client → Server startup: calls API
- Server startup → Game API: mounts routes
- Server startup → Leaderboard stats: computes stats
- Game API → Game loop: starts match
- Game API → SQLite records: reads records
- Game loop → Game setup: creates state
- Game loop → Model roster: selects models
- Game loop → OpenRouter client: requests moves
- Game loop → Action referee: validates actions
- Game loop → Combat resolver: resolves attacks
- Game loop → SQLite records: writes frames
- OpenRouter client → Prompt builder: builds prompts
- OpenRouter client → Move schema: formats moves
- OpenRouter client → OpenRouter: requests completion
- OpenRouter client → SQLite records: logs calls
- Server startup → SQLite records: initializes records
- Leaderboard stats → SQLite records: reads match data
- Replay export → SQLite records: exports matches
- SQLite records → Arena database: reads and writes
- Shared game types → Game loop: defines game types
