Bevytiles is a 3D geospatial engine 🌎 for Bevy. Designed to stream and render the real world in real time. It lets you visualize any location on Earth directly inside your Bevy games and applications.
Built for indie developers and professionals alike, Bevytiles is a perfect fit for UAV simulations, flight-planning software, lightweight GIS analysis, presentations, digital sand tables, and any other geospatial visualization.
It provides precise, ground-truth altitude data, essential for accurate collision detection and spawning mechanics in games, as well as for topographical analysis in GIS workflows.
Originally developed to power a flight simulator, Bevytiles was extracted into a lightweight, standalone library so it can be embedded seamlessly into any Bevy project.
Screen.Recording.2026-08-21.at.11.18.46.mov
cargo run --example demoFlies over the Grand Canyon. A/D roll, Q/E yaw, W/S pitch, +/- throttle, R reset after crashing
into the terrain. Tiles cache under .cache/; the first run downloads them (Esri imagery serves
JPEG despite the endpoint name — decoding handles both).
rustup target add wasm32-unknown-unknown
cargo install wasm-server-runner
cargo run --example demo --target wasm32-unknown-unknown # dev loop, opens on :1334
./web/build.sh # static bundle → web/distOn wasm32 the tile source uses browser fetch on Bevy's task pool instead of threads, and keeps
native-zoom heightmaps in memory instead of a disk cache. Details and caveats in
web/README.md.
use bevy::prelude::*;
use bevytiles::prelude::*;
App::new()
.add_plugins(DefaultPlugins)
.insert_resource(WorldConfig::from_lat_lon(46.206889, 9.497194)) // the Dolomites
.add_plugins(TerrainPlugin)
.add_systems(Startup, | mut c: Commands, w: Res<WorldConfig>| {
c.spawn((Camera3d::default(), TerrainCamera,
Transform::from_translation(w.initial_position(5000.0))));
})
.run();Configuration mirrors raytiles: WorldConfig, StreamingConfig, RenderingConfig (runtime
mutable — the plugin syncs materials), NetworkConfig. world.max_zoom defaults to 15; raising
it (≤ 22) opts into heightmaps synthesized from the native-zoom ancestors and flat default
normals. Large worlds use the raytiles rebase convention via the TerrainAnchor resource
(absolute = user − world_offset); see the demo's rebase_large_world.
| module | role |
|---|---|
lod |
pure desired-set policy (snapshot-tested — values match the C++ engine exactly) |
source |
tile fetching: native = worker threads + HTTP + disk cache; wasm = fetch futures + memory cache; decode + synthesis, whole-tile payload channel |
store |
ECS systems: reconcile / promote / update_desired / status; one entity per tile |
material + assets/shaders/terrain.wgsl |
displacement, lighting, fog |
synth |
Terrarium float decode / quadrant upsample / carry-safe encode |
height |
uint16 height grids + bilinear ground_height |
| bevytiles | bevy |
|---|---|
| 0.1 | 0.19 |
- Data: imagery © Esri; elevation/normals from the Mapzen/AWS terrain tiles. Mind their terms.
cargo testruns the full suite (lod snapshots, synthesis math, source integration against seeded caches — all offline).
- Apache License, Version 2.0 (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or https://opensource.org/licenses/MIT)