Library / SDK
mitsuba-renderer/nanogui avatar
mitsuba-renderer/nanogui

NanoGUI Rendering Library Setup and Architecture

Minimalistic C++/Python GUI library for OpenGL, GLES2/3, Metal, and WebAssembly/WebGL

1,818 stars215 forksC++NOASSERTION

At a glance

What is it?
NanoGUI is a C++ and Python widget toolkit using OpenGL, GLES2/3, or Metal rendering, with WebAssembly code generation for the web. Its graphics-oriented design suits custom applications but does not target conventional native desktop widgets.
Who is it for?
C++ and Python developers building a graphics-rendered interface should consider NanoGUI when GLFW, NanoVG, or MetalNanoVG fit their application and they can accept a C++17-based build. Developers seeking a conventional native desktop widget suite, a documented Python installation command, or a supported macOS binding path should choose a different toolkit.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 37 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

NanoGUI's Graphics Toolkit Use Case

NanoGUI addresses applications that already own a graphics context and need controls drawn inside that rendering pipeline. It is aimed at graphics developers rather than developers looking for a general replacement for operating-system widgets. The library provides buttons, sliders, text boxes, windows, panels, layout objects, callbacks, and other widget types, but its drawing path is tied to OpenGL 3+, GLES2/3, or Metal through NanoVG and MetalNanoVG.

That boundary matters. A conventional application may need native file dialogs, system menus, accessibility services, or controls supplied directly by Windows, macOS, or Linux. The repository does not identify NanoGUI as a replacement for those native interfaces. Its target is a GUI composed from renderable primitives inside an application window.

The project supports C++17 and exposes its documented functionality to Python through `nanobind`. This makes it relevant to Python graphics applications that need widgets sharing the application's rendering surface, as well as C++ tools such as renderers, viewers, and technical applications. The phrase "minimalistic" in the project description is supported by its compact vector library and focused widget architecture. It should not be interpreted as a promise that every desktop control is available.

NanoGUI Context, Widget, and Redraw Data Flow

NanoGUI separates window and input responsibilities from two-dimensional rendering. GLFW creates cross-platform contexts and handles events. GLAD supplies OpenGL access on Windows. NanoVG or MetalNanoVG draws the two-dimensional primitives used by the widgets. This arrangement lets NanoGUI participate in an existing graphics application without introducing a separate native widget renderer.

A widget is associated with a parent widget or screen, receives layout constraints, and can register a stateful callback. In the documented button example, the callback prints a message when the button is pushed. The slider example closes over a `TextBox *`, so changes to the slider update the text box without requiring a global variable. This callback mechanism is explicit and remains available in Python through a regular callback function.

Layout is handled by objects such as `BoxLayout`. Widgets report constraints through methods including `set_fixed_width`, `set_fixed_size`, `set_layout`, and `set_callback`. NanoGUI does not redraw continuously by default. The README states that the event loop is conservative and issues redraw calls only when explicitly requested by an event callback. An application that changes displayed values outside a callback must account for requesting the appropriate redraw itself.

Rendering also has an explicit display concern. The repository advertises cross-platform HDR display and extended color space support, with an `example_hdr`, but the normal widget examples do not explain that configuration. This is a graphics-feature claim, not a general guarantee that every host window configuration is available.

Building NanoGUI Across C++ and Python

The repository uses CMake and documents support for macOS with Clang, Linux with GCC or Clang, FreeBSD with Clang, and Windows with Visual Studio 2017 or newer. It requires a recent C++17-capable compiler. The README says that dependencies are built jointly through CMake, but it does not give a complete native build command or a backend-selection command. Inventing either would make setup advice unreliable.

For Python, the repository advertises binary wheels on PyPI and includes a `pip`-compatible installation script. The `pyproject.toml` specifies Python 3.10 or newer, `scikit-build-core>=1.0`, `nanobind==3.0.0`, and `nanobind-backend>=1.0.0`. Because no `pip install` command is documented, there is no install command to reproduce here. The README identifies PyPI as the wheel distribution source.

The Python build uses `scikit-build-core`, requires CMake 3.15 or newer, and passes `-DNANOGUI_BUILD_EXAMPLES=OFF`. It installs artifacts into `nanogui` directories in the Python package. The source lists macOS, Linux, FreeBSD, and Windows as supported native platforms, but it does not provide a PyPI wheel matrix. Check the package index for wheel tags relevant to the intended interpreter and platform before selecting this installation path.

A First C++ NanoGUI Button

The first useful operation is adding a widget to an existing `window` and connecting it to a callback. The following example is copied from the README. It creates a plain button whose callback writes `pushed!` when the button is pressed. The surrounding application must already provide the window and event-loop context described by the architecture.

cpp
Button *b = new Button(window, "Plain button");
b->set_callback([] { cout << "pushed!" << endl; });

This is a small application fragment, not a standalone program. The README does not include the includes, screen initialization, context creation, or main loop needed to compile it by itself. Those parts depend on the selected graphics backend and host window.

The parent relationship matters. Passing `window` attaches the button to that window, while `set_callback` installs behavior for the button event. The lambda uses C++17 syntax and the project naming conventions described in the README use `underscore_case` for methods and variables. The same pattern can be applied within multiple windows, although the README does not describe lifecycle or ownership rules in detail.

A First Python NanoGUI Layout

Python bindings expose the same widget and layout operations through `nanobind`. This example creates a horizontal panel, places a slider and text box inside it, and connects the slider value to the text box. It illustrates the binding API shown in the README, but it still assumes an existing `window`.

python
panel = Widget(window)
panel.set_layout(BoxLayout(BoxLayout.Horizontal, BoxLayout.Middle, 0, 20))
slider = Slider(panel)
slider.set_value(0.5)
slider.set_fixed_width(80)
tb = TextBox(panel)
tb.set_fixed_size(Vector2i(60, 25))
tb.set_value("50")
tb.set_units("%")

The panel's `BoxLayout` places its children from left to right and aligns them according to `BoxLayout.Middle`. The slider begins at `0.5`, while the text box starts at `"50"` and displays a percent unit. The fixed dimensions keep the controls from expanding indefinitely in this example.

The callback closes over the text box instance and converts the slider's floating-point value to an integer string. This is the Python equivalent of the documented C++ propagation pattern. C++ uses a typed lambda, while the README's Python example uses a named function.

python
def cb(value):
    tb.set_value("%i" % int(value * 100))
slider.set_callback(cb)

At a slider value of `0.5`, this callback sets the text box to `"50"`. The README does not document error handling for malformed input, callback exceptions, or widget destruction while a callback is active, so applications should not infer those guarantees.

OpenGL, GLES, Metal, and WebAssembly Boundaries

NanoGUI's backend coverage is unusual for a widget library, but it creates integration constraints. OpenGL 3+ is the primary desktop rendering path. GLES2/3 extends the design to ARM devices such as the Raspberry Pi and browsers through WebGL. Metal support covers modern Macs, iPhones, and other supported Apple devices according to the README. WebAssembly generation requires Emscripten and is described as working out of the box.

These are rendering paths, not deployment guarantees. A browser build still needs a JavaScript and WebAssembly host, while a native build needs the appropriate context, compiler, graphics driver, and backend configuration. The README does not document browser version requirements, WebGL context attributes, device pixel ratio handling outside the Retina claim, or how to select a backend at runtime.

The Python package metadata introduces a platform distinction. Project classifiers list Python 3 and C++ user-interface packages, and `requires-python` is `>=3.10`, but the repository does not state that Python bindings are supported for every native backend. In particular, a Metal C++ rendering backend does not by itself establish a Metal Python wheel.

WebAssembly is suitable when the application already uses Emscripten. It is a poor fit when the application requires native operating-system integrations absent from NanoGUI's documented feature set. The graphics backend choice should therefore be made before evaluating the Python package.

NanoGUI Trade-Offs, License, and Maintenance Cost

The principal trade-off is close integration with custom rendering at the cost of a narrower native-control model. NanoGUI can draw widgets through the same general two-dimensional graphics stack used by an application, and it offers a small vector library instead of depending on Eigen or Enoki. Developers remain responsible for the surrounding graphics application, event loop, context, display configuration, and backend-specific setup.

The `pyproject.toml` identifies the package license as `BSD-3-Clause` and points to `LICENSE.txt`. The repository description classifies the license as custom because GitHub cannot classify it automatically, so the license file is the source to inspect before redistribution or integration. This is a compliance review point, not legal advice. The README does not summarize attribution, warranty, or redistribution conditions.

The repository is not archived. Its last push was on 2026-09-16. The repository has no GitHub releases, so there is no release history from which to infer upgrade cadence or compatibility policy. The README mentions improved ports and revamped widgets, which suggests that API changes between upstream versions deserve attention. The Python package pins `nanobind==3.0.0` in its build requirements, making its build configuration part of the upgrade surface.

The direct alternative is a native desktop GUI toolkit that delegates controls and window integration to each operating system. Its approach prioritizes platform-native widgets and system conventions rather than drawing a custom interface through NanoVG, OpenGL, GLES, or Metal. NanoGUI is the better fit when the interface must be part of a graphics-rendered scene. A native toolkit is the better fit when native controls and desktop conventions are the main requirement.

Editorial conclusion

C++ and Python developers building a graphics-rendered interface should consider NanoGUI when GLFW, NanoVG, or MetalNanoVG fit their application and they can accept a C++17-based build. Developers seeking a conventional native desktop widget suite, a documented Python installation command, or a supported macOS binding path should choose a different toolkit. Before adoption, verify the `LICENSE.txt` terms, build NanoGUI for the required graphics backend and platform, and confirm that wheel availability and backend selection match the deployment target.

Frequently asked questions

What is NanoGUI used for?

NanoGUI is a C++ and Python widget library using OpenGL 3+, GLES2/3, and Metal rendering, with WebAssembly support through Emscripten. It provides widgets, layouts, event handling, and Python bindings for applications that own a graphics context.

How do I install NanoGUI for Python?

The README points to binary wheels on PyPI, while the repository includes a `pip`-compatible installation script and Python package metadata. It does not provide a specific `pip install` command, and the package requires Python 3.10 or newer.

Does NanoGUI support native macOS and Metal applications?

The README lists macOS as a supported native platform and says the Metal backend supports modern Macs, iPhones, and similar devices. The README does not state that Python bindings are available for every Metal backend configuration.

Does NanoGUI redraw its interface automatically?

The README says the event loop only issues redraw calls when explicitly requested by an event callback. Applications that change widgets outside such callbacks may need to arrange redraw requests themselves, although the README does not document that API.

What license does NanoGUI use?

The Python project metadata lists `BSD-3-Clause` and identifies `LICENSE.txt` as the license file. Review that file for the repository's actual terms, particularly before redistributing the library.

Official sources

  1. Issues
  2. mitsuba-renderer/nanogui on GitHub
  3. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mitsuba-renderer-nanogui.svg)](https://hysenlabs.com/projects/mitsuba-renderer-nanogui)

Was this useful?