# lqf0624/fm-tactics-lab architecture

> Architecture diagram of the GitHub repository lqf0624/fm-tactics-lab, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-11-15). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/lqf0624/fm-tactics-lab
- Repository: https://github.com/lqf0624/fm-tactics-lab

## Overview

FM Tactics Lab is a Windows desktop workbench for running repeatable tactical experiments with the local FM27 match engine. The main workflow is to prepare teams and tactics, run seeded matches (optionally in batches or A/B rounds), then compare validated match statistics. Save-backed opponent selection and tactical-plan generation add a separate research path; tactics, set pieces, attribute experiments, and local history broaden the product. The README documents the product flow; sampled code confirms key API, save-reader, and batch-runner responsibilities, but not every subsystem connection.

Main entry points: [`src/desktop_save_mode.py`](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/desktop_save_mode.py) (Save import), [`src/fm27_tactics_server.py`](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/fm27_tactics_server.py) (Tactics API), [`src/desktop_warm_batch.py`](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/desktop_warm_batch.py) (Warm batch runner), [`native/desktop_host.cpp`](https://github.com/lqf0624/fm-tactics-lab/blob/main/native/desktop_host.cpp) (Native engine host)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_desktop["Desktop experience"]
  node_desktop_ui["Tactics workspace<br/>[app.js]"]
  node_desktop_host["Desktop host<br/>[main.rs]"]
  node_api["Tactics API"]
end

subgraph group_experiments["Match experiments"]
  node_scenario["Team scenarios"]
  node_batch["Batch experiments<br/>[fm27_batch.py]"]
  node_runner["Warm batch runner"]
  node_results["Match results"]
  node_storage[("Experiment storage<br/>[desktop_storage.py]")]
  node_attribute_lab["Attribute experiments"]
end

subgraph group_save_research["Save research"]
  node_save_import["Save import"]
  node_save_reader["Save reader"]
  node_opponents["Opponent selection"]
  node_coach_plans["Coach preset plans"]
  node_real_generation["Real AI plans"]
end

subgraph group_tactics["Tactical inputs"]
  node_fmf["FMF tactic import<br/>[fm27_fmf.py]"]
  node_tactic_pool[("Opponent tactic pool")]
  node_setpieces["Set-piece plans<br/>[fm27_setpieces.py]"]
  node_execution["Execution settings"]
end

subgraph group_engine_runtime["Engine runtime"]
  node_simulator["Match simulator<br/>[fm27_simulator.py]"]
  node_native_host["Native engine host<br/>[desktop_host.cpp]"]
  node_fm_engine["Local FM27 engine"]
end

node_user(("Experimenter"))

node_user -->|"edits and runs"| node_desktop_ui
node_desktop_ui -->|"uses desktop app"| node_desktop_host
node_desktop_host -->|"pipes requests"| node_api
node_api -->|"validates inputs"| node_scenario
node_api -->|"dispatches runs"| node_batch
node_batch -->|"uses warm runner"| node_runner
node_runner -->|"runs matches"| node_simulator
node_simulator -.->|"invokes host"| node_native_host
node_native_host -->|"loads engine"| node_fm_engine
node_native_host -->|"collects statistics"| node_results
node_runner -->|"records outcomes"| node_results
node_runner -->|"persists batches"| node_storage
node_api -->|"serves save mode"| node_save_import
node_save_import -->|"starts reader"| node_save_reader
node_save_import -->|"selects opponents"| node_opponents
node_save_import -->|"uses coach plans"| node_coach_plans
node_save_import -->|"prepares AI plans"| node_real_generation
node_user -->|"imports tactics"| node_fmf
node_fmf -->|"configures teams"| node_scenario
node_user -->|"manages candidates"| node_tactic_pool
node_scenario -->|"includes set pieces"| node_setpieces
node_scenario -->|"sets execution"| node_execution
node_user -->|"tests attributes"| node_attribute_lab
node_attribute_lab -->|"compares matches"| node_simulator

click node_desktop_ui "https://github.com/lqf0624/fm-tactics-lab/blob/main/src/tactics_ui/app.js"
click node_desktop_host "https://github.com/lqf0624/fm-tactics-lab/blob/main/tauri/src/main.rs"
click node_api "https://github.com/lqf0624/fm-tactics-lab/blob/main/src/fm27_tactics_server.py"
click node_scenario "https://github.com/lqf0624/fm-tactics-lab/blob/main/src/fm27_tactics_server.py"
click node_batch "https://github.com/lqf0624/fm-tactics-lab/blob/main/src/fm27_batch.py"
click node_runner "https://github.com/lqf0624/fm-tactics-lab/blob/main/src/desktop_warm_batch.py"
click node_results "https://github.com/lqf0624/fm-tactics-lab/blob/main/native/native_statistics.h"
click node_storage "https://github.com/lqf0624/fm-tactics-lab/blob/main/src/desktop_storage.py"
click node_save_import "https://github.com/lqf0624/fm-tactics-lab/blob/main/src/desktop_save_mode.py"
click node_save_reader "https://github.com/lqf0624/fm-tactics-lab/blob/main/src/desktop_save_worker.py"
click node_opponents "https://github.com/lqf0624/fm-tactics-lab/blob/main/src/desktop_opponent_scope.py"
click node_coach_plans "https://github.com/lqf0624/fm-tactics-lab/blob/main/src/desktop_coach_presets.py"
click node_real_generation "https://github.com/lqf0624/fm-tactics-lab/blob/main/src/desktop_real_generation.py"
click node_attribute_lab "https://github.com/lqf0624/fm-tactics-lab/blob/main/src/desktop_attribute_analysis.py"
click node_fmf "https://github.com/lqf0624/fm-tactics-lab/blob/main/src/fm27_fmf.py"
click node_tactic_pool "https://github.com/lqf0624/fm-tactics-lab/blob/main/src/fm27_tactic_pool.py"
click node_setpieces "https://github.com/lqf0624/fm-tactics-lab/blob/main/src/fm27_setpieces.py"
click node_execution "https://github.com/lqf0624/fm-tactics-lab/blob/main/native/native_execution_experiment.h"
click node_simulator "https://github.com/lqf0624/fm-tactics-lab/blob/main/src/fm27_simulator.py"
click node_native_host "https://github.com/lqf0624/fm-tactics-lab/blob/main/native/desktop_host.cpp"

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_desktop_ui,node_desktop_host,node_api toneBlue
class node_scenario,node_batch,node_runner,node_results,node_storage,node_attribute_lab toneAmber
class node_save_import,node_save_reader,node_opponents,node_coach_plans,node_real_generation toneMint
class node_fmf,node_tactic_pool,node_setpieces,node_execution toneRose
class node_simulator,node_native_host,node_fm_engine,node_user toneIndigo
```

## Components

### Desktop experience

- [Tactics workspace](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/tactics_ui/app.js): `src/tactics_ui/app.js`
- [Desktop host](https://github.com/lqf0624/fm-tactics-lab/blob/main/tauri/src/main.rs): `tauri/src/main.rs`
- [Tactics API](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/fm27_tactics_server.py): `src/fm27_tactics_server.py`

### Match experiments

- [Team scenarios](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/fm27_tactics_server.py): `src/fm27_tactics_server.py`
- [Batch experiments](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/fm27_batch.py): `src/fm27_batch.py`
- [Warm batch runner](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/desktop_warm_batch.py): `src/desktop_warm_batch.py`
- [Match results](https://github.com/lqf0624/fm-tactics-lab/blob/main/native/native_statistics.h): `native/native_statistics.h`
- [Experiment storage](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/desktop_storage.py): `src/desktop_storage.py`
- [Attribute experiments](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/desktop_attribute_analysis.py): `src/desktop_attribute_analysis.py`

### Save research

- [Save import](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/desktop_save_mode.py): `src/desktop_save_mode.py`
- [Save reader](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/desktop_save_worker.py): `src/desktop_save_worker.py`
- [Opponent selection](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/desktop_opponent_scope.py): `src/desktop_opponent_scope.py`
- [Coach preset plans](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/desktop_coach_presets.py): `src/desktop_coach_presets.py`
- [Real AI plans](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/desktop_real_generation.py): `src/desktop_real_generation.py`

### Tactical inputs

- [FMF tactic import](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/fm27_fmf.py): `src/fm27_fmf.py`
- [Opponent tactic pool](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/fm27_tactic_pool.py): `src/fm27_tactic_pool.py`
- [Set-piece plans](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/fm27_setpieces.py): `src/fm27_setpieces.py`
- [Execution settings](https://github.com/lqf0624/fm-tactics-lab/blob/main/native/native_execution_experiment.h): `native/native_execution_experiment.h`

### Engine runtime

- [Match simulator](https://github.com/lqf0624/fm-tactics-lab/blob/main/src/fm27_simulator.py): `src/fm27_simulator.py`
- [Native engine host](https://github.com/lqf0624/fm-tactics-lab/blob/main/native/desktop_host.cpp): `native/desktop_host.cpp`
- **Local FM27 engine**

### Other components

- **Experimenter**

## Connections

- Experimenter → Tactics workspace: edits and runs (evidence: `README.md`)
- Tactics workspace → Desktop host: uses desktop app (evidence: `README.md`)
- Desktop host → Tactics API: pipes requests (evidence: `README.md`)
- Tactics API → Team scenarios: validates inputs (evidence: `src/fm27_tactics_server.py`)
- Tactics API → Batch experiments: dispatches runs (evidence: `src/fm27_tactics_server.py`)
- Batch experiments → Warm batch runner: uses warm runner (evidence: `src/desktop_warm_batch.py`)
- Warm batch runner → Match simulator: runs matches (evidence: `src/desktop_warm_batch.py`)
- Match simulator → Native engine host: invokes host
- Native engine host → Local FM27 engine: loads engine (evidence: `README.md`)
- Native engine host → Match results: collects statistics (evidence: `README.md`)
- Warm batch runner → Match results: records outcomes (evidence: `src/desktop_warm_batch.py`)
- Warm batch runner → Experiment storage: persists batches (evidence: `src/desktop_warm_batch.py`)
- Tactics API → Save import: serves save mode (evidence: `src/fm27_tactics_server.py`)
- Save import → Save reader: starts reader (evidence: `src/desktop_save_mode.py`)
- Save import → Opponent selection: selects opponents (evidence: `src/desktop_save_mode.py`)
- Save import → Coach preset plans: uses coach plans (evidence: `src/desktop_save_mode.py`)
- Save import → Real AI plans: prepares AI plans (evidence: `src/desktop_save_mode.py`)
- Experimenter → FMF tactic import: imports tactics (evidence: `README.md`)
- FMF tactic import → Team scenarios: configures teams (evidence: `README.md`)
- Experimenter → Opponent tactic pool: manages candidates (evidence: `README.md`)
- Team scenarios → Set-piece plans: includes set pieces (evidence: `README.md`)
- Team scenarios → Execution settings: sets execution (evidence: `README.md`)
- Experimenter → Attribute experiments: tests attributes (evidence: `README.md`)
- Attribute experiments → Match simulator: compares matches (evidence: `README.md`)
