JSFiddle - React, Tailwind, and code Playground
by Scott Kaye
HTML
<div class="grid-wrapper">
<div class="grid">
<div class="tile">
<span class="label">TR1ASD<strong>322</strong></span>
<div class="connector right"></div>
<div class="connector down"></div>
</div>
<div class="tile">
<span class="label">TR1DBD<strong>322</strong></span>
</div>
<div class="tile">
<span class="label">TR1ASQ<strong>318</strong></span>
</div>
</div>
</div>
<div class="controls">
<div>Pitch: <input type="range" id="pitch" min="10" max="70" value="50"></div>
<div>Yaw: <input type="range" id="yaw" min="-65" max="-25" value="-35"></div>
</div>
CSS
:root {
--square-height: 30px;
--ease: cubic-bezier(.41,.47,.45,.97);
}
body {
transform-style: preserve-3d;
display: flex;
height: 100vh;
overflow: hidden;
justify-content: center;
align-items: center;
background: radial-gradient(#727C87, #262F3B);
font-family: Segoe UI, sans-serif;
}
.controls {
position: absolute;
top: 0;
right: 0;
background: rgba(0, 0, 0, 0.25);
color: #ddd;
padding: 10px;
border-radius: 2px;
box-shadow: 1px 1px 0 rgba(255, 255, 255, 0.05), inset 5px 5px 10px rgba(0, 0, 0, 0.1);
margin: 10px;
}
.controls>div {
display: grid;
grid-template-columns: 1fr 2fr;
align-items: center;
font-weight: 500;
}
.grid-wrapper {
animation: grid-wrapper-in 1500ms var(--ease) 1 forwards;
}
@keyframes grid-wrapper-in {
from { opacity: 0; }
to { opacity: 1; }
}
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 100px;
transition: transform 1500ms var(--ease);
transform-style: preserve-3d;
}
.grid.dragging {
transition: none;
}
.tile {
backface-visibility: hidden;
width: 200px;
height: 200px;
background: radial-gradient(#ccc, #fff);
transform-style: preserve-3d;
position: relative;
display: flex;
justify-content: center;
align-items: center;
/* Bloom */
box-shadow: 0 0 50px 5px rgba(255, 255, 255, 0.25), inset 0 0 10px rgba(50, 127, 255, 0.5);
}
.tile::before,
.tile::after {
content: "";
position: absolute;
background: #8B929C;
bottom: 0;
left: 0;
right: 0;
height: var(--square-height);
transform: translateY(50%) rotateX(-90deg) translateY(50%);
/* AO */
filter: drop-shadow(0 0 30px rgba(0, 0, 0, 0.2));
}
.tile::after {
background: #7d7f82;
top: 0;
left: 0;
height: auto;
width: var(--square-height);
transform: rotateY(90deg) translateX(50%) translateZ(calc(var(--square-height) / -2));
}
.tile .label {
user-select:...
JavaScript
P(async () => {
const pitchControl = document.querySelector("#pitch");
const yawControl = document.querySelector("#yaw");
let camera = {
pitch: pitchControl.value,
yaw: yawControl.value
};
document.addEventListener("input", function(e) {
switch (e.target) {
case pitchControl:
camera.pitch = e.target.value;
break;
case yawControl:
camera.yaw = e.target.value;
break;
}
updateCamera();
}, false);
function updateCamera() {
document.querySelectorAll(".grid").forEach(grid => {
let transform = `rotateX(${camera.pitch}deg) rotateZ(${camera.yaw}deg)`;
grid.style.transform = transform;
});
}
updateCamera();
setTimeout(() => {
document.querySelectorAll(".grid").forEach(grid => {
grid.classList.add("dragging");
});
}, 1500);
})();