Interactive game theory: build payoff matrices, run strategy tournaments, and watch cooperation evolve — all in the browser, no backend.
Available in English, Turkish, German and Russian.
| Module | What it does |
|---|---|
| Matrix Games | Edit a payoff matrix and see Nash equilibria, dominant strategies, Pareto optimality and mixed equilibria update live. |
| Iterated Tournament | Axelrod-style round-robin between strategies, with noise and reproducible seeds. Build your own strategies from ordered rules — no coding. |
| Spatial Games | Nowak & May's grid model: cells play their neighbours and copy whoever scores best. Cooperation survives only by forming clusters. |
| Evolutionary Dynamics | Replicator dynamics, ESS analysis and phase portraits. Can run on the tournament strategies, reproducing Axelrod's ecological simulation. |
Every experiment is shareable: the Share button encodes the full setup into the URL, so a link reproduces the exact same run.
npm ci # or: make install
npm run dev # or: make devThen open the printed local address.
Run make for the full list. The most used:
| Command | Purpose |
|---|---|
make dev |
Development server |
make test |
Run the test suite once |
make watch |
Tests in watch mode |
make check |
Type-check, lint and test — run before committing |
make build |
Production build into dist/ |
make icons |
Regenerate the PNG app icons from the brand mark |
The icon is a 2×2 payoff matrix with the equilibrium cell highlighted. The
source of truth is public/favicon.svg; scripts/generate-icons.mjs renders the
PNG sizes that Safari and Android require, writing them without an image
dependency. Edit the SVG, then run make icons and keep the two in step.
Everything runs client-side. The core idea is that simulation logic is pure TypeScript with no React or DOM imports:
src/
├── engine/ # Pure TS: games, solver, strategies, tournament, spatial, evolution
├── workers/ # Web Worker wrappers for the long-running simulations
├── ui/ # React components, one folder per module
├── state/ # Zustand stores
├── i18n/ # Four dictionaries, type-checked against the English source
└── lib/ # URL state encoding and sharing
That separation buys two things: the engine is directly unit-testable, and it can be moved into a Web Worker unchanged. The tournament and spatial modules do exactly that, so a long simulation never freezes the interface.
Reproducibility comes from a seeded RNG (engine/core/rng.ts) rather than
Math.random, which is what makes shared links show identical results.
Stack: React 19, TypeScript, Vite, Tailwind CSS, Zustand, Recharts, Vitest.
The site is live at https://ukbey.github.io/game_theory/.
Every push to main runs .github/workflows/deploy.yml, which type-checks,
lints and tests before publishing. A failing check blocks the deploy, so a
broken build never reaches the site.
Enabling this takes one manual step, once per repository: Settings → Pages → Build and deployment → Source: GitHub Actions.
Two things are easy to get wrong on a project page. The workflow handles both, which is worth knowing if you fork this or rename the repository:
- Base path. The site is served from a subdirectory, so the build runs with
BASE_PATH=/<repo-name>/. Vite rewrites the asset URLs and the router reads the same prefix fromimport.meta.env.BASE_URL. Without it every asset 404s. - Client-side routing. Pages cannot resolve
/tournamenton the server, soindex.htmlis copied to404.html. Pages serves that for unknown paths and the app takes over from there.
make build, then serve dist/. Set BASE_PATH if the site lives in a
subdirectory, and configure the host to fall back to index.html for unknown
paths.