Benchmarks
BUI's published numbers with their full context: start time and battery cost for every API, frame times, Rust against gpui, and JavaScript startup and animation.
- Ryzen 7 5800U
- Windows 11
BUI is fast where it matters to people: it opens quickly, it sits at zero CPU while you’re not touching it, and it stays smooth when thousands of things move. Here are the numbers, with everything you need to judge them.
Start time and battery
What was measured: the same small settings window (a label, a text field, a checkbox, a slider and a button), written each of the five ways, from bench/apps. Each ran on BUI’s CPU renderer (the default) and on its GPU renderer (BUI_GPU=1).
The last rows are one gpui-syntax source 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.
How: the median of 10 launches, from process start until the first frame is on screen, with Python 3.14 and Node 22.
Start time, every way in
The same small settings window written five ways; median of 10 launches
Lower is better
- CPU renderer
- GPU renderer
- RustHTML + CSS
- CPU renderer: 38 ms
- GPU renderer: 42 ms
- JavaScriptReact, Node.js
- CPU renderer: 94 ms
- GPU renderer: 99 ms
- Blender componentsPython
- CPU renderer: 112 ms
- GPU renderer: 116 ms
- tkinter syntaxPython
- CPU renderer: 139 ms
- GPU renderer: 159 ms
- Qt syntaxPython
- CPU renderer: 156 ms
- GPU renderer: 161 ms
Open benchClose bench
| App | 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 |
Python 3.14 and Node 22. The last rows are one gpui-syntax source file (bindings/rust/bench/common/settings.rs) compiled unchanged against blenderui, gpui and gpui-fast; gpui has no form widgets, so there the controls are styled divs. Battery cost is the CPU time an app causes; memory doesn't count GPU memory.
Source: README.md#performance · Ryzen 7 5800U laptop, Windows 11, on AC power
| App | 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 |
Python 3.14 and Node 22. The last rows are one gpui-syntax source file (bindings/rust/bench/common/settings.rs) compiled unchanged against blenderui, gpui and gpui-fast; gpui has no form widgets, so there the controls are styled divs. Battery cost is the CPU time an app causes; memory doesn't count GPU memory.
What it means:
- On the same code, blenderui shows its first frame about 5× sooner than gpui and gpui-fast, spends about 8× less CPU getting there, and on the CPU renderer uses half the memory.
- Idle, gpui keeps about 1.2% of a core busy. blenderui uses none.
- The GPU renderer starts a little slower and uses more memory (the GPU device). It pays off on large, animated scenes, below.
Start time, same gpui code
One gpui-syntax file compiled against each library; median of 10 launches
Lower is better
5.7×faster start than gpui-fast
- BUI
- Others
- blenderuiCPU renderer40 ms
- blenderuiGPU renderer43 ms
- gpui-fastGPU226 ms5.7× more
- gpuiZed's, GPU231 ms5.8× more
Open benchClose bench
| Same gpui code | Renderer | Start time | CPU used to start | Memory (idle) | Idle CPU per minute |
|---|---|---|---|---|---|
| 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 |
gpui has no form widgets, so there the controls are styled divs. Memory doesn't count GPU memory.
Source: README.md#performance · Ryzen 7 5800U laptop, Windows 11, on AC power
Idle CPU, same gpui code
CPU time per minute while the window sits idle
Lower is better
0 msidle CPU on the CPU renderer: it sleeps
- BUI
- Others
- blenderuiCPU renderer0 ms
- blenderuiGPU renderer2.1 ms
- gpui-fastGPU2.5 ms1.2× more
- gpuiZed's, GPU743 ms354× more
Open benchClose bench
| Same gpui code | Renderer | Start time | CPU used to start | Memory (idle) | Idle CPU per minute |
|---|---|---|---|---|---|
| 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 |
gpui has no form widgets, so there the controls are styled divs. Memory doesn't count GPU memory.
Source: README.md#performance · Ryzen 7 5800U laptop, Windows 11, on AC power
How battery cost is measured: laptops can’t report energy per app, so the benchmark uses CPU time as a proxy. It counts the CPU an app spends starting up, and the CPU it uses over 20 seconds while the window sits idle: that’s what drains a battery while an app is open. BUI redraws only when something changes and otherwise sleeps, so idle use is near zero on either renderer.
Fine print: Node’s event loop accounts for the JavaScript idle figure. Python’s times include starting the interpreter. Memory doesn’t count GPU memory.
Frame times
What was measured: the full Blender components demo (520×900), from Python and C.
Frame cost
Python and C, the full component demo (520×900)
Lower is better
0.05 msfor a hover or scrub frame
- Complete frameeverything redrawn~0.7 ms
- Input to screennative window~0.06 ms
- Hover or scrubdamage only~0.05 ms
Open benchClose bench
| Frame | Time |
|---|---|
| Complete frame (everything redrawn) | ~0.7 ms |
| Hover or number-scrub frame (damage only) | ~0.05 ms |
| Native window: input event → on screen | ~0.06 ms |
Dear ImGui's demo window with every section open (27k triangles, 1280×800) is a full software redraw of about 5–8 ms.
Source: README.md#performance · Ryzen 7 5800U laptop, Windows 11, on AC power
Rust against gpui and gpui-fast
What was measured: a 1000×800 window filled with N rounded, numbered cells, built with the same element tree in every framework. In this table, every cell changes every frame (the worst case), with 3,000 cells. All apps ran in the same session.
Frames per second
Rust, 3000 animated cells, same session
Higher is better
3×the frame rate of gpui
- BUI
- Others
- blenderuiGPU renderer59.9 fps
- blenderuiCPU renderer57.6 fps
- gpui-fast31.5 fps1.9× fewer
- gpui19.9 fps3× fewer
Open benchClose bench
| 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 % |
gpui-fast's heavy-scene frame rate varies between sessions on this laptop (30–60 fps), so compare within one session.
Source: README.md#performance · Ryzen 7 5800U laptop, Windows 11, on AC power
CPU per frame
Rust, 3000 animated cells; gpui's numbers don't include its GPU time
Lower is better
2.8×less CPU per frame than gpui-fast
- BUI
- Others
- blenderuiGPU renderer11.6 ms
- blenderuiCPU renderer22.0 ms
- gpui-fast31.9 ms + GPU2.8× more
- gpui50.5 ms + GPU4.4× more
Open benchClose bench
| 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 % |
gpui-fast's heavy-scene frame rate varies between sessions on this laptop (30–60 fps), so compare within one session.
Source: README.md#performance · Ryzen 7 5800U laptop, Windows 11, on AC power
| 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 % |
gpui-fast's heavy-scene frame rate varies between sessions on this laptop (30–60 fps), so compare within one session.
More results, at 100 and 1,000 cells:
Uncapped frame rate
Frames per second with vsync off, as the scene grows
Higher is better
- blenderui GPU
- blenderui CPU
Open benchClose bench
| 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: Application::new().gpu(true), tk.Tk(gpu=True), bui.set_gpu(True) or BUI_GPU=1. Its shaders evaluate the software raster's formulas: 10 of 172,800 pixels differ by more than 3/255.
Source: README.md#performance · Ryzen 7 5800U laptop, Windows 11, on AC power
| 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: Application::new().gpu(true), tk.Tk(gpu=True), bui.set_gpu(True) or BUI_GPU=1. Its shaders evaluate the software raster's formulas: 10 of 172,800 pixels differ by more than 3/255.
What it means:
- The GPU renderer beats gpui-fast on every measurement. It uses 2.2× less CPU per frame at 100 cells, 4.4× less at 1,000 and 2.8× less at 3,000, where it also runs at nearly twice the frame rate. It uses less RAM and the same GPU memory.
- The GPU renderer halves blenderui’s own CPU cost (22.0 to 11.6 ms at 3,000 cells). What stays on the CPU is the Rust side: cascade, layout and the paint list.
- The CPU raster stays the lightest on memory and remains the default.
How: each app measures its own CPU cycles across all threads (Windows’ QueryProcessCycleTime), its frames and its memory, over a 10-second window after a 3-second warm-up. The runner adds GPU utilisation and GPU memory from Windows’ performance counters, because GPU work isn’t process CPU time. “+ GPU” means gpui’s numbers exclude its GPU work, so read them with the GPU columns in the full results.
Fine print: one laptop, one 60 Hz display (which caps every app), an integrated GPU.
JavaScript and React
Startup
What was measured: a small React app (a counter) that quits as soon as its first frame is on screen. Each figure is the median of 12 launches after a warm-up launch (node bench/startup.js).
JavaScript: first frame
A small React app, median of 12 launches
Lower is better
4.9 MBsingle executable with QuickJS
- QuickJS executablebui build68 ms
- Bun executablebui build --bun79 ms
- Bunbun app.js80 ms
- Node.jsnode app.js108 ms
Open benchClose bench
| First frame | Launch to exit | RAM at first frame | What you ship | |
|---|---|---|---|---|
| QuickJS executable (bui build) | 68 ms | 104 ms | 19 MB | 4.9 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 frame is measured from the runtime's start. Launch to exit is wall time measured from outside, including process creation and teardown.
Source: README.md#performance · Ryzen 7 5800U laptop, Windows 11, on AC power
| First frame | Launch to exit | RAM at first frame | What you ship | |
|---|---|---|---|---|
| QuickJS executable (bui build) | 68 ms | 104 ms | 19 MB | 4.9 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 frame is measured from the runtime's start. Launch to exit is wall time measured from outside, including process creation and teardown.
Animation
What was measured: the same scene as the Rust table, in one mode: one cell changes per frame, like a hover or a ticking value. GPU renderer, medians of 3 runs, React’s production build. CPU is the whole process, counted with the cycle counter as for Rust.
- Plain JS uses
@blender-ui/native. - React with signals passes the changing values as signals, so the grid renders once.
- React with state re-renders the grid every frame.
JavaScript: CPU per frame, 3,000 cells
One cell changes per frame; GPU renderer
Lower is better
- Plain JS
- React + signals
- React + state
- QuickJS
- Plain JS: 16.3 ms
- React + signals: 14.9 ms
- React + state: 51 ms
- Bun 1.4
- Plain JS: 13.1 ms
- React + signals: 13.3 ms
- React + state: 20.8 ms
- Node 22
- Plain JS: 14.4 ms
- React + signals: 14 ms
- React + state: 18.9 ms
Open benchClose bench
| 3,000 cells | FPS | CPU per frame | RAM |
|---|---|---|---|
| Rust | 59.6 | 12.0 ms | 43 MB |
| QuickJS: plain JS / React with signals / React with state | 59.1 / 58.7 / 19.7 | 16.3 / 14.9 / 51.0 ms | 56 / 61 / 67 MB |
| Bun 1.4: plain JS / React with signals / React with state | 58.8 / 58.4 / 55.8 | 13.1 / 13.3 / 20.8 ms | 80 / 85 / 118 MB |
| Node 22: plain JS / React with signals / React with state | 55.8 / 56.7 / 54.8 | 14.4 / 14.0 / 18.9 ms | 88 / 93 / 121 MB |
Plain JS uses @blender-ui/native; React with signals renders the grid once; React with state re-renders it every frame. React's production build throughout.
Source: README.md#performance · Ryzen 7 5800U laptop, Windows 11, on AC power
| 3,000 cells | FPS | CPU per frame | RAM |
|---|---|---|---|
| Rust | 59.6 | 12.0 ms | 43 MB |
| QuickJS: plain JS / React with signals / React with state | 59.1 / 58.7 / 19.7 | 16.3 / 14.9 / 51.0 ms | 56 / 61 / 67 MB |
| Bun 1.4: plain JS / React with signals / React with state | 58.8 / 58.4 / 55.8 | 13.1 / 13.3 / 20.8 ms | 80 / 85 / 118 MB |
| Node 22: plain JS / React with signals / React with state | 55.8 / 56.7 / 54.8 | 14.4 / 14.0 / 18.9 ms | 88 / 93 / 121 MB |
Plain JS uses @blender-ui/native; React with signals renders the grid once; React with state re-renders it every frame. React's production build throughout.
| 1,000 cells | FPS | CPU per frame | RAM |
|---|---|---|---|
| Rust | 60 | 4.8 ms | 32 MB |
| QuickJS: plain JS / React with signals / React with state | 60 / 60 / 56.8 | 6.0 / 5.6 / 17.8 ms | 38 / 40 / 43 MB |
| Bun: plain JS / React with signals / React with state | 60 / 60 / 60 | 5.2 / 5.2 / 7.5 ms | 58 / 63 / 81 MB |
| Node: plain JS / React with signals / React with state | 60 / 60 / 60 | 5.6 / 5.6 / 6.9 ms | 68 / 71 / 97 MB |
What it means:
- JavaScript costs little over Rust: 0.4–2.4 ms per frame, for sending changes to BUI’s UI thread.
- Signals make React as cheap as the plain API: the component doesn’t re-render.
- QuickJS starts fastest and uses the least memory, from a 5 MB file. It has no JIT, so re-rendering a 3,000-element list every frame drops it to 20 FPS. Keep big lists on signals, or build with
--bun.
Next steps
Last updated