diff --git a/.claude/skills/pixellab/SKILL.md b/.claude/skills/pixellab/SKILL.md new file mode 100644 index 0000000..d681cf7 --- /dev/null +++ b/.claude/skills/pixellab/SKILL.md @@ -0,0 +1,78 @@ +--- +name: pixellab +description: Generate pixel art for Supervillain via the Pixel Lab API — sprites, tiles, animations. Use when adding or regenerating game art assets, or when the user asks for new sprites/tiles/graphics. +--- + +# Pixel Lab art pipeline + +Pixel Lab (https://api.pixellab.ai/v1) generates the game's pixel art. + +## Auth + +The API key is exported as `PIXELLAB_API_KEY` in `~/.zshrc`. Shells launched by +the harness may not have it loaded — `source ~/.zshrc` first, or read the env var. +Check remaining credit with: + +```bash +curl -s https://api.pixellab.ai/v1/balance -H "Authorization: Bearer $PIXELLAB_API_KEY" +``` + +Note: a `{"usd": 0.0}` balance does NOT mean generation fails — the account is +generation-credit based. Just try a small generation. + +## Generating assets + +Use the helper script (stdlib-only Python, no venv needed): + +```bash +# Whole starter pack — idempotent, skips files that already exist: +python3 .claude/skills/pixellab/scripts/generate.py --batch assets/pixellab/manifest.json + +# One-off: +python3 .claude/skills/pixellab/scripts/generate.py \ + "a gold vault tile" assets/pixellab/tiles/vault.png --size 16 --view "high top-down" +``` + +To regenerate an asset, delete the PNG and re-run the batch (or run a one-off). +To add assets, add entries to `assets/pixellab/manifest.json` and re-run. + +## Conventions (keep these or the art clashes) + +- **Size:** 32x32 for everything. The OpenAPI schema claims a 16px minimum, but + the API rejects transparent (`no_background`) generations below 32x32 with + "Canvas must be size 32x32 area or larger" — so 32 is the real floor. The Bevy + frontend's `TILE_SIZE` is 16 world units; render 32px art scaled to fit. + Pixflux maximum is 400px. +- **Style suffix:** every prompt gets the shared style from the manifest + `defaults.style` ("dark evil lair theme, muted palette with purple and teal + accents..."). Change it in one place only. +- **Seed:** fixed at 1337 in the manifest for coherence across the set. +- **Characters:** `"transparent": true`, `"view": "low top-down"`, `"direction": "south"`. + Stored in `assets/pixellab/sprites/`. +- **Tiles:** opaque, `"view": "high top-down"`. Stored in `assets/pixellab/tiles/`. + +## API surface (pixflux is the main one) + +- `POST /generate-image-pixflux` — text to pixel art. Body: `description`, + `image_size {width,height}`, optional `no_background`, `view` + (`side | low top-down | high top-down`), `direction` (8 compass points), + `seed`, `color_image` (forced palette), `init_image`. +- `POST /generate-image-bitforge` — style-matched generation from a reference + image (use when matching an existing asset's exact style; max 200px). +- `POST /rotate` — generate other facing directions from one sprite. +- `POST /animate-with-text` / `animate-with-skeleton` — animation frames (64px only + for text mode). +- `POST /inpaint` — edit a region of an existing sprite. +- Response: `{"image": {"base64": ...}, "usage": ...}` — decode base64 to PNG. + +Generation takes ~5-20s per image; the batch script retries on 429/5xx. + +## Where art goes + +- `assets/pixellab/manifest.json` — the manifest (source of truth for the set) +- `assets/pixellab/sprites/*.png` — characters (transparent) +- `assets/pixellab/tiles/*.png` — terrain/furniture (opaque) +- Generated PNGs are committed to git (they are small and regeneration costs credits). + +The Bevy frontend (`src/bin/bevy.rs`) still renders flat colored rects; wiring +these sprites in is Milestone 3 in DESIGN.md. diff --git a/.claude/skills/pixellab/scripts/generate.py b/.claude/skills/pixellab/scripts/generate.py new file mode 100644 index 0000000..188ab29 --- /dev/null +++ b/.claude/skills/pixellab/scripts/generate.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 +"""Generate pixel art for Supervillain via the Pixel Lab API. + +Auth: reads PIXELLAB_API_KEY from the environment (exported in ~/.zshrc). + +Single image: + python3 generate.py "a gold vault tile" out.png --size 16 + python3 generate.py "evil overlord" out.png --size 16 --transparent --view "low top-down" + +Batch (skips outputs that already exist, so it is safe to re-run): + python3 generate.py --batch manifest.json + +Manifest format (paths are relative to the manifest file): + { + "defaults": {"size": 16, "style": ", 16x16 pixel art, dark evil lair"}, + "items": [ + {"out": "tiles/floor.png", "description": "stone floor", "view": "high top-down"}, + {"out": "sprites/villain.png", "description": "overlord", "transparent": true} + ] + } +""" + +import argparse +import base64 +import json +import os +import sys +import time +import urllib.error +import urllib.request + +API = "https://api.pixellab.ai/v1" + + +def api_key() -> str: + key = os.environ.get("PIXELLAB_API_KEY") + if not key: + sys.exit("PIXELLAB_API_KEY not set (it is exported in ~/.zshrc)") + return key + + +def generate(description: str, size: int, transparent: bool = False, + view: str | None = None, direction: str | None = None, + seed: int | None = None, retries: int = 3) -> bytes: + body = { + "description": description, + "image_size": {"width": size, "height": size}, + "no_background": transparent, + } + if view: + body["view"] = view + if direction: + body["direction"] = direction + if seed is not None: + body["seed"] = seed + + req = urllib.request.Request( + f"{API}/generate-image-pixflux", + data=json.dumps(body).encode(), + headers={ + "Authorization": f"Bearer {api_key()}", + "Content-Type": "application/json", + }, + ) + for attempt in range(retries): + try: + with urllib.request.urlopen(req, timeout=180) as resp: + data = json.load(resp) + return base64.b64decode(data["image"]["base64"]) + except urllib.error.HTTPError as e: + detail = e.read().decode(errors="replace")[:200] + if e.code in (429, 500, 502, 503) and attempt + 1 < retries: + wait = 10 * (attempt + 1) + print(f" HTTP {e.code}, retrying in {wait}s: {detail}") + time.sleep(wait) + continue + sys.exit(f"Pixel Lab error {e.code}: {detail}") + raise AssertionError("unreachable") + + +def run_batch(manifest_path: str) -> None: + with open(manifest_path) as f: + manifest = json.load(f) + root = os.path.dirname(os.path.abspath(manifest_path)) + defaults = manifest.get("defaults", {}) + style = defaults.get("style", "") + + items = manifest["items"] + done = skipped = 0 + for item in items: + out = os.path.join(root, item["out"]) + if os.path.exists(out): + skipped += 1 + continue + os.makedirs(os.path.dirname(out), exist_ok=True) + desc = item["description"] + item.get("style", style) + png = generate( + desc, + size=item.get("size", defaults.get("size", 16)), + transparent=item.get("transparent", defaults.get("transparent", False)), + view=item.get("view", defaults.get("view")), + direction=item.get("direction", defaults.get("direction")), + seed=item.get("seed", defaults.get("seed")), + ) + with open(out, "wb") as f: + f.write(png) + done += 1 + print(f"[{done + skipped}/{len(items)}] {item['out']}") + print(f"Generated {done}, skipped {skipped} existing.") + + +def main() -> None: + p = argparse.ArgumentParser(description=__doc__) + p.add_argument("description", nargs="?") + p.add_argument("out", nargs="?") + p.add_argument("--batch", help="manifest JSON path") + p.add_argument("--size", type=int, default=16) + p.add_argument("--transparent", action="store_true") + p.add_argument("--view", choices=["side", "low top-down", "high top-down"]) + p.add_argument("--direction") + p.add_argument("--seed", type=int) + args = p.parse_args() + + if args.batch: + run_batch(args.batch) + return + if not args.description or not args.out: + p.error("need DESCRIPTION and OUT (or --batch)") + png = generate(args.description, args.size, args.transparent, + args.view, args.direction, args.seed) + with open(args.out, "wb") as f: + f.write(png) + print(f"wrote {args.out}") + + +if __name__ == "__main__": + main() diff --git a/.gitignore b/.gitignore index ea8c4bf..02d1c02 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +.letta/settings.local.json diff --git a/.letta/.lettaignore b/.letta/.lettaignore new file mode 100644 index 0000000..baa2dcb --- /dev/null +++ b/.letta/.lettaignore @@ -0,0 +1,47 @@ +# .lettaignore — Letta Code file index exclusions +# +# Files and directories matching these patterns are excluded from the @ file +# search index and disk scan fallback. Comment out or remove a line to bring +# it back into search results. Add new patterns to exclude more. +# +# Syntax: one pattern per line, supports globs (e.g. *.log, src/generated/**) +# Lines starting with # are comments. +# +# --- Dependency directories --- +node_modules +bower_components +vendor + +# --- Build outputs --- +dist +build +out +coverage +target +.next +.nuxt + +# --- Python --- +venv +.venv +__pycache__ +.tox + +# --- Version control & tooling --- +.git +.cache +.letta + +# --- Lock files --- +package-lock.json +yarn.lock +pnpm-lock.yaml +poetry.lock +Cargo.lock + +# --- Logs --- +*.log + +# --- OS artifacts --- +.DS_Store +Thumbs.db diff --git a/README.md b/README.md index 0eaedfd..cbec042 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The threat readout in the sidebar shows when the next raid is coming. Raids are | Key | Action | |-----|--------| -| `hjkl` / arrows | Move the Supervillain | +| `WASD` / `hjkl` / arrows | Move the Supervillain | | `SPACE` / `p` | Pause / resume time | | `+` / `-` | Simulation speed | | `b` | Build mode | @@ -32,7 +32,7 @@ The threat readout in the sidebar shows when the next raid is coming. Raids are | Key | Action | |-----|--------| -| `hjkl` / arrows | Move cursor | +| `WASD` / `hjkl` / arrows | Move cursor | | `TAB` | Cycle build category | | `n` / `p` | Cycle item in category | | `SPACE` | Place selected tile | diff --git a/assets/pixellab/manifest.json b/assets/pixellab/manifest.json new file mode 100644 index 0000000..32ed207 --- /dev/null +++ b/assets/pixellab/manifest.json @@ -0,0 +1,32 @@ +{ + "defaults": { + "size": 32, + "seed": 1337, + "style": ", 32x32 pixel art, dark evil lair theme, muted palette with purple and teal accents, crisp readable silhouette" + }, + "items": [ + { "out": "sprites/villain.png", "description": "supervillain overlord with purple cape, black armor, glowing magenta eyes", "transparent": true, "view": "low top-down", "direction": "south" }, + { "out": "sprites/minion_worker.png", "description": "hunched minion worker in gray coveralls carrying a shovel", "transparent": true, "view": "low top-down", "direction": "south" }, + { "out": "sprites/minion_guard.png", "description": "minion guard in black tactical armor holding a stun baton", "transparent": true, "view": "low top-down", "direction": "south" }, + { "out": "sprites/minion_technician.png", "description": "minion technician in yellow hazard suit with a wrench", "transparent": true, "view": "low top-down", "direction": "south" }, + { "out": "sprites/minion_scientist.png", "description": "mad scientist minion in white lab coat and green goggles", "transparent": true, "view": "low top-down", "direction": "south" }, + { "out": "sprites/henchman.png", "description": "hulking elite henchman brute in spiked black armor", "transparent": true, "view": "low top-down", "direction": "south" }, + { "out": "sprites/agent_investigator.png", "description": "detective agent in beige trench coat and fedora with magnifying glass", "transparent": true, "view": "low top-down", "direction": "south" }, + { "out": "sprites/agent_thief.png", "description": "cat burglar agent in sleek black stealth suit", "transparent": true, "view": "low top-down", "direction": "south" }, + { "out": "sprites/agent_saboteur.png", "description": "saboteur agent in balaclava with explosive charges", "transparent": true, "view": "low top-down", "direction": "south" }, + { "out": "sprites/agent_soldier.png", "description": "special forces soldier in green fatigues with rifle", "transparent": true, "view": "low top-down", "direction": "south" }, + { "out": "sprites/agent_super.png", "description": "superhero agent in blue and gold suit with flowing cape", "transparent": true, "view": "low top-down", "direction": "south" }, + { "out": "tiles/floor.png", "description": "dark stone dungeon floor, seamless texture", "view": "high top-down" }, + { "out": "tiles/wall.png", "description": "dark metal-reinforced stone wall block", "view": "high top-down" }, + { "out": "tiles/rock.png", "description": "solid unexcavated dark rock and earth, seamless texture", "view": "high top-down" }, + { "out": "tiles/throne.png", "description": "evil golden throne on a purple dais", "view": "high top-down" }, + { "out": "tiles/power_core.png", "description": "glowing cyan reactor core machine", "view": "high top-down" }, + { "out": "tiles/lab.png", "description": "laboratory bench with bubbling green chemicals", "view": "high top-down" }, + { "out": "tiles/vault.png", "description": "vault floor covered in gold coins and treasure", "view": "high top-down" }, + { "out": "tiles/barracks.png", "description": "military bunk bed with dark blanket", "view": "high top-down" }, + { "out": "tiles/guard_post.png", "description": "guard watch post with weapon rack", "view": "high top-down" }, + { "out": "tiles/trap_spike.png", "description": "floor spike trap with metal spikes", "view": "high top-down" }, + { "out": "tiles/trap_fire.png", "description": "fire nozzle trap embedded in floor grate", "view": "high top-down" }, + { "out": "tiles/door.png", "description": "reinforced metal security door seen from above", "view": "high top-down" } + ] +} diff --git a/assets/pixellab/sprites/agent_investigator.png b/assets/pixellab/sprites/agent_investigator.png new file mode 100644 index 0000000000000000000000000000000000000000..c4258a5915c39551b8840490b174ba1c742fde95 GIT binary patch literal 1520 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANN<+dW+zLn`J>otB*=5-M`M ze(ue1Z$`zYmt~w=ODmUTdkbngx;SX_HU+hu@=o@;+TdiMs8AR9fs=7!$0xSN6$`o6 zu3Wi6!}ZBdCokqHt3h|{h4PfR@XB;nDJX6Y%}YAp##sq7jJ!NwVUtmgELRzqkopdtiPxb10 z2X3|%tG-N_G9~9lZdmpnwMM^X5B^LPx>U@)qpD0l%HY7vWK)I}UJN&L5|8!?m-tpO z#6R%6WA@n3@%E!&Q&EP6r`;XF^Im9N5_;l+Usrm>tIE zuw7fP?(<)chDbjJef3V4*=H@P&p&5Qh`$;u66&IQS&vaRV*Rf~=i}{_>rS`a$z!mw zU(3+&&UTk%Hv6giG~bu+d!#S5b_p-svSshGK+Y#iY<2GZ-kzMPr(ye?p;m5YN=SY1 zW8KF-Zr2k2<^Gu6d3m~f>59E3E*i0X%U9S$2(itZWO*%Oe^r@2!^)eFcgEGvs$W0n z@zI^}ObPER<;z8Sm;I0GC@m4a-OF(3e0X;H#96kCCsW+GwPHR@nKUoDVf(H*hr-Pz ze}B$d|8Tm9&py33+;v?#CkwwelySazRAk|Ld(QT0Jy+~Z?(OqkXVkm>uD_9Pwer1n z)mB%#9^d0IxG+yoPVx=YgQU6B0cHh^z^H}GqUD#aB&%i9R;N!R4 zS^svou3D)xYu@2k`ToIQuge$S?AtBsyy9g>R#MA8_adXT$-I%1R$9ip$N32{zkR9H z)ydJhTlDqz#~v@W?nPC0%=YaSd|dH!QOzYI8HOp<*N&%}>oMuI2T!TpJK>@-cVmFc zrJy$z(s`dMzE8hdpDfG0EbU{(LmLLYxp#a&F7eqm?c}1(rh=k-PDU#i{rV<6U*vgb z)OW3iMHa26AByDLZE@Nm<7aqbo?h17)h>Sb>lU4iR-U!T^w86SuBh)?AJ1J$R0^|7 zy4E097MrFU$=h=4<%uOq&ij8JUU_GCvAED0lPj{%HoDJWoZ@WApuZ>Nfc9gfLup>w zoimv>&uKWCm3rkv=ML?1sVdv=>`k|C>?u-XcJpCOxVuTgIIYg%WZO*-HEzwB$sfa} zA8+cAWpovd`7mYCil(-x@*B4f?v4&IMAUfV)xs?di(UYx3b|Dedb)h+%I8G&{mU{KJJyRl3WWceN!G z!_Ud{7OmU2@3WxA*5Ag>Uz=3lUwpcFsm|T9IkB_jlvRs$828U#c3ORg;b-Qu+*z{E zDo<~Jswl0?^j0Xqbn1P-ZF@d5ow60mHA{KvR~#ogPwp?1m|()|T{q7P&UQFD>wAFd z)RV690hI+J=I7q2npQKhs&V&j-^S>7u_~n8g8NJn6Q}3ijn>6COJA_L{>*ecVIOZK z`TZhS^7^``V!r1Y6E5%m+`DzknT1+mwwM`S3Rq*8XF}( zM=#B?(Ncb`>4DpmR|pnZ&Uv(3w|K%?u@K*-Iq8=3{>r6zKKoj!-`ZHc`t(E}vBSTw z9buGu#do~KAdThKtJjPb7bbEE6!w;USmot^^cX#Wnx{ literal 0 HcmV?d00001 diff --git a/assets/pixellab/sprites/agent_saboteur.png b/assets/pixellab/sprites/agent_saboteur.png new file mode 100644 index 0000000000000000000000000000000000000000..ee542ff250f29949ba510b895b02cdb80aeaf558 GIT binary patch literal 1252 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANMUt36#DLn`Jxo#vY(>@IS= zp7Uc~?@@Q>pgU^QCR=Q6_0_)9u!t#FWr>q+hNDPJ)v7KR{*^538P(7FuJm)a%iWS@ z=WFOX<-TMQN2qVqn$p!4C%WGr*~-jkSoYSWY;X1>xo!7SHhS*)Yw=Zo?H1$wXJ_mG z8NWZ<{NFn2-@7Bq6XRDgysy2p`1{_{)V-PY%hXv81&O8#X1TcbID85{eOgwUK!Rr8u{3;!~$lEa%YZc2N?#>$m*j>6A-Hl#K4)ExWcZ_Bi|YIOC;G z(ZJcn`!Ykxc{x@77uGN}nXL)Y5#(f-wAMOY8+2`#)>UW%2A3XVvT{&07?(p@SGSBNV9e!W@@l2xE zQr1O9XBPMvXT0K=_IR?lFvFbRznJu6C9eOL^%HN6;oG`smY2sejxAfd?(7z4J@8oi z!tdvoqEw!6M;gClFb@2{!gBG_hW}@q+jj_RgzvZgv|^=)!CcPA?CoE-?fqTp5S(B( zmnGrwud=)Uj&6G&cD84k=!uj|zv`{NHk7<_JbaYV&wt;^EH9I_4hlMCV< zeld|<;s0%Avz$9iRx?iMQ8$TJJbmDs?3|e2PlKmsbb*w1t53Vv&^h5q+HU6m4;U7k zyK77pyRqvmzr*&+oDNzGCw91|-ac7zsDM97@TSAMww*I2f8F_8_4~??fWziVp-kD& zPOlIRoxbJ%Tc!v7i`0H!xM%+A*^#FjD?_9*Z9MFzAHVqACGa%w-}N2}3aqOa{yko3 z5nC0X9xlG2=u&4(bIC317hB37$jdn7WIJ!@m?I@`I z{WbM;o6bxxm5x(}I!z1*dL3>S@MsGOM4J>pTUhoi_`A}Qq{0NxPARwiz8CsQMOCK~ zioaN9zJHUk<5(9<-g}#t1i`|}J15H3U({Z7P7j}6_d2`dbfApwUW=-#jZwJ`WtNOF za^_xEjh6(4N?)?0BMq-TCLtJzp9S zC@PYusWN*Vds_NCW9wr13+HMquiacTMSJQl%jf0&l1}=P{ulQ7_+~5s#k}+H{^YH< z3i5AyDb8OS61AfE-t%|v0=iSWR8LLynk!}cggbJNoqpW>@Y^0%Cp)9pzxZawdSw5p zs`cl+L;4gWT$mYGUv;yap8n+-2SeYyxFo@y3;&q2 z?hZZ6JOAj@Lg781gAd=mlC@uIUe8adbMNE2rqw8N7cQ=?E1cGwWL?jcwTsE;-UP|x Q3=9kmp00i_>zopr0Pb;D`v3p{ literal 0 HcmV?d00001 diff --git a/assets/pixellab/sprites/agent_soldier.png b/assets/pixellab/sprites/agent_soldier.png new file mode 100644 index 0000000000000000000000000000000000000000..c45a226f22029e0d4ce38af3436c47715d3059f0 GIT binary patch literal 1010 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANOKJ3U<-Ln`Jxoqo|@CRF5D z{o!*vHVEV_nf7+qn;VLH9??pHleU?e3aDh)T*#QR@8*}#_?nORKiFS*(R^{qtS=|U zv$X{xoTEjyPT|bEnRxe|1V>)%w8ovAue0Cb^_V{Qrc}I*zj5)iy63y^@BBWe`r-e) zQ;T`zyke$ZP2b3DFKWltbKRuTTYit$_kH*OteHFaEZ4JRQypgLo)wDl6p!>2|7at6 zK3H{Bq;WFr`CZcVqVMn#@nD9Coiz`p zn5|_vaB-rdTHYJB_gS8aFLwDHN#1mDL+!OIN;a~4bz&ozt??Bq)L)<}$aY-!&75`t zy|A*WK4!1Etv4_+ACI3rZ_~L}Z>GZr9p9e5u$_I}Z$GO;q3X#SM-zEszb|!pU~2HC z&AqISw>WHR`VQ`fuE&Mt&#XjtUlf_~cZu+!e;=5%6ZG?#6k1l)YTvDC{NXu!lUe7R zIS=1h^9#(|uPZsj;b4u>=}kAZEVt&*etUo7PgCXt6BoNPRAeUoxUYWUer+Jv_XiX1 z=-*{nq1gK;|NG2;SC&4i_;FKkALpE|{ko>APSsB=W_4`J{Jz<0`?<#x%^s=e_QW-N z?BIR4vn55GJ6`Vb)PwxekA6k9BrjGD>abazHgi$*g4Y{GT%SsXiCwenTi79-)3*NV zC%Yfd-k+%#{bahajV0)@rsk1vc`tdhBW~^y>U*}tFyYVM=lhR)NO4@;%)KIO%a%5a zZ)dFH_4nMLaA4ulLl;VCo=lsXrMG&inPC6PluiA8_VLfpeachy;aR(RzwCvO+43lRD^V-0&rdS%y*mrScxJ+z4C*|R3N&}P}Xd*AMg%XvNc zv(vb!N^Nb3=#AIX(y}Yp=4`#HI{9S6(@&><7N@HmcvW=J|IRGg8?2obK7QwyOm(p- zQ}|*3wo~|9AKYRmqqFm<|8-GA+xnf=G+>5n#WsfC+jA^C1Gj~pz4@yD*WuZE zCZ~(GPVqX~xbc8PUCg|Kf~S`L!jlik7u=a!e*d4s`Md`o@7#QLE&X@i`F-=>KmS{4 z|Ni;spLP5DRlJ4DFPW5^{Qlo`z}Y`f?ARKnk5{gpcTxEmxZOLUEm6($sDFb*zsA39 zq8Yb8^RYd(;(T82E+W5?N!quRNnvTV*-B5-Df_KOW*Ez_3A`I6sJY={h|RK#=EZJ{Zai#g>$SA|JnKd(w^_kzv|!56SH|F z_2cZtqlSL>abhm3NvW z`9S5t*VWmlH`qBIJ#Ee6@IO=g`tKZuGbiF?KE&@Wl1!9ODEn7ba*^#`#otP5T4*&4&Z3wPo2)ov2%q5fu}f z8?k3$ScM4hMK;^k=vxwRH!7Tt%Gy8M_0Sy47>oA~tB-uRr?1IyV$(Fy=<3j`2e+_< ztz9kl?&IkQKiOl?KX0%+FZDt7?tIU$2Q6#vL?2luKPli#8)raox42l@VvT*bl>?%- z#-6a!Ri3Nf&}qIqG4N&Pl6#X6e_Vg|#@yN^XUsPh9Zf!S=Ir73*M)@_`^^3`jit-{ zN>}LXRjqbWhXb;+C*()}b-5|BR!`mTVV;rqsU0^i$$XeTLyKX>?YGBYPd%(2@bi`4 zM1koiJf3sr^v1XGZ2KB@;bqB*P182le=({!C;4G%oGwq0k7;9_J9}So*rxXG#1L~$ zg>OMM4=R6rigc^iVc4;D|E2dY4w%|p{QvDnn$dI77WV^RE}0cB-OTJ7_M+3i$^Z3S zkqJ7_886%`P4POgZJYCfvsICEwrM>%DB`l<|LwmKZ*wp8F4}yf&(m&xJFD{PiMCwa zZqqIc+fS^h$(eGH`<%iC!R5*!dZH}0J3Ui#jJ_?rxMRbOKF_%S7F+xOxt8tg z{PQ~d!%v%txwDi9=Le!U^LsRNMXaq|F_=#IREm# Yjd0Jsz*k)U3=9kmp00i_>zopr0Oig;`Tzg` literal 0 HcmV?d00001 diff --git a/assets/pixellab/sprites/agent_thief.png b/assets/pixellab/sprites/agent_thief.png new file mode 100644 index 0000000000000000000000000000000000000000..3154b2291ffe08c9edeaff6bd13bcd2dc850c1a5 GIT binary patch literal 916 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANOK(Vi}jAr*73PCK73?J9EI zzB~6##lnv|cYP1dy79#Qc8EaotSt(Rj|46jIBKmrrRct+Kx_J;mEn4K9x&B23b9u` zWm@GhM}t>%Y35|J93h`ecU9I29WULI-R68Fbncape%z~m+?#$QW_4|zseK|jS)WPZNA>2~pO^gC}%6aw!Po9YuB-_v!^E=4O23R&^cZAmN)B>dE5zI zw{KGyu>b$4F0t#6p3?iz&Tpml&ebpcv!jor`v0F7teG#i+0;IY*kWg2PP9IE)OxwNbOGH}t-&0dFXVoz*Si<@>D|7)(LdGyD=sh^?KubNzYe!xwUAzL(9k{@Z5!=*f|l_3@m}Z>}|0 z3ofgDx6JvDVC+nXtFL2jUii1VOu0<_Nws^*k6+Q}zU+I>bGI*Q>*V}5JRFGzHX%K8 z8&^F)_9=8y((%ZyD|z-Uk4y?Oemvxq*roeC{rL(Vt2Jw@3V$$N_`=L*r>gX+pCxUb h!sBzS{XF%|6aM)abU7U6VPIfj@O1TaS?83{1OOxMzo7sC literal 0 HcmV?d00001 diff --git a/assets/pixellab/sprites/henchman.png b/assets/pixellab/sprites/henchman.png new file mode 100644 index 0000000000000000000000000000000000000000..0da51f085d14861b317693da2d33fc0d059fb0f5 GIT binary patch literal 1505 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 Hr-UW|X5mG} literal 0 HcmV?d00001 diff --git a/assets/pixellab/sprites/minion_technician.png b/assets/pixellab/sprites/minion_technician.png new file mode 100644 index 0000000000000000000000000000000000000000..38e87ffce1eed1d2d562e175e0fe145c2d01bcba GIT binary patch literal 1523 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANN>z7y&o8VzHf9Lx-pY8t_zu)=& z;D4PY!fkf(W~Z<7x8IN}pRp!h=;lsq$%cc?cMNCi-pStKd*Dt=S<6+% z2an&Xd#zr#J-W@0QKPHp=&dtzb_O#@nC9rXJ`MNq)m%K?U7m@Fed~q)Q9K;X+WX%# zA7Z#+_2vH3T#kT{x}%nR4PJ2W5ooxy>UGeOOOYu{!e8yWGQ~(~TFW9n$;(djr&M&V zie9P^dD6n9;l<7EFFNX$GcbsVw;bj)2&MNXQd{?n)uB=>{Dh19qX0;sUpAe zdVE>oI!UX&yvO%_;cP7SF3pnNWb#M0c8!J+2lKy!|NP!FEx+zi|G%QTU}f#`S!v3j z-Sd|>Z)Xy?8=|eGn|87G_9U^~D`$5EF8arCbgBEytT|UsbuK!gBWXMPjZ3`B8=kpV zbFOBJx1@V*xVLt_NTy-;vv+H6|JZu@xTLI6>y0asG92>{D4$NQ&AVBry;U`RL*}>V zcP6v4oS*6A)bDdql7sWXY4-A?QT@|Z8$7xrkG%Ui=U$rh){7s7ZtySq{j~LtrgrL+ zp8k!Q{1Zg^|H>~|rZTfV}qfxy18O1m4iXNYAv)0KnEO>vyL*=L3Vz*qy zOZAqep8{~I?VwtkE}OUgF+&K#1*LT*2gEciTc%9zC(9 z=RR#ejNcl6ShFH--?vbW$WFek!F%iuc0Y-o$HN_QutV@7gNSI$3$yR1K7ZMmta~PA zx8&^GBCCqSjVn&QG)vz4ih0%a^&PV|^mX37?=Ufz@kT|8f!bzICIK`5F7N(r9PduV z99qC$?&0Jj7kq#Hf#bK=pOp@}%_9*i_;i2cnbprvqo?cD(e> zqIQqnLGH;nRaUx%)<|vWJoATpPX3+?&vsr&(>9ywd+C~YJcsMViP!gV3r3gx{c^tL zMxCx)gWGD>@@DSdFz@aM7Z;Xu^g5=0XjR#@GK}ZO=ExOpp$sanm0ew16apuTEqNWX zSSw_))~d};E^c=WCJNkiULO7RlW1{!Tc_UC2az8?eiNRxR&w%9m8&A>g!abG?AI(- z<}L02n%~g1Md9JIyz@JjEa+(HKc&jf;5yOTcG_IAt1G&m-I}~;rJnbbxAnf~*C^?F znAon_V*L22_LsR=I!idGD$fpmytts;xWMc?&&~cK#t2(Orkl^$9G+b*W_V)qynNQq zV1|&zS~A}ot_mwNc$~K6Kal!%)4#YYEv3IKKEJZGwm8|Pw0j%(5^tU#6~8%sH!svM vnsx2hrk`K_o;S?j75wS_m4Evu?Pomkx~5#P)cZRF0|SGntDnm{r-UW|^m^Ks literal 0 HcmV?d00001 diff --git a/assets/pixellab/sprites/minion_worker.png b/assets/pixellab/sprites/minion_worker.png new file mode 100644 index 0000000000000000000000000000000000000000..88e798f711fbde1820521c85184d503757a277d6 GIT binary patch literal 1077 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 NJYD@<);T3K0RSFqe?tHO literal 0 HcmV?d00001 diff --git a/assets/pixellab/tiles/barracks.png b/assets/pixellab/tiles/barracks.png new file mode 100644 index 0000000000000000000000000000000000000000..edb40e9a49551a31a1a2a64004b62e5ae315a476 GIT binary patch literal 2509 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNvQ#@T9Ln`JRot`;CBwg}& zeeJm~XWqzEZ~o3^c0fo>NFrgnH;0Q*k`Ql_&XNl*r!Q&sZ@Qw@A8{}2)Z=EiVhv9Z zp3W8*;ogr9Dx8~Iv{_ml4jsCuV_kjrjg0Nx{PN$4C)PxJy6V{fsC)J9`^)YB-~a#l ze|}w@rr63aKkWIw-c?ieJpOr2=J(W#Rt!4Y?)SWuSypI8DDfNU{;OwOu-dNW!^Mzd zS*Mf}5y?G%Uly;ntEuXkGxOjF_U?~|&MA3TeY`ofVHVqg51|WIYHbtPvCi|{83qHR zd(9hin=T5}*)kn)c_lP2{o&=+3>_}n1+Bfy+88#t&U!d8k3l5#xFAzx;r(-2Izcb5 zPC0&2r2pPSVTPmq8LPUqrUnU_1YBJ?*Dr1I7v55%-I=nRXFvaZ=rq5OcBX;=&*NZk z1_^(@1wT`YUfOiMOX6`}gE0vWzEvY*9^upD43^CW2tTglU_GbR* z>K##EJjcP|`M2-2WnEUTk8{4u{c7_Q;F(f*ns@e%uYZ`&Xyj`jo8mgFz<9sox*q}z zcbVG-nM~&USY3}#P!L-6jUh>ucgk_8KvUL}moJ#M=F0CDZ1}R|&^h&T<(%aQ8cbc3 z?)F<6I^}+~(a~<#Wf5K(mu9|J+bAG@<%UW}`Ec`NKdv2~{$iVLjJi+e7D@LLJpJH6;>D;)mW9H1%rE{z+rd@pExn`Y8q_e_&xwP;6-wIw&zjZNW zuY%Q1g_MS0&(^9G9}Zxvm#OG#c1~{D(p6sO=(%88%C7GHC3Y^a=d5qEci$@GWT

zMnEb@M(XWdy*U~4y9Fm#{`|?Daj0VUO52mqzWGXfEWH#m{rrOq7yb0UsK1c6aR0XH zaENPY;mOO@A5}i~{SH_Z`R(t!$5(W80z?dA7=j*a^8NoRXtGzTVfX&8p4;5h1P!$c zH&=#jxqt9JzdcXG<1QtR!vUQ=?~?v*Q|D;Qd1QG|UrypsF}JBxsjQ?c>t(M`w-(A; z1hJjpeB<{Mv31e^YWwEAbD5F9=wzgbd2_tvLZzT~xf={8S^jqF>GjS#C^j>5cX{mQ z3Rzug#s?eaYehVbINHLJqF9fg%okzTY5 zH-~;hi>fwdb-5=~*DcrJoNBPzuAv@gm>7l8#@0_wZh?ed5JwT-)yaO7+XH=be{{iqKBL0?^UAxew5RK*9$&nBLu zU!gfWKC=1zHhxo6R6ddM<=Va#DS6z+VLHpVzLlEy@5=L^CtHP&%D$<3BFHf5uqK1v zzn2W3ldl`vnD`w&qp{Ml+a%Jj)b{+DUso&g=6%n<5w_r#(4VaD<|l4X-g0&qr^XA7 zsgjHTU%Kd|8Mc+-63_Bz{T)kedi1$8!fc4m> zzcCgS456(#c`^@geBqIOCOmszd#*3%MWITqWbT*yerTDR`abcIekk&6X~BjolU3#> zEZ{k9RCrQcsyBjJ&}(9IfOM9^!2F`ZIQPeN2&Ocs%*;6qYRRrXZ7m)N_1x{i|3f ze7tCVsnP#4v(U*e8tY{&j=pYg=Wsu*P#f7YX-ROjE&KeaLqGrdiG(iwyfuAe>w?5% zHBnMl8(KY+9`Q1$ZC)G_8gq8ewJ?Tn{~zi5{qNBe9=5re<6rF{`kEN9Z3 z8AW@QpJn{B8AiGCpQ_U0R=$G$hj|)n_h`4m_-Z}A^=EbU= zDfTygxcrSJrS}E=FlXVCU%zh7(TbuJE(Qm+*$Fj9&C6Cry zY?!~aTinQQ;-iV_^=t=zJvIOQcYYnC#vD!+&-ApTQZ=*YUvAcaz~NY0DebJR&c#zP z?`Xjz9ru1$!#_rcHlAGic}0@uYO!N0SFBSqEa6mM^6AF9_Kqnb8_S+%iTv^5dH(X9 zEW?82du}=20paHT(zo8H6#kLY>lJw>cjMz+rl(O1k%f{{mW^w6T%NsR-oEe&Dzd)3 zLOpFAY%$l?M7fo}XZU+4<-T|OjH?#&O;3k^K0Wt4(}vQ|bLUvkcZ*={3NO)Fw!6Gx zc7BY1<(5gC^S>Eowgz}BCEPmtOHun>2-gq(3)Sj&KMsx*>hR&Z5IQ>j=nRimPW5!w%o3=E#GelF{r5}E+ndbY9v literal 0 HcmV?d00001 diff --git a/assets/pixellab/tiles/door.png b/assets/pixellab/tiles/door.png new file mode 100644 index 0000000000000000000000000000000000000000..c119c9489bf9fbc9b37d671d57b86d409fac9601 GIT binary patch literal 2221 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANMEC7v#hAr*6ar&ssHl!_j= zFMpT)Ztv#Lx89X`-%j1Gox8GO&k`F|-3uPv-9kNW87`a`B{COv&QLqDqF%yOP&upV zzvmxk-x@|Q-lj|q-H;_*x080)=1nh4PqW_qdB^+XG5>e$E-$;`Wph&Hv-R`u*3YZu z_J6hxm)QU9@y4rpAL@)grM_wHK9a=7p!jOh^f19PXPeD)-w7|$+c?9qW0$7?MIM{` zo?jVmaEpiE=s3!A=)o-h-Rdo*!`l8p{pl-+r`hRQ=A0P=PVcG+?^qW-5J%<_9bLH^6j z3*M_Yi0ds94|`}im&M_Q^^b+_PaySn{dp_r;T^U+6D!#8x=>NdAkLi@`&h_3R~P}8}FIB zgkg;v@8UUk+CE0VXGlnTzISC)=h@i>Hp0h^IhCgytNRx}dy>hZ^i+hQYwdc2Jui*< z)fjk`ukJ6A4q{k%)3dcjv3c=yMullSd9!LHoF;2XFD(D1fA*N~Y>v4TzW(fg)RH?V zZ@2%xuMgcX{|~>nmzQC&&7I9#Sq_x1iCe+LeB7HWaNA+KR_pmY*c%kS?R@mA_hg-K z(zd^94Ex?Zsz}>qA6F)wb$R)P&#m)v47r3AN!d&yIP=gKq9<|L5_$ z-2Tzj&gvU0)+m=ar3CtkhFLF9JGSt^a$X?@RsD8zuS4mhJnh z1YA!CNl71{`Z$j3&Ci`B4F#`4w=^2fyL>QnOTZSDBh&kPk~#Sfe~QxkRh-hK@?`P! ze#7e((>1nm)<~Pa5|wH&wdOxCasNBtIG@eDU31JVSDH*JIk@m_^o3KcS6)oqyZ?Q- ziUrSW<(IpjhD{KaJ^FH!!1fH5(lgs!gV!-X=+u3(#_Ng7%AHle`PQ_mxvlKjdf~~L zgMWE?a}^(3iv{H=n68`3-4PYEG;X)=@+js5{K|_?94^tnRFW92JP3SHyXyY78rXx7TBPb%YuYS}r#*UP!hPYG`&+fvtWd)=4+S?k-D;Wc>Z@FKg z-g>qN7jFN)QFi$p%b6Fy)^1GR_9E@*6>jHKOYc?Q?Oh_dh_FBvLHnK+Th1;1?Kz7z_8^z9QJ#yrw$k0Q-?0&Im()xDj9K-A|NP%c$K|Uh z1?`;iDdu>}XVH_!IX^v{4MnEfR)72OQ@^f}T}_@zp^s1W%Im0}eU(rkGe$}VnZ)*Q-Uzylo`g+nr_XzunSe+N$ z<(Iz|?&gbH*Dy;kP*qZ&=f{Q6*&luSZ*ETiu*);`ajJv{zXFR~oWzpM71w7iC^Kx4 zStJvb8xpy_Y);kc##w@sADzj#(bX^bR8Xz_t)Knbe{~Q1@6^9fKl%J~OJIk}H@6K2 zuYBEa=kJ`mGfPyzjXLkdz`(%Z>FVdQ&MBb@0E7iD AVgLXD literal 0 HcmV?d00001 diff --git a/assets/pixellab/tiles/floor.png b/assets/pixellab/tiles/floor.png new file mode 100644 index 0000000000000000000000000000000000000000..2cd9392059ff46f4ee6a44172a0041d534c10ce3 GIT binary patch literal 2786 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 literal 0 HcmV?d00001 diff --git a/assets/pixellab/tiles/lab.png b/assets/pixellab/tiles/lab.png new file mode 100644 index 0000000000000000000000000000000000000000..7ea54386c02b1be5356bb252d9bdaf67e098bdd7 GIT binary patch literal 2467 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNvS)MMAAr*64r&kw*d=))z zzx(^f^Evap#hAQ3I$GR?T3IGIDC}|0cGqGRnaJfDB^bD}kE3dp~|;hrkUQ1d|%dZ>1!;D#1z|q+m4lnpL3o6_FKgT-nMr) zTQp|Qv@~daEBdu1^|P#Fc~@S>i;OkpyET1ej_>~~zgRj-ykY+7r>~S(v^C{rNTju9 zvX=|;v|HHy^mI9S=0}eD?Q?NQ6SEF4DO>RR)me=d9gFVd?!U9d!q3EX!qbc;N);Bb z_DDCJzUuzs0#C{2KCSYAE#=aQo<~($3z#OIJoqC=U5rIf??%U+Bn7TZu{ZUl^)4T0 z)t5c9XxGW6tCIvi$Fi(g_eY;0ZFbMnCHl|qn)>{yGd?=AQ$r#`fZ@kMtxs;plHT;G zq#Ss;RbbBrxy=h3r9Q9IaMb(JTrpv%V%nrfd=~h*OqIqg2x{`lUar7xwF7Nj2w4i7u}>VUdnn#5g+_OE&Zb2oi! z4_j7smPh}^;rdg*1p=5=r2W=izQM|{K*icFYf8rZlefR?9oLC2RQ@Z{7Q8w4Z=DRBvH ze!uhJqo@5A$?K7BeyfEw>L*x1WkNW@1CDK?I9v0$W@Z_xPlzFdC zb+6iDXm|VMyW+D?s)RiKJ>H7la$YP}eD$t;_tAr;OQ#)s%)2G_>%=$TjCA%l?9nu4 zEVy&!{ogYV@APLLKlSF!JHZ{HYR`9AD3m8SI$UF3qW-1(=RUP$IpI%oNf&qU{#fEX zN5{VN+OonmZ&(;!X3l&O{OjR7leW!Y%@>tTI_#DCbzh##B8EegPEC0u!jNKGv|qmR zS*#G-x#T;?Wa6Yh*~IzlbqPIra(#Ja#fy-AoO4(du4JjLj5oS0AH(GEbZOYB=X)8# zWF*TSr18*9PU;WK+FAOm zzMuLueS?|Tnd%h35?$Lw0sbm)iMtQdqE1Crt(cgSvb0}8_2zBX2Y$IlA zcU*Ml=CF45*|ndgU%R;At`S@zb{xb&HTU0n5)4Vv?o@xO|!eOex~C#rAdKc?d? zMn_nc4|2OI9}f&Ho#JgOZm4>6Y1`g=)yh6+#CUwwU(4$UZ_BbxmH#_=tNhzXv(Ilg z$ow218F5#7az@gn9zmTmcU)HNYug#U%=opx^2^$7U2e9$-}&YqQkli^I`P^17>5;m zS?^xyxs{OgIs10R#$TEu&P%R^H|Aw@>{|C&NNB??mOqU4o36Sg7c=*@naR!gU!fwe zI90gx>x?6IHCwB#^+H|qUOSk(_B}tx-)Ct5*RHDib7E+?)cxqaQ`hgm%Y2|OzwFbU zQ%A4-(AseO@yqM!8qf9RkA1oDME!8+bN}Rx76v@M8*-MZn);l3wZ9}-Y|VP}@t z-K;9h?J!vs@2jQoWW&d+$L}+_NS1p&|9xnA+F}W%T?qlv(S3L2`fpzqcbu?dm8DP7 z9`WL@OFwrk>PgJtXgczvNi*WMtIzzmN30KcADi%R$r}rXhD9%X=FM?ly=Gx+v(LQR z-w#V)&KEcS-T89Pdh6!%@t!L-&fPL4=Yq1VNxlOk!%0qC5y%$d%)|}3>`B?^H>=s9xSPNXTfq(YNfI65%J&m6OTGsj~dbgOI0zSy}qUZ*NJSF`HRZ{{MvA_QGGql2$1^ZDL9f?jL$q zqn&(zx}<5H7(?=V?VW%7J<~1t|0*a)=Z3^uwyst7Ss&LNFh$|5BkSzLhZ@fOUh#SU zUfth*hFb*O`D7h7%&fd++PufIQSM@qFnfRu^Uus#QyX#$%+C5o@25Ze`tN)RE=EWHON?o{8@!rY1XK#E@ z{lryY9Dba^K5YJib^l~?bI%5DSlKzVW08;Z->dO#2@4iUOV#duIp^O;_o^GA%YOfU z{BHV*m!}SwZ~gjHJ2O~0c;eL*WmD7Dv(No!%#k@T;m)GN=NT9n7(8A5T-G@yGywn~ C?y)-n literal 0 HcmV?d00001 diff --git a/assets/pixellab/tiles/power_core.png b/assets/pixellab/tiles/power_core.png new file mode 100644 index 0000000000000000000000000000000000000000..baedb710f047fd63864c4cac9a89dfcc6f7464f8 GIT binary patch literal 2722 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANM^nVv3=Ar*50^k?VpSnt1Y z`Mmnv_dn-s?H6u;{cXbOB|9v58kVSScoUcur9NrNW!QexJ3Y)!yEvmv{^nd-v>7xajAW+i=b8)Mjyx6(Lhk zPfZM2Dtf)#L&8%gwQXsP@XfWH3~A{(k9w8L0@Ze$nVEPcd8+&B`!xoK4 z`nsRu3S+B7*=)|UID}_^n8UR&qRU8t`?$v0wunT%pf9o_o=a2sg)UpojQYVE6w$pz zP2jYeltJ;Tmf5Q|?AzTqvs~A~y~na6iRBD;jLrEqR(t0(b+Oj1X>w3vTA=YY^f^P< zlCYos>YF0C7kfBu3ELL)#5mygoF)4#PyV^m_0b{lqJE%ixAwXF(d-6+YqbRx1hiHQ zFsUTJK6z!$@*J^6P9efGo+_#+bAGnt&Ogr_aG$3rfmy-JYF{vug92xRd_~7XKOc|B zzx+z?ZeiQ_<|0SKW4{N#_$DoBmiYMYx2R8fmgtTp8@K)1w|aReZ)1a9(&KbJ*(F|r z)^paU6-L%%&f8NgcCma#_xm-!7?c>cg}a4kE4|ZuoU_uTUFBuRLcf^YV>lCw@Ji#kk}9D?KO8zOcs%CqJ%Q_u4m(DWF;6mB%DMg^*Qt zAxlN$Hz_l`e=g&|Q@X~WU1{Zutm-8it`kkUl;Wp~OzL>^s^f8A^aP(j^3p#q-PGzm z{YO9j_~$dC45udrTo1qhbjG$%>nyI^{gXN^D0WBc?Djg-!++CKDsr9N3{A3vbHCKR z`n~#%YVX#ohr)WR7!D=msh;@G#L>bv%~ncN`>e=XPMzv0-)g^4?C?JEnf2OLSJrEF zoqY=@9amq!dhwel8_v&tI_s~tg44#9MOTxenrB>7=-c10@cV-u!ao|fU+TK=uQlt? zG5^+d+4ud;?i*Q?mUgS3n6A3*-dBZFP7^Pm zw`s__^7wk{h3;owUl#dkUEFNN{Ly7vKu<-GRaN2de1@wG3qJqqf8eLP$&+hhX>VM; z>-sPe&EKw7&;2gPZD%cwc3C`oW#aF9`J0zzn@82PR4iiDFHp8xa>h$}l~sIE!QB-r zZ-mFY-<-9;M#y%ffy$j??dSPX-GM?o0s{>=SBScDIXVN?JEwsdFK{p|wYeCMuhozZvvR*vwm3o0ikx!T40_X>!vd*f>VMz~#G z={>LF`kyEMiUR++N9$Jn@e*4agAn{RZTH&Z{F;XciCXH&!qg^*7w-|zPQoZ7#rT1>sn#Q6IM z*{z5|dRdTDFEuTZC)vL~gggCH!BeT09bW%-$}9KB zE8P38IqUx`hQslDWOePCdUt;)%VA&e@QT3Bm&zeYrFTBfRX3dfhgH1(ugK0%k>Boo zWY{EL@aaPRrf1IKj0R=}Y=i{dGVlO1ear8ZKhb5vVWntW5+lbhEs z=Ck!)`rd6y;ddf4)bvJ+g{`2W-`-|H(4LRlP z!i9_{GZw%7qq5Jkd($#z@9#G=Ok8Upoa&cPxuUOhBs7J+B!0nc7InQjD%)zgkGk*g z%g_(H^^e_yv-ipRIw9V<`Z z{x!9*BxB!mg<|)($6fzqpBxiEVWG8lrp71jC2ap*ch)aj)};UAlg+?Ty3Jr;pd%{_H4L{%)OBl+`a5Pi42jlP)hsLW>@AcWl2KboX-IlTf{V zUu5=geSJ7ESEjo0;GN47PopkhZ%2{QXdHvt))TpxWf5DOy zx-GfZ6U%ZOJ63metIa)J+!MQ*^Ohd3TzcF=+h0;&t=BEur|4IGK~`I%~(HY zRhsA`?(Cg5{m->kgtu~(nyy_aU-4g`;e5Ek7Pg#~PQR!A&d7ZCbS+zFK(waA`Hd@d z&RqQRY4?`=dkyx6XRRL}H+);DQ!nK?B|I?u=He5JnpSQ3v_H?izpiY{PAdim1_n=8 KKbLh*2~7Yw=|ofj literal 0 HcmV?d00001 diff --git a/assets/pixellab/tiles/rock.png b/assets/pixellab/tiles/rock.png new file mode 100644 index 0000000000000000000000000000000000000000..5c215a2cff1d858d11529af161694a077ed16e9e GIT binary patch literal 2636 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 WEVQlpoyx$#z~JfX=d#Wzp$Pzug1emn literal 0 HcmV?d00001 diff --git a/assets/pixellab/tiles/trap_fire.png b/assets/pixellab/tiles/trap_fire.png new file mode 100644 index 0000000000000000000000000000000000000000..6ac2ee301bc4fb6ba0eede9ca7d0770e9054dd50 GIT binary patch literal 2771 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 O7(8A5T-G@yGywoF3|Jrl literal 0 HcmV?d00001 diff --git a/assets/pixellab/tiles/trap_spike.png b/assets/pixellab/tiles/trap_spike.png new file mode 100644 index 0000000000000000000000000000000000000000..5a1f6003b6736d717a4f23f06cdb0eb30ddfb3f4 GIT binary patch literal 2603 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 literal 0 HcmV?d00001 diff --git a/assets/pixellab/tiles/vault.png b/assets/pixellab/tiles/vault.png new file mode 100644 index 0000000000000000000000000000000000000000..f0a455262149c8b93901f23f2313587f4b20b37c GIT binary patch literal 2886 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 10 starts a raid countdown; hotter burns the + countdown faster (1 + heat/50 per tick); notoriety + heat set raid strength; + an intel warning fires ~12s before arrival; repelling a raid vents 10 heat + and pays salvage. A cold lair is simply never raided. +- Terminal frontend rewrote down to a thin view (~430 lines): SPACE/p pauses, + +/- scales time, powers work anytime, world map is a modal not a phase. +- Deleted the 1,900-line legacy binary (`src/main.rs` + friends) that predated + the lib split. Net diff: **-1,434 lines** while adding a whole system. Great + feeling. +- Save format grew a `SIM` line (tick, raid countdown), backward compatible. +- 130 tests (19 new on the sim), clippy clean. + +## Notes & gotchas + +- The old code only accrued income inside `update_resources()`, which was + called on *build actions* — passive income basically didn't exist unless you + kept clicking. The economy tick fixes that structurally. +- Smoke-testing the TUI through a pty caught a real crash: `script` reports a + 0x0 terminal, layout math went negative, `as usize` produced a capacity + overflow panic. Added a 60x20 minimum-size guard. Lesson: pty smoke tests + are cheap and find real bugs — keep doing them. +- `Instant::now()` still lives in the frontend only. The sim itself never + reads the wall clock — protect this; it's the multiplayer/replay seam. + +## Known debts (deliberate) + +- Scheme minions are **consumed**, not deployed-and-returned. Wrong tradeoff + long-term; fix when schemes get risk/failure rolls. +- One global "agency" pool. The escalation ladder (investigator → infiltrator + → strike team → siege) and per-agency heat are the next threat iteration. +- RNG is unseeded (`rand::rng()`) — fine for now, but determinism guardrail + says this becomes a seeded, serialized RNG before any multiplayer work. +- Raids in progress aren't persisted; on load the raiders politely withdraw. diff --git a/devlogs/2026-07-05-pixel-art-pipeline.md b/devlogs/2026-07-05-pixel-art-pipeline.md new file mode 100644 index 0000000..6863b5e --- /dev/null +++ b/devlogs/2026-07-05-pixel-art-pipeline.md @@ -0,0 +1,41 @@ +# 2026-07-05 — Pixel Lab art pipeline + starter asset pack + +First step toward Milestone 3 (make it beautiful): a reproducible pixel art +pipeline using the Pixel Lab API (token: `PIXELLAB_API_KEY` in `~/.zshrc`). + +## What shipped + +- **Skill:** `.claude/skills/pixellab/SKILL.md` — documents auth, endpoints, + conventions, and the regeneration workflow, so any future session can extend + the art without rediscovering the API. +- **Generator:** `.claude/skills/pixellab/scripts/generate.py` — stdlib-only + Python, single-image or batch mode. Batch mode is idempotent (skips existing + PNGs), so re-running the manifest only fills gaps. Retries on 429/5xx. +- **Manifest:** `assets/pixellab/manifest.json` — source of truth for the + starter set: shared style suffix ("dark evil lair theme, muted palette with + purple and teal accents"), fixed seed 1337 for coherence, per-item view and + transparency settings. +- **Starter pack (23 images, 32x32):** the Supervillain, 4 minion classes, a + henchman, all 5 agent types (`assets/pixellab/sprites/`, transparent, + low top-down, facing south) and 12 key tiles — floor, wall, rock, throne, + power core, lab, vault, barracks, guard post, spike/fire traps, door + (`assets/pixellab/tiles/`, opaque, high top-down). + +## Gotchas learned + +- The OpenAPI schema says 16px minimum, but transparent (`no_background`) + generations are rejected below 32x32 ("Canvas must be size 32x32 area or + larger"). 32 is the real floor; we standardized everything on 32x32. +- `/balance` returning `{"usd": 0.0}` does not mean generation is blocked — + the account is generation-credit based. Test with a real call. +- Responses are `{"image": {"base64": ...}}` PNG, ~5-20s per generation. + +## Next + +- Wire the sprites into the Bevy frontend (replace the flat colored rects) — + that's the real start of Milestone 3. +- Use `/rotate` to get 4-direction facings for the villain and agents once + entities actually render with direction. +- `bitforge` (style-matched generation from a reference image) is the tool for + keeping future assets consistent with this set: pass an existing sprite as + the style reference. diff --git a/devlogs/README.md b/devlogs/README.md new file mode 100644 index 0000000..8ba123d --- /dev/null +++ b/devlogs/README.md @@ -0,0 +1,10 @@ +# Devlogs + +Development notes, one file per working session or theme, named +`YYYY-MM-DD-topic.md`. These are the informal record: what was done, what was +decided and why, what broke, what's bugging us. The formal design record lives +in [DESIGN.md](../DESIGN.md) (vision, pillars, decisions log); devlogs are +allowed to be messy and opinionated. + +When you finish a meaningful chunk of work, add an entry. Future-you reads +these to remember why the code looks the way it does.