# WARDROBEGOD — state of play + how to improve it heaps *Recon 2026-07-24 across JING5 / ultra / m3ultra. Every fleet claim below was spot-verified live (see §B).* ## TL;DR The **bench works, the wardrobe is empty, and one bug is dangerous.** The three-column three.js dress-up shell runs, the local Blender pipeline (convert / scale / decimate-keep-weights / **fit** / assemble) works, and the Cloudflare flux generator works — but `library/` holds **2 bodies + 1 garment PNG (which is invisible to its own UI)**, `out/` and `jobs/` are empty, the trellis tier is dead (no `MB_TOKEN`), and `/api/blender` is an **unauthenticated arbitrary-file → Blender** primitive. Meanwhile the fleet already contains *everything wardrobegod is trying to become*, several times over: - **NPCFACTORY** (ultra) — a further-along dress-up bench: **17 finished rigged, walk-animated NPC GLBs** + a **completed reskin engine** (paint clothes onto a body's own UV atlas). - **90sDJsim** (ultra) — a shipped $0 2D wardrobe: **441 authored transparent-PNG garment sprites** + a self-healing doll compositor. - **MODELBEAST** (m3ultra :8777, **UP, 26 live operators**) — free local **virtual try-on** (`mflux_image_edit` = "Edit Image (local, Qwen)": *"put the shirt from image 2 on the person in image 1"*), flux, RMBG-2.0, TRELLIS.2, Hunyuan3D, SF3D, layered-RGBA cutouts, MoMask text→motion. - **character_kit_modular** (ultra) — a socket-swap costume engine on rigged mixamorig bases. - **MIRPAMO** (everywhere) — a local, offline Mixamo (auto-rig → 22-bone mixamorig + retarget). - **~2,394 + 2,548 + ~163** animation clips already on disk. **The decision:** stop treating wardrobegod as a Blender-op bench and make it the one thing the fleet *lacks* — the **canonical garment/outfit LIBRARY + a dressing-room authoring UI + a multi-consumer EXPORT HUB**. The dressing *engines* exist five times over; the connective tissue exists zero times. Graft the fastest proven engines onto that spine (reskin, try-on, the 2D doll, donor-harvest). --- ## A. Where it's at — honest state of play ### Works today - **`server.py`** (stdlib ThreadingHTTPServer :8150): `/api/lib`, `/glb?p=` (Blender convert-cache), `/file?p=`, `/api/upload`, `/api/blender` (op dispatch), `/api/gen` (CF flux), `/api/rmbg`, `/api/to3d`, `/api/hangable`. No build step. - **`blender_ops.py`** (166 lines): `convert / scale / decimate-keep-weights / fit / assemble`. The **fit** op (data_transfer `VGROUP_WEIGHTS POLYINTERP_NEAREST` + armature parent, `blender_ops.py:128-132`) is the proven wardrobe mechanic — wrap it, don't rewrite it. - **`web/index.html`** (316 lines): OrbitControls + GLTFLoader stage, 3 tabs, body/garment lists, mixer that auto-plays `animations[0]`. - **CF flux** `/api/gen` → `@cf/black-forest-labs/flux-1-schnell` works with only the CF creds in `.env`. - Blender 5.1.2 + PIL present on JING5 — the whole local pipeline runs with **no farm dependency**. ### Content truth (the real problem) ``` library/bodies/ phrtt2.glb (1.67M), droidte2-18k.glb (7.97M) library/gen/ brown-corduroy-jacket.png, -cut.png library/garments/ brown-corduroy-jacket-cut.png ← INVISIBLE to the UI (bug #2) out/ jobs/ EMPTY .env CLOUDFLARE_* only — NO MB_TOKEN ``` **Zero garments have ever been fitted to any body.** ### The bodies are not the consistent A-pose set the brief assumed The 6 `~/Documents/anatomy` FBX (verified by headless render): **2 A-pose** (`dudescholng`, `2_views_3d`), **2 T-pose** (`phrtt2`, `droidte2`), 2 arms-down/contrapposto. **5 of 6 are unrigged**; only `droidte2` has a skeleton (41-bone reduced mixamo) **and it's already clothed** (shorts+boots), 482k-tri raw. Each is an independent TRELLIS reconstruction — **no shared topology, own UV atlas**. → **One fitted garment can't be reused across bodies; each needs its own per-body fit, and only shrinkwrap/proximity works (no vertex correspondence).** ### The real bugs (file:line) 1. **SECURITY — `/api/blender` is unguarded.** `allowed()` guards `/file /glb /api/rmbg /api/to3d /api/hangable` but **not** `/api/blender` — `fx()` passes `a['path']/a['body']/a['garment']/ a['garments']` straight into `glb_of()`→`run_blender()` (`server.py:238-265`). Under the documented `WG_HOST=0.0.0.0` (`server.py:7`) that's an **unauthenticated arbitrary-file → Blender import + library-write** for any tailnet peer. `allowed()` itself is sound (`server.py:58-61`) — it's just not called here. **Fix before any 0.0.0.0 exposure.** 2. **`scan()` hides PNG garments.** `server.py:67` uses `MODEL_EXT` for `garments`, but `/api/hangable` writes a **.png** there (`server.py:374`). Every hanging-texture / doll cutout is silently filtered out — the whole 2D route dead-ends in an unshowable directory. **One-line fix, prerequisite for 2D.** 3. **`glb_of` cache-key collision.** `server.py:96` keys on `slug(basename(path))` only, single-source mtime check (`:97`). Same-basename files in different dirs collide → serve wrong geometry. 4. **Silent corruption in `mb_download`.** `server.py:156-157` writes `json.dumps(data)` when the farm response isn't bytes; a JSON error body gets written **into** the target `.png/.glb` and the job is marked **done**. Affects `/api/gen /api/rmbg /api/to3d`. 5. **`JOBS` leaks unbounded** (`server.py:50`), and `glb_of` spawns a `convert` job on every cache miss even inside synchronous GET `/glb` (`server.py:98`), orphaning records. 6. **Local rmbg keyer is crude** — iterative border flood-fill through near-white (`>232`), binary alpha, `server.py:329-344`. On a non-white bg it never seeds → **silent no-op opaque copy**. 7. **Rigid-attach is ephemeral** — `web/index.html:215-225` clones into three.js and **POSTs nothing**; the toast admits *"preview only."* Attach transforms live only in browser memory. 8. **`fit`**: picks body as `max(meshes, key=len(vertex_groups))` → multi-part body donates weights from one mesh only (`blender_ops.py:115-117`); no `matrix_parent_inverse` (`:131`). 9. **`assemble` trusts an unenforced bone-name contract** (`blender_ops.py:151-161`). 10. No auth / CORS / rate-limit / delete / thumbnails / search; gen filenames overwrite silently. > **Not a bug (verified, don't touch):** the suspected `decimate` `modifier_move_up` infinite-loop / > 30-min hang **does not reproduce** on Blender 5.1.2 — the operator returns `{'FINISHED'}`, loop exits > in one iteration. Code smell only. ### Convention drift - three.js from **unpkg CDN** (`index.html:133-136`) — house style is **vendored** r175 (breaks offline / un-shippable into a game build). - README frames the generator as MODELBEAST-only; commit `6f32c08` quietly made **CF the primary** flux backend — a cloud path outside the LOCAL-FIRST doctrine. - "Only dressed outfits ship into games" is **one unenforced README line** (`README.md:45`) — no code gate. --- ## B. What the fleet already gives us (verified live 2026-07-24) ### MODELBEAST — `http://100.89.131.57:8777` (m3ultra), **UP, 26 live operators** ✓ Bearer `MB_TOKEN` (on disk at `~/Documents/backnforth/.env`, len 44 — never paste). Contract: `POST /api/assets` (multipart) → `POST /api/jobs {operator, asset_ids|asset_id, params}` → poll `GET /api/jobs/{id}` → outputs = assets with `parent_job==id` → `GET /api/assets/{id}/file`. `main.py:290-293` already accepts an **`asset_ids` array** → multi-image try-on is submittable today. Wardrobe-critical live operators (display name → slug): | Display name | Slug | Use | |---|---|---| | **Edit Image (local, Qwen)** | `mflux_image_edit` | **virtual try-on** — 1-3 imgs, *"put the shirt from image 2 on the person in image 1"*. The key unused capability. | | Qwen-Image-Layered (local) | `qwen_layered_local` | image → N editable RGBA layers = the "paper cut-out layers" rep, generated | | FLUX (local, MLX) | `flux_local` | flux2-klein-4b, ~40s, ungated | | Remove Background (local) | `bg_remove_local` | RMBG-2.0 matting (better than the local keyer) | | SD1.5 + anatomy LoRAs / SD+LoRA (ComfyUI) | `sd_local` | OpenPose T-pose ControlNet + IP-Adapter identity lock | | TRELLIS.2 (SOTA) / TRELLIS.2 MLX | `trellis*` | image → GLB (~2-5 min) — **single-image only** | | Hunyuan3D 2.1 (local MLX) | `hunyuan3d_mlx` | image → GLB, no HF login | | **SF3D (fast draft)** | `sf3d` | image → textured GLB, seconds — good for quick garment blockouts | | **Motion (MoMask)** | text → BVH motion (+mp4) — text-to-animation | | | Upscale (SeedVR2), Brush 3DGS Train | — | polish / gaussian-splat | Copyable stdlib CLI: `~/Documents/MODELBEAST/mb` → `./mb run flux_local -p prompt=... --wait --download out/`. Launch pattern: `export MB_TOKEN=$(grep '^MB_TOKEN=' ~/Documents/backnforth/.env | cut -d= -f2); python3 server.py`. ### NPCFACTORY (ultra `~/Documents/NPCFACTORY`, 410M) — the further-along sibling ✓17 banks confirmed - Same stdlib + **vendored** three.js house style; already has orbit stage + clip dropdown + speed/height-normalise, click-a-part bone-attach dress-up, recipe JSON, in-UI Blender bank-builder. - **17 finished rigged, walk-animated NPC GLBs** in `library/banks/` (tradie/cop/goth/nanna/postie/ busdriver/bizdad… 7-25MB each) — instant dressed+animated characters to load. - **The reskin trio** (E6 COMPLETE, all 3 confirmed on disk): `tools/render_plates.py` (bind-pose front/back EEVEE ortho plates, 1024, transparent), `tools/align_plate.py`, `tools/bake_skin.py` (Cycles DIFFUSE projection bake onto the rig's own UVs, front/back via `Normal.Y<0`). `archetype_batch.py` = batch factory template. - **Constraint:** reskin only works on **single-mesh / single-UVMap / single-material** bodies — **John's nude TRELLIS-2 figures are exactly this class.** (`droidte2` is disqualified: multi-part, clothed.) ### 90sDJsim (ultra `~/Documents/90sDJsim`) — the 2D wardrobe, already shipped ✓441 sprites confirmed - **`web/world/media/doll/` = 441 transparent-PNG garment layers**, `_i_.png`. Runtime compositor `doll.js` (704×1408, ORDER base→bottom→shoes→top→hat, bag last). `doll_layout.json` nudges. - **Self-healing loader** `server.py:167-178`: `_art_slug = re.sub(r'[^a-z0-9]+','_',name.lower()).strip('_')`. **Drop a PNG + restart = that garment wears its own art, zero code change.** - **$0 generator:** `tools/{gen_wardrobe,doll_composite,doll_stage,build_wardrobe_manifest}.py` — prompt → `flux_local` on **solid green** → `bg_remove_local` → stage onto 704×1408 via measured `SLOT_DEF` anchors. Prompt template + 321 authored items + 432 reference JPGs exist. - **Caveat:** the full doll pipeline is **ONLY on ultra**; the JING5 checkout is stripped → export-to-djsim must rsync to ultra. ### character_kit + character_kit_modular (ultra canonical `~/Documents/character_kit/`) - Rigged mixamorig bases (65-bone) + already-rigged wearable props (`rigged/{w_beanie,w_felthat}.glb`, `props/modular/{beanie,buckethat,felthat,boombox,camera}.glb`). - `scripts/merge_anims.py` — base rig + N anim-only FBX → **one multi-clip GLB** (NLA tracks). - `modular/scripts/`: `cut_parts.py` (cut a mixamorig char into swappable socket parts), `assemble.py` (`attach_part`, `fit_part` cross-rig auto-scale, `attach_attachment` bbox-fit+bone-parent), `texture_variants.py` (numpy hue-mask recolour). `parts_library/library.json` = the garment-registry schema to copy. ### Animation banks - **ultra `~/Documents/MOTIONLIB/green/mixamo_full` = 2,394 anim-only mixamorig FBX** (1.3G, shippable w/ attribution) + `cmu_bvh` 2,548 BVH + 100style/accad/kaykit/quaternius. - **~163 local mixamorig clips** already on JING5+ultra — enough for a showcase set now, no downloads. ### Garment donors + bodies - **ultra `~/Documents/3D=models/characters/people-normal/` = ~40 clothed, mixamorig-rigged FBX** (`man_suit_01`, `man_dj_streetwear_01`, `woman_raver_01`, `man_worker_hivis_01`…). **Exclude `actorcore-unreal/` (RED, native-only).** - Clean multi-LOD nude base: **m3ultra `~/Documents/trellis2-bench/anatomy_{2000,8000,30000,50000,800k}.glb`**. - ultra `3d-from-m5/AUDIT.md`: of 4278 files, **43 are rigged + game-budget (≤10k tris)**. - **fluxgod** (JING5) — `mb.py/a1111.py/openrouter.py` multi-lane client with restart-safe queue + autocrop. Copy wholesale rather than re-implement CF-only. ### Two honest fleet limits (do NOT build against these) - **TRELLIS.2 is single-image** — do NOT build a "4-view sheet → TRELLIS" bridge; multi-view is only for reskin plates / QC. - **No live vision model** (m4pro Ollama = text `qwen2.5:7b` + `nomic-embed` only) → **auto-tagging garments is NOT an existing capability** (needs a `qwen2.5-vl` pull or paid OpenRouter). MODELBEAST has a local text LLM (Qwen3-30B) but not a captioner. - **No garment/clothing LoRA exists** — styled-garment fidelity is prompt-only until `brush_train` makes one. --- ## C. The plan — phased, each ending in a demo **Guiding principle:** the data model (§D) is cheap stdlib JSON — it goes in Phase 1 and every phase populates it. Fast/proven engines first (reskin, try-on, 2D doll), quality-core cloth mid (donor harvest), UI polish last. ### Phase 0 — Unblock (½ day) 1. **Bug #2** (`server.py:67`): add `.png` to `garments` scan exts → cutouts/doll layers become visible. 2. **Bug #1** (`server.py:238-265`): call `allowed()` on the blender-op paths before any 0.0.0.0 exposure. 3. **Export `MB_TOKEN`** at launch (unlocks try-on, RMBG-2.0, trellis) — LaunchAgent or launcher script. 4. **Bug #4** (`server.py:156-157`): check content-type/magic bytes before writing a farm response; mark the job `error` on a JSON body. ### Phase 1 — "It dresses and it moves" (1 day) → dressed, animated character on screen - **Track 1 — the stage moves:** add a **clip dropdown + play/pause/scrub** (the mixer exists at `index.html:191-194`; there's no selector). Build clips via `character_kit/scripts/merge_anims.py` (base rig + ~10 local clips → one multi-clip GLB, NLA tracks) → rsync to JING5. - **Track 2 — it dresses:** load a rigged mixamorig base; rsync one NPCFACTORY bank NPC (already dressed+animated) as the guaranteed floor. Attach a rigid hat (`character_kit/rigged/w_felthat.glb`) via the existing bone-attach, but **make it persist** (POST an `outfit.attach` record, not just an in-browser clone). Add runtime `material.color` colourway tinting (free). - **Demo:** a rigged character **walks on screen wearing an attached hat**, clip dropdown switches animations, a colour swatch retints it. - **Stretch (starts the real nude-figure track):** kick off the first reskin bake on `phrtt2` (T-pose, single-mesh/UV — ideal reskin class): `mirpamo rig phrtt2.glb` → `render_plates` → repaint → `bake_skin`. ### Phase 2 — Reskin engine: paint clothes onto nude bodies (2-3 days) Copy the NPCFACTORY trio (137 lines). New `POST /api/reskin`, mirroring `run_blender`+`job_thread`: ``` 1. blender -b -P render_plates.py -- body_rigged.glb plates/ → front.png, back.png 2. MB job mflux_image_edit asset_ids=[front.png, garment_cut.png] "put the garment from image 2 onto the person in image 1, keep exact pose+silhouette, plain bg" 3. blender -b -P align_plate.py -- edited_front.png front.png aligned_front.png 4. blender -b -P bake_skin.py -- body_rigged.glb aligned_front.png aligned_back.png costume.png 5. three.js: material.map = TextureLoader().load(costume.png); needsUpdate=true ``` A **costume dropdown** swaps `material.map` at runtime — instant, free, reversible toggling between pre-baked outfits. - **Demo:** pick a nude TRELLIS body → pick/generate a garment → walking clothed character; flip a dropdown to change costumes instantly. - **Ceiling (say it out loud):** the nude *silhouette never changes* — sells tight/printed garments & uniforms & mid-distance figures, but a jacket reads as a jacket-print bodysuit. Hero silhouette garments need Phase 4. ### Phase 3 — The 2D paper-doll product + first export contract (2-3 days) Adopt `90sDJsim/tools/{gen_wardrobe,doll_composite,doll_stage,build_wardrobe_manifest}.py` wholesale. Emit `media/doll/_i_.png` honoring `_art_slug` exactly. Wire `qwen_layered_local` / `bg_remove_local` for matting-grade cutouts (upgrading the crude local keyer). Import the **441 sprites** as a starter pack. `POST /api/export {target:"djsim", outfit}` writing over rsync to ultra. - **Demo:** generate a garment → it appears as a doll layer → **drops into 90sDJsim with zero consumer code change** (self-healing `DOLL_ART`). Highest-ROI, lowest-risk value on the board. ### Phase 4 — Quality-core: real 3D cloth via donor harvest + hide-masks (8-9 days) New `blender_ops.py` op `harvest`: import a clothed mixamorig donor → `bpy.ops.mesh.separate(type= 'MATERIAL')` (**Blender copies all vertex groups onto the separated garment automatically — the whole trick**) → purge empty groups → `attach_part` → `__-harvest.glb`. `/api/wear` runs `assemble.py fit_part(anchor=mixamorig:Hips)`. License-gate: exclude `actorcore-unreal/`. Batch the ~40 donors → **~80-150 pre-weighted staple garments** at $0. - **Graft from proxy-standard:** author `hide_torso/hide_upperarm/hide_thigh/hide_shin/hide_foot/ hide_scalp` vertex groups once, apply an inverted `MASK` modifier per garment's `hides` list — **replacing the 3mm DISPLACE "puff" hack** (`blender_ops.py:122-124`) — so nude skin stops poking through. - **Demo:** a real jacket (collar/cuff volume) on a mixamorig body **bending correctly through a walk clip**, no skin poke-through. The only route that looks like a person in actual clothes. - **Ceiling:** garments captive to donor proportions (clip/gap on dissimilar bodies), wardrobe donor-bounded, 65-bone donor vs 22-bone MIRPAMO leaves cuff verts under-driven. ### Phase 5 — Dressing Room UI + full export hub (1 week) Rebuild `web/index.html` as a real dressing room: **vendor three.js r175** (drop the CDN), thumbnail garment grid with slot tabs + tag search + license filter, live click-to-swap composing by *reference* (never re-bake per click), a 2D-doll preview toggle (reuse `doll.js` verbatim), save/load/randomize outfits, and an **export dropdown** (djsim | thriftgod | procity | not-tonight | glb). Add a `render_thumb` Blender op (EEVEE 256×256 A-pose). Gate every export on `license != "red"` — the only actual enforcement of "only dressed/green ships." --- ## D. The data model (actual JSON — stdlib files, no DB) `library/index.json` written on every mutation, read once by the UI. Replaces `scan()` (which returns only `{name,path,kb,home}` and drops PNGs). **Slots & layers** ``` slot ∈ head | torso | legs | feet | hand_l | hand_r | accessory | bag layer (draw/stack int; drives 3D normal-push AND 2D doll ORDER): skin=0 underwear=10 legs=20 feet=25 torso=30 outer=40 head=50 accessory=60 bag=70 ``` **Garment record** (`library/garments/.json`) ```json { "slug": "coogi-multi-knit", "title": "Coogi multicolour knit", "slot": "torso", "layer": 30, "skeleton": "mixamorig", "hides": ["hide_torso","hide_upperarm"], "tags": ["knit","90s","multicolour","oversized"], "brand": "coogi-parody", "license": "green", "colorway": { "base": "#8a2b6d", "tintable": true }, "reps": { "flat_png": "garments/coogi-multi-knit.png", "doll_layer": "garments/coogi-multi-knit.doll.png", "sprite": "garments/coogi-multi-knit.sprite.png", "glb": "garments/coogi-multi-knit-harvest.glb", "skin_tex": "garments/coogi-multi-knit.reskin.png", "thumb": "garments/coogi-multi-knit.thumb.png" }, "source": { "prompt": "...", "backend": "flux_local", "seed": 42 }, "provenance": { "created": "2026-07-24T...", "donor": null } } ``` **Outfit record** (`library/outfits/.json`) ```json { "name": "raver-fit-01", "body": "bodies/phrtt2_rigged.glb", "slots": { "torso":"coogi-multi-knit","legs":"baggy-jnco","feet":"doc-8eye","head":"bucket-hat" }, "layerOrder":[ "legs","feet","torso","head","bag" ], "anim": "wan_walk", "attach": { "bucket-hat": { "bone":"mixamorig:Head","scale":1.0,"y":0.0,"z":0.0 } } } ``` The `attach` block **bakes the currently-ephemeral rigid-attach state** (`index.html:215-225`) so hats/props survive reload + export. **Export contracts** (verified against each consumer's real loader) | Target | Contract | Slot map | |---|---|---| | **90sDJsim / thriftgod doll** | write `reps.doll_layer` → `90sDJsim/web/world/media/doll/_i_.png`; `` = `re.sub(r'[^a-z0-9]+','_',name.lower()).strip('_')`. Self-healing `DOLL_ART` = drop file + restart. Rsync to ultra. | torso→top, legs→bottom, feet→shoes, head→hat, bag→bag | | **thriftgod / procity racks** | emit `reps.flat_png` as `fittings.js garment({image})` plane texture / PROCITY `StockSlot{kind:'garment'}` | slot → rack `kind:'garment'` | | **not-tonight** | emit `reps.sprite` (32×48, quantized to the 14-entry `outfits.ts PALETTE`) | head→hair/accessory, torso→top, outer→outer, legs→legs, feet→shoes | | **3D GLB (hero/games)** | `assemble(body,{torso:garment})` or `fit` → `out/.glb` → 3GOD depot | native mixamorig | Schema is a **superset of** `character_kit_modular/parts_library/library.json` → parts flow between benches (anti-silo, not a new competing format). --- ## E. The 2D paper-doll track (first-class, not a fallback) John explicitly has "2D paper cut-out" garments, they're the **cheapest content**, and `GODVERSE_MAP.md` already recommends *"clothes cutouts on a hanger card OVER 3D garment mesh."* Mostly **adoption**, not building: - Generator exists & is $0: `90sDJsim/tools/gen_wardrobe.py` — prompt → `flux_local` on **solid green** → `bg_remove_local` → `doll_stage.py` onto 704×1408 via measured `SLOT_DEF` anchors. - Battle-tested prompt (`build_wardrobe_manifest.py`): *"paper doll clothing item for a dress-up game, ``, 1990 australia, ``, floating centered on a plain pure white background, painterly stylized 3d game illustration, full item visible, no body, no person, no mannequin, no hanger, no text, no logos."* Lift verbatim, incl. per-slot VIEW phrasing. - Content on hand: **441 sprites + 321 items + 432 reference JPGs.** - Upgrade: `qwen_layered_local` → RGBA layers = the literal "layered paper cut-out" rep, cleaner than the keyer. - **Prerequisite: fix bug #2** or none of this is ever visible. - **Honest scope:** the djsim doll dresses **one fixed 704×1408 front-view silhouette** — it **cannot** dress arbitrary 3D bodies. The dressing room is two products sharing one library: a 2D doll authoring view (djsim/not-tonight) and a 3D stage (reskin/harvest/socket). Toggle honestly; never pretend a flat sprite is dressing the 3D body. --- ## F. Open questions (only John can answer) 1. **wardrobegod vs NPCFACTORY** — keep wardrobegod as the JING5 library/authoring/export hub and *borrow* NPCFACTORY's stage+banks (plan assumes this), or physically **merge** the two? 2. **Canonical nude base + consent** — rig/reskin target: mint from `trellis2-bench/anatomy_8000.glb`, use `phrtt2` (ideal reskin class), or the 43 rigged game-budget set? Hard `license!="red"` export gate? 3. **`MB_TOKEN` persistence** — OK to add a LaunchAgent / boot-time read from `backnforth/.env`? 4. **Where the canonical library physically lives** — JING5 (author), ultra (doll pipeline runs), or 3GOD depot? 5. **First export target** — 90sDJsim (biggest existing 2D consumer, zero-code drop-in) or 3D-in-thriftgod? 6. **Hero garments** — accept painted-on reskin for crowd/mid, donor-harvest for staples; invest in socket-torso swap for true hero couture (bigger build, not in this plan)? 7. **Garment LoRA** — curate a set + `brush_train` for on-brand 90s Aussie op-shop garments, or prompt-only for now? --- ## G. Risks & what will look bad (no sugar-coating) - **Reskin is a painted-on illusion** — zero added geometry; unchanged nude silhouette + a jacket *print* is a dead giveaway at close range; can't layer, can't drape; re-bake to change (runtime swap only toggles *already-baked* costumes). Single-mesh/UV bodies only. - **Virtual try-on is a 2D still** — `mflux_image_edit` gives a believable clothed image in ~2 min (great for browsing) but doesn't animate and drifts identity/pose. Preview surface, not hero render. - **Donor cloth is proportion-captive** — weights transfer perfectly, but a suit molded to `man_suit_01` floats/clips on a slim TRELLIS figure (no cloth sim). Wardrobe is donor-bounded. 65-bone vs 22-bone leaves cuffs under-driven. Unknown fraction of donors are single-atlas (skin+cloth fused) → won't separate cleanly — real number unknown until triage runs. - **3D fit on unstructured topology is per-body & clips** — no shared topology → fitted garment doesn't transfer across bodies; expect clipping/sleeve mismatch on non-A-pose bodies; MIRPAMO can candy-wrap joints on non-manifold soup. - **The 2D doll can't dress the real 3D bodies** — one fixed front-view silhouette only. - **Generation fidelity is prompt-only** (no garment LoRA) — exotic garments hit-or-miss. - **Export writes into live game dirs** — needs dry-run + `license!="red"` gate + write only `_i_.png` (never overwrite generic fallbacks). - **Overlap with NPCFACTORY is real** — build this as the library/export layer NPCFACTORY lacks, not a third isolated dress-up stage. - **Auto-tagging is not available today** (no live vision model) — treat as manual or paid-OpenRouter. - **Farm GPU = 1 job/node** — batch gen queues; push flux/RMBG to the 2nd MODELBEAST node on ultra. **One-liner for John:** by end of week you get a real "change clothes + walk" button (reskin + rigid attach + clip playback) and a best-in-class 2D wardrobe that drops straight into 90sDJsim; good-looking real-cloth 3D comes in Phase 4 from harvesting donors you already own; and the thing you'll use every day — the dressing-room library + export hub — is the spine that turns every engine into value for five existing consumers.