How to be a god at FlappyBird (and feel like a supahacka)

Aymeric Arnoult
4 min readFeb 22, 2022

This is the occasion to take a revenge against this horribly frustrating game.

Go to http://flappybird.io/. Open devtools with ctrl(command for mac users)+maj+I. (This will work best on Chrome or Firefox; with Safari, you have to toggle their visibility before).

Flappy score to the moon

Enter the Matrix

In the sources tab, click on the app.js file. You should have a pretty-print button. Click it.

Search var stage.

Variables in the code
Variables in the console

See ? All variables and functions are in the global scope. It means that the whole page, including devtool, can see, access, and mutate those variables. If you try to type stage in the console tab, your should see a result.

Therefore we’re going to play with it. Try preventing the death sentence by typing

die = null

You should now be able to continue playing after hitting a pipe, generating some glitches with the pipe due to their regenerations.

Pipe bug
Pipe glitch

But that’s quite unfortunate, as without the death menu, it’s now impossible to submit our score to the global leaderboard :((

Submit score

Well, I think you already thought about it, right ? Yep, correct, there is a function to do that. I’ll save you some seconds : it is named submitScore. It takes a single argument, which is a google analytics token to be able to identify you, which is also available in the window scope (window is the name of the global scope in the browser context). It is even visible in the console at the beginning of the game.

So, to submit your score, simply type

submitScore(token)

Tadaam ! You’re in the official leaderboard.

Choose your score

Getting a high score like this is way more handy. But, what if you could directly modify the score ?

As the game is coded thanks to a special engine which uses canvas, you can not simply change the value of a HTML tag in the elements tab. Fortunately, via some JS variables, you can still access it.

With some research in the die function, you will end up finding the counter.text variable holding the score. In Javascript, everything is mutable by default. That’s why you can simply type

counter.text = 455654567485987589

It will give a weird visual rendering as the outline is not updated consequently. Nevermind. Don’t forget to launch a game before so that you get a token ! You can just repeat the submit step to push the score to the leaderboard after that, with a funny pseudo if you like :

Leaderboard
Leaderboard

Avoid this on your game

Make stuff immutable

As we said earlier, everything in JS is mutable by default.

var variable = "i am mutable"
variable = "i am mutated" // valid
var obj = { property: "i am mutable" }
obj.property = "i am mutated" // valid

To protect against this possibility, you have two mechanisms in JS. For primitive variables, using const instead of var will make it immutable.

const immutable = 'i am immutable'

immutable = 'i am mutated' // Uncaught TypeError: Assignment to constant variable.

NB: regardless of what you are trying to achieve, it is generally a good idea to use const in the most places you can to avoid unwanted variable mutation. 90% of the time, you do not need var or let.

For compound objects, this is slightly more complicated. There is a whole thread about this on StackOverflow : https://stackoverflow.com/questions/7757337/defining-read-only-properties-in-javascript

Make stuff inaccessible

Rather than making stuff immutable (functions will still be overridable), you can make it inaccessible.

To achieve that, you have to put your variables and functions in a dedicated scope unaccessible via window. This is achievable with a IIFE: https://en.wikipedia.org/wiki/Immediately_invoked_function_expression

Make stuff unreadable

Last but not least, to mitigate the investigation process of the gentle cheaters, you can prevent them from simply searching var stage as we just did. This is one of the many features provided by web bundlers like Webpack, Rollup, Parcel, Esbuild, and others. The goal of these tools is to transpile, assemble, and compress JS code. To achieve this compression goal, they will rename every identifier with a single letter identifier. So, var score will become var s, for example.

So next time you want to beat your friends at some random browser game, maybe try this technique ? I remember it was also quite easy to do that on messenger minigames, so why not on the one you’re playing ?

--

--

Aymeric Arnoult

Software engineer, involved in creative web dev and crypto, curious about AI, medias and economy. Ex story writer at https://medium.com/@sun_app.