📖 Writing Sample — No Starch Press Proposal

Mobile-First JavaScript Games
From Arcade to Grandmaster

A project-based journey through 10 games — built with pure modern JavaScript (ES6+ through ES2024+), zero frameworks, and mobile-first design principles.

📱 Mobile-First Architecture ♟️ Minimax AI Engine 🔒 ES2024 Private Fields 🧠 Alpha-Beta Pruning 📊 Piece-Square Tables Object.groupBy() 📦 Zero Dependencies

Author: Francisco Perez  |  Portfolio: drfperez.github.io  |  Experience: 30+ years CS education  |  Scientix Ambassador 🇪🇺

⬇ View Both Chess Demos

📋 Book Proposal Summary

Mobile-First JavaScript Games guides intermediate developers through building 10 scalable, mobile-ready games from scratch using native modern JavaScript (ES6+ to ES2024+) — with absolutely no heavy frameworks or external engines. Every project is built mobile-first: touch APIs, viewport scaling, gesture handling, and performance-conscious design are woven into every chapter.

💡 Key differentiator: This book doesn't recycle old code. It teaches cutting-edge language features — private class fields (#), Object.groupBy(), immutable array methods like toReversed() and toSpliced(), logical assignment operators (||=, &&=), structuredClone(), and Top-Level Await — all in the context of real, playable games that run on any smartphone browser.

📚 Chapter Outline (10 Games)

Ch1: Galactic Clicker ES6+
Ch2: Retro Pong ES6+
Ch3: Snake ES2023+
Ch4: Card Memory ES2024
Ch5: Flappy Clone ES6+
Ch6: Space Invaders ES2022+
Ch7: 2D Platformer ES2024
Ch8: Checkers ES2023+
Ch9: ♞ Chess ES2024+
Ch10: Go ES2024+

Outro: Progressive Web Apps (PWAs) — Top-Level Await, Service Workers, offline caching, installable apps.

📦 Complete Source Code — Available on GitHub

Both chess implementations featured in this writing sample are fully open-source. Clone, fork, and explore the code — from the basic random-move engine to the full minimax AI with alpha-beta pruning and piece-square positional tables.

🔗 github.com/drfperez/chess-basic  |  🔗 github.com/drfperez/chess-minimax

✍️

Writing Sample — Chapter 9: Chess (Advanced Rules & AI)

Below is a complete didactic walkthrough of the chess engine that would appear in Chapter 9 of the book. It covers two versions — a basic random-move AI (for introducing turn-based logic and rule validation) and an advanced minimax engine with alpha-beta pruning (for teaching recursion, tree search, and positional evaluation). Both versions use modern ES2024+ JavaScript throughout: private class fields, Object.groupBy(), logical assignment operators, and more.

📖 Pedagogical approach: The book introduces the basic version first so readers understand the chess rules engine. Then it layers on minimax, alpha-beta pruning, and piece-square tables — each concept explained in isolation before combining them into the full engine below.
1

Project Setup & ES6 Import Map

We use a browser-native import map to load the chess.js library directly from a CDN as an ES6 module — zero bundler, zero configuration. This keeps the setup lightweight and teaches students how modern browsers natively resolve module specifiers.

<script type="importmap">
        {
        "imports": {
        "chess.js": "https://esm.sh/chess.js@0.12.1"
        }
        }
    </script>
<script type="module">
    import { Chess } from 'chess.js';
</script>
2

HTML Structure — The 8×8 Grid Board

The board is a CSS Grid with 64 dynamically-generated squares. Each square carries a data-square attribute using standard algebraic notation (e.g., "e4"). Squares are also made draggable for seamless touch and mouse interaction.

.board {
        display: grid;
        grid-template-columns: repeat(8, 1fr);
        width: min(70vw, 70vh, 560px);
        height: min(70vw, 70vh, 560px);
    }
3

ModernChess Class — Private Fields (ES2022+)

All game state is encapsulated using true private fields (the # prefix). This teaches students proper encapsulation — no leaked internal state, no accidental external mutations. The #aiSearchDepth field controls how many plies the minimax engine searches ahead.

class ModernChess {
        // True private fields — inaccessible from outside the class
        #game;
        #boardElement;
        #selectedSquare = null;
        #legalMovesForSelected = [];
        #aiSearchDepth = 3;  // Configurable search depth
    }
4

Piece-Square Positional Tables

Each piece type has an 8×8 centipawn table encoding decades of chess knowledge. Knights thrive in the centre (+20), rooks dominate open files, and kings seek shelter after castling. These values are added to the base material value of each piece during board evaluation.

const KNIGHT_TABLE = [
        [-50,-40,-30,-30,-30,-30,-40,-50],
        [-40,-20,  0,  0,  0,  0,-20,-40],
        [-30,  0, 10, 15, 15, 10,  0,-30],
        [-30,  5, 15, 20, 20, 15,  5,-30],
        [-30,  0, 15, 20, 20, 15,  0,-30],
        [-30,  5, 10, 15, 15, 10,  5,-30],
        [-40,-20,  0,  5,  5,  0,-20,-40],
        [-50,-40,-30,-30,-30,-30,-40,-50]
    ];
    // "Knights on the rim are grim" — corners penalised at -50
// Central squares (d4,e4,d5,e5) reward +20 for knight activity
5

Board Evaluation — Material + Position

The #getPieceValue() method combines base material values (pawn=100, knight=320, bishop=330, rook=500, queen=900, king=20000) with the positional bonus from the corresponding piece-square table. The evaluation is asymmetric: from Black's (AI's) perspective, positive means good for Black, negative means good for White.

#getPieceValue(piece, x, y) {
        const baseValues = { p: 100, n: 320, b: 330, r: 500, q: 900, k: 20000 };
        let value = baseValues[piece.type] ?? 0;
        let positionalBonus = 0;
        if (piece.type === 'n') positionalBonus = KNIGHT_TABLE[x][y];
        // ... same pattern for all piece types
        return piece.color === 'b' ? (value + positionalBonus) : -(value + positionalBonus);
    }
6

ES2024: Object.groupBy() for Piece Classification

The Object.groupBy() static method (new in ES2024) splits all pieces on the board into white and black groups in a single call. This replaces manual loops and demonstrates how modern JavaScript simplifies data classification tasks.

const flatBoard = this.#game.board().flat().filter(Boolean);
// ES2024: group all pieces by color in one elegant call
const piecesGrouped = Object.groupBy(flatBoard, piece => piece.color);
// Result: { w: [white pieces], b: [black pieces] }
7

Minimax Algorithm — Core Concept

Minimax is the foundational algorithm for two-player zero-sum games. The AI assumes both players play optimally: the maximising player (Black/AI) tries to maximise the score, while the minimising player (White/human) tries to minimise it. The algorithm recursively explores the game tree up to a fixed depth.

#minimax(depth, alpha, beta, isMaximizing) {
        if (depth === 0 || this.#game.game_over()) return this.#evaluateBoard();
        const moves = this.#game.moves({ verbose: true });
        if (isMaximizing) {
            let maxEval = -Infinity;
            for (const move of moves) {
                this.#game.move(move);
                let evaluation = this.#minimax(depth - 1, alpha, beta, false);
                this.#game.undo();
                maxEval = Math.max(maxEval, evaluation);
            }
            return maxEval;
        }
        // Minimising player — symmetric, uses Math.min
    }
8

Alpha-Beta Pruning — Cutting the Search Tree

Alpha-beta pruning dramatically reduces the number of evaluated nodes. It tracks two bounds — alpha (best for maximiser) and beta (best for minimiser) — and prunes entire branches when they can't influence the final decision. This cuts the effective branching factor from ~35 to roughly √35 ≈ 6.

// Inside the maximising loop:
alpha = Math.max(alpha, evaluation);
if (beta <= alpha) break;  // Beta cutoff — prune this branch!

// Inside the minimising loop:
beta = Math.min(beta, evaluation);
if (beta <= alpha) break;  // Alpha cutoff — prune!
Impact: Without pruning, depth-3 from the starting position evaluates ~42,000 nodes. With alpha-beta, it drops to ~5,000–8,000 — an 80%+ reduction — while returning the exact same best move.
9

ES2024: Logical Assignment (||=)

The #showMessage method uses the logical OR assignment operator (||=), another ES2024 feature. It assigns a default value only if the left-hand side is falsy — a clean, one-line pattern for default parameters.

#showMessage(msg, bgColor) {
        bgColor ||= "#ff4757dd";  // ES2024: assign default if falsy
        const errDiv = document.getElementById('errorMsg');
        errDiv.textContent = msg;
        errDiv.style.background = bgColor;
        // Auto-dismiss after timeout
    }
10

Piece-Square Table Summary

A quick-reference guide to the centipawn values driving the AI's positional decisions:

PieceBest SquaresWorst SquaresStrategic Insight
Pawnd4/e4 (+30)a3/h3 (-20)Central pawns dominate
Knightd4–e5 (+20)Corners (-50)Centre control is critical
BishopLong diagonals (+10)Corners (-20)Open diagonals = power
Rook7th rank (+10)Starting squares (-5)Open files & 7th rank
QueenCentre (+5)Corners (-20)Don't develop too early
KingCastled (+30)Centre (-50)Safety first, then activate
🎮 LIVE WRITING SAMPLES

Two Versions — Basic & Advanced AI

Left: Basic random-move AI (Chapter introduction)  |  Right: Full minimax engine with alpha-beta pruning (Chapter climax)

📗 Basic Version — Random AI

ES6 Modules · Click/Drag · Random Black moves

🔗 github.com/drfperez/chess-basic

📘 Advanced Version — Minimax AI

Alpha-Beta Pruning · Piece-Square Tables · ES2024+

🔗 github.com/drfperez/chess-minimax

📖 This writing sample demonstrates the pedagogical style of Chapter 9.
The full book covers 10 games, each introducing progressively advanced JavaScript features and computer science concepts — all built mobile-first, with zero frameworks, and running natively on any modern smartphone browser.

✉️ Contact: Francisco Perez  |  drfperez.github.io  |  Scientix Ambassador 🇪🇺  |  30+ years CS education