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

miaoda-game-behavior-core

v0.3.0

Published

Engine-independent behavior trees with perception, steering, deterministic RNG, bounded diagnostics, and explicitly invalidated path-replanning caches.

Downloads

556

Readme

miaoda-game-behavior-core

Use this engine-independent behavior-tree layer for guards, enemies, companions, and NPCs. It provides line-of-sight/FOV conditions and steering actions on top of mistreevous; your game supplies the entity bridge, custom actions, and optional path planner.

Install

pnpm add miaoda-game-behavior-core mistreevous miaoda-game-vision2d-core

Minimal tree

import { BehaviorRunner, State, type BehaviorAgent } from 'miaoda-game-behavior-core';

const definition = `root {
  selector {
    sequence { condition [CanSeeTarget] action [MoveToTarget] }
    action [Patrol]
  }
}`;

let dt = 0;
const agent: BehaviorAgent = {
  config: { speed: 80, sightRange: 400, fovDeg: 70 },
  getPosition: () => enemyPosition,
  setPosition: (position) => { enemyPosition = position; },
  getFacingDeg: () => facingDegrees,
  getTarget: () => playerPosition,
  getObstacles: () => visionObstacles,
  getDeltaTime: () => dt,
};

const runner = new BehaviorRunner(definition, agent, {
  Patrol: (a) => { patrol(a as BehaviorAgent); return State.SUCCEEDED; },
});

function tick(seconds: number) {
  dt = seconds;
  runner.step(seconds);
}

step takes finite seconds and should run once per simulation tick. CanSeeTarget uses distance, shared obstacles, and optional facing cone. MoveToTarget and MoveTo return RUNNING until within arriveRadius, then SUCCEEDED; they never overshoot.

Built-in leaves

| Tree expression | Purpose | | --- | --- | | condition [CanSeeTarget] | Line of sight and optional FOV | | condition [IsTargetInRange radius] | Straight-line range check | | action [MoveToTarget] | Steer directly toward current target | | action [MoveToTargetAvoiding] | Follow agent.findPath when available | | action [MoveTo x y] | Steer toward a fixed point | | action [FleeFromTarget] | Steer away while a target exists |

followPath(agent, waypoints) is exported for custom patrol or route leaves. Without findPath, direct steering treats obstacles as sight blockers only; it does not navigate around walls.

Agent bridge

Implement BehaviorAgent with position read/write, facing in degrees (0° = +X), target position, Obstacles, and the current delta in seconds. config.speed is world units per second; arriveRadius, sightRange, and fovDeg tune movement and perception. Use the same Obstacles instance that drives your vision rendering so AI and player-facing cones agree.

For terrain navigation, add findPath(from, to): Vec2[] | null and use MoveToTargetAvoiding. The planner can adapt miaoda-game-grid-core A* or a navmesh; the behavior package consumes the route but does not own the algorithm.

Cached replanning

The compatibility function moveToTargetAvoiding(agent) plans every call. For expensive planners, give each agent a ReplanningPathFollower with explicit invalidation rules:

const navigator = new ReplanningPathFollower({
  maxAgeSeconds: 0.3,
  targetMoveDistance: 40,
  unreachableRetrySeconds: 0.6,
  getNavigationRevision: () => navigationRevision,
  onReplan: (event) => aiTrace.record(event),
});

navigator.step(agent);

navigationRevision remains host-owned: increment it when doors, blockers, traversal costs, or a navmesh change. The follower owns only copied waypoints and simulation-time cache age. It never queries physics or integrates position itself.

For MDSL trees, set BehaviorRunnerOptions.pathReplanning to the same options and the built-in action [MoveToTargetAvoiding] uses one follower owned by that runner. Omit it to preserve plan-every-call behavior.

Diagnostics and deterministic trees

Pass runner options as the fourth constructor argument. A seeded or authoritative random source controls lotto and ranged wait/repeat/retry nodes. Diagnostic history is opt-in and bounded; traceCapacity: 0 (the default) retains nothing.

const runner = new BehaviorRunner(definition, agent, customFunctions, {
  random: seededRandom,
  diagnostics: {
    traceCapacity: 128,
    onNodeStateChange: (change) => debugPanel.record(change),
  },
});

const snapshot = runner.getSnapshot();
const recent = runner.getRecentTransitions();

getSnapshot() returns a detached, recursively frozen id/type/name/state/children tree. Transitions include monotonic sequence and runner step numbers. Call clearTransitions() when a debug capture has been consumed. Observers run synchronously, so defer file, network, or cross-thread work to the host.

Public API

BehaviorRunner, BehaviorRunnerOptions, diagnostic snapshot/transition types, ReplanningPathFollower, replanning event/options types, State, canSeeTarget, isTargetWithin, moveToTarget, moveToTargetAvoiding, moveTo, fleeFromTarget, followPath, BehaviorAgent, SteeringConfig, and Vec2 are exported.

The core does not own a scene node, input devices, rendering, collision queries, or game-specific actions such as Attack and Patrol; provide those through the agent and custom functions.