textual-tetris
textual-tetris is a minimalist Tetris clone written with Textual, an amazing TUI framework for Python. It focuses on compact components, colorized blocks, and a responsive keyboard feel in the terminal.
Original Blog post: https://mgaitan.github.io/en/posts/textual-tetris/
Running
The easiest way is using uvx (part of uv):
uvx textual-tetris
For local multiplayer:
uvx textual-tetris --2players
Remote games
Start a server as local Player 1, then connect Player 2:
uvx textual-tetris server --name Ada
uvx textual-tetris connect ws://HOST:8765 --name Grace
The server UI connects through the same WebSocket protocol as every other player, so the server remains
independent from Player 1. Run uvx textual-tetris connect without a URL to use ws://localhost:8765.
For a server without a local player, use headless mode and connect two clients:
uvx textual-tetris server --headless
uvx textual-tetris connect --name Ada
uvx textual-tetris connect --name Grace
Use watch-only mode to observe without occupying a player slot or joining the challenger queue:
uvx textual-tetris connect ws://HOST:8765 --watch-only --name Observer
For an agent-versus-agent game with a local spectator UI, start the server itself in watch-only mode, then connect
both agents to ws://localhost:8765:
uvx textual-tetris server --watch-only
Other spectators wait in a FIFO queue by default. When a player disconnects or loses, the winner stays and the next queued client is promoted. Watch-only clients are never promoted.
Every interactive client uses arrow keys to move and rotate and Space to hard drop. Press N to change your
visible name. Press C to open a one-line chat input; Enter sends, Escape cancels, and incoming messages appear as
non-blocking notifications. A player who becomes a spectator can press J to join the challenger queue again.
Share over the internet
For a temporary game, a Cloudflare Quick Tunnel
can expose the local WebSocket server without opening an inbound port or requiring a Cloudflare account. Install
cloudflared, bind the game locally, and start the tunnel in another terminal:
uvx textual-tetris server --host 127.0.0.1 --port 8765 --name Ada
cloudflared tunnel --url http://localhost:8765
cloudflared prints a temporary https://<random>.trycloudflare.com URL. Replace https with wss when connecting:
uvx textual-tetris connect wss://<random>.trycloudflare.com --name Grace
Quick Tunnel URLs change whenever cloudflared restarts and are intended for testing and short-lived games. Use a
named Cloudflare Tunnel when a stable hostname is required.
Agentic player
An automated AI (like Codex) player can use the same WebSocket without rendering the terminal UI.
On connection, the server sends a welcome message describing protocol v2, the assigned role and player id,
valid messages and events, and the piece catalog. It then sends revisioned state snapshots containing both
players and the complete connection roster.
The welcome also includes the complete piece catalog: each rotation code maps to its four relative block coordinates, so the client does not need to know how pieces are encoded internally.
Every message
has a monotonically increasing revision; ignore older messages. A piece_locked event identifies the locked
piece_id, and an input with an id receives an ack event, so an agent can wait for confirmed state changes.
Send actions as JSON, for example:
{"type": "input", "id": 42, "action": "left"}
Agents can also set their name and use chat:
{"type": "name", "name": "Codex"}
{"type": "chat", "message": "good luck"}
The same server supports agent-versus-agent games: launch server --headless for no UI or server --watch-only to
watch locally, then connect two automated WebSocket clients. A raw watch-only client can connect with
?role=spectator; it receives state and chat events but can never become a player.
Screenshots
Single-player
Two-player
Gameplay
- Blocks follow the classic rules: move left/right, rotate, soft drop, and hard drop.
- Every locked piece awards a small bonus; clearing 1–4 lines follows the traditional scoring table. Levels increase automatically based on the number of cleared lines, and the drop interval accelerates per level.
- The
Nextwidget previews the upcoming piece so you can plan ahead, and the score widget keeps score/level/lines visible at all times.
Controls
In the default one-player mode, use arrows or W/A/S/D to move and rotate, and Space or Q to hard drop.
In remote mode, use arrows and Space. C opens chat, N changes your player name, and J joins the queue.
With --2players:
| Key | Action |
|---|---|
A / D / S / W (Player 1) |
Move left/right, soft drop, rotate |
Q (Player 1) |
Hard drop |
← / → / ↓ / ↑ (Player 2) |
Move left/right, soft drop, rotate |
Space (Player 2) |
Hard drop |
N / Shift+N |
Change Player 1 / Player 2 name |
Ctrl+Q |
Quit |
R |
Restart after a game-over |
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file textual_tetris-0.5.0.tar.gz.
File metadata
- Download URL: textual_tetris-0.5.0.tar.gz
- Upload date:
- Size: 20.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bc1b3afbfa164eedcc130821e9aa61bf4cab188822838b0f877f898dd7f65b45
|
|
| MD5 |
5ad19c76e518c0feb880f485a6f7a3c9
|
|
| BLAKE2b-256 |
b8476ff0f126b13232fae73def47c13e6d0e8eabc7b14c0782df259edee1e79d
|
Provenance
The following attestation bundles were made for textual_tetris-0.5.0.tar.gz:
Publisher:
cd.yml on mgaitan/textual-tetris
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
textual_tetris-0.5.0.tar.gz -
Subject digest:
bc1b3afbfa164eedcc130821e9aa61bf4cab188822838b0f877f898dd7f65b45 - Sigstore transparency entry: 2385566532
- Sigstore integration time:
-
Permalink:
mgaitan/textual-tetris@787f3b3955b3412f19b0c9fab35ee2b6bb5c505d -
Branch / Tag:
refs/tags/0.5.0 - Owner: https://github.com/mgaitan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
cd.yml@787f3b3955b3412f19b0c9fab35ee2b6bb5c505d -
Trigger Event:
release
-
Statement type:
File details
Details for the file textual_tetris-0.5.0-py3-none-any.whl.
File metadata
- Download URL: textual_tetris-0.5.0-py3-none-any.whl
- Upload date:
- Size: 22.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2a0b8ac683005816baacbbd747e8cfa001bd39fd230574544b0c9b33bc80411d
|
|
| MD5 |
5cff1b00b1a8d412e63546a4ab6ee89c
|
|
| BLAKE2b-256 |
dff48328d95d1aa7e62401ddaff10cdd4d18320e2f399e9b064b31db4fb728f2
|
Provenance
The following attestation bundles were made for textual_tetris-0.5.0-py3-none-any.whl:
Publisher:
cd.yml on mgaitan/textual-tetris
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
textual_tetris-0.5.0-py3-none-any.whl -
Subject digest:
2a0b8ac683005816baacbbd747e8cfa001bd39fd230574544b0c9b33bc80411d - Sigstore transparency entry: 2385566867
- Sigstore integration time:
-
Permalink:
mgaitan/textual-tetris@787f3b3955b3412f19b0c9fab35ee2b6bb5c505d -
Branch / Tag:
refs/tags/0.5.0 - Owner: https://github.com/mgaitan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
cd.yml@787f3b3955b3412f19b0c9fab35ee2b6bb5c505d -
Trigger Event:
release
-
Statement type: