From dea75ed94f049ef576f9f44a169ebc97f19ca207 Mon Sep 17 00:00:00 2001 From: fOuttaMyPaint Date: Sat, 18 Jul 2026 18:43:20 -0400 Subject: [PATCH] feat: add text-version-stamp example (TextCurve solids + self-labeling renders) The gallery covered mesh, curves-with-bevel, GPv3, and armatures but nothing exercised the TextCurve data API, which AI-generated code routinely gets wrong (parsing version_string as bare semver, expecting to_mesh results to outlive to_mesh_clear). The stamp's body is the live bpy.app.version_string, so every render self-documents which Blender produced it and CI artifacts become self-labeling. The check asserts the closed-form solids contract (evaluated z-extent = 2 x (extrude + bevel_depth), bevel widening the outline by 2 x bevel_depth), that flat text is filled but planar, that body edits regenerate geometry, that version_string starts with the dotted version tuple ("4.5.11 LTS" is not bare semver), and that a Mesh reference dies at to_mesh_clear(). Co-Authored-By: Claude Fable 5 --- .cursor-plugin/plugin.json | 1 + .github/workflows/blender-smoke.yml | 13 + AGENTS.md | 4 +- CLAUDE.md | 6 +- README.md | 22 +- ROADMAP.md | 2 +- .../assets/text-version-stamp-hero.webp | Bin 0 -> 17928 bytes docs/gallery/index.html | 11 + docs/gallery/text-version-stamp/index.html | 524 ++++++++++++++++++ examples/gallery.json | 13 + examples/text-version-stamp/README.md | 40 ++ examples/text-version-stamp/preview.webp | Bin 0 -> 12442 bytes .../text-version-stamp/text_version_stamp.py | 281 ++++++++++ 13 files changed, 909 insertions(+), 8 deletions(-) create mode 100644 docs/gallery/assets/text-version-stamp-hero.webp create mode 100644 docs/gallery/text-version-stamp/index.html create mode 100644 examples/text-version-stamp/README.md create mode 100644 examples/text-version-stamp/preview.webp create mode 100644 examples/text-version-stamp/text_version_stamp.py diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json index bb943c8..00cf94a 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -75,6 +75,7 @@ "examples/shape-key-blend", "examples/swatch-grid", "examples/temp-override-join", + "examples/text-version-stamp", "examples/turntable", "examples/wave-displace" ] diff --git a/.github/workflows/blender-smoke.yml b/.github/workflows/blender-smoke.yml index 4f9b73a..baa6f5b 100644 --- a/.github/workflows/blender-smoke.yml +++ b/.github/workflows/blender-smoke.yml @@ -298,3 +298,16 @@ jobs: # Exits non-zero on failure. xvfb-run -a "$BLENDER" --background \ --python examples/armature-bend/armature_bend.py -- + + - name: Shipped example - text version stamp (TextCurve solids + version string) + run: | + set -euo pipefail + # Check only (no render): a TextCurve whose body is the live + # bpy.app.version_string; asserts the Curve subclass and built-in + # font contracts, that flat text is filled but planar, the closed + # form z-extent = 2*(extrude+bevel_depth), body edits regenerating + # geometry, that version_string starts with the dotted version tuple + # ("4.5.11 LTS" is not bare semver), and that a Mesh reference dies + # at to_mesh_clear(). Exits non-zero on failure. + xvfb-run -a "$BLENDER" --background \ + --python examples/text-version-stamp/text_version_stamp.py -- diff --git a/AGENTS.md b/AGENTS.md index 3859022..8cad4c5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -27,7 +27,7 @@ The content base (counts are CI-enforced against README.md and the manifest): - 2 templates: `extension-addon-template` for Extensions Platform add-ons, and `headless-batch-script-template` for unattended batch jobs. - 17 snippets covering canonical patterns. -- 18 examples under `examples//`: runnable scripts that assert a real +- 19 examples under `examples//`: runnable scripts that assert a real API contract with deterministic checks, exit non-zero on failure, and optionally render a still via `--output`. Each is executed headless on Blender 4.5 LTS and 5.1 by `blender-smoke.yml`; its render ships in the @@ -41,7 +41,7 @@ Blender-Developer-Tools/ rules/.mdc # 6 rule files templates// # 2 starter templates snippets/.py # 17 standalone Python snippets - examples// # 18 runnable smoke-gated examples (+ gallery.json) + examples// # 19 runnable smoke-gated examples (+ gallery.json) scripts/build_gallery.py # generates docs/gallery/ (stdlib only) scripts/site/ # vendored landing-page build (build_site.py + template) docs/gallery/ # committed generated gallery pages + hero assets diff --git a/CLAUDE.md b/CLAUDE.md index f37452c..a4996d5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -19,7 +19,7 @@ skills//SKILL.md - AI workflow definitions, 12 total rules/.mdc - Anti-pattern rules, 6 total templates// - Starter projects, 2 total snippets/.py - Standalone code patterns, 17 total -examples// - Runnable smoke-gated examples, 18 total (+ gallery.json) +examples// - Runnable smoke-gated examples, 19 total (+ gallery.json) scripts/build_gallery.py - Regenerates docs/gallery/ from gallery.json (stdlib only) scripts/site/ - Vendored landing-page build (Jinja2) docs/gallery/ - Committed generated gallery pages + hero renders @@ -80,11 +80,11 @@ v0.1.0: canonical object creation and deletion, depsgraph evaluated mesh, bmesh v0.2.0: Principled BSDF material, driver-with-custom-function via `driver_namespace`, application handler registration, shader node group with cross-version `interface` API, `foreach_get` bulk vertex read, version-branch skeleton, and USD export with `evaluation_mode='RENDER'`. -## Examples (18) +## Examples (19) Runnable scripts at `examples//`, each asserting a real API contract with deterministic checks (exit non-zero on failure) and optionally rendering a still via -`--output`. All eighteen run headless on Blender 4.5 LTS and 5.1 in `blender-smoke.yml`; +`--output`. All nineteen run headless on Blender 4.5 LTS and 5.1 in `blender-smoke.yml`; their renders ship in the site gallery at `docs/gallery/`. `examples/gallery.json` is the gallery's source of truth. When authoring a new one, copy the anatomy of `examples/bmesh-gear/` (script structure, README shape, dark-studio render recipe) and diff --git a/README.md b/README.md index 79d255f..ade00f2 100644 --- a/README.md +++ b/README.md @@ -17,14 +17,14 @@

- 12 skills  •  6 rules  •  2 templates  •  17 snippets  •  18 examples + 12 skills  •  6 rules  •  2 templates  •  17 snippets  •  19 examples

--- ## Overview -This repository ships **12 skills, 6 rules, 2 templates, 17 snippets, and 18 runnable examples** for Blender Python development targeting Blender 5.1 (current stable) with Blender 4.5 LTS fallback support. +This repository ships **12 skills, 6 rules, 2 templates, 17 snippets, and 19 runnable examples** for Blender Python development targeting Blender 5.1 (current stable) with Blender 4.5 LTS fallback support. The content is consumed by AI coding agents (Cursor, Claude Code, any MCP-capable client) when working on Blender add-ons, geometry nodes scripts, batch pipelines, or animation tooling. There is no build step. Edit the markdown and Python files directly. @@ -314,6 +314,24 @@ linear blend skinning — every evaluated vertex equals Σ wᵢ · (`pose_bone.matrix` @ `bone.matrix_local.inverted()`) @ rest, with the root ring pinned and the tip deflected. A straight tube is a failure. + + + + +Text version stamp: beveled brass 5.1.2 numerals standing on a dark studio floor over a glowing teal underline, with a small steel BLENDER caption above — the body text is the live bpy.app.version_string + + + +### [text-version-stamp](examples/text-version-stamp/) + +A beveled 3D stamp of the running Blender version — a `TextCurve` whose `body` is the +live `bpy.app.version_string`, so every render self-documents which Blender made it. +Asserts the TextCurve solids closed form (evaluated z-extent = 2 × (extrude + +bevel_depth), bevel widening the outline by 2 × bevel_depth), that flat text is filled +but planar, that body edits regenerate geometry, that `version_string` is not bare +semver on LTS builds (`"4.5.11 LTS"`), and that a Mesh reference dies at +`to_mesh_clear()`. + diff --git a/ROADMAP.md b/ROADMAP.md index 8c35cab..0d63cd1 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -97,7 +97,7 @@ Not committed; target list for the next content version. (v0.3.0 shipped the smo - Refresh the `slotted-actions-animation` skill against any 5.2 changes - Bump `blender_version_min` in the templates if 5.2 APIs are used - Additional snippets for asset library scripting, EXR baking, multi-file extensions -- Gallery coverage follow-ups from the GPv3 review: `text-version-stamp` (TextCurve self-labeling renders); lower priority: light-linking, bulk `pixels.foreach_set`, VSE sequences-to-strips witness (`grease-pencil-rosette` and `armature-bend` shipped first) +- Gallery coverage follow-ups from the GPv3 review: light-linking, bulk `pixels.foreach_set`, VSE sequences-to-strips witness (`grease-pencil-rosette`, `armature-bend`, and `text-version-stamp` shipped first) ## Future (uncommitted) diff --git a/docs/gallery/assets/text-version-stamp-hero.webp b/docs/gallery/assets/text-version-stamp-hero.webp new file mode 100644 index 0000000000000000000000000000000000000000..c9787ca2776f67e4ee2cfd1bcca30232b1fda3fd GIT binary patch literal 17928 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 D(_Q`^ literal 0 HcmV?d00001 diff --git a/docs/gallery/index.html b/docs/gallery/index.html index 13309b8..4a1b6c3 100644 --- a/docs/gallery/index.html +++ b/docs/gallery/index.html @@ -399,6 +399,17 @@

armature-bend

View example +
+ + text-version-stamp — The TextCurve data API — curves + +
+

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.

+

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.

+ View example +
+