# Cool Profile Picture Animation in HTML, CSS, and JS

I saw this cool pixilation filter in the About Us section of a landing page, but it was static and boring. So, I created this effect using pure HTML, CSS, and JS and animated it on hover to reveal the faces.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1717329590340/19fffb8b-ac52-4eaa-bbe7-e6f0455c39cf.png align="center")

## The Demo

Photo by [Alex Suprun](https://unsplash.com/@sooprun?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash) on [Unsplash](https://unsplash.com/photos/man-in-black-button-up-shirt-ZHvM3XIOHoE?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash)

%[https://codepen.io/davidreddy293/pen/xxNqyWX] 

## The Code

```xml
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Pixel Profile Pic test</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      body {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
        background-color: #000814;
      }

      .main_container {
        width: 100%;
        min-height: 100vh;
        overflow: hidden;
        display: flex;
        justify-content: center;
        align-items: center;
      }

      .outerImage {
        width: 400px;
        height: 400px;
        display: flex;
        justify-content: center;
        align-items: center;
        background-image: url("/pi.png");
        background-size: cover;
        background-position: center;
        overflow: hidden;
        border-radius: 20%;
      }

      .innerImage {
        width: 100%;
        height: 100%;
        background-size: cover;
        background-position: center;
        clip-path: polygon(20% 20%, 80% 20%, 80% 80%, 20% 80%);
        border-radius: 20%;
      }
    </style>
  </head>
  <body>
    <div class="main_container">
      <div
        class="outerImage"
        onmouseenter="removePixelation()"
        onmouseleave="applyPixelation()"
      >
        <canvas id="canvas" class="innerImage"></canvas>
      </div>
    </div>

    <script>
      var img = new Image();
      img.src = "/pi.png";
      img.onload = function () {
        console.log("image loaded");
        draw(this);
      };

      var pixels = [];

      var canvas = document.getElementById("canvas");
      var ctx = canvas.getContext("2d");
      var size = 30; // size of the pixels
      var imgData;

      function draw(img) {
        canvas.width = img.width;
        canvas.height = img.height;
        ctx.drawImage(img, 0, 0, img.width, img.height);
        imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
        applyPixelation();
      }

      var originalImagel;
      function applyPixelation() {
        console.log("applying pixelation");

        originalImagel = ctx.getImageData(0, 0, canvas.width, canvas.height);
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // Create an array of all pixel positions
        pixels = [];
        for (var i = 0; i < imgData.width; i += size) {
          for (var j = 0; j < imgData.height; j += size) {
            pixels.push({ x: i, y: j });
          }
        }

        // Shuffle the array
        pixels.sort(() => Math.random() - 0.5);

        var index = 0;
        function drawPixel() {
          for (let k = 0; k < 4; k++) {
            // Draw 4 pixels at a time
            if (index >= pixels.length) {
              return; // All pixels have been drawn
            }
            var pixel = pixels[index++];
            var color = getAverageColor(pixel.x, pixel.y, size, imgData);
            ctx.fillStyle =
              "rgb(" + color.r + "," + color.g + "," + color.b + ")";
            ctx.fillRect(pixel.x, pixel.y, size, size);
          }
          setTimeout(drawPixel, 0); // Call drawPixel again after a delay
        }
        drawPixel(); // Start the drawing process
      }

      //   function removePixelation() {
      //     ctx.putImageData(imgData, 0, 0);
      //   }
      function removePixelation() {
        if (!pixels || pixels.length === 0) {
          // Reinitialize the pixels array if needed
          pixels = [];
          for (var i = 0; i < imgData.width; i += size) {
            for (var j = 0; j < imgData.height; j += size) {
              pixels.push({ x: i, y: j });
            }
          }
          // Reverse the order of the pixels to un-pixelate from the last to the first
          pixels.reverse();
        }

        var index = 0;
        function revealPixel() {
          for (let k = 0; k < 4; k++) {
            // Reveal multiple pixels at a time for a faster animation
            if (index >= pixels.length) {
              return; // All pixels have been revealed
            }
            var pixel = pixels[index++];
            // Clear the specific pixel block
            ctx.clearRect(pixel.x, pixel.y, size, size);
            // Draw the original pixels within each block from the stored original image
            ctx.putImageData(
              originalImagel,
              -pixel.x,
              -pixel.y,
              pixel.x,
              pixel.y,
              size,
              size
            );
          }
          setTimeout(revealPixel, 0); // Call revealPixel again after a delay
        }
        revealPixel(); // Start the revealing process
      }

      function getAverageColor(x, y, size, imgData) {
        var total = { r: 0, g: 0, b: 0, count: 0 };
        for (var i = 0; i < size; i++) {
          for (var j = 0; j < size; j++) {
            var idx = (x + i + (y + j) * imgData.width) * 4;
            total.r += imgData.data[idx + 0];
            total.g += imgData.data[idx + 1];
            total.b += imgData.data[idx + 2];
            total.count++;
          }
        }
        return {
          r: (total.r / total.count) | 0,
          g: (total.g / total.count) | 0,
          b: (total.b / total.count) | 0,
        };
      }
    </script>
  </body>
</html>
```

## The Conclusion

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1717330662175/6c56b263-b7ec-4ff5-88e5-834459a41e95.png align="center")

I added this cool animated pixel effect to my portfolio site. It makes the profile picture come to life when you hover over it. Check it out at [daviddodda.com](http://daviddodda.com).

and shutout to [@d](https://daviddodda.com)[omi\_kissi](https://x.com/domi_kissi) and [@inCleveri](https://x.com/inCleveri) for the inspiration.
