Go to file
type-two b1381d22d2 Phase 0+1: unblock the bench, then make it dress and move
Phase 0 — the fixes that were blocking every tier:
· /api/blender had no allowed() guard, unlike every other path-taking endpoint. Under the
  documented WG_HOST=0.0.0.0 that was an unauthenticated arbitrary-file -> Blender import +
  library-write for any tailnet peer. Now gated on allowed() + isfile.
· scan() listed garments as models only, but /api/hangable writes .png there — so every
  cut-out the generator produced was invisible in its own UI and the whole 2D paper-doll
  route dead-ended. garments now lists models AND images.
· mb_download() wrote json.dumps(data) whenever the farm response wasn't bytes, and mb_req
  parses any JSON-200 into a dict — so a farm error body got written *into* the target
  .png/.glb and the job was still marked done. Now raises instead.
· MB_TOKEN is read off disk from backnforth/.env, so the farm tiers (RMBG-2.0, image-edit
  try-on, trellis) stop silently dying when a launch forgets to export it.
· glb_of() keyed its cache on the basename alone, so two sources that slug the same served
  each other's geometry; the key now carries a hash of the full path.
· JOBS grew forever and glb_of minted an orphan job on every cache miss inside GET /glb.
  run_blender() now tolerates jid=None and finished jobs get reaped.

Phase 1 — a dressed, animated character on screen:
· clip transport: the mixer used to blind-play animations[0] with no way to reach the rest.
  Clip dropdown + play/pause + scrub + speed, with the scrub head following playback.
· rigid attach stopped being a lie. It cloned into three.js and POSTed nothing ("preview
  only"), so every hat placement died on reload. Attachments now carry their bone/offset/
  tint and persist via /api/outfit -> library/outfits/<name>.json, reloadable from a chip.
· colourway swatches retint the last attached item (materials are cloned per instance so a
  tint doesn't bleed), giving free variants with no re-generation.
· flat cut-out garments get a 2D preview pane — the paper-doll tier had no way to be seen.

Verified end-to-end in the browser: tradie_at_wanwalk (22-bone mixamorig) walks wearing a
red-tinted felt hat on mixamorigHead, saved, page reloaded, restored from disk.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 15:43:02 +10:00
web Phase 0+1: unblock the bench, then make it dress and move 2026-07-24 15:43:02 +10:00
.gitignore CF Workers AI backend: flux direct (backnforth contract) + local border-flood keyer 2026-07-21 00:16:37 +10:00
blender_ops.py WARDROBEGOD v1 — wardrobe generator bench (bodies, fits, garment gen pipeline) 2026-07-20 20:53:43 +10:00
README.md WARDROBEGOD v1 — wardrobe generator bench (bodies, fits, garment gen pipeline) 2026-07-20 20:53:43 +10:00
server.py Phase 0+1: unblock the bench, then make it dress and move 2026-07-24 15:43:02 +10:00
STATE_AND_PLAN.md Phase 0+1: unblock the bench, then make it dress and move 2026-07-24 15:43:02 +10:00

WARDROBEGOD — one skeleton, infinite fits

The wardrobe generator bench: load bodies (FBX/GLB/OBJ), build a clothes library, generate new garments on the farm, fit them, assemble dressed NPCs. Sibling of NPCFACTORY (the dress-up/clip bench) and MeshGod imagelab — this one owns clothing.

python3 server.py                 → http://localhost:8150
WG_HOST=0.0.0.0 python3 server.py → expose on the tailnet
MB_TOKEN=mbt_… python3 server.py  → enables the generator tab (MODELBEAST bearer token)

No build step: stdlib server + three.js from CDN. Heavy lifting = local headless Blender (blender_ops.py, tested on 5.1.2; override path with WG_BLENDER).

What it does

  • Library panes: bodies (scans library/bodies/ + ~/Documents/anatomy + thriftgod's web/assets/models), garments, generated images, finished outfits. Upload via file inputs.
  • Stage: orbit viewer; FBX auto-converts to GLB (cached in .glbcache/); HUD reads tris / height / rig state (bones + clips); first clip auto-plays.
  • Body ops: scale-to-height (bases arrive 1.0m tall — normalize to ~1.72m); decimate-keep-weights (the SAFE local path for rigged meshes — never farm /finish).
  • Rigid attach (tier 1): hats/bags/shoes → pick a bone, slide offsets, preview live. Bake permanently via the fleet /rig endpoint (m1ultra :8011) when happy.
  • Deforming FIT (tier 2): weight-transfers the rigged body's skinning onto a garment mesh (Blender data_transfer, nearest-face interpolated, optional inflate-mm of air), parents it to the armature. FIT → wardrobe item = garment+skeleton GLB (reusable); fit → dressed glb = body+garment in one.
  • Assemble: body + ticked fitted garments → one dressed GLB in out/ — drop straight into thriftgod / djsim / procity, or publish to 3GOD.

Generating NEW clothing (the pipeline, $0 on MODELBEAST)

  1. flux (flux_local, Klein) — product-shot prompt template: garment laid flat, white bg
  2. cutout (bg_remove_local) — the biggest quality lever before 3D
  3. then ONE of:
    • → rigid 3D (trellis_mac, ~5 min): hats, shoes, bags, glasses — bone-parent these. NOT for floppy cloth: reconstruction eats thin geometry (fleet traps ledger).
    • → hanging texture: flat garment PNG for rack planes (djsim fittings.js garment({image})) and the paper-doll wardrobe. Flat clothes love this route.
    • deforming wearables: model/retopo against the base body (or socket-cut a clothed torso, character_kit_modular style), then FIT. Never raw-gen these.

House rules

  • Bases (anatomical models) stay in the library. Only dressed outfits ship into games.
  • FIT requires a rigged body. Unrigged base → rig first (MIRPAMO on ultra, or Mixamo).
  • One skeleton (mixamorig) across the fleet: any garment fitted on one body fits every body on that skeleton, and every clip in the bank drives it.