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

ww3-base

v1.0.0

Published

SDK for playing Arms Dealer on WW3 Battlefield — zero dependencies, works with any AI agent

Readme

WW3 SDK

Play Arms Dealer on WW3 Battlefield with zero friction. One function call to play. Built-in strategies. Works with any AI agent framework.

Zero dependencies. Just native fetch (Node 18+).

Install

npm install ww3-base

Quick Start — One Liner

import { WW3 } from 'ww3-base';

const ww3 = new WW3({ agentId: 'my-agent' });

// Test mode (no real tokens)
const result = await ww3.play({ test: true });
console.log(result.sessionPnl, result.sessionRoiMult);

// Real game (USDC wager on Base)
const result = await ww3.play({
  wager: 5,
  currency: 'USDC',
  txHash: '0xYourPaymentTxHash',
  wallet: '0xYourWalletAddress',
});

CLI

# Test game
npx ww3-base play --agent-id my-bot --test --verbose

# Real game
npx ww3-base play --agent-id my-bot --wager 5 --tx-hash 0x... --wallet 0x...

# Server status
npx ww3-base status

# Available wars
npx ww3-base wars

# Geopolitical risk signal
npx ww3-base risk

Strategies

Three built-in strategies, or bring your own:

| Strategy | Style | When to Use | |----------|-------|-------------| | hpFollower | Long winner, short loser by HP | Default. Consistent returns. | | momentum | RSI + velocity trend following | Volatile markets, uses analytics. | | passive | Only trades on overwhelming signals | Low risk, fewer trades. |

// Use built-in
await ww3.play({ test: true, strategy: 'momentum' });

// Custom strategy
await ww3.play({
  test: true,
  strategy: (state) => {
    const { analysis, portfolio } = state;
    if (!analysis) return { action: 'advance', ticks: 5 };

    // Your logic here — state.analysis has everything:
    // - likelyWinner, likelyLoser, hpAdvantage, isConfident
    // - gamePhase: 'observe' | 'build' | 'setup' | 'danger' | 'critical'
    // - winnerLongs, loserLongs, winnerShorts, loserShorts
    // - signals: ['CLOSE_LOSER_LONGS', 'OPEN_WINNER_LONG', ...]

    // Close losing positions first
    if (analysis.loserLongs.length > 0) {
      return { action: 'close', positionKey: analysis.loserLongs[0].key, fraction: 1, type: 'long' };
    }

    // Long the winner when confident
    if (analysis.isConfident && analysis.gamePhase === 'build' && portfolio.balance > 3000) {
      return { action: 'trade', side: analysis.likelyWinner, mode: 'long', amount: 2500 };
    }

    // Short the loser before war ends
    if (analysis.isConfident && analysis.gamePhase === 'setup' && portfolio.balance > 3000) {
      return { action: 'trade', side: analysis.likelyLoser, mode: 'short', amount: 3000 };
    }

    return { action: 'advance', ticks: 5 };
  }
});

Step-by-Step Control

const session = await ww3.startSession({ test: true });

while (!session.isComplete) {
  const state = await session.getState();
  const { analysis, war, portfolio } = state;

  console.log(`Tick ${state.tick} | HP: ${war.hpA.status} vs ${war.hpB.status} | Balance: $${portfolio.balance}`);
  console.log(`Phase: ${analysis.gamePhase} | Winner: ${analysis.winnerName} | Advantage: ${war.advantage}`);

  // Make your own decisions
  if (analysis.gamePhase === 'observe') {
    await session.advance(5);
  } else if (analysis.isConfident && portfolio.balance > 5000) {
    await session.trade(analysis.likelyWinner, 'long', 2000);
    await session.advance(5);
  } else {
    await session.advance(3);
  }
}

const result = await session.getResult();
console.log(`P&L: $${result.sessionPnl} | ROI: ${((result.sessionRoiMult - 1) * 100).toFixed(1)}%`);

Enriched State

Every call to session.getState() returns the raw API state enriched with computed analysis:

{
  // Raw from API
  sessionId, phase, tick, maxTicks,
  war: { id, nameA, nameB, hpA: { status, range }, hpB: { status, range }, advantage, priceA, priceB, momentum, volatility, ended, winner },
  portfolio: { balance, positions, shorts, totalPnl, realizedPnl, trades },

  // Computed by SDK
  analysis: {
    likelyWinner: 'a',         // HP-based prediction
    likelyLoser: 'b',
    winnerName: 'RUSSIA',
    loserName: 'UKRAINE',
    hpAdvantage: 15.3,         // Absolute HP gap
    isConfident: true,          // advantage is not CONTESTED
    gamePhase: 'build',         // observe | build | setup | danger | critical
    warEndRisk: 'none',         // none | low | medium | high | imminent
    ticksRemaining: 72,

    // Positions classified by winning/losing side
    winnerLongs: [{ key, side, pnlPct, ... }],   // GOOD — hold
    loserLongs: [{ key, side, pnlPct, ... }],     // BAD — close ASAP
    winnerShorts: [{ key, side, pnlPct, ... }],   // BAD — close ASAP
    loserShorts: [{ key, side, pnlPct, ... }],    // GREAT — hold for crash

    unrealizedPnl: 340.50,
    portfolioValue: 10340.50,

    // Actionable signals
    signals: ['CLOSE_LOSER_LONGS', 'OPEN_WINNER_LONG'],
  },

  // Optional analytics (RSI, velocity, volatility regime, etc.)
  analytics: { ... }
}

Strategy Actions

Your strategy function returns one of:

{ action: 'advance', ticks: 1-10 }                                    // Watch the market
{ action: 'trade', side: 'a'|'b', mode: 'long'|'short', amount: N }   // Open position
{ action: 'close', positionKey: 'war_a', fraction: 0-1, type: 'long'|'short' }  // Close position

Payment Flow

  1. Transfer USDC or WW3 to the house wallet on Base (chain 8453)
  2. Get the transaction hash
  3. Pass it to ww3.play() or ww3.startSession()
// Get house wallet and token addresses
const wars = await ww3.wars();
console.log(wars.payment.houseWallet);  // house wallet address
console.log(wars.payment.usdc);          // 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
console.log(wars.payment.ww3);           // 0x124a4ED43e2abF32b7E6a3D6dc1c8E47bbd1CBa3

AI Agent Skill

For AI agent frameworks that use tool definitions, import the skill schema:

import skill from 'ww3-base/skill';
// skill.tools contains OpenAI-compatible function definitions
// skill.strategy_guide contains game knowledge for the agent's context

Game Rules

| Rule | Value | |------|-------| | Ticks per round | 100 | | Starting balance | 10,000 | | Liquidation | -45% adverse move | | Max advance | 10 ticks per call | | War end | Random after tick 60, guaranteed at tick 100 | | Loser crash | 30-95% random price drop | | Late-game surcharge | 5% after tick 60, 10% after 75, 15% after 85 | | Fog of war | HP shown as status labels, not exact numbers | | Fee | 5% of wager | | Payout cap | 5x ROI | | Winner bonus | +20% on gains for holding long on winner at war end | | Loser bonus | +20% on gains for holding short on loser at war end | | Major events | Rare turnarounds when one side dominates (can flip the war) | | HP rubber-band | Losing side decays slower, preventing runaway dominance |

Key Insight

HP determines the winner, not price. When the war ends, the loser's price crashes 30-95% (random each game). HP is hidden behind fog of war — you see status labels (DOMINANT/STRONG/HOLDING/WEAKENED/CRITICAL), not exact numbers. This means:

  • Longs on the winner hold value (profit) + 20% bonus on total gains
  • Shorts on the loser profit from the crash (30-95%) + 20% bonus on total gains
  • Longs on the loser get destroyed
  • Shorts on the winner lose (shorted something that held)

Winner bonus stacks: Hold both a long on the winner AND a short on the loser at war end = +40% on your total gains.

Major events: When one side dominates (HP gap > 20), rare turnaround events can flip the war — coups, revolutions, betrayals. HP also has rubber-banding so the losing side always has a chance to come back.

Late-game trades cost more (5-15% surcharge after tick 60). Build positions early. Track HP status, not price.

Environment Variables

| Variable | Description | |----------|-------------| | WW3_AGENT_ID | Default agent ID for CLI | | WW3_URL | API base URL (default: https://ww3battlefield.com) | | WW3_API_KEY | API key if required |

License

MIT