Using PixiJS to generate or animate a Chrome Extension icon
Tags: chrome, icons, webgl, javascript
Published: 2017-09-23 21:59:39

---
title: "Using PixiJS to generate or animate a Chrome Extension icon"
published: true
tags: chrome,icons,webgl,javascript
canonical_url: https://hackernoon.com/using-pixijs-to-generate-or-animate-a-chrome-extension-icon-cad2d5ff40c9
cover_image: https://cdn-images-1.medium.com/max/1024/1*INDPbjoKv1glkuTj2DkzBg.png
---

For the last few months I’ve primarily been tinkering with different chrome extensions/plugins. From extensions that simply darken your webpage, to extensions that override the new tab and inject in it a ton of websites, to create sort of a workspace. You can check my latest work [here](https://chrome.google.com/webstore/search/k.ivanow)

### Disclaimer:

Everything that is described bellow can be done with pure canvas js codding, instead of using [PixiJS](http://www.pixijs.com/). However I’ve grown quite fond of [PixiJS](http://www.pixijs.com/) since I have used it at work and for several side projects.

### Why would anyone do&nbsp;this?

At first icons are the most boring part of any project (especially for developers like myself). However this is exactly why some minor touches in an icon can have great impact on the users. I have seen a lot of extensions for Chrome (all adblockers, Limitless, etc) that use the icon badge to display text in it (how many ads are blocked, how much time have you spent on the current webpage,&nbsp;etc).

However earlier today I thought that I haven’t seen any extension, that animates its icon. I searched for a while and saw several StackOverflow posts that explain how to animate icon, by switching between a set of images, defined in the manifest. I decided that it has to be a better way and found that chrome.browserAction.setIcon() receives not only path to the icon, but can accept imageData as well! _Hooray!!!_ Now, let us proceed to the main part of this&nbsp;article.

### How to animate the&nbsp;icon

The thought process is straight forward and the execution is&nbsp;easy:

1. Create background page (it will be responsible for the rendering and updating of the&nbsp;icon)
2. Create [PixiJS](http://www.pixijs.com/)stage in the background page (it will actually animate the&nbsp;icon)
3. Decide on animation — [PixiJS](http://www.pixijs.com/) has pretty awesome set of filters, tints, scales, skews and so on… Decide what you want to animate and figure out how to animate it. For me, I decided to use my latest extension — [Mindfulness](https://chrome.google.com/webstore/detail/mindfulness/blpljgcghbboofdodkmciihhacgjoffo) was mainly centered on how much time you have left to live (Memento Mori sort of thing) so I decided that an animated clock that changes its color would be appropriate.
4. Execute said animation and update the chrome extension icon on every&nbsp;frame.

#### A few things to keep in&nbsp;mind:

1. [PixiJS](http://www.pixijs.com/) ticker will not work in a background page. Nothing based on requestAnimation will work, since the background page is never focused. Use setInterval and animate in it. I use around 33ms, but I could’ve used a 1000ms, it all depends on the animation you have decided to&nbsp;make.
2. When extracting the stage as imageData, don’t use the size of the stage, instead use the size of the renderer. The stage is just a container and as such, its width and height are changed by its children. This can result in stretching, squashing or distorting the icon in any other&nbsp;way.
3. Chrome extension icons have issues when the size gets over 190px, according to [this answer on StackOverflow](http://stackoverflow.com/a/37602444/4424049), so I keep it at128x128.

So, I created a clock class that creates and animates a clock (_who would’ve guessed_).

```javascript
var PixiClock = function() {
    this.size = 128;
    this.events = {
        frameRendered: new Signal(),
    }
    this.app = new PIXI.Application(this.size, this.size, { transparent: true });

    document.body.appendChild(this.app.view);

    PIXI.loader.add('icon', 'img/icon512.png').load(function(loader, resources) {

        this.icon = new PIXI.Sprite(resources.icon.texture);
        this.createLines();
        this.app.stage.addChild(this.icon);

        var animate = function() {
            this.lines.secondsLine.rotation = PIXI.DEG_TO_RAD * new Date().getSeconds() * 6;
            this.lines.minutesLine.rotation = PIXI.DEG_TO_RAD * new Date().getMinutes() * 6;
            this.lines.hoursLine.rotation = PIXI.DEG_TO_RAD * new Date().getHours() * 30;
            this.app.renderer.render(this.app.stage);
            this.events.frameRendered.dispatch();
        }.bind(this);
        setInterval(animate, 33);

        animate();
    }.bind(this));
};

PixiClock.prototype.createLines = function(color) {
    var lineWidth = 60;
    this.icon.scale.set(1, 1);

    this.lines = {
        secondsLine: new PIXI.Graphics(),
        minutesLine: new PIXI.Graphics(),
        hoursLine: new PIXI.Graphics()
    }

    for (var i in this.lines) {
        this.icon.addChild(this.lines[i]);
        this.lines[i].cacheAsBitmap = true;
        this.lines[i].lineStyle(lineWidth, 0xffffff);
        this.lines[i].tint = color != undefined ? color : 0x333333;
        this.lines[i].position = {
            x: this.icon.getBounds().width / 2 - lineWidth / 2,
            y: this.icon.getBounds().height / 2
        };
        this.lines[i].moveTo(0, 0 + lineWidth);
        this.lines[i].lineTo(0, 0 - this.icon.getBounds().height / 2);
    }
    // graphics.endFill();

    this.lines.hoursLine.scale.set(1, 0.7);
    this.lines.minutesLine.scale.set(1, 0.8);

    this.icon.scale.set((this.size / this.icon.width), (this.size / this.icon.height));
};

PixiClock.prototype.deleteLines = function() {
    this.icon.removeChildren();
}
```

The concept is&nbsp;simple

1. Create stage
2. Add the main icon of the extension
3. Add 3 lines (one for each clock&nbsp;hand)
4. Rotate them based on the current&nbsp;time
5. Change their colour by recreating them for certain tabs (this logic is out of the scope of the&nbsp;article)
6. Dispatch event on every&nbsp;frame
7. In the background page, catch this event and update the extension icon

```javascript
var pixiClock = new PixiClock();
pixiClock.events.frameRendered.add(function() {
    chrome.browserAction.setIcon({
        imageData: pixiClock.app.renderer.plugins.extract.canvas(pixiClock.app.stage).getContext("2d").getImageData(
            0, 0,
            pixiClock.app.stage.width, pixiClock.app.stage.height
        )
    });
})
```

Here is the end result. I use two styles for the arrows depending on the webpage the user is&nbsp;at.

![](https://cdn-images-1.medium.com/max/164/1*03D71diPHSc0JlE1eVt-HA.gif)

#### Prologue

_I guess_

I just came up with something that I haven’t seen done (at least so far. Feel free to correct me if I am wrong) and how to do it and decided to share&nbsp;it.

Something similar can be done with a large set of assets, that can be switched to simulate an animation, which is the most common approach I’ve seen while my brief research for the&nbsp;article.

The exact same result can be done with a simple canvas and JS code. I prefer [PixiJS](http://www.pixijs.com/) because I am familiar with it and it allows me to make more complex animations, if I decide&nbsp;to.

I hope that you found this article interesting, even if it is for the sole fact that you can just take some part of animated canvas or WebGL context and use it as an icon for chrome extension, instead of a simple png. You can even create your whole icon by simple shapes and filters or blend modes, if you have the time and desire to do&nbsp;so.

_P.S. Check out the_ [_extension_](https://chrome.google.com/webstore/detail/mindfulness/blpljgcghbboofdodkmciihhacgjoffo)_, that was the cause for the idea behind this&nbsp;article._

* * *


_This post was originally published on [medium.com](https://hackernoon.com/using-pixijs-to-generate-or-animate-a-chrome-extension-icon-cad2d5ff40c9)_