<div id="root"></div>
* {
box-sizing: border-box;
}
:root {
--dice-size: 100px;
--dice-scale: 0.5;
--dot-size: 8px;
--dot: radial-gradient(currentColor var(--dot-size), transparent 0);
--face-background: radial-gradient(
rgb(165 41 41 / 69%) 50%,
rgb(127 13 13 / 69%)
);
color: rgba(255, 255, 255, 0.87);
background-image: radial-gradient(#114410 1px, #102e15 0);
background-size: 10px 10px;
}
#root {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
body {
font-family: "Host Grotesk", serif;
}
button {
font-family: inherit;
}
.main-form {
margin: 0 auto 4rem;
display: flex;
flex-direction: column;
gap: 1rem;
max-width: 10rem;
label {
display: flex;
flex-direction: column;
gap: 0.625rem;
font-size: 1.2rem;
}
input {
border-radius: 8px;
padding: 0.5rem;
font-size: 1rem;
}
}
.primary-button {
padding: 0.5rem 1rem;
font-size: 1rem;
letter-spacing: 1px;
font-weight: bold;
background: linear-gradient(145deg, #d4b03d, #c66a1a);
color: white;
border: none;
border-radius: 15px;
cursor: pointer;
transition: background 300ms;
text-transform: uppercase;
}
.primary-button:hover {
background: linear-gradient(145deg, #e6bc54, #d68910);
}
.dice-container {
display: flex;
flex-wrap: wrap;
gap: 1rem;
justify-content: center;
}
.dice {
width: var(--dice-size);
height: var(--dice-size);
perspective: 1000px;
filter: drop-shadow(0 20px 15px rgba(0, 0, 0, 0.5));
opacity: 0;
animation: fade-in 250ms var(--animation-delay) ease-in forwards;
}
.dice__cube {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d;
animation-duration: 800ms;
animation-delay: var(--animation-delay);
animation-timing-function: cubic-bezier(0.36, 0, 0.66, 1);
animation-fill-mode: forwards;
}
.dice__face {
display: grid;
place-items: center;
position: absolute;
width: var(--dice-size);
height: var(--dice-size);
background: rgba(97, 10, 10, 0.8);
color: rgb(243, 244, 217);
border-radius: 16px;
font-size: 34px;
}
/* front */
.dice__face:nth-child(2) {
translate: 0 0 calc(var(--dice-size) / 2);
background-image: var(--dot), var(--dot), var(--face-background);
background-size: 50% 50%, 50% 50%, 100% 100%;
background-repeat: no-repeat;
background-position: 0 0, 100% 100%, 50% 50%;
}
/* right */
.dice__face:nth-child(3) {
transform: rotateY(90deg) translateZ(calc(var(--dice-size) / 2));
background-image: var(--dot), var(--dot), var(--dot), var(--face-background);
background-size: 50% 50%, 50% 50%, 50% 50%, 100% 100%;
background-repeat: no-repeat;
background-position: 0 100%, 50% 50%, 100% 0, 50% 50%;
}
/* back */
.dice__face:nth-child(5) {
transform: rotateY(180deg) translateZ(calc(var(--dice-size) / 2));
background-image: var(--dot), var(--dot), var(--dot), var(--dot), var(--dot),
var(--face-background);
background-size: 50% 50%, 50% 50%, 50% 50%, 50% 50%, 50% 50%, 100% 100%;
background-repeat: no-repeat;
background-position: 0 0, 0 100%, 50% 50%, 100% 0, 100% 100%, 50% 50%;
}
/* left */
.dice__face:nth-child(4) {
transform: rotateY(-90deg) translateZ(calc(var(--dice-size) / 2));
background-image: var(--dot), var(--face-background);
background-size: 50% 50%, 100% 100%;
}
/* top */
.dice__face:nth-child(1) {
transform: rotateX(90deg) translateZ(calc(var(--dice-size) / 2));
background-image: var(--dot), var(--face-background);
}
/* bottom */
.dice__face:nth-child(6) {
transform: rotateX(-90deg) translateZ(calc(var(--dice-size) / 2));
background-image: var(--dot), var(--dot), var(--dot), var(--dot), var(--dot),
var(--dot), var(--face-background);
background-size: 50% 50%, 50% 50%, 50% 50%, 50% 50%, 50% 50%, 50% 50%,
100% 100%;
background-repeat: no-repeat;
background-position: 0 0, 0 50%, 0 100%, 100% 0, 100% 50%, 100% 100%, 50% 50%;
}
.dice--1 {
.dice__cube {
transform: scale(var(--dice-scale)) rotateX(-60deg) rotateY(-45deg)
translateY(-200px) rotateZ(0deg);
animation-name: throw-dice;
}
}
.dice--2 {
.dice__cube {
transform: scale(var(--dice-scale)) rotateX(30deg) rotateZ(-45deg)
translateZ(200px) rotateX(0deg);
animation-name: throw-dice-2;
}
}
.dice--3 {
.dice__cube {
transform: scale(var(--dice-scale)) rotateY(-90deg) rotateZ(-30deg)
rotateX(45deg) translateX(200px) rotateY(0deg);
animation-name: throw-dice-3;
}
}
.dice--4 {
.dice__cube {
transform: scale(var(--dice-scale)) rotateY(90deg) rotateZ(30deg)
rotateX(-45deg) translateX(-200px) rotateY(0deg);
animation-name: throw-dice-4;
}
}
.dice--5 {
.dice__cube {
transform: scale(var(--dice-scale)) rotateX(-60deg) rotateY(-45deg)
rotateX(-90deg) translateZ(-200px) rotateY(0deg);
animation-name: throw-dice-5;
}
}
.dice--6 {
.dice__cube {
transform: scale(var(--dice-scale)) rotateX(-60deg) rotateY(-45deg)
rotateX(180deg) translateY(200px) rotateZ(0deg);
animation-name: throw-dice-6;
}
}
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes throw-dice {
35% {
transform: scale(var(--dice-scale)) rotateX(0deg) rotateY(-45deg)
translateY(0) rotateZ(360deg);
}
50% {
transform: scale(var(--dice-scale)) rotateX(-20deg) rotateY(-45deg)
translateY(-60px) rotateZ(540deg);
}
65% {
transform: scale(var(--dice-scale)) rotateX(-40deg) rotateY(-45deg)
translateY(0) rotateZ(630deg);
}
80% {
transform: scale(var(--dice-scale)) rotateX(-50deg) rotateY(-45deg)
translateY(-20px) rotateZ(690deg);
}
100% {
transform: scale(var(--dice-scale)) rotateX(-60deg) rotateY(-45deg)
translateY(0) rotateZ(720deg);
}
}
@keyframes throw-dice-2 {
35% {
transform: scale(var(--dice-scale)) rotateX(90deg) rotateZ(-45deg)
translateZ(0) rotateX(-360deg);
}
50% {
transform: scale(var(--dice-scale)) rotateX(70deg) rotateZ(-45deg)
translateZ(60px) rotateX(-540deg);
}
65% {
transform: scale(var(--dice-scale)) rotateX(60deg) rotateZ(-45deg)
translateZ(0) rotateX(-630deg);
}
80% {
transform: scale(var(--dice-scale)) rotateX(50deg) rotateZ(-45deg)
translateZ(20px) rotateX(-690deg);
}
100% {
transform: scale(var(--dice-scale)) rotateX(30deg) rotateZ(-45deg)
translateZ(0) rotateX(-720deg);
}
}
@keyframes throw-dice-3 {
35% {
transform: scale(var(--dice-scale)) rotateY(-90deg) rotateZ(-30deg)
rotateX(60deg) translateX(0) rotateY(360deg);
}
50% {
transform: scale(var(--dice-scale)) rotateY(-90deg) rotateZ(-30deg)
rotateX(50deg) translateX(60px) rotateY(540deg);
}
65% {
transform: scale(var(--dice-scale)) rotateY(-90deg) rotateZ(-30deg)
rotateX(30deg) translateX(0) rotateY(630deg);
}
80% {
transform: scale(var(--dice-scale)) rotateY(-90deg) rotateZ(-30deg)
rotateX(40deg) translateX(20px) rotateY(690deg);
}
100% {
transform: scale(var(--dice-scale)) rotateY(-90deg) rotateZ(-30deg)
rotateX(45deg) translateX(0) rotateY(720deg);
}
}
@keyframes throw-dice-4 {
35% {
transform: scale(var(--dice-scale)) rotateY(90deg) rotateZ(30deg)
rotateX(-10deg) translateX(0) rotateY(360deg);
}
50% {
transform: scale(var(--dice-scale)) rotateY(90deg) rotateZ(30deg)
rotateX(0deg) translateX(-60px) rotateY(540deg);
}
65% {
transform: scale(var(--dice-scale)) rotateY(90deg) rotateZ(30deg)
rotateX(-25deg) translateX(0) rotateY(630deg);
}
80% {
transform: scale(var(--dice-scale)) rotateY(90deg) rotateZ(30deg)
rotateX(-40deg) translateX(-20px) rotateY(690deg);
}
100% {
transform: scale(var(--dice-scale)) rotateY(90deg) rotateZ(30deg)
rotateX(-45deg) translateX(0) rotateY(720deg);
}
}
@keyframes throw-dice-5 {
35% {
transform: scale(var(--dice-scale)) rotateX(-60deg) rotateY(-45deg)
rotateX(-60deg) translateZ(0) rotateY(-360deg);
}
50% {
transform: scale(var(--dice-scale)) rotateX(-60deg) rotateY(-45deg)
rotateX(-80deg) translateZ(-60px) rotateY(-540deg);
}
65% {
transform: scale(var(--dice-scale)) rotateX(-60deg) rotateY(-45deg)
rotateX(-60deg) translateZ(0) rotateY(-630deg);
}
80% {
transform: scale(var(--dice-scale)) rotateX(-60deg) rotateY(-45deg)
rotateX(-80deg) translateZ(-20px) rotateY(-690deg);
}
100% {
transform: scale(var(--dice-scale)) rotateX(-60deg) rotateY(-45deg)
rotateX(-90deg) translateZ(0) rotateY(-720deg);
}
}
@keyframes throw-dice-6 {
35% {
transform: scale(var(--dice-scale)) rotateX(-60deg) rotateY(-45deg)
rotateX(250deg) translateY(0) rotateZ(-360deg);
}
50% {
transform: scale(var(--dice-scale)) rotateX(-60deg) rotateY(-45deg)
rotateX(220deg) translateY(60px) rotateZ(-540deg);
}
65% {
transform: scale(var(--dice-scale)) rotateX(-60deg) rotateY(-45deg)
rotateX(200deg) translateY(0) rotateZ(-630deg);
}
80% {
transform: scale(var(--dice-scale)) rotateX(-60deg) rotateY(-45deg)
rotateX(190deg) translateY(20px) rotateZ(-690deg);
}
100% {
transform: scale(var(--dice-scale)) rotateX(-60deg) rotateY(-45deg)
rotateX(180deg) translateY(0) rotateZ(-720deg);
}
}
/*
* https://frontendeval.com/questions/rolling-dice
*
* Create a dice roller application that can roll anywhere from 1-99 six-sided dice
*/
function Dice({ value, index }: { value: number; index: number }) {
const className = `dice dice--${value}`;
const styles = {
"--animation-delay": `${index * 50}ms`,
} as React.CSSProperties;
return (
<div className={className} style={styles}>
<div className="dice__cube">
{Array(6)
.fill("")
.map((_, index) => (
<div key={index} className="dice__face"></div>
))}
</div>
</div>
);
}
function App() {
const [numberOfDice, setNumberOfDice] = React.useState<string>("");
const [diceValues, setDiceValues] = React.useState<number[]>([
1, 2, 3, 4, 5, 6,
]);
const [round, setRound] = React.useState<number>(0);
function handleNumberOfDiceChange(
event: React.ChangeEvent<HTMLInputElement>
) {
setNumberOfDice(event.target.value);
}
function handleNumberOfDiceSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
if (!numberOfDice) {
return;
}
const newDiceValues = Array.from(
{ length: parseInt(numberOfDice) },
() => Math.floor(Math.random() * 6) + 1
);
console.log(newDiceValues);
setDiceValues(newDiceValues);
setRound((round) => round + 1);
}
return (
<>
<form className="main-form" onSubmit={handleNumberOfDiceSubmit}>
<label>
Number of dice:
<input
type="number"
max={99}
min={1}
name="numberOfDice"
value={numberOfDice}
onChange={handleNumberOfDiceChange}
/>
</label>
<button className="primary-button" type="submit">
Roll
</button>
</form>
<div className="dice-container">
{diceValues.map((value, index) => (
<Dice key={`${index}-${round}`} value={value} index={index} />
))}
</div>
</>
);
}
ReactDOM.render(<App />, document.getElementById('root'));
View Compiled
This Pen doesn't use any external CSS resources.