Tetro TUI is a terminal-based but modern tetromino-stacking game that is very customizable and runs cross-platform.
- Download a release for your platform (Linux/MacOS/Windows/...) if available.
- Navigate to the application binary (
tetro-tui/tetro-tui.exe/...) and run it in a terminal
Cargo (crates.io):
cargo install tetro-tui
# tetro-tuiArch Linux (aur.archlinux.org):
yay -S tetro-tui # Or paru, etc.
# tetro-tuiTetro TUI is written in Rust and can be compiled as usual:
git clone https://github.com/Strophox/tetro-tui
cd tetro-tui
cargo runTetro TUI is about tetromino pieces falling from the sky and stacking inside a 2D playing field. When a horizontal line is full it automatically clears away and everything 'stacked' above shifts down.
A skilled player may keep playing indefinitely. Different game modes will change up the gameplay while still using the same base mechanics.
We provide a solid amount of configuration options and features:
- Graphics: Unicode/ASCII/Electronika styles, old-terminal-compatible or very modern designs, 10 color palettes, hard drop/piece lock/line clear effects and much more.
- Gameplay and handling: Various rotation systems, piece randomizers, adjustable preview, timings (DAS¹, ARR¹, SDF¹, LCD, ARE), IRS/IHS/IMS/ITS¹ (¹caveat).
- Game keybinds: to your heart's desire.
- Game mode miscellany: Swift ('40-Lines'), Classic ('Marathon'), Master, Puzzle, Cheese, Combo, Custom (select goal, initial gravity, toggle gravity progress, cmdline flags: start board, seed).
- Highscores, replays, statistics, ... - can can be accessed as well as backed up with a simple savefile.
Visuals depend on / can be customized together with your underlying terminal settings. E.g. you can set a bigger font to scale the game, or use cool-retro-term for nostalgic look etc.
See also: Complete list of Tetro TUI v3.0 menus contents:
New game/
- Swift: How fast can you clear 40 lines?
- Classic: Clear 150 lines at increasing gravity.
- (unlocked after Classic) Master: Clear 150 lines at instant gravity.
- Puzzle: Clear 24 hand-crafted puzzles.
- Cheese-20: Eat through lines like Swiss cheese. Limit∈[None, Some(10), Some(11), .., Some(20), ..]
- Combo-30: Get consecutive line clears. Limit∈[None, Some(10), Some(11), .., Some(30), ..]
- Ascent*: (experimental, requires 'Ocular'- + 180° rotation)
- Custom: [Del]=reset
- Initial fall delay = 1.0s (Gravity: 1.0 Hz)
- Progressive gravity ∈ [on, off]
- Limit ∈ [None, TimeElapsed(300s), .., PointsScored(200), .., PiecesLocked(100), .., LinesCleared(40), ..]
- Game save: (Only shows up after using
Ctrl+S)Settings/Adjust-Graphics/
- Slot ∈ [Default, Focus+, Guideline, Terminal compatibility, Elektronika 60, Blank slate, Custom I/II/..]
- Color Palette (modifiable presets) ∈ [Monochrome, ANSI, Standard, Okpalette, Gruvbox, Solarized, Terafox, Fahrenheit, The Matrix, Sequoia]
- TUI style ∈ [ASCII, Unicode, Elektronika 60]
- Mino textures ∈ [ASCII, Unicode, Elektronika 60]
- Hard drop effect ∈ [None, Particles ASCII, Streak ASCII, Beam ASCII, Beam]
- Lock effect ∈ [None, Transform ASCII, Pulse Unicode, White]
- Line clear effect ∈ [None, Instant, Left to right, Inward, Outward, Flash white, Blink, Pop out, Pop out (more), Sparks ASCII, Blast]
- Mini tetromino style ∈ [ASCII, Braille]
- Small tetromino style ∈ [ASCII, Blocks, Braille]
- Normalsize previews ∈ [unlimited, 1, 2 ..]
- Frames per second ∈ [5, 10, .., 60, ..]
- Show grid ∈ [on, off]
- Show piece shadow ∈ [on, off]
- Preview spawn when stack high ∈ [on, off]
- Color board tiles ∈ [on, off]
- Show left HUD ∈ [on, off]
- Show keybinds legend ∈ [on, off]
- Show active buttons ∈ [on, off]
- Show FPS counter ∈ [on, off]
Settings/Adjust-Keybinds/
- Slot (modifiable preset) ∈ [Default, Control+, Guideline, Vim, Custom I/II/..]
- MoveLeft, MoveRight
- RotateLeft, RotateRight, Rotate180
- DropSoft, DropHard
- TeleDown, TeleLeft, TeleRight
- HoldPiece
Settings/Adjust-Gameplay/
- Slot ∈ [Default, Finesse+, Guideline, NES, Gameboy, Custom I/II/..]
- Piece rotation system ∈ [Ocular, ClassicL, ClassicR, Super]
- Piece randomization ∈ [Completely random, 7-Bag, 14-Bag, .., Recency (^2.5), Recency (^2.6), .., Balance out]
- Piece preview count ∈ [0, 1, .., 4, ..]
- Delayed auto move (DAS) ∈ [0ms, 1ms, .., 167ms, ..]
- Auto move rate (ARR) ∈ [0ms, 1ms, .., 33ms, ..]
- Soft drop speedup (SDF) ∈ [0x, 0.25x, .., 15x, ..]
- Line clear duration (LCD) ∈ [0ms, 5ms, .., 200ms, ..]
- Spawn delay (ARE) ∈ [0ms, 5ms, .., 50ms, ..]
- Allow initial rotation/hold (IRS/IHS/IMS/ITS) ∈ [on, off]
- Convert double-tap to teleport ∈ [None, Some(5ms), Some(10ms), ..]
Settings/Advanced-Settings/
- Save contents ∈ ["--Nothing", "Only settings --No scores,replays", "Only settings,scores --No replays", "Everything (settings,scores,replays)"]
- Assume enhanced-key-events available ∈ [on, off]
- Blindfold gameplay ∈ [on, off]
- Pause on focus lost ∈ [on, off]
- Renderer selected ∈ [Standard, Legacy, Prototype, Twoxel, Braille]
Why do some gameplay (DAS/ARR/SDF...) settings (or some keybinds like Ctrl/Shift/Alt/...) not work for me?
It is likely that your current terminal provides too little input information to enable custom timings¹ or those special keys. (¹Instead, DAS/ARR/SDF will be determined by how quickly your terminal sends key-repeat events.) If possible use an enhanced terminal like Kitty or Alacritty (also others) for flawless game handling.
Explanation:
The fundamental problem lies in how terminals usually send input signals.
- Due to historical reasons, most will only send "key pressed" but not "key released again". This makes it impossible to implement mechanics such as: "If
[←]is pressed, move left with a certain speed until key is released again."
- Affected mechanics: Fixed DAS, Fixed ARR, Fixed SDF (& holding Soft Drop will lock the piece), Unable to hold Teleport, Unable to hold buttons for IRS/IHS/IMS/ITS.
- Note that some terminals e.g. on Windows do send key-release signals, without this being auto-detected: Use the 'Override' in Advanced Settings for such cases.
- Also due to history, modifier keys can only modify 'actual' text signals and are never sent by themselves.
- Affected mechanics: Cannot register modifier
Ctrl/Alt/Shift/Win/⌘/... as individual key presses.Precisely these issues are fixed with 'enhanced keyboard events' / 'progressive enhancement' / 'kitty protocol'.
You can press
?in every single menu to access a keybinds overview for it.Otherwise please refer to the tables below.
Menu controls:
Universal:
Keys ≈ Meaning Enter,eSelect Esc,q,Back,Go back Del,dDelete/Reset ↓/↑,j/kNavigate down/up ←/→,h/lAdjust value ?Open Keybinds Overview Ctrl+Alt+LRe-load from savefile (Caution: overwrites current data!) Ctrl+Alt+SDo savefile storage (respects save preferences) Ctrl+CExit program (respects save preferences) Specific to 'Scores and Replays':
Keys Meaning Alt+Del,Alt+dDelete replay (in 'Scores and Replays') Home/EndNavigate to top/bottom Specific to 'Start New Game':
Keys Meaning Alt+←/→,Alt+h/lAdjust value differently (under ⇝['Combo','Custom','Game save']) Home/EndSet fall delay to infinite/zero (under ⇝'Custom'), jump to beginning/end of inpus (under ⇝'Game save') Alt+EnterView replay instead of starting game save (under ⇝'Game save') Ctrl+U(For experienced/impatient players) unlock all game modes Specific to 'Gameplay settings':
Keys Meaning Alt+←/→,Alt+h/lAdjust value differently (under ⇝'Piece randomization'⇝['*-Bag', 'Recency (*)']) (Default) Game controls:
Default Key (customizable) Action ←Move left →Move right ARotate left (CCW) - Rotate around (180°) DRotate right (CW) ↓Soft drop ↑Hard drop - Teleport down - Teleport left - Teleport right SpaceHold piece
Key Action EscPause game ?Open Keybinds Overview
Key Special action Ctrl+DForfeit game Ctrl+RRestart game mode (Caution: discards current game) Ctrl+ZUndo last input (Caution: overwrites current game) Ctrl+LLoad game save (Caution: overwrites current game) Ctrl+SStore game save (accessible in 'Start New Game'⇝'Game save' or (live)'Game'⇝ Ctrl+L)Ctrl+EStore seed (accessible in 'Start New Game'⇝'Custom') Ctrl(+Alt)+GCycle through graphics settings slots Ctrl+Alt+BToggle on/off visibility of tiles ('Blindfolded') Ctrl+Alt+LRe-load from savefile (Caution: overwrites current data!) Ctrl+Alt+SDo savefile storage (respects save preferences) Ctrl+CExit program (respects save preferences) Replay controls:
Key Action Enter,eStart Game from current replay state ('take over') Esc,q,BackExit replay SpacePause replay ↓/↑,j/kSpeed up / slow down replay by ±0.25x -Reset replay speed to =1.0x ←/→,h/lSkip forward / backward 1s in time .Skip forward one player input & pause 1/2/3...Jump to 10%/20%/30%/... Home/EndJump to beginning/end ?Open Keybinds Overview
Key Special action Alt+↓/↑,Alt+j/kSpeed up / slow down replay by ±0.05x Alt+.Skip forward one game state change & pause (might not work properly for modded games) Ctrl+LToggle replay looping Ctrl+SStore game save (accessible in 'Start New Game'⇝'Game save' or (live)'Game'⇝ Ctrl+L)Ctrl+EStore seed (accessible in 'Start New Game'⇝'Custom') Alt+I(Experimental) Toggle instantaneous interactive input intervention mode Ctrl(+Alt)+GCycle through Graphics Settings slots Ctrl+Alt+LRe-load from savefile (Caution: overwrites current data!) Ctrl+Alt+SDo savefile storage (respects save preferences) Ctrl+CExit program (respects save preferences)
The application will not store anything by default and 'Keep save file' needs to be opted in;
The exact location of the config file is shown in the Advanced Settings menu and is based on
dirs::config_dir():
- Usually
/home/yourname/.config/.tetro-tui_v1.0_savefile.json- or
C:/User/yourname/AppData/Roaming/.tetro-tui_v1.0_savefile.jsonSavefile grows primarly due to number/length of saved replays. As a rule of thumb, 1min of gameplay with fast inputs adds ≲ 1 kB. If you end up with a lot of play time but can't/don't want to spare the kB / MB, you can:
- Delete some entries (// just their replay data) in Scores and Replays using
[Del](//[Alt+Del]).- Configure which categories of data get stored in the first place on program exit (see Advanced Settings).
We put to practical use our customizability and provide many *settings slots* (profiles/templates), e.g. to simulate guideline gameplay¹/keybinds¹/graphics (¹Handling limitations may apply to your terminal);
Note that the 'Default' settings slots – though they should remain very familiar – do take liberties in 'shifting mechanics closer to the platonic ideal' of a tetromino stacker game. This is obviously not an objective statement, in practice it just means:
Keybinds:
- Default controls set to WASD + Arrow keys (also preferred due to common terminal limitations).
- Dedicated keys possible for Rotate 180°, Teleport Down ('Sonic Drop'), even Teleport Left/Right.
Gameplay:
- Default use of the flexible/intuitive/symmetrical Ocular Rotation System (instead of: the quirky / sometimes asymmetrical industry default).
- Default Recency Randomizer which is random but biases toward choosing less recent pieces (instead of: 'overdeterministic' 7-Bag).
- Points (score) bonus system is currently kept custom and simple.
- '1pt for simple line clear, with increasing bonus for larger lineclears, combos, spins and perfect clears.'
- Note: 'Allspin' (instead of: preoccupation with 'T-spins'), currently no 'minis'.
- Note: Combos (but no additional points for 'back to back' other than existing incentives for special maneuvers).
- Exact formula:
point_bonus = if is_perfect_clear{ 4 }else{ 1 } * if is_spin{ 2 }else{ 1 } * (lineclears * 2 - 1) + (combo - 1)- Different lock reset limit: 'max time = 10⋅current lock delay' (instead of: 'max 15 moves with current lock delay').
- Speed/gravity/fall curve slightly less fast but very close to 'standard'.
Graphics:
- Chosen default palette is more pastel with uniform perceptual brightness.
See this list quoted from the Falling Tetromino Engine that powers the core game logic:
In terms of advanced game mechanics the engine aims to compare with other modern tetromino stackers. It should already incorporate many features desired by familiar/experienced players, such as:
- Available player actions:
- Move left/right,
- Rotate left/right/180°
- Drop soft/hard
- Teleport down(='Sonic drop') and left/right
- Hold piece,
- Tetromino randomizers: 'Uniform', 'Stock' (generalized Bag), 'Recency' (history), 'Balance-out',
- Piece preview (arbitrary size),
- Spawn delay (ARE),
- Spawn actions (IRS/IHS/IMS/ITS; by keeping rotate/hold pressed during spawn),
- Rotation systems: 'Ocular' (engine-specific, playtested), 'Classic', 'Super',
- Delayed auto-move (DAS),
- Auto-move rate (ARR),
- Soft drop factor (SDF),
- Customizable gravity/fall and lock delay curves (exponential and/or linear; also, '20G' (fall rate of ≥1200 Hz) just becomes ≤00083s fall delay),
- Ensure move delay less than lock delay toggle (i.e. DAS/ARR are automatically shortened when lock delay is very low),
- Allow lenient lock-reset toggle (i.e. reset lock delay even if rotate/move fails),
- Lock-reset cap factor (i.e. maximum time before lock delay cannot be reset),
- Line clear duration (LCD),
- Customizable win/loss conditions based on the time, pieces, lines, points,
- Score more points for larger lineclears, spins ('allspin'), perfect clear, combo,
- Game reproducibility (PRNG/determinism).
An extensive attempt at better tetromino rotation with regards to symmetry and visual intuition;
The Ocular rotation system affords:
- Symmetric/mirrored situations should lead to symmetric/mirrored outcomes (e.g. no distinct but visually identical states).
- Rotation generally based on 'proximity where it looks like the piece should (be able to) go'.
- Pieces should prefer downwards placement, not 'teleport up' in general.
See this visual/'heatmap' comparison of industry default vs. Ocular rotation:
Programmers / Terminal enthusiasts: Can you tell me more about the programming behind this terminal game?
This project handles quite a few aspects to provide an excellent user experience for a classic game. Among the many things that have accumulated inside the scope of this project are:
- A fully-featured Tetromino game engine/backend featuring:
- Several dozens of configurable, advanced and important options.
- Provided pre-implementations of extremely common standard mechanics.
- Decoupled core game loop ('interpreter') with ergonomic API (hopefully).
- Basic but functional modding functionality with ergonomic API (hopefully).
- Different and interesting game modes, including special game modes that rely on engine modding.
- Extensive TUI menus to allow modifying all relevant configuration options without being forced to edit the save file manually: * Graphics options, Configurable keybinds, Gameplay settings.
- Providing many curated configuration templates for everything, inspired by existing standards and games.
- Sidenote: Ever since its inception as a proof-of-concept the terminal user interface (TUI) has directly and only relied on Crossterm. Currently there appears no need to change this situation, though a full TUI library like Ratatui might be reconsidered e.g. to handle UI translation (displaying other languages) etc.
- A good input-update-render game loop.
- Implementing game replay.
- Savefile storage:
- Especially replay data serialization and compression.
- Scoreboard and statistics.
- Game graphics renderer that handles all of the effects and dozens of graphics settings, efficiently.
- Custom buffer diff'ing so we can guarantee we only send the minimum number of required changes to the terminal (this minimizes flicker), see .
- Miscellaneous:
- Commandline arguments.
- Terminal limitations, all the time.
- Doing all of the above as simply, ergonomically and as correctly as possible while providing feedback to the user when something doesn't work as expected.
- Code quality.
Tetro TUI started as a passion project from someone who loves programming, minimalistic games and ASCII art;
Out of curiosity I looked into the depths of this common type of Tetromino game: Basic versions are simple to code up, but it gets surprisingly nontrivial when it comes to comprehensively supporting of modern/advanced features and slews of QOL mechanics while dealing with terminal limitations!
I've given it my best effort to implement a most featureful and customizable version that not only remains totally faithful to the basic idea of the game, but also runs and looks nice within the confines of a mere terminal - Enjoy! ☻ L. Werner
Licensed under MIT.
100% human-sourced spaghetti code
Color palettes featured: Gruvbox, Solarized, Terafox, Fahrenheit, matrix, Sequoia Monochrome.
A big thank you to the AUR package maintainers:
Thank you to the people who provided inspiration:
- Dunspixel – regarding 'O'-spins
- Martín G – regarding new line clear effect from his own PICO-8 game
- thehuglet – for showing the potential of terminal graphics
- Akousoukos – for making Apotris
Special Thanks
- GrBtAce, KonSola5 and bennxt – support during early dev and research
- madkiwi – for advice regarding 4-wide-6-residual combo layouts
- and RayZN and ˗ˋˏthe One and Onlyˎˊ˗ – for advice regarding the Tetro logo









