npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@driftengine/nav

v4.13.4

Published

A navigation mesh: geometry to walkable convex polygons, and a straight line across them

Readme

@driftengine/nav

A navigation mesh: geometry in, convex walkable polygons out, and a straight line across them.

9,052 bytes gzipped, measured by scripts/size-gate.test.mjs against scripts/fixtures/size/nav-only.ts. Optional — nothing in @driftengine/core imports it, so a game that does not path pays nothing.

Why this exists when NavGraph already does

core/src/nav/navGraph.ts says in its own header that it is a graph rather than a mesh, that this is a decision rather than a first step, and that "if a world's walkable space genuinely is a region, this is the wrong structure and a mesh is the row that is still open." A streamed open world is that world. The module named its own trigger; this pulls it.

The graph is not replaced. It stays right for the case it was built for — roads, corridors, rails, docking lanes — which is what consumers kept arriving with, and a mesh would have asked them to throw that away. Two structures for two shapes of world, and one search: NavMeshQuery builds a NavGraph over polygons and hands it to core's NavSearch, so there is exactly one A* in this repository.

The pipeline

| Step | What it produces | | ------------------ | ------------------------------------------------------------------------------ | | voxeliseWalkable | Where an agent of a given size could stand, as spans in grid columns | | buildRegions | Watershed partitioning, so a corridor splits two rooms instead of joining them | | buildContours | One closed boundary per region, simplified and checked for self-intersection | | buildPolyMesh | Convex polygons that tile the region and border each other both ways | | NavMeshQuery | A* over the polygons, then a funnel — so open ground is one straight line |

const field = voxeliseWalkable(geometry, {
  cellSize: 0.3,
  cellHeight: 0.2,
  maxSlope: 45,
  agentHeight: 2,
  agentRadius: 0.5,
  maxStep: 1,
});
const regions = buildRegions(field, { minRegionSpans: 8, maxStep: 1 });
const mesh = buildPolyMesh(buildContours(field, regions, 1.3), 6, field);

const query = new NavMeshQuery(mesh);
const path = new Float64Array(256);
const count = query.findPath(from.x, from.z, to.x, to.z, 2, path);

findPath returns 0 for no route, which is an answer rather than an error: a world with a gap in it has two components, and an agent that asks for the other side has to be told.

What it does not do

  • Steering. §6.5 of the design reverses the refusal of a navigation mesh, which is a function from geometry to a graph. What an agent does with a path stays a game's decision, and ai/src/entities/context.ts's refusal is upheld on exactly that line.
  • A closed box's inside. A column inside a box meets the floor, the box's bottom and its top, and nothing there says the space between is solid short of trusting every mesh's winding. So the floor a closed box encloses stays walkable: an island inside the box's walls that no route from outside reaches, but nearestPoly can still snap a point beside the box onto it. A test pins it.
  • More than one layer of polygons. The voxel field keeps both floors under a bridge, and the regions keep them apart, but a contour follows the lowest walkable span in each column, so where two floors overlap only the lower one becomes polygons.

Walls, pillars and the shortest way round

  • A wall is a solid. A face too steep to stand on is clipped to every cell it crosses and stands in that column as a solid, so a building on the ground blocks, and so does a wall with no thickness and no top. Erosion judges a neighbour at the span's own height, so the agent keeps its radius from a wall even when the wall's top is walkable, and from a ledge higher than maxStep. Give the voxeliser the same maxStep as buildRegions: the polygons are flat, so two edges that touch are a portal whatever their heights, and erosion is what keeps a floor and a ledge apart.
  • A shared border is one line. A room the watershed splits is several regions, and a portal is where two polygons' edges overlap. The points where a border changes what it faces are held in every outline through them, and each stretch between is simplified the same way from both sides, so the regions meet edge to edge at any deviation.
  • A pillar is a hole. A region's inner loops are bridged into its outline, so a path goes round a free-standing pillar and no polygon claims the ground under it.
  • A path is the shortest way round. The search runs over portals, the overlaps between neighbouring polygons' edges, so the corridor it hands the funnel holds the shortest path: 9.81 on the wall in query.test.ts, where a search over polygon centres gives 10.75.