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

@quantum-native/quantum-chess-sdk

v0.2.5

Published

Player SDK for building Quantum Chess AIs — match runner, explorer, tournament system, reference AI

Readme

Quantum Chess SDK

Build AI players for Quantum Chess. The SDK provides the full quantum chess engine (legal moves, quantum state simulation, measurements) so you only need to implement one method: pick a move.

Install

npm install @quantum-native/quantum-chess-sdk

No registry configuration is needed — the package and its engine are on the public npm registry. If install fails with a 404 / "not found" from npm.pkg.github.com, your .npmrc is routing the @quantum-native scope to GitHub Packages. Remove that line so the scope resolves to public npm:

# delete this if present in ~/.npmrc or ./.npmrc
@quantum-native:registry=https://npm.pkg.github.com

Quick Start

import type { QCPlayer, QCMoveChoice } from "@quantum-native/quantum-chess-sdk";

const myAI: QCPlayer = {
  name: "MyFirstAI",
  control: "ai",

  async chooseMove(view, explorer, clock) {
    // Pick the first legal move
    const move = view.legalMoves.standard[0];
    return { type: "standard", from: move.from, to: move.to };
  }
};

export default myAI;

That's a complete AI. The engine handles everything else: quantum physics, move validation, board state, measurements.

What You Get

When your chooseMove is called, you receive:

  • view.gameData -- current board: 64 pieces, 64 probabilities, ply count, castle flags, en passant
  • view.legalMoves -- every legal move pre-computed, split into standard, splits, and merges
  • view.sideToMove -- "white" or "black"
  • explorer -- a sandboxed engine clone for lookahead (see below)
  • clock -- time remaining in milliseconds (null if untimed)

You return one of:

{ type: "standard", from: 12, to: 28 }              // e2-e4
{ type: "split", from: 1, targetA: 16, targetB: 18 } // knight splits
{ type: "merge", sourceA: 16, sourceB: 18, to: 1 }   // knight merges

Explorer (Lookahead)

The explorer lets you try moves without affecting the real game. Apply a move, evaluate, then undo to try the next one:

async chooseMove(view, explorer, clock) {
  if (!explorer) return { type: "standard", from: view.legalMoves.standard[0].from, to: view.legalMoves.standard[0].to };

  let bestMove = view.legalMoves.standard[0];
  let bestScore = -Infinity;

  for (const move of view.legalMoves.standard) {
    const choice = { type: "standard" as const, from: move.from, to: move.to };
    const result = explorer.apply(choice);

    if (result.success && !result.measured) {
      const score = explorer.evaluate().score;
      if (score > bestScore) {
        bestScore = score;
        bestMove = move;
      }
      explorer.undo();
    }
  }

  return { type: "standard", from: bestMove.from, to: bestMove.to };
}

Explorer Methods

  • apply(choice, opts?) -- try a move, returns { success, measured, measurementPassProbability }
  • undo() -- undo the last apply, restoring the previous position
  • evaluate() -- material + probability score (positive = white advantage)
  • view -- current game state at this node (pieces, probabilities, legal moves)

Handling Measurements

Some moves trigger quantum measurements with probabilistic outcomes. When result.measured is true, branch on both outcomes:

const result = explorer.apply(choice);
if (result.measured) {
  const p = result.measurementPassProbability ?? 0.5;

  const pass = explorer.apply(choice, { forceMeasurement: "pass" });
  const passScore = explorer.evaluate().score;
  explorer.undo();

  const fail = explorer.apply(choice, { forceMeasurement: "fail" });
  const failScore = explorer.evaluate().score;
  explorer.undo();

  const expected = p * passScore + (1 - p) * failScore;
}

Standalone Engine (analysis / tools)

Most AIs only implement chooseMove and let the match runner own the engine. To drive the engine yourself — a position explorer, analysis tool, or test harness — use the one-call helpers. Paste the same position string the app shows (FEN, setup moves, and history all supported):

import { createPositionExplorer, toMoveChoice } from "@quantum-native/quantum-chess-sdk";

const explorer = await createPositionExplorer(
  "position fen 2KR2k1/5ppp/8/8/3q4/8/8/8 w - - 0 1 setup g8^f8h8 d8^d7g8",
);

const moves = explorer.view.legalMoves;                  // legal moves for the side to move
const result = explorer.apply(toMoveChoice(moves.standard[0])); // try a move; undo() to revert
const score = explorer.evaluate().score;

view.legalMoves entries carry engine metadata; toMoveChoice() turns one into the { type, from, to } shape apply() expects (it also handles split and merge moves).

createAnalysisEngine(position) returns a bare QCEngine (for getView() / executeMove()) the same way. Both accept a position/FEN string or a QChessPosition object, and an optional { rules } override (defaults to DEFAULT_RULES).

setup moves build quantum state (superposition/entanglement) before the game starts — they are not game moves. The FEN's active color decides whose turn it is, regardless of how many setup moves there are.

import {
  QCEngine, QuantumChessQuantumAdapterWasm, loadQCGameModule,
  createStackExplorer, DEFAULT_RULES, parsePositionString,
} from "@quantum-native/quantum-chess-sdk";

const mod = await loadQCGameModule();               // load the engine once
const engine = new QCEngine(new QuantumChessQuantumAdapterWasm(mod), {
  ...DEFAULT_RULES, allowCastling: false,           // override any rule field
});
engine.initializeFromPosition(
  parsePositionString("position fen 2KR2k1/5ppp/8/8/3q4/8/8/8 w - - 0 1")!,
);
const explorer = createStackExplorer(
  engine, engine.getGameData(), () => new QuantumChessQuantumAdapterWasm(mod),
);

Migrating from createQuantumForgePort (≤ 0.2.2): earlier builds exposed a port-backed adapter constructed as new QuantumChessQuantumAdapter(createQuantumForgePort(QFW)). Both that adapter and createQuantumForgePort were removed — use createPositionExplorer / createAnalysisEngine (or QuantumChessQuantumAdapterWasm directly). The engine, explorer, and move APIs are unchanged, and the WASM adapter matches the live game exactly — including captures through the explorer and setupMoves, which the old adapter did not always reflect.

Playing Against Your AI

The easiest way to test your AI: write a .js file and upload it in the game.

1. Write your AI file

Create my-ai.js:

export default {
  name: "My First AI",
  control: "ai",

  async chooseMove(view, explorer, clock) {
    // Pick a random legal move
    const moves = view.legalMoves.standard;
    const pick = moves[Math.floor(Math.random() * moves.length)];
    return { type: "standard", from: pick.from, to: pick.to };
  }
};

2. Load it in the game

  1. Go to VS AI in Quantum Chess
  2. Select Custom AI as the engine
  3. Click Upload File and choose your .js file
  4. Click Start Game

Your AI plays as the opponent. Edit the file and re-upload to iterate.

Other Hosting Options

JavaScript Module (URL)

Host your AI file and load it by URL:

import { loadCustomAI } from "@quantum-native/quantum-chess-sdk";
const ai = await loadCustomAI({ type: "module", url: "/my-ai.js" });

HTTP Server (any language)

Your server receives POST /move with { view, clock } and returns a QCMoveChoice.

from flask import Flask, request, jsonify
import random

app = Flask(__name__)

@app.route("/move", methods=["POST"])
def choose_move():
    data = request.json
    moves = data["view"]["legalMoves"]["standard"]
    pick = random.choice(moves)
    return jsonify({"type": "standard", "from": pick["from"], "to": pick["to"]})

app.run(port=8080)

Load in the game:

import { loadCustomAI } from "@quantum-native/quantum-chess-sdk";
const ai = await loadCustomAI({ type: "http", url: "http://localhost:8080/move", name: "MyPythonAI" });

Web Worker

For heavy computation without blocking the UI:

// worker.js
self.onmessage = (e) => {
  const { type, view, clock } = e.data;
  if (type === "chooseMove") {
    const move = view.legalMoves.standard[0];
    self.postMessage({ type: "standard", from: move.from, to: move.to });
  }
};

Message format:

  • Main thread sends: { type: "chooseMove", view: QCEngineView, clock: QCClock | null }
  • Worker responds with: QCMoveChoice via postMessage (e.g. { type: "standard", from, to })

WebSocket

For persistent connections and pondering:

const ai = await loadCustomAI({ type: "websocket", url: "ws://localhost:8081", name: "MyWSAI" });

Message format:

  • Client sends: { type: "chooseMove", requestId: number, view: QCEngineView, clock: QCClock | null }
  • Server responds: { requestId: number, ...QCMoveChoice }

The requestId ties the response to the request. Include the full QCMoveChoice fields in the response object alongside requestId.

Learn Quantum Chess

New to Quantum Chess? Learn the rules and strategy at chess.quantumnative.io. Join the community on Discord.

License

MIT -- see LICENSE. The quantum simulation engine is compiled to WebAssembly (qc-game.wasm) and bundled with this package; it is built from a separately-licensed source.