ascii-movie serves the Star Wars ASCII film over SSH and Telnet from Go
Star Wars SSH + Telnet server written in Go.
At a glance
- What is it?
- ascii-movie is a Go rewrite of the classic Star Wars ASCII animation that plays the film in a terminal or hosts it over SSH and Telnet, built on the Charm bubbletea stack with an interactive UI, keyboard and mouse support. It suits a tinkerer who wants a public terminal service or a containerised demo, and the Telnet path has no encryption.
- Who is it for?
- ascii-movie fits a developer who wants to run the Star Wars ASCII animation locally as a bubbletea program, or to put a public terminal service on the internet with an SSH front end and a container image.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A terminal film with an interactive layer, not just a pipe
ascii-movie streams the original Star Wars ASCII animation to command line clients over SSH or Telnet. The project documentation credits two inspirations, asciimation and the iconic towel.blinkenlights.nl presentation, and describes this Go rewrite as introducing an interactive UI with both keyboard and mouse support.
That last part is the difference from the versions most people have seen. The classic towel.blinkenlights.nl presentation was a stream you watched, and the asciimation site is a recorded asciicast. Here the animation is driven by a program, so the Charm bubbletea stack is in play, along with bubbles, lipgloss for styling, bubblezone for mouse regions, and termenv for colour detection.
The dependency list in go.mod also includes the charmbracelet/ssh and charmbracelet/wish packages, which are the SSH server framework and the middleware framework built on it. That is what makes the serve subcommand possible: wish is the standard way to build a multi-user SSH server in Go, with a bubbletea program attached to each session.
The user is two different people. One is a developer who wants to run the animation in their own terminal, which is the play subcommand. The other is an operator who wants to run a public terminal service, which is the serve subcommand.
Two subcommands: play in a terminal, serve over the network
The command line has two shapes, and the documentation points at generated docs for the details.
The play subcommand plays a movie directly in your terminal. The serve subcommand hosts the SSH and Telnet servers. The generated command line documentation lives in the docs directory, with separate pages for ascii-movie_play.md and ascii-movie_serve.md.
The command line itself is built with spf13/cobra and spf13/pflag, so the usual subcommand, flag and help conventions apply.
There is also a third surface that the documentation does not dwell on, but the compose file reveals: an API. The compose configuration sets ASCII_MOVIE_API_ADDRESS to port 1977, and it publishes that port only on 127.0.0.1, so the API is reachable from the host but not from the network.
The three environment variables, ASCII_MOVIE_SSH_ADDRESS, ASCII_MOVIE_TELNET_ADDRESS and ASCII_MOVIE_API_ADDRESS, are the configuration surface for the server mode. The Docker image sets the environment variables for you, so the compose file is the fastest way to see the intended deployment shape.
The compose file shows the intended production layout
The compose file is short and shows several deliberate choices.
app:
image: "ghcr.io/gabe565/ascii-movie"
build: .
environment:
COLORTERM: "$COLORTERM"
TERM: "$TERM"
ASCII_MOVIE_SSH_ADDRESS: ":2222"
ASCII_MOVIE_TELNET_ADDRESS: ":2323"
ASCII_MOVIE_API_ADDRESS: ":1977"
ports:
- "2323:2323"
- "2222:2222"
- "127.0.0.1:1977:1977"
read_only: trueThe SSH and Telnet servers are bound to 2222 and 2323 inside the container and published on the same ports on the host, while the API is published on 1977 but only against localhost. The container also runs read_only, and there is a small helper service that chowns the data volume to the container user before the app starts, with the app depending on that chown completing successfully.
That arrangement explains the volume in the Dockerfile. The SSH server needs host keys, and the environment variable ASCII_MOVIE_SSH_HOST_KEY points at two files in the data directory, an id_ed25519 and an id_rsa, which the volume provides. The image also creates a dedicated unprivileged user with uid 1000, sets TERM to xterm-256color, and makes /data a volume.
The Docker image builds a static binary with an embedded film
The Dockerfile is a two stage build that ends in a minimal Alpine image.
The build stage starts from golang:1.24.6-alpine, downloads modules with go mod download, and then runs go generate -x ./... before compiling. That generate step is the interesting one: the film data is produced during the build, not committed as an opaque blob you have to fetch separately.
The compile step uses the xx toolchain for cross platform builds, with CGO disabled, the flags -w -s to strip the binary, trimpath, and a gzip build tag. The final image is alpine:3.22.1 with only tzdata added, the binary copied to /bin, the non-root user, the volume and the entrypoint set to the ascii-movie binary with serve as the default command.
So the movie content is baked into the executable at build time. The Dockerfile also sets a separate goreleaser.Dockerfile, and the repository has a .goreleaser.yaml for release packaging, plus a compose.yaml for local development with a develop section that watches the source and rebuilds on change.
The Telnet port is the weak point, and the example shows why
The documentation offers three ways to see the animation. You can ssh to starwarstel.net, telnet to starwarstel.net, or run a container locally with docker run --rm -it ghcr.io/gabe565/ascii-movie play.
The public Telnet endpoint is the one to think carefully about. Telnet carries the session in clear text, and an SSH server implemented with charmbracelet/ssh can give you a real authenticated session while Telnet gives anyone who connects whatever the program hands them.
The Docker example for serving makes the same point in a different way. The watch locally example runs the container with sudo, and the serve example maps the standard ports.
sudo docker run --port=22:22 --port=23:23 ghcr.io/gabe565/ascii-movie serveMapping port 23 on the host is the conventional Telnet port, and it is also a port that scanners look for. Whether you expose it is your call, but the compose file's choice of 2323 and 2222 is the safer default, and the fact that the documentation shows both means you should notice the difference rather than copy the first example.
Licensing, releases and what is actually in the tree
The licence is GPL-3.0, and the repository carries a LICENSE file. For a project that serves a film over the network, that is worth a moment of thought, since the software licence and the rights in the animation are separate questions and only the first is answered here. The repository has a movies directory, and the build generates the film content into the binary, which means the animation data is inside the artefact you redistribute.
On maintenance, the last push was on 2026-10-22 and the repository is not archived. The listed releases are v1.9.7 from 2025-03-04, v1.9.6 from 2025-02-17 and v1.9.5 from 2024-09-03, so the tags are older than the recent commits and the repository is where the current work lives.
The rest of the tree shows the shape of a Go project with generated documentation and an embedded terminal UI. There is main.go, a cmd/ directory for the commands, internal/ for the application logic, system/ and assets/ for resources, docs/ for the generated command line reference, a compose.yaml, a.golangci.yaml for linting, a.pre-commit-config.yaml, and a.github/ directory with the build workflow that the badge points at.
The dependency set also includes prometheus/client_golang, so the server mode can expose metrics, and golang.org/x/crypto and golang.org/x/sync for the SSH host keys and concurrency.
Editorial conclusion
ascii-movie fits a developer who wants to run the Star Wars ASCII animation locally as a bubbletea program, or to put a public terminal service on the internet with an SSH front end and a container image. It does not fit a deployment that needs confidentiality on the Telnet port, since Telnet traffic including the session is unencrypted, and it does not fit a project that needs the film assets redistributed, since the repository ships a movies directory and the legal status of the original animation is not addressed in the documentation. Before adopting it, read the Installation and Usage wiki pages for the SSH host key setup, check that the compose file binds the API port to localhost only as it does now, and confirm which ports you expose, since the Docker example maps the standard Telnet port.
Frequently asked questions
How do I play the Star Wars ASCII movie in my terminal?
Run the play subcommand of the ascii-movie binary, or use the published container image with docker run --rm -it ghcr.io/gabe565/ascii-movie play. The README also lists public ssh and telnet endpoints you can connect to.
What ports does ascii-movie use when serving?
The compose file sets the SSH server to 2222, the Telnet server to 2323 and the API to 1977, publishing 2323 and 2222 on the host and 1977 only on 127.0.0.1. The Docker example in the documentation maps the standard ports 22 and 23 instead.
Does ascii-movie need Go or Docker to run?
Neither is required if you use the published image or the public service. To build from source you need Go, since the module targets go 1.24.6 and the Dockerfile builds with a golang 1.24.6 alpine stage and a CGO disabled build.
What licence is ascii-movie under?
The repository is licensed GPL-3.0, with the licence file at the root of the repository. The documentation does not address the rights in the animation itself, which is baked into the binary at build time by the go generate step.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/gabe565-ascii-movie)Was this useful?