Rust GUI frameworks
2016 Text 2026: rusttype is deprecated; successors carry on
03

Fonts: rusttype to swash

Drawing text is its own ecosystem.

Before a UI can shape or lay out text it needs glyphs: the outlines of individual letters, turned into pixel coverage. Rust's first popular answer was rusttype (2016), later deprecated in favour of ab_glyph, which does the same job with a smaller, faster API. Give it font bytes and a character, and it hands back an outline and, when drawn, a coverage value per pixel. There is no shaping and no layout. (Adjust the font path for your system.)

glyph-fonts/src/bin/one.rs ✔ compiled · ab_glyph 0.2, rusttype 0.9 · rustc 1.95.0
use ab_glyph::{Font, FontRef, PxScale, ScaleFont};
use book_error::{Context, Result};

fn main() -> Result<()> {
    // Three different failures, three different variants: a missing file
    // (Io), a corrupt font (Font), and a glyph with no outline (Missing).
    let bytes = std::fs::read("/System/Library/Fonts/Supplemental/Arial.ttf")?;
    let font = FontRef::try_from_slice(&bytes)?;
    let scaled = font.as_scaled(PxScale::from(32.0));

    // Glyph outlines in, coverage values out: no shaping, no layout.
    let glyph = font.glyph_id('R').with_scale(32.0);
    let outline = font.outline_glyph(glyph).context("font has no outline for 'R'")?;
    let bounds = outline.px_bounds();
    outline.draw(|_x, _y, coverage| {
        let _ = coverage; // 0.0..=1.0 alpha for one pixel
    });
    println!("R is {}x{} px, advance {}", bounds.width(), bounds.height(), scaled.h_advance(font.glyph_id('R')));
    Ok(())
}

The older crate did the same work through a layout iterator that positioned glyphs one after another, which is the shape of the API that most 2016-era Rust GUIs were written against.

glyph-fonts/src/bin/two.rs ✔ compiled · ab_glyph 0.2, rusttype 0.9 · rustc 1.95.0
use book_error::{Context, Result};
use rusttype::{point, Font, Scale};

// rusttype (2016) is deprecated; ab_glyph is its maintained successor.
// The shape of the API shows what "just rasterize text" looked like.
fn main() -> Result<()> {
    let bytes = std::fs::read("/System/Library/Fonts/Supplemental/Arial.ttf")?;
    let font = Font::try_from_vec(bytes).context("file is not a valid TrueType/OpenType font")?;

    let glyphs: Vec<_> = font.layout("Hi", Scale::uniform(32.0), point(0.0, 32.0)).collect();
    for g in &glyphs {
        if let Some(bb) = g.pixel_bounding_box() {
            println!("glyph at {}..{}", bb.min.x, bb.max.x);
        }
    }
    Ok(())
}

Both crates have been overtaken by the fontations family from the Google Fonts team: read-fonts and skrifa parse font files, and swash (which depends on skrifa) scales, rasterizes and shapes. In our lockfiles skrifa is everywhere: egui, iced, Slint, Xilem, Dioxus Native, Floem and gpui all resolve it, and Vello, Parley, cosmic-text and swash depend on it directly. The layers above it, shaping and layout, are the next two pages.

crates.io first publish.