‹ zgba 中国吧
EN
Blenders UI and Runtime: Much Faster Than GPUI

Blender’s UI and Runtime: Much Faster Than GPUI

Blender’s user interface, as a library you can use from Python, Rust, JavaScript (React, Svelte), C, C++ and Dear ImGui.

People spent decades building and optimizing Blender’s GUI. It’s battery and memory efficient, and super duper fast. We decoupled it, to give everyone a chance to build their own products with it. It supports multiple languages and frameworks, so you won’t miss a beat!

Website and full documentation: bui.preetham.top · Chat: Discord

This README is a small book. Read it front to back for the whole story, or jump to the chapter you need. Every chapter links to a longer guide in docs/ or on the website when there’s more to say.

Part II: Getting started

Part IV: Guides by language

Part VII: The project

BUI takes the user interface of Blender (its widget drawing, its interaction rules and its look) and turns it into a standalone UI library with a small C core. Your code builds the widget tree and handles callbacks. Layout, input, drawing and presenting all happen in fast native code, on the CPU or the GPU.

At the heart of BUI is the kit: a small runtime written in C. The kit holds every widget in one tree, lays them out, handles the mouse and keyboard, and draws them the way Blender does. The drawing code is a C port of Blender’s own widget code, and the interaction follows Blender’s rules. On top of the kit sit bindings: thin layers that let Python, Rust, JavaScript, C++ and Dear ImGui talk to it.

Blender’s interface is famous for how it feels. You press a number field and drag: the cursor vanishes, the value glides under your hand, and you never hit the edge of the screen. You type 2*pi into a field and it just works. You type “ad cu” into a menu and it finds “Add Cube”. Millions of artists have these habits in their hands.

That interface is also fast and frugal. It redraws only what changed, sleeps when nothing does, and starts in milliseconds. BUI exists so that any app, in any language, can have both: Blender’s feel, and Blender’s efficiency.

Before you ship something with BUI, read the known limitations: no accessibility support yet, no input methods, and it looks like Blender, not like your operating system.

You can drive BUI many ways, and all of them share the same C runtime, so they all get the same widgets and interactions:

Not sure which to pick? If you already have code, use the row that matches it. If you’re starting fresh in Python, the Blender components are the friendliest.

Every screenshot here is a real BUI window, rendered off-screen. Where an image comes in a dark and a light version, GitHub shows the one that matches your theme.

The node editor, from Python (examples/site/geometry_nodes.py)

A pie menu, and Blender’s menu search (type in any open menu)

The color picker, and a tooltip

CSS effects in Rust: filters, clip-path, transforms, blend modes, backdrop-filter (site_effects.rs)

CSS grid with repeat(auto-fill, minmax()), spans and grid-auto-flow: dense (site_grid.rs)

CSS @keyframes at 0.25 s, 0.6 s and 1.0 s (site_animation.rs)

examples/showcase.rs: HTML + CSS in Rust

Dear ImGui’s demo with its own widgets, in Blender’s theme

Qt syntax

tkinter programs: text with tags, canvas, dialogs

Python. You need CPython 3.11 or newer. Wheels are published for Windows, Linux and macOS, so there’s nothing to compile. One package gives you all four Python APIs (tkinter syntax, Qt syntax, the Blender components and Dear ImGui):

Import it as blenderui. You’ll also see import bui in older examples: it’s the same code under its original name, but an unrelated project owns bui on PyPI, so prefer blenderui in anything you publish.

Rust. The crate is blenderui on crates.io:

The first build compiles BUI’s C kit for you, so you need Rust 1.88 or newer, CMake and a C compiler (on Windows, the Visual Studio Build Tools for the default MSVC target), and on Linux the X11 headers (libx11-dev or libX11-devel; no GL headers are needed).

JavaScript. You need Node.js 18 or newer, or Bun:

The npm packages are prebuilt for Windows x64. On Linux, build the addon from a clone (npm install then npm run build in bindings/, with Rust, CMake and a C compiler); windows are native X11 windows there. On macOS, JavaScript runs headless for now (see Platforms).

C and C++. Build from source with CMake 3.20+ and a C11 / C++20 compiler (MSVC, GCC or MinGW-w64, or Clang); on Linux, also the X11 headers:

In your own CMake project, add BUI as a subdirectory and link bui::kit (or bui::imgui for Dear ImGui):

Dear ImGui. Python gets it with pip install blenderui (import blenderui.imgui). C++ links bui::imgui, C links bui_cimgui. Rust uses the blenderui-imgui crate:

If something goes wrong:

More: docs/getting-started.md and Install BUI on the website.

Run any tkinter program on BUI without changing a line:

blenderui-tk makes import tkinter return BUI’s implementation for that run. Or opt in from code:

That snippet is only a window with an entry and a button. These two are larger, unchanged programs from examples/site/, running on BUI:

Unchanged tkinter and ttk programs (examples/site/tk_export.py, ttk_queue.py)

Number fields (Spinbox, Scale) scrub like Blender’s, Ctrl+Z / Ctrl+Shift+Z undo edits, and filedialog opens Blender’s File Browser. Guide: docs/tkinter.md.

Build with Blender’s own components:

That snippet is a small window. This is a bigger program built from the same components, a Render Properties editor:

A Render Properties editor from the components (examples/site/render_props.py)

There are 45 components: layout, values, buttons, views, menus and pie menus, the color picker, the color ramp, curve and node editors, areas and templates. Reference: docs/components.md.

Write Qt-style Python. The import is the only line that differs from PySide or PyQt, and neither is needed:

A bigger program in the same syntax, a material editor (not the output of the snippet above):

Qt syntax (examples/site/qt_material.py)

Qt syntax is partial (about 24% of Qt’s method names on the main widget classes); anything missing raises AttributeError. Guide: docs/qt.md.

BUI’s Rust crate has two first-class syntaxes, and they draw the same window:

In rsx! (this is bindings/rust/blenderui/examples/hello.rs; run it with cargo run —release —example hello in bindings/rust):

In gpui builders, the same window:

Two small things that trip people up in rsx!:

Here’s a bigger example, a render-farm dashboard, written once in each syntax. The two programs draw identical pixels:

site_dashboard.rs (rsx!) and site_dashboard_builder.rs (gpui builders)

Guide: docs/rust.md, and the Rust tutorial on the website.

Without React, @blender-ui/native gives you a DOM-like API:

These snippets are small. This is a larger example, a task list in React, and not the output of the code above:

A task list in React (examples/site/js/todo_react.js); the DOM-like version draws the same

Node.js 18+ or Bun. Prebuilt for Windows x64; on Linux, build the addon from source (npm run build in bindings/node) and windows are native. Guide: docs/javascript.md.

The real Dear ImGui 1.93 runs on BUI: BUI’s windows, input, CPU/GPU renderer, Blender’s theme and the Inter font. Existing ImGui code compiles unchanged.

C (cimgui.h, cimgui conventions: ImGui_Button, ImGui_ButtonEx, and the backend in cimgui_impl_bui.h) and Rust (blenderui-imgui) work the same way:

Build with -DBUI_IMGUI_BLENDER_WIDGETS=ON (or the Rust feature blender-widgets) and ImGui’s widgets become Blender’s own: DragFloat is Blender’s drag-to-scrub number field (Shift for precision, Ctrl to snap), SliderFloat Blender’s number slider, checkboxes drag-toggle, menus and combos get Blender’s menus. The rest of the ImGui API is unchanged. (The PyPI wheel is built without it, so from Python you get ImGui’s own widgets in Blender’s theme unless you build from source.)

Dear ImGui’s own demo with BUI_IMGUI_BLENDER_WIDGETS=ON: number fields, sliders, color rows and panel headers are Blender’s

A larger example, a scene inspector, once with ImGui’s stock widgets and once with Blender’s:

The same ImGui code: ImGui’s widgets (left) and the Blender-widgets build (right) (examples/site/imgui_inspector.cpp)

Guide, coverage and the stock look: docs/imgui.md.

The kit’s API is one header, kit/include/BUI_kit.h, and it doubles as the reference: every function has a one-line comment. This is a shortened examples/kit_hello.c: a slider and a button in a native window.

The window below is a bigger program than the one above, a modifier stack:

A bigger C program: a modifier stack (examples/site/kit_modifiers.c)

Without a window system, render into a raster instead (BK_render(ctx, raster, w, h, full)), which is also how tests and screenshots work. Guide: docs/c-api.md.

What’s under the hood:

More: ARCHITECTURE.md and How it works.

These rules live in the C kit, so they work the same everywhere Blender widgets are drawn: the Python components, tkinter and Qt syntax, the Rust and JavaScript Blender components and form controls inside styled, ImGui’s Blender-widgets build, and every C kit widget.

Coming soon: typing values with units (“2 m”), Blender’s search-as-you-type popups, and widget drag and drop. More: Blender’s widgets.

In Rust and JavaScript you pick the look per element:

The components are Button, Checkbox, Radio, NumberField, NumberSlider, TextField, TextArea, ColorSwatch, Dropdown and ProgressBar. Each one is the HTML element it stands for, so every attribute, style and event works on it:

cargo run —example forms: plain HTML, inside styled, and the Blender components

The same markup, plain (left) and inside styled (right). Plain HTML looks the same in both themes.

Blender components from Rust (site_components.rs)

Python’s Blender components (Panel, PieMenu, the node editor …) are a separate, larger set.

BUI has two renderers, and they draw the same pixels.

The shaders evaluate the software raster’s formulas: the parity test finds 10 of 172,800 pixels that differ by more than 3/255, on both backends.

BUI_GPU=1 overrides the app-wide setting in code; BUI_GPU=0 turns the app-wide defaults off, but a window that asks for the GPU itself still gets it. Where no device can start, BUI quietly stays on the CPU (BUI_GPU_DEBUG=1 says why).

Which one? A tool window, form or settings panel: the CPU (lightest on memory, idles at zero). A large or HiDPI window, lots of animation, thousands of items: the GPU (about half the CPU per frame, or less, for about 10 MB more RAM plus GPU memory). Servers and tests: the CPU. macOS: the CPU, for now (a GPU renderer there is coming soon).

Leave a BUI window open and walk away: it uses no CPU at all. Hover a button, and BUI redraws that button, not the window.

On the full component demo, that’s about 0.7 ms for a complete frame and about 0.05 ms for a hover or number-scrub frame. Animations run only while something moves, paced to the display. More: Damage rendering.

A window host puts a kit context in a top-level window and feeds it input.

BUI_UI_SCALE=1.5 fixes the UI scale instead of following the display (1 is Blender’s default, 20 px widgets). More: Window hosts.

Your app’s text looks the same on Windows, Linux and macOS, and it looks like Blender’s:

Limits worth knowing: no per-glyph font fallback yet (missing characters show as boxes), no IME, right-to-left text is reordered but not shaped, no OpenType features. Font fallback and IME are coming soon. More: Text and fonts.

BUI looks like Blender because it uses Blender’s theme. It ships two: Blender’s Dark theme (the default) and its Light preset. Both are generated by tools/gen_theme.py from Blender’s own Blender_Dark.xml and Blender_Light.xml presets, over Blender 5.x’s built-in defaults. Switch at run time, and every open window relayouts and redraws:

Widgets, panels, the region background, the styled HTML sheet and ImGui’s Blender style all follow the theme. Plain HTML keeps a browser’s look either way. Inside each theme you can still color things yourself: bg / fg in tkinter, setStyleSheet in Qt syntax, color= on components, full CSS on HTML in Rust and JavaScript, ImGui’s own style colors.

BUI also includes Blender’s icons: all 781 of Blender’s SVG icons, rasterized with Blender’s NanoSVG code so they’re sharp at any scale. Use them by Blender’s name: Button(“Add”, icon=“ADD”), EnumRow(…, icons=[…]).

Coming soon: loading any Blender theme file, beyond Dark and Light. More: Theming.

pip install blenderui gives you four APIs in one package:

You can mix them in one process: windows, timers and the event loop are shared (bui.host). Every interaction runs in C, so tests can drive widgets headless. On the website: tkinter, Qt syntax, components, headless testing.

The blenderui crate is a web-like framework drawn by BUI: every HTML element, CSS, Tailwind, HTML-like markup (rsx! / view!) or gpui-style builders, components and hooks. A taste:

Not yet: async resources (use_resource),

View original article