File size: 5,619 Bytes
3c4d5f8
41979b0
 
3c4d5f8
7e5faa7
3c4d5f8
7e5faa7
3c4d5f8
 
7e5faa7
47b3964
 
 
 
b32194e
3c4d5f8
b9560ee
7e5faa7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
---
title: HuggingWizards
emoji: πŸ§™
colorFrom: purple
colorTo: indigo
sdk: gradio
sdk_version: 5.9.1
app_file: app.py
pinned: false
short_description: Nemotron-4B is the Game Master
tags:
  - track:wood
  - sponsor:nvidia
  - achievement:offgrid
  - achievement:sharing
---
Social Media Post and Demo Video: https://www.linkedin.com/posts/dean-byrne-02a28b191_huggingwizards-for-hugging-face-hackathon-activity-7472041413648502785-K2rP?utm_source=share&utm_medium=member_desktop&rcm=ACoAAC0RumIBxlIKTkKv5tF-hb2OU7TdZ19kxcQ
# πŸ§™ HuggingWizards

A small 2D pixel-wizard **co-op arena** that runs as a Gradio Space on **ZeroGPU**.
Up to **8 players** join one shared arena, fight a central **boss** and the
**minions** it spawns, and upgrade their magic between rounds. Everyone else can
**spectate** live. Controls: **WASD** to move, **Space** to attack.

The hackathon twist: **NVIDIA Nemotron-Mini-4B-Instruct** is the **Game Master**.
At the end of every round it decides:

- **Rewards** β€” how much gold each wizard earns (based on damage / survival).
- **Blessings** β€” individual boons for wizards who earned them: any timed aura,
  a `full_heal`, or even an `extra_life` for a struggling player.
- **Boss attack pattern** β€” `balanced`, `sniper` (fast aimed bolts), `artillery`
  (slow heavy orbs + dense shockwaves), `swarm` (minion floods), or `berserker`
  (relentless charges). The active pattern shows next to the boss's name.
- **Boss attack speed (with decaying mercy)** β€” the GM reads every wizard's
  HP% and lives and tunes `boss_attack_speed` (0.5–2.0): slower for a wounded
  party, faster for a healthy one. Guardrail: the allowed floor rises each
  wave (no mercy left by ~wave 13), out-of-range or malformed values are
  clamped, and every trace records `requested` vs `applied` plus the floor.
- **Boss & minion reset** β€” next-round boss HP, minion count/HP, spawn rate,
  boss damage, aggression, and the enemy archetype mix.
- **Card pool** β€” which level-up cards may be offered next wave.

Every round produces a structured **agent trace** (prompt β†’ raw model output β†’
parsed decision β†’ applied effect), saved under `traces/` and shown live in the
Gradio dashboard.

## Architecture

- **Client** (`static/`): HTML5 canvas game loop in the browser (rendering + input).
- **Server** (`app.py`, `game/`): FastAPI WebSocket + a ~20 Hz authoritative game
  tick on CPU. Gradio is mounted for the trace/leaderboard dashboard.
- **Game Master** (`game/gamemaster.py`): `@spaces.GPU` burst inference at round
  boundaries only β€” the pattern ZeroGPU is built for. Falls back to deterministic
  logic if the model/GPU is unavailable (so it runs locally too).

## Run locally

```bash
pip install -r requirements.txt
python app.py
# open http://localhost:7860
```

The Game Master uses Nemotron only when a GPU + the `spaces`/`transformers` stack
is present; otherwise it transparently uses the deterministic fallback so local
dev and CI still work.

## Game Master model

On a Space the model is loaded **at startup** (the ZeroGPU pattern: weights are
downloaded and staged before any `@spaces.GPU` call, so the 60 s GPU window is
spent purely on inference). Locally it is lazy-loaded on the first round.

Environment variables:

| Variable | Values | Effect |
|---|---|---|
| `HUGGINGWIZARDS_NO_LLM` | `1` | Skip the model entirely; deterministic Game Master (CI / quick dev). |
| `HUGGINGWIZARDS_QUANT` | `auto` (default), `none`, `4bit`, `8bit` | Quantization via bitsandbytes. `auto` = bf16 on Spaces/big GPUs, NF4 4-bit on local GPUs with <12 GB VRAM. |

Quantization notes: 4-bit NF4 shrinks the 4B model from ~8.5 GB to ~3 GB of
VRAM and speeds up cold loads β€” ideal for small local GPUs. On ZeroGPU's H200
plain bf16 is both comfortable and faster per token, so `auto` keeps bf16 there.

## Assets

Pixel art / audio from free packs (Tiny RPG Character Pack, Tiny Swords,
Free Pixel Effects, Retro Impact Effect Pack, Pixel UI pack 3, Pixel RPG Music
Pack). See each pack's license.

- **Maps**: each boss faction has its own territory β€” the Tiny Swords grass
  tileset plus a per-theme ground tint, landmark buildings
  (`static/assets/buildings/`: orc camp huts, the Iron Legion's blue castle,
  the Lancer Host's red keep, the Archer Coven's monastery & ranges) and a
  seeded scenery mix (bushland / rockfields / forest). Scenery is purely
  cosmetic β€” the server simulation is unchanged.
- **Effects**: spell-cast muzzle flashes, impact bursts (on boss/minion/player
  hits) and death poofs are drawn client-side from the Free Pixel Effects
  spritesheets, triggered by snapshot flags (`hurt`, attack, minion id removal).
  Skill activations and GM blessings are server-driven events rendered with
  more of the pack: freezing novas, felspell blasts, protection circles,
  vortex summons, sunburn blessings, magic-bubble heals.
- **Characters**: pick a champion (Warrior / Archer / Lancer / Pawn) on the
  name screen β€” Tiny Swords blue units (`static/assets/chars/`), all size-normalized
  and growing with level.
- **Special bosses**: **Aegis** (red wave, holy-spell attacks) on waves 3/9/15… and
  **Toaster Bot** (green wave, glitch-portal attacks) on waves 5/11/17…  Beat one and
  every survivor gains its signature attack as a permanent power.
- **Timed auras**: rare floor-only power-ups (30–60 s) visualized with the Retro
  Impact Effect Pack (`static/assets/retro/`) wreathing the wizard.
- **Music**: a looping track from the Pixel RPG Music Pack starts on the first
  join/spectate click (browser autoplay policy); a πŸ”Š button toggles it.