Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>PXG-Tiny — 483k-param offline text→pixel-sprite model</title> | |
| <meta name="description" content="PXG-Tiny turns plain English into 16×16 pixel-art game sprites fully offline. 483,040 parameters, 38 verified classes, pure NumPy runtime — CPU-only, no GPU, no network. By Chowdhury Tarul Ahsan."> | |
| <style> | |
| :root{ | |
| --bg:#0d0f1a; --bg2:#141830; --panel:#1a1f3a; --panel2:#20264a; | |
| --ink:#e8eaf6; --dim:#9aa3c7; --faint:#5a6288; | |
| --gold:#ffd24a; --green:#5df08a; --blue:#5db8ff; --purple:#b48cff; | |
| --red:#ff6b6b; --line:#2a3060; | |
| --mono:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; | |
| --sans:"Inter",-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif; | |
| } | |
| *{margin:0;padding:0;box-sizing:border-box} | |
| html{scroll-behavior:smooth} | |
| body{background:var(--bg);color:var(--ink);font-family:var(--sans);line-height:1.6; | |
| background-image:radial-gradient(circle at 15% -10%,#1b2150 0%,transparent 45%), | |
| radial-gradient(circle at 90% 0%,#231a4a 0%,transparent 40%);} | |
| .wrap{max-width:1180px;margin:0 auto;padding:0 24px} | |
| a{color:var(--blue);text-decoration:none} | |
| a:hover{text-decoration:underline} | |
| code,pre,.mono{font-family:var(--mono)} | |
| .px{image-rendering:pixelated;image-rendering:crisp-edges} | |
| /* ---------- nav ---------- */ | |
| nav{position:sticky;top:0;z-index:50;background:rgba(13,15,26,.85);backdrop-filter:blur(10px); | |
| border-bottom:1px solid var(--line)} | |
| nav .wrap{display:flex;align-items:center;gap:22px;height:60px} | |
| nav .logo{font-family:var(--mono);font-weight:700;font-size:17px;color:var(--gold);letter-spacing:.5px} | |
| nav .logo span{color:var(--ink)} | |
| nav .links{margin-left:auto;display:flex;gap:20px;font-size:14px} | |
| nav .links a{color:var(--dim)} nav .links a:hover{color:var(--ink);text-decoration:none} | |
| @media(max-width:760px){nav .links{display:none}} | |
| /* ---------- hero ---------- */ | |
| header{padding:76px 0 60px;text-align:center} | |
| .badge-row{display:flex;gap:10px;justify-content:center;flex-wrap:wrap;margin-bottom:26px} | |
| .badge{font-family:var(--mono);font-size:12px;padding:5px 12px;border:1px solid var(--line); | |
| border-radius:999px;color:var(--dim);background:var(--bg2)} | |
| .badge b{color:var(--gold);font-weight:600} | |
| h1{font-family:var(--mono);font-size:clamp(34px,6vw,58px);line-height:1.08;letter-spacing:-1px} | |
| h1 .t{color:var(--gold)} | |
| .sub{max-width:760px;margin:20px auto 0;color:var(--dim);font-size:18px} | |
| .sub b{color:var(--ink);font-weight:600} | |
| .cta{margin-top:34px;display:flex;gap:14px;justify-content:center;flex-wrap:wrap} | |
| .btn{font-family:var(--mono);font-size:14px;padding:12px 22px;border-radius:10px;border:1px solid var(--line); | |
| color:var(--ink);transition:.15s;display:inline-block} | |
| .btn:hover{text-decoration:none;transform:translateY(-2px)} | |
| .btn.primary{background:var(--gold);color:#1a1400;border-color:var(--gold);font-weight:700} | |
| .btn.primary:hover{box-shadow:0 6px 24px rgba(255,210,74,.35)} | |
| .btn.ghost{background:var(--bg2)} | |
| .hero-strip{margin:44px auto 0;max-width:940px;background:var(--panel);border:1px solid var(--line); | |
| border-radius:14px;padding:20px;display:flex;gap:6px;justify-content:center;flex-wrap:wrap} | |
| .hero-strip img{width:64px;height:64px} | |
| .hero-cap{font-family:var(--mono);font-size:12px;color:var(--faint);margin-top:10px} | |
| /* ---------- sections ---------- */ | |
| section{padding:64px 0;border-top:1px solid var(--line)} | |
| .kicker{font-family:var(--mono);font-size:12px;letter-spacing:2px;text-transform:uppercase; | |
| color:var(--green);margin-bottom:10px} | |
| h2{font-family:var(--mono);font-size:clamp(24px,3.4vw,34px);margin-bottom:14px;letter-spacing:-.5px} | |
| .lead{color:var(--dim);max-width:820px;margin-bottom:34px} | |
| .lead b{color:var(--ink)} | |
| /* ---------- gallery grid ---------- */ | |
| .grid38{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:14px} | |
| .card{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:16px; | |
| display:flex;gap:14px;align-items:center;transition:.15s} | |
| .card:hover{border-color:var(--gold);transform:translateY(-2px)} | |
| .card img{width:72px;height:72px;flex:none;background:#0a0c16;border-radius:8px;padding:4px;border:1px solid var(--line)} | |
| .card .cls{font-family:var(--mono);font-size:11px;color:var(--green);letter-spacing:1px;text-transform:uppercase} | |
| .card .prompt{font-size:13px;color:var(--dim);margin-top:3px;line-height:1.4} | |
| .verified{display:inline-block;margin-top:6px;font-family:var(--mono);font-size:10px;color:var(--green)} | |
| /* ---------- attribute pairs ---------- */ | |
| .pair-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px} | |
| .pair{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:16px;text-align:center} | |
| .pair img{width:96px;height:96px;margin:6px auto} | |
| .pair .prompt{font-family:var(--mono);font-size:12.5px;color:var(--gold);min-height:38px;display:flex;align-items:center;justify-content:center} | |
| .pair img:hover{transform:scale(1.06)} | |
| /* ---------- tables / misc ---------- */ | |
| .tbl{width:100%;border-collapse:collapse;background:var(--panel);border:1px solid var(--line); | |
| border-radius:12px;overflow:hidden;font-size:14.5px} | |
| .tbl th{background:var(--panel2);font-family:var(--mono);font-size:12px;letter-spacing:1px; | |
| text-transform:uppercase;color:var(--dim);text-align:left;padding:12px 16px} | |
| .tbl td{padding:12px 16px;border-top:1px solid var(--line);color:var(--dim)} | |
| .tbl td:first-child{color:var(--ink);font-weight:600} | |
| .stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:14px;margin:30px 0} | |
| .stat{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:18px;text-align:center} | |
| .stat .n{font-family:var(--mono);font-size:26px;font-weight:700;color:var(--gold)} | |
| .stat .l{font-size:12px;color:var(--dim);margin-top:4px} | |
| pre{background:#0a0c16;border:1px solid var(--line);border-radius:12px;padding:18px;overflow-x:auto; | |
| font-size:13.5px;line-height:1.65;margin:16px 0} | |
| pre .c{color:var(--faint)} pre .s{color:var(--green)} pre .k{color:var(--purple)} | |
| .two-col{display:grid;grid-template-columns:1fr 1fr;gap:22px} | |
| @media(max-width:860px){.two-col{grid-template-columns:1fr}} | |
| .note{background:var(--panel);border-left:3px solid var(--gold);border-radius:0 10px 10px 0; | |
| padding:14px 18px;font-size:14px;color:var(--dim);margin:18px 0} | |
| .note b{color:var(--ink)} | |
| ul.feat{list-style:none;display:grid;gap:12px;margin-top:10px} | |
| ul.feat li{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:13px 16px; | |
| color:var(--dim);font-size:14.5px} | |
| ul.feat li b{color:var(--ink)} | |
| ul.feat li .tick{color:var(--green);font-family:var(--mono);margin-right:8px} | |
| .warn li .tick{color:var(--red)} | |
| /* ---------- footer ---------- */ | |
| footer{border-top:1px solid var(--line);padding:44px 0 60px;color:var(--faint);font-size:14px} | |
| footer .wrap{display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap} | |
| footer b{color:var(--dim)} | |
| .platforms{display:flex;gap:12px;flex-wrap:wrap;margin-top:14px} | |
| .chip{font-family:var(--mono);font-size:12px;border:1px solid var(--line);border-radius:8px; | |
| padding:7px 12px;color:var(--dim);background:var(--bg2)} | |
| .chip:hover{color:var(--ink);border-color:var(--gold);text-decoration:none} | |
| </style> | |
| </head> | |
| <body> | |
| <nav> | |
| <div class="wrap"> | |
| <div class="logo">PXG<span>-Tiny</span></div> | |
| <div class="links"> | |
| <a href="#gallery">38 classes</a> | |
| <a href="#control">control</a> | |
| <a href="#benchmarks">benchmarks</a> | |
| <a href="#quickstart">quickstart</a> | |
| <a href="#limits">limitations</a> | |
| <a href="play.html" target="_blank">live demo ↗</a> | |
| </div> | |
| </div> | |
| </nav> | |
| <header> | |
| <div class="wrap"> | |
| <div class="badge-row"> | |
| <span class="badge"><b>483,040</b> parameters</span> | |
| <span class="badge"><b>38</b> verified classes</span> | |
| <span class="badge"><b>CPU-only</b> · no GPU</span> | |
| <span class="badge"><b>~1.8 MB</b> fp32 bundle</span> | |
| <span class="badge"><b>0</b> network calls</span> | |
| </div> | |
| <h1>plain English →<br><span class="t">pixel sprites</span> — fully offline</h1> | |
| <p class="sub">PXG-Tiny is a deliberately miniature text-to-sprite model: <b>483k parameters</b>, | |
| a pure <b>NumPy</b> inference runtime, and a built-in verifier that checks every sprite against | |
| your prompt before showing it. Runs on <b>any laptop CPU</b> in ~0.6 s per sprite.</p> | |
| <div class="cta"> | |
| <a class="btn primary" href="play.html" target="_blank">▶ Try it live (HF Space)</a> | |
| <a class="btn ghost" href="https://github.com/tarulahsan/PXG-Tiny-AI" target="_blank">GitHub</a> | |
| <a class="btn ghost" href="https://huggingface.co/Tarul/pxg-tiny" target="_blank">Hugging Face</a> | |
| <a class="btn ghost" href="https://www.modelscope.ai/models/tarulahsan/pxg-tiny" target="_blank">ModelScope</a> | |
| </div> | |
| <div class="hero-strip" id="heroStrip"></div> | |
| <div class="hero-cap">every sprite on this page was generated by the final v0.4 model — prompt & seed recorded in <a href="https://github.com/tarulahsan/PXG-Tiny-AI">manifest.json</a></div> | |
| </div> | |
| </header> | |
| <section id="gallery"> | |
| <div class="wrap"> | |
| <div class="kicker">full acceptance grid</div> | |
| <h2>All 38 classes, verified 100%</h2> | |
| <p class="lead">The final acceptance run tested <b>every class with two prompt styles × two seeds through the | |
| exact shipped user path</b>: <b>152/152 passed (100%)</b>. A second, independent sweep with 39 | |
| never-seen phrasings scored <b>99.1%</b>. Each card below is a real accepted render — | |
| hover any sprite to zoom.</p> | |
| <div class="grid38" id="grid38"></div> | |
| </div> | |
| </section> | |
| <section id="control"> | |
| <div class="wrap"> | |
| <div class="kicker">attribute grounding</div> | |
| <h2>Prompt words actually change pixels</h2> | |
| <p class="lead">The corpus is built from a procedural rasterizer with <b>counterfactual twin pairs</b> — | |
| identical geometry, one changed word — so the model learns word→pixel causality, not vibes.</p> | |
| <div class="pair-grid" id="pairGrid"></div> | |
| </div> | |
| </section> | |
| <section id="benchmarks"> | |
| <div class="wrap"> | |
| <div class="kicker">measured, not marketed</div> | |
| <h2>Benchmarks</h2> | |
| <div class="stats"> | |
| <div class="stat"><div class="n">100%</div><div class="l">38-class grid<br>152/152 prompts</div></div> | |
| <div class="stat"><div class="n">99.1%</div><div class="l">fresh-phrasing sweep<br>116/117</div></div> | |
| <div class="stat"><div class="n">31/31</div><div class="l">showcase gallery<br>shipped pipeline</div></div> | |
| <div class="stat"><div class="n">98.89%</div><div class="l">val top-1<br>teacher-forced</div></div> | |
| <div class="stat"><div class="n">100%</div><div class="l">INT8↔fp32 parity<br>max |Δlogit| 2e-05</div></div> | |
| </div> | |
| <table class="tbl"> | |
| <tr><th>Protocol</th><th>Result</th><th>What it measures</th></tr> | |
| <tr><td>Full 38-class grid</td><td>152/152 = 100%</td><td>2 prompt styles × 2 seeds per class, exact shipped pipeline (verifier-guided retries on)</td></tr> | |
| <tr><td>Fresh-phrasing sweep</td><td>116/117 = 99.1%</td><td>39 novel phrasings × 3 seeds, same pipeline — guards against overfitting to test prompts</td></tr> | |
| <tr><td>Raw held-out (verifier off)</td><td>59.4% mean · 50% strict</td><td>46 adversarial rephrasings, single free-run sample — the honest backbone-only number</td></tr> | |
| <tr><td>Parity gate</td><td>PASS</td><td>NumPy runtime vs trained torch model, bit-level teacher-forced comparison</td></tr> | |
| </table> | |
| <div class="note"><b>Why the raw number is low and the shipped number is 100%:</b> the 483k backbone knows | |
| every class (perfect teacher-forced accuracy) but autoregressive sampling drifts on hard prompts. | |
| The verifier-guided escalation — palette bias → spatial priors → canonical anchor — closes that gap | |
| for the user path. Both numbers are published on purpose.</div> | |
| </div> | |
| </section> | |
| <section id="quickstart"> | |
| <div class="wrap"> | |
| <div class="kicker">5-minute quickstart</div> | |
| <h2>Run it on your laptop</h2> | |
| <p class="lead">No GPU. No PyTorch at inference. No internet. Python ≥ 3.9 with <code>numpy</code> and <code>pillow</code>.</p> | |
| <div class="two-col"> | |
| <div> | |
| <pre><span class="c"># 1. get the bundle</span> | |
| git clone https://github.com/tarulahsan/PXG-Tiny-AI | |
| <span class="k">cd</span> PXG-Tiny-AI | |
| pip install numpy pillow pytest | |
| <span class="c"># 2. single sprite</span> | |
| python3 cli.py <span class="s">"a golden sword"</span> -o sword.png | |
| <span class="c"># 3. four variations on one sheet</span> | |
| python3 cli.py <span class="s">"an iron chest"</span> --variations 4 \ | |
| --sheet chest_variants.png | |
| <span class="c"># 4. batch from a prompt list</span> | |
| python3 cli.py --sheet-from-prompts prompts.txt \ | |
| --outdir sprites/</pre> | |
| </div> | |
| <div> | |
| <pre><span class="c"># Python API</span> | |
| <span class="k">from</span> pxg_tiny.pipeline <span class="k">import</span> PXGPipeline | |
| pipe = PXGPipeline() | |
| grid, meta = pipe.generate_pixels( | |
| <span class="s">"a ruby potion that glows"</span>, seed=7) | |
| <span class="k">if</span> grid <span class="k">is</span> <span class="k">None</span>: | |
| <span class="k">print</span>(meta[<span class="s">"message"</span>]) <span class="c"># clarify / refuse</span> | |
| <span class="k">else</span>: | |
| pipe.generate_png(<span class="s">"a ruby potion that glows"</span>, | |
| <span class="s">"ruby_potion.png"</span>) | |
| <span class="c"># ask-first gate (rule-based, offline)</span> | |
| PXGPipeline.ask(<span class="s">"render a 3d photo"</span>) | |
| <span class="c"># -> "i only make 16x16 pixel-art sprites..."</span></pre> | |
| </div> | |
| </div> | |
| <ul class="feat"> | |
| <li><span class="tick">▸</span><b>Ask-first behavior</b> — asks clarifying questions on unknown objects or | |
| conflicting words ("tiny huge sword"), refuses photos/3D/animation requests instead of hallucinating.</li> | |
| <li><span class="tick">▸</span><b>Verifier-guided sampling</b> — every candidate sprite is checked against the | |
| parsed prompt; failed seeds escalate through self-guidance (8 attempts) automatically.</li> | |
| <li><span class="tick">▸</span><b>Deterministic seeds</b> — same prompt + seed ⇒ same sprite, forever.</li> | |
| <li><span class="tick">▸</span><b>22 automated tests</b> — tokenizer, gates, NumPy kernels, end-to-end: <code>pytest tests/ -q</code></li> | |
| </ul> | |
| </div> | |
| </section> | |
| <section id="limits"> | |
| <div class="wrap"> | |
| <div class="kicker">honest limitations</div> | |
| <h2>What it won't do</h2> | |
| <ul class="feat warn"> | |
| <li><span class="tick">✕</span><b>16×16 only</b> — larger canvases, spritesheets and tilemaps are refused by | |
| design; scaling to 32×32 would 4× the sequence length and require a full redesign.</li> | |
| <li><span class="tick">✕</span><b>38-class vocabulary</b> — anything outside the trained families gets a | |
| clarifying question, never a hallucinated blob.</li> | |
| <li><span class="tick">✕</span><b>Binary transparency</b> — master-palette indices mean no soft edges/anti-aliasing.</li> | |
| <li><span class="tick">✕</span><b>Impossible combos downgrade</b> — "emerald dagger" renders a default dagger | |
| (the recipe set has no such training pair) instead of failing.</li> | |
| <li><span class="tick">✕</span><b>No animation / multi-view</b> — roadmap items from the main PXG program.</li> | |
| </ul> | |
| </div> | |
| </section> | |
| <section id="how"> | |
| <div class="wrap"> | |
| <div class="kicker">under the hood</div> | |
| <h2>Architecture in 30 seconds</h2> | |
| <pre>caption ids (32 chars) ──► <span class="k">intent encoder</span> (bi-attention, fp32) ──► 8 prefix vectors | |
| [8 prefixes | 256 visual tokens] ──► 4× pre-LN causal blocks (d=96, 4 heads, FFN 256) | |
| └─► 32-way softmax over <span class="s">master-palette indices</span> (0 = transparent) | |
| teacher-forced top-1 98.89% · KV-cached decode ~0.6 s/sprite on 2 CPU cores | |
| training corpus: 97,005 fully procedural rows (CC0), counterfactual twins + paraphrase engine</pre> | |
| <ul class="feat"> | |
| <li><span class="tick">▸</span><b>Built-in visual "tokenizer"</b> — sprites are grids of 32 master-palette indices, | |
| so decoding is byte-exact and alpha transparency is exact by construction.</li> | |
| <li><span class="tick">▸</span><b>Self-teaching recipe</b> — no external dataset: the procedural rasterizer makes | |
| captions honest by construction; twins teach causality; paraphrases teach invariance.</li> | |
| <li><span class="tick">▸</span><b>Verifiable</b> — quality gates calibrated so the GT corpus passes 100%; parity | |
| harness proves the shipped NumPy runtime matches the torch training reference bit-for-bit.</li> | |
| </ul> | |
| </div> | |
| </section> | |
| <footer> | |
| <div class="wrap"> | |
| <div> | |
| <b>PXG-Tiny v0.4</b> — offline text → pixel-sprite model<br> | |
| Created by <b>Chowdhury Tarul Ahsan</b> · <a href="mailto:tarulahsan@gmail.com">tarulahsan@gmail.com</a><br> | |
| Code: MIT · Weights & corpus: CC0 (self-generated) | |
| </div> | |
| <div> | |
| <div class="platforms"> | |
| <a class="chip" href="https://github.com/tarulahsan/PXG-Tiny-AI" target="_blank">github ↗</a> | |
| <a class="chip" href="https://huggingface.co/Tarul/pxg-tiny" target="_blank">hugging face ↗</a> | |
| <a class="chip" href="play.html" target="_blank">live demo ↗</a> | |
| <a class="chip" href="https://www.modelscope.ai/models/tarulahsan/pxg-tiny" target="_blank">modelscope ↗</a> | |
| </div> | |
| <div style="margin-top:14px;font-family:var(--mono);font-size:11px"> | |
| every sprite on this page: generated by PXG-Tiny v0.4, accepted by its own verifier | |
| </div> | |
| </div> | |
| </div> | |
| </footer> | |
| <script> | |
| const M = { | |
| "showcase": [ | |
| { | |
| "cls": "wizard", | |
| "prompt": "a wizard with a purple hat", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "wizard.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "knight", | |
| "prompt": "a knight in iron armor", | |
| "seed": 2026, | |
| "attempt": 2, | |
| "file": "knight.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "archer", | |
| "prompt": "an archer with a green hood", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "archer.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "skeleton", | |
| "prompt": "a skeleton warrior", | |
| "seed": 6078, | |
| "attempt": 6, | |
| "file": "skeleton.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "zombie", | |
| "prompt": "an undead with green skin", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "zombie.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "cat", | |
| "prompt": "a small gray cat", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "cat.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "dog", | |
| "prompt": "a brown dog", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "dog.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "bird", | |
| "prompt": "a small blue bird", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "bird.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "fish", | |
| "prompt": "a golden fish", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "fish.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "deer", | |
| "prompt": "a brown deer with antlers", | |
| "seed": 6078, | |
| "attempt": 6, | |
| "file": "deer.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "mouse", | |
| "prompt": "a little gray mouse", | |
| "seed": 1013, | |
| "attempt": 1, | |
| "file": "mouse.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "bat", | |
| "prompt": "a purple bat with wings", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "bat.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "sword", | |
| "prompt": "a golden sword", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "sword.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "dagger", | |
| "prompt": "a sharp iron dagger", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "dagger.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "shield", | |
| "prompt": "a round iron shield", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "shield.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "staff", | |
| "prompt": "a magic staff with a ruby orb", | |
| "seed": 2027, | |
| "attempt": 2, | |
| "file": "staff.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "potion_round", | |
| "prompt": "a red potion in a round bottle", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "potion_round.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "potion_vial", | |
| "prompt": "a slim vial of green potion", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "potion_vial.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "gem", | |
| "prompt": "a shiny blue gem", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "gem.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "coin", | |
| "prompt": "a gold coin", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "coin.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "chest", | |
| "prompt": "a wooden chest with gold bands", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "chest.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "key", | |
| "prompt": "an upright golden key", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "key.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "house", | |
| "prompt": "a cottage with a red roof", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "house.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "barrel", | |
| "prompt": "a wooden barrel", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "barrel.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "crate", | |
| "prompt": "a wooden crate", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "crate.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "apple", | |
| "prompt": "a red apple", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "apple.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "bread", | |
| "prompt": "a loaf of bread", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "bread.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "fireball", | |
| "prompt": "a large fireball", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "fireball.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "oak_tree", | |
| "prompt": "a green oak tree", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "oak_tree.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "pine_tree", | |
| "prompt": "a dark pine tree", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "pine_tree.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "bush", | |
| "prompt": "a leafy bush", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "bush.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "rock", | |
| "prompt": "a gray rock", | |
| "seed": 1013, | |
| "attempt": 1, | |
| "file": "rock.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "chair", | |
| "prompt": "a wooden chair", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "chair.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "table", | |
| "prompt": "a wooden table", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "table.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "stool", | |
| "prompt": "a wooden stool", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "stool.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "grass_tile", | |
| "prompt": "a grass texture tile", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "grass_tile.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "stone_tile", | |
| "prompt": "a stone texture tile", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "stone_tile.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "cls": "water_tile", | |
| "prompt": "a water texture tile", | |
| "seed": 0, | |
| "attempt": 0, | |
| "file": "water_tile.png", | |
| "gate": "accept" | |
| } | |
| ], | |
| "attributes": [ | |
| { | |
| "slug": "sword_gold", | |
| "prompt": "a golden sword", | |
| "seed": 0, | |
| "file": "attr_sword_gold.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "slug": "sword_iron", | |
| "prompt": "a sword made of pure iron", | |
| "seed": 0, | |
| "file": "attr_sword_iron.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "slug": "potion_red", | |
| "prompt": "liquid potion of red brew", | |
| "seed": 0, | |
| "file": "attr_potion_red.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "slug": "potion_green_vial", | |
| "prompt": "a slim vial of green potion", | |
| "seed": 0, | |
| "file": "attr_potion_green_vial.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "slug": "house_red_roof", | |
| "prompt": "a cottage with a red roof", | |
| "seed": 0, | |
| "file": "attr_house_red_roof.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "slug": "house_slate_roof", | |
| "prompt": "a cottage with a slate roof", | |
| "seed": 4052, | |
| "file": "attr_house_slate_roof.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "slug": "gem_ruby_glow", | |
| "prompt": "a ruby gem that glows", | |
| "seed": 0, | |
| "file": "attr_gem_ruby_glow.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "slug": "gem_emerald", | |
| "prompt": "an emerald gem", | |
| "seed": 0, | |
| "file": "attr_gem_emerald.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "slug": "rock_mossy", | |
| "prompt": "a mossy boulder", | |
| "seed": 3039, | |
| "file": "attr_rock_mossy.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "slug": "oak_autumn", | |
| "prompt": "old oak with autumn leaves", | |
| "seed": 0, | |
| "file": "attr_oak_autumn.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "slug": "bush_berries", | |
| "prompt": "a bush that has berries", | |
| "seed": 0, | |
| "file": "attr_bush_berries.png", | |
| "gate": "accept" | |
| }, | |
| { | |
| "slug": "coin_side", | |
| "prompt": "a gold coin seen from the side", | |
| "seed": 0, | |
| "file": "attr_coin_side.png", | |
| "gate": "accept" | |
| } | |
| ] | |
| }; | |
| // hero strip: 12 picky sprites | |
| const hero = ["wizard","knight","archer","deer","bat","cat","sword","gem","potion_vial","house","oak_tree","fireball"]; | |
| document.getElementById("heroStrip").innerHTML = hero.map(c => | |
| `<img class="px" src="assets/sprites/${c}@8.png" alt="${c}" title="${c}">`).join(""); | |
| // 38-class grid | |
| const pretty = c => c.replace(/_/g," "); | |
| document.getElementById("grid38").innerHTML = M.showcase.map(s => | |
| `<div class="card"><img class="px" src="assets/sprites/${s.file.replace(".png","")}@8.png" | |
| alt="${s.cls}" title="${s.prompt}"> | |
| <div><div class="cls">${pretty(s.cls)}</div> | |
| <div class="prompt">"${s.prompt}"</div> | |
| <span class="verified">✓ verified · seed ${s.seed}</span></div></div>`).join(""); | |
| // attribute pairs | |
| document.getElementById("pairGrid").innerHTML = M.attributes.map(a => | |
| `<div class="pair"><div class="prompt">"${a.prompt}"</div> | |
| <img class="px" src="assets/sprites/${a.file.replace(".png","")}@8.png" alt="${a.slug}"></div>`).join(""); | |
| </script> | |
| </body> | |
| </html> | |