# wvaske/hex-crawl-app architecture

> Architecture diagram of the GitHub repository wvaske/hex-crawl-app, 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/wvaske/hex-crawl-app
- Repository: https://github.com/wvaske/hex-crawl-app

## Overview

HexCrawl VTT is a self-hosted, real-time tabletop for wilderness exploration. A DM configures maps, terrain, clues, and encounters; players join through a shared link, claim characters, and travel. The server handles campaign commands and state synchronization, computes gated discoveries, and returns role-appropriate campaign state. The client renders the hex map and table panels. The README documents additional exploration and campaign features whose individual runtime wiring is not shown in the sampled source, so those links are left unspecified.

Main entry points: [`packages/server/src/http/app.ts`](https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/http/app.ts) (HTTP API), [`packages/server/src/state/runtime.ts`](https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/state/runtime.ts) (Campaign runtime), [`packages/client/src/ws.ts`](https://github.com/wvaske/hex-crawl-app/blob/main/packages/client/src/ws.ts) (WebSocket client), [`packages/server/src/ws/handlers.ts`](https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/ws/handlers.ts) (Command handlers)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_client["Web client"]
  node_webapp["Web app entry<br/>[main.tsx]"]
  node_campaigngate["Campaign access<br/>[CampaignGate.tsx]"]
  node_tableview["Table view<br/>[TableView.tsx]"]
  node_canvas["Hex map canvas<br/>[CanvasEngine.ts]"]
  node_panels["Table panels"]
  node_clientstate["Session state<br/>[session.ts]"]
  node_clientws["WebSocket client<br/>[ws.ts]"]
  node_clientapi["HTTP client<br/>[api.ts]"]
  node_pluginregistry["Plugin registry<br/>[registry.ts]"]
end

subgraph group_server["Server runtime"]
  node_http["HTTP API<br/>[app.ts]"]
  node_wshandlers["Command handlers<br/>[handlers.ts]"]
  node_hub["WebSocket hub<br/>[hub.ts]"]
  node_runtime["Campaign runtime<br/>[runtime.ts]"]
  node_store["State store<br/>[store.ts]"]
  node_db[("Persistent database<br/>[sqlite.ts]")]
  node_pluginhost["Plugin host<br/>[host.ts]"]
end

subgraph group_exploration["Exploration engines"]
  node_knowledge["Knowledge gates<br/>[knowledge.ts]"]
  node_deliver["Discovery delivery<br/>[deliver.ts]"]
  node_fog["Fog of war<br/>[fog.ts]"]
  node_trails["Trail discovery<br/>[trails.ts]"]
  node_encounters["Encounters<br/>[encounters.ts]"]
  node_timeweather["Time and weather<br/>[weather.ts]"]
end

subgraph group_shared["Shared domain"]
  node_sharedomain["Campaign model<br/>[domain.ts]"]
  node_route["Known-ground routing<br/>[route.ts]"]
end

subgraph group_extensions["Integrations"]
  node_mcp["MCP integration<br/>[hexcrawl-mcp.mjs]"]
end

node_dm(("DM"))
node_players(("Players"))

node_dm -->|"opens table"| node_webapp
node_players -->|"opens shared link"| node_webapp
node_webapp -->|"routes campaign"| node_campaigngate
node_campaigngate -->|"connects live"| node_clientws
node_campaigngate -->|"requests campaign"| node_clientapi
node_clientapi -->|"HTTP requests"| node_http
node_clientws -->|"WebSocket messages"| node_hub
node_hub -->|"dispatches commands"| node_wshandlers
node_wshandlers -->|"updates campaign"| node_runtime
node_http -->|"reads campaign"| node_store
node_wshandlers -->|"uses state"| node_store
node_store -->|"manages runtime"| node_runtime
node_store -->|"persists state"| node_db
node_http -->|"evaluates clues"| node_knowledge
node_http -->|"delivers discoveries"| node_deliver
node_http -->|"reads campaign"| node_runtime
node_wshandlers -->|"records travel"| node_runtime
node_runtime -->|"uses campaign model"| node_sharedomain
node_route -->|"uses hex model"| node_sharedomain
node_clientws -->|"applies snapshots"| node_clientstate
node_tableview -->|"reads session"| node_clientstate
node_tableview -->|"renders map"| node_canvas
node_tableview -->|"shows controls"| node_panels
node_canvas -->|"sends map actions"| node_clientws
node_panels -->|"sends commands"| node_clientws
node_mcp -.->|"calls integration API"| node_http
node_pluginhost -.->|"extends campaign"| node_runtime
node_pluginregistry -.->|"registers client plugins"| node_tableview

click node_webapp "https://github.com/wvaske/hex-crawl-app/blob/main/packages/client/src/main.tsx"
click node_campaigngate "https://github.com/wvaske/hex-crawl-app/blob/main/packages/client/src/views/CampaignGate.tsx"
click node_tableview "https://github.com/wvaske/hex-crawl-app/blob/main/packages/client/src/views/TableView.tsx"
click node_canvas "https://github.com/wvaske/hex-crawl-app/blob/main/packages/client/src/engine/CanvasEngine.ts"
click node_panels "https://github.com/wvaske/hex-crawl-app/tree/main/packages/client/src/components/panels"
click node_clientstate "https://github.com/wvaske/hex-crawl-app/blob/main/packages/client/src/stores/session.ts"
click node_clientws "https://github.com/wvaske/hex-crawl-app/blob/main/packages/client/src/ws.ts"
click node_clientapi "https://github.com/wvaske/hex-crawl-app/blob/main/packages/client/src/api.ts"
click node_http "https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/http/app.ts"
click node_wshandlers "https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/ws/handlers.ts"
click node_hub "https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/ws/hub.ts"
click node_runtime "https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/state/runtime.ts"
click node_store "https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/state/store.ts"
click node_db "https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/db/sqlite.ts"
click node_knowledge "https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/engine/knowledge.ts"
click node_deliver "https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/engine/deliver.ts"
click node_fog "https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/engine/fog.ts"
click node_trails "https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/engine/trails.ts"
click node_encounters "https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/engine/encounters.ts"
click node_timeweather "https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/engine/weather.ts"
click node_sharedomain "https://github.com/wvaske/hex-crawl-app/blob/main/packages/shared/src/domain.ts"
click node_route "https://github.com/wvaske/hex-crawl-app/blob/main/packages/shared/src/rules/route.ts"
click node_pluginhost "https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/plugins/host.ts"
click node_pluginregistry "https://github.com/wvaske/hex-crawl-app/blob/main/packages/client/src/plugins/registry.ts"
click node_mcp "https://github.com/wvaske/hex-crawl-app/blob/main/mcp/hexcrawl-mcp.mjs"

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_webapp,node_campaigngate,node_tableview,node_canvas,node_panels,node_clientstate,node_clientws,node_clientapi,node_pluginregistry toneBlue
class node_http,node_wshandlers,node_hub,node_runtime,node_store,node_db,node_pluginhost toneAmber
class node_knowledge,node_deliver,node_fog,node_trails,node_encounters,node_timeweather toneMint
class node_sharedomain,node_route toneRose
class node_mcp,node_dm,node_players toneIndigo
```

## Components

### Web client

- [Web app entry](https://github.com/wvaske/hex-crawl-app/blob/main/packages/client/src/main.tsx): `packages/client/src/main.tsx`
- [Campaign access](https://github.com/wvaske/hex-crawl-app/blob/main/packages/client/src/views/CampaignGate.tsx): `packages/client/src/views/CampaignGate.tsx`
- [Table view](https://github.com/wvaske/hex-crawl-app/blob/main/packages/client/src/views/TableView.tsx): `packages/client/src/views/TableView.tsx`
- [Hex map canvas](https://github.com/wvaske/hex-crawl-app/blob/main/packages/client/src/engine/CanvasEngine.ts): `packages/client/src/engine/CanvasEngine.ts`
- [Table panels](https://github.com/wvaske/hex-crawl-app/tree/main/packages/client/src/components/panels): `packages/client/src/components/panels`
- [Session state](https://github.com/wvaske/hex-crawl-app/blob/main/packages/client/src/stores/session.ts): `packages/client/src/stores/session.ts`
- [WebSocket client](https://github.com/wvaske/hex-crawl-app/blob/main/packages/client/src/ws.ts): `packages/client/src/ws.ts`
- [HTTP client](https://github.com/wvaske/hex-crawl-app/blob/main/packages/client/src/api.ts): `packages/client/src/api.ts`
- [Plugin registry](https://github.com/wvaske/hex-crawl-app/blob/main/packages/client/src/plugins/registry.ts): `packages/client/src/plugins/registry.ts`

### Server runtime

- [HTTP API](https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/http/app.ts): `packages/server/src/http/app.ts`
- [Command handlers](https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/ws/handlers.ts): `packages/server/src/ws/handlers.ts`
- [WebSocket hub](https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/ws/hub.ts): `packages/server/src/ws/hub.ts`
- [Campaign runtime](https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/state/runtime.ts): `packages/server/src/state/runtime.ts`
- [State store](https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/state/store.ts): `packages/server/src/state/store.ts`
- [Persistent database](https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/db/sqlite.ts): `packages/server/src/db/sqlite.ts`
- [Plugin host](https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/plugins/host.ts): `packages/server/src/plugins/host.ts`

### Exploration engines

- [Knowledge gates](https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/engine/knowledge.ts): `packages/server/src/engine/knowledge.ts`
- [Discovery delivery](https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/engine/deliver.ts): `packages/server/src/engine/deliver.ts`
- [Fog of war](https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/engine/fog.ts): `packages/server/src/engine/fog.ts`
- [Trail discovery](https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/engine/trails.ts): `packages/server/src/engine/trails.ts`
- [Encounters](https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/engine/encounters.ts): `packages/server/src/engine/encounters.ts`
- [Time and weather](https://github.com/wvaske/hex-crawl-app/blob/main/packages/server/src/engine/weather.ts): `packages/server/src/engine/weather.ts`

### Shared domain

- [Campaign model](https://github.com/wvaske/hex-crawl-app/blob/main/packages/shared/src/domain.ts): `packages/shared/src/domain.ts`
- [Known-ground routing](https://github.com/wvaske/hex-crawl-app/blob/main/packages/shared/src/rules/route.ts): `packages/shared/src/rules/route.ts`

### Integrations

- [MCP integration](https://github.com/wvaske/hex-crawl-app/blob/main/mcp/hexcrawl-mcp.mjs): `mcp/hexcrawl-mcp.mjs`

### Other components

- **DM**
- **Players**

## Connections

- DM → Web app entry: opens table
- Players → Web app entry: opens shared link
- Web app entry → Campaign access: routes campaign
- Campaign access → WebSocket client: connects live
- Campaign access → HTTP client: requests campaign
- HTTP client → HTTP API: HTTP requests
- WebSocket client → WebSocket hub: WebSocket messages
- WebSocket hub → Command handlers: dispatches commands
- Command handlers → Campaign runtime: updates campaign
- HTTP API → State store: reads campaign
- Command handlers → State store: uses state
- State store → Campaign runtime: manages runtime
- State store → Persistent database: persists state
- HTTP API → Knowledge gates: evaluates clues
- HTTP API → Discovery delivery: delivers discoveries
- HTTP API → Campaign runtime: reads campaign
- Command handlers → Campaign runtime: records travel
- Campaign runtime → Campaign model: uses campaign model
- Known-ground routing → Campaign model: uses hex model
- WebSocket client → Session state: applies snapshots
- Table view → Session state: reads session
- Table view → Hex map canvas: renders map
- Table view → Table panels: shows controls
- Hex map canvas → WebSocket client: sends map actions
- Table panels → WebSocket client: sends commands
- MCP integration → HTTP API: calls integration API
- Plugin host → Campaign runtime: extends campaign
- Plugin registry → Table view: registers client plugins
