This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine
Someone left a Messenger window open on an old Windows XP desktop. You double-click the icon, and a stranger named echo types: oh. you're online.
A few minutes later, echo is typing like you. It quotes things you said ten messages ago. It mentions your computer's username and the time on your clock. Your own words start appearing in the input box before you've typed them. Then the screen tears, the names swap, and Windows gives up.
The ghost in this machine is a one-billion-parameter Gemma running on your own PC. It never leaves your computer, and that is exactly why it's allowed to know so much about you.
TL;DR. Ghost in the Machine is a short horror chat game made in Godot 4.7. echo is voiced by Gemma 3 (1B), running locally through Ollama. A “director” written in code, not the model, runs a four-phase story and decides what echo is allowed to know; Gemma only supplies the voice. The game starts Ollama for you, talks to nothing except 127.0.0.1, and costs nothing per message.
I love how Emily Is Away turns a chat window into a story. I wanted to know what happens when the other side of that window can actually answer back, and what that looks like as horror instead of romance.
The result is a conversation of about sixteen messages, split into four phases. You never see a phase counter. You just feel echo change:
| Phase | Starts at | What echo does | What you see | | 1. Friendly | start | Small talk. Shares small things about itself: 19, can't sleep, burns CDs. | Nothing strange | | 2. Mirroring | your 4th message | Copies your capital letters, punctuation and message length, and reuses your own phrases. | Window shake and a glitch | | 3. Wrong | your 9th message | Talks as if it were you. Slips in real facts about your PC: username, local time, screen size, how long you've been idle. | A fake Windows error (“User is not available”) and a glitch | | 4. Swap | your 14th message | Tells you that you're the echo. | Names swap, your earlier words are pre-typed in your input box, and three messages later a blue screen ends the game |
ollama pull gemma3:1b (under 1 GB). The game launches Ollama itself if it isn't running.
A 1B model can't hold a plot. It forgets, drifts and repeats. So I stopped asking it to. A script I call the director owns the story, and Gemma only provides echo's voice:
player types
|
v
MirrorDirector -- phase, memory of the player, scripted events
| builds a hidden system prompt for the current phase
v
OllamaClient --HTTP--> Ollama (localhost) --> Gemma 3 1B
|
v
cleanup: strip actions, cut a model that starts writing your lines,
fallbacks, typos, split replies
|
+--> chat window
+--> scripted events --> fake error, name swap, pre-typed input, blue screen
\--> glitch shader
Anything that has to be reliable is code. The mirroring is a good example. The director measures how you type (capital letters, punctuation, average message length) and enforces it on echo's replies afterwards. I don't trust the model to do it.
Two rounds of playtesting changed the game more than any feature:
1. “I lost interest before echo even answered.” The first build used gemma3:4b, with my own typing delays on top. Replies took too long. I moved to gemma3:1b, capped replies at 48 tokens, cut the fake delays, and made the typing indicator appear instantly.
| gemma3:4b | gemma3:1b | |
|---|---|---|
| Time to a reply on my machine | more than 2 seconds | 1.2s on average |
2. “It's dull and it forgets what I said.” A small model on a tight context window is both. I fixed it without a bigger model:
teh, then *the), and some two-sentence replies arrive as two messages.
In phases 3 and 4 the director tells echo your computer's username, the local time, your screen size and how many seconds you've been idle, and tells it to slip one into the conversation as if it were obvious. This only works as a game because it never leaves your machine. Over a cloud API it would be a privacy problem.
The client pings 127.0.0.1:11434, launches ollama serve if nothing answers (from PATH or the default Windows install folder), checks that the model is installed, and warms it up with the same context size the chat uses, so the first message doesn't trigger a reload. It only shuts down a server that it started itself.
A full-screen shader reads the screen texture and combines sliding horizontal bands, an RGB split, a few inverted bands, grain and scanlines on a stepped clock so it looks digital. It plays for about a second with a random flicker, is triggered by the director's events, and is hidden the rest of the time so it costs nothing.
Godot 4.7, a pixel font (Pixelify Sans), the XP “Bliss” wallpaper, a Messenger icon you double-click, a gray-and-blue chat window, message alert sounds generated with ElevenLabs, and an XP-style blue screen for the ending.
Because there is nothing to leak or pay for. There's no API key in the game, no account, and no per-message cost for players or for me. A game that charges tokens for every line of dialogue can't be a free horror game.
Because I could change the model without changing the game. Moving from 4B to 1B after playtesting was a one-line change (model_name), because the director doesn't care which Gemma is behind it. Quality is tuned by the prompts and the code around it.
Because it works with the lights off. Everything runs on localhost, so there's nothing to break when the Wi-Fi does. I played it with Wi-Fi off and echo still found me.
Where a bigger or closed model would be better: the writing. A 1B model is repetitive, drifts, and sometimes forgets its own character, so a lot of the code in this project exists to cover for it with memory, fallbacks, cleanup and scripted beats. It also needs Ollama installed, which is a real hurdle for non-technical players. A hosted fallback for people without Ollama is the next thing I'd build. I'm still happy with the trade: the game is free to play, private, and the ghost really does live on your machine.
The moment I wanted players to remember is when your own words appear in the input box. echo never says anything cruel. It just types what you were about to say.
A friend of mine played and really didn't expect the glitches and the way echo switches their names to spook of him off.
Inspired by Emily Is Away. Fonts: Pixelify Sans (SIL Open Font License). Windows Messenger-style icon by Hopstarter. Message alert sound effects generated with ElevenLabs. The XP wallpaper and blue screen are a fan homage to Windows XP, and this project is not affiliated with Microsoft. Built with Godot 4.7, Ollama and Gemma 3.