<div class="tilebase">
  <div class="tilemask" style="--depth: 0;"></div>
  <div class="tilemask" style="--depth: 1;"></div>
  <div class="tilemask" style="--depth: 2;"></div>
  <div class="tilemask" style="--depth: 3;"></div>
  <div class="tilemask" style="--depth: 4;"></div>
  <div class="tilemask" style="--depth: 5;"></div>
  <div class="tilemask" style="--depth: 6;"></div>
</div>
<div class="tile">
  Tile:<br>
  <input type="range" step="0.25" value="2" min="0.25" max="3" oninput="tile(this.value)">
</div>
<a style="position: absolute; bottom: 1rem; left: 50%; transform: translateX(-50%); color: white;" href="http://jane.propjockey.io/">Follow me on Twitter!</a>
<div class="accents">
  Accent:
  <label><input type="radio" name="accent" onclick="accent('initial')" checked> None</label>
  <label><input type="radio" name="accent" onclick="accent('gold')"> Gold</label>
  <label><input type="radio" name="accent" onclick="accent('cyan')"> Cyan</label>
  <label><input type="radio" name="accent" onclick="accent('rebeccapurple')"> Purple</label>
  <label><input type="radio" name="accent" onclick="accent('red')"> Red</label>
  <label><input type="radio" name="accent" onclick="accent('white')"> White</label>
  <label><input type="radio" name="accent" onclick="accent('black')"> Black</label>
</div>

* {
  box-sizing: border-box;
  margin: 0px;
  padding: 0px;
  font-family: sans-serif;
}
body {
  display: grid;
  height: 100vh;
  overflow: hidden;
  background: radial-gradient(circle at right, #8a8655, #62633a, #2c3416, #0c1800 80%);
}
.tilebase {
  --wall: 512px;
  --tile: 2;
  --size: calc(var(--wall) / var(--tile));
  --offset: (var(--size) / 40);
  position: relative;
  margin: auto;
  transform-style: preserve-3d;
  transform: perspective(2019px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) translateZ(50px);
  width: var(--wall);
  height: var(--wall);
  background: var(--accent, url(https://i.imgur.com/lY6jkFw.png) 0 100% / var(--size) var(--size));
  /* original/unmodified source of image: https://www.flickr.com/photos/robertjewett/25131705462/ */
}
.tilebase .tilemask {
  position: absolute;
  width: 100%;
  height: 100%;
  background: url(https://i.imgur.com/lY6jkFw.png) 0 100% / var(--size) var(--size);
  transform: translateZ(calc(var(--depth) * var(--offset)));
  -webkit-mask: url(https://i.imgur.com/0YebqQu.png) left 0 bottom calc(var(--size) * (var(--depth) + 1)) / var(--size) calc(var(--size) * 7);
  mask: url(https://i.imgur.com/0YebqQu.png) left 0 bottom calc(var(--size) * (var(--depth) + 1)) / var(--size) calc(var(--size) * 7);
}

.accents {
  font-weight: bold;
  color: white;
  position: absolute;
  bottom: 0px;
  right: 0px;
  width: 7rem;
  padding: 1rem;
}
.accents label {
  display: block;
  padding: 0.25rem;
}
.accents input {
  float: right;
  margin-top: 0.125rem;
}
.tile {
  padding: 1rem;
  font-weight: bold;
  color: white;
  text-align: center;
  position: absolute;
  left: 50%;
  top: 0px;
  transform: translateX(-50%);
}

const b = document.body
const t = b.querySelector(".tilebase")
b.addEventListener("pointermove", ev => {
  const ang = 30
  const w = (b.offsetWidth / 2)
  const x = ev.pageX - w
  const ax = Math.abs(x)
  const sx = x === 0 ? 0 : x / ax
  const h = (b.offsetHeight / 2)
  const y = ev.pageY - h
  const ay = Math.abs(y)
  const sy = y === 0 ? 0 : (y / ay * -1)
  const rx = Math.min(ang, ay / Math.min(512, h) * ang) * sy + "deg"
  const ry = Math.min(ang, ax / Math.min(512, w) * ang) * sx + "deg"
  t.style.setProperty("--rx", rx)
  t.style.setProperty("--ry", ry)
})
const accent = c => {
  t.style.setProperty("--accent", c)
}
const tile = v => {
  t.style.setProperty("--tile", v)
}
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.