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/wasm-codecs

v0.5.1

Published

LAZ decoding for voxelkloud, compiled to wasm from laz-rs: standalone laszip chunks for COPC and EPT, whole files for the single-file tier, and the LAS framing needed to find them.

Readme

@voxelkloud/wasm-codecs

LAZ decoding for voxelkloud, compiled to wasm from laz-rs. 148,064 bytes, 51,691 gzipped.

npm install @voxelkloud/wasm-codecs

Pure Rust, built with the stock wasm32-unknown-unknown target. The rest of the ecosystem ships laz-perf through Emscripten; this needs no C toolchain.

What it does, and what it leaves alone

A codec and a frame reader. It answers where are the compressed points and what are the bytes behind them, and stops there. Which of those bytes is an intensity and which is a classification differs between COPC, EPT and a bare .laz — that belongs to the format driver, and the arithmetic here does not change with it. Everything comes back as raw LAS point records, little-endian, exactly as an uncompressed .las stores them.

Two decode shapes, because the callers genuinely differ.

Indexed — one chunk at a time, which is what COPC and EPT hand you. Build the decoder once per file; parsing the laszip VLR is the expensive part and it does not change between nodes.

import { initLazCodec, readLasHeader, LazChunkDecoder } from "@voxelkloud/wasm-codecs";

await initLazCodec();

// One ranged GET of the front of the file is enough to find everything.
const header = readLasHeader(await range(url, 0, 4096));
if (!header.vlrsComplete) throw new Error("read further and try again");

const decoder = new LazChunkDecoder(header.findVlr("laszip encoded", 22204)!.data);
for (const node of hierarchy) {
  const records = decoder.decode(await range(url, node.offset, node.byteSize), node.pointCount);
}

Unindexed — a whole file, for the single-file tier and for an EPT node fetched entire. Takes .las as readily as .laz.

import { decodeLazFile } from "@voxelkloud/wasm-codecs";

const decoded = decodeLazFile(new Uint8Array(await file.arrayBuffer()));
decoded.points; // decoded.pointCount * decoded.pointSize bytes

Notes that will bite you otherwise

initLazCodec is process-wide. Everything exported here is a view onto one wasm instance, so there is no way to run two isolated instances in one JS realm. Decode in a worker — which the loader does anyway — and isolation is the worker's. That is also the recovery path if the module ever traps: a wasm panic poisons its instance for good, and replacing the worker is the only way back. Every failure this package anticipates is a thrown Error rather than a trap, including corrupt chunks and truncated files, but a trap is not something a library can catch on your behalf.

Free what you take. LasHeader, Vlr, DecodedLas and LazChunkDecoder own wasm memory that no GC of ours reclaims. Call .free(), or hold them with using.

Selective decoding is a real saving and a sharp edge. decodeSelective(chunk, count, LazField.Z | LazField.RGB) skips the layers you did not ask for, on LAS point formats 6 and up. But an unselected field is not zeroed: its bytes carry the chunk's first point, repeated, because laszip stores that one raw. Treat them as undefined.

There is a ceiling. One call refuses to decode more than 1 GiB. A point count is a number in an untrusted file, and without the ceiling a corrupt header becomes an allocation failure that explains nothing.

Testing

Two suites, and the split is deliberate.

codec.test.ts runs against fixtures/, generated by pnpm fixtures — LAS/LAZ twins across point formats 0, 2, 3, 6, 7, 8 and one with extra bytes, plus a bare variable-size chunk of each in the shape COPC stores per node. Those come out of the same library that decodes them, so they prove the wasm boundary, the framing and the chunk path — not laszip conformance, which would be the same code agreeing with itself.

real-files.test.ts settles conformance against files this repo did not write: the 200 octree nodes PotreeConverter wrote twice under demo/potree, once as .las and once as .laz through LASzip's C++ encoder. Every one of them decodes to the bytes of its uncompressed twin. It also reads a real COPC file's header and hierarchy EVLR and decodes its root node. Those files are gitignored and the suite skips itself when they are absent.

Building from source

Needs cargo, rustup target add wasm32-unknown-unknown, and cargo install wasm-bindgen-cli --version 0.2.127 — the CLI version must match the wasm-bindgen pin in Cargo.toml exactly.

Unlike @voxelkloud/wasm-core, this crate does use wasm-bindgen. Its surface moves megabytes of typed arrays and every entry point can fail on malformed input, which is the case generated glue pays for; the kernels next door are pure f64 functions over fixed offsets, where it would not.

MIT.