FrameLift Plugin SDK
FrameLift is a video player whose features are not baked into the executable.
Each feature — the playlist, the history panel, the on-screen overlay, the
settings menu — ships as a plugin: a standalone Qt plugin DLL/SO the host loads
at runtime from its plugins/ directory. This SDK is the public surface external
authors use to write their own.
Plugins, modules, and features
The model uses three terms precisely (see Architecture for the full model):
- A plugin is the Qt plugin DLL/SO you build and ship. It is declared by a
single
.Plugin.json, has one id, and returns oneIModulefrom itsIPluginfactory. The artifact name is the lowercase plugin id (e.g.framelift.playlist.so). - A module is a built-in host component compiled into the host (playback,
audio, graphics, the window), declared by a
.Module.json. Modules are the capabilities a plugin builds on, not something you ship. - A feature is a named capability string (e.g.
media.playback.ffmpeg) that a plugin or module provides or requires. Features are how dependencies resolve.
Why a plugin SDK
The host ↔ plugin boundary is a COM-like binary ABI: pure abstract
interfaces, POD-only method signatures, and extern "C" entry points. A plugin
built with any compatible compiler interoperates with the host regardless of how
the host itself was built. Concretely, that buys you:
- A dependency-free build. A plugin needs only a C++23 compiler, CMake, and Qt. You do not link any third-party UI, logging, image, or JSON library — none of those types cross the boundary.
- Toolchain independence. No standard-library types are shared across the DLL edge, so there is no requirement to match the host's compiler or its standard-library build flags.
- A versioned contract. Every plugin compiles in the single-integer
FRAMELIFT_ABI_VERSIONit was built against. The host checks it before touching a vtable and loads the plugin only on an exact match, so an out-of-date binary fails loudly instead of corrupting memory. See ABI Compatibility.
What a plugin can do
Through the module context a plugin can:
- Run one-time setup when it is installed, and tear down cleanly on shutdown.
- Read and write settings, and contribute its own page to the settings menu.
- Register keybinds that show up in the shared keybind UI.
- Render its own UI as embedded Qt Quick (QML), driven by a
QObjectview-model (optional). - React to media events from the player — file loaded, seek completed, property changes such as the current title.
- Talk to other plugins through typed services (
IHistory, …) and a publish/subscribe event bus.
How the pieces fit
┌─────────────────────────────────────────────┐
│ framelift (host) │
│ │
│ loads plugins/*.{so,dll} ◄ ABI compat gate │
│ instantiates one IModule per enabled plugin│
│ passes IModuleContext& into each module │
└───────────────┬──────────────────────────────┘
│ pure abstract interfaces, POD signatures
▼
┌─────────────────────────────────────────────┐
│ YourModule : public ModuleBase │
│ │
│ OnInstall(ctx) ── wire up services │
│ HandleMediaEvent() ── react to the player │
│ Q_PROPERTY/QML ── draw UI (optional) │
└─────────────────────────────────────────────┘
Where to go next
- Installation — get the SDK and verify your toolchain with an example.
- Your First Plugin — write, build, and load a minimal plugin from scratch.
- Guides — settings, keybinds, UI, media events, and cross-plugin communication, one topic at a time.
- Reference — the full SDK API surface.