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

@office-rs/rofd

v0.1.6

Published

TypeScript SDK wrapping the rofd WASM OFD exports.

Readme

@office-rs/rofd

TypeScript SDK for embedding the rofd OFD (GB/T 33190) view + annotation editor into any web page. Compiles the Rust editor to WebAssembly and renders via WebGPU.

Live Demo

https://office-rs.github.io/rofd/

Features

  • View OFD body (read-only render).
  • Annotate — select body text and apply highlight / underline / strikeout / squiggly via applyMarkup, or draw with the freehand / rect / free-text tools.
  • Surgical save — re-serializes annotations and preserves untouched body entries byte-for-byte.
  • WebGPU only — no Canvas2D fallback. Chrome / Edge 113+ required.
  • Zero framework — drop into any HTML page; the SDK owns the canvas, event binding, and render loop.
  • Persistent scrollbars — classic vertical/horizontal scrollbars appear only when content overflows; drag the thumb, click the track to page, click the arrow buttons at the bar ends to step, or use the wheel. Scrolling is bounded at the first page top and last page bottom.

Install

npm install @office-rs/rofd
# or: yarn add @office-rs/rofd / pnpm add @office-rs/rofd

Browser support

WebGPU requires Chrome / Edge 113+ (or any browser shipping WebGPU). On unsupported browsers Ofd.init throws WebGPU is not supported in this browser.

Quick start

<div id="ofd-container" style="width: 800px; height: 600px"></div>

<script type="module">
  import { Ofd } from '@office-rs/rofd';

  const container = document.getElementById('ofd-container');
  const ofd = await Ofd.init(container, {
    // Ctrl+S handler — host decides where to persist the bytes.
    onSaveRequest: async () => {
      const bytes = ofd.saveOfd();
      await fetch('/api/save', { method: 'POST', body: bytes });
    },
  });

  // Author + timestamp must be injected before editing (the library never
  // reads the system clock — see AGENTS.md §4.4).
  ofd.setClock('ravenq', Date.now());

  // Load an .ofd package and start annotating.
  const resp = await fetch('/doc.ofd');
  ofd.loadOfd(new Uint8Array(await resp.arrayBuffer()));
</script>

Ofd API

Ofd.init(container, config?) boots the editor: loads the wasm module, checks WebGPU, creates a canvas, initializes the wasm editor, loads fonts, wires callbacks, binds DOM events, and starts the render loop.

| Method | Description | |---|---| | loadOfd(bytes: Uint8Array) | Load an .ofd package from raw bytes. | | saveOfd(): Uint8Array | Serialize the current document back to OFD package bytes. | | setClock(author: string, ts: number) | Inject author + timestamp (ms) for subsequent edits. Call before any annotation edit. | | setTooltipEnabled(enabled: boolean) | Toggle the hover tooltip (annotation author + creation time, local timezone). On by default. | | setTool(kind: string) | Switch the active tool. One of: select (text), hand, freehand, rect, ellipse, arrow, line, polygon. Unknown values — including the legacy markup strings highlight / underline / strikeout / squiggly — fall back to the text tool. | | applyMarkup(kind: MarkupKind): string \| null | Convert the current body-text selection into a markup annotation (highlight / underline / strikeout / squiggly; color via setMarkupColor). Returns the new annotation id, or null when there is no selection. The selection is kept so further markups can stack on the same range. | | hasTextSelection(): boolean | Whether a body-text selection currently exists (drives markup-button enabled state). | | setOnTextSelectionChange(cb) | Subscribe to the body-text selection appearing / changing / clearing. Signal-only — query hasTextSelection() / getSelectedText() afterwards. | | deleteAnnotation(id: string): boolean | Delete the annotation with the given id. | | deleteSelected(): number | Delete all currently-selected annotations; returns the count. | | handleScrollPage(direction: 'up' \| 'down') | Scroll by one page height. | | handleZoomAt(factor: number, cx: number, cy: number) | Zoom by factor while keeping (cx, cy) (device pixels) anchored. | | get canUndo / get canRedo | Whether undo / redo is available. | | destroy() | Stop the render loop and remove the canvas. |

Callbacks (passed to Ofd.init)

| Callback | Fires when | |---|---| | onChange | Document changed (render loop re-renders). | | onSelectionChange | Selection set changed. | | onTextSelectionChange | Body-text selection appeared / changed / cleared. | | onCursorChange | Caret / cursor moved. | | onSaveRequest | Ctrl+S pressed — host should prompt for path or auto-save. | | onContextMenu(x, y, annotationId) | Right-click. annotationId is null when hitting page body or desk background. | | onWarning(warnings: string[]) | Non-fatal parser issues (degraded load). | | onAnnotationFocus(id) | Annotation gains editing focus (e.g. double-click FreeText). | | onAnnotationInteract(id) | Single-click interaction with an annotation (e.g. selecting a highlight). | | onPageChange(pageIndex) | Page at viewport vertical center changed. | | onZoomChange(zoom) | Zoom factor changed (1.0 = 100%). |

Fonts

The web can't read system fonts, so the SDK fetches defaults from CDN (jsDelivr, ICP-licensed China CDN nodes):

  • NotoSans-Regular.ttf
  • NotoSansCJKsc-Regular.otf

To use custom fonts, pass fonts in OfdConfig:

await Ofd.init(container, {
  fonts: [
    { url: '/fonts/MyFont.otf' },
    { data: myFontBytes }, // inline Uint8Array
  ],
});

License

Apache-2.0. See LICENSE.