SuperAPI AI Directory

rust-wasm-geo

Frontend & websites

View repository

Updated 10-15 21:42

About this skill

Rust / WASM geo

Default stack context: tech-stack skill. This skill covers Rust/WASM geo only.

When to apply

  • Turf or JS geometry is too slow (profile first — main-thread blocking > ~100ms)
  • OSM parsing, map model build, isochrones, spatial indexes, graph routing
  • Thousands of features, repeated geometry ops, or polygon booleans at scale
  • Adding or reviewing a wasm-pack crate, wasm.ts boundary, or Vite WASM plugins

Stay on Turf (JS) for single-feature ops on small GeoJSON and interactive editing feedback during prototyping.

Turf vs Rust/WASM

Stay on Turf (JS) Add Rust/WASM
Single-feature ops on small GeoJSON Thousands of features, repeated ops, or graph routing
Interactive editing feedback OSM parsing, map model build, isochrones, spatial indexes
Prototyping Main-thread blocking > ~100ms (profile first)

Batch geometry on large arrays (not routing/OSM): geoarrow-wasm instead of rolling your own.

Crate selection (quick)

Need Crate
Geometry / GeoJSON geo, geojson
Spatial index rstar
Road routing fast_paths
Graph algorithms petgraph
OSM → graph osm-reader (a-b-street fork)
Snap traces to roads route-snapper-graph
Polygon booleans i_overlay (see a-b-street/utils)
Contours / isolines contour
Serialized map models bincode + serde
Vector file I/O flatgeobuf, geozero

Per-crate usage notes and WASM dependency versions: crates-and-packages.md.

Project structure

One crate per app, named for what it computes (geo-isochrone, route-buffer, …).

app/
├── wasm/
│   └── geo-isochrone/          # Rust crate (wasm-pack output → pkg/)
│       ├── Cargo.toml
│       └── src/
│           ├── lib.rs          # #[wasm_bindgen] surface only
│           └── isochrone.rs    # pure geo logic
└── src/
    └── features/isochrone/
        ├── wasm.ts             # sole JS import of pkg — React never imports pkg directly
        └── useIsochrone.ts     # React hook / Query wrapper
  • lib.rs = #[wasm_bindgen] exports; inner modules = pure geo logic (testable without WASM).
  • JS boundary: wrap exports in wasm.ts. Pass GeoJSON strings or bincode Uint8Array — not hand-built JS objects.
  • State split: durable compute state in Rust; UI state in React (Zustand / URL / local useState).

WASM stack (Cargo)

Crate Role
wasm-bindgen JS ↔ Rust boundary
serde-wasm-bindgen Serialize/deserialize across boundary
wasm-bindgen-futures Async exports
console_error_panic_hook Readable panics in devtools
getrandom with features = ["js"] RNG in browser
web-time Time in WASM

Build: wasm-pack (--target web), vite-plugin-wasm, target wasm32-unknown-unknown.

Reference setups: a-b-street/ltn, a-b-street/15m, a-b-street/utils.

Docs when stuck: wasm-bindgen book, geo on docs.rs.

App integration

App type Guide
Vite SPA (no Start) vite-spa-integration.md
TanStack Start tanstack-start-integration.md

Both: dynamic-import WASM from wasm.ts only; never top-level import of .wasm in shared modules that may load on the server.

Non-negotiable rules

Topic Rule
React imports Components/hooks import wasm.ts only — never pkg/ or raw .wasm
Boundary types GeoJSON as string or bincode Uint8Array; validate with Zod on the JS side after parse
Coordinates WGS84, [lng, lat] at all API boundaries
Server modules No WASM init in *.server.ts, server loaders, or createServerFn handlers
SSR WASM runs client-only; lazy-init after hydration (see Start guide for route ssr)
Turf fallback Keep Turf for small/interactive paths until profiling proves WASM is needed

Related skills

Topic Skill
Map React API, layers, events react-map-gl
Loaders, search params, Query tanstack-router-conventions
Route SSR, Start layout, server tanstack-start-conventions
Client UI state around map tools zustand-state-management
useEffect / map listeners react-dev