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

@bitruvius/tiles3d-points

v0.3.2

Published

Composed off-main-thread decoder for OGC 3D-Tiles point clouds (v1.0 .pnts + v1.1 glTF POINTS): wires @bitruvius/gltf + draco into a worker-pooled CesiumPointDecoder

Readme

@bitruvius/tiles3d-points

The composed OGC 3D Tiles point-cloud decoder: 1.0 .pnts and 1.1 glTF POINTS, uncompressed or Draco, decoded off the main thread.

Internal building block. This package exists so that @bitruvius/sdk-maplibre and the Bitruvius codecs can resolve their dependencies on npm. It has no standalone product story. Unless you are deliberately building against it, install the SDK instead.

What it does

Hand it tile bytes and a georeference context. It sniffs the 4-byte magic and dispatches to the 1.0 .pnts reader, the 1.1 glTF POINTS reader, or the first point-cloud inner of a cmpt composite, decodes Draco geometry where the tile is compressed, rebases the positions into the shared ENU meters frame, and returns a PackedPointTile the renderer uploads as it stands. By default all of that happens in a Web Worker pool.

The public surface is one interface: CesiumPointDecoder from @bitruvius/geo-core. Callers see decode(buffer, ctx), concurrency and dispose(), and never see glTF, Draco or a worker.

Why it is its own package

Three packages meet here, and none of them is allowed to import another. @bitruvius/gltf is a pure bytes-in parser with no wasm, so it takes compression through a seam (Tiles3DPointDecoderSeams). @bitruvius/draco implements that seam and depends only on @bitruvius/geo-core, because I3S needs Draco too and never goes through the glTF parser. @bitruvius/tiles3d, the streaming engine, also depends on @bitruvius/geo-core alone and takes a CesiumPointDecoder by constructor injection. The wiring itself is three lines, and they are the only place the parser and the codec are named together:

import { Tiles3DPointDecoder } from '@bitruvius/gltf';
import { DracoDecoder } from '@bitruvius/draco';

new Tiles3DPointDecoder({ draco: new DracoDecoder() });

Those lines have nowhere to live. Put them in the parser and every uncompressed tileset pays for megabytes of wasm. Put them in the engine and streaming inherits a codec. Put them in the MapLibre layer and a custom renderer cannot reuse them. So the composition is a package, and it is the only one in the chain that depends on both halves.

The worker chunk has to ship from here. Draco point geometry plus packing millions of points into the quantized ENU grid is heavy, and on the main thread it spends the map's frame budget. The pool therefore spawns a published module worker, new Worker(new URL('./point-decode-worker.js', import.meta.url)). That worker entry imports the parser and the codec, so it can only be built and published by the package allowed to depend on both. The chunk is as much the deliverable here as the API is.

Nothing in it knows about a renderer. No MapLibre import, no GPU, no DOM. The MapLibre point-cloud layer calls createPointDecoder() and injects the result, and a renderer of your own with its own tile loop does exactly the same thing.

What is in it

createPointDecoder(opts) builds the default decoder, Draco seam already wired.

import { createPointDecoder } from '@bitruvius/tiles3d-points';

const decoder = createPointDecoder({ poolSize: 4 });
const tile = await decoder.decode(buffer, ctx);

It runs a worker pool by default, sized from navigator.hardwareConcurrency and clamped to 1..4. Pass workers: false for the main-thread path, which is also selected automatically where Web Workers are unavailable, such as SSR and test environments.

WorkerTiles3DPointDecoder is the pool itself, for the control the factory does not expose: explicit Draco wasm bytes or an absolute wasmUrl for cross-origin and CDN hosting, or a custom worker factory. The pool spins up lazily on the first decode, so construction is cheap and side-effect free.

Three behaviors are worth knowing before you build against it.

Transfers are zero-copy in both directions. Tile bytes are transferred into the worker and consumed, so do not reuse the buffer after calling decode. The packed tile transfers back out the same way.

The Draco wasm URL is resolved on the main thread and forwarded per request, because a worker cannot reliably resolve its package's sibling wasm/ asset. Under a cross-origin CDN build the worker source is fetched once with a CORS GET and spawned from a same-origin Blob URL, since new Worker(crossOriginUrl) throws a synchronous SecurityError.

Degradation is reported, not silent. If the pool cannot spawn (a blocked cross-origin worker, or a CSP without worker-src blob:) the decoder memoizes the failure, decodes on the main thread rather than handing the layer an empty scene, and calls onDegraded once. The MapLibre layer wires that to its onError. The memoization matters: WorkerPool spawns eagerly, so without it every tile retries the spawn.

Who should depend on it

If you are putting 3D Tiles point clouds on a MapLibre map, install @bitruvius/sdk-maplibre and let the layer wire this for you. Depend on this package directly only when you are driving @bitruvius/tiles3d's point engine, or your own tile loop, from a renderer of your own and want a decoder that already covers both 3D Tiles versions.

Its dependencies are @bitruvius/geo-core, @bitruvius/gltf and @bitruvius/draco, and nothing else.

Trademarks

Cesium and 3D Tiles are trademarks of Cesium GS, Inc. glTF is a trademark of The Khronos Group Inc. OGC is a trademark of the Open Geospatial Consortium. Google and Draco are trademarks of Google LLC. Esri and I3S are trademarks of Environmental Systems Research Institute, Inc. MapLibre is a trademark of the MapLibre organization. All other marks are the property of their respective owners.

These names are used solely to describe the data formats this software interoperates with. Bitruvius is not affiliated with, sponsored by, or endorsed by any of them, and no such relationship is implied. Implementing a published specification is not a claim of certification: Bitruvius has not undergone OGC compliance testing for any standard.

License

Proprietary. The full terms ship as LICENSE inside this package, and are readable before installing at cdn.bitruvius.com/legal/sdk-license-v1.txt.

© Bitruvius, Inc.