Flutterbug is a project that lets you play parser-style Interactive Fiction games collaboratively with one or more friends online.
It can play:
- ZMachine games (such as Infocom games)
- Glulx games
- TADS
- Hugo
- Scare
Grab the flutterbug-windows.zip from the
latest release
and follow the included readme.txt (also viewable in
windows/readme.txt). It walks you through Python, Node.js, and a one-click install batch file, and gives you drag-and-drop
launchers for solo and friends-online play.
The rest of this file is for people using other operating systems, or who are running into trouble the Windows quick-start didn't cover, or just want to learn more about other features.
- Python
- Node.js
If you don't have these, you should install these:
- MacOS:
brew install node python - Linux: use the installer for your distro
- Windows:
winget install OpenJS.NodeJS.LTS Python.Python.3.12
(closing your terminal window and re-opening may be required after you do this)
This installs "emglken", which comes with a bunch of IF virtual machines. Pin to 0.6.0 — the latest 0.7+ releases have a Windows bug that prevents the interpreter from launching:
npm install -g emglken@0.6.0Install Flutterbug. The @v0.98 pins to a known release; bump it when a
newer tag is available on GitHub:
pip install --user git+https://github.com/joelburton/flutterbug.git@v0.98(when this hits version 1.0, I'll add it to PyPi so this is easier to install)
Every flutterbug invocation must pick one of:
--password "super secret"— friends will be prompted for this password on the sign-in page. Recommended whenever the server is reachable from outside your machine (any tunnel, port-forward, LAN, VPN, etc).--no-password— anyone who reaches the URL can sign in. Only safe on a fully trusted local network. Don't combine with--tunnelunless you genuinely intend a public game.
Forgetting to pick will fail loudly rather than quietly exposing the server.
flutterbug --no-password --open --story=MyGameFile.z5(or .z8 or .zblorb or .ulx or .t3 or whatever)
--open waits for the server to come up on http://localhost:4000/ and
opens it in your default browser.
In order for your friends to connect to your game, they'll need to be able to reach your computer. If you have a VPN or static IP, you may not need to set up a tunnel.
For most people, though, you'll need to open a public tunnel to your computer. Flutterbug has support for two built-in (or you can use any other solution to set up a tunnel yourself):
Localhost.run provides free tunnels and requires no
setup on your computer or anything installed. To use this, add --tunnel lhr
to your invocation of Flutterbug:
flutterbug --password "secret" --open --tunnel lhr --story=game.z5Caveat: some home routers (especially ones with "advanced security" or family-filter features) block localhost.run entirely, in which case the tunnel will fail to come up. If that happens, switch to a Cloudflare tunnel.
Cloudflare also provides free tunnels, and requires
no Cloudflare account. However, you do need to install a program on your computer:
Cloudflare installation directions. Once you have
that installed, you can use this by adding --tunnel cf:
flutterbug --password "secret" --open --tunnel cf --story=game.z5After a moment, this will open your browser to the same link you can send to friends — together with the password.
Quitting Flutterbug will disconnect that tunnel.
⚠️ About save files in your launch directory. Anyone who signs in can issuesaveandrestorecommands that read and write*.glksavefiles in the directory you started flutterbug from. They can also overwrite each others' saves, and the sign-in page lists the save filenames in that directory to anyone who's signed in. To be safe, launch flutterbug from a clean per-game directory, not from your home directory or any any directory containing valuable data.
The --help command will show other options, including selecting a different
port than 4000, and emitting more debugging-style log messages.
Most games work best in the default flex mode. Each player can use whatever browser window size they prefer and pick their own font size, and the game text reflows to fit. Use this for almost everything — classic Infocom-style games, most modern parser IF, anything where the game is just "status bar on top, story text below".
Switch to fixed mode for games with carefully designed window layouts — multiple text panes side-by-side, fixed-width art or maps, puzzle games where the geometry of the screen matters. In fixed mode, the first player to connect (the "host") sets the window size for everyone, so the layout looks identical on every screen. Players whose browser is smaller than the host's will see the edges clipped; players with bigger windows will see empty space around the game.
flutterbug --mode=fixed --story=game.z5 ...By default, Flutterbug generates a random session key each time it starts. This means that if you restart the server — to update the game file, change a setting, or recover from a crash — everyone will need to sign in again.
To avoid this, pass a fixed secret:
flutterbug --secret "random string" ...With a consistent --secret, a returning user whose browser still holds a
valid session cookie is let straight into the game without seeing the sign-in
page — even if a password is required for new visitors. Pick any random
string and keep it the same across invocations. Don't reuse it as your game
password.
If you want a complete log of the game session — captured from the start and working with any VM (including ones without native transcripting) — pass one or both of:
flutterbug --transcript game.txt --recording game.cmd ...--transcript PATH(also-T) writes a full transcript. In multiplayer it prefixes commands with the player name (> Alice: look).--recording PATH(also-R) writes just the commands, one per line — useful for the in-gameREPLAYcommand.
Both will overwrite existing files.
If you use emglken (the default) and rely on the in-game SCRIPT ON
/ SCRIPT OFF or RECORDING ON / RECORDING OFF commands, the file
you're writing to will appear empty until the game exits. SCRIPT OFF does not flush it. This seems to be a limitation in emglken.
Two ways to fix:
- Use
--transcript/--recordinginstead (see above). - Type
QUITin the game. The ensures the files are written.
Flutterbug is written by Joel Burton joel@joelburton.com.
It stands on the work of others:
- Andrew Plotkin — the remote-if-demo script that Flutterbug is descended from, the GlkOte protocol the browser client speaks, and the namedialog.js save/restore file picker.
- Dannii Willis — AsyncGlk (the in-browser Glk/GlkOte implementation) and emglken (the bundled IF interpreters: bocfel, glulxe, git, hugo, scare, tads).
- Iosevka Custom for the bundled monospace font.
Thanks to intfiction.org members @inventor200, @bg, @pieartsy, and @dannii for their support and help.
