fix(game): center played cards — bake -50% into Framer transform (RTL)
Root cause: the trick cards used a Tailwind -translate-x-1/2 -translate-y-1/2 to center on the felt, but Framer Motion owns `transform` (from x/y/scale), so that centering class was clobbered. In RTL the auto-positioned card then anchored to the right edge and the whole trick cross drifted left of center. Fix: drop the size-0 anchor; position each card at left-1/2 top-1/2 and use Framer `transformTemplate` to prepend translate(-50%,-50%) before the animated translate(x,y) scale — so centering survives and the pile sits dead-center in both LTR and RTL. Burst particles re-centered too. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -443,7 +443,6 @@ function TrickArea({
|
|||||||
const { front } = useCardSkins();
|
const { front } = useCardSkins();
|
||||||
return (
|
return (
|
||||||
<div className="absolute inset-0">
|
<div className="absolute inset-0">
|
||||||
<div className="absolute left-1/2 top-1/2 size-0">
|
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{trick.map((pc) => {
|
{trick.map((pc) => {
|
||||||
const off = { x: TRICK_OFFSET[pc.seat].x * scale, y: TRICK_OFFSET[pc.seat].y * scale };
|
const off = { x: TRICK_OFFSET[pc.seat].x * scale, y: TRICK_OFFSET[pc.seat].y * scale };
|
||||||
@@ -456,7 +455,12 @@ function TrickArea({
|
|||||||
animate={{ x: off.x, y: off.y, opacity: 1, scale: isWinner ? 1.14 : 1 }}
|
animate={{ x: off.x, y: off.y, opacity: 1, scale: isWinner ? 1.14 : 1 }}
|
||||||
exit={{ opacity: 0, scale: 0.6, transition: { duration: 0.25 } }}
|
exit={{ opacity: 0, scale: 0.6, transition: { duration: 0.25 } }}
|
||||||
transition={{ type: "spring", stiffness: 260, damping: 26 }}
|
transition={{ type: "spring", stiffness: 260, damping: 26 }}
|
||||||
className="absolute -translate-x-1/2 -translate-y-1/2"
|
className="absolute left-1/2 top-1/2"
|
||||||
|
// Bake the -50% centering into Framer's transform — Framer owns the
|
||||||
|
// `transform` (from x/y/scale), so a Tailwind -translate-x-1/2 class
|
||||||
|
// gets clobbered (in RTL the card then anchors right → drifts left).
|
||||||
|
transformTemplate={(t) =>
|
||||||
|
`translate(-50%, -50%) translate(${t.x ?? "0px"}, ${t.y ?? "0px"}) scale(${t.scale ?? 1})`}
|
||||||
style={{
|
style={{
|
||||||
filter: isWinner
|
filter: isWinner
|
||||||
? "drop-shadow(0 0 18px rgba(212,175,55,1)) drop-shadow(0 0 6px rgba(255,240,120,0.8))"
|
? "drop-shadow(0 0 18px rgba(212,175,55,1)) drop-shadow(0 0 6px rgba(255,240,120,0.8))"
|
||||||
@@ -468,14 +472,15 @@ function TrickArea({
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
{/* Burst particles when trick is won */}
|
{/* Burst particles when trick is won (centered on the felt) */}
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{phase === "trick-complete" && winner != null && (
|
{phase === "trick-complete" && winner != null && (
|
||||||
<TrickBurst key={`burst-${winner}`} seat={winner} />
|
<div key={`burst-${winner}`} className="absolute left-1/2 top-1/2 size-0">
|
||||||
|
<TrickBurst seat={winner} />
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user