File size: 7,565 Bytes
691d6c7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# PXG-Tiny — offline text → 16×16 pixel-sprite model

**PXG-Tiny** is the deliberately miniature sibling of the Pixel AI (PXG) program:
a **483,040-parameter** generator that turns plain English into production-usable
16×16 pixel-art sprites (weapons, potions, treasure, flora, tiles, buildings…)
fully offline. It ships as a ~1 MB weight bundle and runs on a pure **NumPy**
inference runtime with **no PyTorch and no GPU required**.

**Author:** Chowdhury Tarul Ahsan · <tarulahsan@gmail.com> · v0.4 (2026-08-27)

**Headline numbers** (final acceptance, v0.4):
full-grid verification **38/38 classes — 152/152 prompts (100%)** ·
independent fresh-phrasing sweep **99.1% (116/117)** · raw held-out
(46 prompts, retry disabled) **59.4%** · showcase gallery **31/31** ·
val top-1 **98.89%** · bundle ~1.8 MB fp32

```
"a golden sword, glowing"   ──►  PXG-Tiny  ──►  16×16 RGBA sprite (+ retries,
                                                 clarify/refuse questions)
```

**Tags:** `text-to-image` `pixel-art` `game-assets` `sprite-generator`
`offline` `tiny-model` `numPy-runtime` `int8-quantization`
`self-supervised` `procedural-data` `gpt` `english-prompts`

---

## What it can do

| Capability | Detail |
|---|---|
| **38 grounded object classes** | weapons: sword, dagger, shield, staff · potions: round bottle, slim vial · treasure: chest, coin, gem, key · food: apple, bread · nature: oak/pine tree, bush, rock · tiles: grass/stone/water · building: house · **characters**: wizard, knight, archer, skeleton, zombie · **animals**: cat, dog, bird, fish, deer, mouse, bat · **furniture**: chair, table, stool · effects: fireball |
| Attribute grounding | materials (gold/iron/crystal/ruby/emerald/sapphire/amethyst/wood/copper/slate/terracotta), orientation (upright / lying sideways), glow, moss, berries, autumn leaves, size, roof colors — enforced only where the recipe supports them |
| Ask-first behavior | refuses photos / 3D / animations / other resolutions; asks clarifying questions on unknown objects or conflicting attribute words |
| Verifier-guided sampling | every generation is auto-checked against prompt-grounding constraints; failed seeds escalate through **self-guided palette bias → spatial priors (face box, vial margins, deer antler anchor) → canonical prompt anchoring** (8 tries) |
| Paraphrase-robust English | trained on **97,005** paraphrase-augmented rows across 38 classes: "made of pure iron", "of the crystal kind", "covered in moss", "whose orb is ruby", mid-adjectives, prose or comma forms |
| Deterministic & offline | char-level tokenizer with byte-fallback, fixed seeds, master-palette indices only |

## Quick start (no build step)

```bash
# single sprite
python3 cli.py "a golden sword" -o sword.png

# 4 variations on one sheet
python3 cli.py "an iron chest" --variations 4 --sheet chest_variants.png

# ask-first gate
python3 cli.py --ask "can you render a photo of my cat"

# batch: prompts.txt (one per line)
python3 cli.py --sheet-from-prompts prompts.txt --outdir sprites/
```

Python API:

```python
from pxg_tiny.pipeline import PXGPipeline

pipe = PXGPipeline()                # loads ./weights bundle
grid, meta = pipe.generate_pixels("a ruby potion that glows", seed=7)
if grid is None:
    print(meta["message"])          # clarify/refuse reply instead of pixels
else:
    png_path = pipe.generate_png("a ruby potion that glows",
                                 "ruby_potion.png")[1]["path"]
msg = PXGPipeline.ask("draw a 3d blender model")   # -> refusal message
```

Requirements: Python ≥3.9, `numpy`, `pillow` (rendering only; generation math
is NumPy-only).

## Architecture (483k params)

```
caption ids (32 slots)  ─► intent encoder (bi attn + ReLU FFN, fp32)
                        ─► 8 prefix vectors
[8 prefixes | 256 visual tokens]
  └─ 4× pre-LN causal blocks (d=96, 4 heads, FFN 256, tanh-GELU)
       └─ 32-way softmax over master-palette indices (0 = transparent alpha)

per-token accuracy 98%+ teacher-forced; KV-cached incremental decode at
inference (~0.6 s per sprite on 2 CPU cores).
```

*Visual "tokenizer"* is built-in by design: sprites are stored as grids of
32 master-palette indices, so decoding is byte-exact and alpha transparency
is exact by construction.

## Self-teaching training recipe

No external dataset was needed for v0.2:

1. A procedural rasterizer (11 asset families) draws sprites whose every
   caption word maps to a real rendered attribute — captions are honest by
   construction.
2. Counterfactual twin pairs share geometry but differ in exactly one
   attribute word ("gold" vs "iron"), teaching word→pixel causality.
3. **Paraphrase augmentation**: each ground-truth sprite is re-captioned in
   multiple surface forms (relative clauses, "made of/from", "of the … kind",
   "covered in moss", "lying sideways", polite frames, mid adjectives…) so the
   encoder learns paraphrase *invariance*. The final corpus is **97,005 rows**
   across 38 classes.
4. Quality gates (connectivity, isolated pixels, attribute thresholds) are
   calibrated so the ground-truth corpus passes 100%.

Training itself is `train/train_model.py` (CPU PyTorch, ~50 min @4,200 steps).
`train/quantize_export.py` exports the runnable bundle and proves numerical
parity against the torch reference.

## Bundle contents (`weights/`)

| file | role |
|---|---|
| `gen_int8.npz` | all model weights (see metadata for precision layout) |
| `vq_int8.npz` | master palette (32×4 RGBA lookup = visual codebook) |
| `runtime.json` | geometry + default sampling config |
| `tokenizer.json` | text tokenizer table |
| `metadata.json` | params, metrics, parity report, license, provenance |

`pxg_tiny/runtime_pipeline.OfflinePipeline` implements everything needed to
run it; `PXGPipeline` wraps it with gates, retries, turnarounds and PNG export.

## Testing

```bash
pip install pytest
pytest tests/ -q          # tokenizer, gates, NumPy kernels, end-to-end smoke
```

## Honest limitations

* 16×16 resolution only — larger canvases / spritesheets / tilemaps are
  refused by design (the ask-first gate explains this).
* Class vocabulary is the 38 trained families; anything outside gets a
  clarifying question rather than a hallucinated blob.
* Raw free-run sampling (verifier disabled) passes ~59% of hard held-out
  prompts; the verifier-guided pipeline lifts the shipped user path to
  ~100% (38-class grid) / 99.1% (fresh phrasings). Rare hard prompts can
  still end on an `accept_degraded` last-resort sprite (see EVAL_REPORT §5).
* Some material × class combos the recipes never trained (e.g. "emerald
  dagger") are silently downgraded to the class default instead of failing.
* Animation/multi-view consistency are roadmap items inherited from the main
  PXG program, not in this tiny cut.

See [EVAL_REPORT.md](EVAL_REPORT.md) for the full v0.1 → v0.4 evaluation
journey and honest weakness list, and [TUTORIAL.md](TUTORIAL.md) for a
5-minute quickstart.

## OpenGameArt-CC0 hook

v0.2 did not require external data (procedural ground truth gives perfect
caption alignment). To enrich distribution realism later: download a CC0-only
subset, record SHA256 + page URL per file in `data/oga_manifest.json`, run the
same quality gates, then extend `CLASS_DEFS`. License hygiene stays CC0-only.

## License

Code: **MIT** (see LICENSE). Weights + procedural corpus: **CC0** —
self-generated, no third-party assets ingested; sprites you generate are
yours to use anywhere, no attribution required.