Hemant Bhatt
4 min readSep 25, 2022

--

How to build a gaming analog stick in React

Recently I wanted to experiment with building an analog stick for the web, specifically for mobile. The obvious point to consider(since the solution was web based) was whether the performance is going be near native, like the one we see on mobile games or would the analog stick be laggy. Finally, I did end up creating a pretty good solution for the experiment and here is how I did it.

1. The UI 🎨

For the UI part, I quickly put together an analog stick design on figma. Nothing too fancy.

Analog stick design in figma

The yellow display div above the stick shows the x and y axis of the stick (more about that later).

Later, I used CSS grids with tailwind CSS to put together the elements of the stick for the mobile view.

Analog stick built with CSS grid

2. The stick movement 🥏

Ah yes! The interesting part! How do you animate and make the stick functional ? 🤔

The trick here is that we want the stick to fight the user’s moment. Whatever the user’s motion be, as soon as the user picks up his finger from the screen, we want the stick to bounce backs to its original place🕹️, like a rubber band.

I ended up using framer motion as it lets us use drag constraints for our motion div. When we have drag constraints as 0(in all four directions), we in a way imply that our div should always stay at its original position after the drag event has ended. Here is the code for the motion div.

The dragConstrainsts being 0 in every direction helps us indicate that the stick should always fallback to its orignal position once the user’s movement is over.

The dragElastic prop helps us decide the degree of movement allowed outside the defined constraints. Hence through this we achieve the rubber band effect.

The ref here is used to get the reference of the stick for calculating the x,y co-ordinates in the next section. One thing to note is that the reference was taken for both the inner stick and the outer stick.

3. The stick sampler📐

Once we can drag the stick, we now need the x and y co-ordinate to know the position of the stick in terms of its original position. We do have a onDrag synthetic event in react which is called every 350 milliseconds while the element is being dragged.

For some reason, no matter how hard I tried, I was not able to use the onDrag function to set state of x and y as it was throwing an error related to ' too many re-renders’. If you guys know what might be the reason for this, kindly let me know in the comments.

So now, because of the error, I took the approach of manually tracking and setting the state of the x,y coordinates according to the analog stick. This way I could also choose the custom sampling rate of the stick which could be much lower than 350 milliseconds for a much better experience.

To get the accurate location of the movable analog stick, I used this simple Cartesian plane design.

Cartesian plane for the analog stick

This red circle at the center(analog stick) is initially at (0,0). When it is moved, its coordinates is calculated according to the displacement in respect to the outer circle’s top and bottom part. We get this data through the Element.getBoundingClientRect() web API.

Here is the code for sampling the stick:

Here, the stickCircle is the inner analog stick which actually moves, and the outerstickCircle is the outer stick which remains stationary. I calculate the top and right pixel distances between the 2 circles and then set the x and y state accordingly at a rate of once every 150 ms.

The x and y states can be used for any UI related tasks or can be used for your own web based games.

4. Outcome🥁

Overall it was a pretty good experience building this thing.

You can access the source code here: https://github.com/reel-pre/web-gamepad-analog

And here is the final result:

--

--