Standalone Add-on
So far, you wrote a function and built an add-on.
Now let’s look at what was actually generated.
What Actually Gets Generated
Build into a temporary folder so we can inspect the output:
quickaddon build audiodeck.py \
--out ./dist \
--force
Now inspect the generated directory:
ls -R ./dist
You should see:
dist/
└── audiodeck/
├── __init__.py
├── generated_ops.py
└── user_code.py
user_code.py is simply a copy of your original Python file.
Nothing special happens there. From this point forward, we will treat it as implicit and focus on the other two files.
Those two files define the pattern.
File 1 – generated_ops.py
Open:
dist/audiodeck/generated_ops.py
This file is substantial — but you did not have to write it.
Inside you will find:
- Generated Operator classes
- Shared parameter definitions
- UI draw helpers
- Registration hooks
Example (trimmed):
import bpy
# Auto-generated by quickaddon
# Source addon: Audiogen
_SHARED_PTR_NAME = "qa_shared__audiogen"
_HOST_API = None # injected by host at register time
class _FallbackHostAPI:
...
class QA_SHARED_ROOT(bpy.types.PropertyGroup):
project__audio_path: bpy.props.StringProperty(name="audio_path", default='', subtype="FILE_PATH")
class QA_OT_SETUP_FROM_AUDIO(bpy.types.Operator):
...
class QA_OT_RENDER_FROM_AUDIO(bpy.types.Operator):
...
...
# Panel -> ops mapping, used by host integration hooks
PANEL_OPS = {
"QuickAddon": [
("Setup From Audio", "qa_audiogen.setup_from_audio"),
("Render From Audio", "qa_audiogen.render_from_audio"),
],
}
def draw_shared(layout, context):
...
def draw_tools(layout, context, *, category=None):
...
def draw(layout, context, *, category=None, with_shared=True):
"""
Host integration hook:
- with_shared=True draws shared inputs first.
- category controls which tool group(s) to draw.
"""
if with_shared:
draw_shared(layout, context)
layout.separator()
draw_tools(layout, context, category=category)
class QA_PT_SEQUENCE_EDITOR_QUICKADDON(bpy.types.Panel):
...
def draw(self, context):
layout = self.layout
draw(layout, context, category="QuickAddon", with_shared=True)
_BASE_CLASSES = [
QA_SHARED_ROOT,
QA_OT_SETUP_FROM_AUDIO,
QA_OT_RENDER_FROM_AUDIO,
]
_PANEL_CLASSES = [
QA_PT_SEQUENCE_EDITOR_QUICKADDON,
]
# Prevent double-register in nested/plugin scenarios
_IS_REGISTERED = False
_REGISTERED_MODE = None
def register(*, mode="plugin", host_api=None):
...
for c in _BASE_CLASSES:
bpy.utils.register_class(c)
# namespaced shared ptr
setattr(
bpy.types.Scene,
_SHARED_PTR_NAME,
bpy.props.PointerProperty(type=QA_SHARED_ROOT),
)
...
def unregister():
...
if hasattr(bpy.types.Scene, _SHARED_PTR_NAME):
delattr(bpy.types.Scene, _SHARED_PTR_NAME)
for c in reversed(_BASE_CLASSES):
bpy.utils.unregister_class(c)
...
This file represents your Python functions transformed into Blender operators.
It:
- Defines operator classes.
- Defines shared properties.
- Exposes drawing helpers.
- Registers base classes.
It does not decide where shared values are ultimately stored when embedded in a larger system. It describes behavior and inputs.
That distinction becomes important later.
File 2 – __init__.py
Open:
dist/audiodeck/__init__.py
This file is lightweight.
You will see:
- Add-on metadata (
bl_info) - Registration logic
- A host wrapper
- Standalone panel wiring
Example (trimmed):
bl_info = {
"name": "Audiogen",
...
}
from . import generated_ops
class _StandaloneHostAPI:
...
def register():
generated_ops.register(
mode="plugin",
host_api=_StandaloneHostAPI(),
)
def unregister():
generated_ops.unregister()
This file connects the generated add-on to Blender.
It provides:
- Default shared storage
- HostAPI injection
- Add-on entry points
In standalone mode, this wrapper acts as the host.
The Visual Pattern
When you enable the add-on, the layers look like this:
Your Functions
↓ used by
generated_ops.py (behavior + operators)
↓ used by
__init__.py (standalone host wrapper)
↓ used by
Blender UI + Storage
Two files. Two responsibilities.
You wrote one function. QuickAddon generated the layers and wiring around it.
You now recognize the shape of a standalone QuickAddon add-on.
In the next chapter, we will see how this same structure enables embedding inside another host.