Text Version Stamp

examples/text-version-stamp/

The TextCurve data API — curves.new(type='FONT'), live body text from bpy.app.version_string, extrude and bevel_depth solids, and evaluated-mesh conversion — so every render self-documents which Blender produced it.

Rendered headless by the example itself. Select it to enlarge.

witnesses TextCurve solids are exactly predictable: evaluated z-extent = 2 × (extrude + bevel_depth), bevel widens the outline by 2 × bevel_depth, editing body regenerates geometry — and version_string is not bare semver on LTS ("4.5.11 LTS"), so parse bpy.app.version instead.

tags curves depsgraph rendering

runs on 4.5 LTS · 5.1 · 5.2 LTS

blender --background --python examples/text-version-stamp/text_version_stamp.py --

falsify it Breaks the contract on purpose and must exit 4

blender --background --python examples/text-version-stamp/text_version_stamp.py -- --wrong-body

A runnable example that builds a beveled 3D stamp of the running Blender version — a TextCurve (bpy.data.curves.new(type='FONT')) whose body is the live bpy.app.version_string, so every render self-documents which Blender produced it. CI artifacts made this way are self-labeling.

What it witnesses: the TextCurve data-API contract. curves.new(type='FONT') returns a Curve subclass, the built-in font ("Bfont Regular") is always loaded even headless, body is plain assignable text that regenerates geometry on edit (more characters → strictly wider evaluated mesh), and extrude / bevel_depth 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 ("5.2.3 Release Candidate" ends in "e" and grows 0.0208 for a 0.02 bevel, #505). Flat text (no extrude, no bevel) is already filled — faces exist — but strictly planar. The check also witnesses the depsgraph lifetime hazard: after to_mesh_clear() the returned Mesh reference is dead and any access raises ReferenceError.

Version divergence: the string format itself differs — "5.1.2" on 5.x but "4.5.11 LTS" on 4.5 (the suffix is part of version_string). The check therefore asserts the contract that holds on both: version_string starts with the dotted bpy.app.version tuple. Code that parses version_string as a bare semver breaks on every LTS build; branch on the bpy.app.version tuple instead.

Staging#

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.

The render sets the stamp in Inter, which Blender ships at datafiles/fonts/Inter.woff2 on 4.5 LTS and 5.x alike (found through bpy.utils.system_resource('DATAFILES')). The built-in Bfont's "1" is a bare stem, so the old still read "5.2.I LTS". The check still asserts the built-in Bfont: the font swap happens on the render path only, after every check has passed, and the checked text body and its extents are unchanged.

Run#

# Cheap correctness check (no render) — the CI check:
blender --background --python text_version_stamp.py --

# Falsifier: body is not version_string. Must exit non-zero.
blender --background --python text_version_stamp.py -- --wrong-body

# Also render a still (EEVEE on a GPU host; use --engine cycles on GPU-less hosts):
blender --background --python text_version_stamp.py -- --output stamp.png
blender --background --python text_version_stamp.py -- --output stamp.png --engine cycles

The render scales the stamp to a constant width, so the frame holds for any version-string length.

Exit codes#

Per-script sequential checks. 9 is a valid check code; there is no rule against it. 10 is the shared framing helper.

CodeMeaning
0Success
1Uncaught exception (FATAL wrapper)
2argparse / usage
3Not a FONT TextCurve with the built-in Bfont
4Evaluated glyph mesh does not match a reference TextCurve of the live version_string (--wrong-body lands here)
5Flat text is not a filled planar mesh
6Extrude / bevel closed form failed
7Appending characters did not widen the text
8Mesh survived to_mesh_clear()
9--output produced no file
10Gallery framing violation
13--output: bundled datafiles/fonts/Inter.woff2 not found
14version_string does not start with the dotted bpy.app.version tuple

The blender-smoke workflow runs the check on Blender 5.2 LTS and 4.5 LTS (5.1 on the weekly cron, the needs-5.1 PR label, or manual dispatch). Smoke does not pass --output. Its catalog falsifier is --wrong-body (expects exit 4).

Source

examples/text-version-stamp/text_version_stamp.py View the script on GitHub →
The Blender version number in polished gold 3D characters on a chamfered two-tier dark stone plinth, with BLENDER inked on a brushed-steel nameplate across its face.