Expand description
GlyphWeaveForge is a Markdown-to-PDF library with explicit adapter boundaries.
The public API is centered on Forge, with stable builder-style configuration for source selection, output selection, page settings, theme selection, backend selection, and adapter injection.

§GlyphWeaveForge
GlyphWeaveForge converts Markdown into PDF through a small Rust pipeline with explicit boundaries:
api -> pipeline -> core -> adapters
The crate ships a lightweight built-in renderer by default and can optionally use Typst without changing the public builder API.
§What the crate provides today
- A fluent
Forgebuilder for Markdown-to-PDF conversion. - Three input modes: UTF-8 text, UTF-8 bytes, and filesystem paths (
fsfeature). - Three output modes: in-memory bytes, explicit file path, and output directory (
fsfeature). - Built-in page sizes (
A4,Letter,Legal, custom millimeter sizes). - Built-in layout modes (
Paged,SinglePage). - Built-in themes with optional JSON overrides.
- Resource resolution through filesystem lookup (
fs) or caller-provided resolvers. - Renderer extension points through public
RenderBackendandResourceResolvertraits. - Two backend selections behind a stable builder API:
Minimalby default andTypstwhen the feature is enabled.
§Installation
[dependencies]
glyphweaveforge = "0.1.6"Enable optional features when you need them:
[dependencies]
glyphweaveforge = { version = "0.1.3", features = ["renderer-typst"] }§Main builder flow
use glyphweaveforge::Forge;
let pdf = Forge::new()
.from_text("# Hello\n\nWorld")
.to_memory()
.convert()
.expect("conversion should succeed");
let bytes = pdf.bytes.expect("memory output should contain PDF bytes");
assert!(bytes.starts_with(b"%PDF"));Forge::new() starts with these defaults:
- source: not set
- output: not set
- backend:
RenderBackendSelection::Minimal - page size:
PageSize::A4 - layout mode:
LayoutMode::Paged - theme:
BuiltInTheme::Professional
§Supported inputs and outputs
Always available:
from_textfrom_bytesto_memory- injected resource resolvers through
with_resource_resolverorwith_resource_adapter - explicit backend selection through
with_backend - custom renderer injection through
with_renderer - full option replacement through
with_options
Available with the default fs feature:
from_pathto_fileto_directorywith_output_file_namefor directory outputs- filesystem-based resource lookup for local assets relative to the markdown file
§Output behavior
to_memory()returnsPdfOutput { bytes: Some(...), written_path: None }.to_file(...)writes the PDF and returnsPdfOutput { bytes: None, written_path: Some(...) }.to_directory(...)creates the directory if needed and derives the file name from the source name unlesswith_output_file_name(...)overrides it.
When deriving a directory output name, the crate appends .pdf if it is missing.
§Page sizes, layout modes, and themes
§Page sizes
PageSize::A4PageSize::LetterPageSize::LegalPageSize::Custom { width_mm, height_mm }
Custom page sizes must be strictly positive.
§Layout modes
LayoutMode::Paged: paginates rendered lines across pages.LayoutMode::SinglePage: keeps the rendered content in a single page payload.
§Built-in themes
BuiltInTheme::InvoiceBuiltInTheme::ScientificArticleBuiltInTheme::Professional(default)BuiltInTheme::EngineeringBuiltInTheme::Informational
with_theme(...) selects a built-in preset. with_theme_config(...) lets you combine an optional built-in theme with JSON overrides such as:
namebody_font_size_ptcode_font_size_ptheading_scalemargin_mm
The Typst backend applies the full theme profile, including fonts, colors, margins, body/code sizes, and heading scale. The default minimal backend is a fallback PDF writer; it applies layout-affecting values such as margins and font sizes, while color and font-family overrides are represented only in the resolved theme profile.
Current theme profiles do not yet expose explicit controls for line height, paragraph alignment/indentation, multi-column layout, or page background color. Built-in presets therefore approximate those style guides through currently supported properties (fonts, sizes, heading scale, margins, and palette).
Example:
use glyphweaveforge::{BuiltInTheme, Forge, LayoutMode, PageSize, ThemeConfig};
use serde_json::json;
let pdf = Forge::new()
.from_text("# Report\n\nBody")
.to_memory()
.with_page_size(PageSize::Letter)
.with_layout_mode(LayoutMode::SinglePage)
.with_theme_config(ThemeConfig {
built_in: Some(BuiltInTheme::Engineering),
custom_theme_json: Some(json!({
"name": "custom-engineering",
"margin_mm": 14.0
})),
})
.convert()
.expect("conversion should succeed");
assert!(pdf.bytes.expect("bytes should exist").starts_with(b"%PDF"));§Backend selection
The default build uses the minimal built-in renderer. To opt into the Typst backend, enable renderer-typst and select it explicitly:
use glyphweaveforge::{Forge, RenderBackendSelection};
let pdf = Forge::new()
.from_text("# Hello from Typst")
.to_memory()
.with_backend(RenderBackendSelection::Typst)
.convert()
.expect("typst backend should succeed");
assert!(pdf.bytes.expect("bytes should exist").starts_with(b"%PDF"));Backends exposed by the public API:
RenderBackendSelection::Minimal: always available in the default feature set.RenderBackendSelection::Typst: available whenrenderer-typstis enabled.
The typst Cargo feature is a compatibility alias for renderer-typst.
If you need complete control, with_renderer(...) accepts any type implementing the public RenderBackend trait and overrides the built-in backend selection.
§Feature matrix
fs(default): enables path-based source/output helpers and filesystem resource loading.renderer-minimal(default): keeps the built-in lightweight renderer enabled and addressable in tests/documentation.renderer-typst: enables the Typst-backed renderer.typst: compatibility alias forrenderer-typst.mermaid: enables a Rust-native Mermaid subset renderer for the Typst backend (no Node/npm/network required). Unsupported Mermaid syntax remains visible through explicit fallback notices.- Mermaid fenced-block rendering is available through this Rust-native subset renderer.
math: enables GFM math parsing ($...$,$$...$$) and TeX-subset conversion for real Typst math rendering. The minimal renderer remains a readable text fallback.
§Current Markdown behavior
Supported today:
- headings
- paragraphs
- emphasis/strong text
- inline code
- links
- unordered and ordered lists
- block quotes
- thematic breaks
- fenced code blocks
- images, including injected resolvers and memory-backed assets
- basic HTML
<img>tags withsrc/alt - tables
Resource handling behavior:
- For path-based markdown sources with the
fsfeature, local assets are resolved relative to the markdown file directory. - For text/bytes sources, you can inject assets with
with_resource_resolver(...)orwith_resource_adapter(...). - Missing assets remain visible in the output as explicit fallback text.
Unsupported advanced Markdown stays visible instead of silently disappearing. Examples include:
- footnotes
- Mermaid diagrams (Rust-native rendering on Typst for supported subset types when
mermaid+renderer-typstare enabled; unsupported syntax remains explicit fallback) - unsupported TeX environments/commands are surfaced as visible conversion notices in Typst output
- unsupported raw HTML beyond basic
<img>extraction
These paths render deterministic fallback labels with the original content preserved in the output when possible.
§Math support details
- Inline math uses
$...$and display math uses$$...$$in Markdown. - The Typst backend renders real math with Typst delimiters after converting a practical TeX subset.
- Supported subset includes
\frac,\sqrt, grouped superscripts/subscripts,\sum,\prod,\int,\lim, common Greek letters (\alpha,\beta,\gamma,\delta,\lambda,\pi,\sigma,\Omega,\Delta), symbols (\pm,\infty,\approx,\neq,\leq,\geq,\le,\ge,\to,\cdot,\times), spacing/wrappers (\,,\qquad,\left,\right), and common functions (\sin,\cos,\exp,\partial). - Unsupported environments (
\begin{...}/\end{...}) and unknown commands produce explicit, visible error notices in Typst output instead of silent data loss. - Fenced code blocks like
```mathare still treated as code fences (honest fallback), not as math AST nodes.
§Extending the crate
§Custom resource resolver
use std::io;
use glyphweaveforge::Forge;
let pdf = Forge::new()
.from_text("")
.to_memory()
.with_resource_resolver(|href| {
if href == "logo.png" {
Ok(vec![1, 2, 3])
} else {
Err(io::Error::new(io::ErrorKind::NotFound, "missing"))
}
})
.convert()
.expect("conversion should succeed");
assert!(pdf.bytes.expect("bytes should exist").starts_with(b"%PDF"));§Custom renderer
use glyphweaveforge::{Document, Forge, RenderBackend, RenderRequest, Result};
struct StubRenderer;
impl RenderBackend for StubRenderer {
fn render(&self, _document: &Document, _request: &RenderRequest) -> Result<Vec<u8>> {
Ok(b"stub-pdf".to_vec())
}
}
let pdf = Forge::new()
.from_text("hello")
.to_memory()
.with_renderer(StubRenderer)
.convert()
.expect("custom renderer should be used");
assert_eq!(pdf.bytes, Some(b"stub-pdf".to_vec()));The public extension traits are:
RenderBackendResourceResolver
The rendering request/asset helper types exposed for adapters are:
RenderRequestResolvedAssetResourceStatus
§Limitations
- This crate does not claim real Mermaid diagram rendering.
- This crate does not claim real TeX/LaTeX or advanced math typesetting.
- Footnotes are exposed through visible fallback text rather than full layout support.
- General raw HTML is not a full rendering target; basic
<img>extraction is supported, but broader HTML layout is not. - The minimal renderer writes a compact PDF text stream; it is designed for deterministic output and testability rather than rich page design.
renderer-typstis optional; docs.rs for the default documentation build does not require Typst support to use the crate.
§Public error and result types
Result<T>is an alias forstd::result::Result<T, ForgeError>.ForgeError::MissingSourceandForgeError::MissingOutputprotect incomplete builder usage.ForgeError::InputReadandForgeError::InvalidUtf8cover source loading.ForgeError::Resourcecovers resolver failures.ForgeError::InvalidConfigurationcovers invalid runtime options such as non-positive custom page sizes.ForgeError::Render,ForgeError::TypstCompile,ForgeError::TypstExport, andForgeError::TypstAssetcover backend/rendering failures.ForgeError::OutputWrite,ForgeError::OutputDirectory, andForgeError::InvalidOutputFileNamecover output persistence.
§Architecture note
Release work should preserve the internal boundary:
api -> pipeline -> core -> adapters
§Documentation
Full documentation is available at gustavogutierrez.github.io/glyph-weave-forge:
- Getting Started — installation, quick start, feature flags
- API Reference — complete builder API, types, and error handling
- Contributing — how to contribute, areas to improve, pre-commit checklist
§Author
Created by Gustavo Gutiérrez — Bogotá, Colombia.
- GitHub: @GustavoGutierrez
- crates.io: glyphweaveforge
§License
MIT — see LICENSE for details.
Structs§
- Convert
Options - Conversion options used by the builder and pipeline.
- Document
- Forge
- Main entrypoint for Markdown to PDF conversion.
- PdfOutput
- Result of a conversion.
- Render
Request - Render input passed to a
RenderBackend. - Resolved
Asset - Resolved asset payload returned by a
ResourceResolver. - Resource
Context - Theme
Config - Theme selection and optional JSON overrides.
Enums§
- Built
InTheme - Predefined visual themes.
- Forge
Error - Errors produced by the conversion pipeline.
- Layout
Mode - Output pagination strategy.
- Markdown
Source - Supported markdown input sources.
- Output
Target - Supported PDF output targets.
- Page
Size - Target page size.
- Render
Backend Selection - Built-in renderer backends available through the composition layer.
- Resource
Status
Traits§
- Render
Backend - Port for PDF rendering adapters.
- Resource
Resolver - Port for asset/resource resolution adapters.
Type Aliases§
- Result
- Crate-wide result type.