Image reveal using a mask and CSS keyframes animations

Recently we at Fully Studios launched a site for the beautiful game Planet of Lana. One of the tasks was to create a image reveal effect for the style-frames / screenshots. You can see it in action here if you scroll down on the page.

TLDR;

Create a sprite sheet. Wrap your image in a element that you in CSS adds a mask-image to, and set mask-size: 400% 400%. Animate the mask-position using CSS keyframes.

The sprite

Create a image sprite-sheet, ex 4×4 sprites with the mask. Usually you need a quite big image, like 2048x2048px. But experiment what works best with your image, and also make sure your targeted devices supports that high resolution. The mask should have a transparent background (alpha channel) and the mask object should be black (and end in totally black / no alpha).

By default this means the alpha channel of the mask image will be multiplied with the alpha channel of the element.

MDN

Here’s an example:

Then create a element that you wrap your image in, and add a CSS mask-image property to it, set it’s mask-size to 100% * the number of sprites in each axis, in this case 400% 400%. And set the mask position to the top-left sprite:

.image-reveal {
  mask-image: url(/images/example-mask.png);
  mask-size: 400% 400%;
  mask-position: 0% 0%;
}

To trigger the keyframes animation, we use a JavaScript Intersection Observer API lissener when you have scrolled to the image (see this example how it could work), and attaching a visible class to the container. To this selecto we write a aniamtion declaration, and uses a steps(1) timing-function (easing) to make the flip-book animation that we want (else they will just animate smoothly in a very weird way):

.visible.image-reveal {
  animation: mask-reveal 1s 0s steps(1) forwards;
}

Lastly is the actual keyframes declaration for a 4 x 4 sprite sheet. Here we animated the mask-position so it goes from left to right, sprite 1, 2, 3 and 4, then it jumps down to row 2 (at 22%), and reveals sprite 5, 6 ,7 , 8 etc until it reaches the last sprite in the bottom right.

@keyframes mask-reveal {
  0% {
    mask-position: 0% 0%;
  }
  10% {
    mask-position: 33.33% 0%;
  }
  14% {
    mask-position: 66.66% 0%;
  }
  18% {
    mask-position: 100% 0%;
  }

  22% {
    mask-position: 0% 33.33%;
  }
  26% {
    mask-position: 33.33% 33.33%;
  }
  30% {
    mask-position: 66.66% 33.33%;
  }
  35% {
    mask-position: 100% 33.33%;
  }

  40% {
    mask-position: 0% 66.66%;
  }
  45% {
    mask-position: 33.33% 66.66%;
  }
  50% {
    mask-position: 66.66% 66.66%;
  }
  55% {
    mask-position: 100% 66.66%;
  }

  60% {
    mask-position: 0% 100%;
  }
  65% {
    mask-position: 33.33% 100%;
  }
  70% {
    mask-position: 66.66% 100%;
  }
  75%,
  100% {
    mask-position: 100% 100%;
  }
}

P.S

Don’t forget to wishlist the game on Steam here!

Leave a comment

Your email address will not be published. Required fields are marked *