A runnable example that declares a reusable DippedGlaze shader group through
tree.interface.new_socket — the 4.x/5.x API that replaced tree.inputs/tree.outputs —
and instances it in five mug materials with different parameters, following
procedural-materials-and-shaders
and the shader-node-group snippet.
What it witnesses: the grouping contract. Sockets declared on the interface appear on
every group-node instance; all five materials share ONE group datablock (users == 5); and
the per-material Tint lives on the group node, not inside the group — set it inside the
tree and every mug changes at once.
The render is the proof. The group is a dipped stoneware glaze: bare buff clay at the
foot, a wavy dip line, iron speckle through clay and glaze alike, and a glaze that breaks
back toward clay over the rim. All of that lives inside the group, so the five mugs — a
warm-to-cool lineup of oxblood, amber, celadon, teal and cobalt — carry the same foot band,
the same dip line, the same speckle field and the same rim break. Only the instance-level
Tint differs. If Tint were baked into the group, the lineup would be one colour; if each
material built its own tree, the shared character would be a copy rather than one
datablock (the check's users gate).
A staggered shop-display lineup on the dark house stage: the odd mugs stand on a low walnut riser behind the even ones, so five mugs fill the frame without shrinking to a thin strip. Handles all turn the same way so the only thing that changes along the row is colour. The still renders under the Standard view transform (AgX would wash the five tints toward pastel); the key's spread is narrowed so it lights the mugs, not the back wall, and a warm wedge sits between the riser and the wall. Render path only.
# Cheap correctness check (no render) — the CI check:
blender --background --python shader_node_group.py --
# Falsifier: identical instance Tints. Must exit non-zero.
blender --background --python shader_node_group.py -- --same-tint
# Also render a still (EEVEE on a GPU host; use --engine cycles on GPU-less hosts):
blender --background --python shader_node_group.py -- --output mugs.png
blender --background --python shader_node_group.py -- --output mugs.png --engine cyclesPer-script sequential checks. 9 is a valid check code; there is no rule
against it. 10 is the shared framing helper.
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Uncaught exception (FATAL wrapper) |
| 2 | argparse / usage |
| 3 | Interface sockets missing Tint / Roughness / Shader |
| 4 | Group datablock users ≠ number of mug materials (5) |
| 5 | Instance points at a different node tree |
| 6 | Instance Tint values not pairwise distinct (--same-tint lands here) |
| 7 | --output produced no file |
| 10 | Gallery framing violation |
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 or --same-tint.