Blender add-on extension development
When to Use
Use when adding Blender properties or UI, render settings, scene or USD conversion, interactive edits, render sequences, sensor products, viewport presentation, diagnostics, or tests.
Boundary
Work in the distributed source checkout and use its documented add-on and
runtime interfaces. Start with an add-on implementation and use a minimal
capability probe before reporting a missing runtime capability.
Use paths below relative to the source root. Preserve guarded bpy imports so pure
modules and tests remain importable outside Blender. Keep all worker calls on the
existing serialized session-owner/render thread.
Instructions
Choose the narrowest route before editing:
| Feature |
Start here |
Continue through |
Required tests |
| Blender property or panel |
addon/ovrtx_blender_example/properties.py |
ui.py, engine.py, typed request/composition module |
focused property and panel tests such as tests/test_rtpt_scene_properties.py and tests/test_rtpt_render_panel.py |
| Render setting |
properties.py::RTPT_RENDER_SETTINGS and RtptSettingSpec |
render_requests.py::RenderRequest, ovrtx_scene_composition.py, view_update_stream.py, runtime_scheduler.py |
test_rtpt_scene_properties.py, test_rtpt_render_product_authoring.py, test_rtpt_live_change.py |
| Material graph/OpenPBR |
materialx_openpbr_conversion.py::scene_layer_from_materials |
texture_materialization.py, blender_signal_translation.py::_material_scene_layer_from_scene |
test_materialx_openpbr_conversion.py, test_texture_materialization.py, test_render_requests.py |
| Scene object/topology |
scene_generation.py::SceneGenerationOwner |
_stock_export, _compile_add_on_opinions, topology reconciliation, topology_edit_fallback.py |
test_scene_generation.py, test_scene_generation_contract.py, test_topology_edit_fallback.py |
| Interactive value edit |
blender_signals.py and blender_signal_translation.py |
blender_interactive_edit_builders.py, interactive_edit_planner.py, value_edit_conversion.py, interactive_edit_workflow.py, runtime_scheduler.py |
corresponding test_blender_*, test_interactive_*, test_value_edit_conversion.py |
| Session or sequence |
render_requests.py::RenderRequest |
ovrtx_session.py, ovrtx_session_controller.py, runtime_scheduler.py, engine.py |
test_ovrtx_session.py, test_ovrtx_session_controller.py, test_runtime_scheduler.py, test_final_render_on_rpc_thread.py |
| Sensor/AOV result |
render_requests.py and ovrtx_runtime_client.py |
typed result model, scheduler publication, engine.py presentation |
test_render_requests.py, test_ovrtx_runtime_client.py, scheduler and presentation tests |
| Viewport upload/display |
viewport_handoff.py and viewport_presentation.py |
viewport_render_thread.py, engine.py |
test_viewport_handoff.py, test_viewport_presentation.py, test_viewport_render_thread.py |
| Preflight/diagnostics |
preflight.py or the owning module's diagnostics model |
user_messages.py, ui.py |
test_addon_preflight.py, test_user_messages.py, focused diagnostics test |
For a specialized route, use the matching extend-ovrtx-* skill when present.
Classify ownership before coding
Write down these decisions in the implementation plan:
- Identify the Blender signal and the normalized add-on-owned value.
- Classify it as durable USD topology, durable USD value, same-session runtime
value, session identity, worker-startup configuration, or presentation-only.
- Identify the typed request/result boundary. Do not pass arbitrary
dictionaries across an existing dataclass boundary just to avoid modeling it.
- Decide whether omission means
INHERIT, whether an explicit value means
OVERRIDE, and how reset returns to inherited behavior.
- Identify the observable acceptance result: authored USD, effective setting,
typed product, rendered pixels, or an explicit rejection diagnostic.
Implementation
- Add pure normalized types and conversion policy in a focused module. Reject
unsupported input explicitly; do not silently approximate topology or units.
- Add Blender properties and registration in
properties.py and __init__.py
only when the feature is user-configurable.
- Carry the normalized value through
RenderRequest or the appropriate edit
intent/result type. Include it in identity/digests only when it changes the
composed session.
- Author durable USD through scene generation or composition. Route supported
same-session values through the established edit/update stream. Replace the
generation or session for topology and unsupported live writes.
- Add UI after the typed path works. Display effective state and rejection or
fallback reason, not only the requested value.
- Add unit tests at each boundary and one included fixture/probe that observes
the actual product with the installed runtime when available.
Architectural invariants
- Keep Blender callbacks and UI code free of blocking runtime calls.
- Submit runtime work through
RuntimeScheduler/OvrtxSessionController; do not
instantiate another worker client in a property callback or operator.
- Keep current-scene generation separate from exact-stage validation. Exact-stage
requests must not replace source materials, lights, or topology.
- Preserve
SceneGenerationOwner.replace/accept/reject: a failed candidate
must leave the last accepted generation usable.
- Keep material, lighting, color, and viewport presentation ownership singular.
Do not compensate for a renderer problem by mutating source material values.
- Make cached keys depend on every input that changes output, and test both reuse
and invalidation.
- Return typed results for non-image products; do not force point clouds or AOVs
through an RGBA-only result model.
- Never report success from an accepted API call alone. Check the composed stage,
effective state, product metadata, and visible/numeric output as applicable.
Validation
Run the focused pure-Python tests first, then the complete tests suite.
For Blender-dependent behavior, run the documented included Blender fixture.
For runtime-dependent behavior, use the documented runtime interface and record
versions, request, response, diagnostics, and a caller-selected artifact path.
Test success, inheritance/reset, invalid input, missing optional capability,
cache invalidation, session replacement or reuse, cancellation/shutdown, and
plain-Python import behavior where relevant.
Escalation gate
Report a runtime capability gap only when the smallest documented-interface
probe shows that the typed operation cannot be expressed, is rejected by a
compatible runtime, or cannot return enough metadata to distinguish success
from false success. Missing add-on routing, USD authoring, threading, UI,
conversion, caching, or diagnostics remains add-on work.
Handoff
Return changed paths and symbols, focused and full-suite results, fixture
or visual evidence, compatibility notes, and exactly one boundary decision:
addon-only or runtime-capability-missing with the minimal probe.
1---2name: blender-addon-extension-development3description: Route and implement source changes in the OVRTX Blender add-on. Use when adding Blender properties or UI, render settings, scene or USD conversion, interactive edits, render sequences, sensor products, viewport presentation, diagnostics, or tests.4license: Apache-2.05---6# Blender add-on extension development78## When to Use910Use when adding Blender properties or UI, render settings, scene or USD conversion, interactive edits, render sequences, sensor products, viewport presentation, diagnostics, or tests.1112## Boundary1314Work in the distributed source checkout and use its documented add-on and15runtime interfaces. Start with an add-on implementation and use a minimal16capability probe before reporting a missing runtime capability.1718Use paths below relative to the source root. Preserve guarded `bpy` imports so pure19modules and tests remain importable outside Blender. Keep all worker calls on the20existing serialized session-owner/render thread.2122## Instructions2324Choose the narrowest route before editing:2526| Feature | Start here | Continue through | Required tests |27| --- | --- | --- | --- |28| Blender property or panel | `addon/ovrtx_blender_example/properties.py` | `ui.py`, `engine.py`, typed request/composition module | focused property and panel tests such as `tests/test_rtpt_scene_properties.py` and `tests/test_rtpt_render_panel.py` |29| Render setting | `properties.py::RTPT_RENDER_SETTINGS` and `RtptSettingSpec` | `render_requests.py::RenderRequest`, `ovrtx_scene_composition.py`, `view_update_stream.py`, `runtime_scheduler.py` | `test_rtpt_scene_properties.py`, `test_rtpt_render_product_authoring.py`, `test_rtpt_live_change.py` |30| Material graph/OpenPBR | `materialx_openpbr_conversion.py::scene_layer_from_materials` | `texture_materialization.py`, `blender_signal_translation.py::_material_scene_layer_from_scene` | `test_materialx_openpbr_conversion.py`, `test_texture_materialization.py`, `test_render_requests.py` |31| Scene object/topology | `scene_generation.py::SceneGenerationOwner` | `_stock_export`, `_compile_add_on_opinions`, topology reconciliation, `topology_edit_fallback.py` | `test_scene_generation.py`, `test_scene_generation_contract.py`, `test_topology_edit_fallback.py` |32| Interactive value edit | `blender_signals.py` and `blender_signal_translation.py` | `blender_interactive_edit_builders.py`, `interactive_edit_planner.py`, `value_edit_conversion.py`, `interactive_edit_workflow.py`, `runtime_scheduler.py` | corresponding `test_blender_*`, `test_interactive_*`, `test_value_edit_conversion.py` |33| Session or sequence | `render_requests.py::RenderRequest` | `ovrtx_session.py`, `ovrtx_session_controller.py`, `runtime_scheduler.py`, `engine.py` | `test_ovrtx_session.py`, `test_ovrtx_session_controller.py`, `test_runtime_scheduler.py`, `test_final_render_on_rpc_thread.py` |34| Sensor/AOV result | `render_requests.py` and `ovrtx_runtime_client.py` | typed result model, scheduler publication, `engine.py` presentation | `test_render_requests.py`, `test_ovrtx_runtime_client.py`, scheduler and presentation tests |35| Viewport upload/display | `viewport_handoff.py` and `viewport_presentation.py` | `viewport_render_thread.py`, `engine.py` | `test_viewport_handoff.py`, `test_viewport_presentation.py`, `test_viewport_render_thread.py` |36| Preflight/diagnostics | `preflight.py` or the owning module's diagnostics model | `user_messages.py`, `ui.py` | `test_addon_preflight.py`, `test_user_messages.py`, focused diagnostics test |3738For a specialized route, use the matching `extend-ovrtx-*` skill when present.3940## Classify ownership before coding4142Write down these decisions in the implementation plan:43441. Identify the Blender signal and the normalized add-on-owned value.452. Classify it as durable USD topology, durable USD value, same-session runtime46 value, session identity, worker-startup configuration, or presentation-only.473. Identify the typed request/result boundary. Do not pass arbitrary48 dictionaries across an existing dataclass boundary just to avoid modeling it.494. Decide whether omission means `INHERIT`, whether an explicit value means50 `OVERRIDE`, and how reset returns to inherited behavior.515. Identify the observable acceptance result: authored USD, effective setting,52 typed product, rendered pixels, or an explicit rejection diagnostic.5354## Implementation55561. Add pure normalized types and conversion policy in a focused module. Reject57 unsupported input explicitly; do not silently approximate topology or units.582. Add Blender properties and registration in `properties.py` and `__init__.py`59 only when the feature is user-configurable.603. Carry the normalized value through `RenderRequest` or the appropriate edit61 intent/result type. Include it in identity/digests only when it changes the62 composed session.634. Author durable USD through scene generation or composition. Route supported64 same-session values through the established edit/update stream. Replace the65 generation or session for topology and unsupported live writes.665. Add UI after the typed path works. Display effective state and rejection or67 fallback reason, not only the requested value.686. Add unit tests at each boundary and one included fixture/probe that observes69 the actual product with the installed runtime when available.7071## Architectural invariants7273- Keep Blender callbacks and UI code free of blocking runtime calls.74- Submit runtime work through `RuntimeScheduler`/`OvrtxSessionController`; do not75 instantiate another worker client in a property callback or operator.76- Keep current-scene generation separate from exact-stage validation. Exact-stage77 requests must not replace source materials, lights, or topology.78- Preserve `SceneGenerationOwner.replace`/`accept`/`reject`: a failed candidate79 must leave the last accepted generation usable.80- Keep material, lighting, color, and viewport presentation ownership singular.81 Do not compensate for a renderer problem by mutating source material values.82- Make cached keys depend on every input that changes output, and test both reuse83 and invalidation.84- Return typed results for non-image products; do not force point clouds or AOVs85 through an RGBA-only result model.86- Never report success from an accepted API call alone. Check the composed stage,87 effective state, product metadata, and visible/numeric output as applicable.8889## Validation9091Run the focused pure-Python tests first, then the complete `tests` suite.92For Blender-dependent behavior, run the documented included Blender fixture.93For runtime-dependent behavior, use the documented runtime interface and record94versions, request, response, diagnostics, and a caller-selected artifact path.9596Test success, inheritance/reset, invalid input, missing optional capability,97cache invalidation, session replacement or reuse, cancellation/shutdown, and98plain-Python import behavior where relevant.99100## Escalation gate101102Report a runtime capability gap only when the smallest documented-interface103probe shows that the typed operation cannot be expressed, is rejected by a104compatible runtime, or cannot return enough metadata to distinguish success105from false success. Missing add-on routing, USD authoring, threading, UI,106conversion, caching, or diagnostics remains add-on work.107108## Handoff109110Return changed paths and symbols, focused and full-suite results, fixture111or visual evidence, compatibility notes, and exactly one boundary decision:112`addon-only` or `runtime-capability-missing` with the minimal probe.