Inspired by the 50th anniversary of Microsoft, and the original Altair 4k BASIC, I vibe coded a working teletype paper tape chatbot.
Introducing a retro-futuristic terminal interface that simulates a 1979 Teletype Model 33 ASR — powered by modern LLMs via Ollama. Generates animated, audio-punched paper tape output for your prompts. Powered on/off with sound effects and glowing LEDs.
-
Vintage lighted POWER button with startup/shutdown SFX + glow
-
Screen shake when turning on or off (retro current surge effect)
-
Realistic 8-level paper tape recreation
-
Clicky punch sounds and motor hum synced to paper tape movement
-
Paper tape scrolls in real-time with ASCII output
-
LLM selector (Qwen, TinyDolphin, Granite3-MoE)
-
LED indicators for KSR (keyboard) / ASR (tape) / LLM / JAM status LEDs
-
EOL BELL support (ASCII
BELshown + ding audio) -
BELglyph shown visually on tape -
ASCII accurate PNG rendering of punched tape, rendered by
matplotlib -
LLM integration (multi-model via Ollama API)
-
Models supported:
qwen2.5:0.5b,tinydolphin,granite3-moe -
System prompt identifies the LLM as a Teletype Model 33 ASR (1979)
-
Lightweight models run locally with fast, lightweight footprint
-
Proper header/footer hex codes (#FF, #00)
-
Tape Jam is simulated if input text or LLM response is too large
- Python 3
- Flask
- Matplotlib
- Ollama with supported models (
qwen2.5:0.5b,tinydolphin, etc.)
I set up my server on Amazon AWS Linux. Adjust accordingly for your environment.
To get started, clone the project from GitHub:
git clone https://github.com/m15-ai/Paper-Tape-LLM.git
cd Paper-Tape-LLM
pip install flask matplotlib
Install Ollama for your platform, then pull one or more supported models:
ollama pull qwen2.5:0.5b
ollama pull tinydolphin
ollama pull granite3-moe:1bMake sure the Ollama daemon is running in the background. Use Ollama list to confirm your models are available:
$ ollama serve
$ ollama list
NAME ID SIZE MODIFIED
granite3-moe:1b d84e1e38ee39 821 MB 25 hours ago
tinydolphin:latest 0f9dd11f824c 636 MB 25 hours ago
qwen2.5:0.5b a8b0c5157701 397 MB 25 hours ago
To render the paper tape images with proper spacing and visible control character glyphs (like NUL, BEL, etc.), this project uses the FreeMono font from GNU FreeFont.
This font must be installed on your system for the tape images to render correctly.
You can download it directly from the GNU project:
https://ftp.gnu.org/gnu/freefont/
Look for the file:
FreeMono.ttf
Install it system-wide, or copy it into a known font path (e.g., /usr/share/fonts), then refresh the font cache:
sudo fc-cache -fv
- This font supports printable glyphs for ASCII control characters, which are rendered directly on the tape.
- If the font is missing, you may get blank or misaligned output.
Place the papertape_server.py file in a non-public directory:
$ pwd
/home/ec2-user
$ ls -lsart
total 18
0 drwxr-xr-x. 3 ec2-user ec2-user 75 Apr 16 20:43 .ollama
8 -rw-rw-r--. 1 ec2-user ec2-user 7461 Apr 17 17:44 papertape_server.py
4 -rw-r--r--. 1 ec2-user ec2-user 2305 Apr 17 20:33 server.log
Run the server so it will persist:
nohup python3 papertape_server.py > server.log 2>&1 &
This will expose the /generate_paper_tape endpoint.
Place the papertape.html file, the *.mp3 sound files, and the *.png images into a public directory:
$ pwd
/var/www/html
$ ls -lsart
total 63
0 drwxr-xr-x. 4 root root 33 Dec 16 23:12 ..
4 -rw-rw-r--. 1 ec2-user ec2-user 743 Apr 13 20:37 send_48dp_green.png
60 -rw-rw-r--. 1 ec2-user ec2-user 59755 Apr 16 01:54 tt-starting.mp3
192 -rw-rw-r--. 1 ec2-user ec2-user 193920 Apr 16 01:55 tt-running.mp3
136 -rw-rw-r--. 1 ec2-user ec2-user 136242 Apr 16 01:55 tt-stopping.mp3
16 -rw-rw-r--. 1 ec2-user ec2-user 13503 Apr 16 02:42 ttclick4.mp3
40 -rw-rw-r--. 1 ec2-user ec2-user 37601 Apr 16 04:07 button-on.png
36 -rw-rw-r--. 1 ec2-user ec2-user 35713 Apr 16 04:07 button-off.png
48 -rw-rw-r--. 1 ec2-user ec2-user 46982 Apr 16 17:28 ding.mp3
16 drwxr-xr-x. 2 ec2-user ec2-user 16384 Apr 16 17:28 .
20 -rw-rw-r--. 1 ec2-user ec2-user 17540 Apr 17 18:19 papertape.html
After launching the Flask backend, open papertape.html directly in your browser (e.g., from your /var/www/html or localhost folder). The HTML file sends prompts to the Flask backend, which responds with a PNG image of the paper tape.
This file contains the fully retro-styled frontend interface:
- Power Switch: A clickable image button (
button-on.png,button-off.png) that powers the teletype on/off. Triggers startup and shutdown audio, screen shake, and LED activation. - Text Input & Submit Button: A styled text input box and a green send icon (
send_48dp_green.png) that submits prompts to the server. - LLM Selector: A dropdown menu lets users select which local Ollama model to use. Locked while power is on.
- LED Panel: Simulated KSR, ASR, LLM, and JAM status lights that activate based on interaction state.
- BELL Toggle: Checkbox enabling the inclusion of ASCII
BEL(U+0007) in the final tape and triggering a physical bell sound (ding.mp3). - Paper Tape Scroll: Receives a ASCII-accurate PNG tape image from the server and scrolls it across the screen in "chunky" increments, synchronized with retro click sounds (
ttclick4.mp3). - Audio Feedback: Three hum sounds (
tt-starting.mp3,tt-running.mp3,tt-stopping.mp3) create a realistic audio profile for machine state. The classic teletype bell "ding" can be added at the end of each line. - Tape JAM Handling: Detects long input or LLM output, shows a JAM LED, and aborts the scroll sequence.
This Flask server powers the paper tape simulation and LLM interaction:
- Endpoint
/generate_paper_tape: Accepts a POST JSON payload containing:text: the user promptbell: boolean indicating if theBELcharacter should be addedmodel: the selected LLM model (e.g.qwen2.5:0.5b)
- LLM Request Handling:
- Sends the prompt to the Ollama server using the selected model
- Prepends a system message simulating a 1979 Teletype terminal
- Tape Rendering:
- Converts the LLM completion string to 8-bit ASCII punch codes
- Adds leader (
0xFF) and trailer (0x00) bytes - Optionally appends
BELas a visible glyph - Uses
matplotlibwith theFreeMonofont to render a PNG of the full tape, including glyphs for control characters
- Returns:
- The PNG image via
send_file() - A custom HTTP header (
X-Punch-Count) with the total character count for frontend animation sync
- The PNG image via
The system message sent to each model tells it to behave like a 1979 Teletype terminal. You can modify this string in papertape_server.py to adjust tone, length, or formatting of LLM responses.
@app.route('/generate_paper_tape', methods=['POST'])
def generate_tape():
system_prompt = (
"You are a Teletype Model 33 ASR from the year 1979, connected to a mainframe via serial cable. "
"You respond in short bursts of uppercase text as if printed on a paper tape. "
"Your language is efficient, mechanical, and dry. Limit output to a few words per line, "
"like a real teletype outputting ASCII on paper tape. "
"Avoid punctuation unless absolutely necessary. Never apologize or explain. "
)
Dad's original Micro-soft MITS Altair 4k BASIC bootstrap loader paper tape and BASIC manual. That's where it all started for me:
- Tested on desktop and mobile
- This project was made possible with the help of Grok Studio, so we needed those 50 years to get here.
MIT — for the retro hacker in all of us.

