Skip to content

Commit 0066093

Browse files
TMHSDigitalclaude
andcommitted
fix(examples): text-version-stamp bevel check no longer depends on the release-cycle suffix
The 5.2.3-candidate daily failed with exit 6. The check asserted the whole x-extent grows by exactly 2 x bevel_depth, but the right edge is the version_string suffix. "5.2.3 Release Candidate" ends in "e", whose curved outline grows 0.02080 for a 0.02 bevel (TOL 1e-4). "LTS" grows 0.02007, Beta / Alpha 0.02000, so release builds passed by luck. The left edge is always a digit (check 14), and it grows exactly 0.02000 on every body probed. The check now asserts that edge exactly, and gives the trailing edge a band of [bevel, 1.1 x bevel]. Live runs (happy exit 0, --wrong-body exit 4) on 4.5.14 LTS, 5.2.1 LTS and the 5.2.3 LTS daily (e13b728c6880). A harness that swaps version_string for "<ver> Release Candidate" / LTS / Beta / Alpha returns 0 on all three. Falsifier: shearing every FONT curve by 0.5 slants the leading digit, and the check exits 6 (left growth 0.03236 on 4.5.14, 0.02587 on 5.2.3). Closes #505 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 0c8db00 commit 0066093

3 files changed

Lines changed: 30 additions & 8 deletions

File tree

‎docs/gallery/text-version-stamp/index.html‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ <h1>Text Version Stamp</h1>
6262
<nav class="jumpnav" aria-label="On this page"><span class="tag">jump to</span> <a href="#run">Run</a> <a href="#exit-codes">Exit codes</a> <a href="#source">Source</a> <a href="#related">Related</a></nav>
6363
<section class="detail-section md">
6464
<p>A runnable example that builds a beveled 3D stamp of the running Blender version — a <code>TextCurve</code> (<code>bpy.data.curves.new(type=&#x27;FONT&#x27;)</code>) whose <code>body</code> is the live <code>bpy.app.version_string</code>, so every render self-documents which Blender produced it. CI artifacts made this way are self-labeling.</p>
65-
<p><strong>What it witnesses:</strong> the TextCurve data-API contract. <code>curves.new(type=&#x27;FONT&#x27;)</code> returns a Curve subclass, the built-in font (&quot;Bfont Regular&quot;) is always loaded even headless, <code>body</code> is plain assignable text that regenerates geometry on edit (more characters → strictly wider evaluated mesh), and <code>extrude</code> / <code>bevel_depth</code> produce exactly predictable solids: the evaluated mesh z-extent equals 2 × (extrude + bevel_depth) and the round bevel widens the outline in-plane by 2 × bevel_depth. Flat text (no extrude, no bevel) is already <em>filled</em> — faces exist — but strictly planar. The check also witnesses the depsgraph lifetime hazard: after <code>to_mesh_clear()</code> the returned Mesh reference is dead and any access raises <code>ReferenceError</code>.</p>
65+
<p><strong>What it witnesses:</strong> the TextCurve data-API contract. <code>curves.new(type=&#x27;FONT&#x27;)</code> returns a Curve subclass, the built-in font (&quot;Bfont Regular&quot;) is always loaded even headless, <code>body</code> is plain assignable text that regenerates geometry on edit (more characters → strictly wider evaluated mesh), and <code>extrude</code> / <code>bevel_depth</code> produce exactly predictable solids: the evaluated mesh z-extent equals 2 × (extrude + bevel_depth) and the round bevel pushes the upright leading digit out by exactly bevel_depth. The trailing edge only gets a band (bevel_depth to 1.1 × bevel_depth): it is the release-cycle suffix, and a curved last glyph overshoots (&quot;5.2.3 Release Candidate&quot; ends in &quot;e&quot; and grows 0.0208 for a 0.02 bevel, #505). Flat text (no extrude, no bevel) is already <em>filled</em> — faces exist — but strictly planar. The check also witnesses the depsgraph lifetime hazard: after <code>to_mesh_clear()</code> the returned Mesh reference is dead and any access raises <code>ReferenceError</code>.</p>
6666
<p><strong>Version divergence:</strong> the string format itself differs — <code>&quot;5.1.2&quot;</code> on 5.x but <code>&quot;4.5.11 LTS&quot;</code> on 4.5 (the suffix is part of <code>version_string</code>). The check therefore asserts the contract that holds on both: <code>version_string</code> starts with the dotted <code>bpy.app.version</code> tuple. Code that parses <code>version_string</code> as a bare semver breaks on every LTS build; branch on the <code>bpy.app.version</code> tuple instead.</p>
6767
<h2 id="staging">Staging<a class="anchor" href="#staging" aria-label="Link to this section">#</a></h2>
6868
<p>The polished gold numerals stand on a two-tier chamfered plinth of dark honed stone. A brushed-steel nameplate on its front face carries the BLENDER caption, so gold is reserved for the version and steel for the plate. A card light behind the camera gives the gold faces something to mirror. The still renders under the Standard view transform on the house stage.</p>

‎examples/text-version-stamp/README.md‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ returns a Curve subclass, the built-in font ("Bfont Regular") is always loaded e
1010
headless, `body` is plain assignable text that regenerates geometry on edit (more
1111
characters → strictly wider evaluated mesh), and `extrude` / `bevel_depth` produce
1212
exactly predictable solids: the evaluated mesh z-extent equals 2 × (extrude +
13-
bevel_depth) and the round bevel widens the outline in-plane by 2 × bevel_depth.
13+
bevel_depth) and the round bevel pushes the upright leading digit out by exactly
14+
bevel_depth. The trailing edge only gets a band (bevel_depth to 1.1 × bevel_depth):
15+
it is the release-cycle suffix, and a curved last glyph overshoots ("5.2.3 Release
16+
Candidate" ends in "e" and grows 0.0208 for a 0.02 bevel, #505).
1417
Flat text (no extrude, no bevel) is already *filled* — faces exist — but strictly
1518
planar. The check also witnesses the depsgraph lifetime hazard: after
1619
`to_mesh_clear()` the returned Mesh reference is dead and any access raises

‎examples/text-version-stamp/text_version_stamp.py‎

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
returns a Curve subclass whose `body` is plain assignable text, whose default
55
font ("Bfont Regular") is always loaded even headless, and whose `extrude` /
66
`bevel_depth` produce exactly predictable solid geometry — the evaluated mesh
7-
z-extent equals 2 x (extrude + bevel_depth) and the round bevel widens the
8-
glyph outline in-plane by 2 x bevel_depth. Because the body is the live
7+
z-extent equals 2 x (extrude + bevel_depth) and the round bevel pushes the
8+
leading digit's outline out by bevel_depth. Because the body is the live
99
`bpy.app.version_string`, every render self-documents which Blender made it.
1010
1111
Version note: the string format itself diverges — plain "5.1.2" on 5.x but
@@ -64,6 +64,15 @@ def eval_extents(obj, deps):
6464
return out, me # me is now DEAD — returned only to witness that
6565

6666

67+
def eval_x_bounds(obj, deps):
68+
"""(min x, max x) of the evaluated mesh."""
69+
deps.update()
70+
ev = obj.evaluated_get(deps)
71+
xs = [v.co.x for v in ev.to_mesh().vertices]
72+
ev.to_mesh_clear()
73+
return min(xs), max(xs)
74+
75+
6776
def check(obj):
6877
txt = obj.data
6978

@@ -114,16 +123,26 @@ def check(obj):
114123
file=sys.stderr)
115124
return 4
116125

117-
# solidify: z-extent is exactly 2*(extrude+bevel), bevel widens x by 2*bevel
126+
# solidify: z-extent is exactly 2*(extrude+bevel), and the bevel pushes the
127+
# outline out by bevel_depth. That is exact on the left edge, which is
128+
# always a digit (check 14). The right edge is the release-cycle suffix: a
129+
# curved last glyph overshoots ("5.2.3 Release Candidate" ends in "e" and
130+
# grows 0.02080 for a 0.02 bevel, #505), so it only gets a band.
131+
x_min_flat, x_max_flat = eval_x_bounds(obj, deps)
118132
txt.extrude = EXTRUDE
119133
txt.bevel_depth = BEVEL
120134
txt.bevel_resolution = 3
121135
(nv, nf, x_solid, z_solid), dead = eval_extents(obj, deps)
136+
x_min_solid, x_max_solid = eval_x_bounds(obj, deps)
122137
want_z = 2.0 * (EXTRUDE + BEVEL)
123-
want_x = x_flat + 2.0 * BEVEL
124-
if abs(z_solid - want_z) > TOL or abs(x_solid - want_x) > TOL:
138+
grow_left = x_min_flat - x_min_solid
139+
grow_right = x_max_solid - x_max_flat
140+
if (abs(z_solid - want_z) > TOL or abs(grow_left - BEVEL) > TOL
141+
or not BEVEL - TOL <= grow_right <= 1.1 * BEVEL):
125142
print(f"ERROR: extrude/bevel closed form failed: z {z_solid:.5f} != "
126-
f"{want_z:.5f} or x {x_solid:.5f} != {want_x:.5f}", file=sys.stderr)
143+
f"{want_z:.5f}, left growth {grow_left:.5f} != {BEVEL}, or right "
144+
f"growth {grow_right:.5f} outside [{BEVEL}, {1.1 * BEVEL:.3f}]",
145+
file=sys.stderr)
127146
return 6
128147

129148
# editing body regenerates geometry: more characters -> strictly wider

0 commit comments

Comments
 (0)