--- title: The Tower Learns You emoji: ๐Ÿ—ผ colorFrom: purple colorTo: gray sdk: docker app_port: 7860 pinned: false short_description: A roguelite where a small LLM generates & adapts the game tags: - build-small-hackathon - thousand-token-wood - off-brand - llama-champion - llama-cpp - roguelite - game - gradio - track:wood - sponsor:openai - achievement:offgrid - achievement:offbrand - achievement:llama --- # ๐Ÿ—ผ The Tower Learns You **A proof-of-concept roguelite where a language model is _load-bearing_ โ€” not decoration.** Strip the AI out and there is no game content. The run, the entire skill pool, the bosses, the loot, your class evolutions, and the endgame are all generated by a local LLM โ€” and reshaped around the way you actually play. ![status](https://img.shields.io/badge/status-proof%20of%20concept-c79a4f) ![python](https://img.shields.io/badge/python-3.12-blue) ![frontend](https://img.shields.io/badge/frontend-gr.Server%20(custom%20HTML%2FJS)-8669c4) ![license](https://img.shields.io/badge/assets-CC%20BY%204.0-success) --- ## โ–ถ Demo https://github.com/user-attachments/assets/db5c6ad2-02bf-4fd7-8a0f-b50d60218d7b [Full Demo](https://youtu.be/U6M8d_oUWUg) > _Video not loading? **[Watch / download the 60-second trailer ยป](https://github.com/vknt-m/tower-learns-you/raw/main/demo/out/trailer.webm)**_ โ€” every frame is real, unedited game output: the same `render` HTML the live app produces, captured from authentic engine state. > **๐Ÿ† Built for the [Build Small Hackathon](https://huggingface.co/build-small-hackathon) โ€” track: _Thousand Token Wood_.** > ๐ŸŽฌ **Demo video:** https://github.com/user-attachments/assets/db5c6ad2-02bf-4fd7-8a0f-b50d60218d7b > ๐Ÿ“ฃ **Social post:** https://x.com/lurkingof/status/2066288605937742024 > ### ๐Ÿง‘โ€โš–๏ธ Judging / running locally โ€” use the GitHub **`main`** branch > For the **full** load-bearing-AI experience (incl. AI-generated skills via a local llama.cpp model), > clone and run **[github.com/vknt-m/tower-learns-you](https://github.com/vknt-m/tower-learns-you) > (`main` branch)** โ€” see [Run it](#run-it) below. This hosted Space runs the same game against > HF Inference Providers; the local `main` build is the reference setup for testing/judging. --- ## Why this exists Most games use AI for flavor text or matchmaking. This is an experiment in the opposite: making the model responsible for the parts that normally ship hard-coded. The Python engine owns the **rules** (damage, AP, turn order, balance); the model owns the **content and adaptation**, behind strict typed contracts. The result is a game whose identity is regenerated every run and bent by your own behavior. ## What the AI actually drives - **Run identity** โ€” theme, title, and the provisional archetype the floor sequence is built around. - **The entire skill pool** โ€” 16 skills per run, each named, described, and costed (validated against the same rules authored skills follow). - **Equipment language** โ€” weapon / armor / relic naming drawn from a per-run loot lexicon. - **Class evolutions** โ€” at the mid and late thresholds you evolve into an AI-authored class with a unique signature skill, shaped by how you've been fighting. - **Boss identities & decks** โ€” each guardian's name, epithet, weaknesses, and move deck. - **Live boss adaptation** โ€” the final boss reads your patterns and adjusts its deck mid-fight to counter you. - **Turn narration & ascension passives** โ€” moment-to-moment flavor and the permanent perks carried between runs. All of it is derived from your behavioral history: action ratios, element and skill preferences, defensive tendencies, and healing choices. ## Why it doesn't break The model proposes; Python disposes. Every generated object passes through **Pydantic schemas** and **Python registries** before it can touch game state, so the model can author content but can never change a formula, invent a mechanic, or mutate state directly. If the model is slow, unavailable, or returns something invalid, the engine falls back to deterministic authored content and the UI flags it โ€” the game is always playable, with or without a model. ## The loop Shape an initiate โ†’ choose a starter skill โ†’ climb ten floors of turn-based combat (spend AP, cast skills, read enemy intent) โ†’ claim loot and learn new skills โ†’ evolve at the thresholds โ†’ defeat the adaptive final boss โ†’ ascend and carry permanent power into a freshly generated run. ## Stack - **Frontend** โ€” a custom HTML / CSS / JS client served by Gradio 6 `gr.Server` (no Blocks UI). The Python game logic and HTML rendering are reused as REST endpoints. - **Engine** โ€” deterministic, seeded Python: combat, loot, progression, balance. - **Model gateway** โ€” pluggable backends: `mock` (deterministic, no credentials), `local_openai` (loopback llama.cpp), `hf_inference` (Hugging Face). ```mermaid flowchart LR UI[Custom gr.Server frontend] --> Engine[Deterministic Python engine] Engine --> Core[Combat ยท Loot ยท Progression] Engine --> GW[Typed model gateway] GW --> Mock[Mock โ€” deterministic] GW --> Local[Loopback llama.cpp] GW --> HF[HF Inference] GW --> Guard[Pydantic schemas + registries] ``` ## Run it The default `mock` backend needs no credentials and no GPU: ```powershell python -m venv .venv .\.venv\Scripts\Activate.ps1 python -m pip install -r requirements-server.txt python tools\catalog_assets.py # builds Assets/manifest.json (first run only) python server_app.py ``` Open **http://127.0.0.1:7861/**. To run against a real model, set `MODEL_BACKEND` to `local_openai` (loopback llama.cpp) or `hf_inference` (with `HF_TOKEN` and `HF_MODEL_ID`). The local launcher binds to `127.0.0.1` only and exposes the model nothing but read-only inspection and typed `submit_*` proposal tools โ€” never shell, filesystem, or direct state access. ## Status This is a **proof of concept / demo**, not a finished game. The full ten-floor loop โ€” AI generation, behavioral adaptation, evolutions, and ascension โ€” works end-to-end on both the deterministic mock backend and a local model. Balance and content breadth are intentionally illustrative. ## Tests ```powershell .\.venv\Scripts\python.exe -m pytest -q ``` ## Assets & license Image and audio assets live under `Assets/`, licensed **CC BY 4.0** with attribution to **vknt-m** โ€” see [`ASSET_LICENSE.md`](ASSET_LICENSE.md) and [`ATTRIBUTION.md`](ATTRIBUTION.md). The trailer music and bgm is royalty-free.