Building apps in Rust is supposed to be the future. Instead, it's a maze of trade-offs that nobody explains to you until you're three months in and can't escape.
That's what Matija discovered when he tried to build a multiplayer board game. Bevy crams you into ECS. Iced buries you in .into() calls. egui makes you manually manage spacing. Slint needs a separate markup language. Macroquad has no UI system at all.
So he built Ply — and in the process, revealed something important about how Rust frameworks should work.
The Problem Nobody Talks About
Rust is great at systems programming. It's terrible at app programming.
This isn't a language problem — it's a framework problem. Every Rust UI framework forces you to choose between:
- Control (write everything yourself, fight the framework for every pixel)
- Productivity (accept the framework's model, even when it fights your intuition)
Bevy gives you ECS whether you want it or not. Iced gives you functional reactive programming whether you understand it or not. Slint gives you QML whether you've ever seen Qt or not.
What Rust doesn't give you is a framework that gets out of your way while still doing the hard stuff.
What Ply Does Differently
Ply's core philosophy: make it easier while giving you full control.
That's vague until you see the code. Here's what that looks like in practice:
// Ply's builder pattern + closures
ply::window("My App", (800, 600), |ui| {
ui.frame(|frame| {
frame.text("Hello, Ply!")
.font_size(32)
.center();
});
});
Compare this to Bevy's equivalent (simplified):
// Bevy - ECS everywhere
commands.spawn(TextBundle::from_section(
"Hello",
TextStyle { font_size: 32.0, ..default() },
)).insert(JustifyText::Center);
Or Iced:
// Iced - the .into() avalanche
Text::new("Hello")
.size(32)
.align(Horizontal::Center)
Ply's approach is different in three ways:
1. Immediate Mode (But Fast)
Ply rebuilds the UI every frame. That sounds expensive — and in most frameworks, it would be.
But the author argues: you're redrawing every frame anyway. The GPU is where the time goes, not the layout calculation. Immediate mode means no diffing, no state tracking, no hidden mutations. You just describe what you want, Ply renders it.
Love2D proved this works at scale. Ply takes the same bet.
2. Builder Pattern + Closures
No .end() calls. No deep indentation for every nested element. No ..default() everywhere.
Closures cure the verbosity problem. Builder methods cure the configuration problem. Into<T> everywhere means you can pass hex integers, float tuples, or existing colors — no wrapper functions needed.
// These all work:
.background_color(0xFF0000) // hex
.background_color((255, 0, 0)) // tuple
.background_color(Color::RED) // existing color
3. Managers for State That Persists
Everything runs in a loop in game/app development. Managing state between frames is painful.
Ply gives you managers: TEXTURE_MANAGER, MATERIAL_MANAGER, FONT_MANAGER, NET_MANAGER. You tell the engine where your resources are. It handles caching, eviction, and lifetime. You never think about it.
This is the kind of boring infrastructure that makes frameworks feel "magic" — in a good way.
What 1.0 Ships With
Ply 1.0 isn't a proof of concept. It includes:
- Flexbox-like layout engine — padding, gaps, alignment, scrolling, floating elements
- Full text input — cursor, selection, undo/redo, multiline, password mode, keyboard shortcuts
- Rich text styling — inline colors, gradients, shadows, typewriter effects
- GLSL shaders — on any element, with a SPIR-V build pipeline
- Accessibility — via AccessKit on desktop, JavaScript bridge on web
- HTTP + WebSocket — never blocks the UI
- Cross-platform — Linux, macOS, Windows, Android, iOS, web
There's also a Chrome DevTools-style inspector. No other Rust UI library has this.
The Bigger Picture
What strikes me about Ply isn't just the feature list — it's the philosophy.
The author didn't set out to build a framework. He set out to build a game, hit a wall with every existing option, and decided the wall was the problem.
That's the right instinct. Frameworks should adapt to your problem, not force your problem to adapt to them.
Ply isn't for everyone. If you love ECS, Bevy is still there. If you love declarative UI, Slint is still there. But if you want "write code that reads like what you mean, get results without fighting the borrow checker" — Ply might be what Rust has been missing.
The installation is two commands:
cargo install plyx
plyx init
It comes with a font from Google Fonts, feature flags, and a project structure. The interactive docs run in your browser.
Go build something.
What's your experience with Rust UI frameworks? Are you team Bevy, team Iced, or team "I just want to write code"? Hit me up — I'm building in public and want to know what actually works for people.