feat(assets): wardrobe engine + proof t-shirt — batch-fit, offset-shell, 4-region tint, thrds logo (T-1089)
Engine: tooling/garment-fit/blender_batch_fit_skinned.py (G1 — the skinned Surface-Deform batch the old script couldn't produce; self-check green), blender_author_offset_shell.py (route c: garment shells from OUR body segments, weights inherited by construction, bone-plane cuts, procedural RGBA region mask, UV2 chest channel), make_logo.py. Shader: toon_garment.gdshader — channel-blended 4-region tint + UV2 logo composited after tint / before toon shading. Proof: tshirt_modern fitted to the six healthy bodies, manifest entry with style:modern + logo_capable, thrds wordmark, 18-assertion test suite, 216-capture chromakey QA. Key finding (Q-060 evidence): single-reference SD-fit of an offset-shell degrades on girth-divergent bodies (muscular_m worst) — 24mm standoff tripled headroom but the mechanism limits. Route guidance recorded on T-1089: per-body shell authoring for offset-shell garments; SD-fit for derived/hand-authored ones. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -841,3 +841,8 @@ Follow-facing refinement (user, live session 2026-07-06): during an RMB path-fol
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKHFRCP5R0VBA9BKR97RRBJ0', 'status', 'backlog', 'in_progress', NULL, '2026-07-06 18:55:29', '2026-07-06 18:55:29.038', '2026-07-06 18:55:29.038', NULL, 'da64cb6b48dd4311c5b257cbd70d891b', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKHFRCP5R0VBA9BKR97RRBJ0', 'status', 'in_progress', 'done', NULL, '2026-07-06 19:18:30', '2026-07-06 19:18:30.658', '2026-07-06 19:18:30.658', NULL, '5bcddf023648706d42815d7aaf08255a', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKE0EW2617K9VE4QHSYSR9HW', 'status', 'backlog', 'in_progress', NULL, '2026-07-06 19:25:35', '2026-07-06 19:25:35.248', '2026-07-06 19:25:35.248', NULL, '8fa2e4eba023cb3ae1577a5f16c9cfd2', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKE0EW2617K9VE4QHSYSR9HW', 'description', 'Found by the T-1089 Synty intake spike (2026-07-06), body-only controls with NO garment attached: thin_f/m, heavy_f/m, child misrender in CharacterVisual (exploded/spider arms, detached head/hair; child 303mm max warp, 87 collapsed edges; f-bodies bust-through). These are the newer high-poly bodies (no seg_hips, different segmentation) — exactly the 5 with no production peasant-clothing variants. Upstream of ANY clothing route; blocks T-1089''s 11-of-11 acceptance criterion and resolves part of Q-060. Evidence: spikes/synty-intake/out/bodies_fit_log.json + out/qa_bodies/ (44 screenshots) + out/bodies_recon.json.', 'Found by the T-1089 Synty intake spike (2026-07-06), body-only controls with NO garment attached: thin_f/m, heavy_f/m, child misrender in CharacterVisual (exploded/spider arms, detached head/hair; child 303mm max warp, 87 collapsed edges; f-bodies bust-through). These are the newer high-poly bodies (no seg_hips, different segmentation) — exactly the 5 with no production peasant-clothing variants. Upstream of ANY clothing route; blocks T-1089''s 11-of-11 acceptance criterion and resolves part of Q-060. Evidence: spikes/synty-intake/out/bodies_fit_log.json + out/qa_bodies/ (44 screenshots) + out/bodies_recon.json.
|
||||
|
||||
RESOLVED (pending review). Root cause: fork bodies (thin/heavy/child) had a mesh<->armature mismatch. blender_segment_body.py apply_scale scaled mesh vertices ONLY, leaving the embedded armature at source scale; since character_visual.gd binds every segment onto ONE shared skeleton (skeleton/armature.glb) by bone name, each segment must be internally consistent with its own embedded armature — the mesh-only scale dropped the head ~0.35m below the Head bone and flung limbs apart on relocation. thin/heavy were additionally stale high-poly artifacts (torso 1419-1704v vs 375v) missing seg_hips entirely. Fix: replaced apply_scale with apply_fork_scale (tooling/blender_segment_body.py) which scales mesh AND armature together and BAKES via Blender transform_apply (edit-bone poking alone shears connected chains — arms/fingers still exploded). Rebuilt all 5 via new tooling/blender_rebuild_forks.py from Source-tier gltf; now 19 segments incl seg_hips, low-poly matching the healthy six. Bare-body QA (idle+walk, front+side, real CharacterVisual): all 5 coherent, head/hair attached, no explosion; healthy 6 untouched. Q-060: all 3 peasant garments Surface-Deform-fit onto all 5 forks (15/15 surface_deform, 0 shrinkwrap fallback) — Surface Deform HOLDS at the extremes on repaired bodies. No manifest change (body ids/paths unchanged).', NULL, '2026-07-06 20:02:30', '2026-07-06 20:02:30.990', '2026-07-06 20:02:30.990', NULL, '7606f8b27d88884fcb7d4a2e3a5663bb', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKE0EW2617K9VE4QHSYSR9HW', 'status', 'in_progress', 'review', NULL, '2026-07-06 20:02:31', '2026-07-06 20:02:31.013', '2026-07-06 20:02:31.013', NULL, '942bea5d7db30ea972e6ba64341369a1', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKE0EW2617K9VE4QHSYSR9HW', 'status', 'review', 'done', NULL, '2026-07-06 20:06:22', '2026-07-06 20:06:22.078', '2026-07-06 20:06:22.078', NULL, '10bec531a986c8b28b68229637a1297f', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
|
||||
@@ -719,3 +719,6 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
||||
|
||||
RESOLVED (pending review). Root cause: fork bodies (thin/heavy/child) had a mesh<->armature mismatch. blender_segment_body.py apply_scale scaled mesh vertices ONLY, leaving the embedded armature at source scale; since character_visual.gd binds every segment onto ONE shared skeleton (skeleton/armature.glb) by bone name, each segment must be internally consistent with its own embedded armature — the mesh-only scale dropped the head ~0.35m below the Head bone and flung limbs apart on relocation. thin/heavy were additionally stale high-poly artifacts (torso 1419-1704v vs 375v) missing seg_hips entirely. Fix: replaced apply_scale with apply_fork_scale (tooling/blender_segment_body.py) which scales mesh AND armature together and BAKES via Blender transform_apply (edit-bone poking alone shears connected chains — arms/fingers still exploded). Rebuilt all 5 via new tooling/blender_rebuild_forks.py from Source-tier gltf; now 19 segments incl seg_hips, low-poly matching the healthy six. Bare-body QA (idle+walk, front+side, real CharacterVisual): all 5 coherent, head/hair attached, no explosion; healthy 6 untouched. Q-060: all 3 peasant garments Surface-Deform-fit onto all 5 forks (15/15 surface_deform, 0 shrinkwrap fallback) — Surface Deform HOLDS at the extremes on repaired bodies. No manifest change (body ids/paths unchanged).', 'review', 'high', NULL, 'client', NULL, '2026-07-06 10:38:16.593', '2026-07-06 20:02:31.012', NULL, '5cec3f5395cb96910151ae43d10076dc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKJ25KG3ADM4M5XRXCVR2GQG', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Child/teen bodies composite at adult height — shared-skeleton normalization discards stature', 'Found during T-1090 repair (2026-07-06): the shared-skeleton compositor (character_visual.gd binds every segment to the one Regular-sized armature by bone name) normalizes global scale — only cross-sectional shape survives, so thin reads narrow and heavy reads wide (correct) but child and teen stand at ADULT height. Pre-existing behavior, not a T-1090 regression. If stature matters (it will — children in crowds), options: per-body runtime skeleton, node-level scale on CharacterVisual, or bone-length retarget at load. Interacts with animation retargeting (shorter limbs vs shared UAL clips) and D-164. Sprint-28 verdict warns runtime BONE scaling fails — evaluate NODE scale first.', 'backlog', 'medium', NULL, 'client', NULL, '2026-07-06 20:04:59.392', '2026-07-06 20:04:59.392', NULL, '7ceb0fb9f90b36988d9d2b75765c9585', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKE0EW2617K9VE4QHSYSR9HW', 'bug', '06FB0TNSRXX29H5X0EB0F0GBW4', '5 of 11 body types misrender bare in CharacterVisual (thin_f/m, heavy_f/m, child)', 'Found by the T-1089 Synty intake spike (2026-07-06), body-only controls with NO garment attached: thin_f/m, heavy_f/m, child misrender in CharacterVisual (exploded/spider arms, detached head/hair; child 303mm max warp, 87 collapsed edges; f-bodies bust-through). These are the newer high-poly bodies (no seg_hips, different segmentation) — exactly the 5 with no production peasant-clothing variants. Upstream of ANY clothing route; blocks T-1089''s 11-of-11 acceptance criterion and resolves part of Q-060. Evidence: spikes/synty-intake/out/bodies_fit_log.json + out/qa_bodies/ (44 screenshots) + out/bodies_recon.json.
|
||||
|
||||
RESOLVED (pending review). Root cause: fork bodies (thin/heavy/child) had a mesh<->armature mismatch. blender_segment_body.py apply_scale scaled mesh vertices ONLY, leaving the embedded armature at source scale; since character_visual.gd binds every segment onto ONE shared skeleton (skeleton/armature.glb) by bone name, each segment must be internally consistent with its own embedded armature — the mesh-only scale dropped the head ~0.35m below the Head bone and flung limbs apart on relocation. thin/heavy were additionally stale high-poly artifacts (torso 1419-1704v vs 375v) missing seg_hips entirely. Fix: replaced apply_scale with apply_fork_scale (tooling/blender_segment_body.py) which scales mesh AND armature together and BAKES via Blender transform_apply (edit-bone poking alone shears connected chains — arms/fingers still exploded). Rebuilt all 5 via new tooling/blender_rebuild_forks.py from Source-tier gltf; now 19 segments incl seg_hips, low-poly matching the healthy six. Bare-body QA (idle+walk, front+side, real CharacterVisual): all 5 coherent, head/hair attached, no explosion; healthy 6 untouched. Q-060: all 3 peasant garments Surface-Deform-fit onto all 5 forks (15/15 surface_deform, 0 shrinkwrap fallback) — Surface Deform HOLDS at the extremes on repaired bodies. No manifest change (body ids/paths unchanged).', 'done', 'high', NULL, 'client', NULL, '2026-07-06 10:38:16.593', '2026-07-06 20:06:22.078', NULL, 'dd9ef4733867c6166098027e49a44569', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
|
||||
Reference in New Issue
Block a user