Skip to content

Latest commit

 

History

13 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LineLab

Learn the handful of Teamfight Tactics decisions that get you to top 4.

Live site · Learn · Arena · Solver · API health

LineLab is an independent, beginner-focused tool for learning TFT fundamentals — the durable, patch-agnostic habits (economy, leveling, rolling, items, positioning, reading the lobby) that separate a bleeding-out new player from a reliable top-4 finisher. It teaches by giving you one clear move at a time, then lets you drill it against a live coach.

It uses no Riot Games assets, artwork, champion data, or live-client access, and is not affiliated with or endorsed by Riot Games. The Arena and Solver run on an original Monte Carlo simulation model.


What's inside

  • Learn (/learn) — 14 ranked fundamentals in 5 modules, with a "must-know 6" shown first and a "Go deeper" reveal. Each card is a single actionable rule plus the common mistake it fixes.
  • Arena (/play) — a playable auto-battler with a live coach that calls one move at a time, so you drill the habits instead of reading about them. Includes a post-game review that grades every macro decision.
  • Solver (/solver) — describe any spot and get one recommended move (ROLL / LEVEL / SAVE / STABILIZE) with a plain-English why. The full expected-value table, decision tree, and scenario builder live behind an Advanced toggle.

The coach never asks you to rate your own board — it reads health, gold, level, and board strength for you, runs thousands of fast simulated games, and collapses the result into a single verb.

Tech stack

Layer Stack
Frontend Next.js 14 (App Router), TypeScript, Tailwind CSS
Backend FastAPI + Python, a Monte Carlo expected-value engine
Database Supabase Postgres (saved scenarios); falls back to a local JSON store
Optional AI chat-coach via the Anthropic SDK, off unless ANTHROPIC_API_KEY is set

Repository layout

backend/    FastAPI app + Monte Carlo solver
  app/
    main.py            FastAPI app + endpoints
    models.py          Pydantic wire models
    solver/            the engine (economy, leveling, shop, rollout, evaluator, …)
    chat.py            optional Anthropic-backed chat-coach
  api/index.py         serverless entrypoint (re-exports the ASGI app)
  tests/               pytest suite
frontend/   Next.js app
  app/                 landing, learn, play (Arena), solver, compliance, terms, privacy
  lib/game/            client-side Arena engine
  lib/coach/           one-verb coach (ROLL/LEVEL/SAVE/STABILIZE)
  lib/learn/           fundamentals curriculum content
  components/          UI (Nav, Footer, play/*, solver/*, learn/*, coach/*)
docs/       model notes + build specs (see docs/README.md)

Running locally

You need two processes: the Python backend (the simulation engine) and the Next.js frontend (the UI).

1. Backend (port 8000)

cd backend
python -m venv .venv
. .venv/Scripts/activate          # macOS/Linux: source .venv/bin/activate
pip install -r requirements.txt -r requirements-dev.txt   # drop the second file for runtime only
cp .env.example .env              # optional: fill in for Supabase / chat-coach
uvicorn app.main:app --port 8000

The backend runs fine with an empty .env — it falls back to a local JSON scenario store and leaves the AI chat-coach disabled. GET /api/health reports which stores are active. Interactive API docs are at /docs.

2. Frontend (port 3000)

cd frontend
npm install
cp .env.local.example .env.local   # set NEXT_PUBLIC_API_URL if not localhost:8000
npm run dev

Open http://localhost:3000/learn to start with the fundamentals, or http://localhost:3000/play to practice in the Arena. If the backend is unreachable, the Solver falls back to an embedded sample (with a banner) so the site stays reviewable offline.

Environment variables

Real secrets live only in gitignored .env files (never committed). See backend/.env.example and frontend/.env.local.example. Key ones:

  • SUPABASE_DB_URL — Postgres session-pooler connection string (optional; enables the Supabase scenario store)
  • ANTHROPIC_API_KEY — enables the AI chat-coach (optional)
  • NEXT_PUBLIC_API_URL — where the frontend finds the backend (defaults to http://localhost:8000)
  • LINELAB_DATA_DIR — where the JSON fallback store keeps saved scenarios (defaults to backend/data). Point it at a writable path on hosts that mount the app directory read-only.
  • LINELAB_CORS_ORIGINS / LINELAB_CORS_ORIGIN_REGEX — who may call the API from a browser (defaults to localhost)

GET /api/health reports scenario_store and scenario_store_writable, so you can tell at a glance whether saving is actually going to work.

The Solver API

Method Path Purpose
GET /api/health liveness + which stores/features are active
GET /api/config option vocabulary for the scenario builder
POST /api/compare compare candidate lines for a game state
POST /api/project project a chosen line forward (HP/placement/survival per stage)
POST /api/review grade a sequence of past decisions
POST /api/coach/chat streaming AI chat-coach (requires ANTHROPIC_API_KEY)
GET/POST/DELETE /api/scenarios built-in + saved teaching spots
curl -s localhost:8000/api/compare -H 'content-type: application/json' -d '{
  "state": {"stage":"midgame","hp":58,"gold":42,"level":6,
            "board_strength":"weak","bench_value":"medium","pairs":2,
            "items":"medium","lobby_tempo":"high","goal":"top4"},
  "n_rollouts": 2000
}'

Compliance

LineLab teaches universal TFT concepts using the game's own vocabulary (gold, interest, levels, rolls, traits, augments) but ships no Riot artwork, icons, champion data, or patch tables, and never connects to the live game — no overlay, real-opponent scouting, in-client "do this now" prescriptions, automation, or memory reading. The Arena's opponents are simulated. See /compliance for the full statement.

Deployment

Both halves run on Vercel as two projects off this one repo, each with its own root directory. Pushing to main redeploys both.

Project Root dir Config URL
linelab frontend/ frontend/vercel.json https://linelab-yougijain.vercel.app
linelab-api backend/ backend/vercel.json https://linelab-api-yougijain.vercel.app

Non-secret wiring lives in those two vercel.json files rather than in dashboard settings, so the deployment is reproducible from the repo:

  • the frontend's NEXT_PUBLIC_API_URL and NEXT_PUBLIC_SITE_URL;
  • the backend's LINELAB_CORS_ORIGINS, plus LINELAB_CORS_ORIGIN_REGEX so per-branch preview deployments are allowed without a redeploy.

Two things are worth knowing if you fork this:

  • The backend routes through backend/api/index.py, which just re-exports the ASGI app. It uses routes rather than rewrites — Vercel hands a rewritten request the destination path, which would make every route arrive at FastAPI as /api/index.
  • Solver calls are CPU-bound Monte Carlo runs (~3s at 2 000 rollouts, the frontend's ceiling is 4 500), so the function is given maxDuration: 60.

The backend also sets LINELAB_DATA_DIR=/tmp/linelab, because the application directory is read-only on the serverless runtime. /tmp is per-instance and ephemeral, so saved scenarios survive only within a warm instance — set SUPABASE_DB_URL for real persistence.

Secrets (SUPABASE_DB_URL, ANTHROPIC_API_KEY) are not in vercel.json — set those as environment variables in the Vercel dashboard. Without them the backend still runs: it falls back to the local JSON scenario store and leaves the chat-coach off.

The Supabase scenario store

Setting SUPABASE_DB_URL switches the API off the JSON fallback. Use the Session pooler string from the dashboard's Connect dialog — it suits a long-lived ASGI process. The transaction pooler (6543) also works, because db.py disables prepared statements.

The app creates its own table on first connect (ensure_ready, idempotent) and seeds the built-in teaching spots, so there is no migration step to run.

public.scenarios has RLS enabled with no policies, deliberately. The API is the table's only client and connects as postgres, which bypasses RLS; nothing reaches it through PostgREST. Leaving RLS off would make the table readable and writable by anyone holding the project's publishable key, which is public by design. Don't add permissive policies unless a client starts talking to Supabase directly.

Self-hosting instead of Vercel works unchanged — the backend is a plain uvicorn app.main:app ASGI app, so Render / Fly.io / Railway need no extra config beyond the environment variables above.

License

MIT © 2026 yougijain


Teamfight Tactics and TFT are trademarks of Riot Games, Inc., referenced here nominatively for identification and educational purposes only. LineLab is not affiliated with, endorsed by, or sponsored by Riot Games.

About

Full-stack strategy trainer: Next.js frontend on a FastAPI Monte Carlo simulation engine

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages