Skip to main content
@nemu-ai/pdf generates PDFs from code. It ships two APIs from one package that share a single rendering engine, so you can describe a document with content blocks or place every element by hand, and mix the two when you need to.

Doc API

Declarative. Write a document as a list of content blocks and let the library handle layout, pagination, headers, and footers. Best for reports, articles, and invoices.

Document API

Imperative. Place text, shapes, images, and containers at exact coordinates with flex and flow layout. Best for precise designs and custom layouts.

Features

Real font weights

Six variable fonts are bundled and auto registered. font_weight and markdown bold render genuine weights from thin to black.

LaTeX math

Block and inline formulas are typeset by MathJax into crisp vector paths, with selectable math fonts.

Native charts

Bar, line, area, pie, and donut charts render as vector graphics with no image step.

Tables and notes

Tables with rich cells, callout notes, lists, code blocks, dividers, and images.

Layout engine

Flex and flow containers, z index layering, and explicit positioning in the low level API.

Portable

Works on Node 18+ and Bun, in both ESM and CommonJS. Fonts and the font instancer are bundled.

How the two APIs relate

Doc compiles its block tree down to the Document and Page element API and then calls build. It adds no separate renderer. Anything Doc produces, you could also build by hand with Document. Start with Doc for documents, and drop to Document when you need exact control.
import { Doc, Document } from "@nemu-ai/pdf";

A first look

import { Doc } from "@nemu-ai/pdf";

const doc = new Doc({ page_size: "A4", margin: 54 });

doc.page().content(
  { type: "heading", text: "Quarterly Report", level: 1 },
  { type: "paragraph", text: "Revenue grew across every region this quarter." },
);

await doc.build("report.pdf");

Install the package

Add @nemu-ai/pdf to your project and render your first PDF.