npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

postext

v1.63.9

Published

A programmable typesetter for the web. Layout engine that applies professional editorial rules — columns, orphan/widow prevention, balanced columns, resource placement, running heads — to semantic content. Built on @chenglou/pretext for DOM-free text meas

Readme

postext

A programmable typesetter for the web.

postext is a layout engine that takes semantic content — enriched markdown with referenced resources — and applies professional editorial layout rules to produce publication-grade output. Built on top of @chenglou/pretext for DOM-free, pixel-perfect text measurement.

Website: postext.dev

Install

npm install postext

The main entry has no framework dependency. React (>= 18, a peer dependency) is used only by the postext/react subpath. PDF and EPUB output live in the companion packages postext-pdf and postext-epub.

From a CDN, import it as a module — no build step:

import { buildDocument, renderPage } from 'https://esm.sh/postext';

Quick Example

import { buildDocument, registerResourceImage, renderPage } from 'postext';
import type { PostextConfig, PostextContent } from 'postext';

const content: PostextContent = {
  markdown: '# My Article\n\nThe harbour, shown in :ref{id="harbour"}, was rebuilt in 1854.',
  resources: [
    {
      id: 'harbour',
      typeId: 'figure',
      kind: 'bitmap',
      caption: 'The harbour at dawn.',
      altText: 'Fishing boats moored in a small harbour',
      createdAt: 0,
      updatedAt: 0,
      bitmap: { fileId: 'harbour.jpg', format: 'jpeg', width: 1600, height: 1000 },
    },
  ],
};

const config: PostextConfig = {
  page: { sizePreset: '17x24', dpi: 150 },
  layout: { layoutType: 'double', gutterWidth: { value: 0.75, unit: 'cm' } },
  bodyText: { fontFamily: 'EB Garamond', fontSize: { value: 9, unit: 'pt' } },
  headings: { fontFamily: 'Open Sans' },
  locale: 'en-us',
};

// Fonts before layout: text measured with a fallback font breaks differently.
await Promise.all(['16px "EB Garamond"', 'bold 16px "Open Sans"'].map((f) => document.fonts.load(f)));

// Images are registered by `fileId`, out of band.
const img = new Image();
img.src = '/images/harbour.jpg';
await img.decode();
registerResourceImage('harbour.jpg', img);

const doc = buildDocument(content, config);
document.body.append(...doc.pages.map((page) => renderPage(page, doc)));

buildDocument returns the Virtual Document Tree (VDT): every page, column, line and figure with its coordinates. The renderers only paint it.

API at a glance

| Export | What it does | |---|---| | buildDocument(content, config?) | Lays the content out and returns the VDT (VDTDocument). | | buildDocumentWithFonts(content, config?, options?), prepareFonts(content, config?, options?) | Load the faces the document sets, then lay it out (or only load them). See Fonts. | | renderPage(page, doc), renderPageToCanvas(page, doc, canvas, { scale? }) | Paint one page on a canvas. | | renderToHtml(doc, options?) | Absolutely positioned HTML for the pages. Pages are transparent unless you pass background. | | renderToPdf(doc, { fontProvider }) | From postext-pdf: a print-ready, tagged PDF. | | initMathEngine() | Starts MathJax. Await it before laying out $…$ / $$…$$ on the main thread; until then formulas are grey placeholder boxes. | | registerResourceImage(fileId, image) | Supplies the decoded image of a bitmap or SVG resource to the canvas renderer. | | findLooseLines(doc), drawLooseLines(ctx, page, doc) | The loose justified lines, as data or painted over a page. | | openBundle, createBundle, buildBundle | Read, write and lay out .postext books. | | mergeConfigLayers, leastConfigOverride, commonConfig | A book in several languages: general settings plus a per-language override, merged field by field, and the override that keeps only what a language sets differently. | | attachExercises(root, options?), EXERCISE_SCRIPT | Make the :::exercise blocks of renderToHtml's output answerable (Check, Show solution, Try again, answers kept per book), with store and onResult for a host that records the results. EXERCISE_SCRIPT is the same code as a standalone script. | | renderToScorm(docs, options) | From postext-scorm: a SCORM 1.2 or 2004 package for a learning platform, its exercises reporting their scores. | | createLayoutWorker() (postext/worker) | Runs the layout in a Web Worker, with cancellation. Works from esm.sh too. | | createLayout(content, config?) (postext/react) | A React component that lays the content out and shows its pages. | | readDocx, analyzeDocx, wordToPostext, postextToDocx, wordStyleTracking, applyStyleTracking (postext/word) | Read a Word .docx and report its quality, turn it into Markdown chapters with its styles mapped, write chapters back as a .docx, and carry the character spacing of Word styles onto the book's styles. |

The resolvers (resolve*Config), strippers (strip*Defaults), DEFAULT_* constants and every type are exported as well. The ICC output profiles of print production ship in the package as postext/icc/<id>.icc. See the configuration reference and the document format.

Content

PostextContent is the input:

| Field | Type | Description | |---|---|---| | markdown | string | Enriched markdown: headings, lists, code blocks, [^id] footnotes, [@key] citations, :ref{id="…"} references, ::resource{id="…"} embeds, :::callout, :::exercise, :::verse, :::part, :::toc, :::index, $…$ math, music fences, … | | resources? | Resource[] | Bitmaps, SVGs, tables and videos, referenced by id from the markdown. Binary payloads (pictures, a video's poster and own file) are referenced by fileId; tables carry their model inline. | | metadata? | DocumentMetadata | Title, author and dates (also read from the markdown's YAML frontmatter). | | continuation? | LayoutContinuation | Counters, page numbering and parity carried over from the chapters before, for a book laid out chapter by chapter. | | outline? | OutlineEntry[] | The book's outline, for a :::toc in a chapter laid out on its own. | | citations? | CitationContext | The chapter's share of its book's citations, so a chapter laid out on its own numbers them as in the whole book. | | laterPageIds? | Record<string, number> | The page fences of the chapters after this one, for a composed-page frame that continues its story there. | | notes? | PostextNote[] | Accepted, but the engine does not read it: notes are written in the markdown (below). |

Footnotes are written in the markdown: a [^id] marker where the note is cited and a paragraph that opens with [^id]: for its text. Each note is set at the foot of the column that cites it; footnotes.placement: 'chapterEnd' gathers them after the chapter instead. See Footnotes.

Fonts

postext measures text with the browser's canvas, so the document's web fonts must be loaded before layout. await buildDocumentWithFonts(content, config) does both: it loads every face the configuration and the text ask for, lays the document out, and lays it out again when the pages used a face that was missing. await prepareFonts(content, config) only loads them, before a buildDocument of your own. Both load the faces the page declares (an @font-face rule, a FontFace you added) and take a resolve(family, weight, style) option that hands over the files of the rest.

Measured widths follow the faces. When a face arrives after a build, the engine drops what it measured in that family and the next build measures it again, with no call from you; up to 1.24 that took clearMeasurementCache() and a second build. doc.contentWarnings lists a face that was measured with a fallback as fontFallback. A layout worker has its own font set; send it the font files with registerFonts.

Bundles (.postext files)

A .postext file is a whole book (manifest, chapters, resources and fonts) in one zip: the format the Sandbox exports and imports. Open one and render it, or write one from your own document:

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

const bundle = await openBundle(await file.arrayBuffer());
await loadBundleFonts(bundle);
await registerBundleImages(bundle);
const docs = buildBundle(bundle);                 // one VDTDocument per chapter
const canvas = renderPage(docs[0].pages[0], docs[0]);

const { bytes } = await createBundle({ name: 'My Book', chapters: [{ markdown: '# One\n\n…' }], config });

See Bundles for the full API, the PDF adapters and live examples.

With pretext

postext is designed to work alongside @chenglou/pretext. pretext measures how much space text needs (DOM-free, 300-600x faster than DOM measurement). postext uses those measurements to make editorial layout decisions.

import { prepare, layout } from '@chenglou/pretext';
import { buildDocument } from 'postext';

// pretext: measure text dimensions
const prepared = prepare(paragraphText, '16px/1.5 Inter');
const { height } = layout(prepared, columnWidth, 24);

// postext: apply layout rules
const doc = buildDocument(content, config);

Full Documentation

Visit postext.dev for the full documentation, project vision, architecture, and roadmap. For contributing guidelines, see the GitHub repository.

License

MIT. The math engine bundles MathJax and mhchemParser, both under the Apache License 2.0.