Published on

CSS Minecraft: The Most Insane CSS-Only Game Ever Created

Authors

CSS Minecraft: The Most Insane CSS-Only Game Ever Created

I stumbled upon CSS Minecraft through this viral tweet calling it "the coolest CSS hack ever" - and they're absolutely right. This fully playable Minecraft clone by Benjamin Aster uses zero JavaScript, just pure HTML and CSS wizardry.

The Mind-Blowing Hacks

Radio Buttons as Game State: Each cube contains 8 hidden radio buttons (one per block type). Clicking a cube face actually triggers a <label> that selects a radio button, storing the game state entirely in HTML form elements.

<div class="cube stone">
  <input type="radio" name="cube-layer-0-row-0-column-0" id="cube-layer-0-row-0-column-0-stone" />
  <label for="cube-layer-0-row-1-column-0-stone" class="front"></label>
  <label for="cube-layer-0-row--1-column-0-stone" class="back"></label>
  <!-- ... more faces -->
</div>
& > input[type='radio'] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

The :has() Selector Magic: The modern :has() pseudo-class detects which radio buttons are checked and applies corresponding styles. When you select "stone" in the toolbar, CSS hides all non-stone blocks.

.controls:has(> .block-chooser > .stone > input[type='radio']:checked)
  ~ main
  .cubes-container
  > .cube:not(.stone) {
  display: none;
}

.cubes-container:has(> .cube.grass > input[type='radio']:checked) {
  --background-image: var(--grass-image);
}

Label-Based Block Placement: Here's the genius part - each cube face label points to the neighboring cube's radio button. Click the front face? It activates the block in front. Click the top? The block above appears. Pure CSS interaction.

<!-- This cube at row 0, column 0 -->
<label for="cube-layer-0-row-1-column-0-stone" class="front"></label>
<!-- Points to row 1 (front) -->
<label for="cube-layer-0-row--1-column-0-stone" class="back"></label>
<!-- Points to row -1 (back) -->
<label for="cube-layer--1-row-0-column-0-stone" class="top"></label>
<!-- Points to layer -1 (above) -->

Movement Without JavaScript: Movement uses paused CSS animations with absurdly long durations (10000s). Holding a button triggers :active, which sets animation-play-state: running.

.content {
  --animation-duration: 10000s;
  --max-translation: 400000rem;
}

& .down {
  animation: var(--animation-duration) linear 1ms paused move-down;
}

@keyframes move-down {
  from {
    translate: 0 0;
  }
  to {
    translate: 0 calc(var(--max-translation));
  }
}

.controls:has(.up:active) ~ main .down {
  animation-play-state: running;
}

3D World with CSS Transforms: The entire world uses perspective, preserve-3d, and calculated positions. Each cube gets inline custom properties that position it via calc() functions.

<div class="cubes-container" style="--layer: 0; --row: 1; --column: 2"></div>
main {
  perspective: var(--camera-distance);
  &,
  & * {
    transform-style: preserve-3d;
  }
}

.cubes-container {
  translate: calc(var(--column) * var(--cube-size)) calc(var(--layer) * var(--cube-size))
    calc(var(--row) * var(--cube-size));
}

& > label {
  &.front {
    rotate: y 0grad;
  }
  &.back {
    rotate: y 200grad;
  }
  &.top {
    rotate: x 100grad;
  }
}

The Pickaxe "Air Block" Trick: Selecting the pickaxe (air block) and clicking any cube selects its "air" radio button, which has display: none - effectively deleting the block.

.cubes-container:has(> .cube.air > input[type='radio']:checked) {
  display: none;
}

.controls:has(.air > input[type='radio']:checked) ~ main .cubes-container:hover > .cube > label {
  filter: brightness(70%);
  outline: calc(var(--cube-size) / 24) solid white;
}

This pushes CSS so far beyond its intended purpose that it's almost offensive to web standards - and I love it. The fact that this works at all is a testament to how powerful modern CSS has become.