open source · MIT

imshell: Dear ImGui apps on every platform.

You write one frame(). It brings the rest.

A small C++20 toolkit around Dear ImGui. No browser engine, no runtime.

* macOS, iOS, Windows, Linux, Android, web* Metal, Direct3D 11, OpenGL, WebGL 2* components you can try in the browser

imshell opens the window, sets up the graphics backend and the Dear ImGui backends, runs a frame loop that idles when nothing changes, and fills the gaps between ImGui and each operating system: a title bar with the real OS buttons, touch and the soft keyboard on phones and tablets, native views in the layout, fonts, file dialogs, haptics and auto-update. Dear ImGui stays yours, compiled once by your project. It grew out of DearSQL, a SQL client for desktop, iPad and iPhone, where it runs everything between the OS and the UI.

> Platforms

what differs

* macOSGLFW + Metal, native traffic lights
* iOS & iPadOSUIKit + Metal, touch, the soft keyboard and IME
* WindowsGLFW + Direct3D 11, snap layouts
* LinuxGTK 4 + OpenGL, GTK's frame clock
* AndroidNativeActivity + OpenGL ES 3, an APK without Gradle
* WebEmscripten + WebGL 2, any static host

## The whole app

A delegate draws a frame; imshell::Run does the rest. The same file builds for every platform above.

#include "imshell/app.hpp"
#include "imshell/button.hpp"

struct Hello : imshell::Delegate {
    int clicks = 0;
    void frame() override {
        const imshell::Rect r = imshell::ContentRect(); // under the title bar, inside the safe area
        ImGui::SetNextWindowPos(r.pos);
        ImGui::SetNextWindowSize(r.size);
        ImGui::Begin("hello", nullptr, ImGuiWindowFlags_NoDecoration);
        if (imshell::Button("Click me", imshell::ButtonVariant::Primary))
            ++clicks;
        ImGui::Text("Clicked %d times", clicks);
        ImGui::End();
    }
};

int main() {
    static Hello hello;
    return imshell::Run({.title = "Hello", .titleBar = true}, hello);
}

In CMake, next to your own Dear ImGui:

set(IMSHELL_IMGUI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/imgui)
add_subdirectory(external/imshell)
add_executable(app main.cpp ${IMGUI_SOURCES})
target_link_libraries(app PRIVATE imshell::imshell) # + imshell::components, optional

Getting started →

## What it has

## Performance

Native code and a loop that sleeps when nothing changes: small binaries, a first frame in milliseconds, and an idle window that costs next to nothing.

149 ms

launch to first frame

0.1 %

CPU while idle

1.5 MB

the whole app

314 KB

gallery in the browser

> macOS, release build

hello · gallery

Executable, stripped1.5 MB1.5 MB
Memory30 MB82 MB
CPU0.1 % idle3.1 % animating
Launch to first frame149 ms

Apple M4, 16 GB, macOS 27.0.1, imshell f1a00de, 2026-11-11. hello is the repo's example app: a title bar, buttons and two native views (a text field and a date picker). gallery has every component and the code editor, and never idles: its loading skeleton and progress bar redraw every frame, so its CPU is the cost of animating. Release builds with Dear ImGui, imshell and GLFW linked in, stripped. First frame: from launching hello until it has drawn its first frame and quit, the median of 11 runs. Memory: the physical footprint 3 s after launch. CPU: the time used over the next 10 s, the window focused and left alone. In the browser: the gallery's .wasm and .js as this site serves them (brotli), 279 + 35 KB. Windows, Linux and the phones are not measured yet. site/bench.sh measures it again.