Skip to content

hougangdev/token-fable

Repository files navigation

token-fable — turn the tokens you spend on LLMs into EXP

⚔️ token-fable

Turn the tokens you spend on LLMs into EXP. A token-driven 16-bit pixel RPG that levels up while you work.

Every token you burn in Claude Code (or any local LLM) becomes EXP and combat energy for a hero descending an endless dungeon. You work normally; the hero levels, auto-battles randomized monsters, and drops loot across six rarities. Glance back after a real working session and there's a stack of loot and level-ups waiting — the dopamine hit.

Token usage drives progress — not the clock. This is not an idle/AFK game. Nothing happens while you sit still. Spend tokens and the world moves; stop and it freezes. "Check back every 15–30 minutes" works because that's a window of real usage replayed as a "While you were away…" reveal.

status


Quick start

npm install
npm run build        # build the web UI
npm start            # serve game + API on http://localhost:8787

Open http://localhost:8787 and start feeding it tokens.

For development with hot reload (UI on :5173, server on :8787):

npm run dev

No LLM handy? Use the Feed tokens controls in the dashboard, or curl -X POST localhost:8787/api/ingest -d '{"tokens":120000}'. The whole game is playable with zero LLM connected.


Connecting your LLM

Claude Code (primary, zero-config)

Just run the server. It automatically watches your Claude Code session transcripts at ~/.claude/projects/**/*.jsonl across all your projects and feeds the token usage to a single global hero.

  • Starts fresh: existing history is baselined and ignored on first launch — you begin at Level 1.
  • Never misses tokens: per-file byte offsets persist, so restarting catches up on exactly what you used while it was off, with no double-counting.
  • Robust: usage is parsed defensively (located by its *_tokens keys), so a Claude Code transcript format change won't silently break capture.

Leave it running in the background, code as usual, and check back when you want the reveal.

Local LLMs (Ollama / LM Studio / llama.cpp)

Run the server with an OpenAI-compatible upstream, then point your tool at the proxy:

TOKEN_FABLE_PROXY_UPSTREAM=http://localhost:11434 npm start
# then set your tool's base URL to:  http://localhost:8787/proxy/v1

The proxy streams bytes straight through and only reads the token counts as they pass (OpenAI usage, Ollama eval_count/prompt_eval_count), so overhead is negligible.

Anything else

POST /api/ingest with either a shorthand or a full breakdown:

curl -X POST localhost:8787/api/ingest -d '{"tokens": 5000}'
curl -X POST localhost:8787/api/ingest -d '{"input":2000,"output":4000,"cacheRead":80000,"cacheCreation":1000}'

How it plays

  • EXP & leveling — weighted tokens grant EXP (× your gear's EXP multiplier). Infinite curve: levels fly early, then stretch out.
  • Token weighting — token types are valued by real cost/effort: output (×4.5) > input (×1) > cache-creation (×1.25) > cache-read (×0.1).
  • Model tiers — a token from a costlier model is worth more EXP: opus (×3) > sonnet (×1.5) > haiku (×0.8); local/unknown models are ×1. So an Opus session is a bigger adventure (and you can't cheaply grind on a tiny model). Tiers live in src/engine/balance.ts.
  • Endless dungeon — tokens are spent as combat energy auto-battling procedurally generated monsters; deeper floors mean tougher foes and better loot. Under-geared? You stall (never die) until more levels or gear break you through.
  • Loot & raritycommon → uncommon → rare → unique → legendary → mythical. Luck biases drops toward rarer tiers.
  • Gear matters twice — items boost combat (ATK/DEF/HP) and meta progression (EXP multiplier, Luck), a self-reinforcing loop.
  • Essence economy — salvage unwanted gear into Essence, then spend it to upgrade an item, reroll its stats, or expand your bag. Set an auto-salvage rule to scrap low tiers hands-free.
  • The reveal — quiet while you're heads-down; loud when you return. A summary card + a highlights reel of your rare+ finds.

Configuration

All optional, via environment variables:

Variable Default Purpose
PORT 8787 Server port.
TOKEN_FABLE_DATA ./data Save directory (save.json).
TOKEN_FABLE_PROXY_UPSTREAM Enable the local-LLM proxy (e.g. http://localhost:11434).
TOKEN_FABLE_CLAUDE_DIR ~/.claude/projects Claude Code transcripts root.
TOKEN_FABLE_SEED fixed RNG seed for a fresh save.

Game balance (curves, drop tables, costs, scaling) lives in one file: src/engine/balance.ts.


Architecture

A pure, deterministic engine wrapped by a thin server and a Preact + canvas UI.

Claude Code .jsonl ─┐
local LLM (proxy)  ─┼─▶ tokenEvent ─▶ engine.advance(state, event) ─▶ events
manual /api/ingest ─┘                       │ (pure · seeded · tested)
                                            ▼
                              persist (JSON) + WebSocket ─▶ Preact + canvas dashboard
  • src/engine/ — pure game logic. advance(state, tokenEvent) → { state, events }. No I/O, seeded RNG, fully unit-tested.
  • src/server/node:http + ws. Capture adapters, the driver, atomic persistence, live push.
  • src/web/ — Preact UI + a canvas combat stage (sprite duel, HP bars, damage numbers).

Development

npm test            # vitest — engine unit tests
npm run typecheck   # tsc --noEmit
npm run dev         # hot-reload server + UI
npm run build       # production web build

Roadmap (post-v1)

Final hand-crafted pixel sprites · audio (chiptune SFX) · class/build system · multiple themed dungeons & bosses · data-driven JSON config + content packs · OpenTelemetry capture · multi-machine sync · achievements · packaged distribution (npx).

The current sprites are simple procedural placeholders — distinctive 16-bit art is a planned asset pass.

License

MIT

About

Turn your LLM token usage into EXP — a token-driven 16-bit pixel RPG that levels up while you code

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors