JSFiddle - React, Tailwind, and code Playground

by Константин Дралюк

HTML

<div class="box" id="b">
  <div>
    <img src="https://cms-assets.tutsplus.com/uploads/users/107/posts/25888/image/flat-icon-design6-%5BConverted%5D.jpg" alt="" id="i">
  </div>
  <div class="xor-text -nixie" data-text="Nixie">Nixie</div>
  <div class="xor-text -core" data-text="Core">Core</div>
</div>

CSS

body {
  margin: 100px;
}

.box {
  transform-style: preserve-3d;
  perspective: 1000px;
  display: table;
}

img {
  width: 600px;
  height: 400px;
  display: block;
}

.xor-text {
  position: absolute;
  font-size: 50px;
  font-weight: bold;
  text-transform: uppercase;
  font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
  color: transparent;
  user-select: none;
  pointer-events: none;
}

.xor-text:after, .xor-text:before {
  content: attr(data-text);
  position: absolute;
  left: 0;
  top: 0;
  white-space: nowrap;
}

.xor-text:before {
  mix-blend-mode: overlay;
  color: #000;
}

.xor-text:after {
  mix-blend-mode: color-dodge;
  color: #fff;
}

.xor-text.-nixie {
  left: -.65em;
  top: 1em;
}

.xor-text.-core {
  right: -.6em;
  bottom: 1em;
}

#i {
  transition: 1s ease-out;
}

JavaScript

const getCssString = (rx = 0, ry = 0, delta = 0.02, deep = 200) => {
  return `rotateX(${rx * delta}deg) rotateY(${ry * delta}deg) translateZ(${deep}px) scale(${1 - deep / 1000})`
}

b.addEventListener('mousemove', e => {
	const rects = b.getClientRects()[0]
  const mouseX = e.offsetX - rects.width / 2
  const mouseY = e.offsetY - rects.height / 2
	i.style.transform = getCssString(-mouseY, mouseX, 0.05, 200)
	t.style.transform = getCssString(-mouseY, mouseX, 0.05, 200)
})

b.addEventListener('mouseleave', e => {
	i.style.transform = ''
})