slint
Declarative GUI toolkit for Rust — SPEC.md's handoff spec names it
explicitly ("Rust + Slint + libmpv"), so no alternative was considered.
UI layout/styling live in .slint markup (crates/app/ui/app-window.slint),
compiled at build time via slint-build (build.rs) into generated Rust
types main.rs instantiates with slint::include_modules!().
Pitfalls
.slintfiles aren't Rust —cargo fmt/clippydon't touch them; no linting is wired intoscripts/check.sh.- Slint's winit backend allows only one platform/event-loop init per
process, bound to its creating thread — a second
AppWindow::new()on another thread (e.g. a second#[test]) fails ("platform was initialized in another thread"). All assertions needing a realAppWindowmust live in one test function. AppWindow::new()needs a working windowing backend + X11/Wayland connection to construct at all (winit initializes its event loop immediately, even without ever showing the window) — it's not display-free. CI runsscripts/test.shunderxvfb-runfor this reason (.github/workflows/ci.yml). Property-wiring tests never call.show(), so no compositor/renderer work happens beyond that; actual pixels-on-screen checks stay manual (cargo run -p trango).- Custom fonts (
"Inter","JetBrains Mono") only render if installed as system fonts; Slint falls back silently otherwise — no fonts are bundled. HorizontalLayout/VerticalLayoutdefault tocross-axis-alignment: stretch— children fill the full cross-axis extent unless a layout setscross-axis-alignment: center(as the top bar does).- No dashed-border support — dashed empty-state rows are approximated with a solid muted border instead.
DropArea/DragAreadon't relay OS file drops — only in-appDragAreasources firedropped(confirmed by greppingi-slint-backend-winit1.17.1 forWindowEvent::DroppedFilehandling: there is none), andDataTransferhas no file/path payload type yet (tracking issue). This is why subtitle/translation linking uses an in-app file picker instead of drag-and-drop — see Design decisions.