feather-tk
A lightweight toolkit for building professional tools for film, VFX, and animation, in C++ or Python.
feather-tk is purpose-built for media production software, with features like high-bit-depth color and multi-monitor HiDPI support. It powers DJV, a production-proven image sequence viewer used in professional VFX and animation workflows.
pip install feather-tk
Try it in your browser -- the examples run in WebAssembly.
Why feather-tk?
Lightweight and self-contained. feather-tk has a small, well-defined set of dependencies, and includes a CMake superbuild for building the dependencies.
C++ and Python. The Python bindings follow the C++ API closely, so the documentation and examples of one read for the other, and they install with pip on Linux, macOS, and Windows.
Modern C++ at the core. Clean ownership model using std::shared_ptr, a reactive
observable system for UI state, and a consistent event-driven architecture that makes
writing custom widgets straightforward.
BSD-3-Clause licensed. Use it freely in commercial production tools.
Used in production
| Project | Description |
|---|---|
| DJV | Open source image sequence player for high-resolution film, VFX and animation workflows |
| tlRender | Library for building playback and review applications for VFX, film, and animation |
| toucan | Software renderer for OpenTimelineIO timelines |
Features
- Widget toolkit — full set of UI widgets including layouts, buttons, sliders, numeric editors, menus, toolbars, file browsers, dialogs, tab bars, scroll areas, and a MDI canvas.
- Observable state — reactive value, list, and map observables with automatic lifetime management; widgets subscribe and unsubscribe cleanly without manual bookkeeping.
- Action system — commands with text, icon, keyboard shortcut, checked state, and
enabled state; a single
Actiondrives menus, toolbars, and keyboard handling together. - Style and theming — dark, light, and custom color styles; all sizes and colors are role-based so themes apply globally without touching widget code.
- Settings persistence — JSON-backed settings with typed get/set and automatic save on exit.
- Widgets from JSON — layouts loaded from data, with behavior attached in code by id; a live preview example reloads a layout as the file is edited.
- OpenGL rendering — OpenGL 4.1 and OpenGL ES 3 backends.
- HiDPI — display scale awareness throughout; all size roles scale correctly on high-density displays and multi-monitor setups.
- Python bindings — the C++ API from Python, installed with
pip install feather-tk(a work in progress; the OpenGL layer is not wrapped). - Testable by design — applications run headless, write screenshots, and drive their own UI from scripts; the same machinery tests feather-tk itself.
- Cross-platform — works on Linux, macOS, and Windows, and runs in the browser with Emscripten.
Scope
feather-tk is a toolkit for media applications -- players, viewers, review tools -- not a general application framework. Some things are deliberately out of scope, and knowing them up front saves an evaluation:
- The menu bar is drawn in the window on every platform; there is no native macOS menu bar.
- The file browser is feather-tk's own, for consistency across platforms; native file dialogs are available through the optional NFD dependency.
- There is no accessibility tree for screen readers.
- Text is aimed at production UI -- file names, timecode, labels. Complex scripts and input methods are untested.
What that buys: a stack small enough to read in a sitting, the same pixels on every platform, and rendering the application controls end to end.
Quick start
C++
A window with a text label:
#include <ftk/UI/App.h>
#include <ftk/UI/Label.h>
#include <ftk/UI/MainWindow.h>
#include <ftk/UI/RowLayout.h>
#include <ftk/UI/Spacer.h>
using namespace ftk;
int main(int argc, char** argv)
{
try
{
// Create the context and application.
auto context = Context::create();
auto app = App::create(context, argc, argv, "simple", "Simple example.");
if (app->hasCmdLineHelp())
return 0;
// Create a window.
auto window = MainWindow::create(context, app, Size2I(1280, 960));
// Create a label, centered in the window: the layout centers it
// across, and the spacers center it along.
auto layout = VerticalLayout::create(context);
auto spacer = Spacer::create(context, Orientation::Vertical, layout);
spacer->setStretch(Stretch::Expanding);
auto label = Label::create(context, "Hello world", layout);
label->setFontSize(64);
label->setHAlign(HAlign::Center);
spacer = Spacer::create(context, Orientation::Vertical, layout);
spacer->setStretch(Stretch::Expanding);
window->setWidget(layout);
// Run the application.
app->run();
}
catch (const std::exception& e)
{
std::cout << "ERROR: " << e.what() << std::endl;
return 1;
}
return 0;
}
Python
A window with a text label, after pip install feather-tk:
import feather_tk as ftk
import sys
# Create the context and application.
context = ftk.Context()
app = ftk.App(context, sys.argv, "simple", "Simple example")
if app.hasCmdLineHelp:
sys.exit(0)
# Create a window.
window = ftk.MainWindow(context, app, ftk.Size2I(1280, 960))
# Create a label, centered in the window: the layout centers it across,
# and the spacers center it along.
layout = ftk.VerticalLayout(context)
spacer = ftk.Spacer(context, ftk.Orientation.Vertical, layout)
spacer.setStretch(ftk.Stretch.Expanding)
label = ftk.Label(context, "Hello world", layout)
label.fontSize = 64
label.hAlign = ftk.HAlign.Center
spacer = ftk.Spacer(context, ftk.Orientation.Vertical, layout)
spacer.setStretch(ftk.Stretch.Expanding)
window.widget = layout
# Run the application.
app.run()
# Clean up.
window = None
app = None
Widgets from JSON
A widget tree can be created from data: the structure and the properties live in the JSON, and behavior stays in code.
{
"type": "VerticalLayout",
"marginRole": "Margin",
"children": [
{ "type": "Label", "text": "Hello from JSON" },
{ "type": "FormLayout", "rows": [
{ "label": "Size:", "widget": {
"type": "IntEditSlider", "id": "size",
"range": [ 1, 100 ], "value": 25 } }
] },
{ "type": "PushButton", "id": "apply", "text": "Apply" }
]
}
Widgets are given an "id" and found in code to attach callbacks, the way markup
and script divide a web page:
auto result = ftk::widgetLoad(context, json);
auto button = ftk::findWidget(result.widget, "apply");
widget, errors = ftk.widgetLoad(context, jsonString)
ftk.findWidget(widget, "apply").setClickedCallback(callback)
The preview example renders a layout file and reloads it as
the file is edited in any editor, with problems shown in the window; the
ftk_embed_text() CMake function embeds the same file in the binary for
shipping. Applications register their own widget types with
ftk::widgetLoadRegister().
Examples
Image viewer with menus, toolbars, and persistent settings:
3D object viewer with offscreen rendering and heads-up display:
Text editor with multiple documents:
Gallery of the widgets, layouts, and dialogs -- run it in your browser:
The examples in the examples/ directory:
| Example | Demonstrates |
|---|---|
| simple | The minimal application: a window and a label |
| widgets | Gallery of the widgets, layouts, dialogs, and drag and drop; -tab <name> -screenshot <file> captures any page |
| textedit | Application architecture: documents, actions shared between the menus and tool bars, and persistent settings |
| imageview | A custom image display widget |
| objview | Custom OpenGL rendering inside a widget |
| panel | A tool panel loaded from JSON with the behavior wired up by id |
| preview | Live preview of a widget layout from JSON, reloading as the file is edited |
| gfx | Procedural drawing |
| windows | Multiple windows |
| python | Python counterparts: per-topic scripts, textedit.py mirroring the C++ textedit for a side by side reading, and testing.py, an application that drives and checks itself |
The Python examples mirror the C++ topics. The objview example has no Python counterpart because the OpenGL layer is deliberately not wrapped; the largest Python application built on feather-tk is the DJV Python example.
Architecture overview
feather-tk is organised into three layers:
Core — context and system management, observable values, math and geometry types, image I/O, font rendering, string utilities, file I/O, LRU cache, command/undo stack.
GL — OpenGL abstraction layer: shaders, textures, meshes, offscreen buffers, and a render interface used by the UI layer.
UI — the widget toolkit: the IWidget base class and event system, all built-in
widgets, the style system, action system, settings, and the application event loop.
The observable pattern runs throughout. UI state — numeric model values, action checked
state, style changes, window focus — is all expressed as Observable<T> values that
widgets subscribe to. Observers unregister automatically on destruction, so there are
no manual disconnect calls and no dangling callbacks.
Widget callbacks are single-slot: setting a callback replaces the previous one. When more than one party cares about a change, the state belongs in an observable — any number of observers can subscribe — and the callback's job is only to write the change into it.
Python
The Python bindings are on PyPI, as one wheel per platform for CPython 3.12 and later:
pip install feather-tk
import feather_tk as ftk
The wheel also carries the C++ libraries, headers, and CMake package the module is built on, so a project with its own bindings can build against the same installation:
cmake -DCMAKE_PREFIX_PATH=$(python -c "import feather_tk; print(feather_tk.get_cmake_dir())") ...
To build a wheel from source, with the dependencies built along the way:
pip wheel ./feather-tk
Building
Building from source is for the C++ libraries, or for Python on a platform without a wheel; see Python for the package.
Dependencies
Required:
Optional:
- Native File Dialog Extended — for native file dialogs
- nanobind — for Python bindings
A CMake superbuild script builds all dependencies from source automatically.
Linux
Requirements:
- Git
- CMake 3.31
Install system packages (Debian/Ubuntu):
sudo apt-get install build-essential git cmake xorg-dev libglu1-mesa-dev mesa-common-dev mesa-utils libwayland-dev wayland-protocols libxkbcommon-dev libegl1-mesa-dev libdecor-0-dev
Install system packages (Rocky 8 and 9):
sudo dnf install git libX11-devel libXrandr-devel libXinerama-devel libXcursor-devel libXi-devel mesa-libGL-devel wayland-devel wayland-protocols-devel libxkbcommon-devel mesa-libEGL-devel
Rocky 9 also has libdecor-devel, for window decorations on GNOME's Wayland. The Wayland packages are optional; without them SDL is built with X11 only and runs through XWayland on a Wayland desktop.
Rocky 8 additionally requires a newer compiler:
sudo dnf install gcc-toolset-13
scl enable gcc-toolset-13 bash
Clone and build:
git clone https://github.com/grizzlypeak3d/feather-tk.git
sh feather-tk/sbuild-linux.sh
macOS
Requirements:
- Git
- Xcode
- CMake 3.31
git clone https://github.com/grizzlypeak3d/feather-tk.git
sh feather-tk/sbuild-macos.sh
Notes for switching between architectures:
alias arm="env /usr/bin/arch -arm64 /bin/zsh --login"
alias intel="env /usr/bin/arch -x86_64 /bin/zsh --login"
Windows
Requirements:
- Git (https://git-scm.com)
- Visual Studio 2022
- CMake 3.31
Open "x64 Native Tools Command Prompt for VS 2022" from the Start menu, then:
git clone https://github.com/grizzlypeak3d/feather-tk.git
feather-tk\sbuild-win.bat
Verify the build
Run the object viewer example:
# Linux / macOS
build-Release/examples/objview/objview feather-tk/etc/Objects/Bolt.obj
# Windows
build-Release\examples\objview\Release\objview feather-tk\etc\Objects\Bolt.obj
Metadata
Release files for feather-tk 0.16.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| feather_tk-0.16.1.tar.gz | 17.3 MB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| feather_tk-0.16.1-cp312-abi3-win_amd64.whl | CPython 3.12 | abi3 | Windows x86-64 | Details |
| feather_tk-0.16.1-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl | CPython 3.12 | abi3 | Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 | Details |
| feather_tk-0.16.1-cp312-abi3-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl | CPython 3.12 | abi3 | Linux glibc 2.28+ ARM64, Linux glibc 2.27+ ARM64 | Details |
| feather_tk-0.16.1-cp312-abi3-macosx_11_0_arm64.whl | CPython 3.12 | abi3 | macOS 11.0+ ARM64 | Details |
| feather_tk-0.16.1-cp312-abi3-macosx_10_15_x86_64.whl | CPython 3.12 | abi3 | macOS 10.15+ x86-64 | Details |
Total release size: 203.2 MB
Release files / feather_tk-0.16.1.tar.gz
| Download URL | feather_tk-0.16.1.tar.gz |
|---|---|
| Size | 17.3 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
78d9a73f89c40f0d258811fd04b2ccbd877ffd33793e7dfe7c31ea6355e9c257
|
|
BLAKE2b-256 checksum How to use checksums |
5ed07f2a72e03ec8458fcf5cb5178207131f7e907726e6f390413e91fa5a3534
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency logRelease files / feather_tk-0.16.1-cp312-abi3-win_amd64.whl
| Download URL | feather_tk-0.16.1-cp312-abi3-win_amd64.whl |
|---|---|
| Size | 36.2 MB |
| Tags | CPython 3.12 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
c17b20b9fca70715c14815ec6abf630c38712b35d5b83ef5816362381cb1a788
|
|
BLAKE2b-256 checksum How to use checksums |
69c0e3c5d7b54dd849e3f052920bc0cf4cab2eda4d64a43103626f492b1633c1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency logRelease files / feather_tk-0.16.1-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | feather_tk-0.16.1-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 39.1 MB |
| Tags | CPython 3.12 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
130e03baa4289ca02fe186b367b5887d08dc82adfd0e0d7ddaa92bb6946f9567
|
|
BLAKE2b-256 checksum How to use checksums |
f597786c966cca1ccc0a2d8b84ad63eddd21a48464468dfaa67294f51ea5bae1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency logRelease files / feather_tk-0.16.1-cp312-abi3-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
| Download URL | feather_tk-0.16.1-cp312-abi3-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 38.4 MB |
| Tags | CPython 3.12 Linux glibc 2.27+ ARM64 Linux glibc 2.28+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
06f21ec6abbd2c3e92bf83217740f6c46d939d1c8c07f6fc01c31d6e83cb9e29
|
|
BLAKE2b-256 checksum How to use checksums |
123d83ac3c37d682cb63f56dca5c82b50c2200d54726a547d07a80b7336d67c6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency logRelease files / feather_tk-0.16.1-cp312-abi3-macosx_11_0_arm64.whl
| Download URL | feather_tk-0.16.1-cp312-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 35.8 MB |
| Tags | CPython 3.12 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
3ba912f6315790ab33ce68924c52598f0571a73087fcbe45a5c0f7d889f0a6c9
|
|
BLAKE2b-256 checksum How to use checksums |
2d5e44e47a94b725eb0b1fed9350187095d8eb5386aedbffa75b2722bdd433f9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency logRelease files / feather_tk-0.16.1-cp312-abi3-macosx_10_15_x86_64.whl
| Download URL | feather_tk-0.16.1-cp312-abi3-macosx_10_15_x86_64.whl |
|---|---|
| Size | 36.4 MB |
| Tags | CPython 3.12 abi3 macOS 10.15+ x86-64 |
|
SHA-256 checksum How to use checksums |
e8c37798057c4add2d160d592a7a2adbd850267eec91321b8f8e1e00b658f470
|
|
BLAKE2b-256 checksum How to use checksums |
186811514d1cbf150bfb75cc846e3ee067cb9d2370578876c0c043cd0429278b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency log