React with PixiJS

Mikka Pineda
3 min readOct 9, 2018

--

Do they play nice?

My little side project today was to make a simple Javascript game inspired by an old patent for a prairie dog vacuum:

Making the game allowed me to explore quirky interactions and UX animations I don’t normally get to implement in the B2B apps I build at work. Here’s a demo video of the result:

I built this using React 16 and PixiJS 4, with the aid of the react-pixi-fiber package that allows you to write PixiJS applications using React’s declarative style. Code available here. React-pixi-fiber works with React 16, unlike react-pixi (which only works with React 15… and did not work out so well for me).

PixiJS is a cross-browser compatible 2D Javascript graphics library that lets you dynamically generate and display graphical elements, such as drawings and animations. A nice thing about PixiJS is that it can render in either WebGL or HTML5 <canvas> in case one or the other does not support rendering a particular type of graphical element (more on this below).

(BTW, if you want to work with 3D graphics, three.js is a popular option.)

Though WebGL ultimately renders content through a <canvas> element, the <canvas> API alone is quite limited in what you can do with it. Some say <canvas> is really just the gateway drug to WebGL. Both are Javascript APIs, but with some key differences:

  • WebGL is hardware (as in, GPU) accelerated, so it’s faster than canvas — something that comes in handy when working with computationally expensive operations like 3D transformations.
  • Some things are just technically impossible to render with <canvas>, such as shaders, filters, and meshes. WebGL is much more flexible because its underlying technology, the OpenGL ES 2.0 API, lets you achieve almost any graphical effect you want, even glowing and blurring.
  • Canvas API is much easier to learn than WebGL — it doesn’t require strong math skills (do you remember the relationship between sine and cosine?)
  • Fortunately, with the help of libraries like PixiJS, harnessing the power of WebGL is just as easy as using <canvas>

When using PixiJS with react-pixi-fiber, I found myself creating a React component for each PixiJS object then controlling each object through props. This tied the state of the Pixi application with the state of the React app. Though I loved being able to program a Pixi application declaratively, the react-pixi-fiber package currently only supports a subset of PixiJS features. Sorely missed are meshes, masks and filters.

One way around this is to write the whole Pixi application separately from your React components then load the Pixi application in React’s componentDidMount() lifecycle method. The Pixi application can manage its own state; it doesn’t need the enclosing React app to manage it. Besides, all the Pixi content gets rendered inside a <canvas> element anyway. For example, here’s the HTML for the prairie dog game above:

<html>
<head>...</head>
<body>
<div id="root">
<canvas width="1434" height="391">
</div>
<script src="/static/js/bundle.js"></script>
<script src="/static/js/1.chunk.js"></script>
<script src="/static/js/main.chunk.js"></script>
</body>
</html>

None of the Pixi elements — prairie dogs, vacuum hoses, text, gopher holes, etc. — get their own DOM element nor can <canvas> be traversed like a DOM tree. Since you can’t and don’t need to have all your Pixi objects represented in React’s virtual DOM tree, it isn’t necessary to create a React component for each Pixi object.

The advantage of not React-ifying each object in your Pixi application is twofold:

  • you can access all of Pixi’s features, including meshes, masks and filters
  • it reduces the number of elements that React needs to diff during reconciliation

On the other hand, you lose the declarative programming style of React. Either way, I’m happy PixiJS exists just because it expands creative freedom for the web developer.

--

--