created_at2021-07-30 13:02:46.09536
updated_at2023-11-21 18:00:23.64021
descriptionA bevy 3D text mesh generator for displaying text
Mika (blaind)



bevy_text_mesh   Build Status Latest Version Docs Version

A bevy 3D text mesh generator plugin for displaying text in 3D scenes


The text mesh is generated at runtime from runtime-tessellated (and cached) TrueType font glyphs. Tessellation of glyphs is done with C-based library that is being interfaced through Rust-based FFI API (see ttf2glyph-rs).

Known limitations

Consider this as a preview of the plugin for gathering feedback about the API:

  • The API will change in future - still iterating
  • Multiple TextMesh configuration fields are not implemented yet, see example below
  • Text color update is not implemented yet
  • Spacing of characters are incorrect
  • Mesh cache purging is not implemented - this implementation will leak memory (see #2)
  • WASM builds are not supported (see #11)

Bevy versions support table

bevy bevy_text_mesh
0.12 0.9.0
0.11 0.7.0
0.10 0.6.0
0.9 0.5.0
0.8 0.4.0
0.7 0.2.0
0.6 0.1.0
0.5 0.0.2



Prequisites (for compiling ttf2mesh-rs):

apt-get install build-essential patch

Running the examples

See the examples -folder.

git clone
cd bevy_text_mesh
cargo run --example 3d_scene --release # or
cargo run --example performance --release

Integrating to your Bevy App

Add to Cargo.toml:

bevy_text_mesh = "0.9.0"

Include the library:

use bevy_text_mesh::prelude::*;

Second, add a TextMeshPlugin to your app:


Then, add the desired TrueType-fonts (with suffix .ttf) into your assets folder, a good convention is to store them to assets/fonts folder.

For example, see Fira fonts. Please read also their LICENSE.

mkdir -p assets/fonts
wget -O assets/fonts/FiraSans-Medium.ttf

Next, you are ready to spawn a text in your scene at a system:

First, load a font asset:

let font: Handle<TextMeshFont> = asset_server.load("fonts/FiraSans-Medium.ttf#mesh");

Then, spawn a textmesh bundle:

commands.spawn(TextMeshBundle {
    text_mesh: TextMesh::new_with_color("Hello Bevy", font, Color::rgb(1., 1., 0.)),
    transform: Transform::from_xyz(-1., 1.75, 0.),

Or with expanded syntax:

commands.spawn(TextMeshBundle {
    text_mesh: TextMesh {
        text: String::from("Hello Bevy!"),
        style: TextMeshStyle {
            font_size: SizeUnit::NonStandard(36.),
            color: Color::rgb(1.0, 1.0, 0.0),
            font_style: FontStyle::UPPERCASE, // only UPPERCASE & LOWERCASE implemented currently
            mesh_quality: Quality::Low,
        alignment: TextMeshAlignment {
            vertical: VerticalAlign::Top, // FUNCTIONALITY NOT IMPLEMENTED YET - NO EFFECT
            horizontal: HorizontalAlign::Left, // FUNCTIONALITY NOT IMPLEMENTED YET - NO EFFECT
        size: TextMeshSize {
            width: SizeUnit::NonStandard(135.),       // partially implemented
            height: SizeUnit::NonStandard(50.),       // partially implemented
            depth: Some(SizeUnit::NonStandard(50.0)), // must be > 0 currently, 2d mesh not supported yet
            wrapping: true,                           // partially implemented
            overflow: false,                          // NOT IMPLEMENTED YET
    transform: Transform {
        translation: Vec3::new(-1., 1.75, 0.),


Licensed under MIT license


Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the software by you, shall be licensed as above, without any additional terms or conditions.

Commit count: 38

cargo fmt