# Suzuri
Suzuri is a text rendering library written in Rust.
Use this crate to layout and render text with consistent results.
This crate prioritizes consistency and reproducibility within a two-pass layout data flow.
It ensures that layout results remain stable even when constraints change, provided there is enough
whitespace (e.g., preventing unstable line breaks when layout width is reduced).
## Features
* **Flexible Backend**: Supports both CPU-based rendering and GPU acceleration (via [wgpu](https://wgpu.rs/)).
* **Robust Layout**: Handles text wrapping, alignment, and multi-font shaping with predictable results.
* **Font Management**: Easy loading of system fonts and custom font files via [fontdb](https://github.com/RazrFalcon/fontdb).
* **Thread Safety**: Designed with internal locking for safe concurrent use.
## Overview
The library is composed of the following main functionalities:
* **[`font_storage::FontStorage`]**: Manages font loading and caching. It handles system fonts and custom font data.
* **Text Representation**: Defined by [`text::TextData`] and [`text::TextElement`]. These structures hold the content and styling information (font, size, color, etc.) for text.
* **[`text::TextLayout`]**: The engine that calculates glyph positions, handling wrapping, alignment, and other layout properties based on the configuration.
* **Renderers**:
* **[`renderer::CpuRenderer`]**: Renders text into a pixel buffer on the CPU.
* **[`renderer::GpuRenderer`]**: A graphics-API-independent text renderer. It manages texture atlases and glyph quads, allowing implementation on any graphics backend (e.g., OpenGL, Vulkan, DirectX).
* **[`renderer::WgpuRenderer`]**: A concrete implementation built on top of `GpuRenderer` using the [wgpu](https://wgpu.rs/) graphics API.
The [`FontSystem`] acts as the central hub, coordinating these components to provide a unified API.
## How to Read the Documentation
To get started with Suzuri, we recommend reading the documentation in the following order:
1. **[`FontSystem`]**: The entry point of the library. Learn how to initialize the system.
2. **[`fontdb`]**: Understanding `fontdb` is essential for querying fonts (by family, weight, style) to obtain the Font ID needed for text elements.
3. **[`text::TextData`] & [`text::TextElement`]**: Learn how to create text content with styles and custom data.
4. **[`text::TextLayout`]**: Understand how the text is measured and arranged.
5. **Renderers**: Finally, explore the specific renderer you intend to use (e.g., in [`renderer`] module) for integration details.
## Installation
Add the following to your `Cargo.toml`:
```toml
[dependencies]
suzuri = "0.2.0"
```
To use wgpu features, enable the `wgpu` feature:
```toml
[dependencies]
suzuri = { version = "0.2.0", features = ["wgpu"] }
```
## Usage
### 1. Initialize FontSystem
[`FontSystem`] is the entry point for Suzuri. It handles font loading, layout, and renderer management.
```rust
use suzuri::{FontSystem, fontdb::{self, Family, Query}};
let font_system = FontSystem::new();
font_system.load_system_fonts();
// Query a font
let font_id = font_system
.query(&Query {
families: &[Family::Name("Arial"), Family::SansSerif],
weight: fontdb::Weight::NORMAL,
stretch: fontdb::Stretch::Normal,
style: fontdb::Style::Normal,
})
.map(|(id, _)| id);
// .expect("Font not found"); // Handle error appropriately
```
### 2. Prepare Text Data
Define the content and style of the text you want to render.
```rust
# use suzuri::{FontSystem, fontdb};
# use suzuri::text::{TextData, TextElement};
# let font_system = FontSystem::new();
# let font_id = None;
#
// Color type is user-definable
#[derive(Clone, Copy, Debug)]
struct MyColor { r: f32, g: f32, b: f32, a: f32 }
// For wgpu rendering, convert to [f32; 4] (Premultiplied Alpha)
impl From<MyColor> for [f32; 4] {
fn from(c: MyColor) -> Self {
[c.r * c.a, c.g * c.a, c.b * c.a, c.a]
}
}
let mut data = TextData::new();
if let Some(id) = font_id {
data.append(TextElement {
content: "Hello, Suzuri!".to_string(),
font_id: id,
font_size: 32.0,
user_data: MyColor { r: 1.0, g: 1.0, b: 1.0, a: 1.0 },
});
}
```
### 3. Layout the Text
Configure layout settings with [`text::TextLayoutConfig`] and calculate the placement.
```rust
# use suzuri::{FontSystem, text::TextData};
use suzuri::text::{TextLayoutConfig, HorizontalAlign, VerticalAlign, WrapStyle};
# let font_system = FontSystem::new();
# let data = TextData::<u8>::new();
let config = TextLayoutConfig {
max_width: Some(800.0),
max_height: None,
horizontal_align: HorizontalAlign::Left,
vertical_align: VerticalAlign::Top,
line_height_scale: 1.2,
wrap_style: WrapStyle::WordWrap,
..Default::default()
};
let layout = font_system.layout_text(&data, &config);
```
### 4. Rendering
#### CPU Rendering
For detailed usage, please refer to the [`renderer::CpuRenderer`] documentation.
#### GPU Rendering (wgpu)
To render using wgpu, initialize the renderer with the device and queue, then draw within a render pass.
For detailed usage, please refer to the [`renderer::WgpuRenderer`] documentation.
## License
MIT OR Apache-2.0