Improve dice rolls.

This commit is contained in:
Greyson Parrelli
2026-07-23 10:26:15 -04:00
parent 44f8bcfcab
commit 7bb20e5d2d
6 changed files with 173 additions and 184 deletions
+78 -106
View File
@@ -1187,6 +1187,7 @@ h3 {
/* The battlefield is the lit heart of the table — a spotlit arena inset into
the felt, with a faint centre line where the two sides meet. */
.battlefield {
position: relative;
display: flex;
align-items: center;
justify-content: center;
@@ -1439,136 +1440,107 @@ h3 {
animation: unit-reveal 500ms ease;
}
@keyframes rock-fly-right {
0% {
opacity: 0;
transform: translateX(-70px) translateY(-10px) rotate(0);
}
20% {
opacity: 1;
}
100% {
opacity: 1;
transform: translateX(70px) translateY(4px) rotate(360deg);
}
}
/* --- rock dice --- */
@keyframes rock-fly-left {
0% {
opacity: 0;
transform: translateX(70px) translateY(-10px) rotate(0);
}
20% {
opacity: 1;
}
100% {
opacity: 1;
transform: translateX(-70px) translateY(4px) rotate(-360deg);
}
}
.rock-fly {
/* A little tray of dice under the thrower's side. Fixed slots: the dice
scramble in place, then settle showing the rolled rock faces. */
.dice-roll {
position: absolute;
font-size: 1.4rem;
z-index: 7;
pointer-events: none;
}
.rock-fly-right {
animation: rock-fly-right 700ms ease-in forwards;
}
.rock-fly-left {
animation: rock-fly-left 700ms ease-in forwards;
}
/* --- 3D rock dice --- */
.dice-tray {
position: absolute;
z-index: 8;
bottom: 8px;
display: flex;
gap: 10px;
perspective: 420px;
gap: 7px;
z-index: 8;
pointer-events: none;
transform: translateX(-50%);
}
.dice-roll-left {
left: 27%;
}
.dice-roll-right {
left: 73%;
}
.die {
--size: 34px;
--half: 17px;
.droll {
position: relative;
width: var(--size);
height: var(--size);
/* A filter here would flatten the cube, so it only carries the shadow. */
filter: drop-shadow(0 4px 5px rgba(0, 0, 0, 0.45));
width: 34px;
height: 34px;
border-radius: 7px;
box-sizing: border-box;
border: 2px solid var(--cocoa);
background: linear-gradient(145deg, var(--cream), var(--cream-dark));
box-shadow:
0 3px 5px rgba(0, 0, 0, 0.45),
inset 0 1px 0 rgba(255, 255, 255, 0.5);
}
.die-cube {
position: absolute;
inset: 0;
transform-style: preserve-3d;
/* From a heavily-spun start, settle onto this die's rolled face. */
animation: die-roll 720ms cubic-bezier(0.2, 0.8, 0.3, 1) both;
animation-delay: var(--delay, 0ms);
.droll.is-rolling {
animation: droll-shake 170ms linear infinite;
animation-delay: calc(var(--i) * 45ms);
}
@keyframes die-roll {
.droll.is-settled {
animation: droll-settle 280ms cubic-bezier(0.2, 0.85, 0.3, 1) both;
animation-delay: calc(var(--i) * 55ms);
}
@keyframes droll-shake {
0% {
transform: rotateX(calc(var(--rx) - 900deg)) rotateY(calc(var(--ry) - 1080deg));
transform: rotate(-9deg) translateY(0) scale(1.06);
}
25% {
transform: rotate(7deg) translateY(-2px) scale(1.09);
}
50% {
transform: rotate(-6deg) translateY(1px) scale(1.05);
}
75% {
transform: rotate(8deg) translateY(-1px) scale(1.08);
}
100% {
transform: rotateX(var(--rx)) rotateY(var(--ry));
transform: rotate(-9deg) translateY(0) scale(1.06);
}
}
.die-face {
@keyframes droll-settle {
0% {
transform: scale(1.22) rotate(-5deg);
}
60% {
transform: scale(0.95) rotate(1deg);
}
100% {
transform: scale(1) rotate(0);
}
}
/* A rock icon: a lumpy gray boulder. */
.droll-rock {
position: absolute;
inset: 0;
display: grid;
place-items: center;
border-radius: 6px;
background: linear-gradient(145deg, var(--cream), var(--cream-dark));
border: 2px solid var(--cocoa);
box-sizing: border-box;
width: 14px;
height: 14px;
background: radial-gradient(circle at 35% 28%, #838a90, #34373c);
clip-path: polygon(22% 6%, 60% 0%, 90% 24%, 100% 58%, 82% 96%, 42% 100%, 8% 82%, 0% 40%);
}
.die-front {
transform: translateZ(var(--half));
}
.die-back {
transform: rotateY(180deg) translateZ(var(--half));
}
.die-right {
transform: rotateY(90deg) translateZ(var(--half));
}
.die-left {
transform: rotateY(-90deg) translateZ(var(--half));
}
.die-top {
transform: rotateX(90deg) translateZ(var(--half));
}
.die-bottom {
transform: rotateX(-90deg) translateZ(var(--half));
.droll-n-1 .droll-rock {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.die-pips {
display: grid;
gap: 4px;
padding: 5px;
.droll-n-2 .droll-rock {
width: 12px;
height: 12px;
}
.die-pips-1 {
grid-template-columns: 1fr;
.droll-n-2 .droll-rock:nth-child(1) {
top: 30%;
left: 30%;
transform: translate(-50%, -50%);
}
.die-pips-2 {
grid-template-columns: repeat(2, 1fr);
}
.die-pip {
width: 8px;
height: 8px;
border-radius: 50%;
background: radial-gradient(circle at 35% 30%, #6b7075, #2c2f33);
box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.35);
.droll-n-2 .droll-rock:nth-child(2) {
top: 70%;
left: 70%;
transform: translate(-50%, -50%);
}
@keyframes fx-pop {