blender-addon-development

Builds custom tools and extensions for Blender that add new buttons, menus and features to speed up your workflow.

Installation
Run `npx skills add "https://github.com/el4cteo/blender-skills" --skill "blender-addon-development"` to install this skill, then follow its SKILL.md instructions for my next request.

Paste this into Claude Code, Cursor, or any agent that can run commands.

SKILL.mdShow the author's original SKILL.md
---
name: blender-addon-development
description: Write Blender 5.2 add-ons as extensions - blender_manifest.toml, operators/panels/menus/property groups/preferences, bpy.props rules after 5.0, undo/redo, modal and timer patterns, gpu drawing (no bgl), bundling Python wheels, CLI validate/build/install, testing headless, extensions platform publishing. Use when creating or fixing a Blender add-on, tool, or UI.
license: MIT
metadata:
  author: blender-agent-skills
  version: "1.2.0"
---

# Add-on (Extension) Development

The execution model is in `blender-core`. Start from `assets/addon_template/` (validated, built, and registered in CI): `blender_manifest.toml`, `__init__.py`, `operators.py`, `ui.py`.

## Procedure
1. Copy the template, then set `id` (lowercase_underscores, permanent), `name`, `tagline` (no trailing period, ≤ 64 chars), `maintainer`, `version` (semver), `license` (SPDX, GPL-3.0-or-later for code using bpy), and `blender_version_min = "4.2.0"` or higher if you use newer APIs (e.g. `"5.2.0"` for the GN `properties.inputs` API).
2. Write classes with the prefix convention `MYTOOL_OT_x` (operator), `_PT_` (panel), `_MT_` (menu), `_PG_` (property group), `_AP_` (preferences), `_UL_` (UI list). `bl_idname` for operators is `my_tool.verb_noun`.
3. Validate and build:
   ```
   blender --command extension validate ./my_tool
   blender --command extension build --source-dir ./my_tool --output-dir ./dist
   blender --command extension install-file -r user_default -e ./dist/my_tool-1.0.0.zip
   ```
4. Test headless: register the package in-process, call operators with `temp_override`, and assert on data (see `tests/test_addon.py` in this repo).

## Rules (extension-era, 5.x)
- **Relative imports only** (`from . import ops`). The package name is decided by Blender, so preferences use `bl_idname = __package__`.
- No `bl_info` (it's ignored for extensions). Everything goes in the manifest.
- **No network or file access at import/register time.** Declare `[permissions]` (`files`, `network`, `clipboard`, `camera`, `microphone`) with a reason. Check `bpy.app.online_access` before any network call.
- **Third-party Python packages**: ship `.whl` files in `./wheels/` and list them under `wheels = [...]`. Never `pip install` at runtime. Platform-specific wheels require `platforms = [...]`.
- **Properties (5.0+)**: `bpy.props` values are attributes, not dict entries (`scene["my_prop"]` no longer reaches them). For read-only props use `options={'READ_ONLY'}`. `get_transform`/`set_transform` adapt values while keeping storage. Register with `PointerProperty(type=PG)` on an ID type, and `del` it on unregister.
- **Operators**: `bl_options={"REGISTER","UNDO"}` for undo plus a redo panel. `poll()` guards the context. Return `{"FINISHED"}`/`{"CANCELLED"}`. `self.report({"WARNING"}, msg)` for user feedback. Don't call other operators in loops if a data API exists.
- **UI**: `layout.use_property_split = True` gives modern alignment. Panels in the N-panel use `bl_region_type="UI"` + `bl_category`. Append menu entries with `VIEW3D_MT_*.append(func)` and remove them on unregister.
- **Unregister** everything in reverse order (classes, props, menus, handlers, timers, keymaps, draw handlers). Leaks break reloading.
- **Drawing** (overlays): `gpu` module + `gpu_extras.batch`. `bgl` was removed in 5.0. Textures come from `gpu.texture.from_image(img)`. For scene-linear images use `draw_texture_2d(..., is_scene_linear_with_rec709_srgb_target=True)`.
- **Long tasks**: a modal operator with a timer (`wm.event_timer_add`), or `bpy.app.timers.register` with chunked work. Never block the UI for seconds.
- **Handlers**: decorate persistent ones with `@bpy.app.handlers.persistent`. Keep them cheap (they run every frame/depsgraph update).
- **Keymaps**: add them to `wm.keyconfigs.addon`, store `(km, kmi)` pairs, and remove them on unregister.
- **Translations / i18n**: `bpy.app.translations.register(__package__, dict)`.

## Publishing (extensions.blender.org)
The Blender ID account uploads the built zip. Requirements: a valid manifest, a GPL-compatible license, no obfuscated code, no bundled binaries without source, and permissions declared. Screenshots/README go on the website listing. Update with a higher `version`.

## Gotchas
- `context.scene` inside a draw function can be `None` in some editors. Guard it.
- Storing Blender data references (`bpy.types.ID`) in Python globals crashes after undo or file load. Store names or `session_uid`, and look them up again.
- `bpy.utils.register_class` fails if annotations use `=` instead of `:` for properties.
- 5.0 made several bundled modules private (`rna_info`, `bl_ui_utils`...). Don't import them.
- 5.1 no longer loads the user site-packages by default. Bundle wheels instead of relying on user installs.
- 5.2: `PreferencesFilePaths.active_asset_library` indices are offset (the "All"/"Essentials" entries come first). `UILayout.template_palette(color=)` is removed. New: `UILayout.link`, `UILayout.textbox`, `bpy.data.all_ids`, `Window.screenshot`.

Ships with 4 supporting files:

  • assets/addon_template/__init__.py
  • assets/addon_template/blender_manifest.toml
  • assets/addon_template/operators.py
  • assets/addon_template/ui.py

Mirrored from the author's public source. Install counts from the open skills registry.

The systems behind these skills get built for partners every week.

Partner with us