tui · python
A lonely camera pointed at a window. It takes photos at random times each day, and a local LLM writes one sentence about how it feels to still be there.
Still Alive is a terminal app for a camera that has been left alone. You point a webcam at a window and leave it running. A few times a day, at moments nobody chooses, it takes a photo, draws a generative graphic over it, and asks a language model running on your own machine for one short sentence. Not about what it sees, but about what it feels to still be there.
Over weeks it becomes a quiet archive: the same window through different light and weather, every frame signed with a small, tired thought.
what it does
- Takes a random number of photos each day (for example 4 to 9), at random times inside an active-hours window you set.
- Draws one of five generative overlays on every photo:
orbital,noise_field,signal_wave,constellationorgrid_decay. - Captions every photo with a sentence from a local model served by Ollama. Vision models see the photo. Text-only models only know the date, how long they've been watching, how many pictures they've taken and, optionally, the weather.
- Shows a small ASCII eye in the interface that wanders, blinks, and flashes white the instant a photo is taken.
- Saves every image to
~/.still_alive/shots/and keeps a history of captions, styles and daily counts instate.json.
how it works
the schedule
Each day's plan comes from a random generator seeded with the date itself (still-alive-plan-2026-07-25, for example). Restart the app and you get the same plan for that day, so quitting and relaunching never reshuffles it.
The active window is cut into equal slices, one per photo, and each photo gets a random minute inside its own slice. That keeps the shots spread across the day instead of clumping together.
If the app was closed when a shot was due, it only catches up when the slot is less than 15 minutes old. Older slots are skipped, so opening it in the afternoon doesn't fire a burst of near-identical photos.
one shot, step by step
- The eye flashes white, and OpenCV captures a frame. It reads a few frames first and throws them away, so auto-exposure has time to settle.
- Brightness, contrast and an optional filter (grayscale, sepia, invert or pixelate) are applied.
- A generative overlay is composited on top in semi-transparent white. It's seeded by a hash of the exact timestamp, so the same moment always produces the same graphic.
- If a location is set, the current weather is fetched from Open-Meteo, which needs no API key.
- The prompt is built and sent to Ollama. A vision model also receives the photo, before the overlay is drawn. An empty reply is retried up to three times, and if the model still has nothing to say, the caption falls back to "still here".
- The caption layer is drawn: the timestamp and a
day N · shot Ncounter in one corner, the sentence in another, each on a translucent dark backing so it stays readable on bright or dark scenes. - The image is saved and the day's history is updated.
the prompt
Text-only models are told:
You are a camera. You have been left alone, pointed at a window. It is [weekday], [time], day [day of year] of [year]. You have been watching this window for [days] days. You have taken [shots] pictures in that time.
Write one sentence about this exact moment. Do not describe what you see. Describe what you feel about still being here. Under 12 words. No punctuation at the end.
When a location is configured, a line with the current weather is added. Vision models get a variant that asks them to blend one small detail of the photo with the feeling of still being there.
the eye
The eye in the interface isn't a set of drawn frames. Its lids are an ellipse and its iris and pupil are circles, computed for every character cell on each tick. The character on the lid's edge is chosen from the angle of the ellipse at that point, so curves get slashes, brackets and dashes that follow the shape. A terminal cell is about twice as tall as it is wide, so vertical distances are doubled to keep the iris round. Every 0.4 seconds it may look somewhere else or blink. The eye on this site's homepage is built on the same idea.
a camera somewhere else
The camera doesn't have to be on the machine running the app. In remote mode, every shot pipes a small capture script over SSH to python3 - on the other machine. The script grabs one frame, prints it as a base64 JPEG and exits. Nothing needs installing there beyond Python, OpenCV and Pillow, and there's no streaming server to keep alive, which suits a camera that only needs a handful of frames a day. An old laptop on a windowsill is enough.
the preview
The preview screen shows the camera's live view inside the terminal using half-block characters (▀). Each character cell holds two pixels: one as the text color, one as the background. Brightness, filters, overlay opacity, caption size and caption positions are all applied to a single captured frame, so tweaking them re-renders instantly without touching the camera again.
how it was made
- Python 3.10+ with Textual for the interface, OpenCV for the camera, Pillow for every drawing step, and requests for Ollama and Open-Meteo.
- Everything stays local. The only network calls go to your own Ollama server and, if you set a location, Open-Meteo's free weather API.
- The interface is monochrome, greys only, so the photos are the only thing in color.
- It began life as Window Watcher and was renamed to Still Alive.
run it
You need Python 3.10 or newer and a running Ollama server with at least one model pulled. qwen2.5vl:3b is a good vision model; llama3.2 works for text-only.
git clone https://github.com/Bloodcrane/still-alive
cd still-alive
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
ollama pull qwen2.5vl:3b
python -m still_alive
The first run walks through setup: pick a camera (or a remote one over SSH), the shots-per-day range and active hours, a model, and an optional location for weather. Settings live in ~/.still_alive/config.json and can be changed at any time.
| key | action |
|---|---|
s |
take a shot now |
p |
preview |
r |
run setup again |
q |
quit |
On minimal Linux systems where opencv-python fails because of missing GUI libraries, install opencv-python-headless instead.
license
MIT.