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

rtf-viewer

v1.3.0

Published

Browser-only RTF document engine with Rust/WASM parsing and paginated Canvas output

Downloads

400

Readme

rtf-viewer

A browser-only RTF document engine: original bytes → Rust/WASM parser → paginated layout → Canvas or ImageBitmap. Use the engine in your application or add the lightweight viewer. No framework, server conversion, or automatic font downloads are required.

The 1.x release supports Unicode and common Windows/East Asian codepages, direct text formatting, paragraphs, real paper sizes, automatic pagination, inline PNG/JPEG, and single-level tables with cell boundaries, padding, borders and rows that continue across a page. Merged cells, nested tables, repeated header rows, cell shading and vertical cell alignment keep their fallbacks and report specific diagnostics. Lists resolve real numbering from the document's list tables, including nested levels, bullets and restarts. A WMF or EMF whose drawing is an embedded bitmap is drawn from that bitmap; one drawn with vector records still shows a placeholder. Headers, footers and stylesheet inheritance remain incomplete. Check the support matrix for your document corpus.

Install

npm install rtf-viewer

The package includes JavaScript, TypeScript declarations, the parser Worker, and WASM. npm consumers need neither Rust nor a source checkout. Tested archives and checksums are also available from GitHub Releases.

Render a document

Given a local file input and a canvas:

import { RtfDocument } from 'rtf-viewer';

const file = document.querySelector<HTMLInputElement>('#file')!.files![0];
const canvas = document.querySelector<HTMLCanvasElement>('#page')!;
const rtf = await RtfDocument.load(file);

try {
  console.log(rtf.pageCount); // complete count after loading
  console.log(rtf.getPageSize(0)); // points; page indexes start at zero
  console.log(rtf.diagnostics); // unsupported or approximated content
  await rtf.renderPage(canvas, 0, { ppi: 144 });
} finally {
  rtf.destroy();
}

load() accepts Blob, File, ArrayBuffer, or Uint8Array. For an image pipeline, use await rtf.renderPageToBitmap(index, { ppi: 300 }) and close each returned bitmap with bitmap.close() when finished. Layout uses points; PPI, scale, and pixel ratio change output pixels without changing line breaks or page count.

An AbortSignal cancels loading or rendering. Destroying a document releases its resources and is safe to repeat. Returned bitmaps and supplied canvases belong to the caller. Prepared fonts must be available before layout; relevant font changes require an explicit relayout() and refresh of the caller's page cache. Known unrelated font completions are ignored. Renders whose layout is superseded before completion reject and can be retried. See the API reference for font mapping, cancellation, concurrent rendering, viewer ownership, and asset URL overrides.

Layout and paint yield through scheduler.yield() when available, then MessageChannel, with timers as the last fallback. This reduces waiting between work slices while preserving cancellation and pagination; see the performance measurements.

Public API and versioning

| Import | Purpose | | --------------------- | ----------------------------------------------------------------------------------- | | rtf-viewer | RtfDocument, layoutDocument, pixelSize, and public model/layout/options types | | rtf-viewer/viewer | RtfViewer for navigation and zoom around a supplied canvas | | rtf-viewer/assets/* | Shipped Worker/WASM assets for explicit deployment |

The 1.x API contract includes these exports, public fields, and ownership rules. Incompatible changes require a major version. Format coverage can grow compatibly in minor releases; fixes can change rendered pixels. This is a read-only library, with no editing or round-trip promise.

Relationship to office-open-xml-viewer

office-open-xml-viewer informed the separation of parsing, layout, painting, and UI. Its image-header implementation is imported from a pinned Git submodule and bundled into this package. Dependabot proposes upstream commit updates, which run through our adapter, parser, layout, browser, and package tests before merge.

This shares the small image implementation without running the upstream OOXML build or adapting RTF into DOCX-specific models. Its current npm package does not expose that helper as a public API. If a suitable public entry becomes available, an npm dependency is the preferred replacement. The reuse evaluation records actual imports, measurements, and the limits of this relationship.

Development

Use Node from .node-version, pnpm 10.33.0, and Rust through rustup. Keep Cargo and wasm-bindgen on PATH (on Unix, source "$HOME/.cargo/env" after installing Rust).

git clone --recurse-submodules https://github.com/rwv/rtf-viewer.git
cd rtf-viewer
corepack enable
pnpm install --frozen-lockfile
cargo install wasm-bindgen-cli --version 0.2.128 --locked
pnpm dev

For an existing checkout, run git submodule update --init --recursive. The submodule is a source dependency only: do not install or build its workspace.

pnpm exec playwright install --with-deps chromium firefox webkit
pnpm check

pnpm check covers formatting, lint, Rust format/clippy/tests, generated contracts, deterministic layout, typed browser/Worker/build code, production browser tests, and a fresh npm installation of the packed archive. The contributor guide describes fast checks, required CI gates, and dependency updates. See testing for individual commands and independent reference outputs.

Releases and contributing

Use Conventional Commit titles for squash-merged PRs: fix: for patches, feat: for minor releases, and ! for breaking changes. Release Please maintains the version/changelog PR. Merging that PR creates the tag and release; Actions verifies the package and publishes it through the npm GitHub Environment using OIDC, then verifies the registry download and runs the installed consumer again. Manual dispatch is reserved for recovery. See the release procedure.

Start with the engineering constraints, architecture, and roadmap. Compatibility evidence lives in the producer report, the producer corpus and the verification record. Source reuse and licenses are listed in third-party notices.

The normative reference is Microsoft's Rich Text Format Specification 1.9.1, dated 19 March 2008.