Narrow the sunglasses and fix portrait-type parsing

Move the hinges to +/-0.075 (0.035 box), arms to +/-0.098, and lenses to a
0.024 m radius while keeping the lens plane in front of the eyes. Rebuild the
GLB and AO; fit now measures 0.202 m total width (0.64x head). capture_realism
now parses the documented --portrait-type option instead of ignoring it.
Python tooling 87/87; headless 228/228.
This commit is contained in:
zwitschi committed 2026-11-01 17:56:10 +01:00
1 parent d7b0203502
commit bbf4693475
7 files changed
+20 -12

No files matched your search

+3
View File
@@ -13,6 +13,9 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
(46 `.blend` files removed from the index on 2026-11-01); the `.gdignore` marker stays tracked. (46 `.blend` files removed from the index on 2026-11-01); the `.gdignore` marker stays tracked.
- `screen_designs.py judge` default `google/gemini-2.5-flash-lite` worked on 2026-11-01 - `screen_designs.py judge` default `google/gemini-2.5-flash-lite` worked on 2026-11-01
(7 match / 4 review / 0 diff); `--model` remains available. (7 match / 4 review / 0 diff); `--model` remains available.
- `capture_realism.gd` parses `--portrait-type=N`; it was documented but ignored before the gear
pass. Portrait captures need the requested NPC type to have spawned, otherwise the stage can
finish with an empty frame; use the Blender `npc_coat` preview for a deterministic gear check.
- Gear fit is measured with `python3 tools/blender_assets.py fit` (stdlib, reads the GLBs): - Gear fit is measured with `python3 tools/blender_assets.py fit` (stdlib, reads the GLBs):
head width uses skin vertices weighted to Head in y 1.55–1.81; clothing radius is the cloth head width uses skin vertices weighted to Head in y 1.55–1.81; clothing radius is the cloth
skirt in y 0.30–0.52 with a pants hip fallback. The command reports per-character gear boxes, skirt in y 0.30–0.52 with a pants hip fallback. The command reports per-character gear boxes,
+5 -5
View File
@@ -16,11 +16,11 @@ live in `tools/blender_assets.py` (`_build_gear()`), the contract in `docs/blend
bounding box with head-band status or skirt clearance. Current measurements: head width bounding box with head-band status or skirt clearance. Current measurements: head width
0.315 m; coat skirt 0.225 m, dress 0.260 m; sunglasses 0.282 m (0.90x head); shoulder-bag 0.315 m; coat skirt 0.225 m, dress 0.260 m; sunglasses 0.282 m (0.90x head); shoulder-bag
x-clearance -0.025 m on the coat (radial -0.031 m on the dress). x-clearance -0.025 m on the coat (radial -0.031 m on the dress).
- [ ] Narrow `sunglasses` from 0.28 m to ~0.20 m. The width is driven by the arms/hinges - [x] Narrow `sunglasses` from 0.28 m to ~0.20 m. The hinges moved to ±0.075 (0.035 box), the
(`Hinge` at `x = ±0.11` with a 0.06 box, `Arm` at `±0.138`), not by the 0.03 m lenses, so arms to ±0.098, and the lenses are 0.024 m radius at the same `y=-0.152`, `z=0.035` plane.
pull those in first and shrink the lenses to ~0.024 m radius; keep the lens plane at Rebuilt GLB/AO: measured width **0.202 m** (0.64x head), still inside the head band.
`y = -0.152` (in front of the sclera) and `z = 0.035` (eye line) so it does not ride up Also fixed `capture_realism.gd` so `--portrait-type=N` is actually parsed (it was documented
over the new brow ridge. but ignored).
- [ ] Fix `shoulder_bag` clipping through `npc_coat`/`npc_dress`: the bag body spans `|x|` - [ ] Fix `shoulder_bag` clipping through `npc_coat`/`npc_dress`: the bag body spans `|x|`
0.17–0.25 at the hip while the skirt flares to 0.225–0.26, so its inner half is inside the 0.17–0.25 at the hip while the skirt flares to 0.225–0.26, so its inner half is inside the
cloth. Move it outboard (or up onto the belt line) until the inner face clears the flare, cloth. Move it outboard (or up onto the belt line) until the inner face clears the flare,
+4 -4
View File
@@ -1097,13 +1097,13 @@
"attach": "head", "attach": "head",
"bounds_godot": { "bounds_godot": {
"max": [ "max": [
0.141, 0.101,
0.065, 0.059,
0.158 0.158
], ],
"min": [ "min": [
-0.141, -0.101,
0.005, 0.011,
0.003 0.003
] ]
}, },
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 35 KiB

+2
View File
@@ -112,6 +112,8 @@ func _parse_args() -> void:
elif text.begins_with("--stages="): elif text.begins_with("--stages="):
for name in text.substr(9).split(","): for name in text.substr(9).split(","):
_only_stages[name.strip_edges()] = true _only_stages[name.strip_edges()] = true
elif text.begins_with("--portrait-type="):
_portrait_type = int(text.substr(16))
func _pair(text: String, into: Dictionary) -> void: func _pair(text: String, into: Dictionary) -> void:
var cut := text.find("=", 6) # skip the "res://" scheme var cut := text.find("=", 6) # skip the "res://" scheme
+6 -3
View File
@@ -970,12 +970,15 @@ def build_gear(name):
elif name == "hood": elif name == "hood":
p.append(_hood("Hood", M("plastic_grey"), (0, 0, 0.015))) p.append(_hood("Hood", M("plastic_grey"), (0, 0, 0.015)))
elif name == "sunglasses": elif name == "sunglasses":
# Keep the front frame narrow enough to sit inside the 0.315 m head
# silhouette. The arms/hinges set the overall width, so pull those in
# before shrinking the lenses; the lens plane stays in front of the eyes.
for s in (-1.0, 1.0): for s in (-1.0, 1.0):
p.append(cyl("Lens", 0.03, 0.03, 0.008, (0.05 * s, -0.152, 0.035), M("lens"), p.append(cyl("Lens", 0.024, 0.024, 0.008, (0.04 * s, -0.152, 0.035), M("lens"),
seg=14, rot=(math.radians(90), 0, 0), scale=(1.25, 1.0, 1.0))) seg=14, rot=(math.radians(90), 0, 0), scale=(1.25, 1.0, 1.0)))
p.append(box("Hinge", (0.06, 0.008, 0.01), (0.11 * s, -0.150, 0.045), p.append(box("Hinge", (0.035, 0.008, 0.01), (0.075 * s, -0.150, 0.045),
M("plastic_black"))) M("plastic_black")))
p.append(box("Arm", (0.006, 0.15, 0.008), (0.138 * s, -0.078, 0.042), p.append(box("Arm", (0.006, 0.15, 0.008), (0.098 * s, -0.078, 0.042),
M("plastic_black"))) M("plastic_black")))
p.append(box("Bridge", (0.04, 0.006, 0.008), (0, -0.155, 0.045), M("plastic_black"))) p.append(box("Bridge", (0.04, 0.006, 0.008), (0, -0.155, 0.045), M("plastic_black")))
elif name == "firefighter_helmet": elif name == "firefighter_helmet":