Meteor Survival
Asteroids, on a screen that wraps at all four edges. Turn, burn and fire, and keep breaking the rocks down until there is nothing left to hit you — because the only thing that ends a wave is an empty screen.
Emulated by binjgb (WebAssembly). Click the screen to give it keyboard focus. Open full screen.
How to play
| Screen | Buttons |
|---|---|
| Title | START begins the run — and how long you leave it waiting is what seeds the ship's randomiser, so no two runs open the same way |
| Flying | LEFT / RIGHT rotate · A thrusts for as long as it is held · B fires one shot per press, not one per frame held |
| Hit | Nothing — the ship breaks apart on its own and a fresh one arrives about a second and a half later, untouchable for two seconds after that |
| Game over | Nothing — the last life ends the run, and the title screen comes back by itself |
The ship turns a notch at a time rather than swinging freely, so LEFT and RIGHT are small corrections and you aim by tapping them. Thrust is the opposite kind of control: hold A and the ship keeps accelerating for as long as it is down, up to a top speed, and it carries on in the direction it was pointing when you let go. Both the ship and the rocks wrap round the edges of the screen, and so do your bullets — so a rock that leaves the right side is already coming back at you from the left.
Keyboard
- D-padArrow keys
- AX
- BZ
- STARTEnter
- SELECTC
Emulator
- Toggle the SGB borderS
- Fast-forwardShift
- PauseSpace
- Save / load stateF6 / F9
- RewindBackspace
Breaking rocks
Hit a rock and it does not disappear — it splits into two of the next size down. A large rock becomes two mediums, a medium becomes two smalls, and only a small one is gone for good. So a screen with a handful of large rocks in it is a screen that is about to become a lot busier, and the moment after a good hit is the moment to move.
The points run the other way: a large rock is worth 20, a medium 50 and a small 100. The hard, quick, dangerous rocks pay least and the little ones you have to chase pay most, so a high score comes from finishing what you started rather than from firing at the biggest thing on screen.
You start each run with three ships. Losing one leaves the rock field exactly as it was and hands you a replacement in the middle of the screen, briefly untouchable and free to be moved first — it will not respawn into a rock, but it will respawn into the path of one.
Super Game Boy

On a Super Game Boy the screen sits inside a field of asteroids and stars, with the game's name across the top and the ship parked at the bottom left. The artwork is drawn rather than painted — a Python script generates the border image the same way the game's tiles are generated. The emulator reads the ROM's SGB flag and starts with the border on — press S to toggle it. On anything that is not a Super Game Boy it is simply not there.
Every wave is faster
Waves are numbered, and the number is the whole difficulty curve — nothing else changes it. It moves two things at once, and they run out at very different times.
Count is one of them: a wave opens with two more large rocks than the wave before, so wave 1 starts with three. That lever runs out almost immediately, because there is a hard ceiling of eight large rocks on screen and wave 6 is already at it. From there on, every wave has the same number of rocks.
Speed is the one that keeps going. Every wave adds the same small step to the rocks' velocity, on top of what their size already gives them, and that step is what makes wave 12 harder than wave 6 even though the two look identical at the start. Your own top speed never changes, so the gap between you and the rocks closes from their side only — and it is capped, which is the only reason wave 40 is playable at all. Wave 1 is left deliberately untouched by all of this, so the first wave is always the quiet one.
Under the hood
Written from scratch in C with GBDK-2020 — no game engine, in the same lineage as GB Protector, GB Checkers and Luna Lander. The whole game is one source file; the tile art is generated by a Python script and committed as a header. The cart is 32 KB and ROM-only, with no mapper at all: the rocks, bullets and the border's tiles fit in the second bank, which on a cartridge this size is simply always there.
The sprite budget is exactly full. The DMG will show 40 sprites at once, and the game uses 37 of them: one ship, four bullets and eight rocks of four tiles each. Hitting that ceiling is why each rock owns its four slots for life rather than taking a free one, and why the ship's death animation had nowhere to come from. It uses the ship's own slot to throw four shards out on the diagonals, into the three spares the arithmetic happens to leave.
Positions are 16-bit fixed point, with the high byte being the pixel — which is what lets the ship, the rocks and the bullets all wrap round the screen edges through one shared bit of code. The collision maths is deliberately 8-bit and approximate, because it runs in loops over every bullet against every rock and the exact 16-bit version cost more frames than the game had.
The sound is three one-shots written straight to the sound registers with no driver: the laser on one channel, a two-tone heartbeat on another, and the noise channel shared between the thrust, the explosion and the hits. The heartbeat quickens as the rock count falls — it is the sound of the screen emptying — and the noise channel is arbitrated by priority, so an explosion always gets it and the engine rumble simply resumes afterwards. The Super Game Boy border is generated and committed as tiles, a map and a palette in that second bank; the SGB flag in the ROM header is the only build setting with no test behind it and no visible failure mode, because without it the border is discarded in silence.