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

lazy-pdf

v0.1.0

Published

A minimal virtualized PDF viewer that lazy-loads pages via HTTP range requests.

Readme

lazy-pdf

A minimal virtualized PDF viewer for the browser. Pages are fetched with HTTP range requests and only nearby pages are rendered, so large documents stay light.

Built on pdf.js (pdfjs-dist).

The public API is PdfVirtualViewer (see src/pdf-viewer.js). This package was previously published as [email protected], which is frozen.

Install

npm i lazy-pdf pdfjs-dist

pdfjs-dist is a peer (and runtime) dependency. Import the stylesheet once:

import "lazy-pdf/styles.css";

Quick start

The container must have a definite height and display: flex (the scroller fills it).

<div id="viewer" style="height: 80vh; display: flex; overflow: hidden"></div>
import { PdfVirtualViewer } from "lazy-pdf";
import "lazy-pdf/styles.css";

const viewer = new PdfVirtualViewer(document.getElementById("viewer")!, {
  onStatus: (text) => console.log(text),
});

await viewer.load("https://example.com/book.pdf");

Worker

If pdfjs-dist has no GlobalWorkerOptions.workerSrc yet, PdfVirtualViewer points at the cdnjs build of pdf.js 4.10.38. To use a local worker instead:

import { GlobalWorkerOptions } from "pdfjs-dist";

GlobalWorkerOptions.workerSrc = new URL(
  "pdfjs-dist/build/pdf.worker.min.mjs",
  import.meta.url,
).toString();

Set this before constructing PdfVirtualViewer.

CORS and range requests

PdfVirtualViewer.load() opens the PDF with disableAutoFetch and disableStream, so the host must:

  1. Allow cross-origin reads from your page (Access-Control-Allow-Origin).
  2. Support HTTP range requests (Accept-Ranges: bytes) and expose Content-Range / Accept-Ranges to the browser (Access-Control-Expose-Headers).

Same-origin files (or a same-origin proxy) skip the CORS requirement. The included demo server (npm run serve) proxies remote URLs at /proxy?url= for local testing.

API

import { PdfVirtualViewer } from "lazy-pdf";
import type { PdfVirtualViewerOptions, Annotations } from "lazy-pdf";

const viewer = new PdfVirtualViewer(container, options?);
await viewer.load(url);
viewer.setAnnotation(page, text);
viewer.removeAnnotation(page);
viewer.getAnnotations();      // Record<number, string>
viewer.setAnnotations(map);
viewer.destroy();

PdfVirtualViewerOptions

| Option | Type | Default | Description | |--------|------|---------|-------------| | onStatus | (status: string) => void | — | Load / render progress text | | prefetchPages | number | 2 | Extra pages to render past the viewport | | renderMargin | number | 800 | Extra pixels around the viewport that count as “near” | | maxPageWidth | number | 900 | Cap on rendered page width (px) | | annotations | Record<number, string> | {} | Initial per-page notes (1-based page numbers) | | onAnnotationsChange | (annotations) => void | — | Fired after add / edit / delete |

Page numbers in annotations are 1-based.

Styles

import "lazy-pdf/styles.css";

The stylesheet is also exported as lazy-pdf/styles.css (file: src/pdf-viewer.css). Layout classes from that file:

  • .pvv-scroller — scrollport (needs a flex parent with a height)
  • .pvv-pages / .pvv-page-slot / .pvv-page — virtualized page stack
  • .pvv-annotate-strip — note row under each page

Demo

git clone https://github.com/thejsmaster/pdf-virtual-viewer
cd pdf-virtual-viewer
npm i
npm run serve

Opens on http://localhost:8080. Paste a PDF URL and press Load. Remote files go through /proxy?url= so range requests work locally. The demo constructs PdfVirtualViewer from ./src/pdf-viewer.js.

npm run make-sample -- 40   # optional: generate a multi-page sample PDF

How it works

  1. pdfjs-dist loads the document with range requests (disableAutoFetch / disableStream).
  2. Empty page slots are laid out for the full page count.
  3. On scroll / resize, only slots near the viewport (plus prefetchPages) are rendered to canvas.
  4. Each page has an optional annotation strip underneath.

License

MIT