diff --git a/public/game.html b/public/game.html
index 391613b..16f5662 100644
--- a/public/game.html
+++ b/public/game.html
@@ -371,6 +371,30 @@ logs... {
+ el.classList.remove("last-move-dest");
+ el.classList.remove("last-move-source");
+ });
+ } catch (_) {}
+ try {
+ const prevCircles = boardEl.querySelectorAll(".last-move-circle");
+ prevCircles.forEach((c) => c.remove());
+ } catch (_) {}
+
+ if (data && data.boardState) renderBoardFromState(data.boardState);
if (data && data.boardState) updateTurnBanner(data.boardState);
+
+ try {
+ // only highlight the destination square (not the source). create a proper .last-move-circle
+ if (data && data.from && data.to && data.from !== data.to) {
+ const dest = boardEl.querySelector(`.square[data-square="${data.to}"]`);
+ if (dest) {
+ dest.classList.add("last-move-dest");
+ }
+ const fromEl = boardEl.querySelector(`.square[data-square="${data.from}"]`);
+ if (fromEl) {
+ fromEl.classList.add("last-move-source");
+ }
+ // persist last move per room so a refresh can restore highlights
+ try {
+ if (roomId) {
+ const key = `cn:lastMove:${roomId}`;
+ localStorage.setItem(key, JSON.stringify({ from: data.from, to: data.to, ts: Date.now() }));
+ }
+ } catch (e) {}
+ }
+ } catch (_) {}
} catch (e) {
console.warn("move:moved handler error", e);
}
@@ -1412,7 +1469,20 @@ logs... (s.innerHTML = ""));
+ squares.forEach((s) => {
+ // remove any last-move visual state from previous turns
+ try {
+ s.classList.remove("last-move-dest");
+ s.classList.remove("last-move-source");
+ } catch (_) {}
+ // remove any lingering circle markers
+ try {
+ const prev = s.querySelectorAll('.last-move-circle');
+ prev.forEach((c) => c.remove());
+ } catch (_) {}
+ // clear square contents (pieces/markers)
+ s.innerHTML = "";
+ });
// place pieces according to boardState.pieces (expects algebraic square names)
(boardState.pieces || []).forEach((p) => {
diff --git a/public/styles/style.css b/public/styles/style.css
index f499c78..8e18fc2 100644
--- a/public/styles/style.css
+++ b/public/styles/style.css
@@ -49,8 +49,8 @@ a:hover{text-decoration:underline}
#board{border:1px solid rgba(11,18,32,0.06);position:relative;background-image: url('/assets/chess-pieces/boards/8x8_wood.svg');background-size:cover}
/* square cells and piece images (used by renderFen) */
-.square{width:100%;height:100%;display:flex;align-items:center;justify-content:center}
-.square img, .piece{max-width:78%;max-height:78%;user-select:none}
+.square{width:100%;height:100%;display:flex;align-items:center;justify-content:center;overflow:hidden}
+.square img, .piece{max-width:78%;max-height:78%;user-select:none;position:relative;z-index:3}
/* marker shown on target squares for legal moves */
.square{position:relative}
@@ -245,4 +245,23 @@ button:hover{transform:translateY(-3px);transition:all 180ms ease}
}
#board.shuffle-play .square img{ transition: transform 700ms cubic-bezier(.2,.9,.2,1); transform: rotate(2deg) scale(0.995); filter: drop-shadow(0 6px 18px rgba(0,0,0,0.06)); }
+/* overlay that fills the whole square (subtle green) so the entire cell is highlighted */
+.square.last-move-dest::after{
+ content: '';
+ position: absolute;
+ left: 0; top: 0; right: 0; bottom: 0;
+ background: rgb(164, 229, 208);
+ pointer-events: none;
+ z-index: 2;
+}
+
+/* subtle highlight for the source square of the last move (less prominent) */
+.square.last-move-source::after{
+ content: '';
+ position: absolute;
+ left: 0; top: 0; right: 0; bottom: 0;
+ background: rgb(164, 229, 208);
+ pointer-events: none;
+ z-index: 2;
+}