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

@voxelkloud/format-single

v0.5.1

Published

The single-file tier for voxelkloud: a LAS, LAZ, E57, PLY, PCD or XYZ with no index, downloaded whole and turned into a streamable octree in the browser.

Readme

@voxelkloud/format-single

The single-file tier for voxelkloud: a .las, .laz, .e57, .ply, .pcd or .xyz with no index at all.

npm install @voxelkloud/format-single
import { singleFileFormat } from "@voxelkloud/format-single";
import { formats, loadPointCloud } from "@voxelkloud/loader";

// AFTER the COPC driver — see the tie-break below.
formats.register(copcFormat).register(singleFileFormat);

const { source, tree, openPoints } = await loadPointCloud("/scan.laz");
view.addCloud(source, tree, openPoints);

Or from a file the user dropped, with no request at all:

const source = await loadSingleFileSource(file.name, {
  bytes: new Uint8Array(await file.arrayBuffer()),
  onProgress: (points) => setProgress(points),
});

The build runs in a worker

By default, wherever Worker exists. It is not an optimisation to opt into: a 20M-point build is 31 synchronous seconds with no paint, no spinner and no cancel, and the tab is simply frozen for half a minute.

What crosses back is every node's records, transferred rather than copied, so the size of the cloud costs nothing at the boundary. The worker is created per build and terminated the moment its result lands — which is the other half of the point, because the build peaks at roughly twice the records and a terminated worker's heap goes back whole. Building on the main thread leaves that peak in the page for as long as the cloud is open.

loadSingleFileSource(url, {
  onProgress: (points) => …,  // points decoded so far, at most every 250 ms
  signal: controller.signal,  // terminates the worker; the only way to stop it
  worker: false,              // build inline instead — Node, or a bundler that
});                           // cannot emit the worker chunk

onProgress is pushed from inside the build, not sampled beside it. A build is one synchronous call, so a timer in the worker would not fire once before it returned; the numbers come from a callback the wasm invokes mid-loop.

source.builtInWorker says which path ran. The result is identical either way, and there is a test that builds the same file both ways and compares every byte of every node.

The worker is dist/worker.js, loaded as new Worker(new URL("./worker.js", import.meta.url), { type: "module" }) — the form Vite, webpack 5 and Rollup all understand.

What it is for

Every other driver reads a file somebody already indexed — PotreeConverter wrote a directory, untwine wrote a COPC, Entwine wrote an EPT. This one is for the file as it came off the scanner, with nobody having run anything over it.

The bargain, stated plainly: the whole file is downloaded and the whole cloud is held in memory, because an unindexed file offers nothing to range-request and no tree to descend. That is exactly what COPC and EPT exist to avoid. This tier is the answer when nobody produced one — not a replacement for producing one.

The ceiling is 20 million points, measured: see @voxelkloud/wasm-build for the 31 seconds and 1.7 GB behind that number.

Past LAS it also reads E57, PLY, PCD and XYZ, which have no index either and never will — there is nowhere in any of them to put one.

E57 is the one with real structure behind it: the terrestrial-scanner interchange format, an XML section at the end of the file over bitpacked binary sections. Every scan's pose is applied and spherical records are converted, so a multi-scan file arrives as one cloud in the file's own frame rather than as several clouds on top of each other. Records that carry no position — the no-returns of a scan grid, 58% of libE57's own pump sample — are dropped rather than written at the origin, and which scan a point came from survives as its LAS point source id.

The tie-break with COPC

A COPC file is a valid LAZ. Both drivers can read one, and only one of them should:

| | COPC driver | this driver | | --- | --- | --- | | a .copc.laz | 3 | 0 — refuses outright | | a .laz carrying a copc VLR | 3 | 1 | | a plain .laz | 0 | 1 |

Getting this wrong is expensive in both directions. Letting this driver win downloads two gigabytes to rebuild an octree the file already contains; letting COPC win a plain LAZ used to stop the search and fail, because a decisive sniff ends it — which is why the COPC driver now looks for the copc VLR in the probe's raw bytes rather than claiming everything that starts with LASF.

What is actually here

Very little, and that is the point:

  • the octree comes from @voxelkloud/wasm-build, the converter's own partitioner;
  • the per-node decode from @voxelkloud/format-las, the same one COPC and EPT use, because the builder emits raw LAS records;
  • the tree from @voxelkloud/core's paged octree, resolving its one page out of the heap instead of off a socket.

Testing

The differential test is the one worth knowing about. lion_takanawa.copc.laz is both a COPC and an ordinary LAZ, so the same file can be read two completely different ways: streamed from the tree untwine built, or downloaded and rebuilt here. All 341,989 points come out identical, compared as sets because the two trees legitimately partition differently.

The worker has its own. Node has no Worker, so the tests supply one: a stand-in that loads the real worker.ts with a shimmed self and passes messages through structuredClone with the transfer list, which Node honours — so the test that says a caller's buffer survives is checking a real detach, not a mock.

MIT.