# Navigation Authoring

Blacksite navigation v1 uses authored bounds, obstacles, areas, links, and validation samples to
produce a deterministic Rerecast bake artifact. The scene crate owns one height-aware Polyanya
query core; editor preview, project validation, and `game::navigation::NavigationRuntime` use that
same implementation.

## Authoring

Use **Scene > Navigation** or the path icon in the existing viewport toolbar to create navigation actors:

- **Navigation Bounds** defines an axis-aligned bake region, agent profile, generated artifact path,
  optional debounced auto-bake, and named start/end validation samples.
- **Navigation Obstacle** carves a blocked volume from overlapping bounds.
- **Navigation Area** records a named walkable/blocked volume and traversal cost. V1 applies blocked
  areas during bake and retains walkable cost metadata for a future per-polygon cost callback.
- **Navigation Link** connects otherwise isolated regions. Endpoints are local to the actor;
  direction, enabled state, and traversal cost are authored.

V1 source geometry includes primitives and additive brushes. Imported static-mesh manifests do not
yet contain normalized collision triangles, so imported objects require authored navigation
obstacles until that artifact contract is extended. Bounds never synthesize a walkable floor:
at least one overlapping primitive or additive brush must provide real source triangles, so gaps,
voids, and separated platforms remain non-navigable unless explicitly linked.

Each navigation actor must own exactly one navigation component. Inspector changes are undoable and
save-time validation rejects invalid extents, profiles, area IDs/costs, and link endpoints. New and
duplicated bounds receive an actor-ID-derived artifact path; headless bake and project validation
reject legacy or manually edited paths claimed by more than one bounds actor before any file is
written.

The authoritative bake resolver starts from the active scene's authored snapshot, expands visible
composed subscenes, and expands linked prefab sources recursively. Contributor IDs include their
subscene/prefab chain so repeated source actors remain unambiguous. Prefab transform, primitive,
brush, navigation-component, and nested-instance overrides use their serialized values. Independent
property paths on one component merge with the same reflected semantics as runtime hydration, while
every override must still match the source component base it was authored against. Drifted property
layers and structural overrides are blocked with a rebase/apply/unpack repair action because
silently guessing would produce a different mesh from the hydrated editor world. Prefabs may
contribute geometry, obstacles, areas, and links, but Navigation Bounds remain owned by level
scenes.

## Bake And Preview

Select a bounds actor and click **Bake** in its Inspector, use **Scene > Navigation > Bake Selected
Bounds**, or click the toolbar path icon. The generated artifact must remain under
`assets/navigation/generated/`. Its fingerprint includes the source scene, bounds, agent settings,
overlapping primitive/additive-brush triangles, obstacles, areas, and links. Distant authoring is
excluded so independent bounds do not invalidate one another. Relevant edits immediately mark it
stale; auto-bake waits 0.75 seconds after the latest change before rebuilding. A failed auto-bake
reports once and waits for another authored change before retrying.

The viewport overlay draws authored volumes, baked polygon edges, link endpoints, and the current
path test. Bounds, obstacles, and areas are shown as the same scaled, rotated world-axis-aligned
volumes consumed by the bake, so the overlay remains truthful for transformed or parented actors.
Set **Path start** and **Path end** on the bounds card and choose **Test Path**. Green/red endpoint
markers and an amber route show the exact result returned by the game runtime API. The editor also
tracks the selected artifact path on disk: external deletion, replacement, or rebaking invalidates
the previous preview and reloads the new artifact before another path query can run.

Choose **Pin Current Path** to store the current local-space endpoints as a named validation sample.
Samples can be enabled, edited, loaded back into the preview, or removed from the same bounds card.
Enabled samples are embedded in the artifact and must resolve through the shared multi-link runtime
query during project validation.

## Headless And Runtime

Bake one scene or every scene under `assets/levels/`:

```bash
cargo bake-navigation --project . --scene assets/levels/navigation_authoring_showcase.scn.ron
cargo bake-navigation --project .
cargo bake-navigation --project . --check
```

`--check` never writes. It fails when an artifact is missing, malformed, stale, generated by a
different exact navigation toolchain, or differs from a fresh deterministic bake, making it
suitable for CI. Bake requests are rejected before allocation when their voxel grid exceeds the
production budget (8,192 cells per X/Z axis and 4,194,304 XZ cells total). `cargo validate-levels`
applies the same composed-scene/prefab resolver, validates link proximity and enabled samples,
reports effective disconnected components after valid links, and adds current navigation artifacts
to package dependencies. Artifacts use schema 2, an exact Rerecast/Polyanya/glam generator ID, and a
self-verifying payload hash; incompatible or parseable-tampered artifacts must be rebaked.

Gameplay loads and queries an artifact without editor dependencies:

```rust
let navigation = game::navigation::NavigationRuntime::load(path)?;
let path = navigation.query(start, destination)?;
```

The returned path contains height-resolved world-space points, 3D total length, and the ordered
stable actor IDs of every off-mesh link used by the route. Routes may traverse multiple directed or
bidirectional links across disconnected islands.

The game binary also exposes a renderer-free artifact check for build or deployment tooling:

```bash
cargo run -p game -- --validate-navigation assets/navigation/generated/example.nav.ron
```

It validates link placement and every enabled embedded sample, then exits nonzero with the named
failure instead of opening a window.

See [ADR 0032](../adr/0032-versioned-navigation-bake-and-runtime-query.md) for dependency and
ownership decisions and [the implementation plan](../../.cursor/plans/navigation_authoring_2026-07-11.plan.md)
for acceptance gates.
