Lightweight animated immediate-mode GUI framework for Unreal Engine canvas rendering platform agnostic.
This is a mobile friendly fork of the original, Windows only MonkeGUI.
Inspired by Dear ImGui, built entirely on UCanvas with no external GUI dependencies.
For full API reference, see DOCUMENTATION.md
Discord: aactor
| Menu | Widgets |
|---|---|
![]() |
![]() |
| Color Picker | Tabs / Combo |
|---|---|
![]() |
![]() |
- Immediate-mode API — no retained widget tree
- Fully rendered via
UCanvas— no external render dependencies - Smooth animations on every widget (hover, press, open/close)
- Window dragging and resizing
- Collapsible windows
- Touch and pointer input supplied by Unreal
- Tabs, combo boxes, sliders, checkboxes, color picker, popups, search bar
- Custom styling via
MonkeGUI::Stylenamespace - Unreal Engine 4 / 5 compatible, including iOS and Android targets
- Unreal Engine 4 or 5
- C++17 or newer
- A valid
UCanvas*(e.g. fromPostRender) - A 1×1 white
UTexture*(used for all filled rect rendering) - A
UFont* - C++
MonkeGUI uses Unreal Engine headers and does not depend on Windows APIs, so the same source can be compiled for desktop, iOS, and Android Unreal targets.
Call these at the top of your render function, before any widgets:
MonkeGUI::SetWhiteTexture(myWhiteTexture); // 1x1 white UTexture*
MonkeGUI::SetFont(myFont); // UFont*
MonkeGUI::SetPointerState(pointerPosition, pointerPressed); // touch or mouse state, in canvas coordinates
MonkeGUI::SetupCanvas(Canvas, DeltaTime); // resets state, updates pointerCall SetPointerState every frame before SetupCanvas. For touch, supply the primary finger's position and pressed state from Unreal input; convert the position to UCanvas coordinates if your viewport is scaled. Search-bar text is event-driven: send UTF-8 text with QueueTextInput, and call QueueTextBackspace or QueueTextEscape for those actions. Use IsTextInputFocused() to show or dismiss the platform on-screen keyboard from the host app.
static FVector2D pos = { 200.f, 150.f };
static FVector2D size = { 400.f, 300.f };
if (MonkeGUI::Begin("My Window", &pos, &size, true))
{
static bool enabled = false;
MonkeGUI::Checkbox("Enable Feature", &enabled);
if (MonkeGUI::Button("Execute"))
{
// handle click
}
MonkeGUI::End();
}MonkeGUI::Render(); // always call last| Widget | Function |
|---|---|
| Text | MonkeGUI::Text(label) |
| Button | MonkeGUI::Button(label, width) |
| Checkbox | MonkeGUI::Checkbox(label, &bool) |
| Slider | MonkeGUI::SliderFloat(label, &float, min, max) |
| Combo | MonkeGUI::Combo(label, &index, items, count) |
| Color Picker | MonkeGUI::ColorPicker(label, &FLinearColor) |
| Separator | MonkeGUI::Separator() |
| Search Bar | MonkeGUI::SearchBar(label, buf, size) |
| Tabs | BeginTabs() / TabItem() / EndTabs() |
| Popup | OpenPopup(id) / BeginPopup(id, size) / EndPopup() |
static int tab = 0;
MonkeGUI::BeginTabs();
MonkeGUI::TabItem("General", 0, &tab);
MonkeGUI::TabItem("Advanced", 1, &tab);
MonkeGUI::EndTabs();
if (tab == 0) { /* general widgets */ }
if (tab == 1) { /* advanced widgets */ }static char search[128]{};
MonkeGUI::SearchBar("##search", search, sizeof(search));
for (int i = 0; i < count; i++)
if (MonkeGUI::SearchMatches(names[i], search))
MonkeGUI::Checkbox(names[i], &enabled[i]);if (MonkeGUI::Button("Open Info"))
MonkeGUI::OpenPopup("info");
if (MonkeGUI::BeginPopup("info", { 220.f, 100.f }))
{
MonkeGUI::Text("Hello from a popup!");
if (MonkeGUI::Button("Close", 80.f))
MonkeGUI::OpenPopupId = -1;
MonkeGUI::EndPopup();
}All style values are in MonkeGUI::Style and can be changed at any time:
MonkeGUI::Style::Accent = MonkeGUI::SRGB(255, 100, 50, 220); // orange accent
MonkeGUI::Style::WindowBg = MonkeGUI::SRGB(20, 20, 20, 240);
MonkeGUI::Style::RowH = 20.f;The window background and title bar colors can also be changed at runtime:
MonkeGUI::MenuBg = someColor;
MonkeGUI::TitleBg = someColor;// Set once at init
MonkeGUI::SetFPSCallback([]() -> float {
return 1.0f / myDeltaTime;
});
// Call each frame (before Render)
MonkeGUI::Watermark("My App v1.0");
// renders: "My App v1.0 | 144 FPS"MonkeGUI::FX::SnowRender(DeltaTime, 0.85f); // call before Render()- Engine-provided input — pointer and text events must be supplied by the host Unreal application; MonkeGUI does not poll platform input or open the on-screen keyboard.
- Single context — all state is global; multiple simultaneous GUI contexts are not supported.
- Draw queue cap — the post-render queue holds up to 2048 commands. Very complex layouts may silently drop commands.
- No scrolling — windows and combo boxes do not scroll; content that overflows is clipped.
MonkeGUI was built to provide clean visuals and smooth animations with the simplest possible integration story — drop in one header, supply a canvas and a white texture, and start drawing.
Inspired by Dear ImGui by Omar Cornut.
MIT — see LICENSE.



