# bevy_a5

[![Crates.io](https://img.shields.io/crates/v/bevy_a5.svg)](https://crates.io/crates/bevy_a5)
[![Documentation](https://docs.rs/bevy_a5/badge.svg)](https://docs.rs/bevy_a5)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

A Bevy plugin that puts the [A5](https://github.com/felixpalmer/a5)
pentagonal cell hierarchy under your game world. `bevy_a5` is to spherical
games what [`big_space`](https://docs.rs/big_space) is to deep-space games:
the same floating-origin precision pattern, but the cell space is the
surface of a planet instead of an integer Cartesian grid.

## What you get

- **Cell-anchored coordinates.** Every entity is `(GeoCell, Transform)` —
  *which* A5 cell, plus a small offset within that cell. Float precision
  stays tight even when the underlying world position is on the other side
  of the planet.
- **Floating-origin recentre.** Walk past `recenter_threshold` and the
  plugin shifts the origin to a neighbouring cell, rebasing both
  translation and rotation so the world-space pose is unchanged.
  Recentres are visually invisible.
- **A5 spatial queries.** `grid_disk`, `vertex_neighbors`, `spherical_cap`,
  `compact`/`uncompact` — none of which a Cartesian grid can give you on a
  sphere. All return uniform-resolution cell sets by design (tested
  invariant).
- **Cell → entity index.** `CellEntityIndex` maintained by an observer-style
  system on `Changed<GeoCell>`; `O(1)` "what entities are in cell X?"
  lookup, `SmallVec`-backed buckets to avoid heap-allocation churn.
- **Display helpers.** `build_grid_line_mesh(cells, radius) -> Mesh` for
  one-call wireframe grids; `DrawCellOutline` marker for ad-hoc per-entity
  cell debugging via gizmos.
- **Reusable fly camera.** `FlyCam` component + `CameraPlugin` lifted from
  the duplicated example boilerplate, ready to drop on a `Camera3d`.

## Install

```toml
[dependencies]
bevy = "0.18"
bevy_a5 = "0.1"
```

Bevy 0.18 is the supported version.

## Quick start

```rust
use bevy::prelude::*;
use bevy_a5::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(BevyA5Plugins)               // core + camera + cell hash
        .insert_resource(PlanetSettings::earth())
        .add_systems(Startup, setup)
        .run();
}

fn setup(mut commands: Commands) {
    // Spawn the floating-origin camera at Paris.
    let here = GeoCell::from_lon_lat(2.3522, 48.8566, 9).unwrap();
    commands.spawn_floating_origin(here).insert((
        Camera3d::default(),
        FlyCam::default(),
        Transform::from_xyz(0.0, 5.0, 0.0).looking_at(Vec3::ZERO, Vec3::Y),
    ));

    // Place an entity at a neighbouring cell's centre.
    let neighbour = GeoCell::from_lon_lat(2.3525, 48.8570, 9).unwrap();
    commands.spawn_cell_anchor(neighbour);
}
```

For the full API tour — cell-local frame conventions, recentre semantics,
visualisation helpers, distance / bearing math, the spatial-index pattern —
see [`GUIDE.md`](GUIDE.md).

## Examples

```bash
cargo run --example planet_grid    # Whole-planet wireframe, fly camera
cargo run --example overhead_map   # Top-down map of Paris with slippy tiles
cargo run --example flock          # Spatial-query demo: brownian flock + neighbour highlighting
cargo run --example cell_origin    # Live cell / heading / position HUD on the planet grid
```

`overhead_map` and `flock` cache OSM tiles under `assets/tiles/`. The first
run needs network; subsequent runs hit the cache.

## When to use it (and when not to)

`bevy_a5` makes sense if your game world is **the surface of a sphere**
(Earth, a moon, a fictional planet) and you need consistent positioning at
metre precision across the whole surface, with topologically correct
neighbour lookups (no pole singularity, no longitude-180 seam).

If your world is **flat**, use `big_space` (Cartesian high-precision) or
just plain Bevy `Transform`s — they're faster and simpler. The
[`benches/spatial_index.rs`](benches/spatial_index.rs) bench quantifies
the cost difference: on flat ground, a `(i32, i32)`-tile index is ~30–100×
faster than the A5 equivalent. You're paying for spherical correctness;
don't pay for it on a plane.

## Status

`0.1.0` — pre-release. The public API is stable enough to build against,
but expect breakage at minor versions until 1.0:

- [x] Floating-origin recentre (big-space style — origin always renders at world `(0, 0, 0)`)
- [x] Vertex-aligned cell-local frame (`-Z` toward first boundary vertex)
- [x] Spatial queries with uniform-resolution invariant
- [x] `CellEntityIndex` spatial hash
- [x] `CellTracker` temporal-coherence helper for user-driven movement
- [x] Reusable `FlyCam`
- [x] Adaptive slippy-tile zoom in the `overhead_map` example
- [x] `criterion` benchmark vs Bevy's observers-style cartesian index
- [ ] Multi-planet support (one `Planet` per root entity — currently single global `PlanetSettings`)
- [ ] Multi-`FloatingOrigin` (split-screen / networked players)
- [ ] Observer-based `CellEntityIndex` maintenance for instant reactivity


## License

MIT — see [`LICENSE`](LICENSE).
