Creating an animated Pacman pattern
Tags: css, html
Published: 2020-09-20 01:16:00

---
title: Creating an animated Pacman pattern
published: true
description: How to create an animated pattern using CSS gradients and backgrounds.
tags: CSS,HTML
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/x2y505p9txdrfmnv3uxh.png
---

In this post, we are going to see how to build an animated Pacman-looking pattern like this one:

{% codepen https://codepen.io/alvaromontoro/pen/NWNOebR %}

As you may have noticed on the demo above, **we are just using CSS without HTML or JS**. (Technically, the page still has the `<html>` and `<body>` tags, but it is cool to see the HTML section all empty.)

We are going to build it using CSS gradients ([`linear-gradient`](https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient), [`radial-gradient`](https://developer.mozilla.org/en-US/docs/Web/CSS/radial-gradient), and the less-supported-but-super-cool [`conic-gradient`](https://developer.mozilla.org/en-US/docs/Web/CSS/conic-gradient)), which will help us to create patterns with the `background-image` property.

## Setting the dots pattern

The Pacman pattern will consist of a dark background with dots all over the place. To generate the dots, we use `radial-gradient` and set a `background-size` to make sure that the pattern is small and repeated (by default) instead of only showing one big circle:

```css
html, body {
  background-color: black;
  background-image: radial-gradient(white 10%, transparent 0);
  background-size: 8vmin 8vmin;
}
```

With that code, we will get the whole screen with a black background covered with white dots. Something like this:

![Dark image with repeating dots](https://dev-to-uploads.s3.amazonaws.com/i/ddqqsyfyep7u666rut3b.png)

## Adding a wall

We are going to add a blue wall all around the screen. The easiest way is to add a double inset box-shadow by adding this to the previous CSS rule:

```css
  box-shadow: inset 0 0 0 2vmin black, inset 0 0 0 2.5vmin blue;
  border-radius: 3vmin;
  width: 100vw;
  height: 100vh;
  padding: 0;
  margin: 0;
```

The new code looks like this:

![Dark image with repeating dots and a border surrounding everything](https://dev-to-uploads.s3.amazonaws.com/i/0da0hcxq866u8btzc4le.png)

## Adding Pacman

To create Pacman, we are going to use the `::after` pseudo-element. We are going to make it round by adding a `border-radius:50%` and the mouth will be generated by using a `conic-gradient`: 

```css
body::after {
  content: "";
  display: block;
  top: 0;
  left: 0;
  position: absolute;
  width: 8vmin;
  height: 8vmin;
  border-radius: 50%;
  background: conic-gradient(yellow 55deg, transparent 0 125deg, yellow 0);
}
```

Not all browsers support conic gradients, so our Pacman may look a bit funky for some users. Instead, we could use a clip-path, which would also allow us to animate the mouth move.

With the code above, our Pacman will be at the top left corner of the screen. Change the `top` value to put it at a different height within the screen (use multiples of 8vmin that is the size we have used):

![Previous image, including a Pacman figure at the top left corner](https://dev-to-uploads.s3.amazonaws.com/i/n2az1ncp5auo2czwv055.png)

## Animating things!

Let's start by animating the opening and closing of the Pacman's mouth. We are going to do it by replacing the conic gradient with another that is fully filled, and back:

```css
@keyframes eat {
  0%, 50% { background: conic-gradient(yellow 55deg, transparent 0 125deg, yellow 0); }
  25% { background: conic-gradient(yellow 55deg, yellow 0);}
}
```

> Note: to avoid annoying flickering, we use a conic-gradient that places everything as yellow instead of just setting the background to yellow.

Now we add the following property to the `body::after` and our Pacman opens and closes its mouth:

```css
  animation: eat 0.4s linear infinite;
```

As the `background-image` property is not animatable, it will jump from one state to another without a smooth transition. It's not great, but it will provide a _vintage_ look.

Now let's make Pacman move from left to right. We can do that by changing the position of the background.

```css
@keyframes movePacman {
  0% { transform: translate(-8vmin, 0) }
  100% { transform: translate(100vw, 0) }
}
```

CSS allows multiple animations on the same element; we need to separate them by a comma. So we update the `animation` property of our Pacman to accordingly:

```css
  animation: eat 0.4s linear infinite, 
             movePacman 6s linear infinite;
```

Which leads us to this:

![Animation of Pacman moving through the screen](https://dev-to-uploads.s3.amazonaws.com/i/730w4dle51whzbxf2v8r.gif)

## Final touches

Right now, our Pacman is going through walls and on top of dots without really eating them. Let's fix that with a couple of changes:

### Breaking the walls

We have used the `::after` pseudo-element for drawing Pacman, we still have `::before` to use for "breaking" the walls. We will do that by having a small square in the same position as the Pacman that will go over the wall:

```css
body::before {
  content: "";
  display: block;
  position: absolute;
  width: 2vmin;
  height: 8vmin;
  background: black;
  left: 0;
  top: 40vmin;
  box-shadow: calc(100vw - 2vmin) 0 black;
}
```

Now it is a bit nicer because it looks like the Pacman is being transported from the right to the left in the same way that happens in the actual videogame:

![Screen with the Pacman moving around](https://dev-to-uploads.s3.amazonaws.com/i/jwrwgypd59v95nblcsp5.png)

### Eating dots

But there's one thing left, and it is one thing that is a bit annoying: Pacman goes over the dots, but it never actually eats them.

We can solve that in different ways: having the `::before` grow along with the Pacman's path, have a box-shadow that grows... all of them with the idea to stimulate that Pacman is eating when actually the dots are just hidden behind the new background.

We will do it with a new background that will go directly in the `body`, so we will modify how the background is established there:

```css
  background-image:  linear-gradient(black,  black), radial-gradient(white 10%, transparent 0);
  background-size: 100vw 8vmin, 8vmin 8vmin;
  background-repeat: no-repeat, repeat;
  background-position: calc(-4vmin - 100vw) 40vmin, 0 0;
```

And we need an animation that moves with Pacman:

```css
@keyframes move {
  0% { background-position: calc(-4vmin - 100vw) 40vmin, 0 0; }
  100% { background-position: 0 40vmin, 0 0; }
}
```

And with that, we have the result. But the code is a bit messy. So, let's have a final step for...

## Cleaning the code

We have our animated pattern working, but right now, it is a bit "restrictive." All the values are hardcoded, and while there's nothing excessively wrong with it, it makes things complicated if we want to update positions, sizes, or colors.

And talking about colors, they are too "bright." We should make them a little bit softer. And the animation is a bit slow; we can adjust the timing to something more appropriate.

Some final touches would be:

- Start using CSS variables for sizes, positions, and colors.
- Use `calc()` to calculate positions (and avoid magic numbers)
- Replace colors with softer versions

The leads to the final result that we saw earlier, a zero-element animated Pacman pattern:

{% codepen https://codepen.io/alvaromontoro/pen/NWNOebR %}