Portable Python toolkit for building professional desktop applications with Dear ImGui.
Application chrome, canvas infrastructure, timeline editors, overlay systems, node graphs, live devtools, and 50+ composable modules -- extracted from production use in Discore, a generative art engine.
ABC-driven contracts. Inherit, implement, ship. Type-checked at commit time.
vibekit is designed around abstract base classes -- explicit contracts that host applications inherit and implement. The type checker enforces completeness at commit time, not at runtime. No global singletons, no implicit duck-typing.
Host Application
|
inherits ABCs
|
+-----------------+-----------------+
| | |
AppContext GizmoStore LayoutStore ThemePrefs
| | | |
v v v v
+-------+---------+ GizmoManager LayoutManager apply_holoq_theme()
| | | |
| BaseWindow | | |
| Drawer | GizmoContext LayoutPreset
| Panel | | |
| KeybindManager | Gizmo ABC dock_builder
| CommandPalette | splits & INI
| Notifications |
+-----------------+
Canvas Layer Timeline Layer Node Graph Layer
+--------------+ +---------------+ +----------------+
| Controller | | temporal.py | | node_graph.py |
| CanvasView | | lanes.py | | node_editor.py |
| checker GPU | | lanes_widget | | type colors |
+--------------+ | plotview.py | | pin wiring |
+---------------+ +----------------+
The AppContext ABC is the single bridge between vibekit and any host app:
class AppContext(ABC):
font_bold: Any # imgui font handle
windows: list[Any] # all BaseWindow instances
dockspace_id: int # root ImGui dockspace node
keybinds: Any # KeybindManager instance
@abstractmethod
def open_window(self, wnd: Any) -> None: ...Storage ABCs (GizmoStore, LayoutStore) are injected into individual
managers at construction time -- never imported globally. ThemePrefs remains
a Protocol (data-shape contract compatible with msgspec Structs).
The windowing and workspace management layer. Docking, layout presets, panels, drawers, menus, dialogs, and status bars.
| Module | Description | LOC |
|---|---|---|
| app.py | AppContext + GizmoStore ABCs -- the single interface between vibekit and host apps |
~40 |
| base_window.py | Abstract window with open/close lifecycle, focus tracking, dock header buttons, popup support | ~330 |
| layout.py | LayoutManager -- Blender-style workspace presets, programmatic dock_builder splits, INI save/restore, status bar |
~600 |
| drawer.py | User-configurable panel container window with responsive 2-column layout and config popup | ~130 |
| panel.py | Panel ABC with auto-registration via __init_subclass__, category tagging, card/standalone render paths |
~70 |
| menu.py | MenuItem dataclass + MenuManager for hierarchical menu trees with shortcuts, dynamic items, caching |
~400 |
| menubar.py | Three-zone flex menubar (LEFT | CENTER | RIGHT) with one-frame-delayed centering | ~150 |
| dialog.py | DialogWindow -- OK, Yes/No, OK/Cancel, Input dialogs as popup windows |
~100 |
| status_bar.py | Bottom-pinned status bar scaffold with right-aligned segment renderer | ~100 |
| splash.py | Minimal GLFW splash screen shown before heavy imports (zero imgui dependency) | ~100 |
Pan/zoom canvas, screen-image coordinate mapping, gizmo overlay system, and dockspace empty-region drawing.
| Module | Description | LOC |
|---|---|---|
| canvas_controller.py | Reusable pan/zoom state machine: scroll-zoom, RMB pan with threshold, double-click reset, window-overlap gating | ~250 |
| canvas_view.py | CanvasView -- per-frame geometry snapshot for screen-to-image coordinate conversions and viewport queries |
~80 |
| canvas_checker.py | GPU procedural checker pattern for transparent canvas backgrounds | ~40 |
| gizmo.py | GizmoManager + Gizmo ABC + GizmoContext -- modular DrawList overlays with anchor-based stacking, visibility persistence, config popup |
~530 |
| dock_overlay.py | Find empty dockspace leaf nodes and draw centered buttons/labels (e.g., "New Scene" in empty regions) | ~170 |
Visual node editor built on imgui-node-editor (thedmd). Pure data model + interactive widget.
| Module | Description | LOC |
|---|---|---|
| node_graph.py | NodeGraphModel + NodeRenderDelegate ABCs, GraphNode, GraphEdge, PinDef, NodeTypeDef -- pure data, no imgui |
~200 |
| node_editor.py | NodeEditorWidget -- interactive node graph with pin wiring, bezier links, type-colored connections, flow animation |
~500 |
Three-layer architecture for DAW-style timeline editors: pure data, layout model, interactive widget.
| Module | Description | LOC |
|---|---|---|
| temporal.py | TimeSpan, SpanItem, PointItem, Curve -- pure temporal data structures (no imgui, no numpy rendering) |
~200 |
| lanes.py | Lane, LaneStack, LaneKind -- layout model for horizontal lane-based editors |
~150 |
| lanes_widget.py | LanesWidget -- interactive timeline with DrawList rendering, clip drag/resize, playhead, keyframe editing |
~800 |
| plotview.py | ViewRect, TimeAxis, TimeUnit, PlotMouse -- 2D plot view state and time coordinate conversions |
~200 |
| signals.py | SignalEntry, SignalCache, WaveformLOD -- 1D signal display with smoothing and level-of-detail (pure numpy) |
~200 |
Reusable UI building blocks: card grids, sortable tables, progress steppers, tooltips, toggles, sidebars, splitters, color utilities.
| Module | Description | LOC |
|---|---|---|
| widgets.py | Card grids (table-based + masonry), sidebars, tab strips, toggles, section headers, child cards | ~600 |
| tables.py | Generic sortable table system with ColumnEntry definitions, nested attribute access, color gradients, selectable rows |
~200 |
| progress.py | StepInfo + progress_stepper() -- horizontal multi-step progress indicators with icons |
~100 |
| tooltip.py | set_tooltip() and help_marker() -- lightweight tooltip wrappers |
~15 |
| splitter.py | vertical_splitter() -- draggable resize bar between two side-by-side regions |
~60 |
| colors.py | price_gradient_color(), lerp_color() -- color gradient calculations for data visualization |
~60 |
| color_utils.py | rgb(), u32() -- convert ImVec4 theme colors to RGB tuples and packed U32 for DrawList calls |
~30 |
| pref_editor.py | Table-based preferences form primitives: row_float, row_checkbox, row_color, row_combo with reset buttons |
~200 |
Generic editors and viewers for runtime data structures.
| Module | Description | LOC |
|---|---|---|
| data_editor.py | Recursive data structure editor: gui_any() renders dataclasses, dicts, lists, tuples, sets with inline editing |
~360 |
| tensor_view.py | Tensor visualization: converts numpy/torch tensors to RGB images with modality-aware display in implot | ~300 |
Accent-driven theming system with dark/light modes, brightness control, and auto time-of-day switching.
| Module | Description | LOC |
|---|---|---|
| theme.py | apply_holoq_theme() + apply_holoq_implot_theme() -- full palette generation from accent colors via ThemePrefs |
~600 |
Keybindings, command palette, and command execution infrastructure.
| Module | Description | LOC |
|---|---|---|
| keybinds.py | KeybindManager -- register hotkeys with vim-style chord strings (c-s, c-a-x), per-frame dispatch, condition guards |
~370 |
| command_palette.py | CommandPalette -- Ctrl+P style fuzzy-search command launcher |
~180 |
| commands.py | CommandManager -- decorator-based command registration with auto-coercion, pattern matching, async execution |
~340 |
| command_session.py | CommandSession -- command queuing, history, output channels for REPL-style interfaces |
~200 |
| Module | Description | LOC |
|---|---|---|
| notifications.py | NotificationManager -- auto-dismissing toast notifications with fade-out animation and progress bars |
~310 |
Live runtime inspection, widget introspection, hot-reload, file watching, and dev restart loops.
| Module | Description | LOC |
|---|---|---|
| devtools/ | MCP-based live inspection server -- register objects, eval code, capture screenshots from Claude Code or any LLM agent | ~800 |
| introspect.py | Widget introspection engine -- Ctrl+Shift+Click any widget to copy its source location to clipboard (3-layer tracking) | ~650 |
| hot_reload.py | GuiHotReloader -- three-strategy live code reloading: PATCH (method swap), RECONSTRUCT (stateful), REBUILD (nuclear) |
~600 |
| file_watcher.py | FileWatcher -- mtime-based .py change detection for hot-reload and playground consumers |
~60 |
| dev_restart.py | run_dev_restart_loop() -- parent-process restart loop for crash recovery during development |
~80 |
| devtools_bridge.py | Bridge between app and devtools: register namespaces, set screenshot callbacks, wire main-thread invoker | ~50 |
| devtools_gl.py | OpenGL screenshot capture (glReadPixels to PNG bytes) for devtools screenshot tool | ~50 |
| Module | Description | LOC |
|---|---|---|
| glfw_renderer.py | Extended GLFW renderer with procedural checker-pattern GPU shader for canvas backgrounds | ~200 |
| texture_pool.py | TexturePool -- rent/release pattern for OpenGL texture IDs to avoid per-frame allocation |
~60 |
| async_thread.py | Background asyncio event loop for non-blocking I/O in immediate-mode GUI apps | ~80 |
| Module | Description | LOC |
|---|---|---|
| interfaces.py | IGUI and IPlottable -- minimal ABCs for renderable components |
~20 |
| file_browser.py | FileBrowser ABC + LocalFileBrowser + SSHFileBrowser -- sortable file manager with breadcrumbs, multi-select, context menus |
~960 |
from imgui_bundle import imgui, hello_imgui
from imgui_vibekit.app import AppContext
from imgui_vibekit.base_window import BaseWindow
from imgui_vibekit.keybinds import KeybindManager
from imgui_vibekit.layout import LayoutManager, LayoutStore, LayoutPreset
from imgui_vibekit.notifications import NotificationManager
from imgui_vibekit import theme
# 1. Define your windows
class InspectorWindow(BaseWindow):
def gui_inside(self):
imgui.text('Hello from vibekit!')
# 2. Subclass AppContext
class MyApp(AppContext):
def __init__(self):
self.font_bold = None # Set after font loading
self.keybinds = KeybindManager()
self.dockspace_id = 0
self.inspector = InspectorWindow(self, 'Inspector')
self.windows = [self.inspector]
self.notifications = NotificationManager()
def open_window(self, wnd): # required by AppContext
if wnd not in self.windows:
self.windows.append(wnd)
wnd.open()
def gui(self):
# Process keybinds
self.keybinds.gui()
# Render windows
for wnd in self.windows:
wnd.gui()
# Render notifications
self.notifications.gui()Connect Claude Code to your running app for live inspection:
from imgui_vibekit import devtools
devtools.register('app', my_app)
devtools.register('storage', my_storage)
devtools.start(port=9229)Then from Claude Code, the MCP tools run(), inspect(), screenshot() etc.
operate on your live application state.
vibekit never imports your app's modules. You subclass its ABCs:
class MyApp(AppContext):
def __init__(self):
self.font_bold = None
self.windows = []
self.dockspace_id = 0
self.keybinds = KeybindManager()
def open_window(self, wnd): ... # @abstractmethod — must implement
class MyGizmoStore(GizmoStore):
def write(self): ... # @abstractmethod — must implement
# Inject into managers at construction time
layout_mgr = LayoutManager(app=my_app, store=my_layout_store)
gizmo_mgr = GizmoManager(store=my_gizmo_store)The type checker (ty check) enforces that all abstract methods are implemented
at commit time — missing one is a build error, not a runtime surprise.
Panels and Gizmos register themselves when their class is defined:
class RemotePanel(Panel):
panel_id = 'remote'
panel_label = 'Remote'
panel_icon = fa.ICON_FA_SERVER
panel_category = 'manage'
def gui_content(self):
imgui.text('Connected')
# Now available everywhere:
Panel.get_registry() # {'remote': RemotePanel, ...}Same pattern for Gizmos -- define the class, it appears in the gizmo manager's toggle list and config popup automatically.
Any BaseWindow can render buttons in the dock tab bar:
class MyWindow(BaseWindow):
def gui_inside(self):
# Gear icon in the dock tab, right of the close button
if self.gui_dock_header_button(fa.ICON_FA_GEAR, slot=0):
imgui.open_popup('##settings')
# Second button, stacks to the left
if self.gui_dock_header_button(fa.ICON_FA_EYE, slot=1):
self.toggle_overlays()Gizmos and timeline widgets use the invisible_button + DrawList pattern for custom rendering with full imgui interaction:
class FrameCounter(Gizmo):
gizmo_id = 'frame_counter'
gizmo_label = 'Frame Counter'
gizmo_anchor = GizmoAnchor.TOP_LEFT
def draw(self, ctx: GizmoContext):
frame = ctx.document.current_frame
ctx.emit_text(f'F:{frame}', ctx.left, ctx.top, color=(255, 255, 255))
def measure(self, ctx: GizmoContext) -> GizmoSize:
return GizmoSize(width=80, height=ctx.line_h)# From source (editable, recommended for development)
pip install -e /path/to/imgui-vibekit
# With MCP devtools CLI
pip install -e "/path/to/imgui-vibekit[cli]"Dependencies:
imgui-bundle-- Dear ImGui + imgui-node-editor + implot Python bindingsnumpy-- array operations for signals, tensors, temporal datapyperclip-- clipboard access for widget introspection
Optional extras:
pip install imgui-vibekit[cli]-- MCP devtools bridge (python-devtoolscommand)pip install imgui-vibekit[gl]-- OpenGL + GLFW (splash screen, screenshot capture)pip install imgui-vibekit[vision]-- OpenCV + Pillow (tensor visualization)pip install imgui-vibekit[all]-- everything above + scipy, rich
51 modules -- ~17,000 lines -- ABC-driven -- type-checked contracts
Built by holo-q