AgentStack
SKILL verified MIT Self-run

Blender Syntax Addons

skill-impertio-studio-blender-bonsai-ifcopenshell-sverchok-claude-skill-package-blender-syntax-addons · by Impertio-Studio

>

No reviews yet
0 installs
15 views
0.0% view→install

Install

$ agentstack add skill-impertio-studio-blender-bonsai-ifcopenshell-sverchok-claude-skill-package-blender-syntax-addons

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Blender Syntax Addons? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

blender-syntax-addons

Quick Reference

Version Decision Tree

Creating a Blender addon?
│
├── Target Blender ≥ 4.2?
│   ├── YES → Use blender_manifest.toml (extension system)
│   │         NO bl_info dict. NO __init__.py bl_info.
│   │         See: §Extension System
│   │
│   └── Also support  Sidebar > My Tab",
    "description": "Short description of addon purpose",
    "warning": "",                  # Optional: shown as warning in prefs
    "doc_url": "https://example.com/docs",
    "tracker_url": "https://example.com/issues",
    "category": "Object",          # Must be a valid Blender category
}

Valid category values: 3D View, Add Mesh, Add Curve, Animation, Compositing, Development, Game Engine, Import-Export, Lighting, Material, Mesh, Node, Object, Paint, Physics, Render, Rigging, Scene, Sequencer, System, Text Editor, UV.

Pattern 2: Extension Manifest (Blender 4.2+)

Extensions use blender_manifest.toml instead of bl_info. The __init__.py contains ONLY register()/unregister() — no bl_info dict.

# blender_manifest.toml: REQUIRED for extensions (Blender 4.2+)
schema_version = "1.0.0"

id = "my_addon"
version = "1.0.0"
name = "My Addon"
tagline = "Short description without ending punctuation"
maintainer = "Developer Name "
type = "add-on"

# Minimum Blender version (must be >= 4.2.0 for extensions)
blender_version_min = "4.2.0"
# blender_version_max = "5.1.0"  # Optional: first UNSUPPORTED version

license = ["SPDX:GPL-3.0-or-later"]
# copyright = ["2024 Developer Name"]  # Optional

# Optional: category tags (from Blender's fixed tag list)
tags = ["Object", "Scene"]

# Optional: bundled Python wheels
# wheels = ["./wheels/some_lib-1.0.0-py3-none-any.whl"]

# Optional: platform restrictions
# platforms = ["windows-x64", "macos-arm64", "linux-x64"]

# Optional: permission declarations (required for network/file access)
# [permissions]
# network = "Downloads data from remote server"
# files = "Reads reference files from disk"
# clipboard = "Copies results to clipboard"

Pattern 3: Register / Unregister Lifecycle

# Blender 3.x/4.x/5.x: REQUIRED functions
import bpy

classes = (
    MyPropertyGroup,     # PropertyGroups FIRST
    MY_OT_operator,      # Then operators
    MY_PT_panel,         # Then UI elements
    MyAddonPreferences,  # Preferences can go anywhere
)

def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    # Attach properties AFTER registering their types
    bpy.types.Scene.my_props = bpy.props.PointerProperty(type=MyPropertyGroup)

def unregister():
    # Remove properties BEFORE unregistering their types
    del bpy.types.Scene.my_props
    for cls in reversed(classes):
        bpy.utils.unregister_class(cls)

Registration order rules:

  1. PropertyGroup classes BEFORE any class that references them via PointerProperty
  2. Parent panels BEFORE sub-panels (if using bl_parent_id)
  3. unregister() MUST reverse the order
  4. Property attachments (bpy.types.Scene.my_prop = ...) AFTER register_class()
  5. Property deletions (del bpy.types.Scene.my_prop) BEFORE unregister_class()

Pattern 4: Class Naming Convention (Enforced)

Blender enforces: {ADDON}_{TYPE}_{name} where {ADDON} is uppercase addon identifier, {TYPE} is a two-letter type code, and {name} is lowercase with underscores.

| Type Code | Base Class | Example | |-----------|-----------|---------| | OT | bpy.types.Operator | MYADDON_OT_do_something | | PT | bpy.types.Panel | MYADDON_PT_main_panel | | MT | bpy.types.Menu | MYADDON_MT_context_menu | | UL | bpy.types.UIList | MYADDON_UL_item_list | | HT | bpy.types.Header | MYADDON_HT_header | | KI | bpy.types.KeyingSetInfo | MYADDON_KI_keying |

For bl_idname on operators: use "addonname.action_name" (all lowercase, dot-separated). Example: bl_idname = "myaddon.export_data".

Pattern 5: Multi-File Addon Structure

my_addon/
├── __init__.py          # bl_info (or none for 4.2+) + register/unregister
├── blender_manifest.toml  # 4.2+ only
├── operators.py         # Operator classes
├── panels.py            # Panel classes
├── properties.py        # PropertyGroup classes
├── preferences.py       # AddonPreferences class
├── utils.py             # Helper functions (no bpy.types subclasses)
└── wheels/              # Bundled pip packages (4.2+ only)
    └── some_lib.whl

__init__.py with reload support (legacy addon):

bl_info = {
    "name": "My Addon",
    "blender": (3, 6, 0),
    "category": "Object",
    "version": (1, 0, 0),
}

# Reload support: REQUIRED for F8 / addon toggle without restart
if "bpy" in locals():
    import importlib
    importlib.reload(operators)
    importlib.reload(panels)
    importlib.reload(properties)
else:
    from . import operators
    from . import panels
    from . import properties

import bpy

classes = (
    properties.MyPropertyGroup,
    operators.MYADDON_OT_example,
    panels.MYADDON_PT_main,
)

def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    bpy.types.Scene.my_props = bpy.props.PointerProperty(
        type=properties.MyPropertyGroup
    )

def unregister():
    del bpy.types.Scene.my_props
    for cls in reversed(classes):
        bpy.utils.unregister_class(cls)

__init__.py for extension (4.2+) — NO bl_info, NO reload boilerplate:

from . import operators, panels, properties

import bpy

classes = (
    properties.MyPropertyGroup,
    operators.MYADDON_OT_example,
    panels.MYADDON_PT_main,
)

def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    bpy.types.Scene.my_props = bpy.props.PointerProperty(
        type=properties.MyPropertyGroup
    )

def unregister():
    del bpy.types.Scene.my_props
    for cls in reversed(classes):
        bpy.utils.unregister_class(cls)

Pattern 6: AddonPreferences

# Blender 3.x/4.x/5.x
class MyAddonPreferences(bpy.types.AddonPreferences):
    bl_idname = __package__  # MUST match addon module name — NEVER hardcode

    api_key: bpy.props.StringProperty(
        name="API Key",
        subtype='PASSWORD',
    )
    debug_mode: bpy.props.BoolProperty(
        name="Debug Mode",
        default=False,
    )
    output_path: bpy.props.StringProperty(
        name="Output Path",
        subtype='DIR_PATH',
    )

    def draw(self, context):
        layout = self.layout
        layout.prop(self, "api_key")
        layout.prop(self, "debug_mode")
        layout.prop(self, "output_path")

Access preferences at runtime:

# Blender 3.x/4.x/5.x
prefs = bpy.context.preferences.addons[__package__].preferences
value = prefs.debug_mode

Pattern 7: Extension Packaging (4.2+)

Build and validate an extension for distribution:

# Validate manifest
blender --command extension validate blender_manifest.toml

# Build .zip for upload to extensions.blender.org
blender --command extension build --source-dir ./my_addon --output-filepath my_addon.zip

# Install locally for testing
blender --command extension install-file my_addon.zip

Extension guidelines for extensions.blender.org:

  • MUST check bpy.app.online_access before any network request
  • MUST NOT install pip packages at runtime — bundle in wheels/
  • MUST NOT modify other addons or extensions
  • MUST NOT write to the addon installation directory
  • MUST use relative imports only — no sys.path manipulation
  • MUST load all modules as sub-modules within package namespace
  • SHOULD follow PEP 8

Pattern 8: User-Writable Storage (4.2+)

# Blender 4.2+: get a writable directory for addon data
import os
user_dir = bpy.utils.extension_path_user(__package__, create=True)
config_path = os.path.join(user_dir, "config.json")

Common Operations

Detect Addon vs Extension Context

# Blender 3.x/4.x/5.x: check if running as extension
import os

def is_extension():
    """Check if this addon is installed as a Blender 4.2+ extension."""
    manifest = os.path.join(os.path.dirname(__file__), "blender_manifest.toml")
    return os.path.exists(manifest)

Version-Conditional Registration

# Support both legacy and extension systems
def register():
    for cls in classes:
        bpy.utils.register_class(cls)

    # Handler registration
    bpy.app.handlers.load_post.append(on_load)

def unregister():
    bpy.app.handlers.load_post.remove(on_load)
    for cls in reversed(classes):
        bpy.utils.unregister_class(cls)

# For both: if __name__ == "__main__" block for script testing
if __name__ == "__main__":
    register()

Keymap Registration in Addon

addon_keymaps = []

def register():
    for cls in classes:
        bpy.utils.register_class(cls)

    # Add keymap entry
    wm = bpy.context.window_manager
    kc = wm.keyconfigs.addon
    if kc:
        km = kc.keymaps.new(name='3D View', space_type='VIEW_3D')
        kmi = km.keymap_items.new("myaddon.do_something", 'D', 'PRESS', ctrl=True)
        addon_keymaps.append((km, kmi))

def unregister():
    # Remove keymaps BEFORE unregistering classes
    for km, kmi in addon_keymaps:
        km.keymap_items.remove(kmi)
    addon_keymaps.clear()

    for cls in reversed(classes):
        bpy.utils.unregister_class(cls)

Migration: blinfo to blendermanifest.toml

| bl_info field | Manifest equivalent | Notes | |---------------|-------------------|-------| | "name" | name | Same | | "author" | maintainer | Add email: "Name " | | "version" | version | Tuple → string: (1,0,0)"1.0.0" | | "blender" | blender_version_min | Tuple → string, min "4.2.0" | | "description" | tagline | No ending punctuation | | "category" | tags | String → array: "Object"["Object"] | | "doc_url" | website | Same | | "warning" | (removed) | No equivalent in manifest | | "tracker_url" | (removed) | No equivalent in manifest | | (new) | id | Lowercase identifier, no spaces | | (new) | schema_version | Always "1.0.0" | | (new) | license | SPDX format: ["SPDX:GPL-3.0-or-later"] | | (new) | type | "add-on" or "theme" | | (new) | maintainer | "Name " format |


Reference Links

  • [references/methods.md](references/methods.md) — Complete API signatures for addon registration, preferences, and extension utilities
  • [references/examples.md](references/examples.md) — Working code examples for single-file, multi-file, and extension addons
  • [references/anti-patterns.md](references/anti-patterns.md) — What NOT to do when building Blender addons

Official Sources

  • https://docs.blender.org/api/current/info_overview.html
  • https://docs.blender.org/manual/en/latest/advanced/scripting/addon_tutorial.html
  • https://developer.blender.org/docs/handbook/extensions/
  • https://developer.blender.org/docs/handbook/extensions/addon_guidelines/
  • https://developer.blender.org/docs/features/extensions/schema/1.0.0/

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.