chess-snap 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +145 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.js +23 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +99 -0
- package/dist/renderer.d.ts +10 -0
- package/dist/renderer.js +145 -0
- package/dist/src/config.d.ts +11 -0
- package/dist/src/config.js +23 -0
- package/dist/src/index.d.ts +43 -0
- package/dist/src/index.js +99 -0
- package/dist/src/renderer.d.ts +10 -0
- package/dist/src/renderer.js +145 -0
- package/dist/src/types.d.ts +27 -0
- package/dist/src/types.js +1 -0
- package/dist/types.d.ts +27 -0
- package/dist/types.js +1 -0
- package/package.json +51 -0
- package/src/assets/pieces/alpha/BlackBishop.png +0 -0
- package/src/assets/pieces/alpha/BlackKing.png +0 -0
- package/src/assets/pieces/alpha/BlackKnight.png +0 -0
- package/src/assets/pieces/alpha/BlackPawn.png +0 -0
- package/src/assets/pieces/alpha/BlackQueen.png +0 -0
- package/src/assets/pieces/alpha/BlackRook.png +0 -0
- package/src/assets/pieces/alpha/WhiteBishop.png +0 -0
- package/src/assets/pieces/alpha/WhiteKing.png +0 -0
- package/src/assets/pieces/alpha/WhiteKnight.png +0 -0
- package/src/assets/pieces/alpha/WhitePawn.png +0 -0
- package/src/assets/pieces/alpha/WhiteQueen.png +0 -0
- package/src/assets/pieces/alpha/WhiteRook.png +0 -0
- package/src/assets/pieces/cburnett/BlackBishop.png +0 -0
- package/src/assets/pieces/cburnett/BlackKing.png +0 -0
- package/src/assets/pieces/cburnett/BlackKnight.png +0 -0
- package/src/assets/pieces/cburnett/BlackPawn.png +0 -0
- package/src/assets/pieces/cburnett/BlackQueen.png +0 -0
- package/src/assets/pieces/cburnett/BlackRook.png +0 -0
- package/src/assets/pieces/cburnett/WhiteBishop.png +0 -0
- package/src/assets/pieces/cburnett/WhiteKing.png +0 -0
- package/src/assets/pieces/cburnett/WhiteKnight.png +0 -0
- package/src/assets/pieces/cburnett/WhitePawn.png +0 -0
- package/src/assets/pieces/cburnett/WhiteQueen.png +0 -0
- package/src/assets/pieces/cburnett/WhiteRook.png +0 -0
- package/src/assets/pieces/cheq/BlackBishop.png +0 -0
- package/src/assets/pieces/cheq/BlackKing.png +0 -0
- package/src/assets/pieces/cheq/BlackKnight.png +0 -0
- package/src/assets/pieces/cheq/BlackPawn.png +0 -0
- package/src/assets/pieces/cheq/BlackQueen.png +0 -0
- package/src/assets/pieces/cheq/BlackRook.png +0 -0
- package/src/assets/pieces/cheq/WhiteBishop.png +0 -0
- package/src/assets/pieces/cheq/WhiteKing.png +0 -0
- package/src/assets/pieces/cheq/WhiteKnight.png +0 -0
- package/src/assets/pieces/cheq/WhitePawn.png +0 -0
- package/src/assets/pieces/cheq/WhiteQueen.png +0 -0
- package/src/assets/pieces/cheq/WhiteRook.png +0 -0
- package/src/assets/pieces/game_room/BlackBishop.png +0 -0
- package/src/assets/pieces/game_room/BlackKing.png +0 -0
- package/src/assets/pieces/game_room/BlackKnight.png +0 -0
- package/src/assets/pieces/game_room/BlackPawn.png +0 -0
- package/src/assets/pieces/game_room/BlackQueen.png +0 -0
- package/src/assets/pieces/game_room/BlackRook.png +0 -0
- package/src/assets/pieces/game_room/WhiteBishop.png +0 -0
- package/src/assets/pieces/game_room/WhiteKing.png +0 -0
- package/src/assets/pieces/game_room/WhiteKnight.png +0 -0
- package/src/assets/pieces/game_room/WhitePawn.png +0 -0
- package/src/assets/pieces/game_room/WhiteQueen.png +0 -0
- package/src/assets/pieces/game_room/WhiteRook.png +0 -0
- package/src/assets/pieces/game_room_gothic/BlackBishop.png +0 -0
- package/src/assets/pieces/game_room_gothic/BlackKing.png +0 -0
- package/src/assets/pieces/game_room_gothic/BlackKnight.png +0 -0
- package/src/assets/pieces/game_room_gothic/BlackPawn.png +0 -0
- package/src/assets/pieces/game_room_gothic/BlackQueen.png +0 -0
- package/src/assets/pieces/game_room_gothic/BlackRook.png +0 -0
- package/src/assets/pieces/game_room_gothic/WhiteBishop.png +0 -0
- package/src/assets/pieces/game_room_gothic/WhiteKing.png +0 -0
- package/src/assets/pieces/game_room_gothic/WhiteKnight.png +0 -0
- package/src/assets/pieces/game_room_gothic/WhitePawn.png +0 -0
- package/src/assets/pieces/game_room_gothic/WhiteQueen.png +0 -0
- package/src/assets/pieces/game_room_gothic/WhiteRook.png +0 -0
- package/src/assets/pieces/game_room_space/BlackBishop.png +0 -0
- package/src/assets/pieces/game_room_space/BlackKing.png +0 -0
- package/src/assets/pieces/game_room_space/BlackKnight.png +0 -0
- package/src/assets/pieces/game_room_space/BlackPawn.png +0 -0
- package/src/assets/pieces/game_room_space/BlackQueen.png +0 -0
- package/src/assets/pieces/game_room_space/BlackRook.png +0 -0
- package/src/assets/pieces/game_room_space/WhiteBishop.png +0 -0
- package/src/assets/pieces/game_room_space/WhiteKing.png +0 -0
- package/src/assets/pieces/game_room_space/WhiteKnight.png +0 -0
- package/src/assets/pieces/game_room_space/WhitePawn.png +0 -0
- package/src/assets/pieces/game_room_space/WhiteQueen.png +0 -0
- package/src/assets/pieces/game_room_space/WhiteRook.png +0 -0
- package/src/assets/pieces/glass/BlackBishop.png +0 -0
- package/src/assets/pieces/glass/BlackKing.png +0 -0
- package/src/assets/pieces/glass/BlackKnight.png +0 -0
- package/src/assets/pieces/glass/BlackPawn.png +0 -0
- package/src/assets/pieces/glass/BlackQueen.png +0 -0
- package/src/assets/pieces/glass/BlackRook.png +0 -0
- package/src/assets/pieces/glass/WhiteBishop.png +0 -0
- package/src/assets/pieces/glass/WhiteKing.png +0 -0
- package/src/assets/pieces/glass/WhiteKnight.png +0 -0
- package/src/assets/pieces/glass/WhitePawn.png +0 -0
- package/src/assets/pieces/glass/WhiteQueen.png +0 -0
- package/src/assets/pieces/glass/WhiteRook.png +0 -0
- package/src/assets/pieces/leipzig/BlackBishop.png +0 -0
- package/src/assets/pieces/leipzig/BlackKing.png +0 -0
- package/src/assets/pieces/leipzig/BlackKnight.png +0 -0
- package/src/assets/pieces/leipzig/BlackPawn.png +0 -0
- package/src/assets/pieces/leipzig/BlackQueen.png +0 -0
- package/src/assets/pieces/leipzig/BlackRook.png +0 -0
- package/src/assets/pieces/leipzig/WhiteBishop.png +0 -0
- package/src/assets/pieces/leipzig/WhiteKing.png +0 -0
- package/src/assets/pieces/leipzig/WhiteKnight.png +0 -0
- package/src/assets/pieces/leipzig/WhitePawn.png +0 -0
- package/src/assets/pieces/leipzig/WhiteQueen.png +0 -0
- package/src/assets/pieces/leipzig/WhiteRook.png +0 -0
- package/src/assets/pieces/merida/BlackBishop.png +0 -0
- package/src/assets/pieces/merida/BlackKing.png +0 -0
- package/src/assets/pieces/merida/BlackKnight.png +0 -0
- package/src/assets/pieces/merida/BlackPawn.png +0 -0
- package/src/assets/pieces/merida/BlackQueen.png +0 -0
- package/src/assets/pieces/merida/BlackRook.png +0 -0
- package/src/assets/pieces/merida/WhiteBishop.png +0 -0
- package/src/assets/pieces/merida/WhiteKing.png +0 -0
- package/src/assets/pieces/merida/WhiteKnight.png +0 -0
- package/src/assets/pieces/merida/WhitePawn.png +0 -0
- package/src/assets/pieces/merida/WhiteQueen.png +0 -0
- package/src/assets/pieces/merida/WhiteRook.png +0 -0
- package/src/assets/pieces/neo/BlackBishop.png +0 -0
- package/src/assets/pieces/neo/BlackKing.png +0 -0
- package/src/assets/pieces/neo/BlackKnight.png +0 -0
- package/src/assets/pieces/neo/BlackPawn.png +0 -0
- package/src/assets/pieces/neo/BlackQueen.png +0 -0
- package/src/assets/pieces/neo/BlackRook.png +0 -0
- package/src/assets/pieces/neo/WhiteBishop.png +0 -0
- package/src/assets/pieces/neo/WhiteKing.png +0 -0
- package/src/assets/pieces/neo/WhiteKnight.png +0 -0
- package/src/assets/pieces/neo/WhitePawn.png +0 -0
- package/src/assets/pieces/neo/WhiteQueen.png +0 -0
- package/src/assets/pieces/neo/WhiteRook.png +0 -0
- package/src/assets/pieces/neo_wood/BlackBishop.png +0 -0
- package/src/assets/pieces/neo_wood/BlackKing.png +0 -0
- package/src/assets/pieces/neo_wood/BlackKnight.png +0 -0
- package/src/assets/pieces/neo_wood/BlackPawn.png +0 -0
- package/src/assets/pieces/neo_wood/BlackQueen.png +0 -0
- package/src/assets/pieces/neo_wood/BlackRook.png +0 -0
- package/src/assets/pieces/neo_wood/WhiteBishop.png +0 -0
- package/src/assets/pieces/neo_wood/WhiteKing.png +0 -0
- package/src/assets/pieces/neo_wood/WhiteKnight.png +0 -0
- package/src/assets/pieces/neo_wood/WhitePawn.png +0 -0
- package/src/assets/pieces/neo_wood/WhiteQueen.png +0 -0
- package/src/assets/pieces/neo_wood/WhiteRook.png +0 -0
- package/src/assets/pieces/wood/BlackBishop.png +0 -0
- package/src/assets/pieces/wood/BlackKing.png +0 -0
- package/src/assets/pieces/wood/BlackKnight.png +0 -0
- package/src/assets/pieces/wood/BlackPawn.png +0 -0
- package/src/assets/pieces/wood/BlackQueen.png +0 -0
- package/src/assets/pieces/wood/BlackRook.png +0 -0
- package/src/assets/pieces/wood/WhiteBishop.png +0 -0
- package/src/assets/pieces/wood/WhiteKing.png +0 -0
- package/src/assets/pieces/wood/WhiteKnight.png +0 -0
- package/src/assets/pieces/wood/WhitePawn.png +0 -0
- package/src/assets/pieces/wood/WhiteQueen.png +0 -0
- package/src/assets/pieces/wood/WhiteRook.png +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# ⚡ chess-snap 📸
|
|
2
|
+
|
|
3
|
+
> A blazing fast, zero-dependency Node.js chess image generator powered by Napi-RS. Convert FEN, PGN, and board arrays into highly customizable, pixel-perfect PNGs, JPEGs, and WEBPs instantly.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
## 📋 Table of Contents
|
|
11
|
+
- [🌟 Features](#-features)
|
|
12
|
+
- [⚙️ Requirements](#-requirements)
|
|
13
|
+
- [📦 Installation](#-installation)
|
|
14
|
+
- [🚀 Quick Start](#-quick-start)
|
|
15
|
+
- [Generating an Image from FEN](#generating-an-image-from-fen)
|
|
16
|
+
- [Generating it directly into a Buffer](#generating-it-directly-into-a-buffer)
|
|
17
|
+
- [🎨 Configuration Reference](#-configuration-reference)
|
|
18
|
+
- [📚 Piece Styles (Themes)](#-piece-styles-themes)
|
|
19
|
+
- [🧩 API Reference](#-api-reference)
|
|
20
|
+
- [⚠️ Important Notes](#-important-notes)
|
|
21
|
+
- [📝 License](#-license)
|
|
22
|
+
|
|
23
|
+
## 🌟 Features
|
|
24
|
+
- **Lightning Fast Native API**: Built purely on top of `@napi-rs/canvas`. Bypasses the traditional `node-canvas` Gyps compilation hassle completely on Windows/Linux/Mac.
|
|
25
|
+
- **Smart Memory Caching**: Re-architected rendering engine loads visual assets directly into RAM. Subsequent frame generations drop below *~1ms*. Extremely suitable for High-Traffic Discord Bots or real-time Web Servers.
|
|
26
|
+
- **Endless Customization**: Supports 12 premium piece themes (Neo, Merida, Game Room, Glass, Alpha...), custom HEX backgrounds, exact pixel scaling without loss of quality, and margin configurations.
|
|
27
|
+
- **Native Vector Notations**: Generate algebraic notations (A-H, 1-8). Supports Classic Margin placement (`outside`) or overlapping (`inside`) perfectly colored for visual contrast.
|
|
28
|
+
- **Multiple Output Formats**: Not only `png`, but exports seamlessly to lightweight formats like `jpeg` and `webp` bundled with adjustable `quality` compression controls.
|
|
29
|
+
|
|
30
|
+
## ⚙️ Requirements
|
|
31
|
+
To get the most out of `chess-snap` effortlessly, make sure your environment matches the following criteria:
|
|
32
|
+
- **Node.js**: Version 22.0.0 or higher native runtimes requested.
|
|
33
|
+
- **ES Modules**: Fully compatible with the modern JavaScript `import` ecosystem (`"type": "module"` natively mapped).
|
|
34
|
+
|
|
35
|
+
## 📦 Installation
|
|
36
|
+
Use your favorite package manager to install the dependency securely:
|
|
37
|
+
```bash
|
|
38
|
+
npm install chess-snap
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## 🚀 Quick Start
|
|
42
|
+
|
|
43
|
+
### Generating an Image from FEN
|
|
44
|
+
Here is a comprehensive example showing how to initialize the board, load a position via FEN, highlight specific squares, and save it as a high-quality JPEG wrapper.
|
|
45
|
+
|
|
46
|
+
```javascript
|
|
47
|
+
import ChessImageGenerator from 'chess-snap';
|
|
48
|
+
|
|
49
|
+
async function run() {
|
|
50
|
+
// 1. Initialize options
|
|
51
|
+
const generator = new ChessImageGenerator({
|
|
52
|
+
size: 600, // Total board dimension (600x600 pixels)
|
|
53
|
+
style: 'game_room', // Premium 3D piece styling suite
|
|
54
|
+
flipped: false, // Board perspective (false = White at bottom)
|
|
55
|
+
notations: true, // Draw algebraic coordinates
|
|
56
|
+
notationStyle: 'outside', // Render coordinates inside the classic outer margin
|
|
57
|
+
notationColor: '#CC0000', // (Optional) Explicitly override colored notation text
|
|
58
|
+
format: 'jpeg', // Output engine selection
|
|
59
|
+
quality: 85, // Image compression level (85%)
|
|
60
|
+
light: '#f0d9b5', // HEX background code for light squares
|
|
61
|
+
dark: '#b58863' // HEX background code for dark squares
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// 2. Load position state asynchronously (FEN)
|
|
65
|
+
await generator.loadFEN('r1bqkbnr/pppp1ppp/2n5/4p3/3PP3/5N2/PPP2PPP/RNBQKB1R w KQkq - 0 1');
|
|
66
|
+
|
|
67
|
+
// 3. Highlight significant moves targeting the board
|
|
68
|
+
generator.highlightSquares(['e4', 'e5', 'd4']);
|
|
69
|
+
|
|
70
|
+
// 4. Paint and stream directly onto the physical environment
|
|
71
|
+
await generator.generateImage('output-board.jpeg');
|
|
72
|
+
console.log('Great success!');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
run();
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Generating it directly into a Buffer
|
|
79
|
+
Perfectly streamlined for Express.js responses, Discord.js interaction attachments, and Serverless Edge functions. Bypasses disk-write overhead for absolute peak execution speed.
|
|
80
|
+
```javascript
|
|
81
|
+
import { AttachmentBuilder } from 'discord.js';
|
|
82
|
+
|
|
83
|
+
// Inside your bot command execution block...
|
|
84
|
+
await generator.loadPGN('1. e4 e5 2. Nf3 Nc6 3. Bc4');
|
|
85
|
+
const buffer = await generator.generateBuffer();
|
|
86
|
+
|
|
87
|
+
// Pipe it securely to Discord
|
|
88
|
+
const attachment = new AttachmentBuilder(buffer, { name: 'board.webp' });
|
|
89
|
+
await interaction.reply({ files: [attachment] });
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 🎨 Configuration Reference
|
|
93
|
+
When instantiating `new ChessImageGenerator(options)`, you can securely pass an object containing combinations of the following keys (all mapped and explicitly tailored for TypeScript optional inputs):
|
|
94
|
+
|
|
95
|
+
| Property | Type | Default | Description |
|
|
96
|
+
| :--- | :--- | :--- | :--- |
|
|
97
|
+
| `size` | `number` | `720` | Pixel size of the physical layout parameters confining the 8x8 squares map. |
|
|
98
|
+
| `padding` | `array` | `[0, 0, 0, 0]` | Padding margin applied exclusively outside the scope of the board bounds: `[top, right, bottom, left]`. (*Automatically bounces to `[30, 30, 30, 30]` if neglected alongside `notationStyle: outside`*). |
|
|
99
|
+
| `style` | `string` | `'merida'` | The structural graphical theme of the pieces. |
|
|
100
|
+
| `light` | `string` | `'#f0d9b5'` | Hex pattern representing standard light squares behavior. |
|
|
101
|
+
| `dark` | `string` | `'#b58863'` | Hex pattern representing standard dark squares behavior. |
|
|
102
|
+
| `highlight` | `string` | `'rgba(...)'` | Canvas mapping for active highlights across squares. Submits seamlessly to Alpha layer transparencies. |
|
|
103
|
+
| `flipped` | `boolean`| `false` | Perspective context parameter. Mutate to `true` to immediately paint the grid from Black's perspective exclusively. |
|
|
104
|
+
| `notations` | `boolean`| `false` | Check Boolean state to `true` to enforce coordinate rendering loops. |
|
|
105
|
+
| `notationStyle` | `string` | `'inside'` | `'inside'`: Overlaps texts natively adjacent to the top-left boundary of overlapping squares. `'outside'`: Safely projects coordinates outwards into isolated padded zones cleanly separated by borders. |
|
|
106
|
+
| `notationColor` | `string` | `Auto` | Implement a defined Hex string format targeting strictly text elements mapping. Neglecting this actively generates a Smart-Contrast algorithm based on the nearest pixel grid context. |
|
|
107
|
+
| `format` | `string` | `'png'` | Extracted image wrapper (`'png'`, `'jpeg'`, `'webp'`). |
|
|
108
|
+
| `quality` | `number` | `80` | Explicit constraint representing the dynamic image density ratio target compressing your media ranging heavily between (0 to 100). Applies only fundamentally to `.jpeg` and `.webp`. |
|
|
109
|
+
|
|
110
|
+
## 📚 Piece Styles (Themes)
|
|
111
|
+
Choose your favorite flavor and dynamically swap models natively! All assets are securely vectorized and fundamentally clear. The fully embedded internal library contains:
|
|
112
|
+
- `'alpha'`
|
|
113
|
+
- `'cburnett'`
|
|
114
|
+
- `'cheq'`
|
|
115
|
+
- `'game_room'` (Iconic sleek shadows and 3D reflections)
|
|
116
|
+
- `'game_room_gothic'`
|
|
117
|
+
- `'game_room_space'`
|
|
118
|
+
- `'glass'`
|
|
119
|
+
- `'leipzig'`
|
|
120
|
+
- `'merida'` (Classic gold-standard international playbook styling reference)
|
|
121
|
+
- `'neo'` (Minimalist, modern web layout integration standard)
|
|
122
|
+
- `'neo_wood'`
|
|
123
|
+
- `'wood'` (Hyper-realistic physical wood carved texture)
|
|
124
|
+
|
|
125
|
+
## 🧩 API Reference
|
|
126
|
+
|
|
127
|
+
* `async loadFEN(fen: string): Promise<void>`
|
|
128
|
+
Instantiates the native logical architecture mapping heavily based on the classic **Forsyth-Edwards Notation (FEN)** strings securely.
|
|
129
|
+
* `async loadPGN(pgn: string): Promise<void>`
|
|
130
|
+
Traverses through a multi-length string containing standard chess logic execution mapping based on **Portable Game Notation (PGN)** standard arrays resolving heavily toward the resulting visual representation array limit.
|
|
131
|
+
* `loadArray(array: string[][]): void`
|
|
132
|
+
Overwrites mappings heavily utilizing an automated 8x8 iteration schema defining columns directly referencing `[['r', ...], ...]`.
|
|
133
|
+
* `highlightSquares(squares: string[]): void`
|
|
134
|
+
Constructs targeting coordinates expecting algebraic input syntax wrapped actively within constraints mapping format directly (e.g. `['a1', 'b2']`). Generates highlighting RGBA canvas overlays safely.
|
|
135
|
+
* `async generateBuffer(): Promise<Buffer>`
|
|
136
|
+
Sparks the Napi-RS layer internally painting an off-screen cache frame securely handing back the parsed Node.js `Buffer` environment structure ready for payload consumption natively! (Extremely critical endpoint functionality target avoiding physical disk parsing).
|
|
137
|
+
* `async generateImage(path: string): Promise<string>`
|
|
138
|
+
Abstraction helper securely loading `generateBuffer()` and automatically executing piping parameters parsing directly towards your explicit localized system route handling file path parameters constraints implicitly saving. Backwards compatible implicitly matching `generatePNG()`.
|
|
139
|
+
|
|
140
|
+
## ⚠️ Important Notes
|
|
141
|
+
1. Because `chess-snap` resolves memory resources efficiently, file system manipulation requires an aggressively asynchronous layout. Priority demands explicit handling applying the `await` keyword sequentially prioritizing events correctly spanning `loadFEN()`, `loadPGN()` instances towards generation pipelines explicitly rendering endpoints.
|
|
142
|
+
2. Enabling boolean metrics overriding `notations: true` bound sequentially prioritizing configurations demanding explicitly `notationStyle: 'outside'` securely overrides standard spacing injecting internally bounded margins mathematically shifting standard variables actively adding `30` localized border layout limits retaining pristine visuals securely! As a result, explicitly rendering width configurations logically mutate exceeding explicitly raw values safely maintaining aspect ratios globally.
|
|
143
|
+
|
|
144
|
+
## 📝 License
|
|
145
|
+
This package is thoroughly Open Sourced officially enforcing mapping under strict implementation metrics aligned within the [MIT License](LICENSE).
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PieceStyle } from './types.js';
|
|
2
|
+
export declare const cols: string[];
|
|
3
|
+
export declare const white: string[];
|
|
4
|
+
export declare const black: string[];
|
|
5
|
+
export declare const defaultSize = 720;
|
|
6
|
+
export declare const defaultPadding: [number, number, number, number];
|
|
7
|
+
export declare const defaultLight = "#f0d9b5";
|
|
8
|
+
export declare const defaultDark = "#b58863";
|
|
9
|
+
export declare const defaultHighlight = "rgba(235, 97, 80, 0.8)";
|
|
10
|
+
export declare const defaultStyle: PieceStyle;
|
|
11
|
+
export declare const filePaths: Record<string, string>;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const cols = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
|
|
2
|
+
export const white = ['P', 'N', 'B', 'R', 'Q', 'K'];
|
|
3
|
+
export const black = ['p', 'n', 'b', 'r', 'q', 'k'];
|
|
4
|
+
export const defaultSize = 720;
|
|
5
|
+
export const defaultPadding = [0, 0, 0, 0];
|
|
6
|
+
export const defaultLight = '#f0d9b5';
|
|
7
|
+
export const defaultDark = '#b58863';
|
|
8
|
+
export const defaultHighlight = 'rgba(235, 97, 80, 0.8)';
|
|
9
|
+
export const defaultStyle = 'merida';
|
|
10
|
+
export const filePaths = {
|
|
11
|
+
wp: 'WhitePawn',
|
|
12
|
+
wn: 'WhiteKnight',
|
|
13
|
+
wb: 'WhiteBishop',
|
|
14
|
+
wr: 'WhiteRook',
|
|
15
|
+
wq: 'WhiteQueen',
|
|
16
|
+
wk: 'WhiteKing',
|
|
17
|
+
bp: 'BlackPawn',
|
|
18
|
+
bn: 'BlackKnight',
|
|
19
|
+
bb: 'BlackBishop',
|
|
20
|
+
br: 'BlackRook',
|
|
21
|
+
bq: 'BlackQueen',
|
|
22
|
+
bk: 'BlackKing',
|
|
23
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ChessImageOptions } from './types.js';
|
|
2
|
+
export default class ChessImageGenerator {
|
|
3
|
+
private chess;
|
|
4
|
+
private options;
|
|
5
|
+
private highlightedSquares;
|
|
6
|
+
ready: boolean;
|
|
7
|
+
constructor(options?: ChessImageOptions);
|
|
8
|
+
/**
|
|
9
|
+
* Loads PGN into chess object
|
|
10
|
+
* @param pgn Chess game PGN
|
|
11
|
+
*/
|
|
12
|
+
loadPGN(pgn: string): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Loads FEN into chess object
|
|
15
|
+
* @param fen Chess position FEN
|
|
16
|
+
*/
|
|
17
|
+
loadFEN(fen: string): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Loads a generic 2D Array into chess object
|
|
20
|
+
* @param array 8x8 Chess position array
|
|
21
|
+
*/
|
|
22
|
+
loadArray(array: string[][]): void;
|
|
23
|
+
/**
|
|
24
|
+
* Highlight specified squares
|
|
25
|
+
* @param array Array of square coordinates (e.g. ['e4', 'e5'])
|
|
26
|
+
*/
|
|
27
|
+
highlightSquares(array: string[]): void;
|
|
28
|
+
/**
|
|
29
|
+
* Generates buffer image based on position
|
|
30
|
+
* @returns Image Buffer
|
|
31
|
+
*/
|
|
32
|
+
generateBuffer(): Promise<Buffer>;
|
|
33
|
+
/**
|
|
34
|
+
* Generates a PNG image and saves it to a file (kept for backward compatibility)
|
|
35
|
+
* @param pngPath Output Path
|
|
36
|
+
*/
|
|
37
|
+
generatePNG(pngPath: string): Promise<string>;
|
|
38
|
+
/**
|
|
39
|
+
* Generates an image and saves it to a file using the configured format (png, jpeg, webp)
|
|
40
|
+
* @param imagePath Output Path
|
|
41
|
+
*/
|
|
42
|
+
generateImage(imagePath: string): Promise<string>;
|
|
43
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Chess } from 'chess.js';
|
|
2
|
+
import { defaultSize, defaultPadding, defaultLight, defaultDark, defaultHighlight, defaultStyle, white, black, cols } from './config.js';
|
|
3
|
+
import { generateBoardBuffer, writePNG } from './renderer.js';
|
|
4
|
+
export default class ChessImageGenerator {
|
|
5
|
+
chess;
|
|
6
|
+
options;
|
|
7
|
+
highlightedSquares;
|
|
8
|
+
ready;
|
|
9
|
+
constructor(options = {}) {
|
|
10
|
+
this.chess = new Chess();
|
|
11
|
+
this.highlightedSquares = [];
|
|
12
|
+
this.ready = false;
|
|
13
|
+
this.options = {
|
|
14
|
+
size: options.size || defaultSize,
|
|
15
|
+
padding: options.padding || defaultPadding,
|
|
16
|
+
light: options.light || defaultLight,
|
|
17
|
+
dark: options.dark || defaultDark,
|
|
18
|
+
highlight: options.highlight || defaultHighlight,
|
|
19
|
+
style: options.style || defaultStyle,
|
|
20
|
+
flipped: options.flipped ?? false,
|
|
21
|
+
notations: options.notations ?? false,
|
|
22
|
+
notationColor: options.notationColor || '',
|
|
23
|
+
notationStyle: options.notationStyle || 'inside',
|
|
24
|
+
format: options.format || 'png',
|
|
25
|
+
quality: options.quality ?? 80,
|
|
26
|
+
};
|
|
27
|
+
if (this.options.notationStyle === 'outside' && this.options.padding.every(p => p === 0)) {
|
|
28
|
+
this.options.padding = [30, 30, 30, 30];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Loads PGN into chess object
|
|
33
|
+
* @param pgn Chess game PGN
|
|
34
|
+
*/
|
|
35
|
+
async loadPGN(pgn) {
|
|
36
|
+
this.chess.loadPgn(pgn);
|
|
37
|
+
this.ready = true;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Loads FEN into chess object
|
|
41
|
+
* @param fen Chess position FEN
|
|
42
|
+
*/
|
|
43
|
+
async loadFEN(fen) {
|
|
44
|
+
this.chess.load(fen);
|
|
45
|
+
this.ready = true;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Loads a generic 2D Array into chess object
|
|
49
|
+
* @param array 8x8 Chess position array
|
|
50
|
+
*/
|
|
51
|
+
loadArray(array) {
|
|
52
|
+
this.chess.clear();
|
|
53
|
+
for (let i = 0; i < array.length; i++) {
|
|
54
|
+
for (let j = 0; j < array[i].length; j++) {
|
|
55
|
+
const piece = array[i][j];
|
|
56
|
+
if (piece !== '' && black.includes(piece.toLowerCase())) {
|
|
57
|
+
const color = white.includes(piece) ? 'w' : 'b';
|
|
58
|
+
const type = piece.toLowerCase();
|
|
59
|
+
const square = `${cols[j]}${8 - i}`;
|
|
60
|
+
this.chess.put({ type, color }, square);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
this.ready = true;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Highlight specified squares
|
|
68
|
+
* @param array Array of square coordinates (e.g. ['e4', 'e5'])
|
|
69
|
+
*/
|
|
70
|
+
highlightSquares(array) {
|
|
71
|
+
this.highlightedSquares = array;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Generates buffer image based on position
|
|
75
|
+
* @returns Image Buffer
|
|
76
|
+
*/
|
|
77
|
+
async generateBuffer() {
|
|
78
|
+
if (!this.ready) {
|
|
79
|
+
throw new Error('Load a position first (loadFEN, loadPGN, or loadArray)');
|
|
80
|
+
}
|
|
81
|
+
return generateBoardBuffer(this.chess, this.options, this.highlightedSquares);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Generates a PNG image and saves it to a file (kept for backward compatibility)
|
|
85
|
+
* @param pngPath Output Path
|
|
86
|
+
*/
|
|
87
|
+
async generatePNG(pngPath) {
|
|
88
|
+
const buffer = await this.generateBuffer();
|
|
89
|
+
return writePNG(buffer, pngPath);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Generates an image and saves it to a file using the configured format (png, jpeg, webp)
|
|
93
|
+
* @param imagePath Output Path
|
|
94
|
+
*/
|
|
95
|
+
async generateImage(imagePath) {
|
|
96
|
+
const buffer = await this.generateBuffer();
|
|
97
|
+
return writePNG(buffer, imagePath);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ChessImageOptions } from './types.js';
|
|
2
|
+
import { Chess } from 'chess.js';
|
|
3
|
+
/**
|
|
4
|
+
* The core buffer generator function.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateBoardBuffer(chess: Chess, options: Required<ChessImageOptions>, highlightedSquares: string[]): Promise<Buffer>;
|
|
7
|
+
/**
|
|
8
|
+
* Helper to write a buffer to file securely.
|
|
9
|
+
*/
|
|
10
|
+
export declare function writePNG(buffer: Buffer, filePath: string): Promise<string>;
|
package/dist/renderer.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { createCanvas, loadImage } from '@napi-rs/canvas';
|
|
2
|
+
import { resolve, dirname } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
const _filename = fileURLToPath(import.meta.url);
|
|
5
|
+
const _dirname = dirname(_filename);
|
|
6
|
+
import { cols, filePaths } from './config.js';
|
|
7
|
+
import * as fs from 'fs/promises';
|
|
8
|
+
const imageCache = new Map();
|
|
9
|
+
/**
|
|
10
|
+
* Ensures the piece image for a given style is loaded into memory exactly once.
|
|
11
|
+
*/
|
|
12
|
+
async function getPieceImage(style, pieceKey) {
|
|
13
|
+
const cacheKey = `${style}_${pieceKey}`;
|
|
14
|
+
if (imageCache.has(cacheKey)) {
|
|
15
|
+
return imageCache.get(cacheKey);
|
|
16
|
+
}
|
|
17
|
+
const fileName = filePaths[pieceKey];
|
|
18
|
+
if (!fileName)
|
|
19
|
+
throw new Error(`Unknown piece key: ${pieceKey}`);
|
|
20
|
+
const imgPath = resolve(_dirname, `../src/assets/pieces/${style}/${fileName}.png`);
|
|
21
|
+
try {
|
|
22
|
+
const image = await loadImage(imgPath);
|
|
23
|
+
imageCache.set(cacheKey, image);
|
|
24
|
+
return image;
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
throw new Error(`Failed to load piece image from ${imgPath}: ${err}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Renders the algebraic notations (A-H, 1-8) around the board.
|
|
32
|
+
*/
|
|
33
|
+
function drawNotations(ctx, size, flipped, light, dark, padding, notationStyle, notationColor) {
|
|
34
|
+
const paddingTop = padding[0];
|
|
35
|
+
const paddingLeft = padding[3];
|
|
36
|
+
const paddingBottom = padding[2];
|
|
37
|
+
const paddingRight = padding[1];
|
|
38
|
+
const squareSize = size / 8;
|
|
39
|
+
const fontSize = Math.max(16, Math.floor(squareSize / 3.5));
|
|
40
|
+
ctx.font = `bold ${fontSize}px sans-serif`;
|
|
41
|
+
ctx.textBaseline = 'top';
|
|
42
|
+
const rows = flipped ? [1, 2, 3, 4, 5, 6, 7, 8] : [8, 7, 6, 5, 4, 3, 2, 1];
|
|
43
|
+
const columns = flipped ? [...cols].reverse() : cols;
|
|
44
|
+
for (let i = 0; i < 8; i++) {
|
|
45
|
+
const ySquare = (squareSize * i) + paddingTop;
|
|
46
|
+
const xSquare = (squareSize * i) + paddingLeft;
|
|
47
|
+
if (notationStyle === 'inside') {
|
|
48
|
+
const isLightSquareForNumber = (i % 2 === 0);
|
|
49
|
+
ctx.fillStyle = notationColor || (isLightSquareForNumber ? dark : light);
|
|
50
|
+
ctx.lineWidth = 1.5;
|
|
51
|
+
ctx.strokeStyle = notationColor ? "rgba(0,0,0,0.5)" : (isLightSquareForNumber ? light : dark);
|
|
52
|
+
ctx.strokeText(rows[i].toString(), paddingLeft + 4, ySquare + 4);
|
|
53
|
+
ctx.fillText(rows[i].toString(), paddingLeft + 4, ySquare + 4);
|
|
54
|
+
const isLightSquareForLetter = (i % 2 !== 0);
|
|
55
|
+
ctx.fillStyle = notationColor || (isLightSquareForLetter ? dark : light);
|
|
56
|
+
const textWidth = ctx.measureText(columns[i]).width;
|
|
57
|
+
const letterX = xSquare + squareSize - textWidth - 2;
|
|
58
|
+
const letterY = size - fontSize - 2 + paddingTop;
|
|
59
|
+
ctx.lineWidth = 1.5;
|
|
60
|
+
ctx.strokeStyle = notationColor ? "rgba(0,0,0,0.5)" : (isLightSquareForLetter ? light : dark);
|
|
61
|
+
ctx.strokeText(columns[i], letterX, letterY);
|
|
62
|
+
ctx.fillText(columns[i], letterX, letterY);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
ctx.fillStyle = notationColor || dark;
|
|
66
|
+
ctx.textBaseline = 'middle';
|
|
67
|
+
ctx.textAlign = 'center';
|
|
68
|
+
const numberY = ySquare + (squareSize / 2);
|
|
69
|
+
ctx.fillText(rows[i].toString(), paddingLeft / 2, numberY);
|
|
70
|
+
const letterX = xSquare + (squareSize / 2);
|
|
71
|
+
const letterY = (paddingTop / 2) - 4;
|
|
72
|
+
ctx.fillText(columns[i], letterX, letterY);
|
|
73
|
+
ctx.textBaseline = 'top';
|
|
74
|
+
ctx.textAlign = 'left';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The core buffer generator function.
|
|
80
|
+
*/
|
|
81
|
+
export async function generateBoardBuffer(chess, options, highlightedSquares) {
|
|
82
|
+
const canvasWidth = options.size + options.padding[1] + options.padding[3];
|
|
83
|
+
const canvasHeight = options.size + options.padding[0] + options.padding[2];
|
|
84
|
+
const canvas = createCanvas(canvasWidth, canvasHeight);
|
|
85
|
+
const ctx = canvas.getContext('2d');
|
|
86
|
+
ctx.fillStyle = options.light;
|
|
87
|
+
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
|
|
88
|
+
const squareSize = options.size / 8;
|
|
89
|
+
const paddingTop = options.padding[0];
|
|
90
|
+
const paddingLeft = options.padding[3];
|
|
91
|
+
const rowFn = options.flipped ? (r) => r + 1 : (r) => 8 - r;
|
|
92
|
+
const colFn = options.flipped ? (c) => c : (c) => 7 - c;
|
|
93
|
+
for (let i = 0; i < 8; i++) {
|
|
94
|
+
for (let j = 0; j < 8; j++) {
|
|
95
|
+
const coordCol = cols[colFn(j)];
|
|
96
|
+
const coordRow = rowFn(i);
|
|
97
|
+
const coords = `${coordCol}${coordRow}`;
|
|
98
|
+
const x = (squareSize * (7 - j)) + paddingLeft;
|
|
99
|
+
const y = (squareSize * i) + paddingTop;
|
|
100
|
+
if ((i + j) % 2 !== 0) {
|
|
101
|
+
ctx.fillStyle = options.dark;
|
|
102
|
+
ctx.fillRect(x, y, squareSize, squareSize);
|
|
103
|
+
}
|
|
104
|
+
if (highlightedSquares.includes(coords)) {
|
|
105
|
+
ctx.fillStyle = options.highlight;
|
|
106
|
+
ctx.fillRect(x, y, squareSize, squareSize);
|
|
107
|
+
}
|
|
108
|
+
const piece = chess.get(coords);
|
|
109
|
+
if (piece) {
|
|
110
|
+
const pieceKey = `${piece.color}${piece.type}`;
|
|
111
|
+
try {
|
|
112
|
+
const img = await getPieceImage(options.style, pieceKey);
|
|
113
|
+
ctx.drawImage(img, x, y, squareSize, squareSize);
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
console.error(`Missing piece image for: ${pieceKey} in style ${options.style}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (options.notationStyle === 'outside') {
|
|
122
|
+
ctx.lineWidth = 2;
|
|
123
|
+
ctx.strokeStyle = options.dark;
|
|
124
|
+
ctx.strokeRect(paddingLeft, paddingTop, options.size, options.size);
|
|
125
|
+
}
|
|
126
|
+
if (options.notations) {
|
|
127
|
+
drawNotations(ctx, options.size, options.flipped, options.light, options.dark, options.padding, options.notationStyle, options.notationColor);
|
|
128
|
+
}
|
|
129
|
+
const format = options.format;
|
|
130
|
+
const quality = options.quality;
|
|
131
|
+
const mimeType = `image/${format}`;
|
|
132
|
+
if (format === 'jpeg' || format === 'webp') {
|
|
133
|
+
return canvas.toBuffer(mimeType, quality);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
return canvas.toBuffer('image/png');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Helper to write a buffer to file securely.
|
|
141
|
+
*/
|
|
142
|
+
export async function writePNG(buffer, filePath) {
|
|
143
|
+
await fs.writeFile(filePath, buffer);
|
|
144
|
+
return filePath;
|
|
145
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PieceStyle } from './types.js';
|
|
2
|
+
export declare const cols: string[];
|
|
3
|
+
export declare const white: string[];
|
|
4
|
+
export declare const black: string[];
|
|
5
|
+
export declare const defaultSize = 720;
|
|
6
|
+
export declare const defaultPadding: [number, number, number, number];
|
|
7
|
+
export declare const defaultLight = "#f0d9b5";
|
|
8
|
+
export declare const defaultDark = "#b58863";
|
|
9
|
+
export declare const defaultHighlight = "rgba(235, 97, 80, 0.8)";
|
|
10
|
+
export declare const defaultStyle: PieceStyle;
|
|
11
|
+
export declare const filePaths: Record<string, string>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const cols = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
|
|
2
|
+
export const white = ['P', 'N', 'B', 'R', 'Q', 'K'];
|
|
3
|
+
export const black = ['p', 'n', 'b', 'r', 'q', 'k'];
|
|
4
|
+
export const defaultSize = 720;
|
|
5
|
+
export const defaultPadding = [0, 0, 0, 0];
|
|
6
|
+
export const defaultLight = '#f0d9b5';
|
|
7
|
+
export const defaultDark = '#b58863';
|
|
8
|
+
export const defaultHighlight = 'rgba(235, 97, 80, 0.8)';
|
|
9
|
+
export const defaultStyle = 'merida';
|
|
10
|
+
export const filePaths = {
|
|
11
|
+
wp: 'WhitePawn',
|
|
12
|
+
wn: 'WhiteKnight',
|
|
13
|
+
wb: 'WhiteBishop',
|
|
14
|
+
wr: 'WhiteRook',
|
|
15
|
+
wq: 'WhiteQueen',
|
|
16
|
+
wk: 'WhiteKing',
|
|
17
|
+
bp: 'BlackPawn',
|
|
18
|
+
bn: 'BlackKnight',
|
|
19
|
+
bb: 'BlackBishop',
|
|
20
|
+
br: 'BlackRook',
|
|
21
|
+
bq: 'BlackQueen',
|
|
22
|
+
bk: 'BlackKing',
|
|
23
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ChessImageOptions } from './types.js';
|
|
2
|
+
export default class ChessImageGenerator {
|
|
3
|
+
private chess;
|
|
4
|
+
private options;
|
|
5
|
+
private highlightedSquares;
|
|
6
|
+
ready: boolean;
|
|
7
|
+
constructor(options?: ChessImageOptions);
|
|
8
|
+
/**
|
|
9
|
+
* Loads PGN into chess object
|
|
10
|
+
* @param pgn Chess game PGN
|
|
11
|
+
*/
|
|
12
|
+
loadPGN(pgn: string): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Loads FEN into chess object
|
|
15
|
+
* @param fen Chess position FEN
|
|
16
|
+
*/
|
|
17
|
+
loadFEN(fen: string): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Loads a generic 2D Array into chess object
|
|
20
|
+
* @param array 8x8 Chess position array
|
|
21
|
+
*/
|
|
22
|
+
loadArray(array: string[][]): void;
|
|
23
|
+
/**
|
|
24
|
+
* Highlight specified squares
|
|
25
|
+
* @param array Array of square coordinates (e.g. ['e4', 'e5'])
|
|
26
|
+
*/
|
|
27
|
+
highlightSquares(array: string[]): void;
|
|
28
|
+
/**
|
|
29
|
+
* Generates buffer image based on position
|
|
30
|
+
* @returns Image Buffer
|
|
31
|
+
*/
|
|
32
|
+
generateBuffer(): Promise<Buffer>;
|
|
33
|
+
/**
|
|
34
|
+
* Generates a PNG image and saves it to a file (kept for backward compatibility)
|
|
35
|
+
* @param pngPath Output Path
|
|
36
|
+
*/
|
|
37
|
+
generatePNG(pngPath: string): Promise<string>;
|
|
38
|
+
/**
|
|
39
|
+
* Generates an image and saves it to a file using the configured format (png, jpeg, webp)
|
|
40
|
+
* @param imagePath Output Path
|
|
41
|
+
*/
|
|
42
|
+
generateImage(imagePath: string): Promise<string>;
|
|
43
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Chess } from 'chess.js';
|
|
2
|
+
import { defaultSize, defaultPadding, defaultLight, defaultDark, defaultHighlight, defaultStyle, white, black, cols } from './config.js';
|
|
3
|
+
import { generateBoardBuffer, writePNG } from './renderer.js';
|
|
4
|
+
export default class ChessImageGenerator {
|
|
5
|
+
chess;
|
|
6
|
+
options;
|
|
7
|
+
highlightedSquares;
|
|
8
|
+
ready;
|
|
9
|
+
constructor(options = {}) {
|
|
10
|
+
this.chess = new Chess();
|
|
11
|
+
this.highlightedSquares = [];
|
|
12
|
+
this.ready = false;
|
|
13
|
+
this.options = {
|
|
14
|
+
size: options.size || defaultSize,
|
|
15
|
+
padding: options.padding || defaultPadding,
|
|
16
|
+
light: options.light || defaultLight,
|
|
17
|
+
dark: options.dark || defaultDark,
|
|
18
|
+
highlight: options.highlight || defaultHighlight,
|
|
19
|
+
style: options.style || defaultStyle,
|
|
20
|
+
flipped: options.flipped ?? false,
|
|
21
|
+
notations: options.notations ?? false,
|
|
22
|
+
notationColor: options.notationColor || '',
|
|
23
|
+
notationStyle: options.notationStyle || 'inside',
|
|
24
|
+
format: options.format || 'png',
|
|
25
|
+
quality: options.quality ?? 80,
|
|
26
|
+
};
|
|
27
|
+
if (this.options.notationStyle === 'outside' && this.options.padding.every(p => p === 0)) {
|
|
28
|
+
this.options.padding = [30, 30, 30, 30];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Loads PGN into chess object
|
|
33
|
+
* @param pgn Chess game PGN
|
|
34
|
+
*/
|
|
35
|
+
async loadPGN(pgn) {
|
|
36
|
+
this.chess.loadPgn(pgn);
|
|
37
|
+
this.ready = true;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Loads FEN into chess object
|
|
41
|
+
* @param fen Chess position FEN
|
|
42
|
+
*/
|
|
43
|
+
async loadFEN(fen) {
|
|
44
|
+
this.chess.load(fen);
|
|
45
|
+
this.ready = true;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Loads a generic 2D Array into chess object
|
|
49
|
+
* @param array 8x8 Chess position array
|
|
50
|
+
*/
|
|
51
|
+
loadArray(array) {
|
|
52
|
+
this.chess.clear();
|
|
53
|
+
for (let i = 0; i < array.length; i++) {
|
|
54
|
+
for (let j = 0; j < array[i].length; j++) {
|
|
55
|
+
const piece = array[i][j];
|
|
56
|
+
if (piece !== '' && black.includes(piece.toLowerCase())) {
|
|
57
|
+
const color = white.includes(piece) ? 'w' : 'b';
|
|
58
|
+
const type = piece.toLowerCase();
|
|
59
|
+
const square = `${cols[j]}${8 - i}`;
|
|
60
|
+
this.chess.put({ type, color }, square);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
this.ready = true;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Highlight specified squares
|
|
68
|
+
* @param array Array of square coordinates (e.g. ['e4', 'e5'])
|
|
69
|
+
*/
|
|
70
|
+
highlightSquares(array) {
|
|
71
|
+
this.highlightedSquares = array;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Generates buffer image based on position
|
|
75
|
+
* @returns Image Buffer
|
|
76
|
+
*/
|
|
77
|
+
async generateBuffer() {
|
|
78
|
+
if (!this.ready) {
|
|
79
|
+
throw new Error('Load a position first (loadFEN, loadPGN, or loadArray)');
|
|
80
|
+
}
|
|
81
|
+
return generateBoardBuffer(this.chess, this.options, this.highlightedSquares);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Generates a PNG image and saves it to a file (kept for backward compatibility)
|
|
85
|
+
* @param pngPath Output Path
|
|
86
|
+
*/
|
|
87
|
+
async generatePNG(pngPath) {
|
|
88
|
+
const buffer = await this.generateBuffer();
|
|
89
|
+
return writePNG(buffer, pngPath);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Generates an image and saves it to a file using the configured format (png, jpeg, webp)
|
|
93
|
+
* @param imagePath Output Path
|
|
94
|
+
*/
|
|
95
|
+
async generateImage(imagePath) {
|
|
96
|
+
const buffer = await this.generateBuffer();
|
|
97
|
+
return writePNG(buffer, imagePath);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ChessImageOptions } from './types.js';
|
|
2
|
+
import { Chess } from 'chess.js';
|
|
3
|
+
/**
|
|
4
|
+
* The core buffer generator function.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateBoardBuffer(chess: Chess, options: Required<ChessImageOptions>, highlightedSquares: string[]): Promise<Buffer>;
|
|
7
|
+
/**
|
|
8
|
+
* Helper to write a buffer to file securely.
|
|
9
|
+
*/
|
|
10
|
+
export declare function writePNG(buffer: Buffer, filePath: string): Promise<string>;
|