Sky Hopper feels unfair because gaps seem to conspire against you. The engine in this repo shows exactly how much of that feeling is real. Every gap center is an independent random draw, and every other difficulty number is fixed and knowable in advance.
The numbers that never change
The engine runs on a 540 by 960 design. The bird is a circle of radius 18 pinned at x 100. Gravity pulls at 1500 units per second squared. A tap sets velocity to exactly minus 450, it never adds to it.
From those two constants you can derive your complete correction budget. One tap peaks 67.5 units above the tap point after 0.3 seconds. That is all the height a single input can buy you.
How the engine places each gap
A new pipe spawns after every 280 units of horizontal travel. The gap center is drawn with one Math.random call, uniform between 100 plus half the gap and 880 minus 60 minus half the gap.
At score 0 the gap is 180 tall and the center ranges from 190 to 730, a 540 unit span. Each draw is independent. The gap you just cleared tells you nothing about the next one, because the engine keeps no history between spawns.
Two hard boundaries are baked into that range. The top edge of the highest possible gap sits 100 units below the ceiling. The bottom edge of the lowest possible gap sits 60 units above the ground. Both the ceiling and the ground kill on contact, so high gaps leave you slightly more recovery room than low ones.
The center range also widens slightly as the gap narrows. At score 20, with a 140 tall gap, the center draws between 170 and 750. The playable decisions spread out while the corridor itself tightens, which is why the game feels faster without the pipes visibly changing much.
The pace between pipes is fixed by distance
Pipes are spaced by travel distance, never by time. That matters because your speed rises with score. At score 0 you cover the 280 units between spawns in 1.4 seconds. At score 20, moving at 260, you cover the same distance in about 1.08 seconds. Your tapping rhythm must speed up by roughly a quarter over that stretch even though the gap has stopped shrinking.
One difficulty ramp stops and one never does
The gap shrinks by 2 units per point, from 180 down to a floor of 140 reached at exactly score 20. After that the gap never narrows again.
Speed rises 3 units per point with no cap. At score 20 you fly at 260. At score 40 you fly at 320. The medal table stops at Platinum for a score of 40, but the speed does not stop with it.
Four rules follow from these numbers.
1. Hold the band midpoint near 460 through the opening pipes. It minimizes the worst-case correction to any gap in the 190 to 730 range.
2. Count to 20. That is where the gap freezes, and only reaction speed remains after it.
3. Respect the pipe lips. Each lip extends 6 units wider than the pipe body on both sides and stands 26 tall, so the true corridor at lip height is 12 units narrower than the body gap suggests.
4. Stay alert inside a gap you have almost cleared. A pipe scores when its right edge passes the bird, and the collision checks run every frame until then.
The opening seconds are scripted
On your first tap the spawn timer is preset to 70 percent of the spawn distance, so the first pipe appears after only 84 further units of travel, which is 0.42 seconds at base speed. It enters at x 560 and reaches the bird roughly 2 seconds later. Expect your first real decision almost immediately after starting.
What randomness does to your scores
Because each gap center is an independent uniform draw, consecutive extreme gaps happen with fixed probability and no skill removes them. A run of low gaps forces dives into the 60 unit clearance band above the ground. A run of high gaps forces climbs toward the lethal ceiling. Your best score is stored locally in your browser.
The frame guard also matters for consistent play. The engine clamps each time step to 0.1 seconds, so a background tab or a stutter cannot produce a huge physics jump. Deaths come from the geometry, never from a lag spike, which at least makes every failure reviewable.
Death and restart are scripted too
A collision does not end the run instantly. The bird enters a dying state for 1.0 second, falls under full gravity, and a burst of 15 particles marks the impact point. Only then does the game over panel appear with your score, your best, and the medal thresholds of Bronze at 10, Silver at 20, Gold at 30, and Platinum at 40. One tap restarts from a clean state, and the preset spawn timer applies again, so every restart offers the same opening rhythm.
Use the dying second deliberately. It is a fixed, free interval to reset your grip and breathing before the next attempt, and the engine gives it to you on every single death.
A routine that fits the numbers
- [ ] Hold the midpoint near 460 until the score reaches 10.
- [ ] Correct with single taps, each worth about 68 units of height.
- [ ] Give every pipe lip its extra 6 units of width on both sides when you plan a squeeze.
- [ ] Stay off the ceiling, contact there kills exactly like the ground.
- [ ] Track score 20 as the point where narrowing ends and pure speed begins.
Honest downsides. The uniform draw means run to run score variance is large and unavoidable. Speed has no cap, so every run ends eventually. The medal table ends at 40 while the difficulty keeps climbing, so chasing anything beyond Platinum is pure endurance.
Run the [Sky Hopper game](/en/flappy-bird) and log your first 20 gap centers. If you find a pattern between consecutive gaps, send the list, because the spawn code is a single independent draw and a pattern would be a bug worth fixing.