JSFiddle - React, Tailwind, and code Playground

by Rolf

HTML

<header></header>
<main id="scene">

<die-3d style="top: 20vh; left: 30vw;"></die-3d>
<die-3d style="top: 20vh; left: 60vw;"></die-3d>
<die-3d style="top: 60vh; left: 30vw;"></die-3d>
<die-3d style="top: 60vh; left: 60vw;"></die-3d>

</main>

CSS

:root {
  --table-size: 600px;
  --cards-height: 250px;
}
body {
  position: relative;
  margin: 0; padding: 0; height: 100vh;
  background: linear-gradient(0deg, #333 20%, #666 100%);
  perspective: calc(var(--perspective) * var(--table-size)/10);
  overflow: hidden;
}
header {
  position: absolute; display: inline-block;
  background-color: #fff8;
}
#scene {
  transform-style: preserve-3d; 
  background: linear-gradient(to right, #aaa8 0%, #aaa8 2%, transparent 5%) top left / 50px 50px,
              linear-gradient(to bottom, #aaa8 0%, #aaa8 2%, transparent 5%) top left / 50px 50px;
  width: 100vw;
  height: 100vh;
  padding-top: 30vh;
  transform: rotateY(calc(1deg * var(--sceneRotation)))
             rotateX(calc(1deg * var(--sceneTilt)));
}
die-3d {
  --size: 100px;
  --face: ivory;
  --dot: #338;
  --speed: .2s;
  animaxtion: 5s linear infinite cube-toss;
}

@keyframes cube-toss {
  0%   { transform: rotate3d(  1, 0, 1,   0deg); }
 20%   { transform: rotate3d(  0, 1, 1,  72deg); }
 40%   { transform: rotate3d( -1, 1, 0, 144deg); }
 60%   { transform: rotate3d( -1, 0,-1, 216deg); }
 80%   { transform: rotate3d(  0, 1,-1, 288deg); }
100%   { transform: rotate3d(  1, 0, 1, 360deg); }
}
@keyframes cube-tosrs {
  0%   { transform: rotateX(0.00turn) rotateY(0.00turn); }
  16%  { transform: rotateX(0.33turn) rotateY(0.50turn); }
  33%  { transform: rotateX(0.67turn) rotateY(1.00turn); }
  50%  { transform: rotateX(1.00turn) rotateY(1.50turn); }
  66%  { transform: rotateX(1.33turn) rotateY(2.00turn); }
  83%  { transform: rotateX(1.67turn) rotateY(2.50turn); }
  100% { transform: rotateX(2.00turn) rotateY(3.00turn); }
}

JavaScript

/* global document, console, localStorage */
// Above comment to make JSLint happy

"use strict";

// Teil 1: Szene drehen, kippen, Perspektive ändern
updateScene("sceneRotation")
updateScene("sceneTilt")
updateScene("perspective")

showSceneInfo();

document.addEventListener("keydown", function(keyEvent) {
   console.log(keyEvent);
   switch(keyEvent.key) {
     case '1': updateScene("sceneRotation", -5); break;
     case '2': updateScene("sceneRotation", +5); break;
     case 'q': updateScene("sceneTilt", -5); break;
     case 'a': updateScene("sceneTilt", +5); break;11
     case '+': updateScene("perspective", +1); break;
     case '-': updateScene("perspective", -1); break;
     case 't': runTest();
   }
   showSceneInfo();
});

function getSceneProperty(property) {
   let storedValue = localStorage.getItem(property);
   if (storedValue == null)
      storedValue = property == "perspective" ? 30 : 0;
   return parseInt(storedValue);
}

function updateScene(property, delta = 0) {
   let value = getSceneProperty(property) + delta;
   document.documentElement.style.setProperty("--"+property, value);
   localStorage.setItem(property, value);
}

function showSceneInfo() {
   let rotation = getSceneProperty("sceneRotation");
   let tilt = getSceneProperty("sceneTilt");
   let perspective = getSceneProperty("perspective");
   document.querySelector("body > header").textContent = `rotation: ${rotation}, tilt=${tilt}, perspective: ${perspective}`;
}

function setStyle(element, name, value) {
   // console.log("set " + name + " to " + value);
   element.style.setProperty(name, value);
}

// Teil 2: Die Custom Element
/* global customElements, HTMLElement */

class DieElement extends HTMLElement {
  // Das Element soll auf Änderungen des face Attributs reagieren 
  static get observedAttributes() {
    return ['face'];
  }
  // Callback für Reaktion auf Änderung von Attributen.
  // Würfel entsprechend des face-Wertes ausrichten
  attributeChangedCallback(name,...