Barrier Grid Animation: Illusions on the Web Part 2
This is the second in an article series discussing different optical illusions & mechanical toys and how we can recreate them on the web (and improve them).
Due to the nature of this method, some animations shown here will be fast and fill large screen space. All animations are paused by default. Also, the techniques here require
mix-blend-mode support, so as of this writing Edge will not be supported.
In various forms over the years, I have seen a technique to create animation in books or other non-digital and non-video forms. They go by many different names (Kinegrams, Scanimation®, stereographs), but for this discussion we will use the term “Barrier Grid Animation” as it describes the main shared component to create the illusion of motion.
In the non-digital world, this consists of a transparent sheet/cel with evenly spaced black lines on top of a second layer consisting of a seemingly chopped image. While not required, most of the time we are talking about vertical lines, so that is what we will assume.
With just these two physical elements you can create several frames of animation. By only moving the topmost layer the underlying collection of seemingly random lines take shape and animate.
Constructing the Layers
Both layers follow a pattern based on the width of a bar. For simplifying the math, we will use
1px as our base unit. Our first example had five frames of a pink ball moving around. For such an animation, our top layer (the barrier) should consist of a
1px wide transparent bar followed by
4px of a black bar, repeated.
The bottom layer (consisting of the animation’s frames) will be
1px wide of the first frame, followed by
1px of the second frame, etc. This also is repeated, so when our barrier grid is overlaid the same frame will be visible through the small transparent bar, while the other four are covered. The following example demonstrates this (zoomed in for clarification) with each color representing a different frame.
As we move the top layer left and right we will see effectively one frame at a time in sequence. We are blocking out a majority of each image, but our brain will do its best to fill in the missing pieces as the animation progresses by moving the top layer.
We want a pattern for our image where every fifth pixel is from frame 1, every fifth pixel plus one shows frame 2, etc. We will take the following markup where each unnamed div represents a frame (though the
div.barrier could also be implemented as a pseudoelement):
The cover boils down to a linear gradient to the right with
1px transparency and
4px black. I use CSS Variables to adapt it as I go, such as if I want to quickly see what happens if I change the base unit to
The hardest part of setting up the barrier grid animation is creating the base image with the chopped frames. However, with blend modes and repeating linear gradients we can accomplish it with CSS.
Chopping the Frames
We can take an image and prep it to be a frame in our animation by using multiple backgrounds — the topmost background being a repeating linear gradient on top of the image we want to chop.
To get our second frame we apply the same gradient, but we adjust the
background-position. You can use a preprocessor to adjust this offset without repeating code, though we are only dealing with a few frames so the resulting CSS would be:
We need to stack our frames over each other so we can position them all as
absolute, but we will only see the last frame at this point since we do not have anything with transparency on our frames. Luckily we chose
white as our gradient color which will pair nicely with a
mix-blend-mode: multiply setting.
See the Pen Repeating Linear Gradient Over an Image with Transparency by Dan Wilson (@danwilson) on CodePen.
A whole series could be written on blend modes, or even simply on multiplying colors. The quick-ish version is that for multiple overlapping elements, we look at each pixel and perform a function to blend the colors on each layer at that pixel. More specifically, the functions happen on each of the three RGB channel values, mapping to a range of
1 (so a value of
255 in a channel would equal
1). With multiplication, whenever we have any color multiplied by black (with an R,G,B of
0,0,0), the resulting color will always be black. This comes from standard mathematics where multiplying any number by zero will result in zero.
black x red
rgb(0,0,0) x rgb(1,0,0)
rgb(0 x 1, 0 x 0, 0 x 0) = rgb(0,0,0);
Similarly, multiplying by white is like multiplying a number by one. Any number times one is equal to that same number, so any color multiplied by white will equal the same color.
white x red
rgb(1,1,1) x rgb(1,0,0)
rgb(1 x 1, 1 x 0, 1 x 0) = rgb(1,0,0);
With the math out of the way, we can see how applying the blend mode of
multiply can let the white bars of each frame effectively become transparent by letting anything that is not white be visible. Since each frame is offset by
1px all frames are seen at once and our image is officially “chopped.”
Bringing it all together
With the barrier constructed and the underlying animation images chopped, we are able to create our animation by moving our topmost layer horizontally. You can either do this with a fixed animation, tie into pointer events where you must drag the barrier layer, or tying it into the accelerometer to get that real old school magical vibe. I show these last two techniques in this full demo (for iOS or other devices that do not allow iframes to access accelerometer, you can view the direct demo)
Are there better ways to achieve animation on the web?
Okay, fine. This technique grew out of putting animation into books and small toy packages. We have actual animation in CSS where the browser can fill in the frames for us, and we have the easing option
steps() (with future improvements coming) for cases where we want to specify frames more granularly.
But… this was at least fun, right?