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

@auki/pathfinding

v0.3.1

Published

Hybrid pathfinding library combining navigation graphs with Recast/Detour NavMeshes

Readme

Auki Pathfinding

A hybrid pathfinding library that combines traditional navigation graphs with Recast/Detour NavMeshes for efficient pathfinding in complex 3D environments. Supports traversing across multiple coordinate systems.

Features

  • Hybrid Pathfinding: Combines graph-based pathfinding with NavMesh pathfinding
  • Multi-floor Support: Navigate across multiple floors with inter-floor links

Installation

npm install @auki/pathfinding

Basic Usage

import { Pathfinder, FloorData, NavMap, NavmeshGeometry } from '@auki/pathfinding';

// Create a pathfinder instance
const pathfinder = new Pathfinder({
  maxOffGraphDistance: 10 // Maximum distance to find nearest point
});

// Initialize Recast (required before loading)
await pathfinder.initializeRecast();

// Define your navigation map
const navMap: NavMap = {
  points: {
    p1: { x: 0, y: 0, z: 0 },
    p2: { x: 10, y: 0, z: 0 },
    p3: { x: 5, y: 0, z: 5 }
  },
  edges: {
    e1: { from: "p1", to: "p2" },
    e2: { from: "p2", to: "p3", weightMultiplier: 2.0 }, // 2x weight
    e3: { from: "p3", to: "p1" }
  },
  areas: {
    area1: { edges: ["e1", "e2", "e3"] } // Areas are defined by edges
  }
};

// Create legacy NavMesh geometry (optional)
// This represents a ground plane mesh for the floor
const legacyNavmesh: NavmeshGeometry[] = [
  {
    // A simple 20x20 ground plane at y=0
    positions: [
      // Triangle 1
      -10, 0, -10,  // vertex 0
      10, 0, -10,   // vertex 1
      10, 0, 10,    // vertex 2
      // Triangle 2
      -10, 0, -10,  // vertex 3
      10, 0, 10,    // vertex 4
      -10, 0, 10,   // vertex 5
    ],
    indices: [0, 1, 2, 3, 4, 5]
  }
];

// Create floor data
const floorData = new FloorData(navMap, legacyNavmesh);

// Load the floor
pathfinder.load(floorData);

// Find a path
const start = { x: 0, y: 0, z: 0 };
const end = { x: 10, y: 0, z: 10 };
const path = pathfinder.findPath(start, end);

if (path) {
  console.log(`Found path with ${path.length} waypoints`);
  path.forEach((point) => {
    console.log(`Point: (${point.point.x}, ${point.point.y}, ${point.point.z}) on floor ${point.floorId}`);
  });
}

API Reference

Pathfinder Class

Constructor

new Pathfinder(config?: NavOptions)

Configuration Options

interface NavOptions {
  maxDistance?: number;           // Maximum pathfinding distance
  maxOffGraphDistance?: number;  // Maximum distance to find nearest point
}

Core Methods

  • initializeRecast(): Promise<void> - Initialize Recast navigation (required before loading)
  • load(floorData: FloorData): void - Load single floor navigation data
  • loadMultifloor(data: { data: Record<string, FloorData>, links: InterFloorLink[] }): void - Load multi-floor navigation data
  • findPath(from: V3, to: V3, fromFloorId: string, toFloorId: string): PathPoint[] | null - Find path between two points on specified floors
  • setConfig(config: NavOptions): void - Update configuration

Properties

  • loaded: boolean - Whether the pathfinder is ready

FloorData Class

  • constructor(graph: NavMap, navmeshGeometry: NavmeshGeometry[]) - Create floor data from navigation map and legacy NavMesh geometry
  • getGraphPoint(pointId: string): Point | null - Get point by ID
  • getGraphEdge(edgeId: string): Edge | null - Get edge by ID
  • getPoints(): Readonly<Record<string, Point>> - Get all points
  • graph: ReadOnlyNavMap - Access the navigation graph
  • adjacencies: ReadonlyMap<string, string[]> - Graph adjacency list
  • edgeWeights: ReadonlyMap<string, EdgeWeightInfo[]> - Edge weight information

Data Types

NavMap

interface NavMap {
  points: Record<string, Point>;
  edges: Record<string, Edge>;
  areas: Record<string, Area>;
}

Edge

interface Edge {
  from: string;
  to: string;
  dir?: EdgeDirection;        // 1, 0, -1, or undefined
  weightMultiplier?: number;  // Optional weight multiplier (default: 1.0)
}

Point / V3

type Point = V3;
type V3 = {
  x: number;
  y: number;
  z: number;
};

Area

interface Area {
  edges: string[]; // Array of edge IDs that form the area boundary
}

PathPoint

type PathPoint = {
  point: V3;
  fromPointId: string;
  toPointId: string;
  floorId: string;
  toFloorId?: string; // Present when crossing floors
  floorLink?: InterFloorLink; // Present when using inter-floor link
};

NavmeshGeometry

type NavmeshGeometry = {
  positions: number[]; // Flat array of x, y, z coordinates
  indices: number[];  // Triangle indices
};

Examples

Weight Multipliers

Use weight multipliers to discourage certain paths:

const edges = {
  e1: { from: "p1", to: "p2" },                    // Normal weight
  e2: { from: "p2", to: "p3", weightMultiplier: 5.0 }, // 5x weight (avoided)
  e3: { from: "p1", to: "p3" }                    // Normal weight
};

Area-based Pathfinding

Define areas using edges for complex pathfinding:

const areas = {
  room1: { edges: ["e1", "e2", "e3", "e4"] }, // Edges forming room1 boundary
  room2: { edges: ["e5", "e6", "e7", "e8"] }  // Edges forming room2 boundary
};

Multi-floor Pathfinding

Navigate across multiple floors with inter-floor links:

// Define navigation map for floor 1
const navMap1: NavMap = {
  points: {
    p1: { x: 0, y: 0, z: 0 },
    p2: { x: 10, y: 0, z: 0 },
    p3: { x: 5, y: 0, z: 5 },
    stairs1: { x: 0, y: 0, z: 10 } // Stairs connection point
  },
  edges: {
    e1: { from: "p1", to: "p2" },
    e2: { from: "p2", to: "p3" },
    e3: { from: "p3", to: "p1" },
    e4: { from: "p1", to: "stairs1" }
  },
  areas: {
    room1: { edges: ["e1", "e2", "e3"] }
  }
};

// Define navigation map for floor 2
const navMap2: NavMap = {
  points: {
    p4: { x: 0, y: 10, z: 0 },
    p5: { x: 10, y: 10, z: 0 },
    p6: { x: 5, y: 10, z: 5 },
    stairs2: { x: 0, y: 10, z: 10 } // Stairs connection point
  },
  edges: {
    e5: { from: "p4", to: "p5" },
    e6: { from: "p5", to: "p6" },
    e7: { from: "p6", to: "p4" },
    e8: { from: "p4", to: "stairs2" }
  },
  areas: {
    room2: { edges: ["e5", "e6", "e7"] }
  }
};

// Create legacy NavMesh geometry for floor 1 (ground plane at y=0)
const legacyNavmesh1: NavmeshGeometry[] = [
  {
    positions: [
      -10, 0, -10,  10, 0, -10,  10, 0, 10,  // Triangle 1
      -10, 0, -10,  10, 0, 10,   -10, 0, 10,  // Triangle 2
    ],
    indices: [0, 1, 2, 3, 4, 5]
  }
];

// Create legacy NavMesh geometry for floor 2 (ground plane at y=10)
const legacyNavmesh2: NavmeshGeometry[] = [
  {
    positions: [
      -10, 10, -10,  10, 10, -10,  10, 10, 10,  // Triangle 1
      -10, 10, -10,  10, 10, 10,   -10, 10, 10,  // Triangle 2
    ],
    indices: [0, 1, 2, 3, 4, 5]
  }
];

// Create floor data for each floor
const floor1 = new FloorData(navMap1, legacyNavmesh1);
const floor2 = new FloorData(navMap2, legacyNavmesh2);

// Define links between floors (stairs connecting floor1 to floor2)
const links: InterFloorLink[] = [
  {
    fromFloorId: "floor1",
    toFloorId: "floor2",
    fromPointId: "stairs1",
    toPointId: "stairs2",
    weight: 1.0,
    direction: 0 // bidirectional (0 = both directions)
  }
];

// Load multi-floor data
pathfinder.loadMultifloor({
  data: {
    "floor1": floor1,
    "floor2": floor2
  },
  links
});

// Find path across floors
const path = pathfinder.findPath(
  { x: 0, y: 0, z: 0 },      // Start on floor 1
  { x: 10, y: 10, z: 0 },    // End on floor 2
  "floor1",
  "floor2"
);

if (path) {
  console.log(`Found path with ${path.length} waypoints`);
  path.forEach((point) => {
    if (point.toFloorId) {
      console.log(`Crossing from ${point.floorId} to ${point.toFloorId}`);
    }
    console.log(`Point: (${point.point.x}, ${point.point.y}, ${point.point.z})`);
  });
}

License

MIT