How to use board-gui.js library

This page demonstrates the smallest working setup for the BoardGui widget: just board.css, xiangqi.js and board-gui.js. View the page source for a copy-pasteable starting point. The non-minified versions of the JS and CSS files are accessible if you just removed the ".min" from the URLs, so you can also check the implementation details.

If you only need in-memory functions (e.g. validating if a FEN is correct), you can use xiangqi.js without the GUI. board-gui.js only provides the visual board and user interaction, but it relies on xiangqi.js for all the game logic (for examples list legal moves). board-gui.js requires board.css.

The images (pieces) and sound assets are resolved from https://cdn.elephantchess.io/static by default, but you can also specify a custom base URL in assetsBaseUrl when initializing the BoardGui and copy the assets to be served by your own server. Pieces can be downloaded from https://cdn.elephantchess.io/static/pieces.zip.

Minimal Setup

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8"/>
  <title>Setup</title>
  <link rel="stylesheet" href="https://cdn.elephantchess.io/dist/0.1.1/board.min.css">
  <script defer src="https://cdn.elephantchess.io/dist/0.1.1/xiangqi.min.js"></script>
  <script defer src="https://cdn.elephantchess.io/dist/0.1.1/board-gui.min.js"></script>
</head>
<body>
<div id="board-container" class="board-container"></div>
<script>
  window.addEventListener('load', () => {
      const boardGui = new BoardGui({
            elementId: 'board-container'// defaults to #board-container
        });
      boardGui.loadFen(DEFAULT_START_FEN);
  });
</script>
</body>
</html>

Default Configuration

There are many parameters that can be overridden. Here are the default values:

/**
 * How file numbers are rendered around the board in WXF mode. Only affects the
 * file-number labels; the algebraic orientation (a..i letters) is unaffected.
 */
const FileNumbersStyle = Object.freeze({
    ARABIC_BOTH: 'ARABIC_BOTH',
    CHINESE_BOTH: 'CHINESE_BOTH',
    CHINESE_RED_ONLY: 'CHINESE_RED_ONLY',
    CHINESE_BLACK_ONLY: 'CHINESE_BLACK_ONLY',
    CHINESE_LOWER_ONLY: 'CHINESE_LOWER_ONLY',
    CHINESE_TOP_ONLY: 'CHINESE_TOP_ONLY',
    DEFAULT: 'CHINESE_RED_ONLY',
});
/**
 * Visual style of the board pieces. Used to pick the corresponding image folder
 * (under `${assetsBaseUrl}/images/pieces/<style-lowercased>/`).
 */
const PieceStyleSetting = Object.freeze({
    TRADITIONAL: 'TRADITIONAL',
    ROMANIZED_ROUNDED: 'ROMANIZED_ROUNDED',
    DEFAULT: 'TRADITIONAL',
});
/**
 * @typedef {Object} BoardGuiOptions
 * @property {string}      [elementId]              - id of the container element
 * @property {boolean}     [showCoordinates]        - whether to reserve space for file/rank coordinates
 * @property {string|null} [coordinatesOrientation] - one of {@link CoordinatesOrientation} or `null` to
 *                                                    hide the labels (space is still reserved when
 *                                                    `showCoordinates` is true). The caller is in
 *                                                    charge of resolving any user preference (e.g. cookies).
 * @property {boolean}     [mini]                   - whether this is a mini (thumb) board
 * @property {boolean}     [forceRenderChecks]      - render checks even on mini boards
 * @property {boolean}     [svg]                    - enable the SVG overlay (used for engine arrows)
 * @property {boolean}     [playSounds]             - whether board sounds are enabled
 * @property {string}      [assetsBaseUrl]          - base URL prepended to every static asset path
 *                                                    (images, audio). Default: `https://elephantchess.io`.
 *                                                    Pass an empty string to use relative paths (e.g. when
 *                                                    serving the assets from the current host on localhost).
 * @property {string}      [pieceStyle]             - one of {@link PieceStyleSetting}; selects the piece
 *                                                    image folder.
 * @property {boolean}     [colorblindFriendlyBlackPieces] - if true, black piece images get an invert
 *                                                    CSS filter for improved contrast.
 * @property {boolean}     [flipOpponentPieces]     - if true, opponent piece images are rotated
 *                                                    180° to simulate the OTB appearance.
 * @property {string}      [fileNumbersStyle]       - one of {@link FileNumbersStyle}; selects how
 *                                                    file numbers are rendered in WXF mode.
 */
/** @type {Readonly<Required<BoardGuiOptions>>} */
const DEFAULT_BOARD_GUI_OPTIONS = Object.freeze({
    elementId: 'board-container',
    showCoordinates: true,
    coordinatesOrientation: 'WXF',
    mini: false,
    forceRenderChecks: false,
    svg: false,
    playSounds: true,
    assetsBaseUrl: 'https://cdn.elephantchess.io/static',
    pieceStyle: PieceStyleSetting.DEFAULT,
    colorblindFriendlyBlackPieces: false,
    flipOpponentPieces: false,
    fileNumbersStyle: FileNumbersStyle.DEFAULT,
});

Using xiangqi.js without the GUI

If you only need the game logic in memory (e.g. validating a FEN, listing legal moves, detecting checkmate, etc.), you can use xiangqi.js on its own — no board-gui.js and no board.css required.

Open your browser console on this page and run the snippet below (the callback body of window.addEventListener); it prints the FEN and an ASCII representation of the board, plays two moves, and log the updated representation.

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Example</title>
  <meta charset="UTF-8"/>
  <script defer src="https://cdn.elephantchess.io/dist/0.1.1/xiangqi.min.js"></script>
</head>
<body>
<script>
  window.addEventListener('load', () => {
      // init
      const board = new Board();
      board.loadFen(DEFAULT_START_FEN);
      // logs the current FEN and position
      console.log(board.outputFen());
      board.printBoard();
      // play two moves
      board.registerMove(HalfMove.parseUci('h2e2')); // C2=5
      board.registerMove(HalfMove.parseUci('h9g7')); // H8+7
      // logs the current FEN and position after the moves
      console.log(board.outputFen());
      board.printBoard();
  });
</script>
</body>
</html>

Expected console output

rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w - - 0 0
   a b c d e f g h i
9  r n b a k a b n r
8                   
7    c           c  
6  p   p   p   p   p
5                   
4
2    C           C  
1                   
0  R N B A K A B N R
rnbakab1r/9/1c4nc1/p1p1p1p1p/9/9/P1P1P1P1P/1C2C4/9/RNBAKABNR w - - 0 1
   a b c d e f g h i
9  r n b a k a b   r
8                   
7    c         n c  
6  p   p   p   p   p
5                   
4                   
3  P   P   P   P   P
2    C     C        
1                   
0  R N B A K A B N R

A few useful entry points exposed by xiangqi.js:

Manchu chess (Yitong) variant

xiangqi.js also supports the Manchu (or Yitong) variant. In this variant, Red plays with a single super-chariot (FEN char M) at a1 instead of the usual chariots, horses and cannons. The super-chariot combines the movement powers of chariot, horse and cannon.

Use the constant MANCHU_START_FEN to load the Manchu starting position:

boardGui.loadFen(MANCHU_START_FEN);

All legal-move and checkmate logic automatically handles the super-chariot, so no extra configuration is needed.