wardrobegod/STATE_AND_PLAN.md
type-two 82806fd616 Record the 3GOD absorption in STATE_AND_PLAN
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 22:16:46 +10:00

30 KiB
Raw Permalink Blame History

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).


BUILD STATUS — 2026-07-24

phase state commit demo
0 — unblock done b1381d2 security hole closed, PNG garments visible, farm3D ✓
1 — dress + move done b1381d2 tradie walks in a red-tinted felt hat, restored from disk after reload
2 — reskin done cfca670 phrtt2 wearing a baked corduroy jacket; head-ghosting bug found + fixed
3 — 2D paper doll done 294af7c 392 layers, per-slot swap, randomise, export dry-run to djsim
4 — donor harvest done 8119e2d harvested garment on a different body, bending through a Running clip
5 — dressing room done 305fbf9 thumbnail grid, manifest, rig→LOD→dress bench
SD salvage + MODELBEAST done 5c80e65 juggernautXL beats flux for garments; LoRA stacking + ControlNet + parent_job fix
NPCFACTORY folded in done 037f6ef vendored three.js (no CDN), 17 NPCs, unitfix
nsfw tagging + gate done d6c0ba4 "only dressed ships" is now enforced, not a README line
export hub + unified wardrobe done 9012e3e 401-item grid, 3GOD publish, honest 409s

Export reality (verified against each consumer's real loader, 2026-07-24)

target file drop works? what's actually needed
djsim doll yes self-healing loader — drop + restart
3GOD depot yes POST http://100.94.195.115:8788/api/upload direct over tailnet — the digalot.fyi front 403s because auth trusts the socket peer
djsim ped no rigs.js PED_NAMES (:20-27) hardcoded array
procity ped no ped name array; props via pipeline/publish.py on m3ultra (only box with _normalized/)
thriftgod prop no literal HERO_FLOOR/HERO_COUNTER strings (index.html:1322-1325)
not-tonight no no garment/doll/character art path exists at all

thriftgod has no paper-doll, atlas or reskin consumer — zero grep hits across web/ and tools/. Don't generate art for it expecting somewhere to put it.

What John can do right now: python3 server.py → open :8150. · wardrobe tab — load a rigged NPC, attach + tint props, save/reload the dress-up, play/scrub clips, RESKIN a nude body with any garment and toggle costumes instantly. · doll 2D tab — dress a paper doll from 392 real garments, randomise, export to 90sDJsim.

Corrections to the recon below, found while building:

  • The live farm exposes 26 operators, not 36 (the 36 was the code registry; not all are hot). /api/operators returns display names, so mflux_image_edit appears as "Edit Image (local, Qwen)".
  • Two live operators the plan under-sold: SF3D (fast image→GLB draft) and MoMask (text→motion BVH).
  • numpy is not installable on JING5 (PEP 668) — the doll tier parses djsim's anchors out of source with ast instead of importing its numpy-dependent compositor.
  • Reskin's inherited baker ghosted a second face onto the side of the head; fixed with a neck-height cutoff.
  • riggermore / rigroom do not exist under those names anywhere on the fleet — the rigging bench is MIRPAMO.

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/blenderfx() 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 ephemeralweb/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==idGET /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, <slot>_i_<slug>.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 greenbg_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.glbrender_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/<slot>_i_<slug>.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<donor>__<material>-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/<slug>.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/<name>.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_layer90sDJsim/web/world/media/doll/<slot>_i_<slug>.png; <slug> = 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 fitout/<outfit>.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 greenbg_remove_localdoll_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, <desc>, 1990 australia, <view>, 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 stillmflux_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 <slot>_i_<slug>.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.


3GOD → absorbed (2026-07-24)

Retired: the name, the repo (ssh://git@100.71.119.27:222/monster/3GOD.git), and the viewer UI — wardrobegod's stage/grid/publish covers all of it.

Kept and absorbed into depot/: the asset CDN. It holds 773 live assets and two shipping games fetch from it at runtime (thriftgod index.html:1176, procity loaders.js:7), so the service and its /3god URL stay exactly as they are. The name now survives only as a URL path.

Checked before discarding the UI: 0 of 773 assets had tags or notes, so nothing needed migrating. Tagging lives in library/index.json.

Two things depot/README.md records because they're expensive to rediscover:

  1. Publish direct over the tailnet (100.94.195.115:8788) — the Cloudflare front 403s because auth trusts the raw socket peer. thriftgod's own prop_campaign.py --publish is broken for this.
  2. clean_name deletes illegal characters, so shop!-cat.glb silently resolves to an existing different mesh. god3_name() reproduces the rule and refuses to overwrite.