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.7

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-first PDF renderer for large technical documents, floorplans, and mixed vector/raster PDFs.

HEPR is built around analytic vector rendering. Strokes, fills, and text are extracted from PDF operator streams and rendered on the GPU instead of being flattened into a giant page bitmap. Embedded PDF image layers are still supported, but vector floorplan geometry stays vector geometry.

The project also exposes an npm package API (@soadzoor/hepr) with a native renderer and a three.js wrapper.

Demos

Demo GIF

Credits

HEPR was mostly inspired by the PDF GPU-text rendering work shared at https://wdobbie.com/, and Unreal Engine's Nanite Technology. Thanks for publishing the ideas and experiments that helped shape this project.

Current Highlights

  • WebGL and WebGPU renderer backends.
  • Native canvas renderer plus a three.js THREE.Group wrapper.
  • Three.js material-layer mode for strokes, fills, text, and raster layers, including WebGPU-compatible material implementations.
  • Nanite-inspired Vector LOD for very large vector stroke sets.
  • Multi-page PDF extraction and grid composition.
  • Stroked paths, filled paths, vector text, and embedded raster image layers.
  • Parsed-data ZIP export/import to skip repeated PDF extraction.
  • Runtime diagnostics for FPS, draw counts, Vector LOD state, parse/upload timing, texture usage, and culling stats.

Nanite-Inspired Vector LOD

The Vector LOD path borrows the useful idea from Nanite-style rendering without importing three-nanite or treating PDF strokes as triangle meshes.

The core idea is:

  1. Keep the exact source stroke level.
  2. Build simplified analytic stroke levels during load/preprocessing.
  3. Bucket those levels into a shared tile hierarchy.
  4. At runtime, choose per-tile LOD levels from camera scale, visible tile count, local screen error, and local segment density.
  5. Render the selected analytic stroke IDs through the existing GPU material path.

Important details:

  • Vector LOD is not a raster fallback.
  • It targets stroke-heavy floorplan PDFs first.
  • It uses predefined simplification tolerances from VECTOR_STROKE_LOD_TOLERANCES.
  • It preserves exact geometry when the screen error says exact is needed.
  • It uses smarter tile generation so dense furniture/detail clusters and sparse architectural lines are not forced into one uniform decision.
  • It applies perspective/projected-area budget weighting only when a three.js camera actually creates meaningful near/far scale differences.
  • VECTOR_STROKE_LOD_TARGET_VISIBLE_SEGMENTS is a runtime budget target, not a hard cap. The final draw count depends on tile distribution and available simplification levels.

The default mode is vectorLod: "auto":

  • "auto" enables Vector LOD for large vector-heavy scenes.
  • "off" disables Vector LOD and uses exact vector strokes.
  • "force" builds and uses Vector LOD even below the usual large-scene threshold.

Renderer Modes

Native Demo

The native demo renders directly into the app canvas through WebGlFloorplanRenderer or WebGpuFloorplanRenderer.

Controls include:

  • backend switcher: WebGL / WebGPU
  • Vector LOD mode: Auto / Off / Force
  • page background color/opacity
  • vector override color/opacity
  • collapsible diagnostics panel

Three.js Demo

The three.js demo creates a real THREE.Group with camera-driven material layers. It supports perspective camera pan, zoom, and rotation without switching back to a raster-hosted page texture.

Controls include:

  • backend switcher: WebGL / WebGPU
  • Vector LOD mode: Auto / Off / Force
  • optional touch rotation on touch-capable devices
  • page background color/opacity
  • vector override color/opacity
  • collapsible diagnostics panel

Backend switches reuse the loaded scene and preserve the camera where possible.

npm Package API (@soadzoor/hepr)

Use pdfObjectGenerator to load a PDF or parsed ZIP and create a THREE.Group. The three.js wrapper is camera-driven by default, so the PDF follows your existing THREE.Camera and controls. The generated TypeScript declaration files include JSDoc comments for the main options, return types, and runtime methods.

import * as THREE from "three";
import { pdfObjectGenerator } from "@soadzoor/hepr";

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, width / height, 0.01, 2000);
const renderer = new THREE.WebGLRenderer({ canvas });

const pdfObject = await pdfObjectGenerator(
  source,
  {
    onProgress: (progress) => {
      console.log(progress.stage, progress.value);
    }
  },
  "webgl" // "webgl" (default) | "webgpu"
);

scene.add(pdfObject);

function frame(): void {
  renderer.render(scene, camera);
  requestAnimationFrame(frame);
}

frame();

A minimal typed setup can look like this:

import { pdfObjectGenerator } from "@soadzoor/hepr";
import type { HeprThreePdfObject, PDFLoadProgress } from "@soadzoor/hepr";

const dublinPdfUrl = "/examples/pdfs/dublin.pdf";

const pdf: HeprThreePdfObject = await pdfObjectGenerator(dublinPdfUrl, {
  onProgress: (progress: PDFLoadProgress) => {
    console.log(`${progress.stage}: ${progress.value}`);
  }
});

const bounds = pdf.sceneData.pageBounds;
const width = bounds.maxX - bounds.minX;
const height = bounds.maxY - bounds.minY;
const maxSize = Math.max(width, height);

pdf.scale.set(1 / maxSize, 1 / maxSize, 1);
scene.add(pdf);

Supported source inputs:

  • File / Blob
  • Uint8Array / ArrayBuffer
  • string path or URL to .pdf / .zip
  • base64 payload string (PDF or ZIP)
  • base64 data URL (data:application/pdf;base64,...)

Useful object APIs:

  • pdfObject.getViewState()
  • pdfObject.setViewState(...)
  • pdfObject.setVectorLodMode("auto" | "off" | "force")
  • pdfObject.getVectorStrokeLodStats()
  • pdfObject.setPageBackgroundColor(...)
  • pdfObject.setVectorColorOverride(...)
  • pdfObject.fitToBounds() for the internal fallback view state
  • pdfObject.attachControls(renderer.domElement) for HEPR's fallback 2D controls
  • pdfObject.dispose()

Advanced render pipelines can call pdfObject.prepareFrameForThreeRenderer(renderer, camera) manually before renderer.render(scene, camera), but normal three.js render loops do not need it because the PDF object synchronizes itself through onBeforeRender.

Package exports:

  • @soadzoor/hepr
  • @soadzoor/hepr/three

Architecture

1. PDF Extraction

src/pdfVectorExtractor.ts uses pdfjs-dist operator streams to build structured scene data:

  • stroke primitives and style metadata
  • fill path primitives
  • text instances and glyph primitives
  • raster image layers and placement transforms
  • page rectangles/bounds for multi-page composition

Parse-time optimizations include segment merging, invisible/contained stroke culling, duplicate removal, glyph deduplication, and multi-page layout composition.

2. Scene Loading

src/pdfObjectGenerator.ts and src/main.ts handle:

  • PDF or parsed ZIP source detection
  • page extraction
  • page-grid composition
  • Vector LOD prebuild with progress callbacks
  • renderer upload

Vector LOD building yields back to the browser periodically so loading indicators can update during large PDF loads.

3. Native GPU Rendering

Native renderers:

  • src/webGlFloorplanRenderer.ts
  • src/webGpuFloorplanRenderer.ts

Both renderers use GPU buffers/textures for scene data and analytic shader evaluation for vector content. They share the same Vector LOD runtime in src/vectorStrokeLodCore.ts.

4. Three.js Material Rendering

The three.js wrapper is implemented in src/threePdfObject.ts.

Material layers:

  • src/threeMaterialStrokeLayer.ts
  • src/threeMaterialFillLayer.ts
  • src/threeMaterialTextLayer.ts
  • src/threeMaterialRasterLayer.ts
  • src/vectorStrokeLod.ts

WebGPU-compatible three.js materials live in:

  • src/threeWebGpuStrokeMaterial.ts
  • src/threeWebGpuFillMaterial.ts
  • src/threeWebGpuTextMaterial.ts
  • src/threeWebGpuRasterMaterial.ts

Parsed Data ZIP Format

The exported ZIP contains parsed scene data:

  • manifest.json
  • vector texture payloads
  • optional raster layers
  • optional embedded source PDF fallback

Parsed ZIPs are designed to skip expensive PDF extraction. The runtime Vector LOD hierarchy is currently rebuilt from parsed vector data at load time instead of being persisted, because storing every LOD level can make ZIPs much larger than the original parsed scene.

Open the native demo with ?bulkZip=1 or ?downloadAllZips=1 to reveal the Download All Example ZIPs button.

Example Assets

Folder layout:

  • public/examples/pdfs/
  • public/examples/zips/
  • public/examples/manifest.json

Regenerate the example manifest with:

npm run generate-manifest

Development

Install:

npm install

Run dev server:

npm run dev

Build app:

npm run build

Build library artifacts:

npm run build:lib

Create a local install tarball:

npm run pack:local

Run the npm publish dry run:

npm run publish:dry-run

Build app and library:

npm run build:all

Preview production build:

npm run preview

Notes

  • WebGPU requires browser and GPU support.
  • Three.js WebGPU support is implemented through Three's WebGPU renderer/material path, not by mixing a WebGPU-rendered canvas texture into a WebGL scene.
  • Embedded PDF image layers remain raster images by definition; the "no raster fallback" rule applies to vector floorplan geometry.
  • Parsed ZIPs improve load time by skipping PDF extraction, but large stroke-heavy scenes may still spend time building Vector LOD.
  • Most of this repo was "vibe-coded" with Codex. It would've taken a lot more time (~forever) without AI tools to get to this stage for me, even though I'm a professional graphical programmer. The know-hows, and technical details about PDFs are way out of my expertise.