Cheery Chimp Logo

Cheery Chimp

Balloon Lander

  • Home
  • About Us
  • Privacy Policy
  • Terms and Conditions
  • Contact Us
  • Install app

Balloon Lander

This is a Cheery Chimp original.

How To Play Balloon Lander

Use gas, vents, and ballast to guide your balloon through the levels.

Contact

Feel free to contact us with any bugs, complaints, or requests.

Release Date
August 5, 2026

Behind the Scenes

Lunar Lander on the Commodore 64 gave you one button and a fuel gauge. This is that game with the gravity turned friendly and the wind turned into the puzzle.

I spent a lot of time as a kid with Lunar Lander on the C64. One thrust, straight up, a descent you could not undo, and a fuel number ticking down while you tried to touch a rock at walking pace. It is an almost absurdly small game and it holds up, because the whole thing is a single continuous decision: burn now, or burn later and hope.

Balloon Lander is my attempt at what that shape feels like when it is not about crashing.

One control, and it is not steering

You get heat. That is the entire input. More heat and you rise, less and you sink, and there is nothing whatsoever you can do to move sideways.

Sideways is the wind's job. The sky is built out of layers, each drifting at its own speed in its own direction, and a balloon goes wherever the air it is sitting in is going. So the way you travel east is to find the altitude where the air is heading east and stay in it. Altitude is steering.

That inversion is the whole game and it took a couple of levels to learn to teach. The instinct from every other game is that up is up and left is left, and a control scheme where the only button is vertical but the goal is horizontal feels broken for about thirty seconds before it clicks. After it clicks, a wind map stops looking like scenery and starts looking like a road network — because that is what it is. A layer going one way at one height and the other way at another height is a two-way street, and once a player sees that, they have understood the game.

What Lunar Lander lends here is the shape of the tension rather than the theme. Height is a resource like fuel. Spending it is instant and getting it back is slow, so the plan you make at the top of a level is a plan about a budget, and the last ten seconds — drifting toward a pad at the right height with almost no room to correct — are the same last ten seconds I remember from 1983.

Nine levels that each teach one thing

There are nine, and each exists to introduce exactly one idea. Written out, the roster is essentially a syllabus:

The first flight teaches that you drift while you descend — that doing nothing is still doing something. Open sky teaches that altitude is steering. The ferry teaches that layers run both ways, so you can come back. The flyway teaches that the fast layer is also the busy one. Dead weight introduces ballast and the fact that dropping it is a one-way door. The thermal teaches that air rises on its own, and that free lift beats paid lift. The chimney is endurance in a shaft. The undercut puts your only input perpendicular to where you need to go. And the passenger combines a bird and a tunnel, because at the end the ideas ought to multiply rather than merely accumulate.

Building levels this way — one concept each, in an order where every level can only be solved with the thing the last one taught — is slower than designing interesting shapes and hoping. It is also the only reason a game with an unintuitive control scheme is playable at all.

Every one of them is checked by a solver rather than by my own opinion. It plays the level, confirms it can be finished, and reports the margin — how much slack a competent flight has left over. A level with no margin is a lock rather than a puzzle. A level with too much has not taught anything, because you could have blundered through it. The par printed on each level is a number the solver found, not a number I hoped for.

The day every button in the game stopped working

The best bug of the build, and one I caused myself while adding something nice.

The nice thing was being able to drag the view around in flight to see where you were going. Simple enough: listen for a press on the stage, capture the pointer, follow it. It worked perfectly, and it killed every button in the game. Next, Again, the close button on the modal, every row of the level picker — all visibly pressed, all doing nothing.

The cause is a lovely piece of DOM plumbing. The press handler was attached to the wrapper element that contains the canvas, and it also contains the overlay and the picker. Press a button inside the overlay and that event bubbles up to the wrapper, which dutifully captures the pointer — and capturing a pointer retargets the rest of that gesture to the capturing element. The browser therefore never delivers a click to the button your finger is actually on. The button highlights, because that is CSS, and then nothing happens, because the click went somewhere else.

What makes it interesting is why it had not happened before. The old code opened with a guard that returned early unless the game was in a draggable state, and with a menu open it never was. That guard was doing a job nobody had written it to do: it was protecting every button in the application, invisibly, as a side effect. I removed it for a good reason and the real problem it had been hiding surfaced at once.

The fix is structural rather than another guard — bind the drag listeners to the canvas itself, which contains no buttons, so the question never arises. And there is now a test that fails if the wrapper ever acquires a pointer or click handler again, because the next person to reach for that element will have as good a reason as I did.

Two failures that make no noise

The bugs worth writing down are the ones with no symptom.

The first was in the loading. The game finds the site's shared bridge module through a dynamic import wrapped in a try/catch, so that it also runs standalone with no site around it. That is the right design and it has a sharp edge: if the import path is wrong, nothing throws. The catch fires, the standalone stub loads, and the game runs — with no bridge, no saved progress and no mute button, and looking entirely normal. I would have found that weeks later, inside the shell, wondering why nothing was being remembered. It is pinned by a test now that simply asserts the import path is what it should be.

The second was pure CSS and only appeared when the roster grew to nine. The level picker scrolls — except it did not. It had a scrollbar declared and simply refused to scroll, growing past its container instead. The reason is that a flex item defaults to a minimum height of its own content, so it will not shrink below what it holds, and an overflow rule inside it has nothing to overflow. One declaration — a minimum height of zero — and the scrolling appears. There is no error, no warning, and the bug does not exist until your list gets long enough to need to scroll, which is exactly when you stop watching for it.

The level is in the address bar

A small feature that paid for itself several times over during development: the current level is a URL fragment. Type the level's name or its number and you land on it.

That sounds like a convenience and is really a workflow. Debugging level seven without it means reloading, clicking through the picker, and flying back to the part you were looking at, every single time. With it, a reload puts you exactly where you were.

Retrying a level replaces the history entry instead of adding one, so attempting the same level twenty times does not leave twenty entries in your back button. And there is a test asserting that every level id is unique and contains nothing that would break a URL — because two levels sharing an id silently makes one unreachable, and a space or a hash in one silently sends you to level one. Neither throws. Both just quietly do the wrong thing forever.

What only showed up in play

Several things were wrong in ways no test was ever going to catch, and all of them came out of actually flying the levels.

The wind sock at the spawn point pointed the wrong way, which is the worst possible object to get backwards, since its entire job is to tell you the truth about the air. The basket clipped through the ground on landing, so a successful flight ended with the balloon halfway into the field. Speed carried over between levels, so level four's pace quietly became level five's starting condition. And the flyway level was simply overtuned — correct, solvable, verified, and not fun.

That last one is the useful reminder. The solver can tell you a level is winnable and roughly how much room it leaves. It cannot tell you whether the twenty seconds in the middle are interesting. Nothing can, except flying it.

  • About Us
  • Privacy Policy
  • Terms and Conditions
  • Contact Us

♻️ Made from 100% recycled electrons! ♻️

    Recently Played

      Games you open show up here.