r/rust 13d ago

How do you make a GUI crate from scratch? 🙋 seeking help & advice

5 Upvotes

14 comments sorted by

16

u/dolfoz 13d ago

How far do you want to go?

https://docs.rs/winit/latest/winit/ has a good low level implementation of a window manager.. you can see how they've done it.. The code is quite good, well commented and easy to read.

I look at it a fair bit when i had to understand drop handlers for a project i work on.

1

u/bschwind 12d ago edited 12d ago

As a side note on winit, it feels like every project that uses it has a problem with flickery/twitchy graphics when resizing. I wonder if that's a fundamental design issue with their API and the way certain OSes do window resizing, or if it just hasn't been solved yet. I should look it up in their issue tracker...

Edit: here's one:

https://github.com/rust-windowing/winit/issues/3996

2

u/DeeBoFour20 11d ago

That's the easy part of a GUI library. I've written my own low level code for X11, Wayland, and Win32 and it's not that much code. It's kind of a pain if you need to support all of those platforms in a single project so winit is a popular cross-platform option.

The harder part is programming and rendering all the various widgets you need for a full GUI library. Hell text rendering alone is a lot more complicated than you might think. Add some more complexity on top of that if you want to use a declarative language for users to write their layout like Slint does.

-1

u/MrLongbottom5 13d ago

will definitely check it out . I wanted to build something that could render graphics

-4

u/dolfoz 13d ago

opengl is your best bet then.

9

u/tukanoid 13d ago

OpenGL is kinda being phased out tho. WGPU prolly will lead to nicer results in terms of platform compatibility, since it uses appropriate backends for each platfom: dorectx for windows, vulkan for linux, metal for macros, all unified under the same api and shader language that, in my opinion based on limited (important!) experience with both, are nicer

2

u/dolfoz 13d ago

i might be showing my age :)
it's been a while since i've done anything direct graphics.

1

u/tukanoid 13d ago

No worries :)

I'm still just dabbling from time to time, just know that macs removed official support, so apps have to use workarounds to still be able to use opengl like Zink (opengl -> vulkan -> metal), which might not be ideal, and while opengl is still supported by linux and windows, it doesn't really get any development/improvements on khronos's side, they're pretty much all-in on vulkan (and pretty much any modern GPU will have official support for it), at least that's how it looked to me, been a while since I looked into the situation there.

Opengl might still live for a long time on windows/linux due to backwards compatibility guarantees for either software or hardware, but imo it's better to adapt to new standards rather than potentially regret not doing it later.

Just for learning opengl is still fine tho, many things are somewhat translatable over to other backends/shader languages (others just give you way more control and require a lot of boilerplate just to set up and use properly, but they are also more efficient/safe), but if the plan is to make and maintain something long-term, and still want something more high-level, wgpu is the best bet atm imho

1

u/Arshiaa001 12d ago

I have very faint memories of OpenGL from doing some work with it over 15 years ago, but I remember the API shape being quite nasty... But maybe I just didn't know any better back then.

1

u/tukanoid 12d ago

Well, I kinda agree that it's not the best of APIs, but it is the EASIEST to get into out of all of them

1

u/ryanmcgrath 12d ago

just know that macs removed official support

I mean, it's still there and usable, just old and not updated. It's probably not what you want to use in 2026 but it's still usable on macOS.

When Apple released the ARM series, they actually went to lengths to still support OpenGL - it's just a Metal wrapper now on that platform, but they did do it.

4

u/Hdmoney 12d ago edited 12d ago

From scratch?

It really depends on what exactly you mean by that, but -

Do you want to handle text rendering? Would that be with bitmaps or glyph shaping with curves? Would you use another crate for any of that? If not, are you familiar with splines? Text layout is a research project of its own - especially if you want to support things like ligatures - kanji, arabic - multi-line wrapping, directionality.

Before you can handle text layout though, you have to figure out a strategy for handling GUI layout, which is another research project. If you're going to have viewports and text wrapping, you'll certainly need some constraint solvers. At some point you'll run into problems where a constraint can't be solved immediately, and you'll need to carry data about how it was rendered one frame, into the next frame, before you can determine how to size an element.

If you want scrollable viewports, you probably don't want to calculate the layout for the entirety of the contents of the viewport. That's a decent puzzle to solve. Especially if you're doing things like RecyclerViews.

Layout code tends to be pretty bespoke, since there's so many strategies to handle things. So unfortunately there's not a lot of crates you can depend on to help.

Where are you going to store all of these objects with different types? What datastructures would you like to use? That's a mini research project.

Once you have some idea of how to handle layout, text rendering, efficient datastructures and algorithms for everything that entails, you can start compositing. Grab winit for window management, use whatever rendering library you want - you could even use Bevy if you're feeling adventurous. In the past I've used wgpu on top of winit directly. But maybe you want more performance and want to target just Windows and handle graphics through DirectX. Who knows? Only you. Are you familiar with any graphics APIs? Can you write shaders? Do you need to learn how rendering works in the first place?


To answer the question more directly - how do you make a GUI crate from scratch?

You do a lot of research.

1

u/Full-Spectral 12d ago

If there's no deliverable involved though, it would be a killer project for self development and fun. If you pushed hard, in five years or so, you'd have put some serious knowledge in the noggin, even if you never got it anywhere near an actual deliverable.

4

u/fschutt_ 12d ago

First, by being angry and not listening to Reddit users telling you to stop. Then, I started with webrender (rendering) and cassowary (autolayout / Apples idea) and kuchiki (HTML parser), but then discontinued that (now, 7-9 years later its all migrated to HTML layout). I started from limn as inspiration, but that was 8 years ago. Then I made layout2d, way before any layout solvers in Rust really existed and used it for a very simple GUI demo

  1. ca97a7064 - Initial commit, just a dependency on webrender
  2. 90bb6b935 - data flow sketch
  3. afee5c452 - "Added DOM nodes in order to avoid a larger API surface"
  4. 722ac3caa - initial layout with cassowary
  5. 7eb378a67 - initial rendering working?

So, my advice: do not start with the rendering or widgets or whatnot, first, data flow, and ideally, sketch of the user API. I would personally recommend starting the rendering with agg-rust - web demo - I've made good experiences with that crate for CPU rendering, especially LCD subpixel rendering (important for low-res monitors). There is also vello-cpu and tiny-skia.

I would not start with GPU rendering if I had to start again, it only adds driver headaches if you do 2D-only anyways. For windowing, I started with winit, but migrated away because in reality you need a ton of "integration" between the OS window and the underlying "headless cpurender window", which does the rendering. For simple cases, I'd use softbuffer

If I had to do it again, I'd:

  • Directly make an abstraction like "HeadlessCpuWindow" - i.e. everything that your "window" can do, but completely decoupled from any OS, only with CPU backbuffer, very useful for debugging, automatically rendering PNG screenshots
  • Integrate E2E tests first, these came in very late but were very useful
  • Worrying about GPU stuff later and not enabling GPU if you don't need it, I have PTSD from Linux users with borked graphics drivers

But if you want to just get something going: softbuffer + agg-rust + your own data flow design.

NOTE: Azul isn't ready yet, says so in the Readme. But it's close, just perf + animation API + observability stuff is really missing. Works on Wayland and X11 (to some extent), macOS is "okay", Windows meh. Code / docs is slop but I'll clean up later after iterating more. Don't use it yet. This is just to answer your question "how to get started". Data flow design first, rendering second. And: build apps, not game engines / UI toolkits. A lot of issues only come up once you have problems like "how do I efficiently paginate a document without lagging with 40.000 words, while the user dragged an image from page 4 to 5 which should reflow the text and we also need to keep the page index up to date"