Top Related Projects
Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
A simple and easy-to-use immediate-mode gui library
A single-header ANSI C gui library
Simple and portable (but not inflexible) GUI library in C that uses the native GUI technologies of each platform it supports.
A tiny immediate-mode UI library
Embedded graphics library to create beautiful UIs for any MCU, MPU and display type.
Quick Overview
Nuklear is a single-header ANSI C immediate mode GUI library. It's designed to be easily embedded into applications, providing a simple and lightweight solution for creating graphical user interfaces. Nuklear is highly portable and can be integrated into various graphics APIs and platforms.
Pros
- Lightweight and easy to integrate (single-header file)
- Highly portable across different platforms and graphics APIs
- Customizable and flexible, allowing for extensive styling options
- No external dependencies, making it easy to include in projects
Cons
- Limited built-in widgets compared to more comprehensive GUI libraries
- Immediate mode GUI can be less intuitive for developers used to retained mode systems
- Documentation could be more extensive and user-friendly
- Performance may not be optimal for very complex UIs or large applications
Code Examples
- Creating a simple window:
struct nk_context ctx;
nk_init_fixed(&ctx, memory, MAX_MEMORY, &font);
if (nk_begin(&ctx, "Demo", nk_rect(50, 50, 200, 200),
NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
{
nk_layout_row_dynamic(&ctx, 30, 1);
nk_label(&ctx, "Hello, Nuklear!", NK_TEXT_LEFT);
}
nk_end(&ctx);
- Adding a button and handling clicks:
if (nk_button_label(&ctx, "Click me!"))
{
printf("Button clicked!\n");
}
- Creating a simple input field:
static char text[256] = "Input text here";
nk_layout_row_dynamic(&ctx, 25, 1);
nk_edit_string(&ctx, NK_EDIT_SIMPLE, text, sizeof(text) - 1, nk_filter_default);
Getting Started
- Download the
nuklear.h
header file from the GitHub repository. - Include the header in your project:
#define NK_IMPLEMENTATION #include "nuklear.h"
- Initialize Nuklear context:
struct nk_context ctx; nk_init_fixed(&ctx, memory, MAX_MEMORY, &font);
- In your main loop, begin and end Nuklear frames:
nk_input_begin(&ctx); // Process input events here nk_input_end(&ctx); if (nk_begin(&ctx, "Window Title", nk_rect(50, 50, 200, 200), 0)) { // Add your UI elements here } nk_end(&ctx); // Render Nuklear commands
Competitor Comparisons
Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
Pros of ImGui
- More feature-rich and actively maintained
- Extensive documentation and examples
- Wider community support and adoption
Cons of ImGui
- Larger codebase and potentially higher memory footprint
- C++ only, which may limit integration in some projects
Code Comparison
ImGui:
ImGui::Begin("My Window");
if (ImGui::Button("Click me!"))
doSomething();
ImGui::Text("Hello, world %d", 123);
ImGui::End();
Nuklear:
if (nk_begin(ctx, "My Window", nk_rect(50, 50, 200, 200), 0))
{
if (nk_button_label(ctx, "Click me!"))
doSomething();
nk_label(ctx, "Hello, world 123", NK_TEXT_LEFT);
}
nk_end(ctx);
Key Differences
- ImGui is C++ based, while Nuklear is written in C
- ImGui offers more built-in widgets and features
- Nuklear has a smaller footprint and can be easier to integrate in some cases
- ImGui has better support for custom rendering and styling
- Nuklear provides more low-level control over the UI elements
Both libraries are popular choices for immediate mode GUI development, with ImGui being more feature-rich and widely adopted, while Nuklear offers a lighter-weight alternative with C language support.
A simple and easy-to-use immediate-mode gui library
Pros of raygui
- Lightweight and easy to integrate with raylib
- Designed specifically for game development
- Supports both immediate mode and retained mode GUI
Cons of raygui
- Less feature-rich compared to Nuklear
- Limited to C programming language
- Smaller community and ecosystem
Code Comparison
raygui:
GuiButton((Rectangle){ 25, 25, 125, 30 }, "Button");
if (GuiButton((Rectangle){ 25, 60, 125, 30 }, "Click me!")) {
// Handle button click
}
Nuklear:
if (nk_button_label(ctx, "Button")) {
// Handle button click
}
nk_layout_row_dynamic(ctx, 30, 1);
if (nk_button_label(ctx, "Click me!")) {
// Handle button click
}
Both libraries offer simple ways to create buttons, but Nuklear provides more layout control out of the box. raygui's syntax is more straightforward, while Nuklear requires more setup but offers greater flexibility.
raygui is ideal for quick prototyping and game development with raylib, while Nuklear is better suited for complex, cross-platform applications requiring extensive GUI customization.
A single-header ANSI C gui library
Pros of Nuklear (vurtun)
- More active development and recent updates
- Larger community and more contributors
- Better documentation and examples
Cons of Nuklear (vurtun)
- Slightly more complex API
- Less focus on minimalism and simplicity
- Potentially higher memory footprint
Code Comparison
Nuklear (vurtun):
struct nk_context ctx;
nk_init_default(&ctx, 0);
if (nk_begin(&ctx, "Demo", nk_rect(50, 50, 200, 200),
NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
{
nk_layout_row_dynamic(&ctx, 30, 1);
if (nk_button_label(&ctx, "Button"))
fprintf(stdout, "Button pressed!\n");
}
nk_end(&ctx);
Nuklear (Immediate-Mode-UI):
struct nk_context ctx;
nk_init_default(&ctx, 0);
if (nk_begin(&ctx, "Demo", nk_rect(50, 50, 200, 200), 0))
{
nk_layout_row_dynamic(&ctx, 30, 1);
if (nk_button_label(&ctx, "Button"))
printf("Button pressed!\n");
}
nk_end(&ctx);
The code comparison shows that both versions have similar syntax and structure, with minor differences in window flags and output methods.
Simple and portable (but not inflexible) GUI library in C that uses the native GUI technologies of each platform it supports.
Pros of libui
- Native look and feel across platforms (Windows, macOS, Linux)
- Simple and straightforward API for creating GUI applications
- Lightweight and minimal dependencies
Cons of libui
- Limited widget set compared to Nuklear
- Less flexibility in customizing UI appearance
- Slower development and fewer updates
Code Comparison
libui example:
uiInit(NULL);
uiWindow *window = uiNewWindow("Hello", 300, 200, 0);
uiButton *button = uiNewButton("Click Me");
uiWindowSetChild(window, uiControl(button));
uiControlShow(uiControl(window));
uiMain();
Nuklear example:
struct nk_context ctx;
nk_init_default(&ctx, 0);
if (nk_begin(&ctx, "Hello", nk_rect(50, 50, 200, 200), NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) {
nk_layout_row_static(&ctx, 30, 80, 1);
if (nk_button_label(&ctx, "Click Me")) {
// Button clicked
}
}
nk_end(&ctx);
The code comparison shows that libui has a more straightforward API for creating basic UI elements, while Nuklear offers more fine-grained control over the UI layout and appearance. Nuklear's immediate mode approach allows for more dynamic UI updates, whereas libui follows a more traditional retained mode GUI paradigm.
A tiny immediate-mode UI library
Pros of microui
- Extremely lightweight and minimalistic (under 1000 lines of C)
- Easy to integrate into existing projects due to its simplicity
- No dependencies, making it highly portable
Cons of microui
- Limited set of UI elements compared to Nuklear
- Less customization options and styling capabilities
- Fewer advanced features like layout systems or complex widgets
Code Comparison
microui:
mu_begin(ctx);
if (mu_button(ctx, "Hello")) {
printf("Button pressed\n");
}
mu_end(ctx);
Nuklear:
if (nk_begin(ctx, "Window", nk_rect(50, 50, 200, 200),
NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
{
nk_layout_row_static(ctx, 30, 80, 1);
if (nk_button_label(ctx, "Hello")) {
printf("Button pressed\n");
}
}
nk_end(ctx);
The code comparison shows that microui has a simpler API with fewer options, while Nuklear provides more control over window properties and layout. microui's approach is more straightforward, but Nuklear offers greater flexibility and features at the cost of increased complexity.
Embedded graphics library to create beautiful UIs for any MCU, MPU and display type.
Pros of lvgl
- More comprehensive widget set and built-in themes
- Better suited for embedded systems and microcontrollers
- Active development and regular updates
Cons of lvgl
- Steeper learning curve due to more complex architecture
- Larger memory footprint compared to Nuklear
Code Comparison
lvgl example:
lv_obj_t * btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 100, 50);
lv_obj_center(btn);
lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_CLICKED, NULL);
Nuklear example:
if (nk_button_label(ctx, "Click me")) {
// Button clicked
}
lvgl offers a more object-oriented approach with separate creation and event handling, while Nuklear uses a more immediate-mode style with inline event checking. lvgl's code is more verbose but provides greater flexibility and control over widget properties and behaviors. Nuklear's code is more concise and straightforward, making it easier to quickly prototype simple UIs.
Both libraries have their strengths, with lvgl being more suitable for complex, feature-rich interfaces on embedded systems, and Nuklear excelling in simplicity and lightweight implementation for basic UI needs.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Nuklear
This is a minimal-state, immediate-mode graphical user interface toolkit written in ANSI C and licensed under public domain. It was designed as a simple embeddable user interface for application and does not have any dependencies, a default render backend or OS window/input handling but instead provides a highly modular, library-based approach, with simple input state for input and draw commands describing primitive shapes as output. So instead of providing a layered library that tries to abstract over a number of platform and render backends, it focuses only on the actual UI.
Features
- Immediate-mode graphical user interface toolkit
- Single-header library
- Written in C89 (ANSI C)
- Small codebase (~18kLOC)
- Focus on portability, efficiency and simplicity
- No dependencies (not even the standard library if not wanted)
- Fully skinnable and customizable
- Low memory footprint with total control of memory usage if needed / wanted
- UTF-8 support
- No global or hidden state
- Customizable library modules (you can compile and use only what you need)
- Optional font baker and vertex buffer output
- Documentation
Building
This library is self-contained in one single header file and can be used either in header-only mode or in implementation mode. The header-only mode is used by default when included and allows including this header in other headers and does not contain the actual implementation.
The implementation mode requires defining the preprocessor macro
NK_IMPLEMENTATION
in one .c/.cpp file before #include
ing this file, e.g.:
#define NK_IMPLEMENTATION
#include "nuklear.h"
IMPORTANT: Every time you include "nuklear.h" you have to define the same optional flags. This is very important; not doing it either leads to compiler errors, or even worse, stack corruptions.
Gallery
Example
/* init gui state */
struct nk_context ctx;
nk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font);
enum {EASY, HARD};
static int op = EASY;
static float value = 0.6f;
static int i = 20;
if (nk_begin(&ctx, "Show", nk_rect(50, 50, 220, 220),
NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) {
/* fixed widget pixel width */
nk_layout_row_static(&ctx, 30, 80, 1);
if (nk_button_label(&ctx, "button")) {
/* event handling */
}
/* fixed widget window ratio width */
nk_layout_row_dynamic(&ctx, 30, 2);
if (nk_option_label(&ctx, "easy", op == EASY)) op = EASY;
if (nk_option_label(&ctx, "hard", op == HARD)) op = HARD;
/* custom widget pixel width */
nk_layout_row_begin(&ctx, NK_STATIC, 30, 2);
{
nk_layout_row_push(&ctx, 50);
nk_label(&ctx, "Volume:", NK_TEXT_LEFT);
nk_layout_row_push(&ctx, 110);
nk_slider_float(&ctx, 0, &value, 1.0f, 0.1f);
}
nk_layout_row_end(&ctx);
}
nk_end(&ctx);
Bindings
There are a number of nuklear bindings for different languages created by other authors. I cannot attest for their quality since I am not necessarily proficient in any of these languages. Furthermore there are no guarantee that all bindings will always be kept up to date:
- Java by Guillaume Legris
- D by Mateusz MuszyÅski
- Golang by golang-ui@github.com
- Rust by snuk182@github.com
- Chicken by wasamasa@github.com
- Nim by zacharycarter@github.com
- Lua
- LÃVE-Nuklear by Kevin Harrison
- MoonNuklear by Stefano Trettel
- Python
- pyNuklear by William Emerison Six (ctypes-based wrapper)
- pynk by nathanrw@github.com (cffi binding)
- CSharp/.NET by cartman300@github.com
- V by Nicolas Sauzede
Credits
Developed by Micha Mettke and every direct or indirect contributor to the GitHub.
Embeds stb_texedit
, stb_truetype
and stb_rectpack
by Sean Barrett (public domain)
Embeds ProggyClean.ttf
font by Tristan Grimmer (MIT license).
Big thank you to Omar Cornut (ocornut@github) for his imgui library and giving me the inspiration for this library, Casey Muratori for handmade hero and his original immediate-mode graphical user interface idea and Sean Barrett for his amazing single-header libraries which restored my faith in libraries and brought me to create some of my own. Finally Apoorva Joshi for his single-header file packer.
License
Nuklear is avaliable under either the MIT License or public domain. See LICENSE for more info.
Reviewers guide
When reviewing pull request there are common things a reviewer should keep in mind.
Reviewing changes to src/*
and nuklear.h
:
- Ensure C89 compatibility.
- The code should work for several backends to an acceptable degree.
- Check no other parts of
nuklear.h
are related to the PR and thus nothing is missing. - Recommend simple optimizations.
- Pass small structs by value instead of by pointer.
- Use local buffers over heap allocation when possible.
- Check that the coding style is consistent with code around it.
- Variable/function name casing.
- Indentation.
- Curly bracket (
{}
) placement.
- Ensure that the contributor has bumped the appropriate version in clib.json and added their changes to the CHANGELOG.
- Have at least one other person review the changes before merging.
Reviewing changes to demo/*
, example/*
and other files in the repo:
- Focus on getting working code merged.
- We want to make it easy for people to get started with Nuklear, and any
demo
andexample
improvements helps in this regard.
- We want to make it easy for people to get started with Nuklear, and any
- Use of newer C features, or even other languages is not discouraged.
- If another language is used, ensure that the build process is easy to figure out.
- Messy or less efficient code can be merged so long as these outliers are pointed out and easy to find.
- Version shouldn't be bumped for these changes.
- Changes that improves code to be more inline with
nuklear.h
are ofc always welcome.
Top Related Projects
Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
A simple and easy-to-use immediate-mode gui library
A single-header ANSI C gui library
Simple and portable (but not inflexible) GUI library in C that uses the native GUI technologies of each platform it supports.
A tiny immediate-mode UI library
Embedded graphics library to create beautiful UIs for any MCU, MPU and display type.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot