Color Attribute Wheel

examples/color-attribute-wheel/

The modern color-attributes API — mesh.color_attributes.new() on the CORNER domain, filled by expanding per-vertex HSV across face corners with foreach_get/foreach_set, then wired into a shader Attribute node.

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

witnesses CORNER-domain attributes are sized to loop count, not vertex count; the check asserts the sizing, that active_color points at it, and that the Attribute node is actually linked to Base Color, not just present.

tags mesh materials attributes

runs on 4.5 LTS · 5.1 · 5.2 LTS

blender --background --python examples/color-attribute-wheel/color_attribute_wheel.py --

falsify it Breaks the contract on purpose and must exit 6

blender --background --python examples/color-attribute-wheel/color_attribute_wheel.py -- --point-domain

A runnable example that builds an HSV color wheel disc entirely with bmesh and colors it with Mesh.color_attributes.new() — the modern attributes API, not the deprecated Mesh.vertex_colors alias AI code keeps reaching for. It witnesses the domain trap that comes with it: a CORNER-domain attribute is sized to len(mesh.loops), not len(mesh.vertices), so per-vertex data has to be expanded across face corners before it is written. The material wires the same attribute into a Shader Attribute node (attribute_type='GEOMETRY') feeding Base Color — the step AI code most often skips, leaving the mesh gray even when the attribute data is correct.

What it witnesses: a FLOAT_COLOR attribute on the CORNER domain, filled with one foreach_get (loop → vertex index) and one foreach_set (loop color), never a per-loop Python assignment. The check asserts the attribute is sized to the loop count and not the vertex count, that it is color_attributes.active_color (so a renderer or exporter actually picks it up), and that several probe loops match the closed-form HSV value for the vertex they reference. A separate check in the render path confirms the Attribute node is actually linked to Base Color, not just present in the node tree.

Staging#

The checked disc is flat and zero-thickness. The render path — only after check(), so the verified mesh is untouched until then — domes it into a shallow glazed plate (one foreach_get/foreach_set over vertex positions; the CORNER colours ride the same loops, so the colours on the plate are the colours the check verified), gives it a Solidify body, rings it with a turned brass bezel over a dark backing disc, and stands it at a 14° lean on a walnut studio easel. The glaze is a satin base under a thin clear coat; the dome curves the coat's reflection into a soft sheen instead of the hard horizon line a flat glaze draws. The path gates framing through examples/gallery_framing.py (exit 10): fill 0.739 y, every margin ≥ 0.050.

Run#

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

# Falsifier: POINT-domain attribute. Must exit non-zero.
blender --background --python color_attribute_wheel.py -- --point-domain

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

Exit codes#

Per-script sequential checks. 9 is a valid check code; there is no rule against it.

CodeMeaning
0Success
1Uncaught exception (FATAL wrapper)
2argparse / usage
3Topology ≠ closed form
4Color attribute missing
5Domain/type ≠ CORNER/FLOAT_COLOR (diagnostic, checked last)
6Attribute sized to verts, not loops (--point-domain lands here)
7active_color not set
8Probe loop color off HSV closed form
9--output produced no file
10Framing gate violation on the --output path (gallery_framing)

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 --point-domain (expects exit 6).

Source

examples/color-attribute-wheel/color_attribute_wheel.py View the script on GitHub →
A domed ceramic plate glazed with a full hue wheel that fades to white at the centre, ringed in a brass bezel and standing on a walnut easel.