JavaScript Integration For Chess Mérida Font Displays

Learning Lab
My Journey Through Books, Discoveries, and Ideas

JavaScript integration for chess Mérida font displays

In my previous post here, I discussed using the Chess Mérida font and specific CSS to manually create HTML representations of chess boards. While effective, this method requires constructing the board string character by character. To streamline this, I developed a JavaScript solution that automatically generates the board HTML from a standard Forsyth–Edwards Notation (FEN) string.

Automating Board Generation with FEN

The idea is to simply provide the FEN string, which compactly describes a chess position, and let JavaScript handle the translation into the Merida font glyphs and HTML structure.

HTML Setup for JavaScript

To use the script, I define a placeholder div element in my HTML. This div needs the chessboard-merida-js class and a data-fen attribute containing the FEN string for the desired position. Two optional data attributes control how the board is drawn:

  • data-orientation: "white" (default) or "black", to flip the board.
  • data-coordinates: "true" to show rank/file labels on the border, omitted or "false" for a plain border.

Both attributes are read case-insensitively, so "BLACK" or "TRUE" work just as well as their lowercase forms.



<div class="chessboard-merida-js"
     data-fen="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
     data-orientation="black"
     data-coordinates="true">
  
</div>


<div class="chessboard-merida-js"
     data-fen="r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -">
  
</div>

The JavaScript targets the chessboard-merida-js class, reads the data-fen, data-orientation, and data-coordinates attributes, and replaces the div‘s content with the generated board.

JavaScript Logic Explained

The script performs the following steps:

  1. Initialization: It waits for the DOM to be fully loaded and then finds all elements with the class chessboard-merida-js.
  2. FEN Parsing: For each element found, it retrieves the FEN string from the data-fen attribute. It focuses on the first part of the FEN, which describes the piece placement, splitting it into 8 ranks (rows) and expanding each one into 8 explicit squares.
  3. Glyph Mapping: A mapping (FEN_TO_MERIDA_BASE) stores the base Merida character for each FEN piece type (e.g., ‘P’ maps to ‘p’, ‘n’ maps to ‘m’).

const FEN_TO_MERIDA_BASE = {
  'P': 'p', 'N': 'n', 'B': 'b', 'R': 'r', 'Q': 'q', 'K': 'k', // White bases
  'p': 'o', 'n': 'm', 'b': 'v', 'r': 't', 'q': 'w', 'k': 'l'  // Black bases
};
  1. Square Color Determination: A helper function requiresUppercaseMerida(rankIndex, fileIndex) determines if a square at a given position (0-indexed rank and file) corresponds to a “black” square on the board. This is needed because Merida uses different glyphs (lowercase vs. uppercase) for pieces on light versus dark squares. It calculates this based on the sum of the standard board rank (1-8) and file index (0-7).

function requiresUppercaseMerida(rankIndex, fileIndex) {
  const boardRank = 7 - rankIndex; // Convert FEN rank index to board rank
  return (boardRank + fileIndex) % 2 === 0; // True for dark squares
}
  1. Piece Glyph Generation: The getPieceChar(fenChar, rankIndex, fileIndex) function takes the FEN character for a piece and its position. It finds the base Merida glyph using the map and then converts it to uppercase if requiresUppercaseMerida returns true.
  2. Empty Square Handling: FEN uses digits (1-8) to denote consecutive empty squares. The script parses these digits and uses another helper function getEmptySquareChar(rankIndex, fileIndex) to determine the correct Merida character for an empty square (‘*’ for light, ‘+’ for dark) based on its position.
  3. Coordinate Glyphs: Rather than hardcoding a full set of border strings for every orientation, the coordinate glyphs are generated from two small base arrays — one for rank labels (8→1) and one for file labels (a→h), as seen from White’s side. The black-orientation versions are simply the reverse of these arrays, so flipping the board doesn’t require any duplicated data.

const RANK_CHARS = ['«', '∆', '≈', 'ƒ', '√', '¬', '¡', '¿'];
const FILE_CHARS = ['»', '…', 'Ú', 'À', 'Ã', 'Õ', 'Œ', 'œ'];

const COORD_LEFT = {
  white: RANK_CHARS,
  black: [...RANK_CHARS].reverse()
};

const COORD_BOTTOM = {
  white: `7${FILE_CHARS.join('')}9`,
  black: `7${[...FILE_CHARS].reverse().join('')}9`
};
  1. HTML Construction: The main function renderChessboard(element) reads the orientation to decide the rank and file iteration order, then walks through each rank and each square, calling getPieceChar/getEmptySquareChar as appropriate and building the HTML string for each rank (<div class="rank">...</div>). The left edge of each row and the bottom border use either the plain border characters or the coordinate glyphs, depending on data-coordinates.
  2. Board Injection: Finally, it adds the top and bottom border strings, joins all the HTML parts, and sets the innerHTML of the original placeholder div. It also updates the element’s classes, removing the JS hook (chessboard-merida-js) and adding the standard chessboard-merida class for styling.

function renderChessboard(element) {
  const fen = element.dataset.fen;
  const orientation = (element.dataset.orientation || '').toLowerCase() === 'black' ? 'black' : 'white';
  const showCoordinates = (element.dataset.coordinates || '').toLowerCase() === 'true';
  // ... (FEN parsing, board setup) ...

  const html = [];
  html.push(`<div class="rank">${BORDER_TOP}</div>`); // Add top border

  rankOrder.forEach((boardRankIndex, displayRankIndex) => {
    // ... (Loop through squares, call getPieceChar/getEmptySquareChar) ...
    // ... (Build row string, using COORD_LEFT or BORDER_LEFT on the left edge) ...
    html.push(row);
  });

  html.push(`<div class="rank">${showCoordinates ? COORD_BOTTOM[orientation] : BORDER_BOTTOM}</div>`); // Add bottom border

  element.innerHTML = html.join(''); // Set the generated HTML
  element.classList.remove('chessboard-merida-js');
  element.classList.add('chessboard-merida'); // Apply standard styling class
}

This script allows me to easily insert chess diagrams anywhere on my site just by adding a simple div with the FEN data, and to control orientation and coordinates with a couple of optional attributes.

Here are some examples:

For more insights into this topic, you can find the details here.