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.
- `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.
- `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):
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,
+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
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).
- [ ] Narrow `sunglasses` from 0.28 m to ~0.20 m. The width is driven by the arms/hinges
(`Hinge` at `x = ±0.11` with a 0.06 box, `Arm` at `±0.138`), not by the 0.03 m lenses, so
pull those in first and shrink the lenses to ~0.024 m radius; keep the lens plane at
`y = -0.152` (in front of the sclera) and `z = 0.035` (eye line) so it does not ride up
over the new brow ridge.
- [x] Narrow `sunglasses` from 0.28 m to ~0.20 m. The hinges moved to ±0.075 (0.035 box), the
arms to ±0.098, and the lenses are 0.024 m radius at the same `y=-0.152`, `z=0.035` plane.
Rebuilt GLB/AO: measured width **0.202 m** (0.64x head), still inside the head band.
Also fixed `capture_realism.gd` so `--portrait-type=N` is actually parsed (it was documented
but ignored).
- [ ] 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
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",
"bounds_godot": {
"max": [
0.141,
0.065,
0.101,
0.059,
0.158
],
"min": [
-0.141,
0.005,
-0.101,
0.011,
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="):
for name in text.substr(9).split(","):
_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:
var cut := text.find("=", 6) # skip the "res://" scheme
+6 -3
View File
@@ -970,12 +970,15 @@ def build_gear(name):
elif name == "hood":
p.append(_hood("Hood", M("plastic_grey"), (0, 0, 0.015)))
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):
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)))
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")))
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")))
p.append(box("Bridge", (0.04, 0.006, 0.008), (0, -0.155, 0.045), M("plastic_black")))
elif name == "firefighter_helmet":