1use bevy::{
7 color::palettes::css::GOLD,
8 diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin},
9 prelude::*,
10 text::{FontFeatureTag, FontFeatures, FontSize, Underline},
11};
12
13fn main() {
14 let mut app = App::new();
15 app.add_plugins((DefaultPlugins, FrameTimeDiagnosticsPlugin::default()))
16 .add_systems(Startup, setup)
17 .add_systems(Update, (text_update_system, text_color_system));
18 app.run();
19}
20
21#[derive(Component)]
23struct FpsText;
24
25#[derive(Component)]
27struct AnimatedText;
28
29fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
30 commands.spawn(Camera2d);
32 commands.spawn((
34 Text::new("hello\nbevy!"),
36 Underline,
37 TextFont {
38 font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
40 font_size: FontSize::Vh(20.0),
42 ..default()
43 },
44 TextShadow::default(),
45 TextLayout::justify(Justify::Center),
47 Node {
49 position_type: PositionType::Absolute,
50 bottom: px(5),
51 right: px(5),
52 ..default()
53 },
54 AnimatedText,
55 ));
56
57 commands
59 .spawn((
60 Text::new("FPS: "),
62 TextFont {
63 font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
65 font_size: FontSize::Px(42.0),
66 ..default()
67 },
68 ))
69 .with_child((
70 TextSpan::default(),
71 (
72 TextFont {
73 #[cfg(not(feature = "default_font"))]
75 font: asset_server.load("fonts/FiraMono-Medium.ttf").into(),
76 font_size: FontSize::Px(33.0),
77 ..Default::default()
78 },
79 TextColor(GOLD.into()),
80 ),
81 FpsText,
82 ));
83
84 let opentype_font_handle: FontSource =
86 asset_server.load("fonts/EBGaramond12-Regular.otf").into();
87 commands
88 .spawn((
89 Node {
90 margin: UiRect::all(px(12.0)),
91 position_type: PositionType::Absolute,
92 top: px(5.0),
93 right: px(5.0),
94 ..default()
95 },
96 Text::new("Opentype features:\n"),
97 TextFont {
98 font: opentype_font_handle.clone(),
99 font_size: FontSize::Px(32.0),
100 ..default()
101 },
102 ))
103 .with_children(|parent| {
104 let text_rows = [
105 ("Smallcaps: ", FontFeatureTag::SMALL_CAPS, "Hello World"),
106 (
107 "Ligatures: ",
108 FontFeatureTag::STANDARD_LIGATURES,
109 "fi fl ff ffi ffl",
110 ),
111 ("Fractions: ", FontFeatureTag::FRACTIONS, "12/134"),
112 ("Superscript: ", FontFeatureTag::SUPERSCRIPT, "Up here!"),
113 ("Subscript: ", FontFeatureTag::SUBSCRIPT, "Down here!"),
114 (
115 "Oldstyle figures: ",
116 FontFeatureTag::OLDSTYLE_FIGURES,
117 "1234567890",
118 ),
119 (
120 "Lining figures: ",
121 FontFeatureTag::LINING_FIGURES,
122 "1234567890",
123 ),
124 ];
125
126 for (title, feature, text) in text_rows {
127 parent.spawn((
128 TextSpan::new(title),
129 TextFont {
130 font: opentype_font_handle.clone(),
131 font_size: FontSize::Px(24.0),
132 ..default()
133 },
134 ));
135 parent.spawn((
136 TextSpan::new(format!("{text}\n")),
137 TextFont {
138 font: opentype_font_handle.clone(),
139 font_size: FontSize::Px(24.0),
140 font_features: FontFeatures::builder().enable(feature).build(),
141 ..default()
142 },
143 ));
144 }
145 });
146
147 #[cfg(feature = "default_font")]
148 commands.spawn((
149 Text::new("From an &str into a Text with the default font!"),
152 Node {
153 position_type: PositionType::Absolute,
154 bottom: px(5),
155 left: px(15),
156 ..default()
157 },
158 ));
159
160 #[cfg(not(feature = "default_font"))]
161 commands.spawn((
162 Text::new("Default font disabled"),
163 TextFont {
164 font: asset_server.load("fonts/FiraMono-Medium.ttf"),
165 ..default()
166 },
167 Node {
168 position_type: PositionType::Absolute,
169 bottom: px(5),
170 left: px(15),
171 ..default()
172 },
173 ));
174}
175
176fn text_color_system(time: Res<Time>, mut query: Query<&mut TextColor, With<AnimatedText>>) {
177 for mut text_color in &mut query {
178 let seconds = time.elapsed_secs();
179
180 text_color.0 = Color::srgb(
182 ops::sin(1.25 * seconds) / 2.0 + 0.5,
183 ops::sin(0.75 * seconds) / 2.0 + 0.5,
184 ops::sin(0.50 * seconds) / 2.0 + 0.5,
185 );
186 }
188}
189
190fn text_update_system(
191 diagnostics: Res<DiagnosticsStore>,
192 mut query: Query<&mut TextSpan, With<FpsText>>,
193) {
194 for mut span in &mut query {
195 if let Some(fps) = diagnostics.get(&FrameTimeDiagnosticsPlugin::FPS)
196 && let Some(value) = fps.smoothed()
197 {
198 **span = format!("{value:.2}");
200 }
201 }
202}