diff --git a/packages/chess/src/ui/Board.tsx b/packages/chess/src/ui/Board.tsx index c256207..b15f82a 100644 --- a/packages/chess/src/ui/Board.tsx +++ b/packages/chess/src/ui/Board.tsx @@ -322,19 +322,11 @@ export function Board({ facts, legalMoves, onMove, turn, myColor, lastMove, chec piece.color === turn && (myColor === null || myColor === undefined || piece.color === myColor) } + overlays={overlays} + pieceFacts={factsById.get(piece.id) ?? []} onDragStart={handleDragStart} onDragEnd={handleDragEnd} /> - {/* Per-piece preset overlays (HP pips, etc.). Each is a - pure function of the piece's facts; Board stays - agnostic to which presets exist. */} - {overlays.map((Overlay, i) => ( - - ))} )} diff --git a/packages/chess/src/ui/Piece.tsx b/packages/chess/src/ui/Piece.tsx index 272bd70..82cfbd4 100644 --- a/packages/chess/src/ui/Piece.tsx +++ b/packages/chess/src/ui/Piece.tsx @@ -1,4 +1,4 @@ -import type { PieceColor, PieceType } from '../schema'; +import type { ChessAttrMap, ChessFact, PieceColor, PieceType } from '../schema'; import { pieceAssets } from '../assets/pieces'; import { motion, @@ -6,8 +6,9 @@ import { useSpring, useTransform, } from 'motion/react'; -import { useEffect, useLayoutEffect, useRef, useState } from 'react'; +import { useEffect, useLayoutEffect, useRef, useState, type ReactNode } from 'react'; import type { DragEvent as ReactDragEvent } from 'react'; +import type { PieceOverlayComponent } from './preset-overlays'; export interface PieceProps { color: PieceColor; @@ -18,6 +19,14 @@ export interface PieceProps { * ongoing, etc). When false, drag is disabled and the piece shows a * default cursor. */ isDraggable: boolean; + /** Per-piece preset overlays (HP pips, ammo counter, etc.). Rendered + * INSIDE the drag-transform layer so they follow the piece as it's + * translated / rotated / scaled during a drag. Pass [] when no + * overlays are active. */ + overlays?: ReadonlyArray; + /** Facts for this piece, used by the overlays. Pre-indexed by the + * Board so the overlay component doesn't re-scan all facts. */ + pieceFacts?: ReadonlyArray>; onDragStart: (pieceId: number, square: number) => void; onDragEnd: () => void; } @@ -81,6 +90,8 @@ export function Piece({ pieceId, square, isDraggable, + overlays, + pieceFacts, onDragStart, onDragEnd, }: PieceProps) { @@ -344,6 +355,21 @@ export function Piece({ }`} draggable={false} /> + + {/* + * Per-piece preset overlays (HP pips, etc.) live INSIDE the + * transform layer so they inherit the drag `x/y/rotate/scale` + * motion values and track the piece during drags. Overlays + * that don't apply to this piece's facts return null so the + * DOM stays clean. + */} + {overlays?.map((Overlay, i) => ( + + )) as ReactNode}