TYPF: Modern Font Rendering Engine
Production-ready, cross-platform font rendering with Rust performance and Python convenience
For overall project coordination: See root README.md | PLAN.md | TODO.md
What is TYPF?
TYPF is a modern, cross-platform font rendering engine providing unified text layout and rasterization. It's built in Rust for performance and safety, with Python bindings for ease of use.
Key Design Goals:
- Performance: Sub-millisecond rendering, lock-free concurrency, zero-copy font loading
- Correctness: Pixel-perfect output, comprehensive testing, fuzzing-ready
- Cross-Platform: Native backends for macOS (CoreText), Windows (DirectWrite), Linux (HarfBuzz)
- Flexible Output: PNG, SVG, NumPy arrays, PGM, raw bitmaps
Features
Core Capabilities
✅ Multiple Shaping Backends
- CoreText (macOS native)
- DirectWrite (Windows native)
- ICU + HarfBuzz (cross-platform fallback)
- Automatic backend selection based on platform
✅ Multiple Rasterizers
orge- Custom CPU rasterizer (F26Dot6 fixed-point, scan conversion)tiny-skia- Vector renderer (feature-gated)zeno- Alternative rasterizer (feature-gated)
✅ Modern Font Stack
- Built exclusively on
skrifa+read-fonts - Full OpenType support (TTF, CFF, CFF2)
- Variable font support (wght, wdth, and all registered axes)
- Named instance support
✅ Output Formats
- PNG (via
resvg+pngcrate) - SVG paths with
kurbo - NumPy arrays (Python bindings)
- PGM (P5 format)
- Raw RGBA/BGRA bitmaps
✅ Advanced Features
- COLRv1/CPAL color font support
- Gradients and clip paths
- Complex script shaping (Arabic, Devanagari, CJK)
- Bidirectional text (via
unicode_bidi) - Text segmentation (ICU-based)
Architecture
Project Structure
typf/
├── backends/ # Platform-specific rendering
│ ├── typf-core/ # Shared traits, types, caching (1,086 lines)
│ ├── typf-icu-hb/ # HarfBuzz+ICU backend (~2,000 lines)
│ ├── typf-orge/ # Custom rasterizer (~500 lines)
│ ├── typf-mac/ # CoreText backend (~800 lines)
│ ├── typf-win/ # DirectWrite backend (~1,000 lines)
│ ├── typf-pure/ # Minimal pure-Rust fallback (~350 lines)
│ └── typf-zeno/ # Zeno rasterizer (~200 lines)
├── crates/ # Modular components
│ ├── typf-api/ # Public API facade
│ ├── typf-batch/ # Batch job processing
│ ├── typf-fontdb/ # Font discovery & loading
│ ├── typf-render/ # Output utilities (SVG/PNG)
│ ├── typf-shaping/ # Shaping helpers
│ └── typf-unicode/ # Text segmentation
├── python/ # PyO3 bindings
│ ├── src/lib.rs # Rust FFI layer
│ └── typf/ # Python wrapper
├── typf-cli/ # Command-line tool
├── tests/ # Integration tests
└── examples/ # Rust & Python examples
Backend Comparison
| Backend | Platform | Performance | Completeness | Use Case |
|---|---|---|---|---|
| CoreText | macOS | Excellent | ✅ Full | macOS primary |
| DirectWrite | Windows | Excellent | ✅ Full | Windows primary |
| HarfBuzz+ICU | All | Good | ✅ Full | Cross-platform fallback |
| orge | All | Excellent* | ⚠️ Partial | Custom rasterization (in progress) |
| tiny-skia | All | Good | ✅ Full | Vector rendering (feature-gated) |
| zeno | All | Good | ⚠️ Partial | Alternative rasterizer |
| pure | All | Basic | ⚠️ Minimal | WASM compatibility fallback |
*orge core algorithm complete; backend integration pending
Caching Architecture
Three-Layer Caching:
-
Backend Font Cache (Per-backend, LRU)
- CoreText: CTFont instances (64-128 capacity)
- DirectWrite: IDWriteFont objects (64-128 capacity)
- HarfBuzz: hb_face_t objects (64-128 capacity)
-
Shape Result Cache (Global, Multi-Shard)
- Implementation: 16-shard DashMap + per-shard LRU
- Key: (text, font_key, size, features)
- Benefit: Eliminates lock contention on concurrent workloads
- Capacity: Configurable (1,000-10,000 entries typical)
-
System Font Database (Global, OnceCell)
- Location: typf-fontdb
- DashMap-backed for thread-safe lookups
- Loads system fonts + custom directories once
Memory Management:
- Arc-based shared ownership for font data
- memmap2 for file-backed zero-copy loading
- Mmap kept alive via FontKey references
- Explicit
clear_cache()methods on all backends
Installation
From Source
Prerequisites:
- Rust 1.70+ (
rustup install stable) - Python 3.12+ (for Python bindings)
- Platform-specific dependencies:
- macOS: Xcode command-line tools
- Windows: Visual Studio Build Tools
- Linux: HarfBuzz + FreeType development packages
Rust Library:
cd github.fontlaborg/typf
cargo build --release --workspace
cargo test --workspace --all-features # Run tests
Python Bindings:
⚠️ Important: Python bindings MUST be built inside an active virtual environment. System Python builds will fail with linker errors.
# 1. Create and activate virtual environment
cd github.fontlaborg/typf
uv venv --python 3.12 # or: python3.12 -m venv .venv
source .venv/bin/activate # macOS/Linux
# .venv\Scripts\activate # Windows
# 2. Install maturin in the venv
uv pip install maturin # or: pip install maturin
# 3. Build the bindings
cd python
maturin develop --release --features "python,icu,mac" # macOS
# maturin develop --release --features "python,icu" # Linux
# maturin develop --release --features "python,windows" # Windows
# 4. Verify installation
python -c "import typf; print(typf.__version__)"
Troubleshooting:
If you encounter linker errors or missing Python symbols:
- macOS: Install Xcode CLI tools:
xcode-select --install - Linux: Install Python dev headers:
sudo apt install python3-dev(Debian/Ubuntu) orsudo dnf install python3-devel(Fedora/RHEL) - Windows: Install Visual Studio Build Tools with Python development workload
- All platforms: Ensure you're inside an activated virtual environment before running
maturin develop
To build a distributable wheel:
maturin build --release # Build wheel
pip install target/wheels/typf-*.whl
CLI Tool:
cargo install --path typf-cli
typf --help
Feature Flags
Control optional functionality via Cargo features:
[dependencies]
typf = { version = "*", features = ["mac", "tiny-skia-renderer"] }
Available features:
mac- CoreText backend (macOS only, default on macOS)windows- DirectWrite backend (Windows only, default on Windows)icu- HarfBuzz+ICU backend (cross-platform, default)tiny-skia-renderer- tiny-skia rasterizer (optional)orge- Custom orge rasterizer (experimental)
Usage
Rust API
Basic rendering:
use typf::prelude::*;
// Auto-select best backend for platform
let backend = Backend::auto_select()?;
// Create font specification
let font = Font::new("Arial", 24.0)
.weight(700) // Bold
.style(FontStyle::Italic);
// Render text
let options = RenderOptions::default()
.format(RenderFormat::PNG)
.size(800, 600);
let result = backend.render_text("Hello, TYPF!", &font, &options)?;
// result.data contains PNG bytes
std::fs::write("output.png", &result.data)?;
Variable fonts:
let font = Font::new("RobotoFlex", 24.0)
.variation("wght", 800.0)
.variation("wdth", 125.0);
let result = backend.render_text("Variable!", &font, &options)?;
Font features:
let font = Font::new("OpenSans", 18.0)
.feature("liga", 1) // Enable ligatures
.feature("smcp", 1); // Small caps
let result = backend.render_text("fi fl", &font, &options)?;
SVG output:
let options = RenderOptions::default()
.format(RenderFormat::SVG);
let result = backend.render_text("SVG Text", &font, &options)?;
let svg = String::from_utf8(result.data)?;
Python API
Basic rendering:
from typf import TextRenderer, Font, RenderFormat
# Auto-select backend
renderer = TextRenderer()
# Create font
font = Font("Arial", size=24.0)
# Render text
result = renderer.render(
text="Hello from Python!",
font=font,
format=RenderFormat.PNG
)
# result.data is bytes (PNG)
with open("output.png", "wb") as f:
f.write(result.data)
Variable fonts + NumPy:
import numpy as np
from PIL import Image
font = Font("RobotoFlex", size=48.0)
font.variation("wght", 700)
font.variation("wdth", 100)
result = renderer.render("Variable", font, format=RenderFormat.RAW)
# Convert to NumPy array
arr = np.frombuffer(result.data, dtype=np.uint8)
arr = arr.reshape(result.height, result.width, 4) # RGBA
# Convert to PIL Image
img = Image.fromarray(arr)
img.show()
Batch rendering:
jobs = [
{"font": "Arial", "text": "Job 1", "size": 24},
{"font": "Times", "text": "Job 2", "size": 32},
]
results = renderer.render_batch(jobs)
for i, result in enumerate(results):
with open(f"output_{i}.png", "wb") as f:
f.write(result.data)
CLI
Single render:
# Render to PNG
typf render \
--font=/path/to/font.ttf \
--text="Hello, CLI!" \
--size=48 \
--output=output.png
# Render with variable font axes
typf render \
--font=RobotoFlex.ttf \
--text="Variable" \
--axes="wght=700,wdth=100" \
--output=variable.png
Batch processing (JSONL):
# Create job file
echo '{"font": "Arial", "text": "Line 1", "size": 24}' > jobs.jsonl
echo '{"font": "Times", "text": "Line 2", "size": 32}' >> jobs.jsonl
# Process batch
typf batch < jobs.jsonl
# Streaming mode (memory-efficient)
cat jobs.jsonl | typf stream
Output formats:
# PNG (default)
typf render --font=font.ttf --text="PNG" --format=png --output=out.png
# SVG
typf render --font=font.ttf --text="SVG" --format=svg --output=out.svg
# PGM (grayscale)
typf render --font=font.ttf --text="PGM" --format=pgm --output=out.pgm
# Metrics only (JSON)
typf render --font=font.ttf --text="Metrics" --format=metrics
Performance
Rendering Speed:
- Typical glyph: Sub-millisecond
- Complex scripts (Arabic, Devanagari): 1-5ms
- Batch processing: Rayon-parallelized across CPU cores
Memory:
- Zero-copy font loading via memmap2
- Arc-based shared ownership (no unnecessary clones)
- Multi-shard cache eliminates lock contention
Caching:
- First render: Font load + shape + rasterize (~5-20ms)
- Cached render: Shape lookup only (~0.1-1ms)
- Cache hit rate: 80-95% typical for repeated text
Testing
Run all tests:
cargo test --workspace --all-features
Run platform-specific tests:
# macOS only
cargo test --features mac
# Windows only
cargo test --features windows
# HarfBuzz only
cargo test --features icu
Run integration tests:
cargo test --test integration
Python binding tests:
cd python
pytest tests/
Benchmarks:
cargo bench --workspace
Current Status
Production-Ready ✅
- All 3 platform backends (CoreText, DirectWrite, HarfBuzz)
- Multi-shard LRU caching
- Python bindings (PyO3) with automatic backend selection
- CLI with batch/stream/render commands
- 38+ integration tests passing
- SVG/PNG output with COLRv1 color font support
In Progress ⏳
- Orge rasterizer backend integration
- FFI panic handling (std::panic::catch_unwind wrappers)
- Visual regression framework (SSIM-based)
- Comprehensive documentation
Planned 📋
- SIMD-accelerated fixed-point math (SSE2/AVX2/Neon)
- cargo-fuzz + cargo-miri in CI
- Unified typf_error::Error enum
- seccomp sandboxing for untrusted fonts
- Publishto crates.io
Development
Guidelines: See CLAUDE.md for development workflow, coding standards, and testing requirements.
Quick commands:
# Format code
cargo fmt --all
# Lint
cargo clippy --workspace --all-features -- -D warnings
# Build release
cargo build --workspace --release
# Build Python bindings
cd python && maturin develop --release
For tasks and roadmap: See root TODO.md (look for **(typf)** prefix)
Contributing
We follow a philosophy of ruthless minimalism and test-driven development:
- Write tests first (RED → GREEN → REFACTOR)
- Minimize code (delete > add)
- No panics in library code (use
Result<T, TypfError>) - Document all public APIs (rustdoc with examples)
- Benchmark performance-critical changes
See CLAUDE.md for detailed contribution guidelines.
License
See LICENSE file.
made by FontLab https://www.fontlab.com/
Last Updated: November 16, 2025 Status: Production-ready; focused on hardening and optimization Total Code: ~15,000 lines Rust + 500 lines Python
Release files for typf 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| typf-0.1.0-cp312-cp312-macosx_11_0_arm64.whl | CPython 3.12 | CPython 3.12 | macOS 11.0+ ARM64 | Details |
Release files / typf-0.1.0-cp312-cp312-macosx_11_0_arm64.whl
| Download URL | typf-0.1.0-cp312-cp312-macosx_11_0_arm64.whl |
|---|---|
| Size | 2.9 MB |
| Tags | CPython 3.12 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
1526781d0b201bf3f5ed3f2b07500e4791fcdf93f3c3dc667ec1351fb736a71a
|
|
BLAKE2b-256 checksum How to use checksums |
2266d3d0639ae07d67b86b5389308676feb6cd67c6a885b558004b48846c2e75
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
python-httpx/0.28.1
|