solitaire: let cards be dragged, not only tapped

Tapping stays exactly as it was. A press that travels more than a few
pixels becomes a drag instead, and both paths go through the same pick()
and accepts(), so what lights up and what a move means never depends on
how you did it. The run follows the pointer as a copy while the real
cards stay on the felt, faded, and letting go over nothing keeps the run
in your hand with the targets still lit.

Capture happens when the press becomes a drag, not on pointerdown:
capturing early retargets the click that a tap ends with, and tapping
quietly stops working.
This commit is contained in:
prosolis
2026-07-18 09:03:08 -07:00
parent 19255d933a
commit 8aa3e762ca
4 changed files with 186 additions and 2 deletions
+46
View File
@@ -1498,6 +1498,52 @@ html[data-phase="night"] {
/* A move that won't go. Said in the one language a board can speak. */
.pete-nope { animation: pete-shake 0.4s cubic-bezier(0.36, 0.07, 0.19, 0.97); }
/* Dragging. A press on a card that can be lifted belongs to the card and not to
the page, or a drag down a column scrolls the board instead of moving a run. */
.pete-card[data-live="1"] { touch-action: none; }
[data-solitaire][data-dragging] { cursor: grabbing; user-select: none; }
[data-solitaire][data-dragging] .pete-card[data-live="1"]:hover .pete-card-front {
filter: none;
}
/* The run you lifted stays on the felt, faded: where it came from, and where it
goes back to if you let go over nothing. */
[data-solitaire][data-dragging] .pete-card[data-held="1"] {
opacity: 0.3;
transform: none;
}
[data-solitaire][data-dragging] .pete-card[data-held="1"] .pete-card-front {
box-shadow: none;
}
/* The copy under your hand. It doesn't answer to hit tests — the felt beneath it
has to be the thing you're pointing at. */
.pete-drag {
position: fixed;
left: 0;
top: 0;
z-index: 60;
pointer-events: none;
filter: drop-shadow(0 14px 22px rgba(0, 0, 0, 0.45));
transform: translate3d(-999px, -999px, 0);
}
.pete-drag .pete-card { position: relative; }
.pete-drag[data-ok="1"] .pete-card-front {
box-shadow: 0 0 0 3px rgba(242, 181, 61, 0.9);
}
/* The pile you're actually over, told apart from the ones that would merely
take it. */
.pete-slot[data-over="1"],
.pete-col[data-over="1"] .pete-slot,
.pete-col[data-over="1"] .pete-card:last-child .pete-card-front {
border-color: rgba(242, 181, 61, 1);
box-shadow: 0 0 0 4px rgba(242, 181, 61, 0.75);
}
.pete-slot[data-over="1"],
.pete-col[data-over="1"] .pete-slot {
background: rgba(242, 181, 61, 0.24);
}
/* A card arriving on a foundation lands with a flash: it is the only move in
the game that pays you, so it is the only one that gets a noise. */
.pete-home-flash { animation: pete-home 0.5s ease-out; }