ESP ZeroCode AI · Community
Classic Space Invaders Game
Classic space invaders gameplay from the 1970's for the esp-mosaico.
What it does
- Arcade-faithful gameplay — 55 invaders in 5 rows, four shields, mystery UFO, 3 lives, the original scoring, and the fleet speeding up as it thins out
- Presentation — full-bleed black panel, the arcade screen scaled to fill the area above the control strip (or exact 1:1 at the toggle), with the whole 224×256 field always fully visible
- Full-bleed black — the whole panel is black in every mode, so game elements never move outside the black background
- Onboard display — plays on the Mosaico's own 480×480 QSPI display, no external panel
- On-screen controls — LEFT / RIGHT / FIRE in one row across the bottom of the touchscreen, drawn as light translucent arcade buttons that stay visible without hiding the playfield
- Physical buttons — the onboard AI button moves and the BOOT button fires, as a fallback with no touching
- Arcade-style sound — six noise-and-envelope effects (march that speeds up, laser, invader explosion, player death, UFO siren, shot explosion), not tone beeps
- Mute — a speaker toggle on screen silences the game and is remembered across power-off
- Vibration feedback — the onboard motor pulses when the player is hit, when the mystery UFO is destroyed and when a wave is cleared
- Attract mode — the arcade's idle screen with the score table and high score whenever no game is running
- Free play — a tap anywhere or FIRE starts a game immediately, no credits needed; the high score is the only progress kept
- High score — the top score survives power-off
- Battery readout — the onboard fuel gauge shows charge level in the top margin
- Optional Chain Joystick — an M5Stack Chain Joystick steers with its X axis and fires with its button; detected at power-on so the game runs with or without it
- Optional second Chain Joystick — with two sticks on the chain, the first steers and the second stick's button fires (arcade-panel layout)
- Auto power-off — after 5 idle minutes in attract mode the screen dims; after 10 the device saves the high score and powers itself fully off through the board's power-switch line
- True shutdown, not a sleep — once powered off the device draws no battery current and comes back only by pressing the physical POWER button
- Original shields — an arched 22×16 bunker of our own drawing, eroded pixel by pixel where shots land
- Explosion sprites — a destroyed invader, a player shot that reaches the top of the screen and an invader bomb that lands all flash an explosion before vanishing
- Original artwork throughout — every sprite, shield and explosion is our own drawing, nothing transcribed from the arcade ROM, so the game is protected by our own rights rather than borrowed ones
Manual
Device Type
A handheld arcade cabinet: a self-contained, coin-free alien-invasion shooter in the mould of Taito's 1978 Space Invaders, running on the ESP-Mosaico development kit. It reproduces the cabinet's *rules and feel* — 55 invaders in five rows, four destructible bunkers, the descending march that speeds up as the fleet thins, the same scoring and the same enemy geometry — with all artwork and sound original to this product.
Intellectual Property
position: This is an independent reimplementation, not an emulation and not a clone of the ROM's assets. Nothing in the product is a transcription of Taito's copyrighted data. — whyThisMatters: Game rules, mechanics and scoring are not protected by copyright — only their expression is: the specific pixel art, the specific sound recordings and the ROM code. A game that plays identically but is drawn and voiced with its own assets is the well-established safe position, and it is also the position the product can defend. — whatIsCopied: Nothing. No ROM bytes, no arcade sprite bitmaps, no arcade sound recordings, no arcade code. The sprites, the shield bunker and the explosion sprites are this product's own drawings; the sounds are generated from oscillators at runtime rather than sampled. — whatIsIntentionallyFaithful: The rules and the numbers: 55 invaders in 5 rows of 11, 4 bunkers, 3 lives, one extra life at 1500, invader values 10/20/30 by row, UFO 50/100/150/300, the 2 px fleet step and 8 px drop, the 224x256 field, and the fleet accelerating as it is destroyed. Mechanics and numbers are not expression and are what make the game recognisable. — namesAndMarks: The product is presented as its own title. It does not use the 'Space Invaders' name or logo as the product name, and no Taito or Midway mark appears in the UI or packaging. 'Space Invaders' may still be used descriptively in documentation to say what kind of game this is, which is nominative use. — soundApproach: The effects are synthesised from noise and oscillators at runtime. The original cabinet's sounds were discrete analog circuits that no one can sample from a chip; approximating the same six effects with our own synthesis cannot reproduce a protected recording because no recording is used. — comment: This is engineering diligence, not legal advice. For a free, non-commercial release the risk here is low once the assets are original; before any commercial release, have a lawyer review the name and the marketing.
Hardware
chip: esp32s31 — board: esp-mosaico — gpios: display: on-board CO5300 QSPI 480×480 (GPIO 9, 35, 36, 42, 44, 50, 51; backlight/rail enable GPIO 60) — touch: on-board CST9220 series capacitive controller, I2C0 (SDA GPIO56, SCL GPIO3), interrupt GPIO6 — aiButton: GPIO7, active-low on-board button — bootButton: on-board BOOT button — also the download-mode strap, read only while running — vibrationMotor: GPIO8, active-high through a low-side MOSFET — audio: on-board ES8311 codec + NS4150B Class-D amplifier (I2S GPIO37/40/49/52/54, PA enable GPIO45) — fuelGauge: on-board BQ27220 at I2C0 address 0x55 — powerSwitch: GPIO57 — the SAM8108 power on/off control line, a power-management path rather than a plain application GPIO. Kept Hi-Z at all times except during a shutdown request, when it is driven open-drain LOW for 200 ms — chainUart: GPIO46 (TX) and GPIO47 (RX) to the optional Chain Bridge on the right module header — peripherals: part: M5Stack Chain Bridge (U211) or equivalent ChainBus adapter — optional: true — purpose: UART link from the module header to the Chain daisy-chain bus · part: M5Stack Chain Joystick (U205) — optional: true — purpose: analog X/Y plus Z push button; first node steers and fires · part: M5Stack Chain Joystick (U205) — optional: true — purpose: second node; its Z button alone fires — notes: No other external parts. The display, touch, buttons, speaker, motor and battery gauge are all already on the board; nothing has to be wired for the core product.
Inputs
kind: touchscreen — label: On-screen controls — hardware: CST9220 capacitive touch over the full 480×480 panel — behavior: Three arcade-style buttons in a single row across the bottom of the panel, inside a strip that the game never draws into: LEFT and RIGHT on the left, FIRE on the right (or LEFT / RIGHT / FIRE evenly spaced). They are drawn as pale, low-opacity rounded arcade buttons — a light outline with a faint white fill at roughly 15–20% opacity, and a brighter fill plus a thin highlight while pressed — so they are always legible but never hide game content. Because the strip is reserved, the playfield is never underneath them in either presentation mode. Press-and-hold on LEFT or RIGHT moves the cannon continuously while held; FIRE fires once per press (holding does not auto-repeat). Any tap while in attract mode starts a game. Small speaker (mute) and zoom (1:1 / full-screen) icons sit in the top corners of the panel. Outside gameplay the same row doubles as the menu: tap to start, mute, and zoom. · kind: button — label: AI button — hardware: on-board button, GPIO7, active-low — behavior: Moves the cannon — a press moves it one step, holding it moves it continuously. Any press in attract mode starts a game. · kind: button — label: BOOT button — hardware: on-board button, GPIO61, polled while running — behavior: Fires. In attract mode, starts a game. · kind: joystick — label: Chain Joystick 1 (optional) — hardware: M5Stack Chain Joystick, analog X axis and Z button — behavior: X-axis deflection left of centre moves the cannon left, right of centre moves it right, with a dead zone; the Z button fires. In attract mode the Z button starts a game. The stick's RGB LED is lit dimly while the game is running so the player knows the chain is alive. · kind: joystick — label: Chain Joystick 2 (optional) — hardware: second M5Stack Chain Joystick on the same chain — behavior: Only its Z button is used, as a second fire button, so one stick can steer while the other fires. Its X axis is ignored.
Outputs
kind: display — label: Game screen — hardware: 480×480 QSPI CO5300 panel, driven as a 224×256 monochrome framebuffer — behavior: The whole 480×480 panel is cleared to black every frame, so the game world is always on black and nothing — sprite, score, UFO or overlay band — ever appears to travel outside the black background. A 96 px control strip is reserved across the bottom for the button row; the game is drawn scaled-to-fit inside the remaining 480×384 region, preserving the 224:256 aspect and using nearest-neighbour sampling with no smoothing. Default presentation is full-screen: the game is scaled to 1.5× (336×384) to fill that region, which is larger than the old 1:1 view and leaves narrow black margins either side. A zoom toggle (top-right icon, also the on-screen control in attract mode) switches to exact 1:1 — the 224×256 buffer drawn one source pixel per panel pixel, centred in the same 480×384 region — for genuinely pixel-for-pixel viewing. Palette is the original's: white sprites and text on black with the colour overlay — green band across the player's row at the bottom of the playfield, red across the top row of invaders. Battery level and mute state are shown as small glyphs in the top corners, clear of the playfield. · kind: display — label: Shields — hardware: 4 shields, 22×16 px each at field x 30 / 76 / 122 / 168, y 184, in the green overlay band — behavior: The shields are 22×16 pixels, our own drawing — an arched bunker with straight vertical sides and a notch up into the base, drawn in the same visual language as the cabinet rather than transcribed from it. All four are identical at the start of every wave. Damage is permanent within a wave and is punched exactly where a shot lands: a player shot carves a ragged crater about 3 px in radius, an invader bomb a narrower 2 px hole, eroded in the bitmap's own bit layout rather than by a circle drawn over the sprite. Shields are restored in full only when a new wave begins. The silhouette deliberately differs from the arcade's in detail — arch radius, notch width and outline thickness are our own — while reading instantly as a bunker of this genre in shape, proportion and behaviour. · kind: display — label: Explosions — hardware: field sprites drawn into the 224×256 buffer — behavior: Three explosion events besides the player's death, each drawn for a short timed interval in place of what it replaced. (1) Invader destroyed: the invader disappears and its explosion sprite flashes at that cell for roughly a quarter second before clearing, with the score added immediately. (2) Player shot reaches the top of the screen without hitting anything: a smaller explosion flashes at the top of that column. (3) Invader bomb reaches the bottom of the screen or is stopped by a shield: the bomb explosion plays where it landed. The player's death keeps the two-frame expanding burst at the cannon. Every explosion pattern is drawn for this product — a radial spark burst — and is not transcribed from the cabinet's ROM sprites, which an earlier revision copied. · kind: speaker — label: Game audio — hardware: ES8311 codec + NS4150B amplifier + on-board speaker — behavior: Six effects in a style that reads as the cabinet's, each reproduced as the kind of circuit it was — a noise or pulse source with its own pitch range, amplitude envelope and duration — rather than as a musical note, so the march is a low pulse train and a hit is a burst of noise, not a beep. The melodic and sweep contours are our own: the march is a four-step downward pulse sequence of our choosing, not a transcription of the cabinet's note intervals, and the siren's sweep range is ours. One voice at a time, as the cabinet behaved; an effect already playing is not cut off by a new one. The siren alternates continuously for as long as the UFO is on screen. Muted disables the amplifier entirely. · kind: haptic — label: Vibration motor — hardware: GPIO8, active-high coin motor — behavior: A 120 ms pulse when the player's cannon is hit, a double pulse when the mystery UFO is destroyed, and a short triple pulse when a wave is cleared. No vibration during attract mode.
Connectivity
stack: none — transport: none — purpose: The product is fully self-contained and offline — no Wi-Fi, cloud, BLE or Matter. The only wired link is the optional UART daisy-chain bus for Chain Joysticks.
Commissioning
method: none — instructions: Nothing to onboard — flash the firmware, power on with the POWER button, and the attract screen appears. The optional Chain Joysticks need no pairing: with the Chain Bridge fitted to the right module header, the game enumerates the chain at power-on.
Business Logic
powerOnBehavior: The game boots straight into attract mode: the score table and high score on a black screen, the march silent until first input. The first tap, FIRE press or joystick button starts a game immediately with three lives and a full set of four shields. — automationRules: Chain detection runs once at power-on: if a Chain Bridge node answers on the UART, the joysticks found become active inputs; if none answer within one second, the game runs on touch and the on-board buttons only and never waits for the chain again. · The march tempo is a function of invaders remaining — the fewer left, the shorter the interval between notes. · The fleet's horizontal step interval shortens as invaders are destroyed, and the whole game runs faster from the third wave onward, exactly as the arcade did. · After 5 minutes with no input in attract mode the panel dims to 20% brightness; any input restores it and restarts the timer. · After 10 minutes with no input in attract mode: save the high score, mute the amplifier and blank the panel, then drive GPIO57 low for 200 ms to shut the whole device down, returning it to Hi-Z as the rail collapses. Both idle timers run only in attract mode and reset on any input, so a game in progress, a game-over screen or a long factory-reset hold is never powered off underneath the player. — dayToDayOperation: Power on, tap to start. Steer the cannon with the bottom-row LEFT / RIGHT buttons, the AI button or a Chain Joystick, and fire with the bottom-row FIRE button, the BOOT button or the joystick button. The zoom icon in the top corner switches between the larger full-screen view and exact 1:1. Shoot all 55 invaders to clear a wave and start a harder one. Three lives; one more awarded at 1500 points. Losing all three ends the game with the arcade's GAME OVER sting, then the game returns to attract mode after a few seconds. The high score, mute and zoom choices are saved at every game over and at power-off, so they are as the player left them at the next switch-on.
Factory Reset
trigger: Hold the on-board AI button and the BOOT button together for 5 seconds while in attract mode. — effect: The high score, the mute preference and the zoom preference are erased and the game returns to the state of a first-ever boot — full-screen presentation, sound on. Nothing else on the device is touched.
Failure Modes
scenario: Chain Bridge fitted but no joystick found, or the chain cable is unplugged — behavior: The game runs normally on touch and on-board buttons; no error is shown beyond a small 'no chain' note in the top margin for a few seconds at power-on. · scenario: Chain joystick unplugged mid-game — behavior: The stick's input simply stops; the touch controls and on-board buttons keep working, so play continues uninterrupted. Re-enumeration happens on the next power-on. · scenario: Fuel gauge does not answer — behavior: The battery indicator shows a dash instead of a percentage; gameplay is unaffected. · scenario: Battery runs low — behavior: The battery indicator turns to a warning outline below 15%; the game keeps running until the brown-out, with the high score already saved after every game over. The idle power-off at 10 minutes saves the score before it requests shutdown, so no progress is lost to either path. · scenario: Power blip or hard power-off mid-game — behavior: The in-progress game is lost; the previously saved high score is intact, because it is written whenever a game ends rather than only at power-off. · scenario: Touch controller stops responding — behavior: The on-board buttons and any Chain Joystick still play the game; it degrades to button control rather than becoming unplayable. · scenario: The 10-minute shutdown request does not take effect (the power-switch line is held by something else, or the board stays up) — behavior: The device does not try again and never reboots itself to retry. It stays in the blanked, silenced, panel-off state with the high score already saved, so the player sees a dark device that wakes on the next touch or button press — no crash, no boot loop, no lost score. A second press of the POWER button is the manual fallback. · scenario: Player presses POWER while a game is in progress — behavior: The rail drops mid-game exactly as a battery removal would; the in-progress game is lost and the previously saved high score is intact. The game does not intercept the POWER button — it is a hardware power path, not a game input.
Power Management
batteryPowered: true — sleepMode: No deep sleep and no light sleep — the device either runs normally or is genuinely powered off. Attract mode dims the panel after 5 idle minutes and requests a full hardware power-off after 10, so a forgotten device does not flatten the 65 mAh cell. — wakeSources: None from firmware — there is no wake source because there is no sleeping state. A powered-off device is started by the physical POWER button, which switches the SAM8108 rail back on and cold-boots the firmware into attract mode.
Custom Behavior
frameAccuracy: The game logic is a reimplementation written for this device, not a bundled ROM. It runs the original's fixed-step frame update: the 224×256 buffer is composed and presented at a fixed rate, and entity positions advance in the arcade's own pixel steps (invader step of 2 px horizontally and 8 px down on edge contact, cannon 1 px, player shot 4 px per update) so movement feels and looks like the original rather than like a smooth-scrolling remake. — presentationToggle: Full-screen is the default because a larger game is easier to see on a small panel; the 1:1 mode stays available for genuinely pixel-for-pixel viewing. The 96 px control strip is reserved in both modes, so switching zoom never hides game content and the buttons never move under the player's thumb. — scoring: The cabinet's scoring: top-row invader 30, middle two rows 20, bottom two rows 10, mystery UFO 50 / 100 / 150 / 300 depending on the shot count, extra life at 1500 points. Numbers and rules are not copyrightable expression, which is exactly why the fidelity belongs here. — audioSynthesis: The cabinet's sounds came from six discrete circuits, not a sound chip: a clock divided and gated, with noise generators and RC envelopes per effect. This implementation keeps that *kind* of synthesis — each effect is a noise/pulse generator with its own amplitude envelope and duration, mixed at 16 kHz into the board's ES8311 codec, one voice at a time. The specific contours are ours. That is why the march is a low pulse train that speeds up as the fleet thins and the explosions are bursts of noise rather than musical notes. No samples and no audio files on flash, which also means no recorded performance of any kind is redistributed. — shieldBitmap: The shield is our own 22×16 bitmap: arched crown, straight sides, notched base, all drawn for this product. It must NOT be transcribed from the cabinet's ROM pattern — an earlier revision did exactly that and was replaced. The erosion is applied to this product's own bit grid, so the craters line up with our sprite. — explosionSprites: Three explosion patterns distinct from the player's death: one drawn at a destroyed invader's cell, one where a player shot expires at the top of the screen, and one where an invader bomb lands. Each is shown for its own short time then cleared, in the same colour band as what it replaced — a destroyed top-row invader's explosion is red, everything else white. The patterns are original radial spark bursts, not geometric transcriptions of the cabinet's sprite bytes (which an earlier revision used). — assetProvenance: Every pixel in the product is drawn for it and every sound is generated at runtime. If a future change is tempted to copy an arcade bitmap because it 'looks more authentic', that is the one change that would turn a safe product into an infringing one: the faithful part must stay in the rules, the numbers and the feel, never in the assets. — leftAloneBehavior: Left untouched, the device follows a fixed three-stage idle path, all of it counted in game ticks so it advances at the same rate as the game. (1) Attract mode: the score table and high score stay on screen, silent; no timer is running yet. (2) At 5 idle minutes the panel dims to 20% brightness — the game is fully alive and any touch, button or joystick input snaps back to full brightness and restarts the timer. (3) At 10 idle minutes the high score is written to NVS, the amplifier is muted, the panel is blanked and the whole device is powered off through GPIO57. A powered-off device draws no battery current and comes back only by pressing POWER, which cold-boots straight into attract mode with the high score restored. The timers run only in attract mode and reset on any input, so an in-progress game, a game-over screen, a long factory-reset hold or an active Chain Joystick is never interrupted by either stage. This is deliberately a hardware power-off rather than a deep sleep: an earlier firmware revision armed the AI button as an RTCIO wake source with ANY_LOW on an active-low button, which produced a boot loop that looked exactly like a crash, and the board's rail cannot be woken by touch anyway.
Assumptions
The high score and preferences are stored in NVS on the on-board SPI NOR flash. · The device is used on its internal 65 mAh battery in short sessions; the true power-off at 10 idle minutes is what keeps a forgotten device from being flattened overnight. · Game audio defaults to on at a moderate volume, reachable from the top-corner mute icon in attract mode and during play. · The 200 ms shutdown pulse on GPIO57 is a starting value taken from the board's documented open-drain power-off-request behaviour; the exact minimum hold for the SAM8108 to latch the rail off is to be confirmed on hardware. If 200 ms proves marginal, lengthening the pulse is a tunable, not a behaviour change. · Driving GPIO57 directly is expected to work even though the board exposes no power-control device in its board manager — the pin is documented as a power-management path and is unused by every other on-board device. · The silence heard in the desktop simulator is expected and is not a firmware fault: the simulator has no ES8311 codec or speaker, so the audio path never produces anything to hear. Audibility can only be confirmed on the physical board, by seeing the codec open at boot and then listening. If hardware is silent, the first suspect is the amplifier enable line (GPIO45) and the codec's I2S clock ratio, which fails silently when mismatched. · Arcade fidelity is deliberately limited to rules, numbers and feel. The invader silhouettes are this product's own drawings in the genre's style, not the cabinet's 8×8 sprite bitmaps; the shield and explosion art is original. This is the difference between a game that plays like Space Invaders and a game that redistributes Taito's artwork. · The product is released free, which lowers exposure further: there is no revenue to disgorge and no commercial use of anyone's mark. The name shown to the player is the product's own title, with 'Space Invaders' used only descriptively if at all. · The cabinet's six sound circuits are approximated in kind, not transcribed: our own note intervals, sweep ranges and envelope lengths. Recognisably that family of effects, with nothing copied.
Published 24 Oct 2026
Firmware and source licensed Apache-2.0; photos and text CC-BY-4.0.
The firmware includes open-source software — open-source licences and notices; some components may be used only with Espressif chips.
Built with ESP ZeroCode AI — describe a device, get production firmware.
Terms of Service · Privacy Policy