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

aminus

v1.0.0-beta

Published

Genshin Impact stat and damage calculation library

Readme

Aminus JavaScript/TypeScript Bindings

JavaScript and TypeScript bindings for the Aminus Genshin Impact calculation library.

Features

  • Full TypeScript Support: Complete type definitions for all functions and classes
  • ESM Module Support: Uses modern ES modules
  • WebAssembly: High-performance calculations compiled from Rust
  • Cross-Platform: Works in Node.js, browsers, and bundlers
  • Zero Dependencies: No runtime dependencies besides the WASM module
  • Artifact Optimization: Advanced algorithms for finding optimal artifact combinations

Installation

npm install aminus-js

Quick Start

TypeScript

import { loadWasm, Stat, Element, DamageType, BaseScaling, Amplifier } from 'aminus-js';

async function calculateDamage() {
  // Load the WASM module
  const aminus = await loadWasm();
  
  // Create a character stat table
  const character = aminus.StatTableWrapper.fromArray([
    [Stat.BaseATK, 334.85],
    [Stat.ATKPercent, 0.5],
    [Stat.CritRate, 0.6],
    [Stat.CritDMG, 1.2],
    [Stat.PyroDMGBonus, 0.466],
  ]);
  
  // Calculate damage
  const damage = aminus.calculateDamage(
    Element.Pyro,
    DamageType.Skill,
    BaseScaling.ATK,
    Amplifier.None,
    1.0, // instances
    2.5, // motion value
    character
  );
  
  console.log(`Skill damage: ${damage}`);
}

calculateDamage();

JavaScript (ESM)

import { loadWasm, Stat, Element, DamageType, BaseScaling, Amplifier } from 'aminus-js';

const aminus = await loadWasm();

// Create artifact builder
const builder = aminus.ArtifactBuilderWrapper.kqmAll5Star(
  Stat.ATKPercent,     // sands
  Stat.PyroDMGBonus,   // goblet
  Stat.CritRate        // circlet
);

// Add substat rolls
builder.roll(Stat.CritDMG, 4, 5, 6); // RollQuality.AVG, rarity 5, 6 rolls

// Get final stats
const artifacts = builder.build();
console.log(`Total Crit DMG: ${artifacts.get(Stat.CritDMG)}`);

Artifact Optimization

import { 
  createStatTable, 
  createRotation, 
  optimizeArtifactMainStats,
  optimizeArtifactSubstats,
  Stat, Element, DamageType, BaseScaling, Amplifier 
} from 'aminus-js';

async function optimizeCharacter() {
  // Create character stats
  const characterStats = createStatTable();
  characterStats.set(Stat.BaseATK, 106.0);
  characterStats.set(Stat.CritRate, 0.05);
  characterStats.set(Stat.CritDMG, 0.5);

  // Create rotation (damage sequence)
  const rotation = createRotation();
  rotationadd(
    'pyro_attack',
    Element.Pyro,
    DamageType.Normal,
    BaseScaling.ATK,
    Amplifier.None,
    1.0, // instances
    1.0  // motion value
  );

  // Optimize artifact main stats
  const bestMainStats = await optimizeArtifactMainStats(characterStats, rotation);
  console.log('Best main stats:', bestMainStats); // [sands, goblet, circlet]

  // Optimize artifact substats
  const substatDistribution = await optimizeArtifactSubstats(
    characterStats,
    rotation,
    1.2, // energy recharge requirement
    flower, feather, sands, goblet, circlet
  );
  console.log('Optimal substat distribution:', substatDistribution);
}

Building

Prerequisites

Build Commands

# Install dependencies
npm install

# Build for bundlers (default)
npm run build

# Build for Node.js
npm run build:nodejs

# Build for web browsers
npm run build:web

# Run tests
npm test

# Development mode (build + test)
npm run dev

API Reference

Types

Enums

  • Stat: Character and artifact statistics
  • Element: Elemental types (Pyro, Hydro, etc.)
  • DamageType: Attack types (Normal, Charged, Skill, Burst, etc.)
  • BaseScaling: Damage scaling base (ATK, DEF, HP)
  • Amplifier: Reaction amplifiers (None, Forward, Reverse)
  • RollQuality: Artifact substat roll quality

Core Classes

StatTableWrapper

Manages character statistics.

const stats = new StatTableWrapper();
stats.add(Stat.ATKPercent, 0.5);
const atkPercent = stats.get(Stat.ATKPercent);

// Create from array
const stats2 = StatTableWrapper.fromArray([
  [Stat.BaseATK, 100],
  [Stat.ATKPercent, 0.5]
]);
ArtifactBuilderWrapper

Builds artifact stat combinations.

// Manual construction
const builder = new ArtifactBuilderWrapper(flower, feather, sands, goblet, circlet);

// KQM presets
const builder = ArtifactBuilderWrapper.kqmAll5Star(
  Stat.ATKPercent,     // sands main stat
  Stat.PyroDMGBonus,   // goblet main stat
  Stat.CritRate        // circlet main stat
);

// Roll substats
builder.roll(Stat.CritDMG, RollQuality.AVG, 5, 4);
const finalStats = builder.build();
Rotation

Defines a sequence of damage operations for optimization.

const rotation = createRotation();

// Add damage operations
rotationadd(
  'normal_attack',
  Element.Pyro,
  DamageType.Normal,
  BaseScaling.ATK,
  Amplifier.None,
  1.0, // instances
  1.0  // motion value
);

rotationadd(
  'skill_attack',
  Element.Pyro,
  DamageType.Skill,
  BaseScaling.ATK,
  Amplifier.None,
  1.0,
  2.5
);

// Evaluate total damage
const totalDamage = rotation.evaluate(characterStats);

Functions

Damage Calculation

const damage = calculateDamage(
  element: Element,
  damageType: DamageType,
  scaling: BaseScaling,
  amplifier: Amplifier,
  instances: number,
  motionValue: number,
  character: StatTableWrapper,
  buffs?: StatTableWrapper
): number;

Artifact Optimization

// Optimize artifact main stats
const bestMainStats = await optimizeArtifactMainStats(
  characterStats: StatTableWrapper,
  target: Rotation
): Promise<number[]>; // [sands, goblet, circlet] stat IDs

// Optimize artifact substats
const substatDistribution = await optimizeArtifactSubstats(
  characterStats: StatTableWrapper,
  target: Rotation,
  energyRechargeRequirements?: number,
  flower?: ArtifactPiece,
  feather?: ArtifactPiece,
  sands?: ArtifactPiece,
  goblet?: ArtifactPiece,
  circlet?: ArtifactPiece
): Promise<Record<number, number>>; // stat ID -> roll count

// Calculate stat gradients
const gradients = await calculateStatGradients(
  base: StatTableWrapper,
  target: Rotation,
  slopes: Record<number, number>
): Promise<Record<number, number>>;

// Find effective stats (ReLU heuristic)
const effectiveStats = await calculateReluHeuristic(
  base: StatTableWrapper,
  target: Rotation,
  slopes: Record<number, number>
): Promise<number[]>;

Formula Functions

// Calculate total stats
const totalATK = calculateTotalAtkFromTable(stats);
const totalDEF = calculateTotalDefFromTable(stats);
const totalHP = calculateTotalHpFromTable(stats);

// Calculate multipliers
const critMultiplier = calculateAvgCritMultiplierFromTable(stats);
const defMultiplier = calculateDefMultiplier(charLevel, enemyLevel, defReduction, defIgnore);

Utility Functions

// Convert stat names
const stat = statFromString('atk'); // Returns Stat.ATKPercent
const name = getStatName(Stat.ATKPercent); // Returns 'ATKPercent'

// Check stat properties
const isElemental = isElementalDmgBonus(Stat.PyroDMGBonus); // true

Examples

Character Damage Calculation

import { loadWasm, Stat, Element, DamageType, BaseScaling, Amplifier } from 'aminus-js';

async function calculateDilucDamage() {
  const aminus = await loadWasm();
  
  // Diluc base stats
  const character = aminus.StatTableWrapper.fromArray([
    [Stat.BaseATK, 334.85],
    [Stat.CritRate, 0.242],
    [Stat.CritDMG, 0.5],
  ]);
  
  // Wolf's Gravestone weapon
  const weapon = aminus.StatTableWrapper.fromArray([
    [Stat.BaseATK, 608],
    [Stat.ATKPercent, 0.496],
  ]);
  
  // Artifact stats
  const artifacts = aminus.StatTableWrapper.fromArray([
    [Stat.FlatATK, 311],
    [Stat.ATKPercent, 0.466],
    [Stat.PyroDMGBonus, 0.466],
    [Stat.CritRate, 0.311],
    [Stat.CritDMG, 0.622],
  ]);
  
  // Combine all stats
  character.addTable(weapon);
  character.addTable(artifacts);
  
  // Calculate E skill damage
  const skillDamage = aminus.calculateDamage(
    Element.Pyro,
    DamageType.Skill,
    BaseScaling.ATK,
    Amplifier.None,
    1.0,
    2.016, // Diluc E motion value
    character
  );
  
  console.log(`Diluc E damage: ${skillDamage.toFixed(0)}`);
}

Artifact Optimization

import { loadWasm, Stat, RollQuality } from 'aminus-js';

async function optimizeArtifacts() {
  const aminus = await loadWasm();
  
  // Create KQM 5-star artifact set
  const builder = aminus.ArtifactBuilderWrapper.kqmAll5Star(
    Stat.ATKPercent,     // sands
    Stat.PyroDMGBonus,   // goblet
    Stat.CritRate        // circlet
  );
  
  // Simulate rolling substats
  builder.roll(Stat.CritDMG, RollQuality.HIGH, 5, 6);
  builder.roll(Stat.ATKPercent, RollQuality.AVG, 5, 4);
  builder.roll(Stat.FlatATK, RollQuality.LOW, 5, 2);
  
  const artifacts = builder.build();
  
  console.log('Final artifact stats:');
  console.log(`ATK%: ${(artifacts.get(Stat.ATKPercent) * 100).toFixed(1)}%`);
  console.log(`Crit Rate: ${(artifacts.get(Stat.CritRate) * 100).toFixed(1)}%`);
  console.log(`Crit DMG: ${(artifacts.get(Stat.CritDMG) * 100).toFixed(1)}%`);
  console.log(`Pyro DMG: ${(artifacts.get(Stat.PyroDMGBonus) * 100).toFixed(1)}%`);
}

Browser Usage

For browser environments, you may need to handle WASM loading differently:

<!DOCTYPE html>
<html>
<head>
  <script type="module">
    import { loadWasm, Stat } from './node_modules/aminus-js/pkg/aminus_js.js';
    
    async function main() {
      const aminus = await loadWasm();
      
      const stats = new aminus.StatTableWrapper();
      stats.add(Stat.ATKPercent, 0.5);
      
      console.log('ATK%:', stats.get(Stat.ATKPercent));
    }
    
    main().catch(console.error);
  </script>
</head>
<body>
  <h1>Aminus Web Example</h1>
</body>
</html>

Running Tests

Run all tests:

npm test

Run tests in watch mode:

npm run test:watch

Test files are located in the tests/ directory.

Contributing

  1. Make changes to the Rust source code in src/
  2. Run npm run build to compile WASM
  3. Add or update tests in `