feat(rithmomachia): show pyramid face numbers when selected

Pyramids now display all 4 face values around the piece when selected,
making it clear to players which numbers the pyramid can use for captures.

Implementation:
- Face numbers appear at top, right, bottom, left positions
- Only shown when pyramid piece is selected
- Clean board appearance when not selected
- Numbers scale appropriately with piece size

This permissive display helps players understand pyramid capabilities
without requiring explicit face selection (game auto-validates which
faces enable valid captures).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock
2025-11-02 12:57:47 -06:00
parent 7688921004
commit 5c186f3947
3 changed files with 69 additions and 1 deletions

View File

@@ -7,6 +7,8 @@ interface PieceRendererProps {
value: number | string
size?: number
useNativeAbacusNumbers?: boolean
selected?: boolean
pyramidFaces?: number[]
}
/**
@@ -20,6 +22,8 @@ export function PieceRenderer({
value,
size = 48,
useNativeAbacusNumbers = false,
selected = false,
pyramidFaces = [],
}: PieceRendererProps) {
const isDark = color === 'B'
const { config } = useAbacusDisplay()
@@ -225,7 +229,65 @@ export function PieceRenderer({
{renderShape()}
{/* Pyramids don't show numbers */}
{/* Pyramid face numbers - show when selected */}
{type === 'P' && selected && pyramidFaces.length === 4 && (
<g>
{/* Top face */}
<text
x={size / 2}
y={size * 0.05}
textAnchor="middle"
dominantBaseline="middle"
fill={textColor}
fontSize={size * 0.16}
fontWeight="bold"
fontFamily="Georgia, 'Times New Roman', serif"
>
{pyramidFaces[0]}
</text>
{/* Right face */}
<text
x={size * 0.95}
y={size / 2}
textAnchor="middle"
dominantBaseline="middle"
fill={textColor}
fontSize={size * 0.16}
fontWeight="bold"
fontFamily="Georgia, 'Times New Roman', serif"
>
{pyramidFaces[1]}
</text>
{/* Bottom face */}
<text
x={size / 2}
y={size * 0.95}
textAnchor="middle"
dominantBaseline="middle"
fill={textColor}
fontSize={size * 0.16}
fontWeight="bold"
fontFamily="Georgia, 'Times New Roman', serif"
>
{pyramidFaces[2]}
</text>
{/* Left face */}
<text
x={size * 0.05}
y={size / 2}
textAnchor="middle"
dominantBaseline="middle"
fill={textColor}
fontSize={size * 0.16}
fontWeight="bold"
fontFamily="Georgia, 'Times New Roman', serif"
>
{pyramidFaces[3]}
</text>
</g>
)}
{/* Other pieces show numbers normally */}
{type !== 'P' &&
(useNativeAbacusNumbers && typeof value === 'number' ? (
// Render mini abacus

View File

@@ -508,6 +508,7 @@ export function BoardDisplay() {
const isBorrowedHelper = helpersWithPositions.some((h) => h.piece.id === piece.id)
const isBorrowedMover = selectedHelper && selectedHelper.moverPiece.id === piece.id
const isInNumberBond = isBorrowedHelper || isBorrowedMover
const isSelected = piece.square === selectedSquare
return (
<SvgPiece
key={piece.id}
@@ -517,6 +518,7 @@ export function BoardDisplay() {
labelMargin={labelMargin}
opacity={isInNumberBond ? 0.2 : 1}
useNativeAbacusNumbers={useNativeAbacusNumbers}
selected={isSelected}
/>
)
})}

View File

@@ -11,6 +11,7 @@ export interface SvgPieceProps {
labelMargin?: number
opacity?: number
useNativeAbacusNumbers?: boolean
selected?: boolean
}
export function SvgPiece({
@@ -20,6 +21,7 @@ export function SvgPiece({
labelMargin = 0,
opacity = 1,
useNativeAbacusNumbers = false,
selected = false,
}: SvgPieceProps) {
const file = piece.square.charCodeAt(0) - 65 // A=0
const rank = Number.parseInt(piece.square.slice(1), 10) // 1-8
@@ -55,6 +57,8 @@ export function SvgPiece({
value={piece.type === 'P' ? piece.pyramidFaces?.[0] || 0 : piece.value || 0}
size={pieceSize}
useNativeAbacusNumbers={useNativeAbacusNumbers}
selected={selected}
pyramidFaces={piece.type === 'P' ? piece.pyramidFaces : undefined}
/>
</div>
</foreignObject>