<div class="skew">
  <div class="skew__item">
    <img src="https://pbs.twimg.com/media/BcvmxibIYAAH8a3.jpg" />
  </div>
  <div class="text">
    <p>
      :hover over this cat.
    </p>
</div>
</div>

* {
  font-family: Helvetica, sans-serif;
  margin: 0;
  color: white;
}

.skew {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  background: black;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  --x-translate: 0;
  --y-translate: 0;
  &:hover {
    .skew__item {
      transform: matrix3d(1,0,0.00,var(--x-translate),0.00,1,0.00,var(--y-translate),0,0,1,0,0,0,0,1); 
    }
  }
  &__item {
    width: 60vw;
    max-width: 500px;
    box-shadow: -5px -5px 100px -40px rgba(white, 0.3);
    img {
      width: 100%;
      height: 100%;
      object-fit: cover;
    }
    transition: 0.4s cubic-bezier(0.64, 0.57, 0.67, 1.53);
    &:hover {
      transition: 0.4s ease-out;
    }
  }
}

h1{
  & + p {
    margin-top: 10px;
  }
}

p {
  line-height: 1.5;
}

.text {
  padding: 1.5rem 2rem 0;
  text-shadow: 1px 1px 2px black;
}
View Compiled
const skewItemContainer = document.querySelector(".skew");
const skewItem = document.querySelector(".skew__item").getBoundingClientRect();
const imageCenterX = skewItem.left + skewItem.width / 2;
const imageCenterY = skewItem.top + skewItem.height / 2;
skewItemContainer.addEventListener("mousemove", function(e) {
  const clientX = e.clientX;
  const clientY = e.clientY;

  const xCalc = (clientX - imageCenterX) * 0.000003;
  const yCalc = (clientY - imageCenterY) * 0.000003;
  skewItemContainer.style.setProperty("--x-translate", `${xCalc}`);
  skewItemContainer.style.setProperty("--y-translate", `${yCalc}`);
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.