Back Original

Mousefood – Build embedded terminal UIs for microcontrollers

Crate Docs CI Deps

Mousefood - a no-std embedded-graphics backend for Ratatui!

demo animated demo

Add mousefood as a dependency:

Exemplary setup:

use mousefood::embedded_graphics::{mock_display::MockDisplay, pixelcolor::Rgb888};
use mousefood::prelude::*;
use ratatui::widgets::{Block, Paragraph};
use ratatui::{Frame, Terminal};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // replace this with your display driver
    // e.g. ILI9341, ST7735, SSD1306, etc.
    let mut display = MockDisplay::<Rgb888>::new();

    let backend = EmbeddedBackend::new(&mut display, EmbeddedBackendConfig::default());
    let mut terminal = Terminal::new(backend)?;

    terminal.draw(draw)?;
    Ok(())
}

fn draw(frame: &mut Frame) {
    let block = Block::bordered().title("Mousefood");
    let paragraph = Paragraph::new("Hello from Mousefood!").block(block);
    frame.render_widget(paragraph, frame.area());
}

Embedded-graphics includes bitmap fonts that have a very limited set of characters to save space (ASCII, ISO 8859 or JIS X0201). This makes it impossible to draw most of Ratatui's widgets, which heavily use box-drawing glyphs, Braille, and other special characters.

Mousefood by default uses embedded-graphics-unicodefonts, which provides embedded-graphics fonts with a much larger set of characters.

In order to save space and speed up rendering, the fonts feature can be disabled by turning off the default crate features. ibm437 is a good alternative that includes some drawing characters, but is not as large as embedded-graphics-unicodefonts.

Bold and italic modifiers are supported, but this requires providing fonts through EmbeddedBackendConfig. If only regular font is provided, it serves as a fallback. All fonts must be of the same size.

use mousefood::embedded_graphics::{mock_display::MockDisplay, pixelcolor::Rgb888};
use mousefood::{EmbeddedBackend, EmbeddedBackendConfig, fonts};
use ratatui::Terminal;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut display = MockDisplay::<Rgb888>::new();
    let config = EmbeddedBackendConfig {
        font_regular: fonts::MONO_6X13,
        font_bold: Some(fonts::MONO_6X13_BOLD),
        font_italic: Some(fonts::MONO_6X13_ITALIC),
        ..Default::default()
    };
    let backend = EmbeddedBackend::new(&mut display, config);
    let _terminal = Terminal::new(backend)?;
    Ok(())
}

Bold and Italic fonts

Colors can be remapped using color_theme on EmbeddedBackendConfig. By default the ANSI palette is used.

use mousefood::{ColorTheme, EmbeddedBackend, EmbeddedBackendConfig};
use mousefood::embedded_graphics::{mock_display::MockDisplay, pixelcolor::Rgb888};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut display = MockDisplay::<Rgb888>::new();
    let theme = ColorTheme {
        background: Rgb888::new(5, 5, 5),
        foreground: Rgb888::new(240, 240, 240),
        yellow: Rgb888::new(255, 200, 0),
        ..ColorTheme::ansi()
    };

    let config = EmbeddedBackendConfig {
        color_theme: theme,
        ..Default::default()
    };
    let backend = EmbeddedBackend::new(&mut display, config);
    Ok(())
}

Mousefood includes popular color themes that can be used directly:

  • ColorTheme::ansi() - Standard ANSI colors (default)
  • ColorTheme::tokyo_night() - Tokyo Night dark theme with blue/purple tones

Mousefood can be run in a simulator using embedded-graphics-simulator crate.

Screenshot of a window running the simulator with a mousefood application

Run simulator example:

git clone https://github.com/ratatui/mousefood.git
cd mousefood/examples/simulator
cargo run

For more details, view the simulator example.

WeAct epd demo

Support for EPD (e-ink displays) produced by WeAct Studio (weact-studio-epd driver) can be enabled using epd-weact feature.

This driver requires some additional configuration. Follow the weact-studio-epd crate docs and apply the same flush_callback pattern used in the Waveshare example below.

Setup example
use mousefood::prelude::*;
use weact_studio_epd::graphics::Display290BlackWhite;
use weact_studio_epd::WeActStudio290BlackWhiteDriver;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Configure SPI + GPIO + delay provider for your board.
    // let (spi_interface, busy, rst, delay) = ...;

    let mut driver = WeActStudio290BlackWhiteDriver::new(spi_interface, busy, rst, delay);
    let mut display = Display290BlackWhite::new();

    driver.init()?;

    let config = EmbeddedBackendConfig {
        flush_callback: Box::new(move |d| {
            driver.full_update(d).expect("epd update failed");
        }),
        ..Default::default()
    };

    let backend = EmbeddedBackend::new(&mut display, config);
    let _terminal = Terminal::new(backend)?;
    Ok(())
}

Support for EPD (e-ink displays) produced by Waveshare Electronics (epd-waveshare driver) can be enabled using epd-waveshare feature.

Setup example
use mousefood::prelude::*;
use epd_waveshare::{epd2in9_v2::*, prelude::*};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Configure SPI + GPIO + delay provider for your board.
    // let (mut spi_device, busy, dc, rst, mut delay) = ...;

    let mut epd = Epd2in9::new(&mut spi_device, busy, dc, rst, &mut delay, None)?;
    let mut display = Display2in9::default();

    let config = EmbeddedBackendConfig {
        flush_callback: Box::new(move |d| {
            epd.update_and_display_frame(&mut spi_device, d.buffer(), &mut delay)
                .expect("epd update failed");
        }),
        ..Default::default()
    };

    let backend = EmbeddedBackend::new(&mut display, config);
    let _terminal = Terminal::new(backend)?;
    Ok(())
}

See the full embedded example at examples/epd-waveshare-demo.

Performance and hardware support

Flash memory on most embedded devices is very limited. Additionally, to achieve high frame rate when using the fonts feature, it is recommended to use opt-level = 3, which can make the resulting binary even larger.

Mousefood is hardware-agnostic. Successfully tested on:

  • ESP32 (Xtensa)
  • ESP32-C6 (RISC-V)
  • STM32
  • RP2040
  • RP2350

Full API docs are available on docs.rs.

All contributions are welcome!

Before opening a pull request, please read the contributing guidelines.

Here are some projects built using Mousefood:

  • Tuitar - A portable guitar training tool.
  • Mnyaoo32 - An eccentric way to consume IRC messages using ESP32.
  • Phone-OS - A modern phone OS for ESP32 CYD.

Send a pull request to add your project here!

License MIT License Apache 2.0

Mousefood is dual-licensed under Apache 2.0 and MIT terms.