Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Hello ImGui - ImmApp

Hello ImGui and ImmApp are the two main ways to create applications with ImGui Bundle.

These runners enable you to create powerful ImGui applications with minimal boilerplate code.

Hello ImGui

Quick Start

Python
C++
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))

Documentation

Configuration with RunnerParams

For full control, configure your application via RunnerParams:

Python
C++
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)

See RunnerParams Reference for all configuration options. For Python, see RunnerParams Type Hints

Callbacks

Hello ImGui provides several callback hooks:

CallbackWhen Called
show_guiEvery frame (main GUI)
show_menusEvery frame (menu bar content)
show_statusEvery frame (status bar)
post_initOnce, after OpenGL initialization
before_exitOnce, 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:

Python
C++
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)

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.

Python
C++
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_wheel

ImmApp

ImmApp handles add-on initialization automatically via simple boolean flags.

Quick Start

Python
C++
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
)

Available Add-ons

FlagAdd-onDescription
with_implotImPlot2D plotting
with_implot3dImPlot3D3D plotting
with_markdownrich_mdMarkdown rendering
with_node_editorimgui-node-editorNode graphs
with_tex_inspectimgui_tex_inspectTexture 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 - Full-featured ImGui application with Hello ImGui

Docking Demo shows how to create a full-featured application:

The source code is heavily documented and can be used as a template for your own applications.

Source code: Python | C++

ImmApp - Launch an app with addons

ImmApp with add-ons: assets, markdown, and ImPlot

ImmApp with add-ons: assets, markdown, and ImPlot

Demonstrates how to use ImmApp with multiple add-ons:

Source code: Python | C++

Custom 3D Background

Custom 3D background with OpenGL shaders

Custom 3D background with OpenGL shaders

Demonstrates how to render a custom 3D background using OpenGL:

Source code: Python | C++

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:

Python
C++
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()

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 all

In 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...).

Advanced - Manual Rendering

For complete control over the render loop (useful for game engines or custom frameworks), use manual rendering instead of run().

Python
C++
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()

Use cases: game engine integration, heavy computation between frames, synchronizing with external systems, precise frame timing control.

Demo: Try online | Python | C++


See Also