tower-learns-you / README.md
vknt's picture
Update README.md
79f96e2 verified
|
Raw
History Blame Contribute Delete
6.55 kB
metadata
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 python frontend license


β–Ά Demo

https://github.com/user-attachments/assets/db5c6ad2-02bf-4fd7-8a0f-b50d60218d7b

Full Demo

Video not loading? Watch / download the 60-second trailer Β» β€” 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 β€” 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 (main branch) β€” see 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).
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:

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

.\.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 and ATTRIBUTION.md. The trailer music and bgm is royalty-free.