Skip to main content

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 one IModule from its IPlugin factory. 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_VERSION it 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 QObject view-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.