Navigation

Usage guide of ai.navigation: layered paths from live collision, the agent, settings and defaults, route and steer, the navigation.plan hook, limits, engines.

Source: module-kits:kits/ai_navigation/usage/en.mdView Markdown source

Also read offline — CLI: grip-forge docs ai-navigationMCP tool: gripforge_docs { "topic": "ai-navigation" }

Navigation and paths (ai.navigation) #

Paths for characters and units, computed from the live collision of your game: layered floors, agent size, slopes, steps, moving blockers. Readable offline: gripforge docs ai-navigation, or the MCP tool gripforge_docs (topic ai-navigation).

What it is for #

This is the path search of the catalogue: a kit or a game never writes another one. It bakes a layered grid from the collision boxes and triangle meshes registered in the physics port, finds a route between two points for an agent of a given size, and keeps a transient path per actor that it hands out waypoint by waypoint. It never moves anyone: the actor's own collision controller applies the motion, and nothing is teleported.

Who uses it:

  • npc.core: NPC goals follow its paths (installing ai.navigation is what turns path following on).
  • character.top_down: click to move (the player is the actor, around walls and through doors). Without the service, or with clickPath set to straight, the path is the straight line.
  • moba.lanes: with pathfinding set to navigation, lanes ask for world.navigation paths; its default stays its map grid, since a bake of a large MOBA map costs seconds per route against milliseconds for the grid.
  • units.command keeps its own flow field on purpose: one search from a goal shared by every unit of a group order.

It requires only game.engine. Visual models do not become colliders: a replacement model must bring its real collision through the physics port.

Turn it on #

gripforge_gamekit_install   { project_id: "gkp_…", id: "ai.navigation" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "ai.navigation",
                              config: { "agent": { "radius": 0.5, "height": 2, "maxSlope": 40, "stepHeight": 0.4 } } }

Only the keys that differ from the defaults need to be written. The full reference is gripforge kit api ai.navigation.

Settings and defaults #

KeyDefaultMeaning
agentradius 0.35, height 1.8, maxSlope 45, stepHeight 0.35the default agent: capsule radius and total height in metres, steepest slope in degrees, highest step
cellSize1grid cell in metres (0.25 to 4); reduce it for narrow passages
padding8metres around the requested endpoints baked with them
groundtrueinclude the world.ground height surface (for analytic-ground controllers); false for collision-only interiors or terrain with holes
approach3a goal inside a body (a parked car) or off the floor ends at the nearest reachable floor within this distance; 0 means exact endpoints
smoothtruestraighten grid steps into straight segments checked like baked edges
retrySeconds0.5an actor whose route is not ready asks again when its goal or the static world changes, otherwise at most this often
maxCells, maxLayers16384, 8bounds of a bake (floors per cell up to 16)
plansPerTick4routes planned per tick
sharedBakeCells16384a world of at most this many cells is baked once for every agent
bakeTile16the baked region is widened to whole tiles of this size; 0 bakes the region as asked
bakeCellsPerTick, bakeBudgetMs1024, 4how steer() spreads heavy work over ticks while the actor waits
runtimeworkerin a browser, where bakes and checks run: worker or sync (URL parameter `navRuntime=syncworker` overrides)
layerOverflowblockRust: a cell with too many floors is made non-navigable (block) or the bake is rejected (reject)

Budgets are not moddable.

The service #

route(from, to, agent?) answers at once with ready and the exact endpoints and waypoints, or unreachable, outside, unavailable, budget_exceeded. steer(actorId, from, to, agent?) keeps a path per actor and returns the next waypoint, or waiting while the bake is made (a click-to-move hero walks straight meanwhile; an actor whose goal moved by 2 m at most keeps its route). forget(actorId) drops a path and invalidate() throws the bakes away (needed after ground samplers were changed from outside). On the web, request(from, to, agent) answers a promise.

Bakes are kept until the static world or the agent changes; a request inside an already baked region of the same agent reuses it. Moving bodies never cause a bake: they are prepared once per revision, and the next swept segment of a followed path is checked before it is used. A blocked segment requests a new route, and a door registered as a physics body (closed, removed or moved) is detected by itself. Terrain edits, scene changes and streamed chunks invalidate the bake. Saves keep NPC goals and the paths being followed, so a loaded game takes the same steps.

Hook and event #

Hook navigation.plan { actor, from, to, radius, height, maxSlope, stepHeight, approach } runs before each plan: a tap may move the goal, change the clearance or the approach; cancelled, the route is unreachable with the reason cancelled: <reason>.

{ "id": "giants_wide", "hook": "navigation.plan", "match": { "actor": "troll" }, "set": { "radius": 1.2, "height": 3.5 } }

Event navigation.blocked { actor, status, reason }: once, when a steered actor gets a route that is not ready. An NPC then stops rather than walk through an obstacle. A mod may set cellSize, padding, ground, approach, smooth, retrySeconds and agent.

What it is not #

A layered sampled grid with cardinal connectivity, not Recast, not a polygon union, not a crowd solver and not a jump or climb planner. Each X/Z cell can hold several supported floors (bridges and interiors do not merge with the ground below). Thin walls and too little headroom are rejected by triangle tests; curved primitives are conservative box blockers, not walkable supports; moving bodies block but are not platforms. A square footprint around the capsule makes narrow passages conservative: reduce cellSize. Holes smaller than the cell need an explicit collision blocker. unreachable means no validated path inside the queried region, not proof that a distant detour does not exist. A bake is bounded by cells, layers and 200000 triangles; an oversized query fails explicitly.

Engines #

EngineSupport
Webthe service, with the worker runtime in a browser
Rust (native player, libgfkits)the same service, hook, event and save, checked against the web by parity fixtures
Godot, Unity, Unrealno navigation service of this kit; the collision data contract could feed other adapters

When it does not do what you expect #

SymptomCause and fix
NPCs do not walk to their goalai.navigation is not installed, or the models have no collision in the physics port
unreachable through a narrow gapcellSize too coarse for the agent; reduce it or reduce agent.radius
The hero walks straight at firstwaiting while the bake is made; that is the design, the route arrives a tick or two later
Paths ignore a changed groundcall invalidate() after changing a ground sampler from outside
A goal inside a parked car failsraise approach, or set it to 0 for exact endpoints and handle the failure
Stairs are not climbedstepHeight is lower than the stair, or the slope is over maxSlope