Blender's UI and Runtime: Much Faster Than GPUI

Hacker News by 61 min read 504x views
Blender's UI and Runtime: Much Faster Than GPUI

Share Post

BUI Logo

Blender's person interface, as a archive you can use from Python, Rust, JavaScript/React, C, C++ and Dear ImGui.

People spent decades construction and optimizing Blender's GUI. It's power division and recollection efficient, and excellent duper fast. We decoupled it, to provision everyone a chance to build their own products alongside it. It supports multiple languages and frameworks, so you won't young female a beat!

PyPI Python crates.io @blender-ui/react Wheels  GPL-2.0-or-later Platforms

Website and complete documentation: bui.preetham.top

 panels, figure sliders, vector fields, checkboxes and a color swatch An unmodified tkinter program operating on BUI

This README is a small book. Read it forefront to rear for the entire story, or jump to the division you need. Every division links to a longer guide in docs/ or on the website whenever there's more to say.

Part I: Welcome

  1. What BUI is
  2. Why BUI exists
  3. Who it's for
  4. The many ways in
  5. Features at a glance
  6. A gallery

Part II: Getting started

  1. Install
  2. First app: tkinter
  3. First app: Blender components
  4. First app: Qt syntax
  5. First app: Rust, in rsx and gpui builders
  6. First app: JavaScript and React
  7. First app: Dear ImGui
  8. First app: C

Part III: Concepts

  1. How it works
  2. Blender's widgets and interactions
  3. Three looks: HTML, styled and Blender components
  4. Rendering on the CPU and the GPU
  5. Damage rendering
  6. Window hosts
  7. Text and fonts
  8. Themes: dreary and light

Part IV: Guides by language

  1. Python
  2. Rust
  3. JavaScript and React
  4. Dear ImGui
  5. C and embedding
  6. Where the docs live

Part V: Performance

  1. Before you peruse the numbers
  2. Start period and battery
  3. Frame times
  4. JavaScript and React: startup and animation
  5. Run the benchmarks yourself

Part VI: Reference

  1. Platforms
  2. Environment variables
  3. Building from origin and CMake options
  4. Coverage
  5. Repository layout
  6. Examples

Part VII: The project

  1. Status and roadmap
  2. FAQ
  3. Contributing and publishing
  4. License and credits

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

At the bosom of BUI is the kit: a small runtime written in C. The kit holds all widget in one tree, lays them out, handles the mouse and keyboard, and draws them the way Blender does. The example code is a C harbor of Blender's own widget code, and the communication follows Blender's rules. On top of the kit sit bindings: lean layers that let Python, Rust, JavaScript, C++ and Dear ImGui conversation to it.

What BUI is not:

  • Not Blender. It contains the parts of Blender's UI code it needs and builds on its own. You don't need Blender installed, and you don't need to know Blender to use it.
  • Not a browser. The Rust and JavaScript sides use HTML and CSS as a UI language, but there's no browser engine, no webview and no network.
  • Not a re-imagining. The widget example is ported from Blender's interface_widgets.cc, and the Dear ImGui assistance runs the genuine Dear ImGui.

Blender's interface is celebrated for how it feels. You media a figure site and drag: the cursor vanishes, the value glides under your hand, and you never hit the border of the screen. You category 2*pi into a site and it fair works. You type "ad cu" into a list and it finds "Add Cube". Millions of artists have these habits in their hands.

That interface is additionally accelerated and frugal. It redraws lone 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.

  • You have a tkinter app and desire it looked small akin 1998. Run it on BUI, unchanged.
  • You're construction a tool for artists who already cognize Blender. Give them the panels, sliders and shortcuts their hands expect.
  • You compose Rust or React and desire a native desktop UI without shipping a browser.
  • You use Dear ImGui and desire it to appearance and awareness akin Blender, alongside one build flag.
  • You're curious how a UI toolkit works. The origin is readable, and the concepts are explained in plain words.

You can run BUI many ways, and all of them portion the identical C runtime, so they all get the identical widgets and interactions:

You write You get Status
tkinter code, equal existing programs, unchanged Blender-styled apps; all tkinter and ttk API Complete
Qt-style Python (QWidget, layouts, clicked.connect) The average subset of Qt widgets Partial
Blender components (Panel, NumberSlider, PieMenu, the node publishing company ...) 45 native Blender widgets and editors, from Python; ten of them additionally from Rust and JavaScript Complete
Rust: HTML + CSS + Tailwind, HTML-like markup (rsx! / view!), hooks, or gpui / zopra syntax A web-like framework: HTML that looks akin a browser's, Blender's appearance alongside styled, and Blender components (<NumberSlider>, <Button> ...) Working
JavaScript / React on Node.js or Bun: a DOM-like API or JSX The identical motor and components in native windows, complete napi-rs; React's hooks backed by signals Working
Dear ImGui from C++, C, Python or Rust The genuine Dear ImGui on BUI windows in Blender's theme, or a build anywhere ImGui's widgets are Blender's widgets Working
C (BUI_kit.h) The kit itself: nodes, widgets, windows Working
MyGo MyGo Not yet (coming soon)

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

Blender's widgets and interactions

  • Number sectors you drag alongside a hidden, uninterrupted cursor: Shift for precision, Ctrl to snap.
  • Math in figure fields, alongside Blender's own expression evaluator: 2*pi, min(4, 3), round(1.7), x if c alternatively y.
  • Ctrl+Wheel steps values, Ctrl+C / Ctrl+V copy values, Backspace resets.
  • Drag throughout checkboxes to set them all.
  • Press-drag-release menus, pie menus, and Blender's fuzzy list search: "ad cu" finds "Add Cube", typos are forgiven, latest picks position first.
  • Ctrl+Z / Ctrl+Shift+Z on all UI edit, and inner a content site during you type; Tab between fields.
  • Blender's drift display precision, multi-field vertical drags, and panels that downfall alongside Blender's animation.
  • The HSV color wheel, color ramps, curves, trees, lists, content areas, canvases, a node publishing company and Blender's File Browser.
  • Blender's Dark and Light themes, switchable at run time.
  • tkinter: all 7,846 community names of tkinter and ttk. Nine genuine programs behave identically on the norm archive and on BUI.
  • Qt syntax: widgets, layouts, signals, QPainter, menus and timers.
  • Components: 45 Blender widgets, editors and templates.
  • Dear ImGui: from blenderui import imgui, pyimgui-style.
  • One pip install, no Qt or Tk widgets example anything.

Rust: the web platform, natively

  • All 113 HTML elements, drawn akin a browser draws them; styled gives any subtree Blender's look, and Blender components (<NumberSlider>, <Button>, <ColorSwatch> ...) are genuine Blender widgets.
  • Modern CSS: flexbox, grid alongside named areas, tables, calc() and all math function, var(), oklch() and color-mix(), :has(), nesting, @layer, @media ranges, @container, ::before/::after, counters.
  • Effects and motion: @keyframes animations and transitions, filters, backdrop-filter, blend modes, clip-path, masks, 2D transforms, border-image.
  • Tailwind CSS v4: class="md:hover:bg-sky-500/50" or naked attributes (<div p-4 bg-[#4772b3]>), alongside "did you mean" compile errors.
  • rsx! / view! HTML-like markup, #[component], and hooks in zopra, React or Leptos manner (use_state, signal, Memo, Effect, context).
  • gpui-compatible syntax too: div().flex().gap_2(), Render, cx.listener.
  • On crates.io: cargo add blenderui.
  • Damage rendering: an idle UI expenses 0% CPU, and a hover redraws lone the widget it touches.
  • Opt-in GPU renderer (Direct3D 11 on Windows, OpenGL 3.3 on Linux), modeled on Blender's instanced widget drawing. It draws the identical pixels as the CPU raster.
  • In the benchmark, 2–4× small CPU per example than gpui-fast, alongside less RAM and a ~5 ms archetypal frame.
  • Blender's text: Inter (Blender's UI font) is embedded and rendered alongside FreeType the way Blender renders it, so content looks the identical on all platform. On the GPU, glyphs are drawn from their outlines alongside Slug, falling rear to a per-glyph atlas akin Blender's.
  • One decoder set for all language, in C: PNG, GIF, BMP, TGA, QOI (Wuffs, memory-safe), JPEG (libjpeg-turbo), WebP including animated (libwebp), Radiance HDR, PNM and SVG. The scheme is Blender's imbuf: one depiction category and a format table.
  • Decoded at the size it is drawn, off the UI thread: JPEG thumbnails use DCT scaling (a 4K photo becomes a 256 px thumbnail in ~12 ms), apparent images first, scrolled-away requests cancelled, and lone the image's rectangle redraws whenever it arrives. The leaf never jumps: sizes arrive from the document header.
  • One memory-budgeted cache (256 MiB by default). Scrolling 1,000 photo thumbnails: 2.9 ms p99 frames and 100 MB, against 96 ms and 2.5 GB whenever decoding on the UI thread; 0 allocations in a settled frame, all obstacle freed at exit. Images.
  • Animated GIF and WebP play everyplace an depiction shows, decoded one example at a period at the size drawn (two frames held per animation), all example for its own delay, lone the image's rectangle repainting. Off screen, scrolled distant or in a hidden opening they pause: 200 animations at formerly obtain 0.76 ms p50 / 1.5 ms p99 render frames, and nothing at all formerly off screen. example holds one frame; reduced motion holds them all.
  • Large images on the GPU: images complete 2047 px get a texture of their own on Direct3D 11 and OpenGL (tiled lone former the equipment limit), freed alongside the image.
  • <img>, CSS background-image, object-fit, Blender Image components, tkinter PhotoImage (now additionally JPEG, WebP, BMP, TGA, QOI, HDR, SVG), canvas items, data-table depiction columns, chat-list media and Dear ImGui textures (animated ones too).
  • React 19.3 renders to BUI: HTML presenter components, CSS and Tailwind, events, Suspense, transitions, actions, and Blender components (<NumberSlider>, <Button> ...). BUI draws them, on the CPU or the GPU; there's no browser and no webview.
  • React's hooks, by React's names, holding signals: continue one into JSX ({count}) and a alter updates that one node without re-rendering; peruse it during rendering (count.value) and the component re-renders, as alongside React. A conformance suite checks all hook against React's own.
  • @blender-ui/native: a DOM-like API (createElement, appendChild, addEventListener) alongside the identical signals, for apps without React.
  • Node.js and Bun, through a napi-rs addon, alongside headless manner for tests.
  • bui build app.jsx produces one executable of concerning 7 MB: BUI alongside an embedded QuickJS engine.
  • First example in ~70 ms, at 19 MB of RAM, alongside nothing to install. There's no browser and no webview.
  • --bun builds a Bun executable instead, alongside Node's APIs and a JIT.
  • Builds obtain under a second: the app's bundle is appended to a prebuilt runtime.
  • The genuine Dear ImGui 1.93: all function of imgui.h works, including ShowDemoWindow().
  • Four languages: C++ (drop-in imgui.h), C (cimgui.h, all 399 functions), Python and Rust (generated from imgui.h).
  • Blender's look: Blender's theme colors and metrics alongside Inter; or, alongside BUI_IMGUI_BLENDER_WIDGETS=ON, Blender's genuine widgets and interaction, pixel-identical to BUI's own.
  • Idle expenses nothing: frames run lone on input and during item animates.
  • Native windows on Windows (Win32) and Linux (X11, Wayland through XWayland), and an experimental Cocoa presenter for macOS ported from Blender's GHOST.
  • HiDPI: per-monitor DPI on Windows, Xft.dpi on Linux, Retina on macOS.
  • Headless mode for tests and screenshots, alongside a virtual clock that steps animations exactly.
  • On Linux, libX11 and libGL are loaded at run time, so BUI imports on servers without them.

Every screenshot current is a genuine BUI window, rendered off-screen. Where an image comes in a dreary and a ray version, GitHub shows the one that matches your theme.

 seven nodes alongside typed sockets, colored links and header menus
The node editor, from Python (examples/site/geometry_nodes.py)

A Shading pie list open complete a node editor  Blender's fuzzy hunt through submenus
A pie menu, and Blender's list hunt (type in any open menu)

 HSV wheel, value strip, HSV sliders, hex site and eyedropper A tooltip on a Denoise dropdown
The color picker, and a tooltip

 filters, clip-path shapes, transforms, blend modes and backdrop-filter on a gradient landscape
CSS effects in Rust: filters, clip-path, transforms, blend modes, backdrop-filter (site_effects.rs)

 auto-fill columns, spans and compact packing
CSS grid alongside repeat(auto-fill, minmax()), spans and grid-auto-flow: compact (site_grid.rs)

 a spinner, a advancement sweep, a bouncing domain and a fading toast
CSS @keyframes at 0.25 s, 0.6 s and 1.0 s (site_animation.rs)

More screenshots

 a stylesheet, grid cards, Blender form widgets, a array and lists
examples/showcase.rs: HTML + CSS in Rust

Dear ImGui's demo in Blender's theme, alongside ImGui's own widgets
Dear ImGui's demo alongside its own widgets, in Blender's theme

Qt syntax on BUI
Qt syntax

tkinter Text alongside tags tkinter Canvas tkinter messagebox
tkinter programs: content alongside 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 bundle gives you all four Python APIs (tkinter syntax, Qt syntax, the Blender components and Dear ImGui):

pip instal blenderui python -c "import blenderui; print(blenderui.__version__)"

Import it as blenderui. You'll additionally see import bui in older examples: it's the identical code under its first name, but an unrelated project owns bui on PyPI, so favor blenderui in item you publish.

Rust. The crate is blenderui on crates.io:

The archetypal 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:

npm instal @blender-ui/react react # or: bun add @blender-ui/react react npm instal @blender-ui/native # the DOM-like API, without React

@blender-ui/react @blender-ui/native

The npm packages are prebuilt for Windows x64. On Linux, build the addon from a copy (npm instal afterward 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 origin alongside CMake 3.20+ and a C11 / C++20 compiler (MSVC, GCC or MinGW-w64, or Clang); on Linux, additionally the X11 headers:

git copy https://github.com/ppmpreetham/BUI && cd BUI cmake -S . -B build cmake --build build -j 2 ctest --test-dir build # optional: run the test suites

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

add_subdirectory(BUI) target_link_libraries(myapp PRIVATE bui::kit)

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

cargo add blenderui-imgui

If item goes wrong:

Symptom Fix
ImportError: buipy You're operating from a origin checkout without a build. Build archetypal (cmake --build build), or set BUIPY_BUILD_DIR. The expansion must equivalent your Python version.
The opening never appears Start the event loop: mainloop(), app.exec() or App.run().
Blurry or small UI Set BUI_UI_SCALE, for example BUI_UI_SCALE=1.25.
gpu=True does nothing Run alongside BUI_GPU_DEBUG=1 to see why the GPU equipment didn't start. Without Direct3D 11 or OpenGL 3.3, BUI stays on the CPU renderer, which draws the identical pixels.

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

Run any tkinter program on BUI without changing a line:

blenderui-tk my_app.py # identical as: python -m bui.tksyntax my_app.py

blenderui-tk makes import tkinter come back BUI's implementation for that run. Or opt in from code:

import blenderui.tksyntax as tk from blenderui.tksyntax import ttk, messagebox root = tk.Tk() name = tk.StringVar(value="Cube") ttk.Entry(root, textvariable=name).pack(fill="x", padx=8, pady=8) ttk.Button(root, text="Greet", command=lambda: messagebox.showinfo("Hi", "Hello " + name.get())).pack() root.mainloop()

 a glTF export dialog alongside entries, checkbuttons, broadcast buttons, a spinbox, an choice menu, a measure and a listbox  a render-farm queue alongside a combobox, notebook, treeview and advancement bar
Unchanged tkinter and ttk programs (examples/site/tk_export.py, ttk_queue.py)

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

9. First app: Blender components

Build alongside Blender's own components:

from blenderui.components import App, Panel, NumberSlider, VectorField, Checkbox, ColorSwatch, Button App("Object", (420, 520), Panel("Transform", VectorField("Location", (0.0, 1.25, 0.0)), NumberSlider("Scale", 1.0, min=0, max=10, on_change=print)), Panel("Shading", Checkbox("Shadows", True), ColorSwatch("Color", (0.8, 0.3, 0.1, 1.0))), Button("Apply", on_click=lambda: print("apply")), ).run()

 menus, flank tabs, panels alongside header checkboxes, figure fields, sliders, dropdowns and a color swatch
A Render Properties publishing company 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 lone row that differs from PySide or PyQt, and neither is needed:

import sys from blenderui.qtsyntax import (QApplication, QWidget, QVBoxLayout, QFormLayout, QLineEdit, QComboBox, QSlider, QProgressBar, QPushButton, QLabel, Qt) app = QApplication(sys.argv) window = QWidget() window.setWindowTitle("Export") layout = QVBoxLayout(window) form = QFormLayout() kind = QComboBox() kind.addItems(["glTF", "FBX", "OBJ"]) quality = QSlider(Qt.Horizontal) quality.setRange(0, 100) form.addRow("Format:", kind) form.addRow("Quality:", quality) layout.addLayout(form) bar = QProgressBar() quality.valueChanged.connect(bar.setValue) layout.addWidget(bar) status = QLabel("Ready.") go = QPushButton("Export") go.clicked.connect(lambda: status.setText("Exporting as " + kind.currentText())) layout.addWidget(status) layout.addWidget(go) window.show() sys.exit(app.exec())

 a list, row edit, collection box alongside a form layout, combo box, slider alongside rotation box, checkbox and advancement bar
Qt syntax (examples/site/qt_material.py)

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

11. First app: Rust, in rsx and gpui builders

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

  • rsx! is HTML-like markup inner a macro, alongside #[component] functions and hooks for state.
  • gpui builders are plain method chains: div().flex().gap_3().child(...). State lives in your perspective struct, and cx.listener updates it. gpui code compiles against BUI too.

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

use blenderui::prelude::*; #[component] fn counter(label: &str) { let (count, set_count) = use_state(0); rsx! { <div flex items-center gap-3 p-4 rounded-xl bg-zinc-800> <span text-zinc-300>{label.to_string()} ": " {count().to_string()}</span> <div px-3 py-1 rounded-md bg-sky-700 hover:bg-sky-500 onClick={move || set_count(count() + 1)}> "Add one" </div> </div> } } struct Hello; impl Render for Hello { fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement { rsx! { <body m-0 p-6 min-h-screen flex flex-col gap-4 bg-zinc-900 text-white> <h1 text-2xl font-bold>"Hello, BUI"</h1> <counter label="Clicks" /> <NumberSlider min={0.0} max={10.0} value="5" /> // a genuine Blender slider </body> } } } fn main() { Application::new().run(|cx| { cx.open_window(WindowOptions::default(), |_, cx| cx.new(|_| Hello)).unwrap(); }); }

In gpui builders, the identical window:

use blenderui::prelude::*; struct Hello { count: i32 } impl Render for Hello { fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { let oppose = div().flex().items_center().gap_3().p_4().rounded_xl().bg(rgb(0x27272a)) .child(span().text_color(rgb(0xd4d4d8)).child(format!("Clicks: {}", self.count))) .child(div().px_3().py_1().rounded_md().bg(rgb(0x0369a1)) .hover(|s| s.bg(rgb(0x0ea5e9))).cursor_pointer() .child("Add one") .on_click(cx.listener(|this, _, _, cx| { this.count += 1; cx.notify(); }))); body().m_0().p_6().css("min-height", "100vh").flex().flex_col().gap_4() .bg(rgb(0x18181b)).text_color(white()) .child(h1().text_2xl().font_bold().child("Hello, BUI")) .child(counter) .child(NumberSlider().min(0.0).max(10.0).value("5")) // a genuine Blender slider } } fn main() { Application::new().run(|cx| { cx.open_window(WindowOptions::default(), |_, cx| cx.new(|_| Hello { count: 0 })).unwrap(); }); }

 a heading, a oppose component and a Blender slider

Two small things that trip group up in rsx!:

  • Text children are content (&'static str, String, SharedString) or elements. Numbers and borrowed &str props aren't, so write {count().to_string()} and {label.to_string()}.
  • A component's build is a normal obstacle that ends in markup, normally an rsx!.

Here's a bigger example, a render-farm dashboard, written formerly in all syntax. The two programs diagram identical pixels:

 a CSS grid of stat cards, job rows alongside Blender advancement bars, a node list, a dropdown, clasp and checkbox
site_dashboard.rs (rsx!) and site_dashboard_builder.rs (gpui builders)

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

12. First app: JavaScript and React

/** @jsxImportSource @blender-ui/react */ import { render, useState, NumberSlider } from "@blender-ui/react" function Counter() { const [count, setCount] = useState(0) // React's hook, holding a signal return ( <main styled className="p-6 flex flex-col gap-3"> {" "} {/* `styled`: Blender's appearance */} <span>Clicks: {count}</span> <button onClick={() => setCount((c) => c + 1)}>Add one</button> <NumberSlider min={0} max={10} /> {/* a Blender component */} </main> ) } render(<Counter />, { title: "Counter", width: 360, height: 200, gpu: true })
bun app.jsx # run it (Bun says JSX directly) npx bui build app.jsx # or container it: app.exe, one 7 MB file

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

const { App, indication } = require("@blender-ui/native") const app = new App({ gpu: true }) const win = app.window({ title: "Hello", width: 360, height: 200 }) win.body.className = "m-0 p-6 flex flex-col gap-3 bg-[#2b2b2b] text-[#e6e6e6]" const clicks = signal(0) const label = win.createElement("span") label.textContent = clicks // follows the signal const button = win.createElement("button") button.textContent = "Add one" button.addEventListener("click", () => clicks.value++) win.body.appendChild(label) win.body.appendChild(button)

 a Blender content field, button, checkboxes and a advancement bar
A project catalog in React (examples/site/js/todo_react.js); the DOM-like type 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.

13. First app: Dear ImGui

The genuine 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++:

#include "imgui.h" #include "imgui_impl_bui.h" // see examples/imgui_demo.cpp static void frame(void*) { ImGui::ShowDemoWindow(); ImGui::Begin("Hello"); static float v = 0.5f; ImGui::SliderFloat("Value", &v, 0.0f, 1.0f); ImGui::End(); } int main() { ImGui::CreateContext(); ImGui_ImplBUI_App* app = ImGui_ImplBUI_CreateApp("Demo", 1280, 800, frame, nullptr); ImGui_ImplBUI_RunApp(app); ImGui_ImplBUI_DestroyApp(app); ImGui::DestroyContext(); }

Python:

import blenderui.imgui as imgui # C: cimgui.h · Rust: the blenderui-imgui crate state = {"value": 0.5} def frame(): imgui.show_demo_window() imgui.begin("Hello") _, state["value"] = imgui.slider_float("Value", state["value"], 0.0, 1.0) imgui.end() imgui.run(frame, title="Hello", size=(1280, 800))

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

use blenderui_imgui as imgui; fn main() { let mut value = 0.5f32; imgui::run("Hello", [1280, 800], move || { imgui::show_demo_window(); imgui::begin("Hello"); imgui::slider_float("Value", &mut value, 0.0, 1.0); imgui::end(); }); }

Build alongside -DBUI_IMGUI_BLENDER_WIDGETS=ON (or the Rust feature blender-widgets) and ImGui's widgets rotate into Blender's own: DragFloat is Blender's drag-to-scrub figure site (Shift for precision, Ctrl to snap), SliderFloat Blender's figure slider, checkboxes drag-toggle, menus and combos get Blender's menus. The remainder 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 demo opening drawn alongside Blender's widgets
Dear ImGui's own demo alongside BUI_IMGUI_BLENDER_WIDGETS=ON: figure fields, sliders, color rows and panel headers are Blender's

A environment inspector in Dear ImGui alongside ImGui's own widgets and colors The identical inspector alongside Blender widgets and Blender's style
The identical ImGui code: ImGui's widgets (left) and the Blender-widgets build (right) (examples/site/imgui_inspector.cpp)

Guide, safety and the inventory look: docs/imgui.md.

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

#include <stdio.h> #include "BUI_kit.h" static void on_event(void *data, BKNode *node, int kind, void *ref, double a, double b) { if (kind == BK_EV_CLICK) printf("clicked %s\n", BK_get_str(node, "text")); else if (kind == BK_EV_CHANGE) printf("%s = %g\n", BK_get_str(node, "label"), BK_get_num(node, "value")); } int main(void) { BKNode *root = BK_node_new("frame"); /* everything is a node */ BK_set_num(root, "padding", 8); /* configured by asset name */ BKNode *size = BK_node_new("slider"); BK_set_str(size, "label", "Size"); BK_set_num(size, "max", 10); BK_set_num(size, "value", 2.5); BK_node_add(root, size, -1); BK_geom_set_manager(size, BK_GEOM_PACK); /* Tk's packer, in C */ BK_geom_set(size, "fill", 1); BKNode *apply = BK_node_new("button"); BK_set_str(apply, "text", "Apply"); BK_node_add(root, apply, -1); BK_geom_set_manager(apply, BK_GEOM_PACK); BKContext *ctx = BK_context_new(root); /* input, focus, popups, undo */ BKHost host = {0}; host.emit = on_event; /* the opening fills in the remainder */ BK_context_set_host(ctx, &host); if (BK_window_supported()) { /* Win32, X11 or Cocoa */ BKWindow *win = BK_window_new(ctx, "BUI from C", 320, 120); BK_window_show(win); BK_window_run(); BK_window_free(win); } BK_context_free(ctx); BK_node_free(root); return 0; }
cmake -S . -B build -DBUI_BUILD_EXAMPLES=ON cmake --build build --target bui_kit_hello

 panels, enum rows, figure fields, dropdowns, a slider, checkboxes and buttons
A bigger C program: a modifier stack (examples/site/kit_modifiers.c)

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


 your code: tkinter Qt components Dear ImGui (C++/C/Python/Rust) Rust: rsx! / HTML / CSS / Tailwind / hooks JS / React │ │ │ │ │ │ └──── Python: options, signals │ ImGui center + BUI backend └── manner cascade + taffy layout ◄────┘ │ │ │ C kit (kit/): node tree · geometry · input & communication · Blender widget example · undo · animation · themes · Blender search/expr │ renderer: damage-driven application raster (parallel) or GPU (Direct3D 11 / OpenGL 3.3, instanced, opt-in) │ window: native Win32 / X11 / Cocoa opening · stdlib Tk opening · headless (tests, screenshots) 
  1. Your code, in any tongue above, creates widgets and says what happens when they change.
  2. The kit keeps them in one tree, lays them out and handles input, following Blender's rules.
  3. The renderer draws them, on the CPU by default or on the GPU if you ask.
  4. Damage rendering keeps it cheap: a alter redraws lone the rectangle it touched, and an idle opening uses no CPU at all.

What's under the hood:

  • Blender's genuine UI code. Widget example is a C harbor of Blender's interface_widgets.cc (round_box_edges, widgetbase_draw, the shape tables), and communication follows interface_handlers.cc. Color math, rects, text cursors, cord hunt and expression evaluation are Blender's blenlib, copied in. A few interface records (string search, text-edit undo, float precision) are copied into kit/intern/blender/ and edited for the kit. The X11 and Cocoa hosts prosecute Blender's GHOST; the Win32 presenter is BUI's own.
  • One node tree. Every widget is one kit node. The C kit owns layout, hit testing, hover, focus, drags, menus, tooltips, undo and animation.
  • Damage rendering. A alter marks lone its widget's rectangle, and only changed tiles attain the screen.
  • Thin bindings. Python, Rust and JavaScript keep lone what their syntax layer needs.

More: ARCHITECTURE.md and How it works.

16. Blender's widgets and interactions

These rules live in the C kit, so they activity the identical everyplace Blender widgets are drawn: the Python components, tkinter and Qt syntax, the Rust and JavaScript Blender components and form controls inner styled, ImGui's Blender-widgets build, and all C kit widget.

  • Drag to scrub. Press a figure site and drag sideways. The cursor hides and wraps, so you never hit the display edge, and comes rear anywhere the drag started. A drift moves one click stage per pixel; Shift moves at a tenth of the speed; Esc cancels and restores the value.
  • Ctrl snaps alongside Blender's rules: unbounded floats to entire units, angles to 10°, sliders to 0.1, 1 or 10 depending on their range, integers to multiples of 10.
  • Click to type, and category math: Blender's expression evaluator (expr_pylike_eval.cc) turns 2*pi, 90/4, min(4, 3) or x if c alternatively y into numbers. This plant in Blender figure sectors and sliders; plain content sectors keep what you category as text.
  • Shortcuts on any value: Backspace resets to the default, - negates, Ctrl+Wheel steps, Ctrl+C / Ctrl+V copy and paste, right-click opens Copy, Paste and Reset.
  • Several sectors at once. Drag down complete a pillar of figure sectors to collect them, afterward sideways to alter them together. Drag throughout checkboxes (or panel headers) to set them all in one stroke.
  • Panels downfall alongside Blender's animation; Ctrl+click opens one and closes the others; drag the grip to reorder.
  • Menus activity press-drag-release or click; hover switches menu-bar menus; pie menus open about the pointer.
  • Menu search is Blender's cord search: commencement typing in any open menu. It matches term initials ("ad cu" finds "Add Cube"), forgives typos, and ranks your latest picks first.
  • Undo everywhere. Ctrl+Z and Ctrl+Shift+Z activity on all UI edit, and inside a content site during you type. A burst of typing or a multi-field drag is one step.
  • Float precision follows Blender: small values display the decimals they need.
  • Tooltips appear following Blender's half-second delay.

Coming soon: typing values alongside units ("2 m"), Blender's search-as-you-type popups, and widget drag and drop. More: Blender's widgets.

17. Three looks: HTML, styled and Blender components

In Rust and JavaScript you choice the appearance per element:

You write You get
Plain HTML: <button>, <input type="range">, <select> ... What a browser draws: dreary content on pale and Chrome's form controls, in the Inter UI font
styled on any element: <div styled>, div().styled() Blender's appearance for it and everything inside: Blender's theme (dark or light), UI font, Blender widgets
Blender components (capitalized): <NumberSlider>, <Button> ... Blender's widgets and communication everyplace (drag to scrub, Ctrl+Z, Blender's color picker)

The components are Button, Checkbox, Radio, NumberField, NumberSlider, TextField, TextArea, ColorSwatch, Dropdown and ProgressBar. Each one is the HTML component it stands for, so all attribute, manner and event plant on it:

rsx! { <main class="p-4 flex gap-2"> // browser look <input type="range" /> // Chrome's slider <NumberSlider min={0.0} max={10.0} value="2.5" /> // Blender's slider <div styled><button>"Apply"</button></div> // Blender's appearance inside </main> } div().child(Checkbox().checked(true)).child(Button().child("Apply")) // gpui syntax
import { render, NumberSlider, Button } from "@blender-ui/react" // <NumberSlider min={0} max={10} onChange={...} />, <Button onClick={...}>Apply</Button> // DOM API: win.createElement("NumberSlider")

Form controls as plain HTML, inner styled, and as Blender components
cargo run --example forms: plain HTML, inner styled, and the Blender components

A form and a array in plain HTML, alongside a browser's default look  Blender's theme and widgets
The identical markup, plain (left) and inner styled (right). Plain HTML looks the identical in the two themes.

 figure fields, sliders, a dropdown, checkboxes, a content field, a color swatch, a advancement bar and buttons
Blender components from Rust (site_components.rs)

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

18. Rendering on the CPU and the GPU

BUI has two renderers, and they diagram the identical pixels.

  • The application raster (gpu/intern/gpu_raster.c) is the default. It draws anti-aliased shapes alongside signed-distance coverage, akin Blender's widget shaders, into one example buffer, compares it alongside the final example in 64×32 tiles, and reports lone the tiles that changed. Big canvases diagram in parallel bands on Windows (BUI_RASTER_THREADS). It needs nothing from your graphics cardstock and uses the smallest memory.
  • The GPU renderer is opt-in: Direct3D 11 on Windows (gpu/intern/gpu_d3d11.c) and OpenGL 3.3 center on Linux (gpu/intern/gpu_gl.c). It's modeled on Blender's instanced widget drawing: each primitive is one 128-byte case of a sole uber-shader, so a frame is a few instanced diagram calls. Text and images are cached in atlases. Frames render into a persistent target, so lone damaged regions redraw; on Windows, a flip-model toggle sequence presents dirty rectangles. On Linux, libGL, libEGL and libX11 are loaded at run period (GLX for windows, EGL for offscreen), so no GL headers are needed, and BUI falls rear to the CPU where OpenGL is missing.

The shaders measure the application raster's formulas: the parity test finds 10 of 172,800 pixels that differ by additional than 3/255, on the two backends.

Turn the GPU on:

Where How
Python bui.set_gpu(True) before creating windows; tkinter syntax additionally tk.Tk(gpu=True)
Rust Application::new().gpu(true), or WindowOptions { gpu: Some(true), .. }
JavaScript new App({ gpu: true }), or React's render(..., { gpu: true })
C BUI_gpu_set_default(1), or BK_window_set_gpu(win, 1)
Any app, no code change BUI_GPU=1

BUI_GPU=1 overrides the app-wide environment in code; BUI_GPU=0 turns the app-wide defaults off, but a opening that asks for the GPU itself motionless gets it. Where no equipment 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 ample or HiDPI window, many of animation, thousands of items: the GPU (about fractional the CPU per frame, or less, for concerning 10 MB more RAM affirmative GPU memory). Servers and tests: the CPU. macOS: the CPU, for now (a GPU renderer there is coming soon).

More: Rendering.

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

  1. A alter marks lone its widget's rectangle as dirty (popups get a margin for their shadow).
  2. Dirty rectangles merge (up to 24 per window).
  3. If nothing is dirty, the iteration doesn't render; it sleeps until the next input or timer.
  4. Only the dirty regions are redrawn, clipped to their rectangles.
  5. The raster compares the new pixels alongside the final example in 64×32 tiles; a redraw that changed nothing reports nothing.
  6. Only damaged tiles attain the display (Win32 copies them, X11 sends each rectangle alongside XPutImage, Cocoa invalidates them, the GPU presents dirty rectangles).

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

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

Host Where Notes
Win32 (kit_window_win32.c) Windows BUI's own host. Per-monitor DPI, vsync-paced animation, clipboard, cursors, window-manager features.
X11 (kit_window_x11.c) Linux; Wayland through XWayland Input mapping following Blender's GHOST. Xft.dpi scaling. libX11 is loaded whenever the archetypal opening opens.
Cocoa (kit_window_cocoa.m) macOS Experimental. Ported from Blender's GHOST Cocoa code, alongside Retina scaling. It's checked by CI and has been tried by hand on one Apple Silicon Mac so far; evaluation notes in docs/macos-testing.md.
Tk Python, anywhere A stdlib tkinter opening that shows the kit's example buffer. BUI_HOST=tk forces it; it's additionally the fallback anywhere no native presenter works.
Headless Everywhere No window: render into a raster for tests and screenshots, alongside a virtual clock that steps animations exactly.

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

Your app's content looks the identical on Windows, Linux and macOS, and it looks like Blender's:

  • Inter, Blender's UI font, is embedded (the changeable version, with optical-size and importance axes). UI content is 11 pt at measure 1.
  • Rendered akin Blender's BLF: BUI vendors FreeType 2.13.3 and renders with ray hinting, Blender's gamma-1.43 safety table, Inter's optical size, a genuine bold instance, no kerning (as in Blender), and Blender's text shadows. With BUI_TEXT_FREETYPE=OFF, stb_truetype rasterizes instead.
  • On the GPU, glyphs are drawn from their outlines with Slug by default, or from a per-glyph atlas akin Blender's (BUI_SLUG=0, bui.set_slug(False), .slug(false), BUI_gpu_set_slug(0)).
  • Other fonts: BUI_FONT=path.ttf replaces Inter, BUI_FONT_DIR adds a folder to hunt first, blenderui::add_font (Rust) and BUI_text_add_font (C) enroll faces from memory, and CSS @font-face loads local files.
  • Windows' GDI text is opt-in (-DBUI_TEXT_GDI=ON, Rust feature gdi-text): ClearType-style hinting and scheme fonts, without Slug.

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

22. Themes: dreary and light

BUI looks akin Blender since 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, complete Blender 5.x's built-in defaults. Switch at run time, and all open opening relayouts and redraws:

Where Light theme
C BK_set_theme("light"); BK_theme_name(), BK_theme_color("region_bg", rgba)
Python blenderui.set_theme("light") (also switches the Dear ImGui extension); theme_name(), theme_color(key)
Rust blenderui::set_theme("light"), or Application::new().theme("light"); theme_name(), theme_color(key)
JavaScript new App({ theme: "light" }), app.setTheme("light"), or React's render(..., { theme: "light" })
Dear ImGui Its Blender manner follows the kit's theme (pick it before the backend starts)
Any app, no code change BUI_THEME=light (or dark)

Widgets, panels, the area background, the styled HTML panel and ImGui's Blender manner all prosecute the theme. Plain HTML keeps a browser's appearance either way. Inside all theme you can motionless color things yourself: bg / fg in tkinter, setStyleSheet in Qt syntax, color= on components, complete CSS on HTML in Rust and JavaScript, ImGui's own manner colors.

BUI additionally includes Blender's icons: all 781 of Blender's SVG icons, rasterized alongside Blender's NanoSVG code so they're keen 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 instal blenderui gives you four APIs in one package:

  • tkinter syntax (blenderui.tksyntax): all community tkinter and ttk name (7,846 of 7,846). Run existing programs alongside blenderui-tk app.py, or call blenderui.tksyntax.install() first. messagebox and simpledialog are Blender-styled, colorchooser is Blender's color picker, and filedialog is Blender's File Browser (BUI_FILEDIALOG=native for the OS dialogs). Look-only Tk options (relief, ttk.Style ...) are accepted, but the look comes from Blender's theme. Guide: docs/tkinter.md.
  • Qt syntax (blenderui.qtsyntax): widgets, layouts (box, grid, form, stacked), signals, QPainter, menus, timers and animations, QFileDialog as Blender's File Browser. Partial: model/view classes, docks, toolbars, splitters and Qt stylesheets are missing. Guide: docs/qt.md.
  • Blender components (blenderui.components): 45 components, from NumberSlider to NodeEditor. Reference: docs/components.md.
  • Dear ImGui (blenderui.imgui), pyimgui-style. Guide: docs/imgui.md.

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

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

rsx! { // Tailwind as attributes, any variant, arbitrary values; typos neglect to compile <button px-3 py-1 rounded-md bg-zinc-800 hover:bg-sky-600 md:dark:hover:bg-sky-400 active:style="transform: scale(0.97)" onClick={move || save()}> "Save" </button> // authority stream correct in the markup <ul>{for item in items { <li class="py-1">{item}</li> }}</ul> {if dirty { <p text-amber-400>"Unsaved changes"</p> }} // genuine CSS, evaluated by the engine <div style="width: calc(100% - 2 * var(--gap)); background: color-mix(in oklch, var(--brand) 60%, white)" /> }
error: rsx!: `bg-sky-50O` is not a Tailwind utility; did you average `bg-sky-500` or `bg-sky-50` or `bg-sky-100`? 

What's in the box:

  • Layout by taffy: obstacle stream and wrapping text, flexbox and grid (every property, including grid-template-areas and named lines), tables, related / complete / fixed positioning (fixed boxes are placed against the window), scrolling, and bidirectional text.
  • CSS: selectors flat 4, nesting, @layer / @media / @supports / @scope / @container / @font-face / @property, var() and env(), every math function, CSS Color 4 and 5.
  • Effects and animations: @keyframes animations and transitions (every longhand, cubic-bezier(), steps(), linear(), interruptible transitions), display and backdrop-filter, mix-blend-mode, clip-path, masks, 2D transforms, border-image. Frames render lone during something moves, and headless windows stage a virtual clock (App::advance_clock).
  • Tailwind CSS v4, compiled on archetypal use, alongside compile-time checks in rsx! and tw!.
  • Components and hooks in zopra, React or Leptos style, alongside optional props and keys.
  • Blender components, styled, and the theme.
  • Headless testing: Application::headless(), screenshots, simulated input.

Not yet: async resources (use_resource), generic components, 3D transforms, OpenType features, multi-column layout. Guide: docs/rust.md, crate README: bindings/rust/blenderui, and the website's Rust section (including effects and animations).

  • @blender-ui/react: a React 19.3 renderer. HTML presenter components, CSS and Tailwind, events, Suspense, transitions, actions, and the Blender components. Hooks keep React's names but clasp signals: continue one into JSX and a change updates that node without re-rendering. README: bindings/react.
  • @blender-ui/native: a DOM-like API (createElement, appendChild, addEventListener, className alongside Tailwind, style) alongside signals, memo, consequence and batch. README: bindings/node.
  • How it's fast: BUI renders on its own UI thread, so it never blocks JavaScript; all tick sends one lot of changes; styles are parsed once.
  • Standalone apps: npx bui build app.jsx makes a ~7 MB executable with an embedded QuickJS engine; --bun makes a Bun executable instead; npx bui run app.jsx runs on QuickJS without building.
  • Tests: new App({ headless: true }) renders off-screen, and win.click(x, y) simulates input.

Limits: npm packages are prebuilt for Windows x64 only; events reach JavaScript following BUI handled them (no native preventDefault), and event.target is the deepest listening element. Guide: docs/javascript.md; website: React, native API, signals, standalone executables.

Language What you use Built by
C++ imgui.h + imgui_impl_bui.h CMake mark bui_imgui (bui::imgui)
C cimgui.h + cimgui_impl_bui.h CMake mark bui_cimgui
Python import blenderui.imgui as imgui The _buiimgui extension, in the wheel
Rust the blenderui-imgui crate (on crates.io) Cargo

The C, Python and Rust bindings are generated from imgui.h. ImGui is idle-free on BUI: frames run lone on input and during item animates. The Blender-widgets build (BUI_IMGUI_BLENDER_WIDGETS=ON, Rust feature blender-widgets) swaps in Blender's widgets, and can be switched at run time (ImGui_ImplBUI_SetBlenderWidgets, imgui.set_blender_widgets). In that build, opening heading bars, tooltips, plain popups, tables and the color picker keep ImGui's drawing.

Guides: docs/imgui.md, bindings/imgui/README.md (the backend and the Blender style), bindings/imgui/blender/README.md (the widget mapping), and the website's Dear ImGui section.

The kit's concepts: nodes made by category name (frame, slider, button, panel, tree, canvas, filebrowser ...), properties set by name, Tk's geometry managers (pack, grid, place) in C, a context that owns input, popups, concentration and undo, a host that receives events, and windows. A tradition node draws and handles input itself; Dear ImGui runs on BUI that way. Guide: docs/c-api.md.

To embed BUI in your own renderer, render the kit into a BuiRaster and blit it (as bui.qt.BuiCanvas does inner Qt). A separate, lower-level layer, render sinks (api/bui_c_api.h), hands the triangles, lines and content of the immediate-mode GPU seam to your renderer; the Qt/QPainter backend and the SVG recorder use it. Guide: INTEGRATION.md.

Guide What's inside
Website Everything below, as tutorials, concepts and references, alongside screenshots in dreary and light
Getting started Building, surroundings variables, opening hosts, GPU rendering, troubleshooting
tkinter Running tkinter apps on BUI, behavior notes, limitations
Qt syntax Classes, signals, layouts, painting, coverage
Components The bui.components reference
Rust rsx!, hooks, HTML, CSS and Tailwind coverage, effects, animations, events, headless tests
JavaScript and React @blender-ui/native, @blender-ui/react, how changes cross to the UI thread, performance
Dear ImGui Dear ImGui on BUI from C++, C, Python and Rust; the Blender-widgets build; coverage
C API The C kit (BUI_kit.h)
Integration Embedding BUI example in C, C++, Qt or PySide hosts
Architecture Modules and what was taken from Blender
Syntax coverage The Qt and tkinter surface, exactly
macOS testing How to try the experimental Cocoa presenter on a Mac
Publishing Releasing to PyPI and crates.io
Changelog What changed

29. Before you peruse the numbers

These numbers were measured on a Ryzen 7 5800U laptop (Windows 11, on AC power) before the latest features landed: Dear ImGui, the Linux GPU renderer, the ray theme, and the Blender hunt and expression code. They show the form of things, not a commitment for your machine. Rerun them alongside the tools in Run the benchmarks yourself.

30. Start period and battery

The identical small settings opening (a label, content field, checkbox, slider and button) written all of the five ways, from bench/apps, on BUI's CPU renderer (the default) and its GPU renderer (BUI_GPU=1). The last rows are one gpui-syntax origin file, settings.rs, compiled unchanged against blenderui, Zed's gpui and gpui-fast. gpui has no form widgets, so there the controls are styled divs.

Median of 10 launches, from procedure commencement until the archetypal example is on screen, with Python 3.14 and Node 22:

Renderer Start time CPU used to start Memory (idle) Idle CPU per minute
Rust (HTML + CSS) CPU 38 ms 27 ms 13 MB 0 ms
GPU 42 ms 61 ms 31 MB 1.8 ms
JavaScript (React, Node.js) CPU 94 ms 100 ms 48 MB 68 ms
GPU 99 ms 131 ms 60 MB 71 ms
Blender components (Python) CPU 112 ms 86 ms 23 MB 0 ms
GPU 116 ms 125 ms 32 MB 1.7 ms
tkinter syntax (Python) CPU 139 ms 112 ms 25 MB 0.2 ms
GPU 159 ms 157 ms 43 MB 2.4 ms
Qt syntax (Python) CPU 156 ms 123 ms 27 MB 0 ms
GPU 161 ms 160 ms 36 MB 1.2 ms
Same gpui code: blenderui CPU 40 ms 27 ms 15 MB 0 ms
blenderui GPU 43 ms 60 ms 31 MB 2.1 ms
gpui GPU 231 ms 226 ms 29 MB 743 ms
gpui-fast GPU 226 ms 217 ms 31 MB 2.5 ms

On the identical code, blenderui shows its archetypal example concerning 5× sooner than gpui and gpui-fast, spends concerning 8× small CPU getting there, and on the CPU renderer uses half the memory. Idle, gpui keeps concerning 1.2 % of a center busy; blenderui uses none.

Laptops can't study energy per app, so power division disbursal is measured by the CPU time an app causes: the CPU it spends starting up, and the CPU it uses complete 20 seconds during the opening sits idle (what drains a power division during an app is open). BUI redraws lone whenever item changes and alternatively sleeps, so idle use is near zero on either renderer. The GPU renderer starts a small slower and uses additional recollection (the GPU device), and pays off on large, animated scenes (below). Node's event iteration accounts for the JavaScript idle figure, Python's times contain starting the interpreter, and recollection doesn't figure GPU memory.

Python and C, on the complete component demo (520×900):

Frame Time
Complete example (everything redrawn) ~0.7 ms
Hover or number-scrub example (damage only) ~0.05 ms
Native window: input event → on screen ~0.06 ms

Dear ImGui's demo opening alongside all division open (27k triangles, 1280×800) is a full application redraw of concerning 5–8 ms.

Rust, against Zed's gpui and the faster fork gpui-fast. The environment is 3000 animated cells, and all apps ran in the identical meeting (GPU rows on Direct3D 11):

blenderui (GPU) blenderui (CPU) gpui-fast gpui
FPS 59.9 57.6 31.5 19.9
CPU per frame 11.6 ms 22.0 ms 31.9 ms + GPU 50.5 ms + GPU
RAM 40 MB 30 MB 65 MB 77 MB
First frame ~5 ms ~5 ms ~200 ms ~220 ms
Idle CPU 0 % 0–0.9 % 0–0.4 % 0.9–1.4 %
Full results, the GPU renderer, and the method
blenderui (GPU) blenderui (CPU) gpui-fast gpui
FPS, 1000 animated cells 60 60 49.2 36.4
CPU per frame, 1000 / 100 cells 4.7 / 1.2 ms 10.2 / 4.6 ms 20.5 / 2.7 ms + GPU 27.7 / 4.7 ms + GPU
Uncapped FPS, 100 / 1000 / 3000 cells 1491 / 309 / 94 649 / 202 / 76 - -
RAM, 1000 / 100 cells 35 / 28 MB 24 / 21 MB 45 / 47 MB 47 / 40 MB
GPU memory 19–22 MB none 19–24 MB 16–21 MB

The GPU renderer is off by default. Turn it on with Application::new().gpu(true), tk.Tk(gpu=True), bui.set_gpu(True) or BUI_GPU=1:

  • Every primitive is one case of a sole shader, so a example is a few instanced diagram calls (Direct3D 11 on Windows, OpenGL 3.3 on Linux).
  • Text and images are cached in atlases.
  • Frames render into a persistent target, so lone damaged regions redraw.
  • On Windows, display uses a flip-model toggle sequence alongside dirty rects.

Its shaders measure the application raster's formulas: the parity test finds 10 of 172,800 pixels that differ by additional than 3/255, on the two backends.

gpui-fast's heavy-scene example charge varies between sessions on this laptop (30–60 fps), so difference inside one session. Method, raw data and how to rerun: bindings/rust/bench/README.md.

32. JavaScript and React: startup and animation

Startup. These initiate a small React app (the oppose above) that quits once its archetypal example is on screen. Each fig is the median of 12 launches following a warm-up initiate (node bench/startup.js).

First frame Launch to exit RAM at archetypal frame What you ship
QuickJS executable (bui build) 68 ms 104 ms 19 MB 7.3 MB
Bun executable (bui build --bun) 79 ms 147 ms 35 MB 114 MB
Bun (bun app.js) 80 ms 152 ms 35 MB Bun + your app
Node.js (node app.js) 108 ms 187 ms 45 MB Node + your app
Rust (for reference: the benchmark app) 5 ms ~92 ms 3.5 MB

First example is measured from the runtime's start. Launch to exit is partition time measured from outside, including procedure innovation and teardown.

Animation. The identical environment as the Rust array above, in one mode: one cell changes per frame, GPU renderer, medians of 3 runs. CPU is the entire process, counted alongside the sequence oppose as for Rust.

  • Plain JS uses @blender-ui/native.
  • React alongside signals passes the changing values as signals, so the grid renders once.
  • React alongside state re-renders the grid all frame.
  • React's manufacturing build is used throughout.
3,000 cells FPS CPU per frame RAM
Rust 59.6 12.0 ms 43 MB
QuickJS: plain JS / React alongside signals / React alongside state 59.1 / 58.7 / 19.7 16.3 / 14.9 / 51.0 ms 56 / 61 / 67 MB
Bun 1.4: plain JS / React alongside signals / React alongside state 58.8 / 58.4 / 55.8 13.1 / 13.3 / 20.8 ms 80 / 85 / 118 MB
Node 22: plain JS / React alongside signals / React alongside state 55.8 / 56.7 / 54.8 14.4 / 14.0 / 18.9 ms 88 / 93 / 121 MB
1,000 cells FPS CPU per frame RAM
Rust 60 4.8 ms 32 MB
QuickJS: plain JS / React alongside signals / React alongside state 60 / 60 / 56.8 6.0 / 5.6 / 17.8 ms 38 / 40 / 43 MB
Bun: plain JS / React alongside signals / React alongside state 60 / 60 / 60 5.2 / 5.2 / 7.5 ms 58 / 63 / 81 MB
Node: plain JS / React alongside signals / React alongside state 60 / 60 / 60 5.6 / 5.6 / 6.9 ms 68 / 71 / 97 MB

What this means:

  • JavaScript expenses small complete Rust: 0.4–2.4 ms per frame, for sending changes to BUI's UI thread.
  • Signals create React as cheap as the plain API: the component doesn't re-render.
  • QuickJS starts fastest and uses the smallest memory, from a 7 MB file. It has no JIT, so re-rendering a 3,000-element catalog all example drops it to 20 FPS. Keep big lists on signals, or build alongside --bun.

Method, the recollection breakdown and how to rerun: docs/javascript.md.

33. Run the benchmarks yourself

Every figure complete comes from a tool in this repo. Build in publish mode, close other dense apps, and plug the laptop in. Run one benchmark (and one build) at a time.

Start period and battery: the five ways and gpui (bench/, Windows). The same settings opening written all way, on the CPU and the GPU renderer, affirmative one gpui-syntax document compiled for blenderui, gpui and gpui-fast. It reports start time, CPU used to start, recollection and idle CPU, and writes bench/results.json.

cmake -S . -B build && cmake --build build --config Release --target buipy # Python extension cd bindings/node && npm run build && cd ../.. # Node addon cd bindings/rust && cargo build --release --example bench_app && cd ../.. # Rust app cd bindings/rust/bench && cargo build --release --bins && cd ../../.. # gpui comparison py -3 bench/run.py 10 20 # launches per app, seconds of idle measurement

Frame cost: 100, 1,000 and 3,000 animated cells, against gpui and gpui-fast (bindings/rust/bench/, Windows). A 1000×800 opening filled alongside N rounded, numbered cells, in three modes:

  • anim: all division changes all frame, the worst case.
  • one: one division changes per frame, akin a hover or a ticking value.
  • idle: nothing changes.

Each app measures its own CPU cycles, frames and memory, and run.py adds GPU utilisation and GPU recollection from Windows' achievement counters.

cd bindings/rust/bench set GPUI_FXC_PATH=C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\fxc.exe # gpui needs fxc.exe cargo build --release py run.py --reps 3 # all apps, 100 / 1000 / 3000 cells, concerning 12 minutes py run.py --cells 3000 --apps blenderui,blenderui-gpu --reps 1 target\release\bui-bench --cells 3000 --mode anim # one run by hand (--mode one / idle, --uncapped) set BUI_GPU=1 && target\release\bui-bench --cells 3000 --mode anim # on the GPU renderer

Method and complete results: bindings/rust/bench/README.md.

JavaScript: the identical cells, and startup (bindings/node/bench/):

cd bindings/node node bench/cells.js 3000 # DOM-like API, one division changing per frame node bench/cells.js 3000 --react # React re-rendering the grid node bench/cells.js 3000 --react --signals # React alongside signals: no re-render node bench/cells.js 3000 --gpu # on the GPU renderer bun bench/cells.js 3000 # on Bun node cli.js run bench/cells.js -- 3000 # on the 5 MB QuickJS runtime node bench/startup.js # initiate to archetypal frame: Node, Bun and the two executables

tkinter: canvas example cost (headless, any platform):

py bindings/python/bench/tk_canvas_bench.py 3000 all # move 3,000 canvas items all frame py bindings/python/bench/tk_canvas_bench.py 3000 one # move one

Inside any app: run it alongside BUI_PROFILE=1 to imprint per-phase example times (layout, paint, raster, present) all 60 frames; any value turns it on. Use BUI_GPU=1 / BUI_GPU=0 to choice the renderer. More: Profiling.


Windows Linux macOS
Window Native (Win32) Native (X11; Wayland through XWayland) Native (Cocoa), experimental
Python (pip install) Works: wheels Works: wheels (native X11 host) Works: wheels
Rust (cargo add blenderui) Works Works Experimental
JavaScript / React Works: prebuilt on npm Works: build the addon from origin (npm run build); native X11 windows Headless (see below)
C, C++, Dear ImGui Works Works Experimental
Renderer CPU raster, or GPU (Direct3D 11) CPU raster, or GPU (OpenGL 3.3) CPU raster
HiDPI Per-monitor DPI Xft.dpi Retina (backing scale)

Works method it plant and is tested. Experimental method it's written but has had small hands-on evaluation on genuine hardware (macOS: one Apple Silicon Mac so far, affirmative CI).

macOS. The macOS opening presenter is new: it's a harbor of Blender's Cocoa code (GHOST). So far it has been checked by CI and tried by hand on one Apple Silicon Mac by Krish Kalaria, who reported matter #3 and fixed it in drag petition #4. If you have another one, delight try it and tell us what happens: docs/macos-testing.md. Python can motionless use the stdlib Tk opening there (BUI_HOST=tk; this needs Python's tkinter, for example from python.org or beer instal python-tk). Node runs BUI on its own UI thread and macOS lone allows windows on the chief thread, so JavaScript stays headless on macOS for now.

Linux. libX11 and libGL are loaded whenever the archetypal opening opens, so BUI also imports and renders headless on servers and in containers without them, and falls rear to the CPU raster anywhere OpenGL is missing. Building from origin needs the X11 headers (libx11-dev / libX11-devel); no GL headers are needed. The C, Python, opening and GPU parity tests continue on Linux, on Mesa's application OpenGL and on an NVIDIA GPU.

Packages:

Package Platforms Notes
blenderui on PyPI Windows x86_64, Linux x86_64 (manylinux), macOS arm64 and x86_64 CPython 3.11 to 3.14. No musllinux or 32-bit wheels.
blenderui on crates.io Any phase alongside CMake and a C compiler Rust 1.88+. blenderui-imgui (Dear ImGui) is on crates.io too.
@blender-ui/native, @blender-ui/react on npm Windows x64 Node.js 18+ or Bun. Elsewhere, build the addon from source.
C and C++ (CMake) Windows, Linux, macOS CMake 3.20+, a C11 and C++20 compiler.

35. Environment variables

Most are peruse by the C library, so they activity the identical from all language. On/off variables appearance at the archetypal character: 1, y, Y, t or T is on. Where a changeable and an app-wide API call set the identical thing, the variable wins.

Variable What it does
BUI_GPU 1 draws native windows on the GPU (Direct3D 11 / OpenGL 3.3). Overrides bui.set_gpu(), Application::gpu(), BUI_gpu_set_default(). 0 turns those defaults off; a opening that asks for the GPU itself motionless gets it.
BUI_SLUG GPU text: 1 from glyph outlines (Slug, the default), 0 from a per-glyph atlas.
BUI_GPU_DEBUG 1 prints why the GPU renderer couldn't start.
BUI_GPU_WARP 1 (Windows) creates the Direct3D 11 equipment on WARP, the application rasterizer. Handy in VMs and CI.
BUI_GPU_MAX_TEXTURE Testing: the largest texture flank the GPU renderers provision one depiction (at smallest 64), so images complete it are tiled as on devices alongside a small limit.
BUI_GPU_EGL default or surfaceless (Linux): the EGL phase for offscreen GPU rendering.
BUI_RASTER_THREADS 1 to 8 (Windows): the most threads the application raster uses for big canvases.
BUI_PROFILE Prints example times all 60 frames. Any value turns it on, equal 0.
BUI_THEME dark (default) or light: Blender's theme, whenever the app doesn't set one.
BUI_UI_SCALE A fixed UI measure (1.25, 1.5 ...) alternatively of the display's. Clamped to 0.5–4.
BUI_HOST tk (Python): use the stdlib Tk opening equal anywhere a native presenter exists.
BUI_MAC_TK 0 (Python on macOS): skip starting a hidden Tk base before the archetypal native window.
BUI_FONT, BUI_FONT_DIR A font document to substitute Inter, and an additional font directory to hunt first.
BUI_FILEDIALOG native (or system, tk), Python: document dialogs use the OS's alternatively of Blender's File Browser.
BUI_BOOKMARKS The File Browser's bookmarks file.
BUIPY_BUILD_DIR Running Python from a origin checkout: the directory holding the built buipy extension.
BUI_NODE_ADDON @blender-ui/native: burden this .node addon alternatively of the bundled one.
BUI_HEADLESS 1: bui build apps and bui run render off-screen (same as --headless).
BUI_SOURCE_DIR, BUI_TEXT_GDI Build time, Rust: build the C archive from this checkout; use GDI text.

Every variable, alongside defaults and anywhere it's read: Environment variables and docs/getting-started.md.

36. Building from origin and CMake options

You need CMake 3.20+, a C11 / C++20 compiler (MSVC, GCC/MinGW or Clang) and Python 3.11+ alongside headers. On Linux, additionally the X11 headers.

git copy https://github.com/ppmpreetham/BUI && cd BUI cmake -S . -B build && cmake --build build -j 2 ctest --test-dir build # C, C++, ImGui and Python test suites export PYTHONPATH=$PWD/bindings/python # Windows: set PYTHONPATH=%CD%\bindings\python python examples/components_demo.py cd bindings/rust && cargo test # Rust: CSS, Tailwind, rsx!, hooks, effects, headless windows
Option Default What it does
BUI_BUILD_TESTS ON C test programs and the ctest suites
BUI_BUILD_EXAMPLES OFF The C examples (bui_kit_hello, bui_svg_demo, the location screenshot programs)
BUI_BUILD_PYTHON_BINDINGS ON The buipy expansion (and the ImGui extension); skipped without Python's dev files
BUI_BUILD_IMGUI ON alongside a C++ compiler Dear ImGui on BUI, its C API, demo and test
BUI_IMGUI_BLENDER_WIDGETS OFF Dear ImGui alongside Blender's widgets
BUI_BUILD_QT_BACKEND OFF The C++ Qt/QPainter render-sink backend (needs Qt 5 or 6)
BUI_BUILD_UI OFF Also compile Blender's first ui/ sources (reference only)
BUI_TEXT_FREETYPE ON Render glyphs alongside FreeType akin Blender's BLF; OFF uses stb_truetype
BUI_TEXT_GDI OFF Windows' GDI content and scheme fonts
BUI_SLUG ON Slug as the GPU's default content method (switchable at run time)
BUI_IMAGE_SVG ON SVG images through the kit's nanosvg (no additional code: Blender's icons already use it)
BUI_WARNINGS_AS_ERRORS OFF GCC and Clang only: whenever OFF the build adds -Wno-error; it never adds -Werror or /WX itself

Rebuild the docs screenshots alongside python tools/gen_doc_images.py (and the website's dreary and ray shots alongside --site). More: CMake options.

API Coverage Status
tkinter and ttk 7,846 of 7,846 community names; nine genuine programs behave identically Complete
Qt syntax About 220 of 920 community method names on 25 center widget classes (~24%) Partial
Blender components (Python) 45 components (10 of them additionally in Rust and JavaScript) Complete
HTML elements (Rust, JavaScript) 113 of 113 Complete
CSS properties (Rust, JavaScript) 261 of 745 W3C properties render, 129 additional parse, 355 not recognized (mostly drafts, speech, paged media and SVG) Partial
CSS 2.1 display properties 90 of 90 Complete
Flexbox / Grid 12 of 12 / 23 of 23 Complete
Dear ImGui, C 399 of 399 functions Complete
Dear ImGui, Python and harmless Rust 366 of 399 functions (Rust FFI: 385) Partial
Image formats (every language) PNG, JPEG, WebP, GIF, BMP, TGA, QOI, HDR, PNM, SVG; not yet AVIF, EXR, TIFF, JPEG XL, HEIC Partial

How all was counted: Coverage, SYNTAX_COVERAGE.md, docs/rust.md, docs/imgui.md.

Path Contents
kit/ The C runtime: nodes, input, widget example (the interface_widgets.cc port), menus, geometry managers, canvas, the File Browser, themes (kit_theme_presets.c), the Win32, X11 and Cocoa opening hosts; kit/intern/image/ (images: decoders, cache, employee pool; third-party decoders in kit/extern/); kit/intern/blender/ holds Blender records copied in (string search, text-edit undo, drift precision). API: kit/include/BUI_kit.h
gpu/ Software raster, GPU renderer on Direct3D 11 (gpu_d3d11.c, shaders/) and OpenGL 3.3 (gpu_gl.c), textured meshes, Slug text, content motor (FreeType or stb_truetype + embedded Inter, or GDI)
core/, types/ Blender's blenlib subset (including string_search.cc and expr_pylike_eval.cc) and data types
ui/, compat/ Blender's first interface sources, kept for citation (not compiled by default; kit/ re-ports them in C), and the seams replacing Blender's use APIs
api/ Stable C ABI for render-sink hosts
bindings/python/ The buipy expansion and the bui / blenderui packages (tkinter, Qt, components, ImGui)
bindings/rust/ blenderui, blenderui-sys, blenderui-macros, blenderui-tailwind, blenderui-imgui, blenderui-jsview, blenderui-node, blenderui-qjs, and the benchmark
bindings/node/, bindings/react/ @blender-ui/native and @blender-ui/react
bindings/imgui/ Dear ImGui (vendored), the BUI backend, Blender style, the C API and its generator, the Blender-widgets build
backends/qt/ C++ Qt/QPainter render-sink backend
bench/ The commencement period and power division benchmark; bench/images/ (decoders, thumbnail grid)
examples/, tools/ Demos, the website's screenshot programs (examples/site/), the icon and theme generators, the docs screenshot generator
website/ The records website, bui.preetham.top
File Shows
examples/tk_unchanged_app.py A plain tkinter app: menus, notebook, form, table, text, canvas
examples/components_demo.py Every Blender component in a properties-editor layout
examples/qt_syntax_demo.py Qt syntax: layouts, form widgets, signals
examples/tk_syntax_demo.py tkinter syntax laid out akin a Blender properties editor
examples/kit_hello.c The C kit: a slider and a clasp in a native window
examples/imgui_demo.cpp Dear ImGui's demo opening on BUI, from C++
examples/imgui_demo_c.c The identical from C (cimgui.h)
examples/imgui_blender_compare.cpp ImGui widgets next to BUI's native Blender widgets
examples/site/ The website's screenshot programs: a Render Properties publishing company and a node publishing company (Python components), tkinter and ttk dialogs, a Qt matter editor, an ImGui inspector (C++ and Python), a C modifier stack, and a JavaScript project catalog (DOM and React)
hello.rs Rust: a component, hooks, Tailwind attributes and a Blender slider
showcase.rs Rust: HTML, a stylesheet, flex/grid, tables, Blender form widgets
forms.rs Rust: form controls as plain HTML, inner styled, and as Blender components
site_dashboard.rs, site_dashboard_builder.rs Rust: the identical dashboard in rsx! and in gpui builders
site_effects.rs, site_grid.rs, site_animation.rs Rust: CSS effects, grid and @keyframes
site_plain_html.rs, site_styled.rs, site_components.rs Rust: the three looks
blenderui-imgui demo Dear ImGui from Rust (cargo run -p blenderui-imgui --example demo)
bindings/node/examples/counter.js JavaScript: the DOM-like API
bindings/react/examples/counter.jsx React in JSX (bun examples/counter.jsx)

Done

Area What works
C runtime (kit/) Nodes, Tk-style geometry managers, input, Blender widget drawing, damage rendering, undo, animation, content area, canvas, scroll views, Blender's cord search, expression evaluator, text-edit undo and drift precision, Blender's Dark and Light themes
Native windows Windows (Win32) and Linux (X11; Wayland through XWayland), in C: DPI-aware, frame-paced animation, clipboard, cursors, window-manager features
tkinter syntax Complete: all community tkinter and ttk name (7,846 of 7,846)
Components 45 Blender components, including the color ramp, curve and node editors
Rust HTML (113/113 elements), Flexbox 12/12, Grid 23/23, CSS 2.1 90/90, math functions, var(), CSS Color 4/5, Selectors 4, @layer / @media / @supports / @scope / @container / @font-face / @property, @keyframes animations and transitions, filters / blend modes / masks / clip-path / 2D transforms / border-image, bidi text, backdrop images, object-fit, Tailwind v4, rsx!, #[component] alongside optional props and key, hooks, Blender components, browser-look form controls, headless testing
Dear ImGui The genuine Dear ImGui 1.93 on BUI (CPU, Direct3D 11, OpenGL), Blender theme and Inter; C++ / C (399/399 functions) / Python and Rust (366–385/399); the Blender-widgets build
Rendering Software raster (parallel, damage-tracked), GPU renderer (Direct3D 11 on Windows, OpenGL 3.3 on Linux), textured meshes, portable content motor (FreeType, as in Blender)
JavaScript / React @blender-ui/native: a DOM-like API complete napi-rs, alongside its own UI thread, lone changes crossing the boundary, vsync-paced requestAnimationFrame and signals. @blender-ui/react: a React 19.3 renderer whose hooks (useState, useMemo, useEffect ...) clasp signals that update nodes without re-renders. Both on Node.js and Bun, alongside headless testing. bui build makes standalone executables: concerning 7 MB alongside the embedded QuickJS runtime, or Bun's alongside --bun (guide)
Packaging blenderui on PyPI, alongside a CI workflow for wheels on all platforms (Linux wheels alongside the native X11 host); blenderui on crates.io; @blender-ui/react and @blender-ui/native on npm
Docs The website, bui.preetham.top

Partial or in progress

Area What's missing
Qt syntax (~24%) Model/view classes, docks, toolbars, splitters, Qt stylesheets (details)
CSS (261 of 745 W3C properties render, 129 additional parse) 3D transforms, OpenType font features, multi-column layout; hit evaluation ignores 2D transforms. Most of the remaining W3C catalog is drafts, speech, imprint and SVG (breakdown)
Text No content wrapping about floats; right-to-left content is reordered (bidi) but not shaped (Arabic joining); no OpenType features; no per-glyph font fallback yet (characters missing from the font display as boxes); no IME
Rust components No async resources (use_resource); no generic components
Dear ImGui Python and harmless Rust skip the va_list, void* and C-callback functions (reachable from C and the Rust FFI); alongside Blender widgets, opening heading bars, tooltips, plain popups, tables and the color picker keep ImGui's drawing
JavaScript / React packages npm packages are prebuilt for Windows x64 lone (on Linux, build the addon from source); events attain JavaScript following BUI handled them (no native preventDefault), and event.target is the deepest listening element
macOS Experimental. The native Cocoa opening presenter is written, checked by CI and tried by hand on one Apple Silicon Mac (how to help); JavaScript is headless there (Node's UI thread isn't the chief thread); no GPU renderer yet
Themes Dark and Light work; loading another Blender theme records doesn't yet

Planned (coming soon)

Target Plan
WebAssembly The kit in the browser: the raster blits to <canvas>, DOM events nourish the kit; @blender-ui/react and the DOM-like API on top, unchanged
egui BUI panels inner egui, affirmative a Blender-styled theme
More from Blender's source Per-glyph font fallback (BLF), IME, search-as-you-type popups, units in figure fields, widget drag and drop
macOS GPU and JavaScript windows The GPU renderer on Metal (or the OpenGL backend), and Node windows on the chief thread
More GPU backends Vulkan / WebGPU example the identical case stream as Direct3D 11 and OpenGL
Qt parity Measure against PySide6, run the identical programs on Qt and BUI, inhabit in the missing classes, afterward install() so import PySide6 programs run unchanged
More languages MyGo, C#, Go, Zig, Swift, Kotlin and Lua complete the identical C header; Godot, Unity and Bevy; Flutter

Our roadmap has no dates on it. Like a fine render, it's done whenever the noise goes away.

Do I need Blender installed? No. BUI contains the parts of Blender's UI code it needs and builds on its own. Is it really my unchanged tkinter app? Yes. blenderui-tk app.py makes import tkinter come back BUI's implementation, which covers all community tkinter and ttk name. Nine real programs are tested to behave identically on the norm archive and on BUI. See the limitations for the few differences. Is it a web browser in Rust? No. There's no browser motor and no network. BUI takes HTML elements and CSS as a UI language: they are laid out with taffy and drawn by BUI's engine, alongside Blender's widgets anywhere you ask for them, in a native window. JavaScript is optional: the Rust crate needs none, and the JavaScript packages drive the identical engine. Is the Dear ImGui assistance a re-implementation? No. It's the genuine Dear ImGui (vendored, MIT), operating on a BUI backend, so every function behaves as upstream. The optional Blender-widgets build swaps lone how ImGui's widgets are drawn and how they react to the mouse, by compiling an edited copy of imgui_widgets.cpp. How is it distinct from Electron, Electrobun or GPUIX?
  • Electron ships Chromium alongside all app: on the command of 100 MB or more.
  • Electrobun runs on Bun and renders in the system's webview. It's small to download, but the UI is motionless a browser page.
  • GPUIX, akin BUI, renders React natively: React drives Zed's GPUI.
BUI additionally renders natively, alongside Blender's widgets, a much larger part of CSS, Tailwind, and hooks backed by signals. bui build makes a 5 MB executable that reaches its archetypal example in concerning 70 ms. Do the macros disbursal performance? rsx!, #[component], css! and tw! expand at compile period into the identical builder calls you would compose by hand. Tailwind classes are compiled to CSS once, on archetypal use. Hooks are a few nanoseconds per peruse or write. Can I alter the colors? Yes. Switch between Blender's Dark and Light themes at run time (Themes), color idiosyncratic widgets in every API, and use complete CSS on plain HTML elements in Rust and JavaScript. Loading any another Blender theme document is coming soon. Does it run on my Mac? Probably, but nobody has checked yet: the Cocoa presenter is written and experimental. Python can continually autumn rear to the Tk window (BUI_HOST=tk). If you try it, the notes in docs/macos-testing.md say what to report. Is it prepared for production? Much of it is complete and tested (the C kit, tkinter, the components, Rust, Dear ImGui, JavaScript), and several parts are partial or experimental (Qt syntax, parts of CSS and text, macOS). Status and roadmap shows which is which. Pin your version, and test on the platforms you ship. Who wrote it? The repository is built entirely using LLMs, alongside no human-written code. The drawing and communication code is ported from Blender's sources, and the behavior is checked by tests: C, Python, Rust and JavaScript suites, the tkinter side-by-side programs and the GPU parity test. Why GPL? BUI is derived from Blender's origin code, which is GPL-2.0-or-later, so BUI is too. Can I use BUI in a business app? The GPL allows business use. What it asks is that whenever you allocate a program that includes BUI, you allocate it under the GPL too, alongside its source code available. If that doesn't fit your project, conversation to a attorney before you ship. (This is a summary, not lawful advice.) Star History Chart

42. Contributing and publishing

Contributions are welcome: bug reports, missing tkinter/Qt behavior, CSS features, phase hosts and docs. If you have a Mac, operating the Cocoa host and reporting what happens is among the most helpful things you can do right now. Read CONTRIBUTING.md first, and delight prosecute the Code of Conduct. Report safety issues privately, as SECURITY.md describes.

Releases go to PyPI (blenderui, wheels built by CI on a v* tag), crates.io (the eight Rust crates, in dependency order) and npm (@blender-ui/native, @blender-ui/react). The steps are in docs/publishing.md.

License. BUI is derived from Blender sources and is licensed GPL-2.0-or-later. The SPDX header is kept in all file. Third-party parts keep their own licenses:

Part What it does in BUI License
Blender sources Widget drawing, communication rules, theme, icons, blenlib, GHOST opening code, the File Browser and node editor GPL-2.0-or-later
Dear ImGui by Omar Cornut The immediate-mode GUI that runs on BUI MIT
Inter by Rasmus Andersson The embedded UI font, as in Blender (gpu/extern/Inter-LICENSE.txt) SIL Open Font License 1.1
FreeType 2.13.3 Glyph loading, hinting and rendering, akin Blender's BLF FreeType License or GPLv2 (dual-licensed)
stb_truetype by Sean Barrett Font metrics and character maps, and the fallback rasterizer Public domain
NanoSVG by Mikko Mononen, as edited by Blender Rasterizing Blender's SVG icons Zlib
Slug by Eric Lengyel The GPU glyph safety algorithm (shader code "Copyright 2017 by Eric Lengyel") MIT
Tailwind CSS The v4 default theme values rearward the Tailwind support MIT

The Rust and JavaScript bindings additionally depend on crates and packages specified as taffy, napi-rs, React and QuickJS, all under its own license.

Acknowledgments. Thank you to:

  • Blender and its community: the UI this project is built from, including its GHOST opening code and blenlib.
  • Dear ImGui by Omar Cornut: the immediate-mode GUI that runs on BUI.
  • taffy: flexbox, grid and obstacle layout for the Rust crate.
  • Tailwind CSS: the v4 theme rearward the Tailwind support.
  • FreeType: glyph rendering, as in Blender.
  • stb_truetype: font metrics and the fallback rasterizer.
  • NanoSVG by Mikko Mononen: the icon rasterizer, via Blender's edited copy.
  • Inter by Rasmus Andersson: the embedded UI font, as in Blender.
  • Slug by Eric Lengyel: the GPU glyph safety algorithm.
  • gpui, zopra and Leptos: the APIs the Rust syntax follows.

BUI is Blender's UI, minus the default cube. You're liberated to add your own.

Other Article Hacker News
↑
Close Right Ads
Close Left Ads