Fonts are untrusted binary data the moment they enter your app. Parsing them natively or in the browser can easily turn into a memory-safety headache or a server bandwidth drain.
I built taetype to fix that: a pure-Rust font engine with #![forbid(unsafe_code)] hard-enforced at the crate root. I also compiled the exact same engine to WebAssembly with taetype-wasm.
Whether you call it from Rust or TypeScript, you get the exact same glyph IDs, advance metrics, and subset bytes.
What it does
Instead of stitching together multiple single-purpose libraries, taetype handles the full font lifecycle:
Decode: TTF, OTF, and TTC font collections without dropping unknown tables.
Instance: Full OpenType Font Variations (fvar, gvar, avar formats 1/2, HVAR, VVAR, MVAR, cvar, and CFF2 charstring blends) turned into static instances at any axis position.
Subset: Shrink fonts down to only used glyphs, with full GSUB/GPOS/GDEF lookup rewriting so ligatures, kerning, and mark attachments keep working. COLR (v0/v1) and CPAL references carry through with dependency chasing.
Shape: Complex script shaping, kerning, and ligatures via rustybuzz, plus OpenType JSTF justification priority support.
Rasterize: Built-in, zero-dependency CPU coverage rasterizer (taerizer::cpu) for TrueType and CFF/CFF2 outlines.
Color & Emoji: COLR v0/v1 (gradients, transforms, layers), CPAL, CBDT/CBLC, sbix bitmap strikes, and SVG-in-OpenType documents.
Math Typesetting: Complete OpenType MATH table support (all 56 constants, per-glyph italics correction, and growable glyph variants).
Quick Code Examples
Native Rust (cargo add taetype)
use taetype::Font;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let font_bytes = std::fs::read("MyFont.ttf")?;
let font = Font::from_bytes(&font_bytes)?;
// Shape text using variable axes
let shaped = font.shape("Hello, world", &[("wght", 400.0)], false)
.expect("font must be shapeable");
// Subset keeping only the used glyphs
let subset = font.subset(&shaped.glyphs, &[("wght", 400.0)])?;
// subset.ttf now holds your minimal font file
Ok(())
}
Browser TypeScript (npm install taetype-wasm)
import init, { Font } from "taetype-wasm";
await init();
const fontBytes = new Uint8Array(await fetch("MyFont.ttf").then((r) => r.arrayBuffer()));
// Explicit resource management supported out of the box!
using font = Font.fromBytes(fontBytes);
const shaped = font.shape("Hello, world", { wght: 400 }, false);
if (!shaped) throw new Error("failed to shape text");
const subset = font.subset(shaped.glyphs, { wght: 400 });
// subset.ttf is a Uint8Array containing the subset font
shaped.free();
subset.free();
Verification & Reliability
Font parsers are historical magnets for memory exploits. To ensure reliability:
Compiler-enforced #![forbid(unsafe_code)] at the crate root.
1,400+ unit and integration tests.
Differential testing against Python's fontTools for byte-for-byte accuracy.
Continuous fuzzing via cargo-fuzz (libFuzzer) across 6 targets, plus property testing via proptest.
Output validation using Chromium's opentype-sanitizer (OTS).
Links
Rust Crate (GitHub): GitHub - silly-tae/taetype: Decode, subset, shape, rasterize fonts – zero unsafe. · GitHub
NPM / WASM (GitHub): GitHub - silly-tae/taetype-wasm: Decode, subset, shape, and rasterize fonts in WebAssembly - zero unsafe, browser-only. · GitHub
Still working on it and refining it even further
1 post - 1 participant
Read full topic
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | My state lib PurrGress | 0 | 12.62 | 13-08-2026 |
| 2 | FUI-RS: retained Rust UI for WebAssembly and native desktop without a WebView | 0 | 11.54 | 30-07-2026 |
| 3 | Cargo-Rail v0.20: one workspace engine instead of dependency, CI, cache, release, and split-repo glue/plugins | 0 | 10.4 | 30-07-2026 |
| 4 | Multicalc: Scientific computing for real-time embedded systems in no_std Rust | 0 | 14.36 | 10-08-2026 |
| 5 | Tokcost — zero-dependency CLI for exact LLM token counts (hand-rolled BPE) | 0 | 12.74 | 02-08-2026 |
| 6 | Multicalc: Scientific computing for real time embedded systems in no_std rust | 0 | 9.4 | 28-07-2026 |
| 7 | Qhull_rayon v0.1.0 | 0 | 10.4 | 11-08-2026 |
| 8 | Sigid: a zero-dependency, no_std, three-layer unique ID generator | 0 | 14.69 | 11-08-2026 |
| 9 | My second crate :D : Karatepe, a localisation library | 0 | 6.84 | 11-08-2026 |