A Bevy plugin for rendering terminal-style UIs using ratatui and WGPU
Seamlessly integrate terminal UIs into your Bevy applications. Display ratatui widgets on 2D sprites, 3D meshes, or UI elements with full GPU acceleration.
Terminal3D.mp4
- GPU-Accelerated Terminal Rendering - Render ratatui terminal UIs as GPU textures using WGPU
- Flexible Display Options - Render terminals on Bevy UI nodes, 2D sprites, or 3D meshes
- Full Unicode Support - Complete support for CJK (Chinese, Japanese, Korean) characters
- Interactive Input - Built-in keyboard and mouse input handling with focus management
- Programmatic Glyphs - Automatic rendering of box-drawing, block elements, and Braille patterns
- Real-time Updates - Efficient real-time terminal content updates with minimal overhead
- Easy Setup API - Simple
SimpleTerminal2DandSimpleTerminal3Dhelpers for quick integration
Add to your Cargo.toml:
[dependencies]
bevy = "0.18"
font-kit = "0.14"
bevy_tui_texture = "0.2"use bevy::prelude::*;
use bevy::render::renderer::{RenderDevice, RenderQueue};
use bevy_tui_texture::prelude::*;
use bevy_tui_texture::Font as TerminalFont;
use font_kit::family_name::FamilyName;
use font_kit::properties::Properties;
use font_kit::source::SystemSource;
use ratatui::prelude::*;
use ratatui::style::Color as RatatuiColor;
use ratatui::widgets::*;
use std::sync::Arc;
#[derive(Resource)]
struct Terminal(SimpleTerminal2D);
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(TerminalPlugin::default())
.add_systems(Startup, setup)
.add_systems(Update, render_terminal.in_set(TerminalSystemSet::Render))
.run();
}
fn setup(
mut commands: Commands,
render_device: Res<RenderDevice>,
render_queue: Res<RenderQueue>,
mut images: ResMut<Assets<Image>>,
) {
let fonts = {
let font_data = SystemSource::new()
.select_best_match(&[FamilyName::Monospace], &Properties::new())
.unwrap().load().expect("Failed to load font").copy_font_data()
.expect("Failed to copy font data");
let font_data: &'static [u8] = Box::leak(font_data.to_vec().into_boxed_slice());
Arc::new(Fonts::new(
TerminalFont::new(font_data).expect("Failed to parse font"), 16))
};
// Create termial
let terminal = SimpleTerminal2D::create_and_spawn(
80, 25, fonts, (0.0, 0.0), true, false, false, &mut commands, &render_device,
&render_queue, &mut images,
)
.expect("Failed to create terminal");
// Spawn Camera
commands.spawn(Camera2d);
commands.insert_resource(Terminal(terminal));
}
fn render_terminal(
mut terminal: ResMut<Terminal>,
render_device: Res<RenderDevice>,
render_queue: Res<RenderQueue>,
mut images: ResMut<Assets<Image>>,
) {
terminal.0.draw_and_render(&render_device, &render_queue, &mut images, |frame| {
let area = frame.area();
// Simple "Hello, World!" paragraph
let text = Paragraph::new("Hello, World!")
.style(Style::default().fg(RatatuiColor::Green).bold())
.alignment(Alignment::Center)
.block(Block::bordered().title("Minimal Example"));
frame.render_widget(text, area);
});
}The examples/ directory contains comprehensive demonstrations:
helloworld.rs- Minimal example showing basic terminal rendering
widget_catalog_2d.rs- Interactive showcase of ratatui widgets in 2D UIwidget_catalog_3d.rs- Interactive showcase of ratatui widgets on rotating 3D mesh
multiple_terminals.rs- Managing multiple independent terminalsshader_mesh.rs- Custom shader effects and mesh3d with terminal texturesbenchmark.rs- Performance benchmarking and optimization
wasm_demo.rs- Full widget catalog running in browserwasm_serve.rs- One-command WASM build & serve
cargo run --example helloworld
cargo run --example widget_catalog_3d
# For WASM demo
rustup target add wasm32-unknown-unknown
cargo install wasm-bindgen-cli
# Install wasm-opt (via binaryen)
# macOS: brew install binaryen
# Ubuntu: apt install binaryen
# Install wabt for wasm-strip (via wabt)
# macOS: brew install wabt
# Ubuntu: apt install wabt
cargo run --example wasm_serve
# Output files are placed in `examples/web/`.Configure features in your Cargo.toml:
[dependencies.bevy_tui_texture]
version = "0.2"
default-features = false
features = ["keyboard_input", "mouse_input", "ratatui_backend"]Available features:
keyboard_input(default) - Enable keyboard event handlingmouse_input(default) - Enable mouse event handling for both 2D UI and 3D mesh terminalsratatui_backend(default) - Enable ratatuibold_italic_fonts- Enable fake bold and italic font rendering supportemoji- Enable emoji and extended Unicode character support (WIP)
This library is designed for real-time rendering with:
- Efficient GPU texture updates
- Cached glyph rendering with text atlas
- Minimal CPU-GPU data transfer
- Smart dirty tracking for terminal cells
See examples/benchmark.rs for performance metrics.
- Rust 1.92 or later (2024 edition)
- Bevy 0.18
- Ratatui 0.30
- A GPU with WGPU support
bevy |
ratatui |
bevy_tui_texture |
|---|---|---|
0.18 |
0.30 |
0.2 |
0.17 |
0.29 |
0.1 |
- Windows - Full support
- macOS - Full support
- Linux - Full support
The library renders ratatui terminal UIs as GPU textures, which works in WebGL2 environments. The WASM demo showcases a interactive widget catalog running on a rotating 3D plane in your browser.
- Bevy 0.18 + WGPU 27.0.1 (WebGL2 backend)
- Full ratatui widget rendering (Tabs, Lists, Charts, Gauges, etc.)
- Keyboard and mouse input handling
- 3D ray casting for mouse interaction on 3D meshes
- Programmatic glyphs (box-drawing, block elements, Braille)
- Real-time animations and updates
- Font embedding via
include_bytes!()
Contributions are welcome! Please feel free to submit issues or pull requests.
- See LICENSE
This library builds on the excellent work of:
- Bevy - A refreshingly simple data-driven game engine
- ratatui - A Rust library for cooking up terminal user interfaces
- WGPU - Safe and portable GPU abstraction in Rust
- ratatui-wgpu - Ratatui WGPU backend that inspired this work
- rio - Beautiful glyph rendering
- bevy_egui - Egui integration for Bevy
- egui_ratatui - Egui widget + ratatui backend
- bevy_ui - Native Bevy UI
- tui-rs - Original terminal UI library