Architecture overview¶
BrainDeer is organized in layers under src/brain_deer/. Later layers
depend on earlier ones; nothing reaches up into presentation or plugins from
infrastructure.
The layers¶
app / presentation / plugins
│
▼
application (API, events, ports, commands)
│
▼
domain · warp · surface
│
▼
infrastructure (io, bids)
│
▼
rendering (VTK) · plugin_api / sdk
Layer |
Package |
Responsibility |
|---|---|---|
App |
|
Entry point ( |
Application |
|
Services, event bus, ports, |
Domain |
|
Domain models and logic |
Domain modules |
|
Warp engine; surfaces, tracts, projection |
Infrastructure |
|
NIfTI / volume proxy, BIDS mapping |
Presentation |
|
Qt UI ( |
Rendering |
|
VTK 3D scene, surface LOD, scene rig, tracts |
Plugins |
|
Extension host and stable author API |
Commands |
|
Named actions shared by UI, plugins, and scripts |
Design rationale¶
These principles shaped the 2.0 restructure and should be preserved:
Host + plugins, not a monolith. Domain and I/O stay callable without the full Qt shell where practical. Plugins talk to the running app through
plugin_api.v1/ the app facade — not by reaching into private widget internals.No caller-name coupling. Behavior comes from explicit parameters and injected dependencies (the facade, event bus, command registry), never from who called a function.
Commands are the shared action surface. UI buttons, plugin widgets, and scripting should trigger the same command definitions under
commands/whenever the action is user-facing.Events decouple producers from consumers. Load finished, subject changed, interaction capture — subscribe on the bus instead of hard-wiring panel A to panel B.
Wrap mature tools. Nibabel, VTK, PyQt, and friends stay behind thin adapters (
infrastructure.io,rendering/); we do not reimplement numerics.
Core mechanisms¶
Event bus¶
application/events/bus.py provides a lightweight pub/sub with priorities.
Plugins register handlers via PluginBase.register_event_handler; the host and
core emit through the same bus so UI and plugins stay loosely coupled.
Command registry¶
Actions under commands/ are registered once and can be invoked from the
command palette, plugins, or scripts. Prefer adding a command over inventing a
one-off callback chain between widgets.
Plugin host¶
plugins_host/plugin_manager.py discovers plugins/<id>/plugin.py, restricted
to _BUNDLED_PLUGIN_ALLOWLIST. Convention: plugin.py (lifecycle + logic) and
widget.py (Qt tab). See Plugin development.
App facade¶
plugin_api.v1.BrainDeerAppFacade (and the concrete brain_deer_api) is what
plugins should use for viewer access, interaction capture, and high-level
operations — the stable door into the host.
Data flow (load → view → render)¶
Presentation Application API infrastructure.io
│ │ │
│ open volume/BIDS │ │
│─────────────────────►│ load NIfTI / proxy │
│ │───────────────────────►│
│ │◄───────────────────────│ image + affine
│ │ │
│ │ register layer ──► Viewer / layers
│ │ │
│◄──────── paint ──────┼──────── VTK planes/actors◄┘
See also¶
Subsystems in detail — warp, rendering, I/O & BIDS in detail
Plugin development — writing an extension
API map by layer — curated API map into AutoAPI