Commit c7c76636 authored by Mahmoud Aglan's avatar Mahmoud Aglan

feat: chess pieces now load custom PNGs from branding system

When chess piece images are uploaded via admin (chess_piece_wK, chess_piece_bQ,
etc.), the board renders them instead of vector paths. Falls back to the
original canvas paths if no images are uploaded. Re-renders automatically
once images finish loading.
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent ca122ef4
import { createCanvas, clear, getCanvasCoords } from '../../../core/canvas.js'; import { createCanvas, clear, getCanvasCoords } from '../../../core/canvas.js';
import { getAsset } from '../../../core/theme.js';
const LIGHT_SQ = '#F0D9B5'; const LIGHT_SQ = '#F0D9B5';
const DARK_SQ = '#B58863'; const DARK_SQ = '#B58863';
...@@ -8,6 +9,33 @@ const CHECK_COLOR = '#FF6B6B88'; ...@@ -8,6 +9,33 @@ const CHECK_COLOR = '#FF6B6B88';
const MOVE_DOT = 'rgba(0,0,0,0.25)'; const MOVE_DOT = 'rgba(0,0,0,0.25)';
const CAPTURE_RING = 'rgba(0,0,0,0.25)'; const CAPTURE_RING = 'rgba(0,0,0,0.25)';
const PIECE_ASSET_MAP = {
K: 'chess_piece_wK', Q: 'chess_piece_wQ', R: 'chess_piece_wR',
B: 'chess_piece_wB', N: 'chess_piece_wN', P: 'chess_piece_wP',
k: 'chess_piece_bK', q: 'chess_piece_bQ', r: 'chess_piece_bR',
b: 'chess_piece_bB', n: 'chess_piece_bN', p: 'chess_piece_bP',
};
const pieceImages = {};
let pieceImagesLoaded = false;
let boardInstance = null;
function loadPieceImages() {
if (pieceImagesLoaded) return;
pieceImagesLoaded = true;
let pending = 0;
for (const [piece, slot] of Object.entries(PIECE_ASSET_MAP)) {
const url = getAsset(slot);
if (url) {
const img = new Image();
pending++;
img.onload = () => { if (--pending === 0 && boardInstance) boardInstance.render(); };
img.src = url;
pieceImages[piece] = img;
}
}
}
const PIECE_PATHS = { const PIECE_PATHS = {
K: (ctx, x, y, s) => { drawPiece(ctx, x, y, s, '#fff', '#000', kingPath); }, K: (ctx, x, y, s) => { drawPiece(ctx, x, y, s, '#fff', '#000', kingPath); },
Q: (ctx, x, y, s) => { drawPiece(ctx, x, y, s, '#fff', '#000', queenPath); }, Q: (ctx, x, y, s) => { drawPiece(ctx, x, y, s, '#fff', '#000', queenPath); },
...@@ -225,6 +253,7 @@ export class ChessBoard { ...@@ -225,6 +253,7 @@ export class ChessBoard {
this.wrapper.style.cssText = 'position:relative;width:100%;max-width:400px;margin:0 auto;aspect-ratio:1;'; this.wrapper.style.cssText = 'position:relative;width:100%;max-width:400px;margin:0 auto;aspect-ratio:1;';
container.appendChild(this.wrapper); container.appendChild(this.wrapper);
boardInstance = this;
this.setupCanvas(); this.setupCanvas();
this.bindEvents(); this.bindEvents();
} }
...@@ -325,26 +354,25 @@ export class ChessBoard { ...@@ -325,26 +354,25 @@ export class ChessBoard {
} }
// Draw pieces // Draw pieces
loadPieceImages();
for (const [square, piece] of Object.entries(this.pieces)) { for (const [square, piece] of Object.entries(this.pieces)) {
if (this.dragging && this.dragging.square === square) continue; if (this.dragging && this.dragging.square === square) continue;
if (this.animating && this.animating.square === square) continue; if (this.animating && this.animating.square === square) continue;
const { x, y } = this.squareToXY(square); const { x, y } = this.squareToXY(square);
const padding = sq * 0.05; const padding = sq * 0.05;
if (PIECE_PATHS[piece]) { this.drawPieceAt(ctx, piece, x + padding, y + padding, sq - padding * 2);
PIECE_PATHS[piece](ctx, x + padding, y + padding, sq - padding * 2);
}
} }
// Draw animating piece at interpolated position // Draw animating piece at interpolated position
if (this.animating && PIECE_PATHS[this.animating.piece]) { if (this.animating) {
const padding = sq * 0.05; const padding = sq * 0.05;
PIECE_PATHS[this.animating.piece](ctx, this.animating.x + padding, this.animating.y + padding, sq - padding * 2); this.drawPieceAt(ctx, this.animating.piece, this.animating.x + padding, this.animating.y + padding, sq - padding * 2);
} }
// Draw dragging piece // Draw dragging piece
if (this.dragging && PIECE_PATHS[this.dragging.piece]) { if (this.dragging) {
const ds = sq * 1.2; const ds = sq * 1.2;
PIECE_PATHS[this.dragging.piece](ctx, this.dragging.x - ds / 2, this.dragging.y - ds / 2, ds); this.drawPieceAt(ctx, this.dragging.piece, this.dragging.x - ds / 2, this.dragging.y - ds / 2, ds);
} }
// Coordinates // Coordinates
...@@ -371,6 +399,15 @@ export class ChessBoard { ...@@ -371,6 +399,15 @@ export class ChessBoard {
return { x: c * this.squareSize, y: r * this.squareSize }; return { x: c * this.squareSize, y: r * this.squareSize };
} }
drawPieceAt(ctx, piece, x, y, s) {
const img = pieceImages[piece];
if (img && img.complete && img.naturalWidth > 0) {
ctx.drawImage(img, x, y, s, s);
} else if (PIECE_PATHS[piece]) {
PIECE_PATHS[piece](ctx, x, y, s);
}
}
xyToSquare(x, y) { xyToSquare(x, y) {
const c = Math.floor(x / this.squareSize); const c = Math.floor(x / this.squareSize);
const r = Math.floor(y / this.squareSize); const r = Math.floor(y / this.squareSize);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment