Glyph PBF (SDF) generator for MapLibre GL styles. Build static glyph directories with the CLI, or generate individual 256-codepoint ranges on demand from Rust, browsers, and Node.
The range API is designed for live style editors such as Kartore: drop a font file and make it available immediately, without a separate glyph build and hosting step.
pnpm add @kartore/glyphoreAdd the Rust API without the CLI dependency:
cargo add glyphore --no-default-featuresUse the lower-level engine directly when building another integration layer:
cargo add glyphore-coreInstall the native command-line interface with Cargo:
cargo install glyphoreBuild every covered glyph range from the TTF and OTF files in a directory:
npx @kartore/glyphore build fonts/ -o glyphs/
npx @kartore/glyphore info fonts/NotoSans-Regular.ttfThe output uses each font's internal fontstack name as its directory, including
spaces: glyphs/Noto Sans Regular/0-255.pbf. Only ranges containing mapped
glyphs are written; unlike build_pbf_glyphs, empty ranges are omitted.
These per-font directories are directly usable with a single-entry
text-font array. MapLibre joins multiple text-font entries with commas when
expanding {fontstack}; glyphore does not generate those combined directories.
The native CLI installed through Cargo offers the same commands and output layout:
glyphore build fonts/ -o glyphs/For GitHub Actions, the build can run with Node alone:
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
# Pin glyphore so the generator cannot change when the latest tag advances.
- run: npx --yes @kartore/glyphore@0.2.0 build fonts/ -o glyphs/Generated PBF files contain data derived from the source font. Check the font's license before redistributing them.
import { generateRange, loadFont } from "@kartore/glyphore";
{
using font = await loadFont(fontBytes);
// U+0000–U+00FF. Range starts must be multiples of 256.
const pbf = generateRange(font, 0);
console.log(font.info.fontstackName, pbf);
}Use [font.info.fontstackName] as a symbol layer's text-font array. With that
single entry, MapLibre substitutes the same name for the glyph URL's
{fontstack} placeholder. font.info.coveredRanges contains the sorted range
starts that have at least one glyph.
The using declaration releases the loaded font when its scope exits. For
Node, import loadFont and generateRange from @kartore/glyphore/node; it
reads the bundled WebAssembly file automatically. See
the package README for complete browser and Node examples.
use glyphore::{FontFace, generate_range};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let bytes = std::fs::read("NotoSans-Regular.ttf")?;
let face = FontFace::parse(&bytes)?;
let pbf = generate_range(&face, 0)?;
std::fs::write("0-255.pbf", pbf)?;
Ok(())
}See the glyphore API documentation for feature
selection and the low-level
glyphore-core API documentation for direct
core usage.
cargo fmt --check
cargo clippy --workspace -- -D warnings
cargo test --workspace
pnpm build
pnpm typecheck
pnpm testLicensed under either of Apache License, Version 2.0 or MIT license at your option.