Skip to content

Repository files navigation

🚂 sl — Steam Locomotive

GitHub starsGitHub forksLicense: MITPythonPlatformDependenciesMaintainedWebsite

You typed sl. You meant ls. The railroad thanks you for your patronage.

 ==== ________ ___________
_D _| |_______/ \__I_I_____===__|_________|
|(_)--- | H\________/ | | =|___ ___|
/ | | H | | | | ||_| |_||
| | | H |__--------------------| [___] |
| ________|___H__/__|_____/[][]~\_______| |
|/ | |-----------I_____I [][] [] D |=======|__
__/ =| o |=-~~\ /~~\ /~~\ /~~\ ____Y___________|__
|/-=|___|= || || || |_____/~\___/
\_/ \O=====O=====O=====O_/ \_/

Every other command punishes a typo with an error message. sl rewards it with a steam locomotive. The entire point is maximal output for minimal input — two mistyped letters buy you a train, and you will watch it cross your terminal, because that is the punishment and the prize.

This is a single-file, zero-dependency Python train that takes the joke entirely too seriously: a flicker-free double-buffered renderer, wheels that actually turn, smoke that drifts and dissipates, coal cars, a whistle, and a crash mode that earns its flag.

🎲 No two typos look alike

A bare sl — the classic fumbled ls — rolls the dice on everything: locomotive type, coal-car count, color livery (four named themes plus fully random one-offs), and speed. Sometimes it whistles. Rarely, it flies. Very rarely, it does not make it across.

EventOdds
⚓ The typo turns out to be nauticalabout 1 in 3
📣 The train (or ship) whistles1 in 4
🐬 A dolphin escorts the voyage1 in 5 sea voyages
✈️ The train takes flight1 in 10
💥 The journey does not reach its destination1 in 20

Pass any flag and the dice are off — explicit options are fully deterministic, so your customizations always behave exactly as written.

⚓ New in 4.0: the rails end at a shoreline

Four vessels join the roster. Type sl -t galleon and a three-masted pirate ship crosses your terminal on an animated sea — flapping Jolly Roger, turning nothing, fearing nothing, figurehead shaped like a rubber duck. Her name is SQUEAKY. She has gunports.

 |~~~~~~,
` ` ` ` |x_x__/
` ` ` ` ` | ` ` `
|> | ` ` `
.___|___. .___|___. |>
( | \ ( | \ |
( | \ ( | \ .____|____.
(___________\ (___________\ ( ( | ) \
` | | ( ( | ) \
.____|____. .____|____. ( ( | ) \
` ( ( | ) \ ( ( | ) \ (__)_________(__\
` /| ( ( | ) \ ( ( | ) \ |
/ | ( ( | ) \ ( ( | ) \ /| _____
` / |(__)_________(__\ (__)_________(__\ / | __|~ ~ ~|
/ | /|\ /|\ / || o o |
<o)_/___| / | \ / | \ / || o o |
\__\__________________________________________________|________|
|=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=|
\ [] [] [] [] [] [] [] [] [] |
\_________S Q U E A K Y____________________________________/
\=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_/

The fleet:

  • 🏴‍☠️ galleon — the Jolly Roger flaps on a 4-frame cycle, pennants flick, and the sea shimmers under her hull
  • 🛞 steamer — a sternwheeler whose paddle wheel actually turns (same 4-frame machinery as the locomotive wheels), churn streaming aft
  • sloop — a racing yacht for narrow terminals
  • 🚢 tug — drawn in three-quarter perspective, so it travels diagonally, on the angle its art implies, growing as it approaches

Sea voyages come with bow spray, stern wake, hull bob, and per-vessel whistles (-w): the steamer HOOOONKs, the galleon goes YARRR!. At sea, -a finds an iceberg — crunch, bubbles, and a dignified descent. -F is the Flying Dutchman. And on special request, -d summons a dolphin that dives ahead of the ship, cut cleanly at the waterline.

✨ Features

  • 🎲 Surprise mode — a bare sl randomizes the whole show, every run
  • 🚂 Four locomotives — Classic, Small, D51, and C51 (-t)
  • Four vessels — Galleon, Steamer, Sloop, and Tug (-t), with an animated sea, spray, wake, and a dolphin on request (-d)
  • 🛞 Animated wheels — a 4-frame rotation cycle on every engine
  • 💨 Particle smoke — drifts behind the train and dissipates, with grayscale shading on 256-color terminals
  • 🚃 Coal cars — couple up to 8 tenders behind the engine (-n)
  • ✈️Flying mode — smoothstep climb with a stardust trail (-F)
  • 💥 Accident mode — screen shake, a spark shower, and a proper BOOM (-a)
  • 📣 Whistle — the train toots as it passes (-w)
  • 🖥️ Flicker-free — double-buffered frames on the alternate screen; your terminal contents come back when the train has passed
  • 🎨 Respectful of your eyes — honors NO_COLOR and --no-color; sl | cat prints a static train instead of escape-code soup
  • 📐 Terminal-aware — live resize handling, clean Ctrl+C, monotonic frame pacing that doesn't drift
  • 🪶 Zero dependencies — one file, pure Python standard library

📦 Installation

git clone https://github.com/developtheweb/slTrain.git
cd slTrain
sudo make install

That installs to /usr/local/bin/sl. Prefer to do it by hand?

sudo cp sl /usr/local/bin/ && sudo chmod +x /usr/local/bin/sl

Requirements: Python 3.6+, a Unix-like terminal with ANSI escape support, and a sense of humor. Nothing else — see requirements.txt, which is proudly empty.

Uninstall

sudo make uninstall

The train will remember this.

🚀 Usage

You don't usesl. You commit a typo, and sl happens to you:

$ sl # 🎲 Surprise! Random train, livery, cars, and speed

But if you insist on driving:

$ sl -t classic # The classic engine, no surprises
$ sl -l # Long train: D51 pulling coal cars
$ sl -n 8 # Maximum coal. The economy is booming
$ sl -F # Flight
$ sl -a # Tragedy
$ sl -w -c # A whistling C51
$ sl -s 2.0 # You have somewhere to be
$ sl -s 0.1 # You do not

Options

OptionLong FormDescription
-a--accidentAn accident occurs partway through
-F--flyMake the train fly through the sky
-l--longUse a longer train (D51 pulling coal cars)
-c--C51Use the C51 train type
-t--typeType: classic, small, d51, c51, galleon, steamer, sloop, tug (overrides -l/-c)
-n--carsNumber of coal cars to pull, up to 8 (default: 0; rail only — coal cars do not float)
-d--dolphinA dolphin joins the voyage (implies a vessel)
-w--whistleSound the whistle as the train or ship passes
-s--speedAnimation speed multiplier, 0.1–20 (default: 1.0)
--no-colorDisable colors (NO_COLOR is also honored)
-v--versionShow version information
-h--helpShow help message

Any flag disables surprise mode. The dice only roll for a naked typo.

🔧 How it works

For a joke, it's built like it matters:

  • Double-buffered rendering. Each frame is composed into an off-screen cell buffer and emitted as a single write — no clear-screen between frames, so nothing flickers, ever.
  • The alternate screen. The animation runs on the terminal's alternate buffer, the same trick vim and less use. When the train is gone, your scrollback is exactly as you left it. Like it never happened. It happened.
  • A particle system. Smoke, crash sparks, and stardust are particles with velocity, drag, and gravity, aging through character ramps (@Oo*.) as they dissipate.
  • Monotonic pacing. Frame timing is anchored to a monotonic clock, so the train's speed doesn't drift with render cost or system load.
  • An honest fallback. If stdout isn't a terminal, you get a static train in plain text. sl | cat is a train. sl > file.txt is a train. There is no escaping the train, only escape codes, and those are omitted.

🤔 Why does this exist?

We've all done it — typed sl when we meant ls. Instead of command not found, why not a gentle reminder in the form of a steam locomotive chugging across your terminal?

  • 📚 Typing discipline through consequences — muscle memory training, enforced by rail
  • 😄 Whimsy in the command line — terminals can be fun too
  • 🎭 Coworker delight — watch confusion turn to joy, then back to confusion when it crashes
  • 🧘 Mandatory micro-breaks — the train cannot be skipped, only awaited

❓ FAQ

Can I stop the train? Ctrl+C works and exits cleanly. Learning to type ls also works, but nobody has ever managed it.

The train crashed. Is that a bug? If you passed -a, that's a feature. If you didn't, that's a 1-in-20 roll of surprise mode, and honestly, it's a little bit on you for typing sl.

Why would a train fly? 1-in-10 odds say you'll find out.

I asked for a dolphin and got a ship. A dolphin will not follow a train. Requesting one books sea passage.

Why does the tug move diagonally? It was drawn in three-quarter perspective, so it sails the angle its art implies — toward you. It appears to grow because it is, in the only sense that matters, getting closer.

Is this compatible with the original sl? The spirit, the D51/C51 art heritage, and the -a/-F/-l/-c flags are all honored. The renderer, particles, and surprise mode are new.

🤝 Contributing

Contributions are welcome — new locomotives, new liveries, new disasters. See the Contributing Guidelines.

git clone https://github.com/YOUR_USERNAME/slTrain.git
cd slTrain
git checkout -b feature/amazing-feature
./sl -F # test your changes
git commit -m "Add amazing feature"
git push origin feature/amazing-feature

💖 Support the Project

📝 License

MIT — see LICENSE. The train is free. The train has always been free.

👨‍💻 Author

Reverend Steven Milanese

🙏 Acknowledgments

  • Inspired by the original sl by Toyoda Masashi (1993), who understood that the punishment for a typo should be beautiful
  • The coal car art is adapted from the original sl
  • Thanks to all contributors
  • Special thanks to the first stargazer who inspired this update ⭐

📊 Project Stats

GitHub commit activityGitHub last commitGitHub code size


It's not a bug, it's a locomotive. 🚂

Made with ❤️ by Reverend Steven Milanese
Visit StevenMilanese.com for more projects

About

slTrain is a fun and nostalgic Python script inspired by the classic sl steam locomotive command. This script animates a charming steam locomotive chugging across your terminal, complete with a dynamic smoke trail and colorful ASCII art. It's perfect for adding a bit of old-school charm to your terminal sessions.

Topics

Resources

Code of conduct

Contributing

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages