Skip to content

Commit cd3e232

Browse files
TMHSDigitalclaude
andcommitted
fix: correct version-accuracy defects across skills and snippets
Re-verified empirically on Blender 4.5.10 LTS and 5.1.1 plus the 4.4/4.5/5.0 release notes. Four confirmed defects corrected: 1. EEVEE engine id was inverted. Correct mapping: 4.2-4.5 use 'BLENDER_EEVEE_NEXT'; 5.0+ reclaimed 'BLENDER_EEVEE' (5.0 release notes, confirmed by introspection: 5.1.1 rejects _NEXT, 4.5.10 rejects plain). Fixed version-branch-skeleton.py get_eevee_engine_id(), the headless-batch-scripting detect snippet/choices/prose, and the procedural-materials version table. 2. Slotted Actions framing and fabricated 4.5 shim. The slotted data model shipped in 4.4 (not 5.0); legacy action.fcurves was removed in 5.0; action_ensure_channelbag_for_slot is new in 5.0 and absent on 4.4/4.5 (no auto-detecting shim). Rewrote slotted-actions-animation: real version-branching helper (ensure-fn on 5.0+, strip.channelbag(ensure=True) on 4.4/4.5), removed the hasattr(action,'slots') "5.x sniff", corrected the compatibility matrix and the snippet header comment. 3. save_pre/save handler signature. Arg0 is the file path string, not a Scene (4.5 docs + introspection on both versions). Fixed the handler table and worked examples in drivers-and-app-handlers and app-handler-registration.py so handlers reach scenes via bpy.data, never treating arg0 as a Scene. 4. Geometry Nodes node version tags. For Each Element (4.3) and Mesh to SDF Grid (4.3) were mis-tagged "5.0+"; fixed labels and changed has_for_each_element() to gate on >= (4,3,0). NodeSocketBundle/has_bundles left at 5.0 (confirmed: interface socket works in 5.1, TypeError in 4.5). No content added or removed; counts unchanged (12/6/2/17). All snippets and templates py_compile. Corrected snippets verified to run on 4.5.10 and 5.1.1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: fOuttaMyPaint <TMhospitalitystrategies@gmail.com>
1 parent 881e17b commit cd3e232

8 files changed

Lines changed: 124 additions & 75 deletions

File tree

skills/drivers-and-app-handlers/SKILL.md

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -145,15 +145,17 @@ The handlers live as lists at `bpy.app.handlers.<event>`. To register, append; t
145145

146146
| Handler | Signature | Fires when |
147147
| --- | --- | --- |
148-
| `save_pre` | `(scene)` (some 4.x), `(scene, filepath)` (5.x) | Before the .blend is written. Use to clean up data you don't want serialized. |
149-
| `save_post` | Same | After the .blend is written. Use for post-save bookkeeping. |
150-
| `load_pre` | `(scene)` | Before a .blend is loaded. The current scene is still the old one. |
151-
| `load_post` | `(scene)` | After a .blend is loaded. Use to validate or migrate add-on data. |
148+
| `save_pre` | `(filepath: str)` | Before the .blend is written. The argument is the file being saved (empty string for the startup file), **not** a Scene. Use to clean up data you don't want serialized. |
149+
| `save_post` | `(filepath: str)` | After the .blend is written. Same single filepath argument. |
150+
| `load_pre` | `(filepath: str)` | Before a .blend is loaded. The argument is the file being loaded. |
151+
| `load_post` | `(filepath: str)` | After a .blend is loaded. Use to validate or migrate add-on data. |
152152
| `depsgraph_update_pre` | `(scene, depsgraph)` | Before a depsgraph evaluation pass. |
153153
| `depsgraph_update_post` | `(scene, depsgraph)` | After a depsgraph evaluation pass. Fires very frequently; must be O(1) or near-O(1). |
154154
| `frame_change_pre` | `(scene, depsgraph)` | Before frame is set. |
155155
| `frame_change_post` | `(scene, depsgraph)` | After frame is set. |
156-
| `exit_pre` (new in 5.1) | `(scene)` | Before Blender shuts down. Use for resource cleanup, telemetry flush, etc. |
156+
| `exit_pre` (new in 5.1) | `(*args)` | Before Blender shuts down. Use for resource cleanup, telemetry flush, etc. The argument is not a Scene; accept `*args`. |
157+
158+
The save/load handlers (`save_pre`, `save_post`, `load_pre`, `load_post`) all receive the **file path as a string** as their single argument, **not** a Scene. (Verified empirically on 4.5.10 LTS and 5.1.1, and against `bpy.app.handlers` docs: "Accepts one argument: the file being saved/loaded.") Only the depsgraph/frame-change handlers receive `(scene, depsgraph)`.
157159

158160
The `exit_pre` handler in 5.1 is particularly useful for add-ons that need to release external resources (sockets, log files, child processes) deterministically before the process terminates.
159161

@@ -165,10 +167,15 @@ from bpy.app.handlers import persistent
165167

166168

167169
@persistent
168-
def on_save_pre(scene, filepath):
169-
"""Clear temporary cache data before save so it doesn't bloat the .blend."""
170-
if 'my_addon_cache' in scene:
171-
del scene['my_addon_cache']
170+
def on_save_pre(filepath):
171+
"""Clear temporary cache data before save so it doesn't bloat the .blend.
172+
173+
The handler argument is the path being saved (a string), not a Scene, so
174+
reach the scene(s) through bpy.data.
175+
"""
176+
for scene in bpy.data.scenes:
177+
if 'my_addon_cache' in scene:
178+
del scene['my_addon_cache']
172179

173180

174181
def register():
@@ -201,7 +208,10 @@ from bpy.app.handlers import persistent
201208

202209

203210
@persistent
204-
def increment_save_count(scene, filepath):
211+
def increment_save_count(filepath):
212+
# save_post passes the saved file path (a string) as its only argument.
213+
# Store the running count on the current scene.
214+
scene = bpy.context.scene
205215
counts = scene.get('save_counts', {})
206216
counts[filepath] = counts.get(filepath, 0) + 1
207217
scene['save_counts'] = counts
@@ -224,8 +234,11 @@ from bpy.app.handlers import persistent
224234

225235

226236
@persistent
227-
def cleanup_on_exit(scene):
228-
"""Release the external log file handle before the process terminates."""
237+
def cleanup_on_exit(*args):
238+
"""Release the external log file handle before the process terminates.
239+
240+
exit_pre's argument is unused here; accept *args to stay signature-proof.
241+
"""
229242
global _log_handle
230243
if _log_handle is not None:
231244
_log_handle.close()
@@ -250,14 +263,14 @@ The `exit_pre` handler list is new in Blender 5.1. On 4.5 LTS, fall back to OS-l
250263
- **Doing real work inside `depsgraph_update_post`.** This handler fires on every depsgraph evaluation, which is many times per second during playback or interaction. Anything more than O(1) bookkeeping causes user-visible slowdown.
251264
- **Recursively modifying the scene from a depsgraph handler.** The modification triggers another depsgraph evaluation, which calls the handler, which modifies the scene. Infinite loop, often manifesting as a hang.
252265
- **Asymmetric register/unregister.** The handler is appended on register but not removed on unregister. Disabling the add-on leaves the callback in place. After enable/disable cycles, the callback runs N times per event.
253-
- **Assuming the `save_pre` signature.** It changed across the 4.x to 5.x window. Use `(scene, filepath=None)` defensively, or `*args` if you don't need the values.
266+
- **Treating the `save_pre` argument as a Scene.** The save/load handlers receive the **file path string** (empty for the startup file), not a Scene. Name the parameter `filepath` (or take `*args`), and reach scenes via `bpy.context.scene` / `bpy.data.scenes`. A membership test like `'key' in arg0` against the path string is silently wrong, and `del arg0['key']` raises `TypeError`.
254267

255268
## Version correctness
256269

257270
| Topic | 4.5 LTS | 5.1 stable |
258271
| --- | --- | --- |
259272
| `exit_pre` handler | Not available | New in 5.1; use `atexit` fallback for 4.x |
260-
| `save_pre` signature | `(scene)` in 4.0, varies | `(scene, filepath)` in 5.x |
273+
| `save_pre` / `save_post` signature | `(filepath)` — a string | `(filepath)` — a string (unchanged) |
261274
| `driver_namespace` | Available | Same |
262275
| Driver security | Already restrictive | Same |
263276

skills/geometry-nodes-python/SKILL.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,10 @@ The argument is the exact RNA `bl_idname` of the node class. A few you'll reach
154154
| Vector Math | `ShaderNodeVectorMath` |
155155
| Mix | `ShaderNodeMix` |
156156
| Noise Texture | `ShaderNodeTexNoise` |
157-
| Mesh to SDF Grid (5.0+) | `GeometryNodeMeshToSDFGrid` |
157+
| Mesh to SDF Grid (4.3+) | `GeometryNodeMeshToSDFGrid` |
158158
| SDF Grid to Mesh / Volume to Mesh | `GeometryNodeVolumeToMesh` |
159159
| Repeat Input / Output | `GeometryNodeRepeatInput`, `GeometryNodeRepeatOutput` |
160-
| For Each Element Input / Output (5.0+) | `GeometryNodeForeachGeometryElementInput`, `GeometryNodeForeachGeometryElementOutput` |
160+
| For Each Element Input / Output (4.3+) | `GeometryNodeForeachGeometryElementInput`, `GeometryNodeForeachGeometryElementOutput` |
161161

162162
To list all available Geometry node types in your Blender version:
163163

@@ -243,8 +243,9 @@ def has_bundles():
243243
return major >= 5
244244

245245
def has_for_each_element():
246-
major, _minor, _patch = bpy.app.version
247-
return major >= 5
246+
# The For Each Element zone shipped in Blender 4.3, so it is available on
247+
# the whole 4.5 LTS / 5.x supported range. (Bundles, by contrast, are 5.0+.)
248+
return bpy.app.version >= (4, 3, 0)
248249
```
249250

250251
## Common AI mistakes

skills/headless-batch-scripting/SKILL.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,15 @@ def main():
161161
parser = argparse.ArgumentParser()
162162
parser.add_argument("--output", required=True)
163163
parser.add_argument("--frames", default="1")
164-
parser.add_argument("--engine", default="CYCLES", choices=["CYCLES", "BLENDER_EEVEE_NEXT"])
164+
parser.add_argument("--engine", default="CYCLES", choices=["CYCLES", "EEVEE"])
165165
args = parser.parse_args(argv)
166166

167167
scene = bpy.context.scene
168-
scene.render.engine = args.engine
168+
if args.engine == "EEVEE":
169+
# EEVEE's engine id is 'BLENDER_EEVEE' on 5.0+, 'BLENDER_EEVEE_NEXT' on 4.2-4.5.
170+
scene.render.engine = 'BLENDER_EEVEE' if bpy.app.version >= (5, 0, 0) else 'BLENDER_EEVEE_NEXT'
171+
else:
172+
scene.render.engine = args.engine
169173
scene.render.image_settings.file_format = 'PNG'
170174

171175
output_dir = os.path.dirname(args.output) or "."
@@ -185,7 +189,7 @@ if __name__ == "__main__":
185189
Notes:
186190

187191
- `bpy.ops.render.render(write_still=True)` is one of the few `bpy.ops` calls that work in `--background`.
188-
- `BLENDER_EEVEE_NEXT` is the 5.x EEVEE engine identifier. On 4.5 LTS, use `BLENDER_EEVEE`. Detect via `bpy.app.version`.
192+
- EEVEE's engine identifier is `BLENDER_EEVEE` on Blender 5.0+ and `BLENDER_EEVEE_NEXT` on 4.2-4.5 LTS (the id was reclaimed in 5.0 after legacy EEVEE was removed in 4.2). Detect via `bpy.app.version`.
189193

190194
## Detecting Blender version in scripts
191195

@@ -195,9 +199,9 @@ import bpy
195199
major, minor, _patch = bpy.app.version
196200

197201
if (major, minor) >= (5, 0):
198-
eevee_engine = 'BLENDER_EEVEE_NEXT'
199-
else:
200202
eevee_engine = 'BLENDER_EEVEE'
203+
else:
204+
eevee_engine = 'BLENDER_EEVEE_NEXT'
201205
```
202206

203207
`bpy.app.version` is a `(major, minor, patch)` tuple, always reliable.

skills/procedural-materials-and-shaders/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ When the same subgraph appears across multiple materials, factor it into a `Shad
162162
| --- | --- | --- | --- |
163163
| Principled BSDF | `ShaderNodeBsdfPrincipled` | Same | Some inputs renamed in 5.0; `Specular` -> `Specular IOR Level`. Use string lookup with the 5.x name. |
164164
| Node group socket interface | `group.inputs.new` / `group.outputs.new` | `group.interface.new_socket` | Different APIs, see snippet `shader-node-group.py`. |
165-
| EEVEE engine string | `'BLENDER_EEVEE'` | `'BLENDER_EEVEE_NEXT'` | EEVEE Next is the default in 5.x; legacy EEVEE was retired. |
165+
| EEVEE engine string | `'BLENDER_EEVEE_NEXT'` | `'BLENDER_EEVEE'` | Legacy EEVEE was removed in 4.2. EEVEE Next used the id `'BLENDER_EEVEE_NEXT'` on 4.2-4.5, then reclaimed the plain `'BLENDER_EEVEE'` id in 5.0. |
166166
| Layered Textures | Not present | Not present in 5.1 | Roadmap pushed to 2027. Do not generate code referencing it. |
167167

168168
EEVEE Next stabilized in Blender 5.1 with material caching and feature parity improvements; most Principled BSDF graphs render identically across EEVEE Next and Cycles.

0 commit comments

Comments
 (0)