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}