lootqdm
Turn your training loop into an idle RPG.
lootqdm replaces bland training progress bars with an idle RPG experience. XP bars, loot drops, quests, achievements, level-ups, critical batches — all in your terminal.
╭─ 🗡️ LOOTQDM ─────────────────────────────────────────────────────────╮
│ mnist_run · dark_dungeon ⚙ 00:12:34 │
├───────────────────────────────────┬──────────────────────────────────┤
│ │ │
│ PROGRESS │ STATS │
│ │ │
│ Epoch 3/10 █████████░░░ 80% │ ⚔ DMG (loss) 0.0234 │
│ Batch 128/500 ███████░░░░ 56% │ 🎯 CRIT (acc) 94.2% │
│ ETA 00:08:22 · 1284 it/s │ 💧 MANA (lr) 1e-4 │
│ │ 📉 loss ▇▆▅▄▃▃▂▂▁▁ │
│ 🩸 ██████████░░ 2340/3000 LV 7 │ 🔥 GPU 78% · 4.2 GB │
│ │ │
├───────────────────────────────────┼──────────────────────────────────┤
│ │ │
│ LOOT & EVENTS │ QUESTS │
│ │ │
│ ⚜️ LEGENDARY Cursed Crown! +500 │ 📜 acc ≥ 0.95 ▰▰▰▰▱ 94% │
│ 💠 Rare Void Shard +50 XP │ 📜 loss < 0.01 ▰▰▱▱▱ 42% │
│ 💥 CRITICAL BATCH! +20 XP │ ✅ First epoch ✓ │
│ 🪙 Rusty Coin +5 XP │ ✅ New best acc ✓ │
│ │ │
╰───────────────────────────────────┴──────────────────────────────────╯
Install
pip install lootqdm
Quick Start
Minimal
from lootqdm import GameUI
with GameUI(total_steps=1000) as ui:
for i in range(1000):
loss = 0.9 / (i + 1)
ui.step({"loss": loss, "lr": 1e-3})
Wrap an iterable
from lootqdm import GameUI
with GameUI(total_steps=len(dataloader)) as ui:
for batch in ui.wrap(dataloader):
loss = train_step(batch)
ui.step({"loss": loss.item()})
PyTorch
from lootqdm import GameUI
from lootqdm.integrations.torch import LootqdmCallback
epochs = 10
with GameUI(
total_steps=len(loader) * epochs,
total_epochs=epochs,
theme="neon_cyber",
run_name="mnist",
) as ui:
ui.quest("Low Loss", "loss", 0.1, "<=")
cb = LootqdmCallback(ui)
for epoch in range(epochs):
for batch_x, batch_y in loader:
loss, acc = train_step(batch_x, batch_y)
cb.on_batch_end(loss=loss, acc=acc)
cb.on_epoch_end(val_acc=validate())
Keras
from lootqdm import GameUI
from lootqdm.integrations.keras import LootqdmKerasCallback
with GameUI(
total_steps=steps_per_epoch * epochs,
total_epochs=epochs,
theme="cozy_pastel",
) as ui:
model.fit(x, y, callbacks=[LootqdmKerasCallback(ui)], verbose=0)
Themes
Pick a vibe. Four built-in themes:
| Theme | Mood | Icons |
|---|---|---|
dark_dungeon |
Roguelike, gritty | 🩸 🗡️ 🪙 💠 ⚜️ |
cozy_pastel |
Cottagecore, soft | 🌱 🧺 🍓 🫐 🧁 |
neon_cyber |
Synthwave, flashy | ⚡ 🧬 📀 🧪 💎 |
retro_crt |
Old terminal, ASCII | +XP LV [C] [R] [L] |
GameUI(total_steps=1000, theme="cozy_pastel")
Quests
Set metric-based goals. Progress bars track them live:
with GameUI(total_steps=1000) as ui:
ui.quest("Low Loss", "loss", 0.05, "<=")
ui.quest("High Accuracy", "acc", 0.95, ">=")
# quests check on epoch_end()
Loot System
Every 50 steps, a loot drop is rolled:
| Rarity | Chance | XP | Example (dark_dungeon) |
|---|---|---|---|
| Common | 70% | +5 | 🪙 Rusty Coin |
| Uncommon | 20% | +15 | 🔧 Iron Buckle |
| Rare | 8% | +50 | 💠 Cursed Relic |
| Epic | 1.9% | +150 | 🔮 Bloodstone Amulet |
| Legendary | 0.1% | +500 | ⚜️ Cursed Crown |
Random Events
- 💥 Critical Batch (3% per step) — bonus XP burst
- 🦇 Lucky Batch (1% per step) — mystery bonus
Achievements
Unlocked automatically:
- First epoch complete
- New best metric (per metric key)
- NaN survived (with warning)
- Level milestones (5, 10, 25, 50, 100)
Stat Mapping
Metrics are auto-translated to game stats:
| ML Metric | Game Stat | Icon |
|---|---|---|
loss |
DMG | ⚔ |
acc / accuracy |
CRIT | 🎯 |
lr |
MANA | 💧 |
val_loss |
vDMG | 🛡 |
val_acc |
vCRIT | 🎯 |
Custom mappings:
from lootqdm import StatMapper
mapper = StatMapper(mappings={
"f1_score": ("F1 PWR", "⚔"),
"bleu": ("BLEU", "📝"),
})
API Reference
GameUI
GameUI(
total_steps=1000, # Total training steps
total_epochs=10, # Number of epochs
theme="dark_dungeon", # Theme: dark_dungeon, cozy_pastel, neon_cyber, retro_crt
refresh_rate=10, # Max FPS for terminal refresh
emoji=True, # Enable emoji icons
persist=True, # Save profile to ~/.lootqdm/
run_name="my_run", # Display name for the run
)
| Method | Description |
|---|---|
step(metrics, n=1) |
Advance by n steps with optional metrics dict |
epoch_end(metrics) |
Signal end of epoch; triggers quest checks |
log(message, rarity) |
Add message to the loot feed |
quest(name, metric, target, compare) |
Register a quest goal |
wrap(iterable, metrics_fn) |
Wrap iterable with auto step tracking |
pytorch_step(**metrics) |
Convenience for step(metrics) via kwargs |
Persistence
Profile persists across runs at ~/.lootqdm/profile.json:
- Lifetime XP, total runs, level, achievements, loot log
- Set
persist=Falseto disable
TTY Fallback
When not in a terminal (CI, pipes, LOOTQDM_PLAIN=1), lootqdm automatically falls back to plain logging output. No crashes, no garbled text.
Examples
Run the included examples:
# Simple loop with all 4 themes
python examples/basic_loop.py
# PyTorch (falls back to simulation if torch not installed)
python examples/pytorch_mnist.py
# Keras (falls back to simulation if tensorflow not installed)
python examples/keras_callback.py
Development
git clone https://github.com/lootqdm/lootqdm.git
cd lootqdm
pip install -e ".[dev]"
pytest
License
MIT
Metadata
Release files for lootqdm 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| lootqdm-0.2.0.tar.gz | 61.8 kB | Without provenance | Details for lootqdm-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| lootqdm-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for lootqdm-0.2.0-py3-none-any.whl |
Total release size: 86.1 kB
Release files / lootqdm-0.2.0.tar.gz
| Download URL | lootqdm-0.2.0.tar.gz |
|---|---|
| Size | 61.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ff8417bd93ccbc22f22e621434343c57ef440ef46c78616c9deaec8459414062
|
|
BLAKE2b-256 checksum How to use checksums |
f95cfce12de59d7169be6ea8a5c8ab93f9c2f1f902edf3219b9b30f4d5e51499
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.10
|
Release files / lootqdm-0.2.0-py3-none-any.whl
| Download URL | lootqdm-0.2.0-py3-none-any.whl |
|---|---|
| Size | 24.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ec1f3a948ea03c9609921d2f20f397f513ffbc13a224859ab6356087aa262061
|
|
BLAKE2b-256 checksum How to use checksums |
aec51f2900729c37402ff3ff1927ef1546f5928d646b87e4b87cbe202101cf4d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.10
|
Security for lootqdm 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.