Hello ImGui and ImmApp are the two main ways to create applications with ImGui Bundle.
Hello ImGui is a cross-platform framework that handles window creation, backend initialization, assets, theming, and more.
ImmApp (Immediate App) is a thin wrapper around Hello ImGui that simplifies the initialization of add-ons (ImPlot, Markdown, Node Editor, etc.).
These runners enable you to create powerful ImGui applications with minimal boilerplate code.
Hello ImGui¶
Quick Start¶
from imgui_bundle import hello_imgui, imgui
def gui():
imgui.text("Hello, world!")
hello_imgui.run(gui, window_title="My App", window_size=(800, 600))#include "hello_imgui/hello_imgui.h"
#include "imgui.h"
void gui() {
ImGui::Text("Hello, world!");
}
int main() {
HelloImGui::Run(gui, "My App", {800, 600});
return 0;
}Documentation¶
Hello ImGui Documentation - Full documentation
RunnerParams Reference - All configuration options
API Reference - Full API documentation
Configuration with RunnerParams¶
For full control, configure your application via RunnerParams:
from imgui_bundle import hello_imgui, imgui
def gui():
imgui.text("Hello!")
# Create and configure runner params
params = hello_imgui.RunnerParams()
params.app_window_params.window_title = "My Application"
params.app_window_params.window_geometry.size = (1200, 800)
params.app_window_params.restore_previous_geometry = True
# ImGui window settings
params.imgui_window_params.show_menu_bar = True
params.imgui_window_params.show_status_bar = True
# Set the GUI callback
params.callbacks.show_gui = gui
# Run
hello_imgui.run(params)#include "hello_imgui/hello_imgui.h"
#include "imgui.h"
void gui() {
ImGui::Text("Hello!");
}
int main() {
HelloImGui::RunnerParams params;
params.appWindowParams.windowTitle = "My Application";
params.appWindowParams.windowGeometry.size = {1200, 800};
params.appWindowParams.restorePreviousGeometry = true;
params.imGuiWindowParams.showMenuBar = true;
params.imGuiWindowParams.showStatusBar = true;
params.callbacks.ShowGui = gui;
HelloImGui::Run(params);
return 0;
}See RunnerParams Reference for all configuration options. For Python, see RunnerParams Type Hints
Callbacks¶
Hello ImGui provides several callback hooks:
| Callback | When Called |
|---|---|
show_gui | Every frame (main GUI) |
show_menus | Every frame (menu bar content) |
show_status | Every frame (status bar) |
post_init | Once, after OpenGL initialization |
before_exit | Once, before shutdown |
See Full Callback Reference for details. For Python, see Callbacks Type Hints.
Application Settings¶
ImGui applications store settings (window positions, etc.) in an INI file. By default, it’s named after your window title. For production apps, use a proper config location:
params.ini_folder_type = hello_imgui.IniFolderType.app_user_config_folder # ~/.config or AppData
params.ini_filename = "my_app/settings.ini"You can also store custom settings: hello_imgui.save_user_pref("key", "value") / load_user_pref("key")
DPI-Aware Sizing¶
Never use fixed pixel sizes. This leads to portability issues on high-DPI screens.
Instead, use sizes relative to the font size using “em” units. Hello ImGui provides helper functions:
from imgui_bundle import imgui, em_to_vec2, em_size
def gui():
# Button sized as 10em x 2em (scales with DPI)
imgui.button("A button", em_to_vec2(10, 2))
# For single values, use em_size
width = em_size(10)#include "imgui.h"
#include "hello_imgui/hello_imgui.h"
void gui() {
// Button sized as 10em x 2em (scales with DPI)
ImGui::Button("A button", HelloImGui::EmToVec2(10, 2));
// For single values, use EmSize
float width = HelloImGui::EmSize(10);
}The mouse wheel in a page that scrolls¶
Hello ImGui keeps the mouse wheel on the window it scrolls, as a browser does. A page scrolled with the wheel keeps scrolling when a plot or an image passes under the mouse, and the plot does not zoom. A wheel that starts on the plot zooms it. The page lets go of the wheel when the mouse moves, or 0.7 s after its last wheel event.
A widget of your own that reads the wheel (a value changed by the wheel, a zoom) claims it while hovered, as ImPlot and ImmVision do. Without the claim, in a page that scrolls, the page takes the wheel and the widget never sees it.
The option wheel_session of the runner params turns this off (C++: runnerParams.wheelSession = false): Dear ImGui’s own behavior, where a plot that arrives under the mouse takes the wheel.
imgui.invisible_button("zoom", em_to_vec2(10, 10))
if imgui.set_item_key_owner(imgui.Key.mouse_wheel_y): # hovered: the wheel is this widget's
zoom *= 1.1 ** imgui.get_io().mouse_wheelImGui::InvisibleButton("zoom", HelloImGui::EmToVec2(10, 10));
if (ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY)) // hovered: the wheel is this widget's
zoom *= powf(1.1f, ImGui::GetIO().MouseWheel);ImmApp¶
ImmApp handles add-on initialization automatically via simple boolean flags.
Quick Start¶
import numpy as np
from imgui_bundle import immapp, imgui, implot, rich_md
xs = np.array([1, 2, 3, 4], dtype=np.float64) # ImPlot takes numpy arrays
ys = np.array([1, 4, 2, 3], dtype=np.float64)
def gui():
rich_md.render("# Hello with Markdown!")
if implot.begin_plot("My Plot"):
implot.plot_line("data", xs, ys)
implot.end_plot()
# Enable add-ons with simple flags
immapp.run(
gui,
window_title="My App",
window_size=(800, 600),
with_implot=True,
with_markdown=True
)#include "immapp/immapp.h"
#include "imgui_rich_md/rich_md.h"
#include "implot/implot.h"
void gui() {
RichMd::Render("# Hello with Markdown!");
if (ImPlot::BeginPlot("My Plot")) {
double x[] = {1, 2, 3, 4};
double y[] = {1, 4, 2, 3};
ImPlot::PlotLine("data", x, y, 4);
ImPlot::EndPlot();
}
}
int main() {
HelloImGui::SimpleRunnerParams runnerParams;
runnerParams.guiFunction = gui;
runnerParams.windowSize = {800, 600};
ImmApp::AddOnsParams addons;
addons.withImplot = true;
addons.withMarkdown = true;
ImmApp::Run(runnerParams, addons);
return 0;
}Available Add-ons¶
| Flag | Add-on | Description |
|---|---|---|
with_implot | ImPlot | 2D plotting |
with_implot3d | ImPlot3D | 3D plotting |
with_markdown | rich_md | Markdown rendering |
with_node_editor | imgui-node-editor | Node graphs |
with_tex_inspect | imgui_tex_inspect | Texture inspector |
Full Configuration¶
For advanced configuration, use RunnerParams (same as Hello ImGui) combined with AddOnsParams:
immapp.run(runner_params, addons) # Python
ImmApp::Run(runnerParams, addons); // C++Usage examples and demonstrations¶
Below are demonstrations from the ImGui Bundle Interactive Manual, showcasing various features of Hello ImGui and ImmApp.
Docking Demo¶

Docking Demo - Full-featured ImGui application with Hello ImGui
Docking Demo shows how to create a full-featured application:
Complex app layout (with several possible layouts)
Load additional fonts, possibly colored, and with emojis
Display a status bar and log window
Customize the theme
User settings persistence
The source code is heavily documented and can be used as a template for your own applications.
ImmApp - Launch an app with addons¶

ImmApp with add-ons: assets, markdown, and ImPlot
Demonstrates how to use ImmApp with multiple add-ons:
Load and display assets (images, icons)
Render markdown content with rich_md
Display interactive plots with ImPlot
Custom 3D Background¶

Custom 3D background with OpenGL shaders
Demonstrates how to render a custom 3D background using OpenGL:
Use
runner_params.callbacks.custom_backgroundcallbackLoad and compile shaders
Adjust uniforms via the GUI
Power Save Mode¶
Demonstrates FPS idling to reduce CPU usage when the app is idle.
Hello ImGui tries hard to save the CPU (and the battery): 3 seconds after the last user interaction, it lowers the frame rate to fps_idle (10 by default with immapp.run).
Content that changes on its own (an animation, a live image, a plot of varying data) would then become choppy. Two calls keep it smooth:
set_item_is_live(), right after its widget: the app keeps its full speed while the widget is visible.request_refresh(), from any thread, when new data arrives (a camera, a socket): the next frame comes at full speed.
if implot.begin_plot("Live data"):
implot.plot_line("signal", xs, ys)
implot.end_plot()
hello_imgui.set_item_is_live() # no idling while the plot is visible
# In a thread that receives data:
hello_imgui.request_refresh()if (ImPlot::BeginPlot("Live data"))
{
ImPlot::PlotLine("signal", xs.data(), ys.data(), (int)xs.size());
ImPlot::EndPlot();
HelloImGui::SetItemIsLive(); // no idling while the plot is visible
}
// In a thread that receives data:
HelloImGui::RequestRefresh();The idling settings are global: they act on the whole application. Prefer the calls above to keep some content moving.
immapp.run(gui, fps_idle=10.0) # the frame rate when idle (0: no idling)
# Or while the app runs:
fps_idling = hello_imgui.get_runner_params().fps_idling
fps_idling.fps_idle = 10.0
fps_idling.enable_idling = False # no idling at allIn a browser, frames come at the display’s rate: the idle frame rate is the nearest one it allows (on a 60 Hz display: 30, 20, 15...).
Demo: Try online |
Advanced - Manual Rendering¶
For complete control over the render loop (useful for game engines or custom frameworks), use manual rendering instead of run().
from imgui_bundle import imgui, hello_imgui, immapp
def gui():
imgui.text("Hello, ImGui Bundle!")
# Setup
runner_params = hello_imgui.RunnerParams()
runner_params.callbacks.show_gui = gui
addons = immapp.AddOnsParams()
addons.with_implot = True
immapp.manual_render.setup_from_runner_params(runner_params, addons)
# Custom render loop
while not hello_imgui.get_runner_params().app_shall_exit:
immapp.manual_render.render()
# Do other work here (physics, networking, etc.)
# Cleanup
immapp.manual_render.tear_down()#include "imgui.h"
#include "hello_imgui/hello_imgui.h"
#include "immapp/immapp.h"
int main()
{
// Setup
HelloImGui::RunnerParams runnerParams;
runnerParams.callbacks.ShowGui = []() {
ImGui::Text("Hello, ImGui Bundle!");
};
ImmApp::AddOnsParams addons;
addons.withImplot = true;
ImmApp::ManualRender::SetupFromRunnerParams(runnerParams, addons);
// Custom render loop
while (!HelloImGui::GetRunnerParams()->appShallExit) {
ImmApp::ManualRender::Render();
// Do other work here (physics, networking, etc.)
}
// Cleanup
ImmApp::ManualRender::TearDown();
return 0;
}Use cases: game engine integration, heavy computation between frames, synchronizing with external systems, precise frame timing control.
Demo: Try online | Python | C++
See Also¶
Dear ImGui Basics – Widget concepts, IDs, common patterns
ImGui Test Engine – Automated testing for ImGui apps
Add-on Libraries – ImPlot, ImmVision, markdown, node editors