SPZ Gaussian splats, decoded in the browser faster than libspz.
SPZ is the open compression format Niantic published for 3D Gaussian splats. TurboSPZ is an independent pure-Rust decoder for it, compiled to WebAssembly with SIMD128. It reads every SPZ version libspz reads: v1, v2, v3 and v4, with the legacy gzip framing detected from the magic bytes rather than configured by you.
Turbocharged by Bitruvius TurboSPZ.
Browser decode throughput, turbospz-wasm against Niantic libspz, both compiled to WASM SIMD128, decoding the same file per version.
| SPZ version | Format | turbospz-wasm | libspz | Speedup |
|---|---|---|---|---|
| v2 | gzip (legacy) | 1078 MiB/s | 595 MiB/s | 1.81× faster |
| v3 | gzip (legacy) | 1007 MiB/s | 568 MiB/s | 1.77× faster |
| v4 | zstd (current) | 1078 MiB/s | 847 MiB/s | 1.27× faster |
SH degree 3, scene-averaged over hornedlizard (786K splats) and racoonfamily (933K splats). Higher is faster.
One codebase, one answer. AVX2, NEON, WASM SIMD128 and a scalar fallback all produce byte-identical output. This package ships the WASM SIMD128 path, so a capture decoded in a phone browser matches the same file decoded by the native TurboSPZ tools on a workstation.
Memory-safe by construction. Pure Rust, zero unsafe in the consumer
libraries, and no emscripten anywhere in the build.
import { SpzDecoder } from '@bitruvius/turbo-spz';
const bytes = new Uint8Array(await (await fetch('scene.spz')).arrayBuffer());
const cloud = await new SpzDecoder().decode(bytes);
// cloud.numPoints, cloud.shDegree, then flat Float32Arrays:
// positions (3N), scales (3N), rotations (4N), alphas (N), colors (3N), sh
Reuse one decoder across many files. The wasm is a lazily initialized singleton, so only the first decode on the page pays the init cost.
The arrays arrive as the container stores them, not as your shader wants them. Three conversions stand between decode and a correct render:
scale = Math.exp(logScale); // scales ship as logs
color = 0.5 + 0.28209479177387814 * dc; // SH degree-0 DC to straight colour
alpha = 1 / (1 + Math.exp(-a)); // alphas are opacity logits
Opacity is the one that bites. Get it wrong and the scene renders uniformly near-opaque or near-invisible, with no error to tell you why.
SpzGltfSplatDecoder and WorkerSpzGltfSplatDecoder decode whole 3D Tiles
Gaussian-splat tiles (KHR_gaussian_splatting), which is how Esri and Cesium
splat tilesets stream. The worker variant fans tiles out to a pool so the
entropy decode never blocks your render thread. You rarely wire it up yourself:
a splat layer in @bitruvius/sdk-maplibre uses it by default.
import { Tiles3DSplatLayer } from '@bitruvius/sdk-maplibre';
map.addLayer(new Tiles3DSplatLayer({ id: 'splats', url: tilesetUrl }));
SpzContainerDecoder adapts a standalone .spz file to the SDK's streaming
decoder contract, so a raw capture renders through the same pipeline as any
other Bitruvius container.
npm i @bitruvius/turbo-spz
A self-contained ESM bundle is published on the Bitruvius CDN if you would
rather skip the bundler entirely. In production, pin an exact version, add
integrity= from the release manifest, and allow script-src 'wasm-unsafe-eval'
in your CSP.
This package decodes. It does not encode. There is no encoder in the
package and none inside the .wasm. The decoder is free: anyone who needs to
read SPZ data can pull it and ship it inside their application, under
LICENSE. The TurboSPZ encoder is licensed separately: see
bitruvius.com/turbo-spz for its benchmarks
and licensing terms.
Niantic and SPZ are trademarks of Niantic, Inc. Esri and ArcGIS are trademarks of Environmental Systems Research Institute, Inc. Cesium and 3D Tiles are trademarks of Cesium GS, Inc. Khronos and glTF are trademarks of The Khronos Group 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.
TurboSPZ is an independent implementation of the openly published SPZ format,
developed by Bitruvius and verified against Niantic's libspz reference, which
Niantic releases under the MIT license. It is neither produced nor endorsed by
Niantic, and compatibility claims describe interoperability with the format as
verified by our test suites, not any form of certification.
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.
@bitruvius/turbo-spz — browser SPZ (Niantic gaussian-splat) decode via a pure-Rust
turbospzwasm. Decode-only.Three entry points:
.spzfile (all versions v1–v4) to a flat SpzGaussianCloud..spzfile to the quantized streamingDecodercontract in@bitruvius/geo-core, so BVC-style splat layers render it through the sameSplatRendererpath as any other container..glbgaussian-splat tile (KHR_gaussian_splatting,…_spz_2), satisfying the codec-agnosticGltfSplatDecoderseam in@bitruvius/geo-coreso@bitruvius/tiles3dstreams Esri/Cesium splat tilesets without depending on this package directly.