Skip to content

RayZ3R0/typst-raster

Repository files navigation

typst-raster

npm License: MIT CI Documentation

typst-raster showcase

This entire showcase image was generated with Typst – view the code


A fast, no-nonsense Node.js library for rendering Typst to PNG, JPEG, WebP, or PDF.

It uses the official Typst compiler through native Rust bindings (@myriaddreamin/typst-ts-node-compiler) and Sharp for rasterization, so you get near-native performance with pixel-perfect results. I built it because I needed a reliable way to generate crisp math equations and document snippets in backend services and bots, and nothing else quite cut it.

Comes with New Computer Modern fonts bundled, works out of the box on Lambda, Vercel, Docker, or anywhere else, no system font dependencies required.

Features

  • Native-speed compilation via direct Rust bindings
  • SVG → raster pipeline with Sharp (sub-pixel accurate, any DPI)
  • SVG output support for vector graphics
  • Built-in caching (LRU, enabled by default)
  • Batch rendering API for multiple renders
  • Zero-config font setup (New Computer Modern Book included)
  • Automatic tight cropping in snippet mode (perfect for equations)
  • Full TypeScript support with proper types
  • Variable injection, custom font paths, quality/scale control
  • Metadata extraction from rendered images
  • Stream output for efficient HTTP responses
  • Tiny bundle size, no heavyweight dependencies

Comparison with Alternatives

typst-raster offers a lightweight, all-in-one solution for rendering documents and equations, avoiding the complexity of installing system-level dependencies.

Feature typst-raster System LaTeX (node-latex) MathJax (mathjax-node) Puppeteer (Headless Chrome)
Engine Native Rust (Node Bindings) System Binary (pdflatex) JavaScript Chromium Browser
Prerequisites None (npm install only) Heavy (Requires TeXLive) None Chromium Binary
Install Size ~8.9 MB 2GB - 4GB ~50 MB ~280 MB+
Speed Fast (Native compilation) Slow (Spawns process) Medium Very Slow (Browser startup)
Output PDF, PNG, JPEG, SVG, WEBP PDF only SVG/HTML only PDF, PNG
Serverless ✅ Ready (Fonts included) ❌ Difficult (Too large) ✅ Ready ⚠️ Hard (High RAM usage)
Scope Full Documents + Math Full Documents + Math Math Equations Only Webpages

Why choose typst-raster?

1. No external dependencies required Running standard LaTeX wrappers in Node.js usually requires installing a full TeX distribution (like TeXLive) on the host machine. This is often impossible on managed hosting platforms like Vercel or standard shared hosting. This package runs entirely within Node.js with no external requirements.

2. Solves the missing font issue Generating PDFs or images on cloud functions (AWS Lambda, Google Cloud) often results in broken text because the environments lack standard fonts. This package bundles high-quality fonts internally, ensuring documents render correctly on any server without manual configuration.

3. Direct conversion to multiple formats Most alternatives specialize in one output format. LaTeX tools output PDF; MathJax outputs SVG. typst-raster handles the full pipeline internally, allowing you to generate PDFs for reports or PNGs for web previews using a single library. This removes the need for additional conversion tools like ImageMagick.

Installation

npm install typst-raster

Usage

Simple render

import { Typst } from 'typst-raster';
import { writeFile } from 'fs/promises';

const renderer = new Typst();

const buffer = await renderer.render({
  code: '= Hello from Typst!\nThis is a quick test of the renderer.',
});

await writeFile('hello.png', buffer);

Math equations / snippet mode (recommended for formulas)

const buffer = await renderer.render({
  code: '$ sum_(k=1)^n k = (n(n+1))/2 $',
  snippet: true,     // auto-crop to content
  scale: 3,          // 3× resolution for retina displays
  format: 'png',
});

Passing variables

const buffer = await renderer.render({
  code: 'Hello #sys.inputs.name, welcome to #sys.inputs.project!',
  variables: {
    name: 'Alice',
    project: 'typst-raster',
  },
});

Flatten transparent backgrounds

const buffer = await renderer.render({
  code: '$ E = m c^2 $',
  snippet: true,
  backgroundColor: 'white',
});

Use preamble for theming

const myTheme = `
#set page(fill: rgb("#2b2d31"), margin: 1cm)
#set text(fill: white, font: "Roboto")
`;

const buffer = await renderer.render({
  preamble: myTheme,
  code: '$ sum_(k=1)^n k = (n(n+1))/2 $',
  snippet: true,
});

Render to PDF

const buffer = await renderer.render({
  code: '= Document Title\n\nThis is a *PDF* document.',
  format: 'pdf',
});

await writeFile('document.pdf', buffer);

Render to SVG

const buffer = await renderer.render({
  code: '$ E = mc^2 $',
  format: 'svg',
  snippet: true
});

await writeFile('equation.svg', buffer);

Batch rendering

const results = await renderer.renderBatch([
  { code: '$ a^2 + b^2 = c^2 $', snippet: true },
  { code: '$ \\int_0^\\infty e^{-x} dx = 1 $', snippet: true },
  { code: '$ \\sum_{n=1}^\\infty \\frac{1}{n^2} = \\frac{\\pi^2}{6} $', snippet: true }
]);

// Save all results
for (let i = 0; i < results.length; i++) {
  await writeFile(`equation-${i}.png`, results[i]);
}

Extract metadata

import { getMetadata } from 'typst-raster';

const buffer = await renderer.render({
  code: '$ x^2 $',
  snippet: true,
  ppi: 300
});

const metadata = await getMetadata(buffer);
console.log(`Dimensions: ${metadata.width}x${metadata.height}`);
console.log(`Format: ${metadata.format}`);
console.log(`DPI: ${metadata.density}`);

Stream output (for HTTP responses)

import { createWriteStream } from 'fs';

const stream = await renderer.renderStream({
  code: '$ \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a} $',
  format: 'png',
  snippet: true
});

stream.pipe(createWriteStream('equation.png'));

// Or in Express/Fastify:
// stream.pipe(res);

Disable caching

// Disable cache entirely
const renderer = new Typst({ cache: false });

// Or customize cache size
const renderer = new Typst({ cacheSize: 500 }); // default: 100

API

For more details, visit the Documentation Site.

new Typst(options?: {
  fontPath?: string;  // folder with additional .ttf/.otf files
})
renderer.render(options): Promise<Buffer>
Option Type Default Description
code string Required Typst source
format 'png' | 'jpeg' | 'webp' | 'pdf' 'png' Output format
quality number (1–100) 100 JPEG/WebP quality (ignored for PDF)
ppi number 192 Raster resolution (ignored for PDF)
scale number 1 Additional multiplier (ignored for PDF)
snippet boolean false Crop tightly to content (great for equations)
variables Record<string, string | number | boolean> {} Injected as #sys.inputs.key
backgroundColor string Flatten transparency (raster only)
preamble string Typst code prepended to every render

Error Handling

The library exports a TypstRenderError class that you can catch to handle rendering failures specifically.

import { Typst, TypstRenderError } from 'typst-raster';

try {
  await renderer.render({ code: '#invalid()' });
} catch (error) {
  if (error instanceof TypstRenderError) {
    console.error('Typst compilation failed:', error.message);
  }
}

Credits

Huge thanks to the projects this wouldn't exist without:

License

MIT © 2025 RayZ3R0

About

Blazing-fast Typst → PNG/JPEG/WebP renderer for Node.js using native Rust compiler + Sharp

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published