Chess PGN Viewer

PGN Viewer
HTML5 Application

PGN Viewer

This application provides a modern, offline-first experience for viewing and analyzing chess games stored in the Portable Game Notation (PGN) format. It’s built as a Progressive Web Application (PWA), leveraging a robust template that includes features like internationalization, common UI components based on Bootstrap 5, and seamless cloud synchronization via Dropbox.

A live version of the app is available here, and the full code on GitHub here.

Core features

  • PGN Loading & Parsing: Load PGN files easily through direct text input, file import from your device, or automatically via Dropbox sync. The application parses standard PGN files, including those with multiple games, using libraries like chess.js.

// Example: Loading PGN data (from game-logic.js)
import { Chess } from './lib/chess-1.2.0.min.js';
// ...
export function loadPgn(pgnString) {
  // ...
  try {
    chess = new Chess();
    chess.loadPgn(pgnString);
    initialFen = chess.getHeaders().FEN || new Chess().fen();
    moveHistory = chess.history({ verbose: true }) || [];
    currentMoveIndex = -1;
    return true;
  } catch (error) {
    console.error(`Error loading PGN: ${error}`);
    initializeGame(); // Reset to default state on error
    return false;
  }
}
  • Interactive Chessboard: View the current game position on a clean, interactive chessboard rendered dynamically based on the FEN (Forsyth–Edwards Notation) of the current position.

// Example: Rendering the board (from board-ui.js)
export function renderBoard(boardContainer, fen) {
  // ... clear previous board ...
  // ... parse FEN piece placement ...
  rankIteration.forEach((fenRank, rankIndex) => {
    // ... iterate through rank characters ...
    if (isNaN(parseInt(char, 10))) { // It's a piece
      const algebraic = indicesToAlgebraic(rankIndex, currentFileIndex);
      const square = createSquareElement(rankIndex, currentFileIndex, algebraic);
      const pieceData = pieceMap[char];
      if (pieceData) {
        const pieceImage = document.createElement('img');
        pieceImage.src = `${getCurrentPieceImagePath()}${pieceData}`;
        // ... add piece to square ...
      }
      boardGrid.appendChild(square);
      currentFileIndex++;
    } else { // It's empty squares
      // ... create empty squares ...
    }
  });
  boardContainer.appendChild(boardGrid);
}

* Supports standard piece sets and allows cycling through different visual styles.
* Flip the board orientation (White/Black at the bottom) with a single click.
  • Game Navigation: Step through games move-by-move using intuitive controls (First, Previous, Next, Last). You can also click directly on a move in the notation to jump to that position.

// Example: Navigating moves (from game-logic.js)
export function goToNextMove() {
  if (currentMoveIndex >= moveHistory.length - 1) return null;
  return goToMoveIndex(currentMoveIndex + 1);
}

export function goToMoveIndex(index) {
  // ... reset board to initial FEN ...
  for (let i = 0; i <= index; i++) {
    if (!chess.move(moveHistory[i].san)) return null; // Apply moves up to index
  }
  currentMoveIndex = index;
  return chess.fen(); // Return FEN of the target position
}
  • PGN Data Display: Clearly displays essential PGN headers (White, Black, Result, Event, Date) and the full game notation, including comments. The current move is highlighted in the notation list.
  • File Management: Manage your PGN files directly within the app using the sidebar. Add new files, rename existing ones, or delete them.

PWA & Dropbox integration

Built upon a flexible PWA template, this viewer offers:

  • Offline Access: Thanks to service workers caching application assets, you can view loaded games even without an internet connection.

// Example: Service Worker registration (from index.html)
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service-worker.js', { scope: '/' })
      .catch(error => console.error('Service Worker registration failed:', error));
}
  • Dropbox Synchronization: Connect your Dropbox account to automatically sync your PGN files. Changes made in the app are saved to Dropbox, and files updated elsewhere appear in the app. The system includes conflict resolution to handle cases where a file is modified in multiple places simultaneously.

// Example: Initializing Dropbox Sync (from dropbox-sync.js)
async function initializeDropboxSync() {
  logVerbose('Initializing Dropbox Sync System...');
  initializeSyncCoordinator(); // Handles sync logic
  initializeOfflineHandling(); // Manages online/offline state changes
  await initializeAuthentication(); // Handles login and token management
  // ...
}

This PGN viewer combines standard chess game viewing functionalities with the convenience of a modern web application, accessible anywhere, anytime, even offline, with optional cloud backup and sync. The source code is publicly available on GitHub for those interested in the technical details.

Go to the top of the page