Swatch Grid
Procedural Principled materials — metal and dielectric, the emission pattern, and the cross-version set_specular shim.
examples/light-link-studio/
One key, one hero: a light linked to a receiver collection lights only the hero, proven by two pixel renders in one pass. Linked: 3.6x luminance ratio; unlinked in the same check: the decoy rises 233% while the hero holds at 0.3% drift.
Rendered headless by the example itself. Select it to enlarge.
runs on 4.5 LTS · 5.1 · 5.2 LTS
blender --background --python examples/light-link-studio/light_link_studio.py --
falsify it Breaks the contract on purpose and must exit 6
blender --background --python examples/light-link-studio/light_link_studio.py -- --skip-link
A runnable example that stages one key light linked to a hero sphere beside an identical decoy, renders the studio twice in one pass, and proves the whole light-linking contract in pixels — the feature AI-generated staging code most often misses or misaddresses.
What it witnesses: the light-linking contract and the traps around it.
ld.light_linking is an AttributeError on both versions (verified); the path is obj.light_linking.receiver_collection (ObjectLightLinking, with blocker_collection alongside). Assignment reads back through the API.render.engine swapped: BLENDER_EEVEE on 5.x, BLENDER_EEVEE_NEXT on 4.x) at 3.8x linked ratio on both 4.5.11 EEVEE Next and 5.1.2 EEVEE, matching Cycles within sampling noise. The shipped check still pins Cycles for deterministic tiny-sample CPU renders; luminance gates need view_transform = 'Standard' (AgX compresses the ratios).What each check catches on failure: inverting the link to the decoy collection (exit 6 — hero/decoy ratio collapses to 0.39x), an RNA move of the API onto the Light datablock (exit 3, guarded), a lost assignment read-back (exit 5), a link that doesn't restrict (exit 7, rise below 50%), and a non-surgical restriction (exit 8, hero drift above 5%).
Version witness: ObjectLightLinking API and the measured ratios match on Blender 4.5 LTS and 5.1 (3.7x vs 3.6x linked; rise 238% vs 233% — inside the rise noise described above).
The render is the contract at a glance, on designed subjects: after the check passes on the spheres, the still hides them and stands two identical lathed porcelain chess kings (gilt collar and cross, one shared material) in the hero and decoy collections. The only difference between the kings is the linked key, recoloured amber for the still: the LINKED king glows warm over its placard and the warm floor inlay, the UNLINKED king stays cool grey. The shared fill and rim are pulled down for the still only, because glossy porcelain picks up far more of them than the matte check spheres do. The still's render path gates framing through examples/gallery_framing.py (exit 10) before writing.
# Two-render correctness check (tiny Cycles CPU renders) — the CI check:
blender --background --python light_link_studio.py --
# Falsifier: receiver_collection unset. Must exit non-zero (linked render: decoy lit).
blender --background --python light_link_studio.py -- --skip-link
# Also render the gallery still (Cycles, deterministic samples):
blender --background --python light_link_studio.py -- --output linked.png
Per-script sequential checks. 9 is a valid check code; there is no rule against it.
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Uncaught exception (FATAL wrapper) |
| 2 | argparse / usage |
| 3 | Light datablock gained light_linking |
| 4 | Light objects lost light_linking |
| 6 | Linked state: hero dark or hero/decoy ratio below gate (--skip-link lands here) |
| 7 | Decoy rise below gate when unlinked |
| 8 | Hero drifted across the unlink |
| 9 | --output produced no file |
| 10 | Framing 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 --skip-link (expects exit 6).