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

@soadzoor/hepr

v0.1.71

Published

Highly-Efficient-PDF-Renderer is a GPU-first PDF renderer for large technical documents, floorplans, books, and more, using the latest technologies and various tricks to achieve high performance and visual fidelity.

Readme

Highly Efficient PDF Renderer (HEPR)

GPU rendering for detailed floorplans, technical drawings, and entire books — in a standalone viewer or your three.js scene.

HEPR brings PDF vector content, text, and embedded images to the GPU. WebGL and WebGPU backends, adaptive level of detail, and a reusable .hep document format help keep detailed documents practical to explore.

Live demo · Examples · Manual · API · Documentation · Changelog

Try it

Open the standalone viewer or the three.js demo. Choose a bundled example or drop in a PDF or HEP file, then pan, zoom, search, and select text. Both demos offer WebGL and WebGPU modes.

Features

  • GPU vector rendering: strokes, fills, and text stay sharp as you zoom; embedded images and composited PDF content are supported too.
  • Adaptive detail: vector and text LOD reduce work when detail is too small to see.
  • Three.js integration: add a THREE.Group to your scene and use your camera and controls.
  • Multiple pages: load a whole PDF or selected pages, arranged in a grid.
  • Search and selection: find text, highlight matches, and copy selections on desktop and touch devices.
  • Drawing selection: select drawing elements, inspect their geometry and layer membership, and temporarily recolor vectors.
  • PDF layers: toggle optional content in the main viewer, inspect layer dependencies when picking geometry, or use the shared library APIs.
  • Reusable documents: export .hep files with geometry, images, and a searchable text index to skip PDF parsing on subsequent loads.
  • Fast thumbnails: prepare one PDF/HEP page for its requested pixel size, with cancellation, lossless WebP output, and reusable thumbnail-to-HEP sessions.

Thumbnails

import { renderPdfThumbnail } from "@soadzoor/hepr/bundler";

const { blob, width, height } = await renderPdfThumbnail(file, {
  page: 1,
  maxDimension: 400,
  background: "transparent",
  signal: controller.signal,
});

Thumbnails prioritize a quick overview: fine text and geometry can be approximated at the requested resolution. WebP encoding is lossless; full-quality HEP conversion keeps its normal preparation settings. Use openDocumentSession to share PDF parsing and font resources between thumbnails and HEP conversion.

For Node.js, import the same thumbnail and session functions from @soadzoor/hepr/node. Install the optional Canvas2D backend for server rendering:

npm install @soadzoor/hepr @napi-rs/canvas
import { writeFile } from "node:fs/promises";
import { renderPdfThumbnail } from "@soadzoor/hepr/node";

const { blob, width, height } = await renderPdfThumbnail("drawing.pdf", {
  maxDimension: 400,
  background: "transparent",
});
const outputPath = blob.type === "image/webp" ? "drawing.webp" : "drawing.png";
await writeFile(outputPath, new Uint8Array(await blob.arrayBuffer()));

The Node API accepts PDF paths, file URLs and bytes, uses Canvas2D and Node workers, and requires no browser globals. Its reusable openDocumentSession also supports later full-quality HEP conversion. HEP input thumbnails remain available through the browser API. See Node thumbnails for cancellation, source and worker options.

See it in action

Toggle PDF layers

Show or hide individual layers (PDF OCG) to focus on the parts of a drawing you need.

Toggling layer visibility in a PDF drawing

Zoom into every detail

Vector graphics stay vector. Zoom deep into a detailed floorplan while lines and curves stay sharp and navigation stays smooth.

Zooming into a vector floorplan while preserving sharp detail

Explore whole books

Load an entire book, then find, select, and copy text with crisp rendering and smooth navigation. Here, HEPR handles War and Peace.

Navigating War and Peace and finding and selecting text

Quick start

Install the browser package alongside three.js:

npm install @soadzoor/hepr three

For browser apps built with Vite, use @soadzoor/hepr/bundler throughout your application and add these settings to your existing Vite configuration:

import { defineConfig } from "vite";

export default defineConfig({
  optimizeDeps: { exclude: ["@soadzoor/hepr/bundler"] },
  worker: { format: "es" }
});

No HEPR plugin or manual asset copying is required. See package entry points for other bundlers, prebuilt assets, and Node usage.

Serve a PDF at /document.pdf and add this to your entry module:

import * as THREE from "three";
import { MapControls } from "three/addons/controls/MapControls.js";
import { pdfObjectGenerator } from "@soadzoor/hepr/bundler";

const width = 800;
const height = 600;
const aspect = width / height;
const scene = new THREE.Scene();
const camera = new THREE.OrthographicCamera(-aspect, aspect, 1, -1, 0.1, 100);
camera.position.z = 10;

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);

const controls = new MapControls(camera, renderer.domElement);
controls.enableRotate = false;
controls.screenSpacePanning = true;
controls.update();

const pdf = await pdfObjectGenerator("/document.pdf");

// HEPR centers the document at the origin. Fit its longest side into the view.
const bounds = pdf.sceneData.pageBounds;
const size = Math.max(bounds.maxX - bounds.minX, bounds.maxY - bounds.minY, 1);
pdf.scale.setScalar(1.8 / size);
scene.add(pdf);

renderer.setAnimationLoop(() => renderer.render(scene, camera));

Drag to pan and scroll or pinch to zoom. The responsive viewer example adds window resizing and complete viewer cleanup.

Individual pages also expose normal Three.js transforms on both backends:

const page = await pdf.getPage(0); // Zero-based displayed page index
page.position.z = 20;
page.rotation.y = Math.PI / 6;
page.scale.setScalar(0.8);
// Also available: getPages(), setPagePosition(index, x, y, z),
// and setPageTransform(index, matrix4).

Page views preserve the initial layout and use the page center as their pivot. Compatible pages keep cross-page batching while moving independently, using a shared GPU transform table on both Three.js backends. Paint-order constraints automatically use separate page rendering when needed. See the page API for matrix, ownership, coordinate and HEP compatibility details.

The same loader accepts .hep files, File/Blob objects, bytes, and base64 data. Select PDF pages with { pages: "1-3, 5" }; report loading progress with { onProgress: ({ stage, value }) => console.log(stage, value) }.

When removing a document, call pdf.removeFromParent() and pdf.dispose(). When closing the viewer, also stop its animation loop and dispose its controls and renderer. See the examples to add search, text selection, and drawing selection.

Render your own polylines

Use buildStrokeScene and createThreePdfObject to render your own polylines with HEPR's stroke batching and camera-driven LOD, without a PDF. See the polyline example for geometry, placement, and cleanup.

Save a HEP file

Build a reusable document from a PDF, or export the scene you already loaded:

import { buildHep } from "@soadzoor/hepr/bundler";

const hepBlob = await buildHep("/document.pdf");
// Or: const hepBlob = await buildHep(pdf.sceneData);
// Save or upload the Blob with a .hep filename.

For conversion followed by immediate display, use buildHepWithScene() (also available on document sessions) to receive { blob, scene }. Pass that scene to createThreePdfObject() without decoding the generated HEP; applicable LOD caches are reused. The scene remains usable after the session closes and retains full-resolution image pixels, which can use more memory than a blob-only export.

HEP skips PDF extraction. buildHep includes applicable vector and text LOD caches by default to skip expensive simplification on load. Set withVectorLod: false and/or withTextLod: false to omit them. Shared vector records reduce file size; spatial indexes and GPU resources are prepared when opening the file. Stored vector LODs default to compact precision, with bounded rounding of derived positions; the exact scene stays unchanged. Set vectorLodPrecision: "lossless" to disable additional rounding. See the manual for browser export and Node conversion.

Convert a local PDF or a directory of PDFs from the command line:

npx @soadzoor/hepr ./input.pdf --output-dir=./heps
npx @soadzoor/hepr ./pdfs --workers=4 --output-dir=./heps

Thumbnail CLI modes are available in this checkout. Until a version containing them is published, use the local launcher with the compiled library prepared:

node bin/pdf-to-hep.js ./drawing.pdf --output=thumbnail
node bin/pdf-to-hep.js ./pdfs --output=both --thumbnail-max-dimension=400 --output-dir=./output

--output=hep remains the default. Thumbnail output defaults to page 1, a 400-pixel longest side, lossless WebP and a white background; for example, drawing-thumbnail-p1.webp. Select PNG, another page or a transparent background with --thumbnail-format=png, --thumbnail-page=2 and --thumbnail-background=transparent. both reuses the document session for the thumbnail and canonical HEP conversion. Existing HEP and thumbnail outputs are skipped independently; use --force to regenerate them. See the CLI thumbnail options for details.

The CLI includes applicable vector and text LOD caches by default, matching buildHep and both example viewers. Use --without-vector-lod or --without-text-lod to omit either cache, or both flags for smaller files without stored LODs. Stored vector LODs use compact precision unless --vector-lod-precision=lossless is supplied.

The CLI requires Node.js 22.15+, 23.5+, or 24+. It writes <name>-parsed-data.hep and supports the same conversion flags as the repository's node PDFtoHEP.js command. After installing the package in a project, use npx -- pdf-to-hep --help to see all options. Conversion batches save detailed worker output, warnings, errors, full file paths, and raster-fallback diagnostics to pdf-to-hep-<timestamp>-<unique>.log in the current directory. Use --log-file=./conversion.log to choose a log file; an existing file is appended to. For HEP-only runs, the terminal shows progress, followed by a table of filenames, statuses, durations, peak RSS, PDF and HEP sizes, and percentage size changes. Peak RSS is the highest resident memory of the worker process that converted the PDF, including its runtime and parser thread; copied duplicates show none. Smaller HEPs are green and larger HEPs are red when the terminal supports color and NO_COLOR is unset. The final metrics table includes attempted, successful, failed and skipped counts, warning and raster-fallback counts, total conversion time, average and median attempted conversion times, the highest worker peak RSS, batch wall time, and successful size totals. Existing-file skips are excluded from timing and size comparisons; --force --keep-unchanged conversions count as successful even when the existing HEP is kept. Summed conversion times can exceed wall time when workers overlap. PDFs with identical content (same size and SHA-256) are converted once per batch; the other copies receive a copy of that HEP and are reported as duplicates. Successful copies count toward attempted and successful PDFs, both file-size totals, and raster-fallback counts. Timing statistics include their actual copy time; estimated conversion time saved is reported separately. Warning totals count diagnostics actually emitted during the run. Conversion requires @napi-rs/canvas, which npm installs as an optional dependency by default. If its installation fails or optional dependencies were omitted, install both packages with npm install @soadzoor/hepr @napi-rs/canvas and run npx pdf-to-hep from that project.

Current HEP readers support scene schemas v9–v16. Exports select the version required by their stored features. Eligible oversized JPEG 2000 images retain their original compression and full-resolution pixels in v16, without another lossy encode; only exports using this storage require a v16-capable reader. Regenerate archives with scene schemas older than v9 from the original PDFs. Exports retain hidden content and original layer defaults; temporary layer visibility and primitive colors remain per-view settings.

Learn more

| Page | What you will find | | --- | --- | | Examples | Live demos and integration recipes. | | Manual | Loading, rendering options, interaction, and HEP conversion. | | API reference | Public functions, options, and object methods. | | Documentation | How rendering works and links to technical references. | | Development | Local setup, builds, tests, and example assets. | | Changelog | Release notes, compatibility changes, and upgrade guidance. |

Requirements and scope

Use a modern browser with WebGL2, or WebGPU support for the WebGPU backend. The browser package uses browser canvas APIs; Node PDF conversion may also need the optional @napi-rs/canvas dependency.

HEPR prepares all selected pages before returning a document. It prefers usable output over rejecting a PDF: supported content stays vector-based, while some pages use bounded raster fallback or diagnosed visual approximations. Rasterized pages lose vector sharpness and drawing geometry; searchable text is retained where available. Encrypted PDFs are decrypted, using the password option when one is required. Features unsupported by both compilation and rendering still produce errors. See the manual for platform and format details.

Contributing

Bug reports and focused contributions are welcome. For rendering issues, include a reproducible PDF when possible, the affected page, browser, and backend in an issue. Start with the development guide for local checks.

License and credits

MIT. Inspired by Will Dobbie's GPU text rendering work and Unreal Engine's Nanite. Third-party attributions are listed in THIRD_PARTY_NOTICES.