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.

For AI assistants

This page is written for AI assistants: give it to yours (it is also at https://imgui-bundle.pages.dev/llms.txt), and it will know how to help you write applications with Dear ImGui Bundle, in Python or C++. The full PDF manuals give it even more context.

ImGui Bundle: Conversation Starter for LLMs

ImGui Bundle provides a complete set of libraries on top of Dear ImGui, enabling users to create interactive applications in C++ and Python.

This conversation starter is intended to be studied by a LLM, so that it can then help users.

Please read thoroughly the following sections to understand the structure of the project and how to use it.

The following sections will contain lots of links:

Docs for ImGui Bundle and Hello ImGui

ImGui Bundle is based on Dear ImGui, and can also use Hello ImGui as a base, in order to ease the creation of interactive applications.

Please do read to the following documentation for a comprehensive understanding of the libraries:

Dear ImGui Bundle, full doc (PDF): https://imgui-bundle.pages.dev/doc/assets/imgui_bundle_book.pdf

Hello ImGui https://pthom.github.io/hello_imgui/book/intro.html https://pthom.github.io/hello_imgui/book/doc_params.html https://pthom.github.io/hello_imgui/book/doc_api.html

Docs for Fiatlight Fiatlight is a library heavily based on Dear ImGui Bundle, by the same author. Reading this is not mandatory, it only helps if working on Fiatlight itself. https://pthom.github.io/fiatlight/flgt.pdf

Differences in the C++ versus Python APIs

ImGui Bundle’s Python bindings follow Python’s conventions while maintaining compatibility with the underlying C++ API. Here are the key differences:

1. Naming Conventions

2. Return Values vs Output Parameters

3. Enum Values

4. Module Structure and Imports

Common ImGui Patterns and Gotchas

Widget IDs

ImGui identifies widgets by their label string. You must not have two widgets with the same label in the same scope, or they will conflict.

Solution 1: Use ## to add a hidden ID suffix:

imgui.button("OK")           # ID is "OK"
imgui.button("OK##dialog2")  # ID is "OK##dialog2", but displays as "OK"
imgui.button("##hidden")     # No visible label, ID is "##hidden"

Solution 2: Use push_id()/pop_id() for loops:

for i, item in enumerate(items):
    imgui.push_id(i)          # or push_id(str(i)) or push_id(item.name)
    if imgui.button("Delete"):
        delete_item(item)
    imgui.pop_id()

Begin/End Pairs

Many ImGui functions come in begin/end pairs. Important rules:

  1. imgui.begin() is special: Always call imgui.end(), even if begin() returns False:

    # CORRECT
    if imgui.begin("Window"):
        imgui.text("Content")
    imgui.end()  # Always called!
    
    # WRONG - will cause errors
    if imgui.begin("Window"):
        imgui.text("Content")
        imgui.end()  # Only called when window is visible - BUG!
  2. Other begin/end pairs: Only call end_*() if begin_*() returned True:

    if imgui.begin_menu("File"):
        if imgui.menu_item("Open"):
            open_file()
        imgui.end_menu()  # Only when begin_menu returned True
    
    if imgui.begin_popup("popup"):
        imgui.text("Popup content")
        imgui.end_popup()  # Only when begin_popup returned True

Context Managers (Python)

Python users can use imgui_ctx for automatic end calls, which is cleaner and less error-prone:

from imgui_bundle import imgui, imgui_ctx

# Automatic imgui.end() when exiting the with block
with imgui_ctx.begin("My Window") as window_visible:
    if window_visible:
        imgui.text("Hello")

# Works for other pairs too
with imgui_ctx.begin_menu("File") as menu_open:
    if menu_open:
        if imgui.menu_item("Open"):
            open_file()

# Useful for tree nodes, popups, etc.
with imgui_ctx.tree_node("Settings") as node_open:
    if node_open:
        imgui.text("Settings content")

See: bindings/imgui_bundle/imgui_ctx.py

DPI-Aware Sizing (em units)

Never use hardcoded pixel sizes - they will look wrong on high-DPI screens and different platforms.

from imgui_bundle import imgui, em_to_vec2, em_size

# BAD - hardcoded pixels
imgui.button("Click", imgui.ImVec2(100, 30))

# GOOD - use em units (1 em = font height, typically ~16px at 100% DPI)
imgui.button("Click", em_to_vec2(8, 2))  # or hello_imgui.em_to_vec2(8, 2)

# Also available:
width = em_size(10)  # Single dimension
em = em_size()       # Get 1 em in pixels

The em_to_vec2() and em_size() functions are available directly from imgui_bundle (recommended), and also in hello_imgui and immapp modules.

Horizontal/Vertical Layouts (StackLayout)

ImGui Bundle includes a patched ImGui with StackLayout (by thedmd), which adds BeginHorizontal/EndHorizontal, BeginVertical/EndVertical, and Spring(). Use these instead of repeated SameLine() calls, or when you need right-alignment or flexible spacing.

// Instead of many SameLine() calls:
ImGui::BeginHorizontal("toolbar", ImVec2(ImGui::GetContentRegionAvail().x, 0.f));
ImGui::Button("Left");
ImGui::Button("Also Left");
ImGui::Spring();          // pushes remaining items to the right
ImGui::Text("Right-aligned");
ImGui::EndHorizontal();
imgui.begin_horizontal("toolbar", imgui.ImVec2(imgui.get_content_region_avail().x, 0.0))
imgui.button("Left")
imgui.button("Also Left")
imgui.spring()
imgui.text("Right-aligned")
imgui.end_horizontal()

Prefer StackLayout over SameLine() when:

References for Python APIs

Hello ImGui and ImApp API

Hello ImGui and ImmApp are frameworks that simplify creating interactive applications with ImGui. They handle window creation, rendering, UI loops, and events, allowing developers to focus on GUI elements.

Hello ImGui Core Features

  1. Simple Application Structure:

    • Define a single GUI function that will be called each frame

    • Call HelloImGui::Run() (C++) or hello_imgui.run() (Python) to start the application

  2. DPI-Aware Interface:

    • Automatically handles high-DPI screens across platforms

    • Provides utilities like em_size() and em_to_vec2() for resolution-independent sizing

  3. Asset Management:

    • Embedded asset system for fonts, images, and other resources

    • Functions like image_from_asset() and load_font() for easy asset loading

    • Works across all platforms (including mobile and web)

  4. Theming Support:

    • Multiple built-in themes (Darcula, SoDark, PhotoshopStyle, etc.)

    • Theme customization with ImGuiTweakedTheme

    • Theme editor GUI with show_theme_tweak_gui()

  5. Window Management:

    • Optional docking support

    • Window geometry restoration

    • Multi-viewport support

ImmApp Features

ImmApp extends Hello ImGui with additional capabilities:

  1. AddOns Support:

    • Enables integration with ImPlot, ImPlot3D, Markdown, Node Editor, etc.

    • Simple boolean flags to activate add-ons

  2. Extended API:

    • Simplified interface for common tasks

    • Additional utilities for GUI layouts

Basic Usage

from imgui_bundle import imgui, immapp

def gui():
    imgui.text("Hello, world!")

immapp.run(
    gui_function=gui,           # Function called each frame
    window_title="Hello!",      # Window title
    window_size_auto=True,      # Auto-size window based on content
    with_implot=True,           # Enable ImPlot addon (optional)
    with_markdown=False,        # Enable Markdown addon (optional)
)

Note: When using Hello ImGui or ImmApp, you don’t need to call imgui.begin() and imgui.end() for the main window, as they automatically create a full-window ImGui context.

Async and Pyodide Support

ImGui Bundle supports asynchronous execution for Jupyter notebooks and web deployment via Pyodide.

Desktop Async - For applications that need async integration:

import asyncio
from imgui_bundle import immapp

async def main():
    await immapp.run_async(gui, window_title="My App")
    print("GUI closed")

asyncio.run(main())

Jupyter Notebooks - Use the .nb module for non-blocking execution:

from imgui_bundle import immapp

# Start GUI (non-blocking, continues to next cell)
immapp.nb.start(gui, window_title="My App")

# Later, to stop:
immapp.nb.stop()

# Check if running:
if immapp.nb.is_running():
    print("GUI is active")

Pyodide (Web Browser) - In Pyodide, run() starts the GUI and returns immediately (browsers cannot block):

# Same code works on desktop (blocking) and Pyodide (fire-and-forget)
immapp.run(gui, window_title="My App")

For async control in Pyodide (waiting for GUI to exit), use run_async():

import asyncio
async def main():
    await immapp.run_async(gui, window_title="My App")
    print("GUI closed")
asyncio.create_task(main())
Platformrun()run_async()
DesktopBlockingAwaitable
PyodideFire-and-forgetAwaitable
NotebookUse nb.start()Use nb.start()

Advanced Configuration with RunnerParams

For more sophisticated applications, Hello ImGui provides a comprehensive RunnerParams structure that controls all aspects of application behavior. Instead of using simple parameters, you can create and configure a RunnerParams object:

from imgui_bundle import hello_imgui, immapp

# Create and configure runner parameters
params = hello_imgui.RunnerParams()

# 1. Window settings
params.app_window_params.window_title = "Advanced Application"
params.app_window_params.window_geometry.size = (1200, 800)
params.app_window_params.restore_previous_geometry = True

# 2. ImGui window settings
params.imgui_window_params.show_menu_bar = True
params.imgui_window_params.show_status_bar = True
params.imgui_window_params.default_imgui_window_type = hello_imgui.DefaultImGuiWindowType.provide_full_screen_dock_space

# 3. Callbacks
params.callbacks.show_gui = my_gui_function
params.callbacks.show_menus = my_menus_function
params.callbacks.show_status = my_status_function

# 4. Run the application with full parameters
immapp.run(params)
Key RunnerParams Components
  1. App Window Parameters (app_window_params):

    • Controls the application window appearance and behavior

    • Window geometry (size, position, full-screen mode)

    • Borderless mode with customizable controls

  2. ImGui Window Parameters (imgui_window_params):

    • Configures the ImGui windows inside the application

    • Menu bar options (app menu, view menu, themes)

    • Status bar settings

    • Default window types (full screen, dockspace, none)

  3. Callbacks (callbacks):

    • GUI callbacks (called every frame):

      • show_gui: Main GUI content

      • show_menus: Custom menu bar content

      • show_app_menu_items: Items in the “App” menu

      • show_status: Status bar content

    • Lifecycle callbacks:

      • post_init: Called once after OpenGL/backend initialization

      • before_exit: Called once before shutdown

      • pre_new_frame: Called before each frame starts

    • Font loading:

      • load_additional_fonts: Load custom fonts at startup

    • Custom rendering:

      • custom_background: For custom OpenGL/3D backgrounds

    • Mobile-specific:

      • mobile_on_pause, mobile_on_resume: App backgrounded/foregrounded

  4. Docking Parameters (docking_params):

    • Define dockable window layouts

    • Create complex UI arrangements with splits

    • Manage multiple alternative layouts

  5. Performance Settings:

    • Control frame rate limiting with fps_idling

    • Mobile device optimizations

    • Background rendering options

This comprehensive parameter system allows for highly customized applications while maintaining the simplicity of the basic API for common use cases.

Asset Management

Hello ImGui provides a cross-platform asset system for fonts, images, and other resources.

Asset Directories - By default, assets are loaded from a folder named assets next to your executable or script:

# Set custom assets folder (call before run)
hello_imgui.set_assets_folder("my_assets")

Loading Fonts:

from imgui_bundle import hello_imgui

def load_fonts():
    # Load a font at 18px size
    hello_imgui.load_font("fonts/Roboto-Regular.ttf", 18.0)

    # Load with options (e.g., merge icons into previous font)
    font_params = hello_imgui.FontLoadingParams()
    font_params.merge_to_last_font = True
    hello_imgui.load_font("fonts/icons.ttf", 16.0, font_params)

params = hello_imgui.RunnerParams()
params.callbacks.load_additional_fonts = load_fonts

Loading Images:

from imgui_bundle import hello_imgui, imgui

def gui():
    # Load and display an image from assets
    texture = hello_imgui.im_texture_id_from_asset("images/logo.png")
    imgui.image(texture, imgui.ImVec2(100, 100))

DPI-Aware Sizing - Use em_size() for resolution-independent sizing (see also “Common ImGui Patterns and Gotchas” section above):

from imgui_bundle import imgui, em_to_vec2, em_size

def gui():
    em = em_size()  # Current font size (adapts to DPI)
    imgui.button("Click", imgui.ImVec2(10 * em, 2 * em))

    # Convenience function (preferred)
    imgui.button("Click", em_to_vec2(10, 2))

API References

Hello ImGui: bindings/imgui_bundle/hello_imgui.pyi

ImmApp: bindings/imgui_bundle/immapp/init.pyi bindings/imgui_bundle/immapp/immapp_cpp.pyi

Main ImmApp run function:

@overload
def run(
    gui_function: VoidFunction,
    window_title: str = "",
    window_size_auto: bool = False,
    window_restore_previous_geometry: bool = False,
    window_size: Optional[ScreenSize] = None,
    fps_idle: float = 10.0,
    with_implot: bool = False,
    with_implot3d: bool = False,
    with_markdown: bool = False,
    with_node_editor: bool = False,
    with_tex_inspect: bool = False,
    with_node_editor_config: Optional[NodeEditorConfig] = None,
    with_markdown_options: Optional[RichMd.MarkdownOptions] = None,
) -> None:
    ...

ImGui API

If needed, the Python bindings for ImGui are available in the following files:

Python: bindings/imgui_bundle/imgui/init.pyi bindings/imgui_bundle/imgui/internal.pyi

(those are bindings for imgui.h and imgui_internal.h)

ImPlot and ImPlot3D API

Below are the Python bindings for ImPlot and ImPlot3D, read them if needed:

bindings/imgui_bundle/implot/init.pyi

bindings/imgui_bundle/implot3d/init.pyi

All Library APIs

All library stubs (Python type hints and API documentation) are in bindings/imgui_bundle/*.pyi: https://github.com/pthom/imgui_bundle/tree/main/bindings/imgui_bundle

Key files: hello_imgui.pyi, imgui/__init__.pyi, implot/__init__.pyi, immvision.pyi, immapp/__init__.pyi

Example programs and demos

Hello World

Please do read these minimal hello world programs:

Hello World in Python and C++: bindings/imgui_bundle/demos_python/demos_immapp/demo_hello_world.py and bindings/imgui_bundle/demos_cpp/demos_immapp/demo_hello_world.cpp

A small program using ImGui, ImPlot and ImmApp

The program below shows a beating heart whose pulse is controlled by a knob. It is a good example of how to use ImGui, ImPlot and ImmApp together.

Please do read it:

in python bindings/imgui_bundle/demos_python/demos_immapp/haiku_implot_heart.py and in C++ bindings/imgui_bundle/demos_cpp/demos_immapp/haiku_implot_heart.cpp

Demos for ImPlot and ImPlot3D

If needed, a full set of Python demos for ImPlot and ImPlot3D are available:

bindings/imgui_bundle/demos_python/demos_implot/implot_demo.py

bindings/imgui_bundle/demos_python/demos_implot3d/implot3d_demo.py

They are almost direct translation of the C++ demos available in the ImPlot and ImPlot3D repositories: implot_demo.cpp implot3d_demo.cpp

How to create complex applications layouts using Hello ImGui

The demo below demonstrates how to use Hello ImGui to create complex applications layouts, using the following features:

Read it if needed.

See bindings/imgui_bundle/demos_python/demos_immapp/demo_docking.py

and its C++ equivalent: bindings/imgui_bundle/demos_cpp/demos_immapp/demo_docking.cpp

Custom background:

If a user wants to create a custom 3D background (using OpenGL and shaders), an example is available in the following files, which you can read if needed:

bindings/imgui_bundle/demos_python/demos_immapp/demo_custom_background.py

bindings/imgui_bundle/demos_cpp/demos_immapp/demo_custom_background.cpp

Pure python backends

If a users wants to control the full app cycle (i.e. not using ImmApp or HelloImGui), they may want to use a pure python backend.

If needed, read the following links to understand how to use the pure python backends: https://github.com/pthom/imgui_bundle/tree/main/bindings/imgui_bundle/python_backends

bindings/imgui_bundle/python_backends/examples/example_python_backend_glfw3.py

bindings/imgui_bundle/python_backends/examples/example_python_backend_sdl2.py

ImmVision

ImmVision is an image debugger with zoom, pan, pixel inspection, and colormaps. Key points:

Demos: demos_python/demos_immvision/ (display, inspector, processing, linked views)

Follow up

Consult the links that were marked with “if needed” if you need to help users with specific questions on the APIs