Raven.
A GUI library in C.
A GUI library in C.
Raven
Lightweight, multithreaded, written in C11 with no dependency. Write the interface and its code in one file, in C, C++, Rust, Python, Go, C#, Zig or Lua, and build it with the official IDE.
View on GitHubOne file, any languageThe IDEGet startedOpen source
What you can do
How it works
Describe the interface in C, in XML, or both. Raven handles windows, layout, painting and the GPU.
Rinit(R_BACKEND_VULKAN). Raven opens its own windows and loads Vulkan at run time: nothing to link.
Build the tree with the C API, write it in XML, or mix both. Every object is a Rid, checked on every call.
One frame per call. A game never waits: while (Rdraw_frame()). A tool sleeps until something changes: while (Rwait_frame(-1.0)).
#include <Raven.h>
static void on_clicked(Rid button, void* user) { Rquit(0); }
int main(void) {
Rinit(R_BACKEND_VULKAN);
Rid window = Rwindow_create("Hello", 420, 220, R_WINDOW_DEFAULT);
Rid box = Rwidget_create(R_WIDGET_VBOX);
Rwindow_set_content(window, box);
Rwidget_add_child(box, Rlabel_create("Hello from Raven"));
Rid quit = Rwidget_add_child(box, Rbutton_create("Quit"));
Rbutton_set_clicked_callback(quit, on_clicked, NULL);
while (Rwait_frame(-1.0)) {}
Rshutdown();
}<Window Title="Hello" Width="420" Height="220"> <VBox Spacing="12" Slot.HAlign="Center"> <Label>Hello from Raven</Label> <Button Text="Quit" OnClicked="app.quit"/> </VBox> </Window> <!-- the same window, loaded with Rwindow_create_from_xml_file("hello.xml") -->
New · XMLC
Write the window in XML and its code in <script> beside it. ravenc compiles the XML into your language: your compiler checks every callback and every widget, your usual tools build it, and no XML is read at run time.
<!-- src/main.xmlrs: a whole Rust program --> <script> use raven::*; use std::sync::atomic::{AtomicI32, Ordering}; static CLICKS: AtomicI32 = AtomicI32::new(0); // OnClicked="{on_hello}" below: checked by rustc fn on_hello(_sender: Rid, _action: &str) { let n = CLICKS.fetch_add(1, Ordering::SeqCst) + 1; let text = cstr(&format!("{} clicks", n)); // ui().status: the widget Name="status" unsafe { Rlabel_set_text(ui().status, text.as_ptr()) }; } fn main() { unsafe { Rinit(R_BACKEND_VULKAN) }; main_create(); unsafe { while Rdraw_frame() != 0 {} Rshutdown() }; } </script> <Window Title="Hello" Width="400" Height="200"> <VBox Spacing="12" Slot.Padding="24"> <Label Name="status">Not clicked yet</Label> <Button Text="Click me" OnClicked="{on_hello}"/> </VBox> </Window>
OnClicked="{on_hello}" calls a function of your scripts and ui().status is the widget named status. A typo is a compile error, not a silent button.
The scripts keep their line numbers (#line in C and C++). rustc says main.xmlrs:12, and the IDE opens it there.
Any header, crate or package, no XML escaping, no generated header. Plain .xml stays interpreted with live reload while you design.
# C and C++: CMake add_executable(hello main.xmlc) target_link_libraries(hello PRIVATE raven::raven) raven_target_xmlc(hello) // Rust: build.rs fn main() { raven_build::compile("src/main.xmlrs"); }
The official IDE
The IDE of Raven, made with Raven. A new project in any of the eight languages builds as it is; the interface is edited visually next to its code; F5 builds and runs it with the tools of the language.
fn on_hello(_s: Rid, _a: &str) { let n = CLICKS.fetch_add(1, SeqCst); let t = cstr(&format!("{} clicks", n)); unsafe { Rlabel_set_text(ui().statut, t.as_ptr()) }; }
C, C++, Rust, Python, Go, C#, Zig or Lua: the main.xml…, the files of the language's own tools (CMakeLists.txt, Cargo.toml, go.mod, .csproj, build.zig) and the translations.
Widgets, tree, live preview, properties and XML show the same document; each <script> opens in a tab of its language. Saving keeps your comments and your layout.
The whole API read from the headers, the widgets of the interface (ui.<Name>) and the keys of Rtr("…") while you type.
CMake, Cargo, go, dotnet, zig, Python, LuaJIT, with the environment set from the Raven package. Errors of GCC, Clang, MSVC, rustc and Go land on the line of your .xml….
The CSV files of the project as a grid, one column per language. The preview switches language, right to left included.
Docking, header bar, text editors, tree views: the IDE uses the public API only. What it does, your tools can do.
Example projects
From one window in eight languages to a complete 3D scene editor written in .xmlrs.

A visual editor of 3D scenes for Bevy. Its whole interface, and all the code behind it, is one file: editor.xmlrs, about 1,450 lines of Raven XML and Rust, compiled by ravenc when Cargo builds.
The same window, a button and a counter translated in English and French, as main.xmlc, .xmlc++, .xmlrs, .xmlpy, .xmlgo, .xmlcs, .xmlzig and .xmllua: exactly what the IDE creates, each built by its own tools.
Node graphs, timelines, docking, glass, text editors, web pages, viewports: below, the ones to read first. Six more in the repo: hello, components, memory, overlay and two viewport demos (Vulkan, OpenGL).
Get started
CMake 3.16+ and a C11 compiler. On Linux, the X11 development package (libx11-dev). The Vulkan headers are downloaded when no SDK is found.
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release cmake --build build --config Release cd build && ctest -C Release --output-on-failure
add_subdirectory(raven) target_link_libraries(app PRIVATE raven::raven)
License
Raven is open source under the Apache License 2.0. No watermark, no paid edition, no royalties: what you make with it is yours, and Raven itself is yours to study, fork and improve.
Every widget, every platform, every binding. Nothing is held back, nothing to unlock.
Personal or commercial, open or closed source. Sell it, ship it, use it at work.
The whole source is on GitHub. Fork it, patch it, send a pull request.
Watch