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

@react-chess-tools/react-chess-stockfish

v1.0.1

Published

<div align="center"> <h1>@react-chess-tools/react-chess-stockfish</h1> <p>A React component library for integrating Stockfish chess engine analysis into your applications</p>

Downloads

39

Readme

npm version npm downloads License: MIT TypeScript

Table of Contents

Overview

@react-chess-tools/react-chess-stockfish is a React component library for integrating the Stockfish chess engine into your applications. It provides real-time position evaluation, principal variation lines, and customizable engine configuration through a clean, unstyled component API.

Features

  • Real-time Analysis - Get live position evaluations from Stockfish
  • Evaluation Bar - Unstyled component showing position advantage with customizable orientation
  • Engine Lines - Display principal variations with move numbers
  • MultiPV Support - Analyze multiple candidate moves simultaneously
  • Engine Control - Configure skill level, depth, and number of lines
  • Unstyled Components - Bring your own styles with data-attribute driven styling
  • TypeScript - Full TypeScript support with comprehensive type definitions
  • Web Worker - Non-blocking analysis using Web Workers
  • Security - Built-in worker path validation to prevent XSS attacks

Installation

npm install @react-chess-tools/react-chess-stockfish
yarn add @react-chess-tools/react-chess-stockfish
pnpm add @react-chess-tools/react-chess-stockfish

Note: You also need a Stockfish worker file. See Getting Stockfish Worker below.

Getting Stockfish Worker

This package does not bundle Stockfish. You need to provide your own worker file.

Host Your Own Copy

  1. Download Stockfish.js from the stockfish.js repository
  2. Place the .js and .wasm files in your project's public/ directory (rename them to stockfish.js and stockfish.wasm for simplicity)
  3. Reference the JS file with a relative path:
const workerPath = "/stockfish.js";

Note: Multi-threaded engines use SharedArrayBuffer which requires your server to send Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp headers. If you see SharedArrayBuffer is not defined errors, use the single-threaded version instead.

Quick Start

import { ChessStockfish } from "@react-chess-tools/react-chess-stockfish";

function App() {
  return (
    <ChessStockfish.Root
      fen="r1bqkbnr/pppp1ppp/2n5/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 2 3"
      workerOptions={{ workerPath: "/stockfish.js" }}
    >
      <ChessStockfish.EvaluationBar showEvaluation />
      <ChessStockfish.EngineLines maxLines={3} />
    </ChessStockfish.Root>
  );
}

Demo

Visit the Storybook to see the component in action with interactive examples.

API Reference

ChessStockfish.Root

The root component that manages the Stockfish worker and provides analysis context to all child components.

Note: This is a logic-only component (Context Provider). It does not render any DOM elements.

Props

| Name | Type | Default | Description | | -------------------- | ------------------------------------------ | ------- | ---------------------------------------------- | | fen | string | - | Position in FEN notation to analyze (required) | | config | StockfishConfig | {} | Engine configuration options | | workerOptions | WorkerOptions | - | Worker configuration (required) | | onEvaluationChange | (evaluation: Evaluation \| null) => void | - | Callback when evaluation changes | | onDepthChange | (depth: number) => void | - | Callback when search depth changes | | onError | (error: Error) => void | - | Callback when an error occurs | | children | ReactNode | - | Child components |

StockfishConfig

| Property | Type | Default | Range | Description | | ------------ | -------- | ------- | ------- | ----------------------------------------------- | | skillLevel | number | 20 | 0-20 | Engine playing strength (0 = weakest, 20 = max) | | depth | number | - | 1-255 | Maximum search depth | | multiPV | number | 1 | 1-500 | Number of principal variations to calculate |

WorkerOptions

| Property | Type | Default | Description | | ------------ | ------------------------ | ------- | ----------------------------------------------------- | | workerPath | string | - | URL to the Stockfish worker file (required) | | throttleMs | number | 50 | Throttle updates to prevent excessive re-renders (ms) | | timeout | number | 30000 | Timeout for initialization and analysis (ms) | | onError | (error: Error) => void | - | Callback for worker-specific errors |

Example

<ChessStockfish.Root
  fen="rnbqkbnr/pppppppp/8/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
  config={{ skillLevel: 20, depth: 20, multiPV: 3 }}
  workerOptions={{
    workerPath: "/stockfish.js",
    throttleMs: 50,
    timeout: 30000,
  }}
  onEvaluationChange={(eval) => console.log("Evaluation:", eval)}
  onDepthChange={(depth) => console.log("Depth:", depth)}
  onError={(error) => console.error("Engine error:", error)}
>
  <ChessStockfish.EvaluationBar />
  <ChessStockfish.EngineLines maxLines={3} />
</ChessStockfish.Root>

ChessStockfish.EvaluationBar

An unstyled evaluation bar showing the relative advantage between players.

Supports ref forwarding and all standard HTML div attributes (className, style, id, data-, aria-, etc.).

Props

| Name | Type | Default | Description | | ---------------- | -------------------------------- | ------------ | --------------------------------------------------------------------------- | | orientation | "vertical" \| "horizontal" | "vertical" | Direction of the bar | | perspective | "w" \| "b" | "w" | Which side is at the bottom/left of the board view (affects fill direction) | | showEvaluation | boolean | false | Whether to display evaluation text (e.g., "+1.2") | | asChild | boolean | false | Render as child element (slot pattern) | | children | ReactNode | - | Optional children to render inside the bar | | ref | Ref<HTMLDivElement> | - | Forwarded ref to the div element | | className | string | - | Custom CSS class names | | ... | HTMLAttributes<HTMLDivElement> | - | All standard HTML div attributes |

Data Attributes

The root element provides these data attributes for styling:

| Attribute | Value | Description | | -------------------------------- | ---------------------------------------- | ---------------------------------------------- | | data-stockfish-orientation | "vertical" or "horizontal" | Direction of the bar | | data-stockfish-perspective | "w" or "b" | Which side's perspective (affects fill origin) | | data-stockfish-eval | string | Formatted evaluation (e.g., "+1.2", "#3", "–") | | data-stockfish-eval-type | "cp", "mate", or "none" | Type of evaluation | | data-stockfish-eval-value | number | The raw numeric evaluation value | | data-stockfish-fill-percentage | 0-100 | Fill percentage for CSS styling | | data-stockfish-fill-origin | "bottom", "top", "left", "right" | Where the fill originates from |

Inner Elements:

| Element | Attribute | Description | | -------------------- | -------------------------- | ---------------------------------------------------- | | Fill div | data-stockfish-fill | The fill bar element (uses CSS transform for sizing) | | Evaluation text span | data-stockfish-eval-text | The evaluation text (when showEvaluation is true) |

Example

<ChessStockfish.Root fen={fen} workerOptions={workerOptions}>
  <ChessStockfish.EvaluationBar
    orientation="horizontal"
    perspective="w"
    showEvaluation={true}
    className="my-eval-bar"
  />
</ChessStockfish.Root>

Styling Example

.evaluation-bar {
  width: 20px;
  height: 400px;
  background: #fff;
  border-radius: 4px;
  overflow: hidden;
  position: relative;
}

/* The fill element uses CSS transform for sizing */
[data-stockfish-fill] {
  position: absolute;
  inset: 0;
  background: #333;
  transition: transform 0.15s ease;
}

/* White advantage fills from bottom by default (perspective="w") */
.evaluation-bar[data-stockfish-perspective="w"] [data-stockfish-fill] {
  transform-origin: bottom;
}

/* Black perspective - fill comes from top */
.evaluation-bar[data-stockfish-perspective="b"] [data-stockfish-fill] {
  transform-origin: top;
  background: #333;
}

/* Evaluation text styling */
[data-stockfish-eval-text] {
  position: absolute;
  bottom: 4px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 12px;
  font-weight: bold;
  color: #333;
}

ChessStockfish.EngineLines

Displays principal variation lines from the engine analysis. Each line shows moves in standard algebraic notation with move numbers.

Supports ref forwarding, asChild pattern, and all standard HTML div attributes (className, style, etc.).

Props

| Name | Type | Default | Description | | ------------- | ------------------------------------------------ | ------- | ------------------------------------------------------------ | | maxLines | number | - | Maximum number of PV lines to display (shows all if not set) | | onLineClick | (rank: number, pv: PrincipalVariation) => void | - | Callback when a line is clicked (rank is 1-indexed) | | asChild | boolean | false | Render as child element (slot pattern) | | children | ReactNode | - | Optional children to render | | ref | Ref<HTMLDivElement> | - | Forwarded ref to the div element | | className | string | - | Custom CSS class names | | ... | HTMLAttributes<HTMLDivElement> | - | All standard HTML div attributes |

PrincipalVariation Type

interface PrincipalVariation {
  rank: number; // Line ranking (1 = best)
  evaluation: Evaluation | null; // Line evaluation
  moves: PVMove[]; // Array of moves in the line
}

interface PVMove {
  uci: string; // UCI notation (e.g., "e2e4")
  san: string; // Standard notation (e.g., "1. e4")
}

Data Attributes

Each line element (rendered for each PV) provides these data attributes:

| Attribute | Value | Description | | ---------------- | ------ | --------------------------------------------- | | data-pv-rank | number | Line ranking (1 = best line) | | data-eval | string | Formatted evaluation (e.g., "+1.23", "#3") | | data-depth | number | Current search depth | | data-uci-moves | string | Space-separated UCI moves (e.g., "e2e4 e7e5") |

Inner Elements:

| Element | Attribute | Description | | -------------------- | ---------------- | -------------------------------------------- | | Evaluation text span | data-eval-text | The evaluation text for this line | | Moves container | data-moves | Container for all moves | | Individual move span | data-move | A single move element | | Move span | data-uci | The UCI notation for the move (e.g., "e2e4") |

Accessibility: When onLineClick is provided, lines automatically get role="button" and tabIndex={0} for keyboard accessibility.

Example

<ChessStockfish.Root
  fen={fen}
  config={{ multiPV: 3 }}
  workerOptions={workerOptions}
>
  <ChessStockfish.EngineLines
    maxLines={3}
    onLineClick={(rank, pv) => console.log(`Selected line ${rank}:`, pv)}
    className="engine-lines"
  />
</ChessStockfish.Root>

Using asChild Pattern

<ChessStockfish.EngineLines asChild>
  <div className="custom-lines-container">
    {/* Your custom rendering logic */}
  </div>
</ChessStockfish.EngineLines>

Styling Example

.engine-lines {
  font-family: monospace;
  font-size: 14px;
}

/* Style each line container */
.engine-lines > div {
  padding: 8px 12px;
  border-bottom: 1px solid #eee;
  display: flex;
  gap: 12px;
  align-items: center;
}

/* Evaluation text */
[data-eval-text] {
  font-weight: bold;
  min-width: 50px;
  color: #333;
}

/* Positive evaluation = green */
[data-eval^="+"] {
  color: #27ae60;
}

/* Negative evaluation = red */
[data-eval^="-"] {
  color: #e74c3c;
}

/* Moves container */
[data-moves] {
  color: #666;
}

/* Individual move */
[data-move] {
  cursor: pointer;
}

[data-move]:hover {
  color: #333;
  text-decoration: underline;
}

/* Interactive lines (when onLineClick is provided) */
.engine-lines > div[role="button"] {
  cursor: pointer;
}

.engine-lines > div[role="button"]:hover {
  background: #f5f5f5;
}

Utility Functions

The package exports several utility functions for working with evaluations:

import {
  formatEvaluation,
  normalizeEvaluation,
  cpToWinningChances,
  validateFen,
  uciToSan,
  uciToPvMoves,
} from "@react-chess-tools/react-chess-stockfish";

// Format an evaluation for display
formatEvaluation({ type: "cp", value: 123 }); // "+1.23"
formatEvaluation({ type: "mate", value: 3 }); // "#3"
formatEvaluation(null); // "–"

// Normalize centipawns to -1..1 range
normalizeEvaluation({ type: "cp", value: 100 }); // ~0.14

// Convert centipawns to winning probability (0-1)
cpToWinningChances(100); // ~0.57

// Validate a FEN string (returns true/false)
validateFen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); // true

// Convert UCI move to SAN notation
uciToSan(fen, "e2e4"); // "e4"

// Convert UCI move string to PVMove array
uciToPvMoves(fen, ["e2e4", "e7e5", "g1f3"]);

Hooks

useStockfish

Access the Stockfish analysis state and methods from any child component.

import { useStockfish } from "@react-chess-tools/react-chess-stockfish";

function AnalysisDisplay() {
  const {
    evaluation,
    normalizedEvaluation,
    bestLine,
    principalVariations,
    depth,
    status,
    isEngineThinking,
    hasResults,
    error,
  } = useStockfish();

  return (
    <div>
      <p>
        Evaluation: {evaluation ? formatEvaluation(evaluation) : "Analyzing..."}
      </p>
      <p>Depth: {depth}</p>
      <p>Status: {status}</p>
    </div>
  );
}

Return Values

| Property | Type | Description | | ---------------------- | ---------------------------- | ------------------------------------------------------------------- | | fen | string | Current position being analyzed | | config | StockfishConfig | Current engine configuration | | evaluation | Evaluation \| null | Best line evaluation (cp or mate) | | normalizedEvaluation | number | Evaluation normalized to -1..1 range | | bestLine | PrincipalVariation \| null | Best principal variation | | principalVariations | PrincipalVariation[] | All calculated PV lines | | depth | number | Current search depth | | status | EngineStatus | Engine status ("initializing" | "ready" | "analyzing" | "error") | | isEngineThinking | boolean | Whether engine is currently calculating | | hasResults | boolean | Whether any analysis results are available | | error | Error \| null | Last error that occurred |

Examples

Basic Analysis

import { ChessStockfish } from "@react-chess-tools/react-chess-stockfish";

function BasicAnalysis() {
  return (
    <ChessStockfish.Root
      fen="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
      workerOptions={{ workerPath: "/stockfish.js" }}
    >
      <ChessStockfish.EvaluationBar />
      <ChessStockfish.EngineLines />
    </ChessStockfish.Root>
  );
}

Multi-PV Analysis

import { ChessStockfish } from "@react-chess-tools/react-chess-stockfish";

function MultiPVAnalysis() {
  return (
    <ChessStockfish.Root
      fen="r1bqkbnr/pppp1ppp/2n5/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 2 3"
      config={{ multiPV: 4, depth: 20 }}
      workerOptions={{ workerPath: "/stockfish.js" }}
    >
      <ChessStockfish.EvaluationBar orientation="horizontal" />
      <ChessStockfish.EngineLines maxLines={4} />
    </ChessStockfish.Root>
  );
}

Analysis with Callbacks

import {
  ChessStockfish,
  useStockfish,
} from "@react-chess-tools/react-chess-stockfish";

function AnalysisWithCallbacks() {
  const handleEvaluationChange = (evaluation) => {
    if (evaluation?.type === "mate") {
      console.log(`Mate in ${evaluation.value}!`);
    } else if (evaluation?.type === "cp") {
      console.log(`Advantage: ${evaluation.value / 100} pawns`);
    }
  };

  return (
    <ChessStockfish.Root
      fen="4kb1r/p2r1ppp/4qn2/1B2p1B1/4P3/1Q6/PPP2PPP/2KR4 w k - 0 1"
      workerOptions={{ workerPath: "/stockfish.js" }}
      onEvaluationChange={handleEvaluationChange}
    >
      <StatusDisplay />
      <ChessStockfish.EvaluationBar />
    </ChessStockfish.Root>
  );
}

function StatusDisplay() {
  const { depth, status, isEngineThinking } = useStockfish();

  return (
    <div>
      <span>Depth: {depth}</span>
      <span>Status: {status}</span>
      {isEngineThinking && <span className="thinking">Analyzing...</span>}
    </div>
  );
}

Clickable Engine Lines

import {
  ChessStockfish,
  type PrincipalVariation,
} from "@react-chess-tools/react-chess-stockfish";
import { useState } from "react";

function ClickableLines() {
  const [selectedLine, setSelectedLine] = useState<PrincipalVariation | null>(
    null,
  );

  const handleLineClick = (rank: number, pv: PrincipalVariation) => {
    setSelectedLine(pv);
    console.log(`Clicked line ${rank}`);
  };

  return (
    <div>
      <ChessStockfish.Root
        fen="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
        config={{ multiPV: 3 }}
        workerOptions={{ workerPath: "/stockfish.js" }}
      >
        <ChessStockfish.EngineLines
          maxLines={3}
          onLineClick={handleLineClick}
        />
      </ChessStockfish.Root>

      {selectedLine && (
        <div className="selected-line">
          <h3>Line {selectedLine.rank}</h3>
          <p>{selectedLine.moves.map((m) => m.san).join(" ")}</p>
        </div>
      )}
    </div>
  );
}

Custom Styled Evaluation Bar

import { ChessStockfish } from "@react-chess-tools/react-chess-stockfish";

function CustomEvalBar() {
  return (
    <ChessStockfish.Root
      fen="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
      workerOptions={{ workerPath: "/stockfish.js" }}
    >
      <ChessStockfish.EvaluationBar
        className="custom-eval-bar"
        orientation="horizontal"
        perspective="w"
        showEvaluation={true}
      />
    </ChessStockfish.Root>
  );
}
.custom-eval-bar {
  width: 100%;
  height: 16px;
  background: #e0e0e0;
  border-radius: 8px;
  position: relative;
  overflow: hidden;
}

.custom-eval-bar [data-stockfish-fill] {
  position: absolute;
  inset: 0;
  border-radius: 8px;
}

/* White perspective - fill from left */
.custom-eval-bar[data-stockfish-perspective="w"] [data-stockfish-fill] {
  background: linear-gradient(to right, #2ecc71, #27ae60);
  transform-origin: left;
}

/* Black perspective - fill from right */
.custom-eval-bar[data-stockfish-perspective="b"] [data-stockfish-fill] {
  background: linear-gradient(to left, #e74c3c, #c0392b);
  transform-origin: right;
}

License

This project is MIT licensed.

Show Your Support

Give a star if this project helped you!