LOOP
A conversation with your future self.
I built a phone-simulation game where an unknown number claims to be you, 24 hours in the future. You decide whether to follow their instructions, warn a friend, or stop replying.
Stackp5.js · GPT-4o-mini · Web Audio API
The four strongest screens
Jump to 02, the story engine
Jump to 01, the interface
Jump to 03, the endings
Jump to 03, the endings
LOOP looks 95% like a real iPhone.
That 5% is where it lives. Dread comes from familiarity.
Calm, then urgent, then fragmenting.
Four endings, each triggered by a different kind of behavior.
Restraint over spectacle.
A reminders widget does the work distorted fonts do in cheap horror.
What I learned.
- Constraining the bot's voice was the hardest design problem.
- The audience and the protagonist are the same person.
Role, process and impact
Role, process, impact and the context
- Role
- I built the phone interface, character prompts, story-state logic, and audio cues.
- Process
- I constrained the bot’s replies and tracked player choices in code to keep the branching conversation on course.
- Impact
- Players can follow the warnings, refuse them, contact a friend, or let the conversation time out. Each choice leads to a different ending.
- Role
- Design + Code
- Context
- NYU ITP · Chatbots for Art's Sake
- Year
- 2025
- Tags
01Interface
The interface is the narrative.
- Every visual choice is part of the story: the monospace clock, the reminders widget, the bedroom camera that stays offline until it doesn't.
- LOOP looks 95% like a real iPhone; dread comes from familiarity.
- Mundane reminders and a camera feed that says "Last Updated: 3 seconds ago" do the work that distorted fonts do in cheap horror.
Read more
Chatbots for Art's Sake
Every visual choice in LOOP is part of the story. The monospace clock. The reminders widget with "call dr. about appointment." The bedroom camera that stays offline for the entire game, until it doesn't. None of that is in the chat. The environment creates dread before the bot says a word.
LOOP looks 95% like a real iPhone. That 5% is where it lives. Dread comes from familiarity. The design principle is restraint over spectacle: the scariest version of this interface is the one that almost passes as normal. Cheap horror uses distorted fonts. LOOP uses mundane reminders and a camera feed that says "Last Updated: 3 seconds ago."
The interface
Every screen in LOOP is built from scratch in p5.js and HTML. The lock screen shows a real ticking time and a notification from "Unknown." The home screen has a reminders widget with items like "call dr. about appointment", mundane enough to feel real.
The home camera app shows three feeds: Front Door (live) and Back Door (last updated 3 seconds ago), both on infrared, and Bedroom Window, offline, with a small grey MOTION label in its corner. That camera goes offline as a design choice. Something is there. The game never explains it.
Screen cracks run down the right side of the phone frame. The audio layer adds glitch sounds, a pulsing alarm, and an iOS-style text ping. None of it is labeled. The wrongness is in the details.
Design principles
- The interface is the narrative. Every visual choice, the monospace font, the dark field, the cyan accent, is part of the story, not decoration around it. The game doesn't have a theme applied to a chat app. The chat app is the story.
- Restraint over spectacle. Dread comes from what is almost normal. The scariest version of this interface looks 95% like a real iPhone. No distorted fonts. No gore. A reminders widget with "call dr. about appointment" is more unsettling than any jump-scare.
- Every screen is a proof of work. The kind of detail a viewer zooms in on to see if it holds up. The camera timestamp. The unread badge count. The screen crack on the right side. It has to hold up. A portfolio piece that doesn't survive scrutiny isn't a portfolio piece.
02Story engine
The prompt is mostly what the bot cannot say.
- The bot is GPT-4o-mini on the NYU ITP/IMA proxy, driven by a 200-line system prompt across three acts.
- It had to feel like a scared person texting at midnight: no metaphors, no exclamation points, no therapy-speak, never a capital letter, two sentences at most.
- JavaScript tracks the acts (turn counts, silence timers, betrayal state); the code handles the state transitions.
Read more
The bot is GPT-4o-mini on the NYU ITP/IMA proxy. A 200-line system prompt drives three acts, each with its own voice rules and advancement conditions. The hardest design problem was the chatbot voice: it had to feel like a scared person texting at midnight, not a bot, not a philosopher.
That meant hard constraints: no metaphors, no exclamation points, no therapy-speak, never start with a capital letter, two sentences maximum. The prompt is more about what it cannot say than what it should. Act advancement is tracked in JavaScript, turn counts, silence timers, betrayal state, and the bot receives a tagged response; the code handles state transitions.
- Fragmentation is intentional. As the story collapses in Act 3, the design earns the right to break. But only because Acts 1 and 2 held. The horror of Act 3's one-word messages is that you remember what full sentences felt like.
- The paradox must be felt, not explained. LOOP never uses the words "time loop." The visual design makes you feel the loop before the text tells you about it, because if it had to be explained, it wouldn't land.
Three acts, in order
Each with its own voice rules and advancement conditions.
- ACT 1
Calm. Careful.
You're texting from an unknown number. Patient, lowercase, like someone who has had this conversation before and is trying to do it right this time.
- ACT 2
Urgent. Controlling.
Seven instructions, one at a time. Don't go outside 2–4pm. Don't answer the door. Let unknown calls ring. Each requires conversation before the next is given.
- ACT 3
Fragmenting.
Messages get shorter. Sometimes one word. Signal dropping. The loop closes. "there is no first version." The only exit: set a reminder for 11:47 tomorrow.
03Endings
Four endings, each triggered by a different kind of behavior.
- The game tracks what you say, and also whether you opened the camera app, texted a contact or went silent.
- The contacts list is fully interactive: open Jess, Tyler or Maya and type, and the unknown number already knows.
- Ending D, the betrayal path, is the one players find by accident.
Read more
The game tracks not just what the player says in the main chat, but whether they opened the camera app, whether they tried texting a contact, whether they went silent. Four endings, each triggered by a different kind of behavior.
Ending D, the betrayal path, is the one players find by accident. The contacts list is fully interactive. You can open Jess, Tyler, Maya, and type. The game watches. If you try to warn someone else, the unknown number already knows.
ENDING A
Break the Loop
You refuse to send the message. Tomorrow's version of you receives no warning. They go outside at 2pm. They answer the door.
ENDING B
Stay in the Loop
You set the reminder. Another version of you will receive this message at 11:47 tomorrow. The chain has no origin and no end.
ENDING C
You Became the Sender
Three silence timeouts. The bedroom window camera, offline, motion detected, comes to life. The horror sequence begins without you.
ENDING D
You Told Someone
You texted Jess to explain. The notification arrives instantly: "dont send that message to jess." The unknown number was watching the whole time.
04Reflection
The feeling of being observed is produced by observation.
LOOP is live on GitHub Pages.
Play LOOP ↗Constraining the bot's voice was the hardest design problem.
Every LLM wants to be helpful, verbose, emotionally validating. Every line in the LOOP prompt had to fight that. The result, two sentences, lowercase, no metaphors, never say "I understand", was more about prohibition than prescription. The voice only worked once I stopped writing what the bot should say and started writing what it could never say.
Behavioral tracking is what makes interactive fiction feel authored.
Players who find Ending D almost always think the betrayal path was written just for them. That recognition, "it knew I would try that", is the game's best moment. It only exists because the code watches the messages list, the contacts, the silence timer. The feeling of being observed is produced entirely by observation.
The audience and the protagonist are the same person.
LOOP works because the player is alone, late at night, on a phone. The dread is personal. Portfolio viewers arrive as an audience and leave as participants. Players arrive as participants and leave with the uneasy feeling that the loop already started before they picked up the phone.