A map flying Bangkok → Dhaka → Kathmandu → Dubai → Belgrade → Greenwich, labelling every city in its own script — Thai, Bengali, Devanagari, Arabic, Cyrillic, Latin — each label placed, collision-checked and drawn at animation frame rates, inside a browser tab, with no C, no C++ and no Fortran anywhere in the default build.
Today we released OxiGIS 0.1.0 — a QGIS-class GIS application built on the COOLJAPAN Pure Rust ecosystem, shipped as five crates on crates.io. And you do not have to install anything to try it: the browser build is live right now at gis.cooljapan.tech — 11.2 MB of WebAssembly, served as application/wasm, running the same renderer and the same projection math as the desktop binary.
No C. No C++. No Fortran.
deny.toml bans the C/C++ crypto and TLS stacks outright — ring, aws-lc-sys, aws-lc-rs, openssl*, native-tls, security-framework-sys — and admits cc only as a wrapper of wayland-backend, the one Linux windowing case with no pure-Rust equivalent. cargo deny check bans is part of the release gate.
One source tree produces two artifacts: a single native binary for Linux, macOS and Windows, and a single WASM bundle for the browser. Same panels, same renderer, same CRS math.
Why OxiGIS 0.1.0 is a game changer
The incumbent geospatial stack is not wrong. It is unmovable:
- GDAL, PROJ and GEOS are foundational and decades-validated — and they cannot follow you into a browser tab. Web GIS therefore means a server, which means your cadastral, infrastructure, disaster-response or drone imagery leaves the machine before it is drawn.
- “Build it from source” is a weekend, a package manager and a matrix of
-syscrates, on every platform, forever. - The desktop and the web app are two codebases, two renderers, two subtly different answers to the same projection question.
OxiGIS 0.1.0 ends all three of those, and the claim is narrow enough to check:
- A full GIS interface that builds with Cargo alone.
cargo build --workspace. No system GDAL, no PROJ install, no CMake step.#![forbid(unsafe_code)]in all five crates. - The browser build is the product, not a demo. Drop a Shapefile, GeoJSON, GeoTIFF, GeoPackage or PMTiles archive on the map at gis.cooljapan.tech — it is read and rendered in the tab. Nothing is uploaded, there is no account, and there is no server round-trip.
- The whole application is one codebase. ~120,000 lines of Rust across 227 files, five crates, two shells. 2,565 tests passing, 37 skipped, identical in the default and
--all-featuresbuilds — zero clippy warnings, zero compiler warnings. - Japan is covered in full, not approximated. Every one of the 19 Japan Plane Rectangular zones on each of JGD2011 (6669–6687), JGD2000 (2443–2461) and Tokyo Datum (30161–30179), plus the matching UTM and geographic CRSs, with published Bursa-Wolf parameters for the shifted datums.
- The map, the legend, the hit-test and the printed page give the same answer. Categorized and graduated renderers resolve per feature, once, and every consumer reads that one resolution.
Technical Deep Dive: five crates, two shells, one renderer
oxigis-core— the model, and nothing else. Layers, sources, styles, renderers, the.oxigis.jsonproject format and the Processing registry, with no rendering or windowing dependency at all. It models where data lives, not how to parse it. Itscrs::wktreader takes WKT1 and WKT2 and strips everyTOWGS84[…],AUTHORITY[…]andID[…]group before matching a datum name — becauseTOWGS84contains the substringWGS84, and GDAL, ogr2ogr and QGIS emit that clause for every datum that has one. A naive name match loads Tokyo, ED50 and OSGB36 data unshifted, and looks right while being hundreds of metres wrong.oxigis-render— the wgpu tile renderer, deliberately I/O-free. Raster tiles (XYZ templates and Cloud-Optimized GeoTIFF over HTTP Range), vector tiles (MVT: fill / line / circle / symbol), PMTiles archives, a tile pyramid with LRU caching, and Web Mercator math out to zoom 24, with compile-time assertions guarding every constant that depends on that maximum. It owns no executor and opens no socket — its async surface isPin<Box<dyn Future>>fromcore— which is exactly why it compiles identically for native andwasm32-unknown-unknown.- The label engine — the part that is genuinely obsessive. A glyph atlas, greedy collision-avoiding placement, vertical and bidi-aware orientation, and CJK font fallback. A full atlas does not cost a frame its labels: eviction is per glyph, survivors do not move and the generation is not bumped, so labels the frame is mid-draw stay valid; clearing the whole atlas is the last resort. That is what lets the demo tour keep six scripts on screen while the camera moves.
oxigis-ui— the application, testable without a screen. Layer tree, style and renderer editors, attribute table, Processing dialogs generated fromoxigis-core’s registry, and a complete vector editing system (sketch, snapping, topology, selection, hit-testing, attribute forms, clipboard, undo/redo). Editing is a command/transaction model that is tested without egui — 1,565 of the workspace’s tests live here. Print/export produces real PDF with bidi text shaping, font subsetting, a segmented scale bar carrying its representative fraction, a north arrow, a legend and/Infometadata, up to 300 dpi, JPEG- or Flate-encoded whichever is smaller.oxigis-webandoxigis-desktop— two shells over one core. The web shell is wasm-bindgen + WebGPU with automatic WebGL2 fallback,fetch-backed tile and Range transports, drag-and-drop ingestion and#map=<zoom>/<lat>/<lon>permalinks. The desktop shell is winit with native file dialogs, session persistence, background CJK font discovery and a real command line. Everything that touches the DOM orfetch()iscfg-gated totarget_arch = "wasm32", so the shell’s decisions — permalink rounding, in-flight counting,Content-Rangeparsing, tile-drain convergence — are tested on the host without a browser.
Getting Started
The fastest path is no path at all — open gis.cooljapan.tech and drop a file on the map.
For the desktop application:
cargo install oxigis-desktop # installs the `oxigis` binary
oxigis --help
oxigis path/to/project.oxigis.json
As a library, oxigis-core is the platform-independent model — no GPU, no windowing:
cargo add oxigis-core
use oxigis_core::{Layer, LayerKind, Project, RasterSource};
fn main() -> oxigis_core::CoreResult<()> {
let mut project = Project::new("My Map");
let id = project.layers.add(Layer::new(
"OSM",
LayerKind::Raster(RasterSource::xyz(
"https://tile.osm.example/{z}/{x}/{y}.png",
)),
));
project.layers.set_opacity(id, 0.8)?;
let json = project.to_json_string()?;
println!("{json}");
Ok(())
}
Building the browser bundle yourself:
wasm-pack build crates/oxigis-web --target web
./crates/oxigis-web/serve.sh # dev profile, http://localhost:8080
What’s New in 0.1.0
This is the initial release, so everything is new. The headlines:
- Data formats — GeoJSON (dropped, pasted or embedded in a project), ESRI Shapefile, OGC GeoPackage (SQLite-backed), GeoParquet behind the optional
geoparquetfeature; Cloud-Optimized GeoTIFF over HTTP Range, XYZ templates, Mapbox Vector Tiles, and MBTiles/PMTiles archives read paged rather than loaded whole. - Coordinate reference systems — a built-in EPSG registry with complete Japanese coverage plus the common global CRSs, WKT1/WKT2 reading with real Helmert datum shifts, and reprojection at ingest so everything downstream stays in WGS84.
- Rendering — Single / Categorized / Graduated renderers, N-layer tile compositing with per-layer opacity (eight drawn at once; anything beyond that is reported by name rather than silently dropped), and WebGPU with automatic WebGL2 fallback.
- Editing — sketch, snapping, topology, selection, hit-testing, attribute forms, clipboard, and an undo/redo stack that also covers layer visibility, rename and zoom-range changes.
- Output — PDF print/export with print furniture, GeoJSON layer export, CSV attribute-table export.
- Application — asynchronous cancellable Processing tools, geodesic distance/area measurement, on-screen scale bar, go-to-coordinate,
.oxigis.jsonprojects written atomically (temp file then rename, so a crash mid-write leaves the previous save byte-for-byte intact), and GeoLibre project import. - Hardening before the first release, not after — short final strips in striped COGs, the
TOWGS84substring trap, permanently-poisoned tiles after one transport hiccup, glyph-atlas overflow, MVT ring winding from version-1 encoders, and an attribution line crediting no one: all found and fixed by the pre-release audit. None ever shipped; they are listed inCHANGELOG.mdbecause they are the failure modes the code is now tested against.
Tips
- Serve locally on
localhost, not a LAN IP. WebGPU is only exposed in a secure context, and a LAN IP over plain HTTP is not one — the app silently drops to the WebGL2 fallback../crates/oxigis-web/serve.shdoes the right thing;serve.sh 9000changes the port andserve.sh testruns host tests plus awasm32check. - GeoParquet is desktop-only by design.
oxigis-desktopturns onoxigis-ui’sgeoparquetfeature;oxigis-webdeliberately does not, because arrow/parquet are heavy and native-only — which is exactly why the wasm bundle must be built package-scoped (wasm-pack build crates/oxigis-web): a workspace-wide wasm resolve would unify that feature onto the sameoxigis-uithe browser shell links. Using the crate as a library:cargo add oxigis-ui --features geoparquet. - A tiled (MVT) layer will not offer you a classification. Its renderer combo is drawn disabled, with
TILED_RENDERER_REFUSALas the visible reason, because an MVT paint is matched by source-layer name and never sees a feature’s attributes. That is a stated refusal, not a missing feature — widening it is on the roadmap inTODO.md. - Watch the CRS warning in the layer panel. A historic datum’s shift can be meter-accurate only; the panel names each layer’s CRS and says so rather than letting you assume survey precision.
- Complex-script shaping parity is the next frontier, and it is written down. Labels in Thai, Bengali, Devanagari, Arabic, Cyrillic and Latin are discovered, placed and drawn today; full LTR script itemisation across screen and print has to land on both sides together — measured at up to a 35 % width gap if only one side adopts a real script tag — so it is tracked in
TODO.mdrather than half-shipped. - On the desktop,
--log-fileandRUST_LOGare real. So are file-path arguments,--version, and session persistence for window geometry, the recent-project list and the file dialog’s directory.
This is the foundation
OxiGIS is the application layer of the COOLJAPAN geospatial stack, and it is built entirely out of it: OxiGeo 0.2.4 for data I/O and CRS (with OxiProj 0.1.5 resolved underneath oxigeo-proj for the projection math, and oxigeo-geoparquet behind the optional feature), OxiUI (oxiui-table) for the attribute table model, OxiText and OxiFont (oxitext, oxitext-raster, oxifont-subset / -bundled / -discovery) for glyph rasterisation, font discovery and PDF subsetting, and OxiArc (oxiarc-deflate, oxiarc-lzw) for the compressed payloads inside COG, MVT and PMTiles.
Every one of those is Pure Rust, and every one of them is why the browser build exists at all.
Repository: https://github.com/cool-japan/oxigis
Star the repo if you think opening a sensitive layer should not require uploading it to somebody’s server first. The era of “GIS means installing a C++ stack, or handing your data to one” is over — Pure Rust GIS is here, and it runs in the tab you already have open.
— KitaSan at COOLJAPAN OÜ August 18, 2026