Skip to content

Commit e2f3b9d

Browse files
TMHSDigitalclaude
andcommitted
fix(showcase): fence-kit hero shares one post at each joint
The three-section hero placed whole copies of FenceLow at the 1.60 m tile pitch, so every joint showed two posts band to band. The leading section is still the checked mesh. Each follow-on section is now a render-only copy with its first post group (post, cap, shoe, bands, found as mesh shells) removed, stepped at the post pitch 2*HX, so its rails and brace tenon into the previous section's trailing post. The asset, its budgets and its falsifiers are unchanged; the asset sheet still judges FenceLow alone. Evidence (live, local): - .scratch/blender-5.2.1-windows-x64/blender.exe (Blender 5.2.1 LTS): default exit 0, base_tris=1012 r1=0.5000 r2=0.2174 collider 24; --output framing fill x=0.837 y=0.667, margins >= 0.081. - .scratch/blender-4.5.11-windows-x64/blender.exe (Blender 4.5.11 LTS): default exit 0, base_tris=1012 r2=0.2194 export 75900 B. - tests/check_falsifier_targets.py --run on both binaries: every fence-kit falsifier returns its documented code (9, 15, 16, 16, 17, 18, 19, 20, 21). - Contact sheet: luma 0.227 / stage 0.214 / warmth +0.134 / sat 0.180. - Asset sheet: FenceLow unchanged, in the lineup. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent d191ee8 commit e2f3b9d

6 files changed

Lines changed: 54 additions & 15 deletions

File tree

346 Bytes
Loading
-1.77 KB
Loading
-858 Bytes
Loading

‎showcase/fence-kit/README.md‎

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,18 @@ rail and housed 12 mm into both posts. It clears the bottom rail at the left
1717
post and the top rail at the right one. Rails and kick tenon into the post
1818
volume.
1919

20-
**Hero.** The still shows the kit doing its job: three linked duplicates of
21-
the one checked mesh at the 1.60 m pitch, so every joint in the picture is
22-
the tile fit the budgets assert — the paired posts meet band to band,
23-
`KIT_CLEAR` apart. The run stands in a render-only packed-earth strip, and
24-
the wood weathers in broad silver-grey patches (object-space noise) over
25-
the per-member tone and grain. The strip and the duplicates are staging;
26-
the asset sheet judges the single `FenceLow` section.
20+
**Hero.** The still shows a three-section run that reads as one fence,
21+
with one post at each joint. The leading section is the checked `FenceLow`
22+
mesh. Each follow-on section is a render-only copy with its first post group
23+
(post, cap, shoe and bands, found as mesh shells) removed, stepped at the
24+
post pitch `2·HX`. Its rails and brace then tenon into the previous
25+
section's trailing post. Placed whole at the 1.60 m tile pitch, the sections
26+
meet band to band, which is the tile fit the budgets assert, but every joint
27+
shows a doubled post. The earlier hero did exactly that. The run stands in a
28+
render-only packed-earth strip, and the wood weathers in broad silver-grey
29+
patches (object-space noise) over the per-member tone and grain. The strip
30+
and the trimmed copies are staging; the asset sheet judges the single
31+
`FenceLow` section.
2732

2833
It asserts **budget conformance** of the generated result. It does not
2934
witness an API contract. "It rendered without error" is not a check. This

‎showcase/fence-kit/fence_kit.py‎

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,19 +1262,53 @@ def render_still(low, wood, tex, path, engine):
12621262
ob.hide_render = True
12631263
ob.hide_viewport = True
12641264

1265-
# The hero is the kit doing its job: three sections at the tile pitch,
1266-
# linked duplicates of the one checked mesh, so every joint in the
1267-
# picture is the tile fit the check asserts (posts meet band to band,
1268-
# KIT_CLEAR apart). A run parent carries the yaw; level on the floor,
1269-
# since an X tilt sinks one face of the shoes.
1265+
# The hero is a run that reads as one fence, not three panels parked end
1266+
# to end: the leading section is the checked mesh itself, and each
1267+
# follow-on section is a render-only copy of it with its first post
1268+
# group (post, cap, shoe and bands, found as mesh shells) removed,
1269+
# stepped at the post pitch 2*HX so its rails and brace tenon into the
1270+
# previous section's trailing post - one post per joint. Placed at the
1271+
# 1.60 m tile pitch instead, whole sections meet band to band (the tile
1272+
# fit the check asserts) but every joint shows a doubled post. A run
1273+
# parent carries the yaw; level on the floor, since an X tilt sinks one
1274+
# face of the shoes.
12701275
run = bpy.data.objects.new("FenceRun", None)
12711276
scene.collection.objects.link(run)
12721277
run.rotation_euler.z = math.radians(-24.0)
1278+
follow_me = low.data.copy()
1279+
follow_me.name = f"{low.name}.Follow"
1280+
bm = bmesh.new()
1281+
try:
1282+
bm.from_mesh(follow_me)
1283+
post_edge = POST_XS[0] + POST_W / 2.0 + IRON_T + 0.002
1284+
seen = set()
1285+
doomed = []
1286+
for v in bm.verts:
1287+
if v in seen:
1288+
continue
1289+
group, stack = [], [v]
1290+
seen.add(v)
1291+
while stack:
1292+
cur = stack.pop()
1293+
group.append(cur)
1294+
for e in cur.link_edges:
1295+
o = e.other_vert(cur)
1296+
if o not in seen:
1297+
seen.add(o)
1298+
stack.append(o)
1299+
if max(g.co.x for g in group) < post_edge:
1300+
doomed.extend(group)
1301+
bmesh.ops.delete(bm, geom=doomed, context="VERTS")
1302+
bm.to_mesh(follow_me)
1303+
finally:
1304+
bm.free()
1305+
pitch = 2.0 * POST_XS[1]
12731306
sections = [low]
1274-
for i in (-1, 1):
1275-
dup = bpy.data.objects.new(f"{low.name}.Run{i:+d}", low.data)
1307+
low.location.x = -pitch
1308+
for i in (0, 1):
1309+
dup = bpy.data.objects.new(f"{low.name}.Run{i}", follow_me)
12761310
scene.collection.objects.link(dup)
1277-
dup.location.x = i * TILE
1311+
dup.location.x = i * pitch
12781312
sections.append(dup)
12791313
for ob in sections:
12801314
ob.parent = run

‎showcase/fence-kit/preview.webp‎

-1.52 KB
Loading

0 commit comments

Comments
 (0)