Skip to content

Getting Started

Ignacio Ferro Picón edited this page Oct 16, 2026 · 3 revisions

Getting Started

Install Postext, lay out a first page, then write the same document as a PDF, an EPUB or a 3D book. Every snippet here also runs from a CDN (https://esm.sh/postext) with nothing to install; the Cookbook and the live examples on postext.dev are built that way.

For the ideas behind the engine, read Introduction. For every setting, see Configuration. For the full programming guide, see Programmatic Usage.


Prerequisites

  • A modern browser (Chrome, Safari or Firefox). Layout measures text with canvas font metrics, so it runs in the browser or in a Web Worker. The PDF and EPUB writers also run in Node.
  • Node.js 20 or later and any package manager, if you install from npm.

Install

npm install postext

The other packages are added when you need them:

npm install postext-pdf         # PDF
npm install postext-epub        # EPUB 3
npm install postext-folio three # 3D book viewer
npm install postext-citeproc    # citations in CSL styles

react (18 or later) is a peer dependency of postext, used only by postext/react; the main entry never loads it.


Your first page

Postext measures text with the fonts the browser has loaded, so load them before building. The defaults are EB Garamond for the body and Open Sans for headings.

import { buildDocument, renderPage } from 'postext';

await Promise.all([
  document.fonts.load('16px "EB Garamond"'),
  document.fonts.load('bold 16px "Open Sans"'),
]);

const doc = buildDocument(
  { markdown: '# Hello, Postext\n\nA paragraph of body text, broken with Knuth-Plass and hyphenated.' },
  {
    page: { sizePreset: '17x24' },
    layout: { layoutType: 'double', gutterWidth: { value: 0.75, unit: 'cm' } },
    bodyText: { fontFamily: 'EB Garamond', fontSize: { value: 10, unit: 'pt' } },
  },
);

// One <canvas> per page.
for (const page of doc.pages) document.body.append(renderPage(page, doc));

buildDocument returns a VDTDocument: pages, columns, blocks and measured lines with their coordinates. Every output reads it:

  • renderPage(page, doc) / renderPageToCanvas(page, doc, canvas) / renderToCanvas(doc) draw pages on canvas.
  • renderToHtml(doc) returns absolutely positioned HTML; renderToHtmlIndexed(doc) adds a per-block index for patching a live view. See Integrating the HTML viewer.
  • renderToPdf, renderToEpub and createFolioFromDocument come from their own packages (below).

If the markdown contains maths, start the math engine first with await initMathEngine().


A PDF

The PDF embeds real font files, so renderToPdf asks a font provider for the bytes of each face it sets. This one fetches static WOFF2 files from Fontsource:

import { renderToPdf, decompressWoff2 } from 'postext-pdf';

const fontProvider = async (family: string, weight: number, style: string) => {
  const id = family.toLowerCase().replace(/\s+/g, '-');
  const url = `https://cdn.jsdelivr.net/npm/@fontsource/${id}@latest/files/${id}-latin-${weight}-${style}.woff2`;
  const res = await fetch(url);
  return decompressWoff2(new Uint8Array(await res.arrayBuffer()));
};

const bytes = await renderToPdf(doc, { fontProvider });
const url = URL.createObjectURL(new Blob([bytes], { type: 'application/pdf' }));

Pictures need a resourceBytes provider too. Colour space, outlines and tagged (accessible) output follow the document's pdfGeneration settings. For long books, postext-pdf/worker writes the file on a worker. See Generating PDFs.


An EPUB

renderToEpub takes the book's chapters in order:

import { renderToEpub } from 'postext-epub';

const epub = await renderToEpub([doc], {
  layout: 'reflowable', // or 'fixed': every printed page as it is
  metadata: { title: 'Hello', language: 'en' },
});

See EPUB books.


A 3D book

import { createFolioFromDocument } from 'postext-folio';

createFolioFromDocument(document.getElementById('book')!, doc);

Drag a page by its edge, click it or use the arrow keys. See A 3D book.


A whole book from a .postext file

A .postext bundle (what the Sandbox exports) holds a book's chapters, configuration, pictures and fonts:

import { openBundle, loadBundleFonts, registerBundleImages, buildBundle, renderPage } from 'postext';

const bundle = await openBundle(file);        // a File, Blob or ArrayBuffer
await loadBundleFonts(bundle);
await registerBundleImages(bundle);
const chapters = buildBundle(bundle);         // one VDTDocument per chapter, each continuing the last

createBundle writes one from code. See Bundles.


Layout in a Web Worker

For live previews and editors, run layout off the main thread. A newer build cancels the one in flight:

import { createLayoutWorker } from 'postext/worker';

const layout = createLayoutWorker();
await layout.registerFonts(fontPayloads); // font files as ArrayBuffers, transferred

const controller = new AbortController();
const doc = await layout.build(content, config, { signal: controller.signal });
// controller.abort() rejects the pending build with an AbortError.

layout.dispose();

See Running layout in a Web Worker, including how to load the worker from a CDN.


React

import { createLayout } from 'postext/react';

const Article = createLayout({ markdown: '# Hello' }, { page: { sizePreset: '17x24' } });

export const Page = () => <Article className="pages" />;

See React.


Next steps

Clone this wiki locally