Go · WebAssembly · Bubble Tea

An arcade in your terminal.

termcade draws its playfield out of Unicode block elements, so one terminal cell becomes a 2×2 or 2×3 grid of pixels and the games come out sharper than the font should allow. Asteroid and Tetris are in the binary, and play offline the moment it starts.

go run github.com/aviorstudio/termcade@latest

One static binary · a truecolor terminal at 80×24 or larger

termcade / ASTEROID
 ASTEROID                                                       HIGH 1380
╭────────────────────────────────────────────────────────────────────────╮
                                     ▗▚                                 
                                                                      
                                    ▟▀▀▟▖                               
                                                                        
                                                                        
                                                                        
               ▗▄▄▄                                                     
              ▄▞▘  ▀▀▌                                                  
            ▄▀                          ▗▄▖                            
                                    ▄▀▀▘ ▝▖                           
                        ▗▄▄▖            ▗▘                           
            ▀▄        ▗▞▀▘  ▝▀▀▄    ▝▚▄▖ ▄▀                ▄▄▄▄        
              ▀▄▄▄▀▀▘ ▞▘               ▝▀                ▗▀    ▀▌      
                                                        ▝▖    ▄▘      
                      ▀▚▄▖      ▄▘                         ▀▄▄▄▞        
        ▄▖               ▝▀▚▖ ▄▀                                        
     ▄▞▀ ▝▚▖                ▝▀                                          
   ▄▀      ▝▀▄▖                                                         
             ▐▘                                                        
  ▝▚         ▗▞                      ▗▖                                 
╰────────────────────────────────────────────────────────────────────────╯
     SCORE 000020   WAVE 1   ▲ ▲ ▲   ←/→ turn · ↑ thrust · space fire
quad 2×2 pixels per cellwasm sandboxed guest60 TPS fixed step

In the arcade

Three games in the box, and the way in for the rest.

The starter pack is committed as packages and embedded in the binary, then unpacked into your games directory the first time it runs. The games that come with the arcade are installed exactly the way an added one is — and can be removed exactly the same way.

  • ASTEROID Bundled

    Asteroids-style rock shooter. An inertial ship on a wrapping field, and big rocks that split into faster small ones.

  • TETRIS Bundled

    Falling-block stacker with Super Rotation System kicks, a 7-bag randomizer, ghost piece, lock delay, and gravity that tightens by level.

  • BRICKOUGH Bundled

    Breakout-style brick breaker: steer the ball with paddle english, clear the wall, survive the speed-up.

TERMCADE_PIXELS

One ship. Four ways to cut up a cell.

Every setting draws the same game into the same terminal cells; only the sharpness, and what the font has to know how to draw, change. Below is Asteroid's ship at the start of a wave, captured four times over and blown up — the same five columns of cells every time, a different number of pixels inside them. In the arcade p cycles the style and keeps it, and TERMCADE_PIXELS overrides the saved choice for a single run.

              
             
     ▗▘▚      
     ▟▄▞▖     
    ▝▘ ▝▀     
              
quad 2×2 per cell

Unicode 1.0 block elements. Renders anywhere, and the default.

              
      🬦       
     🬞🬄🬣      
     🬔🬭🬁🬓     
    🬉🬂 🬂🬍     
              
sextant 2×3 per cell

Sharpest, near-square pixels. Needs Unicode 13, or you get tofu.

              
             
     ▄▀▄      
     ▄▀▄     
      ▀▀     
              
half 1×2 per cell

The original look, for fonts that struggle with the rest.

              
      -       
     :::      
    .:_:,     
    -" "-     
              
ascii 3×3 per cell

A density ramp and line characters. No block glyphs at all.

01

Nothing is compiled in

Every game is a WebAssembly package, and it runs under wazero with no filesystem, no network, and a watchdog on every call into it. One that panics gets a crash screen instead of taking the arcade with it, and one that fails to install is listed dimmed, with the reason, rather than quietly missing.

02

Held keys, without the half-second stall

Terminals send no key-release events, so a held key is normally guessed from auto-repeat — which stalls for the OS repeat delay after the first press and makes a paddle feel like it is ignoring you. termcade asks for the Kitty keyboard protocol's event-type reporting, and on terminals that answer — kitty, Ghostty, foot, WezTerm, recent xterm — held keys are exact. Everywhere else it falls back without saying anything.

03

The renderer owns the look

Games draw in square logical units and never see the pixel grid, so the block style, the cell shape and the ANSI batching are the arcade's business rather than theirs. A game written before a pixel style existed renders in it anyway.

The front door

Opens on what you played last.

The library is one keystroke away and the marketplace one more. Browsing is open; signing in adds a game to the account library and installs it on this machine. The library follows you to the web app and every terminal where you sign in, and the arcade has its own account screens.

The live registry is api.termca.de. Package bytes pass through it and are checked against the sha256 recorded when the release was published before either the terminal or web app runs them. TERMCADE_REGISTRY selects a local registry for development.

termcade play — the marketplace is in here too, on m
termcade add author/slug add a marketplace game to your account and this machine
termcade list what is in your arcade
termcade remove author/slug take one off, and off your synced library
termcade signup create an account — or termcade login, termcade logout
termcade dev new you/mygame scaffold a game that is already playable
termcade dev build package a game directory into a .tcade
termcade dev install build/game.tcade install a local package while developing

termcade dev

The arcade you play with is the dev kit.

termcade dev new you/mygame scaffolds a game that already runs, termcade dev build turns the directory into a .tcade, and termcade dev install puts the local build on your own menu. A game is a Go package implementing one interface — and because the boundary is a frozen wasm ABI rather than a Go one, Go is a convenience and not a requirement.

Ticks
Update() runs exactly 60 times a second, stepped off the measured clock rather than drifting
Input
four directions, two action buttons and start — with real releases where the terminal sends them
Drawing
a canvas in square logical units; the game never sees the pixel grid it lands on
HUD
labelled fields and a hint. The shell owns every pixel of the styling
Dependencies
the sdk module, which depends on nothing outside the standard library
Boundary
wasm ABI v1, frozen. A host refuses a guest whose version it does not speak

Three games in the box.
The rest is yours to write.

ONE BINARYSANDBOXED GUESTS60 TICKS A SECOND