d1030def4e
Two pieces of work.
1. Keep milestones, not steps. Staged NN_*.py lanes were saving a full
~80 MB .blend per attempt, so Lena's lane reached 3.0 GB of which 2.2 GB
was 30 .blend files -- five snapshots to land one crotch fix, five more
for the bra. The .py recipes are the real history; the blends are cache.
- .agents/rules/working-files.md: four-tier policy (KEEP / MASTER /
SCRATCH / UNKNOWN) + how to work a lane.
- tools/prune_lane.py: classifies a lane and prunes the scratch tier.
Dry-run by default. Reads a per-lane .lanekeep manifest, flags
binaries byte-identical to a registered original (canonical name
always survives a duplicate pair), and never auto-deletes a .blend
with no step script beside it -- those cannot be rebuilt.
- .gitignore: scratch patterns can never be committed.
Dry run on characters/female/lena_nude reports 2.3 GB reclaimable.
Not applied -- that lane had a live Blender session at the time.
2. .humans/marvelous-designer.html: how we author garments in Marvelous
Designer, written for people rather than agents -- the six-step process,
what has been made, the traps that cost hours, and what is still
unsolved. Matches the .humans/ HTML convention in ariki-game.
Also committing the docs the AGENTS.md knowledge map and the new page
reference, so they are not dangling: the clothing-lane architecture page,
the marvelous-designer skill, and the two screenshots the page embeds.
characters/ is deliberately untracked and stays that way -- it holds GBs of
blends and GLBs, and .gitattributes does not LFS-track .blend.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
215 lines
11 KiB
Markdown
215 lines
11 KiB
Markdown
# Deconstruction — taking a reference apart like a tailor
|
||
|
||
Companion to `../SKILL.md`. That file is drafting/draping doctrine; **this file is
|
||
the step before it**: how to read a clothing image (or description) and take the
|
||
garment apart into pieces our MD lane can actually build. Skipping this step is
|
||
how garments shipped 4–14 cm off their own targets — the drafting was fine, the
|
||
*analysis* had never been written down.
|
||
|
||
The output is a **worksheet of numbers**, not geometry. Panel point lists come
|
||
last, and mostly from `tools/tailor/blocks.py`, not by hand.
|
||
|
||
---
|
||
|
||
## 0. The worksheet (output contract)
|
||
|
||
Fill this in full **before** asking for a bridge session. Every number the drape
|
||
and QC stages use traces back to a row here.
|
||
|
||
| # | Item | Feeds |
|
||
|---|---|---|
|
||
| 1 | Slot split — which separate garments is this outfit? | one config per garment |
|
||
| 2 | Per garment: class + block choice | `blocks.py` function |
|
||
| 3 | Anchoring — what holds it up | construction + arrangement |
|
||
| 4 | Placement targets — each edge's z ± tol vs landmarks | `expect.bands` (gate G1) |
|
||
| 5 | Edge circumference + ease table | panel widths, taper |
|
||
| 6 | Piece list + seam plan | `md.panels` / `md.seams` |
|
||
| 7 | Textile plan — what is texture, not geometry | texture generation |
|
||
| 8 | Fabric read — weight/stiffness | `.zfab` choice + sim recipe |
|
||
| 9 | Risks — unsolved/untested features | scope call before starting |
|
||
|
||
`blocks.py` turns rows 2–5 into a config skeleton (`md` block + `expect.bands`)
|
||
in one call. If no block fits, hand-draft under `tooling.md` §3 rules (named
|
||
landmarks, computed line indices) — never freehand a point list.
|
||
|
||
## 1. Split the outfit into garments by slot
|
||
|
||
The game wears **per-slot parts** (Body, Legs, …) and MD drapes **one garment per
|
||
scene** — a second garment, even frozen, grabs and inverts the new one. So a
|
||
"dress over leggings with a belt" reference is *three* worksheets, three configs,
|
||
three drape sessions. Decide the split first:
|
||
|
||
- One garment per clothing slot it occupies. A dress is one garment (Body slot,
|
||
or whatever slot spans it) even though it covers both regions.
|
||
- Belts, sashes, armbands: texture if flat against the host garment; separate
|
||
garment only if they hang or swing.
|
||
- Outfit photos are assembled at the end from finished `.zpac`s (SKILL.md
|
||
"Outfit assembly") — never co-draped.
|
||
|
||
## 2. Anchoring — decide what holds it up before what it looks like
|
||
|
||
Anchoring determines construction more than silhouette does. MD materialises
|
||
cloth at the arrangement point and does **not** simulate donning, so nothing
|
||
"slides into place".
|
||
|
||
| What the image shows | Anchor | Construction consequence |
|
||
|---|---|---|
|
||
| Straps, sleeves, or a shoulder line | shoulder-hung | bodice block; straps reach `shoulder_z` or the garment settles at the underbust |
|
||
| Strapless top | (unreliable) | **add straps anyway** — a tube slides to the narrowest catch; straps also cover the body's baked-in bra straps |
|
||
| Skirt/trousers at waist or hip | waist tension | cut the waist **smaller** than the hips (0.90–0.92 × hip circ) and let stretch hold it; elastic only mid-settle, never frame 0 |
|
||
| Light/gappy garment (strands, fringe, open weave) | arrangement itself | arrangement height **is** the placement — a light band stays exactly where arranged |
|
||
|
||
Always check what the anchor must *cover*: the target body has baked-in
|
||
underwear, and any neckline or scoop that drops below it reads as the garment
|
||
failing. Check the **back** neckline explicitly — the reference photo almost
|
||
never shows it, `ExportSnapshot3D` cannot show it (`tooling.md` §1.1), and that
|
||
blind spot has shipped defects. If the image doesn't show the back, *decide* the
|
||
back (scoop depth, coverage) and write it on the worksheet rather than letting it
|
||
default.
|
||
|
||
## 3. Read the seams, then discard most of them
|
||
|
||
A real tailor's deconstruction finds every seam. Ours finds them and then
|
||
**collapses almost all of them**, because the MD lane sews whole edges only, has
|
||
no darts, and garment identity for our targets is mostly textiles (SKILL.md).
|
||
Translation table:
|
||
|
||
| Feature in the image | Our move |
|
||
|---|---|
|
||
| Side seams, shoulder seams | keep — these are the block's real seams |
|
||
| Darts (bust, waist) | **no darts.** Taper the panel side edges + stretch ease carries the shaping |
|
||
| Princess seams, yokes | collapse into the panel; if visible, draw them in the texture |
|
||
| Waistband | merge into the panel top; separate band only for strand/fringe skirts |
|
||
| Set-in sleeves | **untested** — no sleeve block yet; treat as scope risk (row 9) |
|
||
| Collars, hoods | **untested/unsolved** — same |
|
||
| Trousers/shorts crotch | **unsolved** (failure catalogue); next approach is 4 panels on the per-leg points |
|
||
| Plackets, buttons, zips, pockets, topstitching | texture, always |
|
||
| Gathers, pleats, ruffles | texture unless the *silhouette* depends on them |
|
||
| Fringe / strands / fur edge | teeth cut into the panel outline (comb panel), never partial seams |
|
||
| Belt/sash flat against the garment | texture |
|
||
|
||
The test for "geometry or texture?": does it change the **silhouette** or the
|
||
**edge positions**? If not, it's texture.
|
||
|
||
## 4. Placement targets — numbers before points
|
||
|
||
Extract where every garment edge sits **before drafting anything**. This is the
|
||
step that was skipped when shipped garments landed 3.9–14 cm off targets that
|
||
existed only as prose.
|
||
|
||
Landmark card for the current body (`tools/tailor/lena_measurements.json`,
|
||
regenerate per body with `measure_body.py`; metres, floor = 0):
|
||
|
||
| Landmark | z | Landmark | z |
|
||
|---|---|---|---|
|
||
| top of head | 1.777 | hip (widest) / crotch | 0.946 |
|
||
| neck base | 1.457 | thigh | 0.865 |
|
||
| shoulder | 1.397 | knee | 0.517 |
|
||
| chest (bust) | 1.264 | ankle | 0.106 |
|
||
| waist | 1.089 | | |
|
||
|
||
Method, per garment edge (top of band, hem, waistline…):
|
||
|
||
1. Find the edge in the image relative to the two nearest **visible** landmarks
|
||
(e.g. "hem lands mid-thigh, about ⅓ of the knee→hip span above the knee").
|
||
2. Interpolate a z from the card. The body is stylized — always place against
|
||
*these* landmarks, never against real-world garment-length conventions.
|
||
3. Assign a tolerance: ±3 cm for fitted edges, ±4 cm for free-hanging hems.
|
||
4. Write the rows into `expect.bands` — gate G1 measures every drape against
|
||
them from then on.
|
||
|
||
Sanity anchor (proven): a pari band 1.31→1.05 m and piupiu 1.05→0.45 m came from
|
||
exactly this read of the kapa haka reference.
|
||
|
||
## 5. Ease — how much bigger than the body
|
||
|
||
For each **horizontal** edge, the panel width comes from the body circumference
|
||
at that z plus ease. Interpolate circumference linearly between the card's
|
||
(z, circ) pairs — neck 0.392, chest 1.083, waist 0.675, hip 1.095 — and **never
|
||
interpolate below the hip** (the legs bifurcate; a slice there measures nonsense).
|
||
|
||
| Fit read from the image | Total ease | Proven case |
|
||
|---|---|---|
|
||
| Snug / bandeau / activewear | +15–20 mm | pari: 1100 vs 1083 bust |
|
||
| Regular fitted top | +90–100 mm | tee: 1180 vs 1083 bust |
|
||
| Loose / drapey | +150 mm and up | (untested above ~150) |
|
||
| Bottoms waist edge | **negative**: 0.90–0.92 × hip circ | piupiu: 1000 vs 1095 hip |
|
||
|
||
Bottoms are the inversion to internalise: the waist edge is cut *smaller* than
|
||
the hips it must pass over, because tension is the anchor (§2).
|
||
|
||
## 6. Vertical spans are 1:1
|
||
|
||
Pattern millimetres map 1:1 to world metres — drape shrinkage is negligible for
|
||
our fabrics. So:
|
||
|
||
- panel cloth height = `(top_z − hem_z) × 1000`
|
||
- a shoulder-hung garment's straps must reach the shoulder: total panel height
|
||
= `(shoulder_z − hem_z) × 1000`, and the front scoop depth is what's left
|
||
between strap top and the visible band top: `scoop = panel_h − (band_top_z −
|
||
hem_z) × 1000`.
|
||
|
||
Proof this math is the real one: it reproduces all three shipped garments —
|
||
tee 480 (shoulder 1.397 → hip-ish hem 0.917), pari 350/scoop 105 (shoulder →
|
||
waist 1.05, band top 1.30), piupiu 600 (1.05 → 0.45).
|
||
|
||
## 7. Blocks — what we can build today
|
||
|
||
| Garment class | Block | Status |
|
||
|---|---|---|
|
||
| Tank / tee / fitted bodice / bandeau-with-straps | `blocks.fitted_top` | **proven** (tee, pari) |
|
||
| A-line / straight skirt | `blocks.aline_skirt` | **proven** (skirt, piupiu v2) |
|
||
| Strand / fringe skirt (piupiu, hula, fur trim) | `blocks.strand_skirt` | proven construction (comb outline), parameters per garment |
|
||
| Dress | `fitted_top` + skirt geometry in one panel pair | **untested** — try taper-through-waist first |
|
||
| Trousers / shorts | — | **unsolved**; next: 4 panels on `Leg_Front_L/R`, `Leg_Back_L/R` |
|
||
| Sleeves, collars, hoods | — | untested; scope risk |
|
||
| Capes / cloaks / rectangles (traditional wear) | plain panels | rectangles + blocks; identity is the textile |
|
||
|
||
Every block bakes in the expensive discoveries — seam parity for
|
||
identical-offset panels, the arrangement-x rules per point family, bodice taper,
|
||
tension waists, strengthen/relax sim recipes — so **prefer a block over a
|
||
hand-typed point list even when the block needs post-editing**. Generate, then
|
||
edit the config, not the other way round.
|
||
|
||
## 8. Textiles carry the identity
|
||
|
||
For traditional wear especially (kapa haka, Mexica, Pacific), the garment reads
|
||
as *itself* because of the textile, not the cut. Spend the effort there:
|
||
generate the pattern procedurally (PIL), set physical size via DPI
|
||
(`dpi = px / (mm / 25.4)`), and keep the generator script — motifs recur.
|
||
Model the shape as simply as the silhouette allows.
|
||
|
||
## 9. Fabric read → sim plan
|
||
|
||
From the image, judge weight and stiffness, then pick levers (`tooling.md` §4):
|
||
|
||
- **Stiffness ladder** (`.zfab` presets): `V2_Woven_Canvas_1` <
|
||
`V2_Woven_Denim_1` < `V2_Non-Fabric_Tyvek_1`. `fabric_api` has no physics
|
||
setters — the `.zfab` *is* the stiffness choice.
|
||
- Fully-sewn sides → strengthen through the whole settle, relax at the end.
|
||
Under-constrained (half-sewn sides, thin straps) → **don't** strengthen
|
||
(it rotates the garment); remove surplus cloth instead.
|
||
- Light/gappy → `SetParticleDistanceOfPattern` ~20 mm and remember §2:
|
||
arrangement height is placement.
|
||
- Skin-tight → `SetAddlThicknessCollision` a few mm before the settle.
|
||
|
||
## 10. Worked example — the kapa haka reference, as this method
|
||
|
||
What was done by trial and error in 2026-07-30/31, restated as the worksheet:
|
||
|
||
| Row | Pari (bodice) | Piupiu (skirt) |
|
||
|---|---|---|
|
||
| Slot | Body | Legs |
|
||
| Class/block | bandeau → `fitted_top` | strand skirt → `strand_skirt` (v2 shipped as `aline_skirt`) |
|
||
| Anchoring | photo shows strapless → **straps anyway** (covers bra straps, fixes height) | waist tension, 1000 vs 1095 hip; light strands → arrangement = placement |
|
||
| Targets | band top 1.31 ±0.03, hem 1.05 ±0.03 | waist 1.05 ±0.03, hem 0.45 ±0.04 (below knee) |
|
||
| Ease | snug: +17 mm over bust | waist 0.91 × hip |
|
||
| Seam plan | shoulders + sides; scoop/armholes in outline | band side edges only; strands are outline teeth |
|
||
| Textile | tāniko band → generated `taniko.png`, DPI-sized to span once | flax strands + geometric banding → `piupiu.png` |
|
||
| Fabric | default sim fabric, strengthen full settle | default, strengthen + (v3) elastic mid-settle |
|
||
| Risks | back neckline never visible in photo — decided, then verified via turntable | hem vs leg-swing envelope (skirt bones downstream) |
|
||
|
||
The lesson the example carries: **nothing in the finished configs is a guess.**
|
||
Every number is a worksheet row, and every worksheet row is checkable — by G1
|
||
against the render, or by `GetLineLength` against the drafted panel.
|