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

wasm-spatial-core

v0.9.0

Published

A high-performance WebAssembly spatial data processing engine for frontend Web3D/GIS applications

Readme

wasm-spatial-core

Generate Cesium 3D Tiles in the browser. Drag in a LAS / GeoTIFF / GLB, get back a streaming tileset.json + pnts / quantized-mesh tiles — no server, no upload, no Cesium ion quota. The data never leaves the user's machine.

CI npm version License: MIT

Tests WASM

🌐 Live Demo · 📦 npm · 📖 API Docs · 📊 Head-to-head vs py3dtiles · 🗺️ Roadmap

🧪 30-second try (drop a .las file, get a Cesium tileset):

<script type="module">
  import init, { parsePointCloudAuto, generateTileset }
    from 'https://esm.run/wasm-spatial-core';
  await init();

  // User drops a LAS file → parse → octree → 3D Tiles.
  // All in the browser. Bytes never touch a server.
  const cloud = parsePointCloudAuto(lasFileBytes);
  const tileset = generateTileset(cloud.positions(), 50000, 10);
  // → { tilesetJson, tiles: Uint8Array[], ... } — feed straight into Cesium.C3DTileset
</script>

Why does this exist?

If you've ever tried to view a customer's LAS scan in Cesium, you've hit one of:

  • Cesium ion wants you to upload their data — GDPR / ITAR / NDA say no.
  • Desktop tools (CloudCompare, Q2C) need install + per-machine license + manual steps.
  • Server-side pipelines (PDAL, untwine) mean infra cost + a backend to maintain.
  • Just-plain-JS parsers choke at 1M+ points (multi-second hangs).

wasm-spatial-core is a Rust → WebAssembly engine that does the whole LAS → octree → 3D Tiles pipeline client-side. The output is byte-compatible with what Cesium.C3DTileset consumes — so you can build a zero-backend, zero-upload Cesium viewer that runs on a static host.

| | Cesium ion (SaaS) | Desktop tools | wasm-spatial-core | |---|---|---|---| | Customer data leaves the browser | ☁️ yes (uploaded) | 💻 no (local) | 💻 no (local) | | Deployable on intranet / air-gap | ❌ | per-machine | ✅ static files | | Per-GB / per-user cost | ✅ yes | license fee | ❌ free (MIT) | | Works inside a web app | ✅ | ❌ | ✅ | | Streams multi-GB scans | partial | n/a | ✅ COPC range fetch |

Not a PROJ / QGIS replacement. CRS coverage is intentionally focused (WGS-84 / Web Mercator / UTM / China offsets). For arbitrary EPSG reprojection, pre-transform with PROJ and feed WGS-84 / ENU.


✨ Capabilities

Core (the killer use case):

  • 🚀 LAS / PLY / OBJ → 3D Tiles (pnts) — octree partition + Draco optional
  • 🏔️ GeoTIFF → Quantized-Mesh Terrain — Cesium CesiumTerrainProvider-compatible (proven by headless test, see W3.6 in ROADMAP_V2.md)
  • 📡 COPC range-fetch streaming — multi-GB scans without loading the whole file

Also in the box (used internally, exposed as public APIs):

  • 🗺️ Coordinate transforms: WGS-84 ↔ GCJ-02 / BD-09 / Web Mercator / UTM (~30–250× faster than JS equivalents — see PERFORMANCE.md)
  • 🧊 Spatial IR + mesh edit: GLB ingest, OBB split, plane clip, QEM decimation
  • ⚡ WebGPU compute kernels (with WASM fallback)
  • 🔒 Zero server, zero upload, zero runtime dependencies

npm install wasm-spatial-core ships a prebuilt 1.2 MB WASM binary — no native deps, no postinstall, works on any static host (GitHub Pages, S3, nginx, even python -m http.server).


🌐 See it work

Live, drag-and-drop, no backend:

| Demo | What it shows | |------|--------------| | Cesium 3D Tiles | Drop a .las / .tif / .glb → octree → 3D Tiles → Cesium globe. The killer demo. | | COPC streaming | Range-fetch a multi-GB .copc scan byte-range by byte-range (no full download). | | Terrain viewer | GeoTIFF → quantized-mesh, with cut / flatten / fill edits. | | Demo hub | All examples + benchmarks. |

Run any of them locally with npm run demo.


🚀 Quick Start: LAS → Cesium in 20 lines

npm install wasm-spatial-core
import init, { parsePointCloudAuto, generateTileset } from 'wasm-spatial-core';
// Cesium loaded separately (CDN or npm) — we only emit the tile bytes.
await init();

// 1. User drops a .las file. Parse it.
const cloud = parsePointCloudAuto(lasFileBytes);
// cloud.positions() → Float32Array [x,y,z, ...]

// 2. Build octree → 3D Tiles (pnts + tileset.json).
const tileset = generateTileset(cloud.positions(), 50000 /* max pts/node */, 10 /* depth */);
// tileset.tilesetJson() → string
// tileset.tile(i)      → Uint8Array (one pnts blob per tile)

// 3. Hand the tiles to Cesium via blob URLs (no server needed).
const json = JSON.parse(tileset.tilesetJson());
for (let i = 0; i < tileset.tileCount; i++) {
  const url = URL.createObjectURL(new Blob([tileset.tile(i)]));
  json.root.content.uri = json.root.content.uri.replace(`tile_${i}.pnts`, url);
  // (in practice, walk the tree and rewrite each leaf's content.uri)
}
const cesiumTileset = await Cesium.C3DTileset.fromUrl(
  URL.createObjectURL(new Blob([JSON.stringify(json)], { type: 'application/json' })),
);
viewer.scene.primitives.add(cesiumTileset);

That's the whole story — no backend, no upload, no ion token. For a working drag-and-drop demo, see the Point Cloud + Cesium example.

npm install draco3d
import { compressTilesetWithDraco } from 'wasm-spatial-core';
import { createEncoderModule } from 'draco3d';

const encoder = await createEncoderModule({});
const compressed = compressTilesetWithDraco(tileset, encoder, { quantizationBits: 11 });
// Typical ratio: ~20% of original size, position-color pairing preserved.

What's in the npm package?

npm install wasm-spatial-core ships a prebuilt WASM binary compiled with point-cloud + geotiff. That gives you:

| Included in npm | Not in npm (custom wasm-pack build) | |-----------------|---------------------------------------| | LAS, PLY, OBJ, PCD parsing | LAZ / COPC (laz-support) | | Octree + 3D Tiles (pnts) | E57 (e57-support) | | GeoTIFF → quantized-mesh terrain | Terrain deformation (terrain-edit) | | Coordinates, GeoJSON, MVT, spatial analysis | Spatial IR + GLB ingest (mesh-ingest) | | | Mesh QEM / clip / OBB split (mesh-edit, needs mesh-ingest) | | | WebGPU compute kernels (webgpu) |

Format counts: 10+ read/write paths in the default npm build (LAS/PLY/OBJ/PCD, GeoJSON, MVT, WKT/WKB, GeoTIFF, GPX, TopoJSON, 3D Tiles/glTF output, …). 15+ when optional format features are enabled (LAZ/COPC, E57, GLB ingest, …).

Runtime checks: supportsLaz(), supportsGeotiff(), lazStatus().

CI runs cargo test --all-features857 tests pass (plus 34 #[ignore]d performance benchmarks) across the full feature matrix. The live count is printed by CI on every run; see the latest rust job log for the current number.


🎯 Core Pipelines

Point Cloud → 3D Tiles

LAS / PLY / OBJ  (npm default)
LAZ / COPC / E57 (optional build features — see table above)
        │
        ▼
  ┌──────────────┐
  │ WASM Parser   │  Browser-side; format set depends on build features
  └──────┬───────┘
         ▼
  ┌──────────────┐
  │ Octree Build  │  8-way spatial partitioning
  └──────┬───────┘
         ▼
  ┌──────────────┐
  │ pnts Encoder  │  3D Tiles Point Cloud binary
  └──────┬───────┘
         ▼
  ┌──────────────┐     ┌──────────────┐
  │ tileset.json  │     │ Draco Compress │  Optional (~20% ratio)
  └──────┬───────┘     └──────┬───────┘
         │                      │
         ▼                      ▼
  Cesium / Three.js — interactive 3D

GeoTIFF → Terrain Tiles

GeoTIFF (.tif)
        │
        ▼
  ┌──────────────┐
  │ WASM Parser   │  Float32/16/8, strip/tile, DEFLATE
  └──────┬───────┘
         ▼
  ┌──────────────┐
  │ Quantized-Mesh │  Cesium terrain binary format
  └──────┬───────┘
         ▼
  ┌──────────────┐
  │ tileset.json   │  LOD pyramid (zoom 0..N)
  └───────────────┘

⚡ Performance

The whole reason this exists: do in-browser what previously needed a server. On Apple M2, single-thread WASM (no WebGPU):

| Dataset | Points | Parse | Octree + Tileset | Total | |---------|--------|-------|------------------|-------| | sample.las | 1K | — | < 1 ms | — | | Synthetic | 500K | 36 ms | 166 ms | 205 ms | | Synthetic | 10M | 1.1 s | 3.6 s | 4.8 s | | Synthetic | 100M | 0.4 s | 6.8 s | 8.5 s |

100M-point number is native release (Rust); WASM is ~1.5× slower but still well under 30 seconds. Compare: potree (JS) takes ~3 s just for octree at 1M.

Coordinate conversion (the same engine, different workload):

| Operation | Pure JS | WASM | Speedup | |-----------|---------|------|---------| | WGS84 → GCJ-02 | ~1,200 ms | ~45 ms | ~27× | | WGS84 → Mercator | ~800 ms | ~12 ms | ~67× |

See PERFORMANCE.md for full methodology + comparison with potree / three.js Octree / las-js.


📦 Format Support

Point Cloud

| Format | Read | Feature Flag | |--------|------|-------------| | LAS (1.2–1.4, Format 0–6) | ✅ | point-cloud | | LAZ (compressed) | ✅ | laz-support | | COPC (Cloud Optimized) | ✅ | laz-support | | PLY (ASCII + binary) | ✅ | point-cloud | | OBJ | ✅ | point-cloud | | PCD (ASCII + binary) | ✅ | point-cloud | | E57 | ✅ | e57-support |

Vector & Geometry

| Format | Read | Write | |--------|------|-------| | GeoJSON | ✅ | ✅ | | MVT (Vector Tiles) | ✅ | ✅ | | WKT / WKB | ✅ | ✅ | | GeoTIFF (Terrain) | ✅ | — | | glTF 2.0 / GLB | — | ✅ | | 3D Tiles (pnts) | — | ✅ | | 3D Tiles (b3dm) | — | ✅ | | 3D Tiles (quantized-mesh) | — | ✅ |

Coordinate Systems

| System | Direction | |--------|-----------| | WGS-84 ↔ GCJ-02 / BD-09 | ✅ | | WGS-84 ↔ Web Mercator (EPSG:3857) | ✅ | | WGS-84 ↔ CGCS2000 | ✅ | | WGS-84 ↔ UTM | ✅ |

Spatial Analysis

R-Tree / Octree indexing, bounding box / KNN queries, haversine / vincenty distance, polygon boolean ops, Douglas-Peucker simplification, convex / concave hull, DBSCAN / grid clustering, TIN interpolation, and more.


📖 API Reference

Point Cloud → 3D Tiles

import { loadSpatialCore } from 'wasm-spatial-core';
const wasm = await loadSpatialCore();

// Auto-detect format
const cloud = wasm.parsePointCloudAuto(bytes);
console.log(cloud.count());        // point count
console.log(cloud.positions());    // Float32Array [x,y,z,...]
console.log(cloud.colors());       // Uint8Array [r,g,b,...] | null

// Octree
const octree = wasm.buildOctree(cloud.positions(), 50000, 10);
console.log(octree.nodeCount());   // node count
console.log(octree.depth());       // tree depth

// 3D Tiles tileset
const tileset = wasm.generateTileset(cloud.positions(), 50000, 10);
console.log(tileset.tileCount());  // tile count
console.log(tileset.tilesetJson()); // tileset.json string

Draco Compression

import { compressTilesetWithDraco, buildDracoTileset } from 'wasm-spatial-core';
import { createEncoderModule } from 'draco3d';

const encoderModule = await createEncoderModule({});

// Compress all tiles
const results = compressTilesetWithDraco(tileset, encoderModule, {
  quantizationBits: 11,   // 8–18, default 11
  encodeSpeed: 5,         // 0–10, default 5
  decodeSpeed: 5,         // 0–10, default 5
  compressColors: false,  // also compress RGB (default false)
});

// Or build a complete compressed tileset
const { tiles, totalCompressedSize, compressionRatio } =
  buildDracoTileset(tileset, encoderModule);

Coordinate Conversion

const coords = new Float64Array([116.404, 39.915, 121.474, 31.230]);
const gcj02 = wasm.batchWgs84ToGcj02(coords);       // batch transform
wasm.batchWgs84ToGcj02InPlace(mutable);             // zero-copy in-place
const [zone, easting, northing] = wasm.wgs84ToUtm(116.404, 39.915);

GeoJSON

// Chunked output: parses the full JSON first, then emits coordinate batches
// (progress callbacks + lower peak coord memory — not byte-stream input).
wasm.parseGeoJsonStream(hugeGeojson, 500, (chunk, processed, total) => { /* ... */ });

// Lower memory per iteration: one feature at a time (input string still required)
const iter = wasm.parseGeoJsonLazy(hugeGeojson);

📖 Full API Docs


🛠️ Build from Source

git clone https://github.com/reed-soul/wasm-spatial-core.git
cd wasm-spatial-core

# Point cloud + GeoTIFF
wasm-pack build --target web --release --out-dir pkg -- --features point-cloud,geotiff

# Run demos
npm run demo

Feature Flags

| Feature | In npm | Default crate | Description | |---------|--------|---------------|-------------| | single-thread | ✅ | ✅ | Zero-config, works everywhere | | point-cloud | ✅ | ❌ | LAS/PLY/OBJ/PCD + octree + 3D Tiles | | geotiff | ✅ | ❌ | GeoTIFF terrain + quantized-mesh | | multi-thread | ❌ | ❌ | Web Workers + SharedArrayBuffer | | laz-support | ❌ | ❌ | LAZ/COPC decompression (+ ~400 KB WASM) | | e57-support | ❌ | ❌ | E57 format | | terrain-edit | ❌ | ❌ | Heightfield flatten/deform (requires geotiff) | | mesh-ingest | ❌ | ❌ | Spatial IR + GLB ingest (Wave 2) | | mesh-edit | ❌ | ❌ | Mesh QEM / OBB split (requires mesh-ingest) | | draco-support | ❌ | ❌ | Draco compression API (JS-side via draco3d) |


📋 Roadmap

| Doc | Scope | |-----|-------| | VISION.md | Product vision — Web3D spatial compute engine (core only) | | ROADMAP_V2.md | Active plan — Waves 1–5 (runtime, IR, terrain, GPU, mesh edit) | | docs/ENGINE_BOUNDARY.md | What is in the engine vs your application | | ROADMAP_V1.md | ✅ Completed — point cloud → 3D Tiles browser pipeline |

V1 highlights (done): LAS → octree → 3D Tiles (npm) · LAZ/COPC/E57 (optional builds) · GeoTIFF terrain · Draco · multi-thread WASM · Node.js batch API

V2 next: spatial IR · terrain/mesh edit (source available; not in default npm) · WebGPU · incremental tiles — see issue templates (start at W2)


🤝 Contributing

See CONTRIBUTING.md.


📄 License

MIT License — © 2026 Zhiqi Weilai


Built with 🦀 Rust + 🕸️ WebAssembly

Native spatial computing in every browser.