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

lmbs-core

v1.0.0

Published

A real-time 2D Linear Motion Battle System core simulation engine.

Readme

⚔️ Linear Motion Battle System (LMBS) Core

A highly modular, engine-agnostic, real-time 2D fighting/RPG battle simulation engine written in TypeScript. This package isolates pure physics, kinematics, collision math, and action queues from rendering and platform dependencies, allowing it to be ported easily into various games or game engines.

The engine is divided into four core domains.

lmbs-core/
├── src/
│   ├── types.ts          (State, configuration, and data structures)
│   ├── BattlerState.ts   (The individual fighter state and 1-to-1 properties)
│   ├── ActionPipeline.ts (The action initialization, notes parsing, and queuing)
│   └── EngineCore.ts     (The central match state, physics ticks, and collision loops)
└── index.ts              (The public API wrapper for external game engines)

Usage

Initialize the Core Engine To start a battle encounter, instantiate the main facade class by passing the viewport bounds, fallback configuration parameters, and your game's static data databases.

import { LinearMotionBattleSystem, LMBSConfig } from "./src/index";

// Define environmental parameters and patches
const battleConfig: LMBSConfig = {
  turnDuration: 240,
  gravityPower: 10,
  groundHeightOffset: 0,        // Baseline floor modification
  damageReaction: false,        // If false, grants invulnerability during hitstun
  agilityMultiplier: 0,         // Scale move speed with character speed stats
  normalAttackRate: 60,
  deadPoseYOffset: 24,
  shadowYOffset: -4,
  
  // Unofficial Knockback Patch Fallbacks
  fallbackKnockbackX: 2,
  fallbackKnockbackY: 2,
  fallbackKnockbackDuration: 15,
  fallbackHitstun: 30
};

// Simulated static databases containing raw skill note string data
const skillsDatabase = [
  { id: 0, repeats: 1, scope: 1, note: "" }, // Basic Attack Placeholder
  { 
    id: 1, 
    repeats: 3, 
    scope: 1, 
    note: "LMBS Duration: 40\nLMBS Hit Delay: 10\nLMBS Area: [20,20,60,20]\nLMBS KnockbackX: 8\nLMBS KnockbackY: 4" 
  }
];

const itemsDatabase: any[] = [];

// Instantiate the battle system environment
const lmbs = new LinearMotionBattleSystem({
  screenWidth: 800,
  screenHeight: 600,
  config: battleConfig,
  skillsDatabase: skillsDatabase,
  itemsDatabase: itemsDatabase
});

👥 Spawning Battle Participants

Fighters (actors or enemies) are defined by pairing their current statistical values and raw metadata strings into an ExternalBattlerData object, then injecting them straight into the simulation pool.

import { LmbsBattlerState, ExternalBattlerData } from "./src/index";

// 1. Configure the Player Fighter
const playerData: ExternalBattlerData = {
  actorOrEnemyId: 1,
  isActor: true,
  agi: 45,
  attackSkillId: 0,
  skills:, // Shortcut slots matrix mapping
  groundHeightOffset: 0,          // Character structural floor baseline tweak
  note: "LMBS Sprite Name: Hero\nLMBS Move Speed: 6\nLMBS Jump Height: 22\nLMBS Double Jump: true\nLMBS Air Dash: true"
};

const hero = new LmbsBattlerState(playerData, battleConfig.gravityPower, battleConfig.deadPoseYOffset);
lmbs.spawnParticipant(hero);

// 2. Configure an Enemy Target
const goblinData: ExternalBattlerData = {
  actorOrEnemyId: 10,
  isActor: false,
  agi: 20,
  attackSkillId: 0,
  skills: [],
  groundHeightOffset: 0,
  note: "LMBS Sprite Name: Goblin\nLMBS Move Speed: 3\nLMBS Action Rate: 120"
};

const goblin = new LmbsBattlerState(goblinData, battleConfig.gravityPower, battleConfig.deadPoseYOffset);
lmbs.spawnParticipant(goblin);

🔄 Running the Core Game Loop

To progress velocities, compute gravity drag curve changes, evaluate AABB overlapping hitboxes, and tick internal state countdown variables, bind the .tick() method straight into your global frame rendering update timeline.

function gameLoop() {
  // 1. Advance the mathematical battle engine states by 1 frame step
  lmbs.tick();

  // 2. Query data out of the engine state to update visual assets/sprites
  const actors = lmbs.core.getActors();
  actors.forEach(actor => {
    const visualSprite = getYourVisualSpriteReference(actor.externalData.actorOrEnemyId);
    
    // Smoothly update position coordinates mapping 1-to-1 from simulation memory
    visualSprite.x = actor._lmbs_X;
    visualSprite.y = actor._lmbs_Y;

    // Check action states to resolve visual sheets/poses dynamically
    if (actor._lmbs_Knockback.duration > 0) {
      visualSprite.playPose("Damage");
    } else if (actor._lmbs_Walking) {
      visualSprite.playPose("Walk");
    } else if (actor._lmbs_ActionSkill.length > 0) {
      // Index 21 houses parsed custom pose strings ("lmbs pose name")
      const activePose = actor._lmbs_ActionSkill[21] || "Attack";
      visualSprite.playPose(activePose);
    } else {
      visualSprite.playPose("Idle");
    }
  });

  // Loop processing step mapping
  requestAnimationFrame(gameLoop);
}

requestAnimationFrame(gameLoop);

🎮 Processing Combat Commands & Input Hooks

The package keeps input polling completely abstract. Your rendering interface tracks key presses or controller gestures, changing the flags or immediately pushing executions down-funnel.

Direct Action Commands:

// Command the hero to use skill slot shortcut index 1 targeting the goblin
if (myInputManager.isButtonPressed("SkillKey")) {
  lmbs.triggerAction(hero, 1, false, goblin);
}

Manual Movement Manipulation:

// Update locomotion states natively to allow the physics engine loop to translate positions
if (myInputManager.isKeyPressed("LeftArrow")) {
  hero._lmbs_Direction = 2; // Face Left constant configuration
  hero._lmbs_Walking = true;
} else if (myInputManager.isKeyPressed("RightArrow")) {
  hero._lmbs_Direction = 4; // Face Right constant configuration
  hero._lmbs_Walking = true;
} else {
  hero._lmbs_Walking = false; // Entity returns cleanly back to neutral idle
}

// Intercept jumping triggers natively
if (myInputManager.isButtonPressed("JumpKey") && !hero._lmbs_Jump.isActive) {
  hero._lmbs_Jump.isActive = true;
  // Apply upward kinetic impulse subtracting vectors away from floor line lines
  hero._lmbs_Y -= hero._lmbs_Jump.power; 
}

📑 Supported Notetag Metadata Reference

When configuring raw asset string packages (ExternalBattlerData.note or skill payloads), use standard metadata syntax formatting:

Character Traits

  • LMBS Sprite Name: [String] – Defines target file visual identifier tracking structures.
  • LMBS Move Speed: [Number] – Sets the base pixel shifting step increment.
  • LMBS Jump Height: [Number] – Peak impulse ceiling boundary adjustments.
  • LMBS Double Jump: [Boolean] – Authorizes extra mid-air upward trajectory commands.
  • LMBS Air Dash: [Boolean] – Authorizes fast horizontal air slides.
  • LMBS Fly Height: [Number] – Enforces hover buffers above floor lines, disabling jumping states natively.

Ability Traits

  • LMBS Duration: [Number] – Life-span window of the collider execution frames.
  • LMBS Hit Delay: [Number] – Wait frames required before resetting active hit triggers for multi-hit capabilities.
  • LMBS Area: [Up, Down, Left, Right] – Hitbox dimension arrays calculated outwards from user coordinates.
  • LMBS Pose Name: [String] – Changes character visual frames while active.
  • LMBS KnockbackX: [Number] – Transferred horizontal kinetic impulse speed.
  • LMBS KnockbackY: [Number] – Transferred vertical kinetic push-up speed.
  • LMBS Hitstun: [Number] – Frames target remains locked out of action state execution layers.
  • LMBS Skill Chain: [Number] – Auto-injects follow-up skill IDs instantly upon termination.

Layout

Module 1: The Shared Blueprints - types.ts

This file holds configurations and strict TypeScript versions

Module 2: 1-to-1 Property Mapping - BattlerState.ts

This class completely replaces Game_Battler.prototype. Every lmbs variable is preserved here as a clean class property. This is where functions like lmbsSetParametersTags() or movement gating logic will live.

Where methods updating this._lmbs_Y, that exact code can be ported inside this class without changing the property names. It accepts an abstract externalStats provider so it can read agi or item notes without knowing if they come from RPG Maker, Unity, or Godot.

Module 3: Action & Combat Execution - ActionPipeline.ts

This module handles everything from parsing note tags ("lmbs knockbackx") to running combo timing windows, chaining skills, and managing target scopes. It isolates the heavy string parsing and the knockbackCounter math we saw in Section 6. It calculates the raw data and bundles it into an ActionPayload to be executed.

Module 4: The Tick & Physics Loop - EngineCore.ts

This class replaces Game_Temp and Game_System. It maintains the global list of active BattlerState instances, monitors the boundaries of the scene, and exposes a single .update(deltaTime) or .tick() method. Your external game loop (like a requestAnimationFrame in JS or a _process loop in Godot) just calls this tick method. The core then loops through all battlers, applies gravity vectors, processes active projectiles, and handles collision math.