Mousefood - a no-std embedded-graphics backend for Ratatui!
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(()) }
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.
Run simulator example:
git clone https://github.com/ratatui/mousefood.git
cd mousefood/examples/simulator
cargo runFor more details, view the simulator example.
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.
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!
Mousefood is dual-licensed under Apache 2.0 and MIT terms.




