<input type="checkbox" name="play" id="play">
<label for="play" class="playBtn"></label>

<div class="scene">
  <div class="cube">
    <div class="wall front"></div>
    <div class="wall back"></div>
    <div class="wall left"></div>
    <div class="wall right"></div>
    <div class="wall top"></div>
    <div class="wall bottom"></div>
  </div>
</div>
body {
  margin: 0; /* this overrides the default margin - which is crucial if your background isn't white/blank/undefined */
  box-sizing: border-box; /* ensures that the border is within the container's limits rather than outside */
  background-color: black; /* the hex code for dark gray, the equivalent of rgb(48,48,48) or hsl(0deg 0% calc( 100% / 16 *3)), and a shorthard for #333333 )*/
  display: grid; /* you could alternately use */
  place-items: center; /* centers every object vertically and horizontally */
  min-height: 100vh; /* we need the viewport (the browser window) to be 100vh (100 viewport height units) so that there is enough space to suspend the object in */
  filter: drop-shadow(0 0 3em lime); /* adds a green glow to the white lines */
  font-size: .5vh; /* sets a fontsize dependent on the height of the viewport */
}

.scene {
  width: 100em; /* sets the width to be 100 units of the font size, thus ensuring responsive scaling that mimics percentages */
  aspect-ratio: 1; /* makes sure the height matches the width of the container, making it a square*/
  perspective: 250em; /* sets the distance of the perspective */
  position: absolute; /* makes the position of the container independent of any other neighboring container - placed wherever you want rather than relative to its neighbors, and free to overlap */
}

.scene * {
  transform-style: preserve-3d; /* makes sure that each container nested inside the .scene tag treats its nested content as a 3D object rather than a 2D projection */
  position: absolute; /*see absove*/
  inset: 0; /* gives the containers nested in the .scene tag a margin of 0, thus making them fill it 100% in width and height; this is shorthand for top, right, bottom, left */
}

.cube {
  rotate: y 20deg;
  animation: spin 6s linear infinite; /* adds a slow spinning animation */
}

.wall {
  border: 3em solid white; /* each wall has a white border - which is contained within the wall's width (this is what box-sizing: border-box does) */
}

.front {
  transform: translateZ(50em); /* pushes the wall out forward from the center, as if closer to the viewer*/
}

.back {
  transform: translateZ(-50em); /* pushes the wall back, farther from the viewer*/
}

.left {
  transform: rotateY(90deg) translateZ(50em); /* turns the wall clockwise, to its left (your right), then pushes it forward (again: its forward, not yours) */
}

.right {
  transform: rotateY(-90deg) translateZ(50em); /* turns the wall counterclockwise, to its right (your left), then pushes it forward (again: its forward, not yours) */
}

.top {
  transform: rotateX(90deg) translateZ(50em); /* turns the wall clockwise, towards the ceiling, then pushes it forward (again: its forward, not yours) */
}

.bottom {
  transform: rotateX(-90deg) translateZ(50em); /* turns the wall counterclockwise, towards the floor, then pushes it forward (again: its forward, not yours) */
}

@keyframes spin { /* the details of the cube's spinning animation: */

  100% { /* in the course of the animation, at the end of it... */
    rotate: y 380deg; /* ...the cube will make a full 360 degree turn, adding to the the 20 degrees that it was already rotated */
  }

}


/* OPTIONAL READING

This section details the appearance and the functioning of the play/pause toggler. It is not a part of the cube - but still a fun thing to learn if you're up for it.

*/

input {
  display: none; /* hides the input, we'll have a label for it instead that is nicer than a tick-box */
}

.playBtn { /* that's the label */
  position: absolute;
  width: 40em;
  aspect-ratio: 1;
  z-index: 1; /* places the label on a layer above the cube - as otherwise it'd be inside the 3D solid, and you wouldn't be able to interact with it */
  display: grid; /* this label will have nested content, and we want it centered */
  place-items: center;
  transition: all .5s ease-in-out; /* when you interact with the button - hover, check/uncheck the input - it will change appearance. This makes it switch between each look smoothly rather than instantly */
}

.playBtn::before, .playBtn::after { /* these are a kind of containers within a container; they aren't declared in the HTML by you - but will show up in the page inspector */
  content: ''; /* text or special characters go here - but we don't need any, we just want containers */
  position: absolute;
  inset: 0 0 50% 0; /* this creates a container that covers the upper half of the space available*/
  border-style: solid;
  border-color: #fff #fff0 #fff0 #fff;
  border-width: 3em 0 0 3em; /* these are all expanded border properties*/
  transform-origin: 0% 100%; /* this places the pivot of the container in its bottom left corner */
  transform: skewY(25deg); /* creates a downward rhomboid */
  transition: inherit; /* borrows transition properties from its parent container */
}

.playBtn::before {
  --dir: 1; /* a custom variable for the direction of transforms; translations applied to the container will be multiplied by this variable; here it changes nothing... */
}

.playBtn::after {
  --dir: -1; /* ...but here it makes the translation take on a negative value, and thus go in the other direction */
  scale: 1 -1; /* the scale on the horizontal axis (the first number) stays the same, but on the vertical (the latter) it is negative, so the object is flipped upside down*/
}

.playBtn:hover { /* when you mouse over the label... */
  scale: 1.25; /* ...it gets a little bit larger */
}

.playBtn:hover::before,
.playBtn:hover::after  {
  filter: drop-shadow(0 0 3em lime); /* ...and it starts glowing brighter */
}

#play:not(:checked) ~ .scene .cube { /* if the PLAY button hasn't been pressed */
  animation-play-state: paused; /* ...the animation is paued */
}

#play:checked ~ .playBtn { /* when you hit the PLAY button */
  rotate: -90deg; /* ...it turns to its side */
}

#play:checked ~ .playBtn::before,
#play:checked ~ .playBtn::after  {
  transform: none;
  inset: 35% 0;
  border-color: #fff;
  border-width: 3em;
  transform-origin: center;
  translate: 0 calc(-80%*var(--dir)); /* ...and turns into a pause button */
}

@media (orientation: portrait) { /* for mobile screens displaying in portait mode (a tall, narrow rectangle) */
  body {
    font-size: .5vw; /* the font size is now depended on the viewport width - rather than height - since now it's the narrower of the two dimensions */
  }
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.