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 🙏

© 2025 – Pkg Stats / Ryan Hefner

swordfight-engine

v1.5.7

Published

A multiplayer sword fighting game engine with character management, round-based combat, and real-time multiplayer support

Downloads

4,572

Readme

SwordFight Engine

A JavaScript-based multiplayer sword fighting game engine with character management, round-based combat, and real-time multiplayer support.

Features

  • Character Management: Multiple character types with unique abilities and stats
  • Round-based Combat: Strategic turn-based fighting system
  • Multiplayer Support: Real-time multiplayer functionality with computer opponent fallback
  • Dual Build System: Full version (115KB) with bundled data, or lite version (17KB) that uses the API
  • Static API: Pre-computed reference API with all possible game outcomes
  • Local Storage: Game state persistence
  • Event-driven Architecture: Custom events for UI integration
  • Modular Design: Clean separation of concerns with ES6 modules

Project Structure

swordfight.engine/
├── src/
│   ├── SwordFight.Game.js        # Main game class (full version)
│   ├── SwordFight.Game.Lite.js   # Lite version entry point
│   ├── classes/                  # Core game logic classes
│   │   ├── CharacterLoader.js    # Bundled character loader
│   │   ├── Moves.js             # Move management and validation
│   │   ├── Round.js             # Round logic and calculations
│   │   ├── RoundAPI.js          # API-based round calculation
│   │   ├── RoundFactory.js      # Round creation factory
│   │   ├── BonusCalculator.js   # Bonus calculation utilities
│   │   └── transports/          # Transport implementations
│   │       ├── MultiplayerTransport.js  # Base transport class
│   │       ├── ComputerTransport.js     # Computer opponent AI
│   │       └── WebSocketTransport.js    # WebSocket multiplayer
│   └── characters/              # Character JSON definitions
├── api/                         # Static API generator (Eleventy)
│   ├── src/                     # API templates
│   └── dist/                    # Generated API (not in git)
└── dist/                        # Built engine files (generated)

Installation

npm install swordfight-engine

Development

For local development:

npm install

### Available Scripts

- `npm run lint` - Run ESLint to check code quality
- `npm run lint:fix` - Automatically fix ESLint issues
- `npm run build` - Lint and bundle the engine
- `npm run build:api` - Build the static API
- `npm run build:api:dev` - Start API dev server with live reload
- `npm run build:all` - Build both engine and API
- `npm run bundle` - Bundle the project with esbuild
- `npm run dev` - Start development mode with file watching

### Code Style

This project uses ESLint with strict rules for code quality and consistency. Run `npm run lint` to check your code before committing.

## Usage

### Choosing a Version

**Full Version (115KB)** - Includes all character data bundled:
```javascript
import { Game } from 'swordfight-engine';

// Create game instance with your character (synchronous)
const game = new Game('computer', 'human-fighter');

// Initialize (loads your character data)
await game.initialize();

// Connect (computer mode doesn't need a transport parameter)
// Opponent character is set via name/character exchange
await game.connect();

Lite Version (17KB) - Loads character data from API (recommended for web):

import { Game, CharacterLoader } from 'swordfight-engine/lite';
import { DurableObjectTransport } from 'swordfight-engine/transports';

// Configure API endpoint
CharacterLoader.setApiBase('https://api.swordfight.me');

// Get player's character from localStorage
const myCharacter = localStorage.getItem('myCharacter') || 'human-fighter';

// Create game instance with your character (synchronous)
const game = new Game('room-123', myCharacter);

// Initialize (loads your character data from API)
await game.initialize();

// Create and connect transport (NOW your character is loaded)
// Opponent character will be set automatically via name/character exchange
const transport = new DurableObjectTransport(game, {
  serverUrl: 'wss://swordfight.your-username.workers.dev'
});
await game.connect(transport);

Note: Both versions use the same initialization pattern:

import { Game } from 'swordfight-engine';

// 1. Create game with your character slug (synchronous)
const game = new Game('computer', 'human-fighter');

// 2. Initialize (load your character data - NOW game.myCharacter exists)
await game.initialize();

// 3. Connect (opponent character exchanged automatically)
await game.connect();

Using the API Directly - Build custom clients:

See API_CLIENT_GUIDE.md for details on using the static API without the engine.

Basic Game Setup (Single Player)

import { Game } from 'swordfight-engine';

// Step 1: Create game with your character (synchronous)
const game = new Game('computer', 'human-fighter');

// Step 2: Set up event listeners BEFORE initializing
// (allows you to show loading UI immediately)
document.addEventListener('round', (event) => {
  const { myRoundData, opponentsRoundData } = event.detail;
  // Handle round completion
});

document.addEventListener('victory', () => {
  // Handle player victory
});

document.addEventListener('defeat', () => {
  // Handle player defeat
});

// Optional: Listen for opponent character being set
document.addEventListener('name', (event) => {
  // event.detail contains { name, characterSlug }
  console.log('Opponent:', event.detail);
});

// Step 3: Initialize (loads your character data)
await game.initialize();

// Step 4: Connect (computer mode auto-creates ComputerTransport)
// Opponent character is exchanged automatically
await game.connect();

// Step 5: Send moves during gameplay
const moveEvent = new CustomEvent('inputMove', {
  detail: { move: 'attack-high' }
});
document.dispatchEvent(moveEvent);

Initialization Lifecycle

The engine uses a simple initialization pattern that supports automatic character exchange:

  1. Constructor (synchronous) - Creates game with your character slug
  2. initialize() (async) - Loads your character data from bundled files or API
  3. connect() (async) - Connects transport and exchanges character/name data with opponent

Benefits:

  • Show loading/waiting UI immediately after creating the game instance
  • Your character loads first, then opponent character is exchanged automatically
  • Character exchange happens via existing name exchange mechanism
  • Transport can be created before opponent character is known
  • Prevent race conditions where transport connects before client is ready

How Character Exchange Works:

// Client side: Create game with your character
const myChar = localStorage.getItem('myCharacter') || 'human-fighter';
const game = new Game('room-123', myChar);

// Initialize loads YOUR character
await game.initialize(); // game.myCharacter now exists

// Transport can now be created (has access to game.myCharacter)
const transport = new WebSocketTransport(game);

// Connect exchanges name + character data
// Transport sends: { name: 'Player1', characterSlug: 'human-fighter' }
// Transport receives: { name: 'Player2', characterSlug: 'goblin' }
await game.connect(transport);

// Listen for when opponent character is received
document.addEventListener('name', (event) => {
  const { name, characterSlug } = event.detail;
  console.log(`Opponent ${name} is using ${characterSlug}`);
  // game.opponentsCharacter is now loaded
});

Game Events

The game engine communicates with the frontend through custom events:

  • round - Dispatched after each round with round data
  • setup - Dispatched after setting up the game state
  • move - Dispatched when a player's move is received
  • opponentsMove - Dispatched when the opponent's move is received
  • name - Dispatched when the opponent's name is received
  • victory - Dispatched when the player wins
  • defeat - Dispatched when the player loses

Exported Utilities

The engine exports several utilities for advanced usage:

BonusCalculator

Static utility class for calculating bonus damage from previous rounds. Useful when building custom clients or using the API directly.

import { BonusCalculator } from 'swordfight-engine';

// Calculate bonus for a move based on previous round's bonus data
const bonus = BonusCalculator.calculateBonus(move, previousRoundBonus);

// Calculate total score including bonus
const totalScore = BonusCalculator.calculateTotalScore(baseScore, moveModifier, bonus);

// Get the bonus that will apply to next round
const nextBonus = BonusCalculator.getNextRoundBonus(result);

See API_CLIENT_GUIDE.md for detailed examples.

Other Exports

  • CharacterLoader - Load character data (bundled or from API)
  • Round - Round calculation class
  • MultiplayerTransport - Base class for custom transport implementations
  • WebSocketTransport - WebSocket-based multiplayer transport

Analysis Tools

The bin/ directory contains analysis scripts for game design and balancing:

Character Difficulty Analyzer

Analyzes the skill level required to play each character effectively:

# View all characters ranked by difficulty
node bin/analyze-character-difficulty.js

# Analyze a specific character
node bin/analyze-character-difficulty.js --character human-monk

# Sort by speed factor instead of overall difficulty
node bin/analyze-character-difficulty.js --sort speed

# Verbose output with all details
node bin/analyze-character-difficulty.js --verbose

Characters are rated from 1-10 (Beginner to Expert). The analyzer considers these factors:

  • Speed/Timing (40% weight) - How often the character wins speed battles (faster = easier)
  • Defense (25% weight) - Availability of defensive options like shields and blocks
  • Forgiveness (20% weight) - Health pool and ability to recover from mistakes
  • Move Complexity (10% weight) - Number and variety of moves to master
  • Risk/Reward (5% weight) - Variance in attack damage and outcomes

Character Stats Analyzer

Analyzes combat statistics and matchups:

# View all character statistics
node bin/analyze-character-stats.js

# Analyze a specific character
node bin/analyze-character-stats.js --character human-fighter

# Analyze head-to-head matchup
node bin/analyze-character-stats.js --matchup human-fighter goblin

Character Validator

Validates character JSON files for correctness:

node bin/validate-characters.js

Building

The project uses esbuild for bundling.

Build the Engine

npm run build

Creates:

  • dist/swordfight-engine.js - Full version (115KB)
  • dist/swordfight-engine.min.js - Full version minified
  • dist/swordfight-engine.lite.js - Lite version (17KB)
  • dist/swordfight-engine.lite.min.js - Lite version minified

Build the Static API

npm run build:api

Generates api/dist/ with ~30,864 JSON files containing all possible game outcomes. See api/README.md for deployment instructions.

Build Everything

npm run build:all

License

MIT License